dodo hold 2 rokov pred
rodič
commit
e1363240a5

+ 1 - 2
molilian.api/Controllers/admin/JdUnionController.cs

@@ -14,7 +14,6 @@ namespace molilian.api.Controllers
     [ApiController]
     [MyAuthorize("admin")]
     [Route("api/[controller]/[action]")]
-    [Route("coupon_api/[controller]/[action]")]
     public class JdUnionController : ControllerBase
     {
         readonly IAuthorizationProvider provider = new AdminProvider();
@@ -41,7 +40,7 @@ namespace molilian.api.Controllers
             if (success)
             {
                 //string desc = ObjectComparer.PrintCompareToString(old, form).Trim();
-                OperationLogCore.LogOperation(token.AccessKey, clientIp, $"tk_pool:{accountId}:cookie", string.Empty, cookie);
+                OperationLogCore.LogOperation(token.AccessKey, clientIp, $"jd_pool:{accountId}:cookie", string.Empty, cookie);
             }
             return new APIResult(new
             {

+ 180 - 0
molilian.api/Controllers/admin/PddUnionController.cs

@@ -0,0 +1,180 @@
+using molilian.core;
+using dodohold.core;
+using Microsoft.AspNetCore.Mvc;
+using System.Text.Json;
+using System.Net;
+using static QRCoder.PayloadGenerator;
+using MySqlX.XDevAPI;
+using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
+using WebSocketSharp.Net;
+namespace molilian.api.Controllers
+{
+
+
+    [ApiController]
+    [MyAuthorize("admin")]
+    [Route("api/[controller]/[action]")]
+    public class PddUnionController : ControllerBase
+    {
+        readonly IAuthorizationProvider provider = new AdminProvider();
+        protected IHttpContextAccessor _accessor;
+        public PddUnionController(IHttpContextAccessor accessor)
+        {
+            _accessor = accessor;
+        }
+
+        [HttpPost]
+        public async Task<ActionResult> updateCookies([FromBody] JsonElement form)
+        {
+            var clientIp = _accessor.HttpContext.GetUserIp();
+            var token = provider.Get(_accessor.HttpContext);
+            string user_agent = _accessor.HttpContext.Request.UserAgent();
+
+
+            string cookie = form.Read<string>("cookie", string.Empty);
+            cookie = cookie.Replace("\r", "").Replace("\n", "").Trim();
+            if (!cookie.EndsWith(";")) cookie += ";";
+
+            var accountId = PddPoolCore.UpdateCookies(cookie, user_agent);
+            bool success = accountId > 0;
+            if (success)
+            {
+                OperationLogCore.LogOperation(token.AccessKey, clientIp, $"pdd_pool:{accountId}:cookie", string.Empty, cookie);
+            }
+            return new APIResult(new
+            {
+                data = new { success, msg = success ? "更新成功" : "更新失败,请检查输入的cookie" },
+            });
+        }
+
+        /// <summary>
+        /// 账号列表
+        /// </summary>
+        /// <param name="form"></param>
+        /// <returns></returns>
+        [HttpPost]
+        public ActionResult list([FromBody] JsonElement form)
+        {
+            var token = provider.Get(_accessor.HttpContext);
+
+            int page = form.Read("current", 1);
+            int size = form.Read("pageSize", 10);
+            string keyword = form.Read("name", string.Empty);
+            bool getTotal = form.Read("getTotal", true);
+            string _status = form.Read("status", string.Empty);
+            int status = _status switch
+            {
+                "online" => 1,
+                "offline" => 0,
+                _ => -1,
+            };
+            var lastTime = form.PathReadArray<string>("lastTime[]");
+
+            string sort = form.Read<string>("sort");
+            string order = form.Read<string>("order");
+
+            string filter = " is_hide=0";
+            if (!string.IsNullOrEmpty(keyword))
+            {
+                filter += $" AND (`name` LIKE @keyword OR `description` LIKE @keyword)";
+                keyword = $"%{keyword}%";
+            }
+            DateTime stime = DateTime.MinValue, etime = DateTime.MinValue;
+            if (lastTime.Count == 2)
+            {
+                if (DateTime.TryParse(lastTime[0], out stime) && DateTime.TryParse(lastTime[1], out etime))
+                {
+                    etime = etime.AddDays(1).AddSeconds(-1);
+                    filter += $" AND last_time BETWEEN @stime AND @etime";
+                }
+            }
+            if (status != -1)
+            {
+                filter += $" AND status=@status";
+
+            }
+
+            filter = filter.StringTrimStart(" AND ");
+
+            //排序
+            string orderBy = "id DESC";
+            if (!string.IsNullOrEmpty(order))
+            {
+                order = "descending".Equals(order) ? "DESC" : "ASC";
+                orderBy = sort switch
+                {
+                    //"num" => $"num {order}",
+                    _ => $"{sort} {order}",
+                };
+            }
+
+            using var conn = DBContext.GetOpenConnection();
+            var result = new DBContext.Table(conn, "pdd_pool")
+                .Where(filter, new { keyword, status, stime, etime })
+                .Page(size, page)
+                .Order(orderBy)
+                .PageList<PddPoolDTO>(getTotal);
+
+            foreach (var item in result.List)
+            {
+                item.app_secret = string.Empty;
+                item.cookies = string.Empty;
+            }
+            return new APIResult(new { data = result });
+        }
+
+        [HttpPost]
+        public async Task<ActionResult> update([FromBody] JsonElement form)
+        {
+            var clientIp = _accessor.HttpContext.GetUserIp();
+            var token = provider.Get(_accessor.HttpContext);
+
+            int id = form.Read<int>("id", 0);
+            string name = form.Read<string>("name", string.Empty);
+            string val = form.Read<string>("val", string.Empty);
+
+            if (id == 0)
+            {
+                return new APIResult(new { data = new { success = false, msg = "更新失败,请检查输入的cookie" } });
+            }
+
+            int result;
+            switch (name)
+            {
+                case "enable_parse":
+                case "enable_coupon":
+                case "status":
+                    bool bVal = val.Equals("True");
+                    result = new DBContext.Table("pdd_pool")
+                           .Add(name, bVal)
+                           .Add("last_time", DateTime.Now)
+                           .Where("id=@id", new { id })
+                           .Update();
+                    break;
+                case "time_range":
+                    int.TryParse(val, out int iVal);
+                    result = new DBContext.Table("pdd_pool")
+                           .Add(name, iVal)
+                           .Add("last_time", DateTime.Now)
+                           .Where("id=@id", new { id })
+                           .Update();
+                    break;
+                default:
+                    return new APIResult(new { data = new { success = false, msg = "更新失败,未授权操作" } });
+            }
+            bool success = result > 0;
+            if (success)
+            {
+                OperationLogCore.LogOperation(token.AccessKey, clientIp, $"pdd_pool:{id}:{name}", string.Empty, val);
+                await EndPointCore.NotifyReload(true);
+
+            }
+            return new APIResult(new
+            {
+                data = new { success, msg = success ? "更新成功" : "更新失败,请检查输入信息" },
+            });
+        }
+
+
+    }
+}

+ 6 - 0
molilian.api/Controllers/admin/ReportController.cs

@@ -77,6 +77,12 @@ namespace molilian.api.Controllers
                 .Order(orderBy)
                 .PageList<DailyLogsDTO>(getTotal);
 
+
+            var accounts = JdPoolCore.List();
+            var hide_ids = accounts.Where(e => e.is_hide).Select(e => e.id).ToList();
+            result.List = result.List.Where(e => e.channel != 1 || !hide_ids.Contains(e.accountId));
+
+
             return new APIResult(new { data = result });
         }
 

+ 1 - 7
molilian.api/Controllers/public/H5Controller.cs

@@ -46,12 +46,6 @@ namespace molilian.api.Controllers
             string sign = app.MakeSign(out nonce, out timer);
             string sign_url = $"appKey={api.app_key}&nonce={nonce}&signRan={sign}&timer={timer}";
 
-
-            https://openapi.dataoke.com/api/tb-service/get-privilege-link?appKey=663dc44dcb55f&nonce=955350&signRan=9FFB668FD91AD897C238C536899C92EC&timer=1716116967528&version=v1.3.1&pid=236e3aa943d948339732430b74737328&goodsId=jyn335Ds0tJYG9g9g0IN6PCJte-GPgAyeRIqOVrK3W0HnY&coupon_id=
-
-
-
-
             return new APIResult(new
             {
                 success = true,
@@ -64,7 +58,7 @@ namespace molilian.api.Controllers
         public ActionResult ddsign([FromBody] JsonElement form)
         {
 
-            var api = PddPoolCore.GetOne();
+            var api = PddPoolCore.GetOne(PddUnionWorkMode.SiteApi);
             if (api == null)
             {
                 return new APIResult(new

+ 34 - 5
molilian.api/Controllers/public/TaskController.cs

@@ -235,7 +235,7 @@ namespace molilian.api.Controllers
                 }
                 catch (Exception ex)
                 {
-                    message = $"【报表接口异常】FastReport\n{ex.Message}\n{ex.StackTrace}";
+                    message = $"【报表接口异常】GetViolationuWarning\n{ex.Message}\n{ex.StackTrace}";
                     NotifyCore.Notify(new NifyMessage
                     {
                         message = message,
@@ -443,10 +443,7 @@ namespace molilian.api.Controllers
                     }
                 }
             }
-            string filter = "";
-#if DEBUG
-            filter = "id IN (7,8)";
-#endif
+            string filter = ""; 
             var jd_list = new DBContext.Table("jd_pool").Where(filter, null).Select<JdPoolDTO>();
             if (jd_list != null)
             {
@@ -512,6 +509,37 @@ namespace molilian.api.Controllers
                 if (any_jd_changed) JdPoolCore.Refresh();
             }
 
+
+            var pdd_list = new DBContext.Table("pdd_pool").Where(filter, null).Select<PddPoolDTO>();
+            if (pdd_list != null)
+            {
+                bool any_pdd_changed = false;
+                foreach (var account in pdd_list)
+                {
+                    bool changed = false;
+                    try
+                    {
+                        account.current_daily_calls = PddPoolCore.SaveCalls(account.id, DateTime.Now.ToString("yyyyMMdd"));
+                        account.current_hourly_calls = PddPoolCore.SaveCalls(account.id, DateTime.Now.ToString("yyyyMMddHH"));
+                        changed = true;
+                        any_pdd_changed = true;
+                    }
+                    catch (Exception ex)
+                    {
+                        message = $"【Pdd计数异常】SaveCalls\n{ex.Message}\n{ex.StackTrace}";
+                        NotifyCore.Notify(new NifyMessage
+                        {
+                            message = message,
+                            priority = NifyMessagePriority.high,
+                            tags = ["red_circle"]
+                        });
+                        continue;
+                    }
+                    if (changed) PddPoolCore.Update(account);
+                }
+                if (any_pdd_changed) PddPoolCore.Refresh();
+            }
+
             await EndPointCore.NotifyReload(true);
             return new APIResult(new { success = true, message = "ok" });
         }
@@ -687,6 +715,7 @@ namespace molilian.api.Controllers
             TkPoolCore.Refresh();
             VeapiPoolCore.Refresh();
             JdPoolCore.Refresh();
+            PddPoolCore.Refresh();
 
             return new APIResult(new
             {

+ 5 - 2
molilian.api/Controllers/public/TkController.cs

@@ -529,10 +529,13 @@ namespace molilian.api.Controllers
                 .Order(orderBy)
                 .Select<TkOrderTrackingDTO>();
 
+            //fake_click_link_type
+
+
             List<object> list = [];
             foreach (var item in data)
             {
-                list.Add(new { item.accountId, url = item.deeplinkUrl, item.shortLinkUrl, count = item.click_num, time = item.exp_time });
+                list.Add(new { pid = item.accountId, url = item.deeplinkUrl, item.shortLinkUrl, count = item.click_num, time = item.exp_time });
             }
             var clientIp = _accessor.HttpContext.GetUserIp();
             LoggerLibrary log = new LoggerLibrary("api", "dplist");
@@ -578,7 +581,7 @@ namespace molilian.api.Controllers
             List<object> list = [];
             foreach (var item in data)
             {
-                list.Add(new { item.accountId, url = item.deeplinkUrl, item.shortLinkUrl, count = item.click_num, time = item.exp_time });
+                list.Add(new { pid = item.accountId, url = item.deeplinkUrl, item.shortLinkUrl, count = item.click_num, time = item.exp_time });
             }
             var clientIp = _accessor.HttpContext.GetUserIp();
             LoggerLibrary log = new LoggerLibrary("api", "unsafeParseDpList");

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
molilian.api/Properties/PublishProfiles/https___ccr.ccs.tencentyun.com_shaobin.pubxml.user


+ 0 - 0
molilian.core/Core/taoke/DataokeCore.cs → molilian.core/Core/dataoke/DataokeCore.cs


+ 0 - 0
molilian.core/Core/taoke/PangolinPoolCore.cs → molilian.core/Core/douyin/PangolinPoolCore.cs


+ 1 - 37
molilian.core/Core/taoke/JdPoolCore.cs → molilian.core/Core/jd/JdPoolCore.cs

@@ -53,43 +53,7 @@ namespace molilian.core
             var list = List();
             if (!list.Any()) return null;
             return list.Where(e => e.id == id && IsNotExceedDailyIncomeLimit(e, action)).FirstOrDefault();
-        }
-
-        //internal static void SaveIncomeAmt(int accountId, decimal income_amt)
-        //{
-        //    string key = $"{accountId}:{DateTime.Now:yyyyMMdd}";
-        //    if (_incomeAmt.ContainsKey(key))
-        //    {
-        //        _incomeAmt[key] = income_amt;
-        //    }
-        //    else
-        //    {
-        //        _incomeAmt.Add(key, income_amt);
-        //    }
-        //    string cache_key = $"cache:jd_pool:{key}:income_amt";
-
-        //    var result = EndPointCore.ProcessEndPointNodes<bool>(node =>
-        //    {
-        //        if (!node.is_public_api) return true;
-        //        if (string.IsNullOrEmpty(node.redis_server)) return true;
-
-        //        var redis = RedisClientManager.GetRedisClient(node.redis_server);
-        //        return redis.Set(cache_key, income_amt, 3 * 86400);
-        //    });
-        //}
-        //public static decimal GetIncomeAmt(int accountId)
-        //{
-        //    try
-        //    {
-        //        string key = $"{accountId}:{DateTime.Now:yyyyMMdd}";
-        //        if (_incomeAmt.ContainsKey(key)) return _incomeAmt[key];
-
-        //        string cache_key = $"cache:jd_pool:{key}:income_amt";
-        //        return RedisHelper.Get<decimal>(cache_key);
-        //    }
-        //    catch (Exception ex) { return 0; }
-        //}
-
+        } 
         internal static void CallsIncrBy(int accountId)
         {
             CallsIncrBy(accountId, DateTime.Now.ToString("yyyyMMdd"));

+ 319 - 0
molilian.core/Core/pdd/PddPoolCore.cs

@@ -0,0 +1,319 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.Filters;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using dodohold.core;
+using Dataoke;
+using Google.Protobuf.WellKnownTypes;
+using System.Diagnostics;
+using System.Text.Json;
+using TencentCloud.Tcm.V20210413.Models;
+using System.Security.Cryptography;
+using System.Collections.Concurrent;
+
+
+namespace molilian.core
+{
+    public partial class PddPoolCore
+    {
+        private static readonly object _lockObj = new();
+        private static IEnumerable<PddPoolDTO> _cached;
+
+        private static string _end_point;
+        private static Dictionary<string, decimal> _incomeAmt = new();
+        private static Dictionary<string, int> _calls = new();
+        private static ConcurrentDictionary<int, DateTime> _suspend = new();
+        static PddPoolCore()
+        {
+            _end_point = Environment.GetEnvironmentVariable("EndPoint");
+        }
+
+        public static PddPoolDTO? GetOne(PddUnionWorkMode mode, int accountid = 0)
+        {
+            var list = List();
+            if (!list.Any()) return null;
+            return list.Where(e => IsMatch(e, mode, accountid)).FirstOrDefault();
+        }
+
+
+        internal static void TempSuspend(int accountId)
+        {
+            _suspend.AddOrUpdate(accountId, DateTime.Now, (key, oldValue) => DateTime.Now);
+        }
+
+
+        private static bool IsMatch(PddPoolDTO item, PddUnionWorkMode mode, int accountid)
+        {
+            if (accountid != 0 && accountid != item.id) return false;
+            if (mode != PddUnionWorkMode.All && mode != item.work_mode) return false;
+
+            if (!string.IsNullOrEmpty(_end_point) && !string.IsNullOrEmpty(item.end_point))
+            {
+                if (item.end_point != _end_point) return false;
+            }
+
+            // 使用初始化参数创建工作时间表
+            if (!new WorkSchedule(item.time_range).IsWorkHour()) return false;
+
+
+            if (_suspend.TryGetValue(accountid, out DateTime suspendTime))
+            {
+                var ts = DateTime.Now - suspendTime;
+                if (ts.TotalSeconds < 70) return false;
+            }
+
+            if (item.daily_calls_limit > 0)
+            {
+                int daily_num = GetCalls(item.id, DateTime.Now.ToString("yyyyMMdd"));
+                if (daily_num >= item.daily_calls_limit) return false;
+            }
+            if (item.hourly_calls_limit > 0)
+            {
+                int hourly_num = GetCalls(item.id, DateTime.Now.ToString("yyyyMMddHH"));
+                if (hourly_num >= item.hourly_calls_limit) return false;
+            }
+            return true;
+        }
+
+        public static int GetCalls(int accountId, string flag)
+        {
+            try
+            {
+                string key = $"{accountId}:{flag}";
+                if (_calls.ContainsKey(key)) return _calls[key];
+
+                string cache_key = $"cache:jd_pool:{key}:calls:{flag}";
+                int num = RedisHelper.Get<int>(cache_key);
+                _calls.TryAdd(key, num);
+                return num;
+            }
+            catch (Exception ex) { return 0; }
+        }
+        internal static void CallsIncrBy(int accountId)
+        {
+            CallsIncrBy(accountId, DateTime.Now.ToString("yyyyMMdd"));
+            CallsIncrBy(accountId, DateTime.Now.ToString("yyyyMMddHH"));
+        }
+
+        internal static void CallsIncrBy(int accountId, string flag)
+        {
+            string key = $"{accountId}:{flag}";
+            if (_calls.ContainsKey(key))
+            {
+                _calls[key] = _calls[key] + 1;
+            }
+            else
+            {
+                _calls[key] = 1;
+            }
+            string cache_key = $"cache:pdd_pool:{key}:calls:{flag}";
+            RedisHelper.IncrBy(cache_key);
+            RedisHelper.Expire(cache_key, 3 * 86400);
+        }
+
+        public static int SaveCalls(int accountId, string flag)
+        {
+            string key = $"{accountId}:{flag}";
+            var result = EndPointCore.ProcessEndPointNodes<int>(node =>
+            {
+                if (!node.is_public_api) return 0;
+                if (string.IsNullOrEmpty(node.redis_server)) return 0;
+
+
+#if DEBUG
+                switch (node.name)
+                {
+
+                    case "bj":
+                        node.redis_server = "101.200.46.46:6379,password=pKBiS4ka2IpXayIdcx00,defaultDatabase=0,idleTimeout=20000,preheat=3,tryit=2,ssl=false,prefix=webhook";
+                        break;
+                    case "gz":
+                        node.redis_server = "8.138.110.158:6379,password=pKBiS4ka2IpXayIdcx00,defaultDatabase=0,idleTimeout=20000,preheat=3,tryit=2,ssl=false,prefix=webhook";
+                        break;
+                    case "coupon1":
+                        node.redis_server = "c1api.molilian.com:6379,password=pKBiS4ka2IpXayIdcx00,defaultDatabase=0,idleTimeout=20000,preheat=3,tryit=2,ssl=false,prefix=coupon";
+                        break;
+                    default: return 0;
+                }
+#endif
+
+                string cache_key = $"cache:pdd_pool:{key}:calls:{flag}";
+                var redis = RedisClientManager.GetRedisClient(node.redis_server);
+                return redis.Get<int>(cache_key);
+            });
+            int num = result.Sum();
+            _calls.TryAdd(key, num);
+            return num;
+        }
+
+
+
+        public static IEnumerable<PddPoolDTO> List(bool force = false)
+        {
+            if (!force && _cached != null) return _cached;
+
+            string cache_key = $"cache:pdd_pool";
+            var list = RedisHelper.Get<IEnumerable<PddPoolDTO>>(cache_key);
+            if (force || list == null)
+            {
+                lock (_lockObj)
+                {
+                    list = new DBContext.Table("pdd_pool")
+                        .Where("status=@status", new { status = 1 })
+                        .Select<PddPoolDTO>();
+                    if (list == null) return default;
+                    RedisHelper.Set(cache_key, list, 30 * 86400);
+                }
+            }
+            _cached = list;
+            return list;
+        }
+        public static void Refresh()
+        {
+            _ = List(true);
+        }
+
+        public static void Disabled(string name)
+        {
+            string cache_key = $"cache:pdd_pool:{name}:disabled";
+            long count = RedisHelper.IncrBy(cache_key);
+            RedisHelper.Expire(cache_key, 10);
+            if (count > 1) return;
+
+            new DBContext.Table("pdd_pool")
+                .Add("status", 0)
+                .Where("name=@name", new { name })
+                .Update();
+            _ = List(true);
+
+            NotifyCore.Notify(new NifyMessage
+            {
+                message = $"【多多:{name}】调用异常",
+                priority = NifyMessagePriority.high,
+                tags = ["red_circle"]
+            });
+        }
+
+
+        public static void Disabled(int accountId, string name, string content)
+        {
+            string cache_key = $"cache:pdd_pool:{name}:disabled";
+            long count = RedisHelper.IncrBy(cache_key);
+            RedisHelper.Expire(cache_key, 10);
+            if (count > 1) return;
+
+            var update = new DBContext.Table("pdd_pool").Add("status", 0);
+            if (accountId > 0)
+            {
+                update.Where("id=@accountId", new { accountId }).Update();
+            }
+            else
+            {
+                update.Where("name=@name", new { name }).Update();
+            }
+
+            _ = List(true);
+
+            NotifyCore.Notify(new NifyMessage
+            {
+                message = $"【多多{accountId}:{name}】cookie 掉线\n\n{content}",
+                priority = NifyMessagePriority.high,
+                tags = ["red_circle"]
+            });
+
+            NotifyCore.AnPushNotify("掉线", $"【多多{accountId}:{name}】cookie 掉线");
+            EndPointCore.NotifyReload(true);
+        }
+
+        internal static void AccountExhausted()
+        {
+            string cache_key = $"cache:pdd_pool:account:exhausted";
+            long count = RedisHelper.IncrBy(cache_key);
+            if (count > 1) return;
+            RedisHelper.Expire(cache_key, 3600);
+            NotifyCore.Notify(new NifyMessage
+            {
+                message = $"【多多】没有匹配账号",
+                priority = NifyMessagePriority.high,
+                tags = ["red_circle"]
+            });
+            NotifyCore.AnPushNotify("没账号", $"【多多】没有匹配账号");
+        }
+
+
+
+        public static int UpdateCookies(string cookies, string user_agent)
+        {
+            if (string.IsNullOrEmpty(cookies)) return 0;
+            string pin = cookies.GetContentPart("pin=", ";");
+            pin = pin.UrlDecode();
+
+            string company = pin;
+            int accountId = 0;
+            if (string.IsNullOrEmpty(pin)) return 0;
+            var exist = new DBContext.Table("pdd_pool").Get<JdPoolDTO>("pin=@pin", new { pin });
+            if (exist != null)
+            {
+                var status = exist.status;
+                var work_mode = exist.work_mode;
+                accountId = exist.id;
+                if (work_mode == JdUnionWorkMode.Crawler) status = true;
+                new DBContext.Table("pdd_pool")
+                   .Add("pin", pin)
+                   .Add("cookies", cookies)
+                   .Add("user_agent", user_agent)
+                   .Add("status", status)
+                   .Add("last_time", DateTime.Now)
+                   .Add("login_time", DateTime.Now)
+                   .Where("id=@id", new { exist.id })
+                   .Update();
+                if (status) _ = List(true);
+            }
+            else
+            {
+                accountId = new DBContext.Table("pdd_pool")
+                    .Add("pin", pin)
+                    .Add("name", pin)
+                    .Add("company", pin)
+                    .Add("description", "由cookies上报创建此记录")
+                    .Add("cookies", cookies)
+                    .Add("user_agent", user_agent)
+                    .Add("create_time", DateTime.Now)
+                    .Add("last_time", DateTime.Now)
+                    .Add("login_time", DateTime.Now)
+                    .Add("status", 0)
+                    .Create();
+            }
+
+            NotifyCore.Notify(new NifyMessage
+            {
+                message = $"【拼多多{accountId}:{company}】cookie 上线",
+                tags = ["green_circle"]
+            });
+            EndPointCore.NotifyReload(true);
+            //NotifyCore.AnPushNotify("上线", $"【淘宝联盟:{dnk}】cookie 上报更新");
+            return accountId;
+        }
+
+
+        public static int Update(PddPoolDTO account)
+        {
+            return new DBContext.Table("pdd_pool")
+                .Add("current_hourly_calls", account.current_hourly_calls)
+                .Add("current_daily_calls", account.current_daily_calls)
+
+                //.Add("today_clickNum", account.today_clickNum)
+                //.Add("today_cosFee", account.today_cosFee)
+                //.Add("today_cosPrice", account.today_cosPrice)
+                //.Add("today_finishCosFee", account.today_finishCosFee)
+                //.Add("today_finishCosPrice", account.today_finishCosPrice)
+                //.Add("today_finishOrderNum", account.today_finishOrderNum)
+                //.Add("today_orderNum", account.today_orderNum)
+                .Where("id=@id", new { account.id })
+                .Update();
+        }
+    }
+}

+ 23 - 0
molilian.core/Core/pdd/goods.cs

@@ -0,0 +1,23 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.Filters;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using dodohold.core;
+using Dataoke;
+using Google.Protobuf.WellKnownTypes;
+using System.Diagnostics;
+using System.Text.Json;
+using TencentCloud.Tcm.V20210413.Models;
+using System.Security.Cryptography;
+
+
+namespace molilian.core
+{
+    public partial class PddPoolCore
+    {
+
+    }
+}

+ 32 - 0
molilian.core/Core/pdd/union.cs

@@ -0,0 +1,32 @@
+using System.Text;
+using dodohold.core;
+
+namespace molilian.core
+{
+    public partial class PddPoolCore
+    {
+        public static Dictionary<string, string> GenerateSignature(PddPoolDTO account, Dictionary<string, string> args)
+        {
+            if (args.ContainsKey("sign")) args.Remove("sign");
+            // 对参数进行ASCII升序排序
+            var sortedArgs = args.OrderBy(kv => kv.Key).ToDictionary(kv => kv.Key, kv => kv.Value);
+
+            // 拼接排序后的参数
+            StringBuilder stringBuilder = new StringBuilder();
+            foreach (var kv in sortedArgs)
+            {
+                stringBuilder.Append(kv.Key).Append(kv.Value);
+            }
+
+            // 在头部和尾部分别拼接client_secret
+            string signString = account.app_secret + stringBuilder.ToString() + account.app_secret;
+            signString = signString.MD5(false, false);
+
+            if (!args.TryAdd("sign", signString))
+            {
+                args["sign"] = signString;
+            }
+            return args;
+        }
+    }
+}

+ 0 - 101
molilian.core/Core/taoke/PddPoolCore.cs

@@ -1,101 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc.Controllers;
-using Microsoft.AspNetCore.Mvc.Filters;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using dodohold.core;
-using Dataoke;
-using Google.Protobuf.WellKnownTypes;
-using System.Diagnostics;
-using System.Text.Json;
-using TencentCloud.Tcm.V20210413.Models;
-using System.Security.Cryptography;
-
-
-namespace molilian.core
-{
-    public partial class PddPoolCore
-    {
-        private static readonly object _lockObj = new();
-        private static IEnumerable<PddPoolDTO> _cached;
-        public static PddPoolDTO? GetOne()
-        {
-            var list = List();
-            if (!list.Any()) return null;
-            return list.OrderBy(l => Guid.NewGuid()).FirstOrDefault();
-        }
-
-        public static IEnumerable<PddPoolDTO> List(bool force = false)
-        {
-            if (!force && _cached != null) return _cached;
-
-            string cache_key = $"cache:pdd_pool";
-            var list = RedisHelper.Get<IEnumerable<PddPoolDTO>>(cache_key);
-            if (force || list == null)
-            {
-                lock (_lockObj)
-                {
-                    list = new DBContext.Table("pdd_pool")
-                        .Where("status=@status", new { status = 1 })
-                        .Select<PddPoolDTO>();
-                    if (list == null) return default;
-                    RedisHelper.Set(cache_key, list, 30 * 86400);
-                }
-            }
-            _cached = list;
-            return list;
-        }
-        public static void Refresh()
-        {
-            _ = List(true);
-        }
-
-        public static void Disabled(string name)
-        {
-            string cache_key = $"cache:pdd_pool:{name}:disabled";
-            long count = RedisHelper.IncrBy(cache_key);
-            RedisHelper.Expire(cache_key, 10);
-            if (count > 1) return;
-
-            new DBContext.Table("pdd_pool")
-                .Add("status", 0)
-                .Where("name=@name", new { name })
-                .Update();
-            _ = List(true);
-
-            NotifyCore.Notify(new NifyMessage
-            {
-                message = $"【多多:{name}】调用异常",
-                priority = NifyMessagePriority.high,
-                tags = ["red_circle"]
-            });
-        }
-
-
-        public static Dictionary<string, string> GenerateSignature(PddPoolDTO account, Dictionary<string, string> args)
-        {
-            if (args.ContainsKey("sign")) args.Remove("sign");
-            // 对参数进行ASCII升序排序
-            var sortedArgs = args.OrderBy(kv => kv.Key).ToDictionary(kv => kv.Key, kv => kv.Value);
-
-            // 拼接排序后的参数
-            StringBuilder stringBuilder = new StringBuilder();
-            foreach (var kv in sortedArgs)
-            {
-                stringBuilder.Append(kv.Key).Append(kv.Value);
-            }
-
-            // 在头部和尾部分别拼接client_secret
-            string signString = account.app_secret + stringBuilder.ToString() + account.app_secret;
-            signString = signString.MD5(false, false);
-
-            if (!args.TryAdd("sign", signString))
-            {
-                args["sign"] = signString;
-            }
-            return args;
-        }
-    }
-}

+ 130 - 1
molilian.core/Core/taoke/TkLogCore.cs

@@ -29,6 +29,8 @@ namespace molilian.core
 
         static string queue_parse_tb_key = "queue:parse_logs:tb";
         static string queue_parse_jd_key = "queue:parse_logs:jd";
+        static string queue_parse_pdd_key = "queue:parse_logs:pdd";
+
         static string queue_parse_dy_key = "queue:parse_logs:dy";
         static string queue_parse_tool_key = "queue:parse_logs:tool";
 
@@ -154,6 +156,33 @@ namespace molilian.core
                 .Add("create_time", data.create_time)
                 .Create(DBContext.InsertType.NORMAL, transaction);
         }
+        private static int save_pdd_parse_logs(PddDataDTO data, string tablename, IDbConnection connection, IDbTransaction transaction)
+        {
+            return new DBContext.Table(connection, tablename)
+                .Add("end_point", data.end_point)
+                .Add("channel", (int)data.channel)
+                .Add("accountId", data.accountId)
+                .Add("accountName", data.accountName)
+                .Add("rawContent", data.rawContent)
+                .Add("success", data.success)
+                .Add("message", data.message)
+                .Add("reason", data.reason)
+                .Add("content", data.content)
+                .Add("itemId", data.itemId)
+                .Add("itemName", data.itemName)
+                .Add("pic", data.pic)
+                .Add("couponAmount", data.couponAmount)
+                .Add("promotionPrice", data.promotionPrice)
+                .Add("taoToken", data.taoToken)
+                .Add("shortLinkurl", data.shortLinkurl)
+                .Add("deeplink_url", data.deeplink_url)
+                .Add("elapsedTime", data.elapsedTime)
+                .Add("subCode", data.subCode)
+                .Add("ip", data.ip)
+                .Add("oaid", data.oaid)
+                .Add("create_time", data.create_time)
+                .Create(DBContext.InsertType.NORMAL, transaction);
+        }
         public static int BatchInsertLogDB(int limit, CSRedisClient redis)
         {
             int total = 0;
@@ -300,6 +329,30 @@ namespace molilian.core
                     total++;
                 }
                 for (int i = 0; i < limit; i++)
+                {
+                    var data = redis.LPop<PddDataDTO>(queue_parse_pdd_key);
+                    if (data == null) break;
+
+
+                    if (data.ip.Contains("127.0.0"))
+                    {
+                        save_pdd_parse_logs(data, "pdd_parse_logs_test", connection, transaction);
+                    }
+                    else
+                    {
+                        save_pdd_parse_logs(data, "pdd_parse_logs", connection, transaction);
+                        if (data.elapsedTime > 1000)
+                        {
+                            save_pdd_parse_logs(data, "pdd_parse_logs_test", connection, transaction);
+                        }
+                        if (data.success)
+                        {
+                            save_pdd_parse_logs(data, "pdd_parse_logs_success", connection, transaction);
+                        }
+                    }
+                    total++;
+                }
+                for (int i = 0; i < limit; i++)
                 {
                     var data = redis.LPop<DyDataDTO>(queue_parse_dy_key);
                     if (data == null) break;
@@ -403,6 +456,12 @@ namespace molilian.core
                 {
                     var data = redis.LPop<PromotionQueryDTO>(promotion_img_key);
                     if (data == null) break;
+
+                    if (data.success)
+                    {
+                        data.similarPromotion = string.Empty;
+                        data.promotionImg = string.Empty;
+                    }
                     connection.Insert(data);
                     total++;
                 }
@@ -460,7 +519,6 @@ namespace molilian.core
             }
             catch (Exception ex) { }
         }
-
         public static async Task LogAsync(TkDataDTO response, AlimamaPlus? alimamaPlus = null)
         {
             try
@@ -560,6 +618,7 @@ namespace molilian.core
                 .SaveAsync();
             }
         }
+
         public static async Task CouponLogAsync(UnionCouponDTO response, AlimamaPlus? alimamaPlus = null)
         {
             try
@@ -674,6 +733,76 @@ namespace molilian.core
             }
             catch (Exception ex) { }
         }
+        public static async Task ParseLogAsync(PddDataDTO response)
+        {
+            try
+            {
+                var ts = DateTime.Now - response.create_time;
+                response.elapsedTime = (int)ts.TotalMilliseconds;
+                _ = RedisHelper.RPushAsync(queue_parse_pdd_key, response);
+
+
+#if DEBUG
+                for (int i = 0; i < 100; i++)
+                {
+                    var data = RedisHelper.LPop<PddDataDTO>(queue_parse_pdd_key);
+                    if (data == null) break;
+
+
+                    if (data.ip.Contains("127.0.0"))
+                    {
+                        save_pdd_parse_logs(data, "pdd_parse_logs_test", null, null);
+                    }
+                    else
+                    {
+                        save_pdd_parse_logs(data, "pdd_parse_logs", null, null);
+                        if (data.elapsedTime > 1000)
+                        {
+                            save_pdd_parse_logs(data, "pdd_parse_logs_test", null, null);
+                        }
+                        if (data.success)
+                        {
+                            save_pdd_parse_logs(data, "pdd_parse_logs_success", null, null);
+                        }
+                    }
+                }
+
+#endif
+
+                if (!response.ip.Contains("127.0.0"))
+                {
+                    saveParseCache(response.channel.ToString(), response.accountId, response.accountName, response.success, response.message, response.reason);
+                }
+
+                if (response.success || response.message.Equals("转链失败"))
+                {
+                    PddPoolCore.CallsIncrBy(response.accountId);
+                }
+
+                if (response.reason.Equals("您的调用次数过高"))
+                {
+                    PddPoolCore.TempSuspend(response.accountId);
+                }
+
+                if (response.success) saveClientRequestTotal(response.channel, response.ip, response.oaid);
+
+                if (!response.success && ("nologin".Equals(response.reason) ||
+                    "方法不存在".Equals(response.reason) ||
+                    "未登录".Equals(response.reason)))
+                {
+                    await Task.Run(() =>
+                    {
+                        PddPoolCore.Disabled(response.accountId, response.accountName, $"{response.rawContent}\n{response.rawContent2}");
+                    });
+                }
+                if ("没有匹配账号".Equals(response.reason))
+                {
+                    PddPoolCore.AccountExhausted();
+                }
+            }
+            catch (Exception ex) { }
+        }
+
         public static async Task ParseLogAsync(DyDataDTO response)
         {
             try

+ 84 - 0
molilian.core/Core/taoke/UnionParseCore.cs

@@ -37,6 +37,7 @@ namespace molilian.core
                 "bdpan" => PanParse(content, ip, oaid),
                 "jd" => await JdParseAsync(content, ip, oaid, accountid),
                 "dy" => await DyParseAsync(content, ip, oaid),
+                "pdd" => await PddParseAsync(content, ip, oaid, accountid),
                 _ => await TaobaoParseAsync(content, ip, oaid, accountid),
             };
         }
@@ -573,6 +574,89 @@ namespace molilian.core
             }, IfExceptional ? APIResultCodeEnum.NotAcceptable : APIResultCodeEnum.OK);
         }
 
+        public static async Task<APIResult> PddParseAsync(string content, string ip, string oaid,
+            int accountid = 0, CancellationToken cancellationToken = default)
+        {
+            var result = PddUnionPlus.GetFormattedObject(content, ip, oaid);
+            content = content.UrlDecode();
+            result.rawContent = content;
+            bool IfExceptional = false;
+            try
+            {
+                var config = TkConfigCore.Get();
+
+                //============================== 放弃转链-地区过滤 ==============================
+                if (accountid == 0 && PddUnionPlus.ShouldIgnoreRequest(config, ip, oaid, out string reason))
+                {
+                    result.success = false;
+                    result.message = "放弃转链";
+                    result.reason = reason;
+                    _ = TkLogCore.ParseLogAsync(result);
+                    return PddParseOutput(result);
+                }
+                var account = PddPoolCore.GetOne(PddUnionWorkMode.All, accountid);
+                if (account == null)
+                {
+                    result.success = false;
+                    result.message = "放弃转链";
+                    result.reason = "没有匹配账号";
+                    _ = TkLogCore.ParseLogAsync(result);
+                    return PddParseOutput(result);
+                }
+                result.accountId = account.id;
+                result.accountName = account.name;
+
+                var plus = new PddUnionPlus(account);
+
+                result = await plus.PddParseAsync(content, result, cancellationToken);
+            }
+            catch (Exception ex)
+            {
+                if (ex.Message.Contains("was canceled"))
+                {
+                    result.success = false;
+                    result.message = "放弃转链";
+                    result.reason = "请求超时";
+                }
+                else
+                {
+                    IfExceptional = true;
+                    _ = new LoggerLibrary("unionParse", "pdd_error")
+                        .Info(ip, oaid)
+                        .Info(content)
+                        .Info(ex.Message, ex.StackTrace)
+                        .SaveAsync();
+                    NotifyCore.Notify(new NifyMessage
+                    {
+                        message = $"【转链异常PDD】\n{content}\n\n{ex.Message}\n{ex.StackTrace}",
+                        priority = NifyMessagePriority.high,
+                        tags = ["red_circle"]
+                    });
+                    result.success = false;
+                    result.message = "内部错误";
+                    result.reason = "转链接口异常";
+                }
+            }
+            _ = TkLogCore.ParseLogAsync(result);
+            return PddParseOutput(result, IfExceptional ? APIResultCodeEnum.NotAcceptable : APIResultCodeEnum.OK);
+
+        }
+
+        private static APIResult PddParseOutput(PddDataDTO result, APIResultCodeEnum code = APIResultCodeEnum.OK)
+        {
+            return new APIResult(new
+            {
+                result.success,
+                result.message,
+                link_type = result.link_type.ToString(),
+                channel = result?.channel.ToString(),
+                result.itemId,
+                result.itemName,
+                result.shortLinkurl,
+                result.deeplink_url,
+            }, code);
+        }
+
     }
 
 }

+ 1 - 0
molilian.core/DTO/Emun/LinkTypeEnum.cs

@@ -18,5 +18,6 @@
         tb= 1,
         jd = 2,
         dy = 3,
+        pdd = 4,
     }
 }

+ 5 - 1
molilian.core/DTO/alimama/TkConfigDTO.cs

@@ -29,6 +29,10 @@ namespace molilian.core
         public int jd_limit_per_ip_24h { get; set; } = 0;
         public int tk_limit_per_ip_24h { get; set; } = 0;
         public string cpsIgnorePercentageCity { get; set; } = string.Empty;
-        public int cps_limit_per_ip_24h { get; set; } = 0; 
+        public int cps_limit_per_ip_24h { get; set; } = 0;
+
+        public int pddIgnorePercentage { get; set; } = 0;
+        public string pddIgnorePercentageCity { get; set; } = string.Empty;
+        public int pdd_limit_per_ip_24h { get; set; } = 0;
     }
 }

+ 1 - 2
molilian.core/DTO/jd/JdPoolDTO.cs

@@ -26,7 +26,6 @@
         public string user_agent { get; set; } = string.Empty;
         public string cookies { get; set; } = string.Empty;
 
-
         public string nodeName { get; set; } = string.Empty;
         public string end_point { get; set; } = string.Empty;
         public decimal current_amt { get; set; } = 0;
@@ -41,7 +40,6 @@
         public bool enable_sync_order { get; set; } = false;
         public int time_range { get; set; } = 0;
 
-
         public int today_clickNum { get; set; } = 0;
         public decimal today_cosFee { get; set; } = 0;
         public decimal today_cosPrice { get; set; } = 0;
@@ -49,6 +47,7 @@
         public decimal today_finishCosPrice { get; set; } = 0;
         public int today_finishOrderNum { get; set; } = 0;
         public int today_orderNum { get; set; } = 0;
+        public bool is_hide { get; set; } = false;
 
     }
 }

+ 34 - 0
molilian.core/DTO/pdd/PddDataDTO.cs

@@ -0,0 +1,34 @@
+namespace molilian.core
+{
+    public class PddDataDTO
+    {
+        public TkChannelEnum channel { get; set; }
+        public LinkTypeEnum link_type { get; set; }
+        public ChannelTypeEnum channel_type { get; set; } = ChannelTypeEnum.none;
+        public int accountId { get; set; } = 0;
+        public string accountName { get; set; } = string.Empty;
+        public bool success { get; set; } = true;
+        public string message { get; set; } = string.Empty;
+        public string reason { get; set; } = string.Empty;
+        public string content { get; set; } = string.Empty;
+        public string taoToken { get; set; } = string.Empty;
+        public string rawContent { get; set; } = string.Empty;
+        public string rawContent2 { get; set; } = string.Empty;
+        public string ip { get; set; } = string.Empty;
+        public string oaid { get; set; } = string.Empty;
+
+        public string itemId { get; set; } = string.Empty;
+        public string itemName { get; set; } = string.Empty;
+        public decimal couponAmount { get; set; } = 0;
+        public decimal promotionPrice { get; set; } = 0;
+        public string pic { get; set; } = string.Empty;
+
+        public string shortLinkurl { get; set; } = string.Empty;
+        public string deeplink_url { get; set; } = string.Empty;
+        public int elapsedTime { get; set; } = 0;
+        public DateTime create_time { get; set; } = DateTime.Now;
+        public string end_point { get; set; } = string.Empty;
+        public int subCode { get; set; } = 0;
+    }
+
+}

+ 34 - 4
molilian.core/DTO/pdd/PddPoolDTO.cs

@@ -1,15 +1,45 @@
-namespace molilian.core
+using System.Xml.Linq;
+
+namespace molilian.core
 {
+    public enum PddUnionWorkMode
+    {
+        All = 0,
+        SiteApi = 1,
+        AffApi = 2,
+        Crawler = 3,
+    }
+
     public class PddPoolDTO
     {
         public int id { get; set; }
         public string name { get; set; } = string.Empty;
-        public string description { get; set; } = string.Empty;
+        public string nodeName { get; set; } = string.Empty;
+        public string end_point { get; set; } = string.Empty;
         public string app_key { get; set; } = string.Empty;
         public string app_secret { get; set; } = string.Empty;
-        public DateTime create_time { get; set; }
-        public DateTime last_time { get; set; }
+        public string pid { get; set; } = string.Empty;
+        public string company { get; set; } = string.Empty;
+        public string description { get; set; } = string.Empty;
+        public DateTime create_time { get; set; } = DateTime.Now;
+        public DateTime last_time { get; set; } = DateTime.Now;
+        public DateTime login_time { get; set; } = DateTime.Now;
         public bool status { get; set; }
+        public PddUnionWorkMode work_mode { get; set; } = PddUnionWorkMode.SiteApi;
+        public string cookies { get; set; } = string.Empty;
+
+
+        public decimal daily_income_limit { get; set; } = 0;
+        public int daily_calls_limit { get; set; } = 0;
+        public int current_hourly_calls { get; set; } = 0;
+        public int hourly_calls_limit { get; set; } = 0;
+        public int current_daily_calls { get; set; } = 0;
+        public decimal draw_balance { get; set; } = 0;
+        public bool enable_parse { get; set; } = false;
+        public bool enable_coupon { get; set; } = false;
+        public bool enable_sync_order { get; set; } = false;
+        public int time_range { get; set; } = 0;
+        public bool is_hide { get; set; } = true;
 
     }
 }

+ 10 - 3
molilian.core/Plus/JDUnion/JdDailyLogs.cs

@@ -34,10 +34,13 @@ namespace molilian.core
             using var conn = CenterHub.GetOpenConnection();
 
 
+
+            int all_total_count = 0, all_success_count = 0, all_abandon_count = 0;
             foreach (var account in accounts)
             {
                 int accountId = account.id;
                 string accountName = $"{channelEnum}_{account.id}";
+                //if (account.is_hide) continue;
 
                 int total_count = TkLogCore.GetTotal($":parse_total:{accountName}:{log_date:yyyyMMdd}");
                 if (total_count == 0) accountName = account.name;
@@ -55,6 +58,9 @@ namespace molilian.core
                     success_percentage = $"{success_count / (double)total_count * 100:f2}%";
                     abandon_percentage = $"{abandon_count / (double)total_count * 100:f2}%";
                 }
+                //all_total_count += total_count;
+                //all_success_count += success_count;
+                //all_abandon_count += abandon_count;
 
                 var exist = new DBContext.Table(conn, "center_daily_logs")
                 .Fields("id,log_date")
@@ -85,9 +91,10 @@ namespace molilian.core
                 }
             }
 
-            int all_total_count = TkLogCore.GetTotal($":parse_total:{channelEnum}:{log_date:yyyyMMdd}");
-            var all_success_count = TkLogCore.GetTotal($":parse_total:{channelEnum}:success:{log_date:yyyyMMdd}");
-            var all_abandon_count = TkLogCore.GetTotal($":parse_total:{channelEnum}:放弃转链:{log_date:yyyyMMdd}");
+            all_total_count = TkLogCore.GetTotal($":parse_total:{channelEnum}:{log_date:yyyyMMdd}");
+            all_success_count = TkLogCore.GetTotal($":parse_total:{channelEnum}:success:{log_date:yyyyMMdd}");
+            all_abandon_count = TkLogCore.GetTotal($":parse_total:{channelEnum}:放弃转链:{log_date:yyyyMMdd}");
+
 
             string all_success_percentage = string.Empty;
             string all_abandon_percentage = string.Empty;

+ 1 - 19
molilian.core/Plus/JDUnion/base.cs

@@ -1,24 +1,6 @@
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc.Controllers;
-using Microsoft.AspNetCore.Mvc.Filters;
-using System;
-using System.Collections.Generic;
-using System.Linq;
+
 using System.Text;
 using dodohold.core;
-using Dataoke;
-using System.Text.RegularExpressions;
-using Org.BouncyCastle.Ocsp;
-using System.Diagnostics;
-using TencentCloud.Fmu.V20191213.Models;
-using Microsoft.VisualBasic;
-using System.Text.Json;
-using static System.Runtime.InteropServices.JavaScript.JSType;
-using System.Security.Cryptography;
-using System.Security.Policy;
-using Google.Protobuf.WellKnownTypes;
-using Microsoft.AspNetCore.Components;
-using Org.BouncyCastle.Pqc.Crypto.Ntru;
 using System.Net;
 
 

+ 115 - 0
molilian.core/Plus/pdd/PddUnionPlus.cs

@@ -0,0 +1,115 @@
+using dodohold.core;
+using System.Text.RegularExpressions;
+
+namespace molilian.core
+{
+    public partial class PddUnionPlus
+    {
+        public static string _url_pattern = @"https?://(?:[\w-]+\.)*(?:yangkeduo\.com|pinduoduo\.com)(?:/[^\s]*)?";
+        public static string GetLink(string content)
+        {
+            if (string.IsNullOrEmpty(content)) return content;
+            string result = content;
+            //
+            Regex regex = new(_url_pattern);
+            MatchCollection matches = regex.Matches(content);
+
+            foreach (Match m in matches.Cast<Match>())
+            {
+                string url = m.Value;
+                return url;
+            }
+            return string.Empty;
+        }
+
+
+        public static string GetDeeplink(string url)
+        {
+            string result = $"pinduoduo://com.xunmeng.pinduoduo/{url}";
+            return result;
+        }
+
+        public static PddDataDTO GetFormattedObject(string content, string ip = "", string oaid = "")
+        {
+            string shortLinkurl = GetLink(content);
+            string deeplink_url = GetDeeplink(shortLinkurl);
+            return new PddDataDTO()
+            {
+                message = string.Empty,
+                link_type = LinkTypeEnum.unknown,
+                channel = TkChannelEnum.pdd,
+                accountName = string.Empty,
+                success = false,
+                content = content,
+                ip = ip,
+                oaid = oaid,
+                elapsedTime = 0,
+                itemName = "点击打开拼多多APP",
+                shortLinkurl = string.Empty,
+                deeplink_url = string.Empty,
+                create_time = DateTime.Now,
+                end_point = _end_point,
+            };
+        }
+
+        public async Task<PddDataDTO> PddParseAsync(string content, PddDataDTO result, CancellationToken cancellationToken = default)
+        {
+            string message = "OK";
+            string url = GetLink(content);
+            if (string.IsNullOrEmpty(url))
+            {
+                result.success = false;
+                result.link_type = LinkTypeEnum.unknown;
+                result.channel_type = ChannelTypeEnum.pdd;
+                result.message = "放弃转链";
+                result.reason = "无效链接";
+                result.accountId = 0;
+                result.accountName = string.Empty;
+                result.content = content;
+                return result;
+            }
+            string shortLinkurl = url;
+
+            if (result.link_type == LinkTypeEnum.other_aff)
+            {
+                result.success = false;
+                result.link_type = LinkTypeEnum.unknown;
+                result.channel_type = ChannelTypeEnum.pdd;
+                result.message = "放弃转链";
+                result.reason = "其他推广链接";
+                result.accountId = 0;
+                result.accountName = string.Empty;
+                result.content = content;
+                return result;
+            }
+
+            if (!result.ip.StartsWith("127.0.0") && FlowControlIgnoreRequest(_config, out string reason))
+            {
+                result.success = false;
+                result.link_type = LinkTypeEnum.unknown;
+                result.channel_type = ChannelTypeEnum.pdd;
+                result.message = "放弃转链";
+                result.reason = reason;
+                result.accountId = 0;
+                result.accountName = string.Empty;
+                result.content = content;
+                return result;
+            }
+
+            switch (_account.work_mode)
+            {
+                //case PddUnionWorkMode.SiteApi:
+                //    result = await GetPromotionBySiteAsync(result, url, cancellationToken);
+                //    break;
+                //case PddUnionWorkMode.AffApi:
+                //    result = await GetPromotionByAffAsync(result, url, cancellationToken);
+                //    break;
+                case PddUnionWorkMode.Crawler:
+                default:
+                    result = await transferUrl(result, url, cancellationToken);
+                    break;
+            }
+            return result;
+        }
+    }
+}

+ 115 - 0
molilian.core/Plus/pdd/base.cs

@@ -0,0 +1,115 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.Filters;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using dodohold.core;
+using Dataoke;
+using System.Text.RegularExpressions;
+using Org.BouncyCastle.Ocsp;
+using System.Diagnostics;
+using TencentCloud.Fmu.V20191213.Models;
+using Microsoft.VisualBasic;
+using System.Text.Json;
+using static System.Runtime.InteropServices.JavaScript.JSType;
+using System.Security.Cryptography;
+using System.Security.Policy;
+using Google.Protobuf.WellKnownTypes;
+using Microsoft.AspNetCore.Components;
+using Org.BouncyCastle.Pqc.Crypto.Ntru;
+using System.Net;
+
+
+namespace molilian.core
+{
+    public partial class PddUnionPlus
+    {
+        static Random _random = new Random();
+        private WebProxy? _proxy = null;
+
+        public TkConfigDTO _config;
+        private static PddPoolDTO _account;
+        private static string _end_point;
+
+        static PddUnionPlus()
+        {
+            _end_point = Environment.GetEnvironmentVariable("EndPoint");
+        }
+
+        public PddUnionPlus(PddPoolDTO account)
+        {
+            _account = account;
+            _config = TkConfigCore.Get();
+
+            if (!string.IsNullOrEmpty(account.nodeName))
+            {
+                _proxy = ProxyNodesCore.GetOne(account.nodeName);
+            }
+        }
+           
+        public static bool ShouldIgnoreRequest(TkConfigDTO config, string ip, string oaid, out string reason)
+        {
+            reason = string.Empty;
+            try
+            {
+                // IP和流量控制
+                string ignorePercentageCity = config.pddIgnorePercentageCity;
+                string? ipInfo = IP2RegionPlus.Search(ip);
+                if (AlimamaPlus.IgnoreRegionIncluded(ignorePercentageCity, ipInfo, out string regionInfo))
+                {
+                    reason = $"地区控制:{regionInfo}";
+                    return true;
+                }
+
+                int limit_num = config.pdd_limit_per_ip_24h;
+                if (limit_num > 0)
+                {
+                    int num = TkLogCore.getClientRequestTotalByIp(TkChannelEnum.pdd, ip);
+                    if (num > limit_num)
+                    {
+                        reason = "IP控制";
+                        return true;
+                    }
+                    num = TkLogCore.getClientRequestTotalByOAID(TkChannelEnum.pdd, oaid);
+                    if (num > limit_num)
+                    {
+                        reason = "OAID控制";
+                        return true;
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                reason = "配置异常";
+            }
+            return false;
+        }
+
+        public static bool FlowControlIgnoreRequest(TkConfigDTO config, out string reason)
+        {
+            reason = string.Empty;
+            try
+            {
+                // IP和流量控制
+                int ignorePercentage = config.pddIgnorePercentage;
+                if (ignorePercentage == 0) return false;
+
+
+                var randomValue = (decimal)_random.Next(0, 100);
+                bool result = randomValue <= ignorePercentage; // 如果生成的随机数小于忽略百分比,则返回 true,表示需要忽略请求
+                if (result)
+                {
+                    reason = "流量控制";
+                    return true;
+                }
+            }
+            catch (Exception ex)
+            {
+                reason = $"配置异常";
+            }
+            return false;
+        }
+    }
+}

+ 194 - 0
molilian.core/Plus/pdd/goods.cs

@@ -0,0 +1,194 @@
+using dodohold.core;
+using Sayaka.Common;
+using System.Text.RegularExpressions;
+
+namespace molilian.core
+{
+    public class PddTransferUrlResult
+    {
+        public string multiGroupShortUrl { get; set; } = string.Empty;
+        public string multiGroupUrl { get; set; } = string.Empty;
+        public string shortUrl { get; set; } = string.Empty;
+        public string url { get; set; } = string.Empty;
+    }
+
+    public class PddTransferUrlResponse
+    {
+        public int errorCode { get; set; }
+        public string errorMsg { get; set; } = string.Empty;
+        public bool success { get; set; } = false;
+        public PddTransferUrlResult result { get; set; } = new();
+    }
+
+    public class PddCreatePromotionUrlResult
+    {
+        public string multiGroupShortUrl { get; set; } = string.Empty;
+        public string multiGroupUrl { get; set; } = string.Empty;
+        public string shortUrl { get; set; } = string.Empty;
+        public string url { get; set; } = string.Empty;
+    }
+
+    public class PddCreatePromotionUrlResponse
+    {
+        public int errorCode { get; set; }
+        public string errorMsg { get; set; } = string.Empty;
+        public bool success { get; set; } = false;
+        public PddCreatePromotionUrlResult result { get; set; } = new();
+    }
+
+    public partial class PddUnionPlus
+    {
+        public async Task<PddDataDTO> transferUrl(PddDataDTO result, string sourceUrl, CancellationToken cancellationToken = default)
+        {
+            var ts = DateTime.Now.Convert2UnixTimestamp(true);
+            string cookies = _account.cookies.Trim();
+
+            string useragent = ProviderFakeUserAgent.RandomComputer;
+            string url = "https://jinbao.pinduoduo.com/network/api/promotion/transferUrl";
+
+            //{"pid":"13848803_189356569","sourceUrl":"https://p.pinduoduo.com/1OAsct0r"}
+
+            var args = new
+            {
+                _account.pid,
+                sourceUrl = sourceUrl.UrlDecode(),
+            };
+            string data = args.Convert2Json();
+
+            WebClientUtility client = new WebClientUtility();
+            client.Proxy = _proxy;
+#if DEBUG
+            client.Proxy = null;
+#endif
+            client.SetContentType("application/json");
+            client.AddHeaders("Referer", "https://jinbao.pinduoduo.com/promotion/url-promotion");
+            client.AddHeaders("Origin", "https://jinbao.pinduoduo.com");
+            client.UserAgent = useragent;
+            client.AddHeaders("Cookie", cookies);
+            client.Post(data);
+            var response = await client.RequestAsync(url, "POST", cancellationToken);
+
+            string body = response.Body();
+            var root = body.Convert2Object<PddTransferUrlResponse>();
+            string message = string.Empty;
+
+            if (!root.success)
+            {
+                message = $"{root.errorCode}:{root.errorMsg}";
+                result.success = false;
+                result.message = "转链失败";
+                result.reason = message;
+                _ = new LoggerLibrary("PddUnion", "transferUrl").Info(body).SaveAsync();
+                return result;
+            }
+
+            if (string.IsNullOrEmpty(root.result?.multiGroupShortUrl))
+            {
+                result.success = false;
+                result.message = "转链失败";
+                result.reason = "无法转链";
+                //_ = new LoggerLibrary("PddUnion", "transferUrl").Info(body).SaveAsync();
+                return result;
+            }
+
+            if (!string.IsNullOrEmpty(root.result?.url))
+            {
+                result.itemId = root.result?.url.GetContentPart("goods_id=", "&");
+            }
+
+            result.success = true;
+            result.message = "OK";
+            result.link_type = LinkTypeEnum.goods;
+            result.shortLinkurl = root.result?.multiGroupShortUrl;
+            result.content = result.shortLinkurl;
+            result.deeplink_url = GetDeeplink(result.shortLinkurl);
+
+
+            return result;
+        }
+
+
+        public async Task<PddDataDTO> createPromotionUrl(PddDataDTO result, string sourceUrl, CancellationToken cancellationToken = default)
+        {
+            var ts = DateTime.Now.Convert2UnixTimestamp(true);
+            string cookies = _account.cookies.Trim();
+
+            string useragent = ProviderFakeUserAgent.RandomComputer;
+            string url = "https://jinbao.pinduoduo.com/network/api/promotion/createPromotionUrl";
+
+            //{"pid":"13848803_189356569","sourceUrl":"https://p.pinduoduo.com/1OAsct0r"}
+
+            string goodsId = sourceUrl;
+            var args = new
+            {
+                _account.pid,
+                goodsId,
+                generateOpenCoupon = true
+            };
+
+            /*
+{
+	"mediaId": "9092702778",
+	"pid": "13848803_189356569",
+	"goodsId": "123",
+	"generateOpenCoupon": true
+}             
+             */
+            string data = args.Convert2Json();
+
+            WebClientUtility client = new WebClientUtility();
+            client.Proxy = _proxy;
+#if DEBUG
+            client.Proxy = null;
+#endif
+            client.SetContentType("application/json");
+            client.AddHeaders("Referer", "https://jinbao.pinduoduo.com/promotion/url-promotion");
+            client.AddHeaders("Origin", "https://jinbao.pinduoduo.com");
+            client.UserAgent = useragent;
+            client.AddHeaders("Cookie", cookies);
+            client.Post(data);
+            var response = await client.RequestAsync(url, "POST", cancellationToken);
+
+            string body = response.Body();
+            var root = body.Convert2Object<PddCreatePromotionUrlResponse>();
+            string message = string.Empty;
+
+            if (!root.success)
+            {
+                message = $"{root.errorCode}:{root.errorMsg}";
+                result.success = false;
+                result.message = "转链失败";
+                result.reason = message;
+                _ = new LoggerLibrary("PddUnion", "transferUrl").Info(body).SaveAsync();
+                return result;
+            }
+
+            if (string.IsNullOrEmpty(root.result?.multiGroupShortUrl))
+            {
+                result.success = false;
+                result.message = "转链失败";
+                result.reason = "无法转链";
+                //_ = new LoggerLibrary("PddUnion", "transferUrl").Info(body).SaveAsync();
+                return result;
+            }
+
+            //goods_id=636365867069&pid=13848803_189356569&goods_sign=E9z2NkASdqlKuWDVwvfdqnADgCEqTQSt_JuMe2WC0G&zs_duo_id=25194414&cpsSign=CC_240807_13848803_189356569_fdbbdfa499058644becc9f8b3b7acaaf&_x_ddjb_act=
+
+            if (!string.IsNullOrEmpty(root.result?.url))
+            {
+                result.itemId = root.result?.url.GetContentPart("goods_id=", "&");
+            }
+
+            result.success = true;
+            result.message = "OK";
+            result.link_type = LinkTypeEnum.goods;
+            result.shortLinkurl = root.result?.multiGroupShortUrl;
+            result.content = result.shortLinkurl;
+            result.deeplink_url = GetDeeplink(result.shortLinkurl);
+
+
+            return result;
+        }
+
+    }
+}

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov