using dodohold.core; using Org.BouncyCastle.Ocsp; using Sayaka.Common; using System.Net; using System.Text.Json; using System.Xml; using TencentCloud.Lighthouse.V20200324.Models; using TencentCloud.Weilingwith.V20230427.Models; using Top.Api; using Top.Api.Request; using Top.Api.Response; namespace molilian.core { public partial class TaobaoOpenPlus { public enum RecommendRequestType { first, second, ori, } string _app_key = string.Empty; string _app_secret = string.Empty; string _pid = string.Empty; string _server_url = "https://eco.taobao.com/router/rest"; bool _debug = false; WebProxy _proxy = null; public TaobaoOpenPlus(string app_key, string app_secret, string pid, bool debug, WebProxy proxy) { _app_key = app_key; _app_secret = app_secret; _pid = pid; _debug = debug; _proxy = proxy; } public static PromotionQueryItemDTO ConverPromotionQueryItem(JsonElement item) { PromotionQueryItemDTO result = JsonSerializer.Deserialize(item.GetRawText()); string h5_url = item.Read("couponShareUrl", string.Empty); if (string.IsNullOrEmpty(h5_url)) { h5_url = item.Read("url", string.Empty); } if (h5_url.StartsWith("//")) h5_url = "https:" + h5_url; result.h5_url = h5_url; result.deeplink_url = AlimamaPlus.GetDeeplink(h5_url); if (result.pic.StartsWith("//")) result.pic = "https:" + result.pic; return result; } public TbkThorMfrsPromotionQueryResponse PromotionQueryRequest(string base64, string oaid) { var client = new DefaultTopClient(_server_url, _app_key, _app_secret, "json"); client.SetProxy(_proxy); TbkThorMfrsPromotionQueryRequest req = new(); TbkThorMfrsPromotionQueryRequest.ManufacturerLaunchOptionDomain obj1 = new() { Img = base64, Pid = _pid, UniqueId = oaid, UniqueIdType = "oaid", SceneCode = "h5_img", SceneSubCode = "Hitoch" }; req.Option_ = obj1; TbkThorMfrsPromotionQueryResponse rsp = client.Execute(req); if (_debug) { var _req = req.Convert2Json(); var _rsp = rsp.Convert2Json(); new LoggerLibrary("debug", oaid).Info(_req, _rsp).Save(); } return rsp; } public async Task<(List, string, int)> GetRecommendDataWithRetry( RecommendRequestType type, string oaid, string cookies, CancellationToken cancellationToken = default) { DateTime stime = DateTime.Now; // 假设传入了一个 CancellationToken cancellationToken 和 int maxRetries 表示最大重试次数 int retryCount = 0; int maxRetries = 50; while (true) { try { (var data, cookies) = await GetRecommendData(type, oaid, cookies, cancellationToken); var ts = DateTime.Now - stime; int elapsedTime = (int)ts.TotalMilliseconds; return (data, cookies, elapsedTime); } catch (Exception ex) { if (type == RecommendRequestType.first && ex.Message.Equals("RECOMMEND_UNKNOWN_ERROR::Recommend未知错误")) { return (new List(), cookies, 2); } if (retryCount >= maxRetries || cancellationToken.IsCancellationRequested) { throw; } retryCount++; Thread.Sleep(100); } } } public async Task<(List, string)> GetRecommendData(RecommendRequestType type, string oaid, string cookies, CancellationToken cancellationToken = default) { string token = "undefined"; if (!string.IsNullOrEmpty(cookies)) token = cookies.GetContentPart("_m_h5_tk=", "_"); string url = GetRecommendUrl(_pid, oaid, token, type); string body = string.Empty; string ua = ProviderFakeUserAgent.RandomMobile; var client = new WebClientUtility(); client.Proxy = _proxy; client.UserAgent = ua; if (string.IsNullOrEmpty(cookies)) { var res = await client.RequestAsync(url, "GET", cancellationToken); if (!res.Successed) { throw res.ResponseException; } body = res.Body(); if (_debug) { new LoggerLibrary("debug", oaid) .Info("第一次 cookies 初始化") .Info(ua, _proxy?.Address?.AbsoluteUri) .Info(url, body) .Save(); } cookies = res.ResponseMessage.GetCookiesString(); token = cookies.GetContentPart("_m_h5_tk=", "_"); } url = GetRecommendUrl(_pid, oaid, token, type); client = new WebClientUtility(); client.Proxy = _proxy; client.UserAgent = ua; if (!string.IsNullOrEmpty(cookies)) client.SetCookies(cookies); var response = await client.RequestAsync(url, "GET", cancellationToken); body = response.Body(); if (_debug) { new LoggerLibrary("debug", oaid) .Info("GetRecommendData") .Info(ua, _proxy?.Address?.AbsoluteUri) .Info(url, cookies) .Info(body) .Save(); } body = body.Trim().StringTrimStart("mtopjsonp1("); body = body.StringTrimEnd(")"); var root = body.Convert2JsonElement(); var ret = root.PathRead("ret[0]", string.Empty); if (!"SUCCESS::调用成功".Equals(ret)) { throw new Exception(ret); } var resultList = new List(); foreach (var data in root.ElementRead("data").ElementRead("resultList").EnumerateArray()) { PromotionQueryItemDTO item = ConverPromotionQueryItem(data); resultList.Add(item); } return (resultList, cookies); } public string GetRecommendUrl(string pid, string oaid, string token, RecommendRequestType type) { var first_data = $"{{\"scene\":\"pltSimilarPromotion\",\"variableMap\":\"{{\\\"pid\\\":\\\"{pid}\\\",\\\"oaid\\\":\\\"{oaid}\\\",\\\"type\\\":\\\"first\\\"}}\"}}"; var second_data = $"{{\"scene\":\"pltSimilarPromotion\",\"variableMap\":\"{{\\\"pid\\\":\\\"{pid}\\\",\\\"oaid\\\":\\\"{oaid}\\\",\\\"type\\\":\\\"second\\\"}}\"}}"; var ori_data = $"{{\"scene\":\"pltPromotionImg\",\"variableMap\":\"{{\\\"pid\\\":\\\"{pid}\\\",\\\"oaid\\\":\\\"{oaid}\\\",\\\"hasCoupon\\\":false,\\\"filterType\\\":\\\"ori\\\",\\\"seq\\\":\\\"\\\"}}\"}}"; string ts = DateTime.Now.Convert2UnixTimestamp(true).ToString(); string data = type switch { RecommendRequestType.first => first_data, RecommendRequestType.second => second_data, _ => ori_data, }; string sign = GetSign(token, ts, data); string url = $"https://h5api.m.taobao.com/h5/mtop.union.thor.landing.page.recommend/1.0/" + $"?jsv=2.4.16&appKey=12574478&t={ts}&sign={sign}&v=1.0&api=mtop.union.thor.landing.page.recommend" + $"&timeout=20000&AntiCreep=true&AntiFlood=true&type=jsonp&dataType=jsonp&callback=mtopjsonp1" + $"&data={data.UrlEncode()}"; return url; } private string GetSign(string token, string ts, string data) { string g = "12574478"; //%7B%22scene%22%3A%22pltPromotionImg%22%2C%22variableMap%22%3A%22%7B%5C%22pid%5C%22%3A%5C%22mm_5993059531_3080100059_115689750259%5C%22%2C%5C%22oaid%5C%22%3A%5C%22-7775661578900138800%5C%22%2C%5C%22hasCoupon%5C%22%3Afalse%2C%5C%22filterType%5C%22%3A%5C%22ori%5C%22%2C%5C%22seq%5C%22%3A%5C%22%5C%22%7D%22%7D //%7B%22scene%22%3A%22pltPromotionImg%22%2C%22variableMap%22%3A%22%7B%5C%22pid%5C%22%3A%5C%22mm_5993059531_3080100059_115689750259%5C%22%2C%5C%22oaid%5C%22%3A%5C%22-7775661578900138800%5C%22%2C%5C%22hasCoupon%5C%22%3Afalse%2C%5C%22filterType%5C%22%3A%5C%22ori%5C%22%2C%5C%22seq%5C%22%3A%5C%22%5C%22%7D%22%7D var signString = $"{token}&{ts}&{g}&{data}"; return signString.MD5(); } } }