tool_links.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. using dodohold.core;
  2. using System.Diagnostics;
  3. using System.Text.Json;
  4. namespace molilian.core
  5. {
  6. public partial class AlimamaPlus
  7. {
  8. public async Task<TkDataDTO> endpoint_tool_links(string content, TkDataDTO result, CancellationToken cancellationToken = default)
  9. {
  10. string t = $"{DateTime.Now.Convert2UnixTimestamp(true)}";
  11. Random random = new();
  12. double randomNumber = random.NextDouble();
  13. string randomString = randomNumber.ToString()[2..];
  14. string cna = _cookies.GetContentPart("cna=", ";");
  15. string firstFiveCharacters = cna[..Math.Min(5, cna.Length)];
  16. var variableMap = new
  17. {
  18. url = content,
  19. union_lens = $"b_pvid:a219t._portal_v2_home_plus_index_htm_{t}_{randomString}_{firstFiveCharacters}_mmWuH",
  20. lensScene = "PUB",
  21. spmB = "_portal_v2_tool_links_page_home_index_htm"
  22. }.Convert2Json(true).UrlEncode();
  23. variableMap = variableMap.Replace(" ", "%20");
  24. _floorId = "61446";
  25. string url = "https://pub.alimama.com/openapi/param2/1/gateway.unionpub/xt.entry.json?" +
  26. $"t={t}&_tb_token_={_tb_token}&floorId={_floorId}&refpid={_refpid}&variableMap={variableMap}";
  27. Stopwatch stopwatch = Stopwatch.StartNew();
  28. stopwatch.Start();
  29. var client = new WebClientUtility().SetContentType("application/json;charset=utf-8")
  30. .AddHeaders("X-Requested-With", "XMLHttpRequest")
  31. .AddHeaders("Cookie", _cookies);
  32. client.Proxy = _proxy;
  33. #if DEBUG
  34. client.Proxy = null;
  35. #endif
  36. if (!string.IsNullOrEmpty(_user_agent)) client.UserAgent = _user_agent;
  37. client.Timeout = GetRequestTimeout2(result.elapsedTime2);
  38. //var response = client.Request(url);
  39. #if DEBUG
  40. var response = await client.RequestAsync(url, "GET");
  41. #else
  42. var response = await client.RequestAsync(url, "GET", cancellationToken);
  43. #endif
  44. stopwatch.Stop();
  45. result.elapsedTime3 = (int)stopwatch.ElapsedMilliseconds;
  46. var body = string.Empty;
  47. try
  48. {
  49. if (!response.Successed)
  50. {
  51. result.channel = TkChannelEnum.tb;
  52. result.link_type = LinkTypeEnum.unknown;
  53. result.success = false;
  54. result.message = "fail";
  55. if (response.ResponseException != null)
  56. {
  57. _ = new LoggerLibrary("api_error", "fail")
  58. .Info(response.ResponseException.Message, response.ResponseException.StackTrace)
  59. .SaveAsync();
  60. throw response.ResponseException;
  61. }
  62. return result;
  63. }
  64. if (response.ResponseMessage.StatusCode == System.Net.HttpStatusCode.Found)
  65. {
  66. _ = new LoggerLibrary("api_error", "fail")
  67. .Info($"302:{response.ResponseMessage.Headers.Location}")
  68. .SaveAsync();
  69. throw new Exception("302 Found, was canceled");
  70. }
  71. JsonElement root;
  72. try
  73. {
  74. body = response.Body();
  75. root = body.Convert2JsonElement();
  76. }
  77. catch (Exception ex)
  78. {
  79. _ = new LoggerLibrary("api_error", "fail")
  80. .Info(ex.Message, ex.StackTrace)
  81. .SaveAsync();
  82. if (body.Contains("https://g.alicdn.com/sd/punish/waf_block.html"))
  83. {
  84. await TkEndpointManager.SuspendAsync(_accountId, "tool_links", TkEndpointManager.SuspendReason.Passive);
  85. result.channel = TkChannelEnum.tb;
  86. result.link_type = LinkTypeEnum.unknown;
  87. result.success = false;
  88. result.message = "waf_block";
  89. return result;
  90. }
  91. if (body.Contains("https://bixi.alicdn.com") && body.Contains("\"action\": \"deny\""))
  92. {
  93. await TkEndpointManager.SuspendAsync(_accountId, "tool_links", TkEndpointManager.SuspendReason.Passive);
  94. result.channel = TkChannelEnum.tb;
  95. result.link_type = LinkTypeEnum.unknown;
  96. result.subCode = TkSubCodeEnum.ParseDeny;
  97. result.success = false;
  98. result.message = "waf_block";
  99. result.reason = "接口风控";
  100. return result;
  101. }
  102. throw new Exception(body);
  103. }
  104. if (body.Contains("https://bixi.alicdn.com") && body.Contains("\"action\": \"deny\""))
  105. {
  106. await TkEndpointManager.SuspendAsync(_accountId, "tool_links", TkEndpointManager.SuspendReason.Passive);
  107. result.channel = TkChannelEnum.tb;
  108. result.link_type = LinkTypeEnum.unknown;
  109. result.subCode = TkSubCodeEnum.ParseDeny;
  110. result.success = false;
  111. result.message = "waf_block";
  112. result.reason = "接口风控";
  113. return result;
  114. }
  115. bool success = root.Read<bool>("success", false);
  116. string message = root.Read("message", string.Empty);
  117. string info_message = root.PathRead("info.message", string.Empty);
  118. if (!string.IsNullOrEmpty(info_message)) message = info_message;
  119. string taoToken = root.PathRead("data.taoToken", string.Empty);
  120. string shortLinkurl = root.PathRead("data.shortLinkurl", string.Empty);
  121. string couponLinkTaoToken = root.PathRead("data.couponLinkTaoToken", string.Empty);
  122. string couponShortLinkUrl = root.PathRead("data.couponShortLinkUrl", string.Empty);
  123. decimal couponAmount = root.PathRead<decimal>("data.couponAmount", 0);
  124. string couponEffectiveEndTime = root.PathRead("data.couponEffectiveEndTime", string.Empty);
  125. string couponEffectiveStartTime = root.PathRead("data.couponEffectiveStartTime", string.Empty);
  126. string itemId = root.PathRead("data.itemId", string.Empty);
  127. string mktId = root.PathRead("data.outputMktId", string.Empty);
  128. string itemName = root.PathRead("data.itemName", string.Empty);
  129. decimal promotionPrice = root.PathRead<decimal>("data.promotionPrice", 0);
  130. string sellerNickName = root.PathRead("data.sellerNickName", string.Empty);
  131. string shopTitle = root.PathRead("data.shopTitle", string.Empty);
  132. string pic = root.PathRead("data.pic", string.Empty);
  133. if (pic.StartsWith("//")) pic = "https:" + pic;
  134. string qrCodeUrl = root.PathRead("data.qrCodeUrl", string.Empty);
  135. string itemTaoToken = taoToken;
  136. if (response.ResponseMessage != null)
  137. {
  138. switch (response.ResponseMessage.StatusCode)
  139. {
  140. case System.Net.HttpStatusCode.OK:
  141. {
  142. if (couponAmount > 0 && !string.IsNullOrEmpty(couponLinkTaoToken) && !string.IsNullOrEmpty(couponShortLinkUrl))
  143. {
  144. taoToken = couponLinkTaoToken;
  145. shortLinkurl = couponShortLinkUrl;
  146. }
  147. string shortLink = GetLink(taoToken);
  148. content = ReplaceUrls(content, shortLink);
  149. }
  150. break;
  151. case System.Net.HttpStatusCode.Found:
  152. string location = response.ResponseMessage.Headers.Location.OriginalString;
  153. if (!string.IsNullOrEmpty(location) && location.Contains("www.alimama.com/member/login.htm"))
  154. {
  155. success = false;
  156. message = "nologin";
  157. }
  158. break;
  159. default:
  160. {
  161. success = false;
  162. message = "other";
  163. }
  164. break;
  165. }
  166. }
  167. if (!success)
  168. {
  169. shortLinkurl = GetLink(content);
  170. switch (message)
  171. {
  172. case "该商品已经下架或未加入淘宝客":
  173. case "该链接不支持转化,请更换链接尝试":
  174. result.subCode = TkSubCodeEnum.NoConvert;
  175. break;
  176. case "网络错误":
  177. result.subCode = TkSubCodeEnum.NetError;
  178. break;
  179. default:
  180. var _headers = response.ResponseMessage.Headers;
  181. var headers = "";
  182. foreach (var h in _headers)
  183. {
  184. foreach (var Value in h.Value)
  185. {
  186. headers += $"{h.Key}: {Value}\n";
  187. }
  188. }
  189. _ = new LoggerLibrary("api_error", "fail")
  190. .Info(message, content)
  191. .Info(headers, body)
  192. .SaveAsync();
  193. break;
  194. }
  195. }
  196. shortLinkurl = GetLink(taoToken);
  197. string deeplink_url = GetDeeplink(shortLinkurl);
  198. //补充原商品链接 2025-06-01
  199. result.item_url = GetLink(itemTaoToken);
  200. result.item_deeplink_url = GetDeeplink(result.item_url);
  201. result.channel = TkChannelEnum.tb;
  202. if (success)
  203. {
  204. result.subCode = TkSubCodeEnum.Success;
  205. switch (result.link_type)
  206. {
  207. case LinkTypeEnum.profile:
  208. case LinkTypeEnum.goods:
  209. case LinkTypeEnum.video:
  210. case LinkTypeEnum.live:
  211. break;
  212. default:
  213. result.link_type = LinkTypeEnum.goods;
  214. break;
  215. }
  216. }
  217. result.success = success;
  218. result.message = message;
  219. result.reason = string.Empty;
  220. result.content = content;
  221. result.couponAmount = couponAmount;
  222. result.couponEffectiveEndTime = couponEffectiveEndTime;
  223. result.couponEffectiveStartTime = couponEffectiveStartTime;
  224. result.taoToken = taoToken;
  225. if (!string.IsNullOrEmpty(shortLinkurl))
  226. {
  227. result.shortLinkurl = shortLinkurl;
  228. result.deeplink_url = deeplink_url;
  229. }
  230. result.mktId = mktId;
  231. result.itemId = itemId;
  232. result.itemName = itemName;
  233. result.promotionPrice = promotionPrice;
  234. result.sellerNickName = sellerNickName;
  235. result.shopTitle = shopTitle;
  236. result.pic = pic;
  237. result.qrCodeUrl = qrCodeUrl;
  238. }
  239. catch (Exception ex)
  240. {
  241. if (response.ResponseMessage?.StatusCode == System.Net.HttpStatusCode.OK)
  242. {
  243. if (body.Contains("<p>抱歉!页面无法访问……</p>"))
  244. {
  245. throw new APIException("抱歉!页面无法访问……");
  246. }
  247. }
  248. throw;
  249. }
  250. return result;
  251. }
  252. }
  253. }