KsUnionPlus.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. using COSXML.Network;
  2. using dodohold.core;
  3. using Spire.Pdf.Graphics;
  4. using System.Diagnostics;
  5. using System.Net;
  6. using System.Text.RegularExpressions;
  7. using TencentCloud.Apm.V20210622.Models;
  8. using static dodohold.core.ZTOExpress.CreateOrderArgs;
  9. namespace molilian.core
  10. {
  11. public partial class KsUnionPlus
  12. {
  13. public static string _url_pattern = @"https?://(?:[\w-]+\.)*(?:chenzhongtech\.com|kuaishou\.com)(?:/[^\s]*)?";
  14. public static string GetLink(string content)
  15. {
  16. if (string.IsNullOrEmpty(content)) return content;
  17. string result = content;
  18. //
  19. Regex regex = new(_url_pattern);
  20. MatchCollection matches = regex.Matches(content);
  21. foreach (Match m in matches.Cast<Match>())
  22. {
  23. string url = m.Value;
  24. return url;
  25. }
  26. return string.Empty;
  27. }
  28. public static string GetDeeplink(string url, LinkTypeEnum type)
  29. {
  30. string shareObjectId = string.Empty;
  31. string url_pattern = @"shareObjectId=([^\s&]+)";
  32. var match = Regex.Match(url, url_pattern);
  33. if (match.Success) shareObjectId = match.Groups[1].Value;
  34. string result = type switch
  35. {
  36. LinkTypeEnum.video => $"kwai://work/{shareObjectId}",
  37. LinkTypeEnum.profile => $"kwai://profile/{shareObjectId}",
  38. LinkTypeEnum.live => $"kwai://live/play/{shareObjectId}",
  39. LinkTypeEnum.baseDomain or LinkTypeEnum.other_aff => "kwai://home",
  40. LinkTypeEnum.goods or LinkTypeEnum.note => "kwai://home",
  41. _ => string.Empty,
  42. };
  43. return result;
  44. }
  45. public static KsDataDTO GetFormattedObject(string content, string ip = "", string oaid = "")
  46. {
  47. string shortLinkurl = GetLink(content);
  48. LinkTypeEnum link_type = string.IsNullOrEmpty(shortLinkurl) ? LinkTypeEnum.unknown : LinkTypeEnum.baseDomain;
  49. string deeplink_url = GetDeeplink(shortLinkurl, link_type);
  50. return new KsDataDTO()
  51. {
  52. message = string.Empty,
  53. link_type = link_type,
  54. channel = TkChannelEnum.ks,
  55. accountName = string.Empty,
  56. success = false,
  57. content = content,
  58. ip = ip,
  59. oaid = oaid,
  60. elapsedTime = 0,
  61. itemName = "点击打开快手APP",
  62. shortLinkurl = shortLinkurl,
  63. deeplink_url = deeplink_url,
  64. create_time = DateTime.Now,
  65. end_point = _end_point,
  66. };
  67. }
  68. private LinkTypeEnum GetLinkType(string url)
  69. {
  70. if (string.IsNullOrEmpty(url)) return LinkTypeEnum.unknown;
  71. string url_pattern = @"https?://(?:[\w-]+\.)*(?:chenzhongtech\.com|kuaishou\.com)/fw/(?:photo|long-video)/[^\s]*\bshareObjectId=[^\s&]+";
  72. var match = Regex.Match(url, url_pattern);
  73. if (match.Success) return LinkTypeEnum.video;
  74. url_pattern = @"https?://(?:[\w-]+\.)*(?:chenzhongtech\.com|kuaishou\.com)/fw/user/[^\s]*\bshareObjectId=[^\s&]+";
  75. match = Regex.Match(url, url_pattern);
  76. if (match.Success) return LinkTypeEnum.profile;
  77. url_pattern = @"https?://(?:[\w-]+\.)*(?:chenzhongtech\.com|kuaishou\.com)/fw/live/[^\s]*\bshareObjectId=[^\s&]+";
  78. match = Regex.Match(url, url_pattern);
  79. if (match.Success) return LinkTypeEnum.live;
  80. if (url.Contains("chenzhongtech.com") || url.Contains("kuaishou.com")) return LinkTypeEnum.baseDomain;
  81. return LinkTypeEnum.unknown;
  82. }
  83. private bool IsAffCode(string content)
  84. {
  85. string url_pattern = @"復制整段消息,打開快手|复制整段消息,打开快手";
  86. var match = Regex.Match(content, url_pattern);
  87. if (match.Success) return true;
  88. return false;
  89. }
  90. private async Task<(bool, string)> GetDesiredUrlAsync(string url)
  91. {
  92. string result = url;
  93. try
  94. {
  95. string pattern = @"https:\/\/v\.kuaishou\.com\/[A-Za-z0-9]+";
  96. Match match = Regex.Match(url, pattern);
  97. //不是短网址,不用展开
  98. if (!match.Success) return (true, url);
  99. WebClientUtility client = new()
  100. {
  101. Proxy = _proxy ?? ProxyNodesCore.RandomOne(),
  102. UserAgent = Sayaka.Common.ProviderFakeUserAgent.RandomComputer,
  103. AllowAutoRedirect = false
  104. };
  105. #if DEBUG
  106. client.Proxy = null;
  107. #endif
  108. client.Timeout = GetRequestTimeout(0);
  109. var response = await client.RequestAsync(url);
  110. if (response.ResponseMessage != null)
  111. {
  112. result = response.ResponseMessage.Headers.Location.ToString();
  113. result = result.UrlDecode();
  114. return (true, result);
  115. }
  116. }
  117. catch (Exception ex)
  118. {
  119. result = $"{ex.Message}\n{ex.StackTrace}";
  120. }
  121. return (false, result);
  122. }
  123. public TimeSpan GetRequestTimeout(int deduction = 0)
  124. {
  125. #if DEBUG
  126. return TimeSpan.FromMilliseconds(10 * 1000);
  127. #endif
  128. int min = (int)(_config.rt_max * 0.3);
  129. if (_config.rt_max == 0) return TimeSpan.FromMilliseconds(1000);
  130. int timeout = _config.rt_max;
  131. if (deduction == 0)
  132. {
  133. timeout -= min;
  134. return TimeSpan.FromMilliseconds(timeout);
  135. }
  136. timeout -= deduction;
  137. if (timeout <= min) return TimeSpan.FromMilliseconds(1);
  138. return TimeSpan.FromMilliseconds(min);
  139. }
  140. public async Task<KsDataDTO> KsParseAsync(string content, KsDataDTO result, CancellationToken cancellationToken = default)
  141. {
  142. //正文里面不包含url
  143. if (string.IsNullOrEmpty(result.shortLinkurl) && IsAffCode(content))
  144. {
  145. result.success = false;
  146. result.link_type = LinkTypeEnum.other_aff;
  147. result.message = "放弃转链";
  148. result.reason = "其他推广链接";
  149. result.accountId = 0;
  150. result.accountName = string.Empty;
  151. result.content = content;
  152. result.deeplink_url = GetDeeplink(content, LinkTypeEnum.goods);
  153. return result;
  154. }
  155. string url = string.Empty;
  156. if (!string.IsNullOrEmpty(result.shortLinkurl))
  157. {
  158. //从http获取跳转的url
  159. Stopwatch stopwatch = Stopwatch.StartNew();
  160. stopwatch.Start();
  161. (bool success, url) = await GetDesiredUrlAsync(result.shortLinkurl);
  162. stopwatch.Stop();
  163. // 获取执行时间
  164. result.elapsedTime2 = (int)stopwatch.ElapsedMilliseconds;
  165. result.link_type = GetLinkType(url);
  166. if (result.link_type == LinkTypeEnum.other_aff)
  167. {
  168. result.success = false;
  169. result.message = "放弃转链";
  170. result.reason = "其他推广链接";
  171. result.accountId = 0;
  172. result.accountName = string.Empty;
  173. result.content = content;
  174. result.deeplink_url = GetDeeplink(content, LinkTypeEnum.goods);
  175. return result;
  176. }
  177. //没有链接、 不是链接
  178. if (!success)
  179. {
  180. result.success = false;
  181. result.link_type = LinkTypeEnum.unknown;
  182. result.message = "放弃转链";
  183. result.reason = url;
  184. result.accountId = 0;
  185. result.accountName = string.Empty;
  186. result.content = content;
  187. return result;
  188. }
  189. result.deeplink_url = GetDeeplink(url, result.link_type);
  190. return result;
  191. }
  192. if (!result.ip.StartsWith("127.0.0") && FlowControlIgnoreRequest(_config, out string reason))
  193. {
  194. result.success = false;
  195. result.link_type = LinkTypeEnum.unknown;
  196. result.message = "放弃转链";
  197. result.reason = reason;
  198. result.accountId = 0;
  199. result.accountName = string.Empty;
  200. result.content = content;
  201. result.deeplink_url = GetDeeplink(content, LinkTypeEnum.goods);
  202. return result;
  203. }
  204. //result.shortLinkurl = url;
  205. switch (_account.work_mode)
  206. {
  207. case KsUnionWorkMode.SiteApi:
  208. result = await UnionGeneratelink(result, content, cancellationToken);
  209. break;
  210. case KsUnionWorkMode.Crawler:
  211. default:
  212. //result = await transferUrl(result, url, cancellationToken);
  213. break;
  214. }
  215. return result;
  216. }
  217. }
  218. }