|
@@ -171,41 +171,43 @@ namespace molilian.core
|
|
|
/// <param name="url"></param>
|
|
/// <param name="url"></param>
|
|
|
/// <returns></returns>
|
|
/// <returns></returns>
|
|
|
public async Task<(bool, string)> GetDesiredUrlAsync(WebProxy proxy, string url, CancellationToken cancellationToken = default)
|
|
public async Task<(bool, string)> GetDesiredUrlAsync(WebProxy proxy, string url, CancellationToken cancellationToken = default)
|
|
|
- {
|
|
|
|
|
- var result = await GetDesiredUrlResultAsync(proxy, url, cancellationToken);
|
|
|
|
|
- return (result.Success, result.Content);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private readonly record struct DesiredUrlResult(bool Success, string Content, bool UsedGeneralLinkParse);
|
|
|
|
|
-
|
|
|
|
|
- private async Task<DesiredUrlResult> GetDesiredUrlResultAsync(WebProxy proxy, string url, CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
{
|
|
|
string result;
|
|
string result;
|
|
|
- bool usedGeneralLinkParse = false;
|
|
|
|
|
try
|
|
try
|
|
|
{
|
|
{
|
|
|
- if (!IsShortLink(url)) return new(false, "不是淘宝短网址", false);
|
|
|
|
|
|
|
+ if (!IsShortLink(url)) return (false, "不是淘宝短网址");
|
|
|
|
|
|
|
|
if (_account.use_general_link_parse_pool)
|
|
if (_account.use_general_link_parse_pool)
|
|
|
{
|
|
{
|
|
|
- usedGeneralLinkParse = true;
|
|
|
|
|
- var parsed = await endpoint_tbk_dg_general_link_parse(url, new TkDataDTO { content = url }, cancellationToken);
|
|
|
|
|
- if (parsed.subCode != TkSubCodeEnum.GeneralLinkParsePoolUnavailable)
|
|
|
|
|
|
|
+ try
|
|
|
{
|
|
{
|
|
|
- if (!parsed.success) return new(false, parsed.reason, true);
|
|
|
|
|
-
|
|
|
|
|
- string desiredUrl = IsDigitsOnly(parsed.itemId)
|
|
|
|
|
- ? $"https://item.taobao.com/item.htm?id={parsed.itemId}"
|
|
|
|
|
- : parsed.item_url;
|
|
|
|
|
- return new(true, desiredUrl, true);
|
|
|
|
|
|
|
+ var parsed = await endpoint_tbk_dg_general_link_parse(url, new TkDataDTO { content = url }, cancellationToken);
|
|
|
|
|
+ if (parsed.success)
|
|
|
|
|
+ {
|
|
|
|
|
+ string desiredUrl = IsDigitsOnly(parsed.itemId)
|
|
|
|
|
+ ? $"https://item.taobao.com/item.htm?id={parsed.itemId}"
|
|
|
|
|
+ : parsed.item_url;
|
|
|
|
|
+ return (true, desiredUrl);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // 账号池无可用账号时,继续按下探网址设置执行原逻辑。
|
|
|
|
|
- usedGeneralLinkParse = false;
|
|
|
|
|
|
|
+ catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
|
|
|
|
|
+ {
|
|
|
|
|
+ throw;
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (Exception ex)
|
|
|
|
|
+ {
|
|
|
|
|
+ _ = TaobaoGeneralLinkParseCacheCore.NotifyFailureOnceAsync($"{ex.GetType().Name}: {ex.Message}", 0, _accountId);
|
|
|
|
|
+ }
|
|
|
|
|
+ // 解析失败、接口异常或账号池无可用账号,均回退原 HTTP 逻辑。
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
|
- if (!_account.enable_deep_url) return new(true, url, false);
|
|
|
|
|
|
|
+ if (!_account.enable_deep_url) return (true, url);
|
|
|
|
|
+
|
|
|
|
|
+ string shortUrl = url;
|
|
|
|
|
+ string? cachedUrl = await TaobaoShortLinkCacheCore.GetAsync(shortUrl);
|
|
|
|
|
+ cancellationToken.ThrowIfCancellationRequested();
|
|
|
|
|
+ if (cachedUrl != null) return (true, cachedUrl);
|
|
|
|
|
|
|
|
if (_account.use_general_link_parse_pool)
|
|
if (_account.use_general_link_parse_pool)
|
|
|
{
|
|
{
|
|
@@ -234,9 +236,11 @@ namespace molilian.core
|
|
|
|
|
|
|
|
if (response.ResponseMessage?.StatusCode == HttpStatusCode.Found &&
|
|
if (response.ResponseMessage?.StatusCode == HttpStatusCode.Found &&
|
|
|
!string.IsNullOrEmpty(response.ResponseMessage?.Headers?.Location?.OriginalString))
|
|
!string.IsNullOrEmpty(response.ResponseMessage?.Headers?.Location?.OriginalString))
|
|
|
- {
|
|
|
|
|
|
|
+ {
|
|
|
string redirectUrl = response.ResponseMessage?.Headers?.Location?.OriginalString;
|
|
string redirectUrl = response.ResponseMessage?.Headers?.Location?.OriginalString;
|
|
|
- return new(true, redirectUrl, false);
|
|
|
|
|
|
|
+ if (redirectUrl.StartsWith("//")) redirectUrl = "https:" + redirectUrl;
|
|
|
|
|
+ await TaobaoShortLinkCacheCore.SaveAsync(shortUrl, redirectUrl);
|
|
|
|
|
+ return (true, redirectUrl);
|
|
|
}
|
|
}
|
|
|
var responseBody = response.Body();
|
|
var responseBody = response.Body();
|
|
|
result = responseBody;
|
|
result = responseBody;
|
|
@@ -250,10 +254,11 @@ namespace molilian.core
|
|
|
{
|
|
{
|
|
|
result = match.Groups[1].Value; // 返回匹配的 URL
|
|
result = match.Groups[1].Value; // 返回匹配的 URL
|
|
|
|
|
|
|
|
- if (string.IsNullOrEmpty(result)) return new(false, "没有匹配的URL", false);
|
|
|
|
|
- if (result.StartsWith("//"))
|
|
|
|
|
- result = "https:" + result;
|
|
|
|
|
- return new(true, result, false);
|
|
|
|
|
|
|
+ if (string.IsNullOrEmpty(result)) return (false, "没有匹配的URL");
|
|
|
|
|
+ if (result.StartsWith("//"))
|
|
|
|
|
+ result = "https:" + result;
|
|
|
|
|
+ await TaobaoShortLinkCacheCore.SaveAsync(shortUrl, result);
|
|
|
|
|
+ return (true, result);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
@@ -276,7 +281,7 @@ namespace molilian.core
|
|
|
_ = new LoggerLibrary("api_error", "desiredUrl_error").Info(ex.Message, ex.StackTrace).SaveAsync();
|
|
_ = new LoggerLibrary("api_error", "desiredUrl_error").Info(ex.Message, ex.StackTrace).SaveAsync();
|
|
|
result = "网络异常";
|
|
result = "网络异常";
|
|
|
}
|
|
}
|
|
|
- return new(false, result, usedGeneralLinkParse);
|
|
|
|
|
|
|
+ return (false, result);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
@@ -284,14 +289,17 @@ namespace molilian.core
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
/// <param name="url"></param>
|
|
/// <param name="url"></param>
|
|
|
/// <returns></returns>
|
|
/// <returns></returns>
|
|
|
- public (bool, string) GetDesiredUrl(string url)
|
|
|
|
|
|
|
+ public (bool, string) GetDesiredUrl(string url)
|
|
|
{
|
|
{
|
|
|
string result;
|
|
string result;
|
|
|
try
|
|
try
|
|
|
{
|
|
{
|
|
|
- if (!IsShortLink(url)) return (false, "不是淘宝短网址");
|
|
|
|
|
-
|
|
|
|
|
- string desiredUrlPattern = "var url = '(.*?)'";
|
|
|
|
|
|
|
+ if (!IsShortLink(url)) return (false, "不是淘宝短网址");
|
|
|
|
|
+
|
|
|
|
|
+ string? cachedUrl = TaobaoShortLinkCacheCore.Get(url);
|
|
|
|
|
+ if (cachedUrl != null) return (true, cachedUrl);
|
|
|
|
|
+
|
|
|
|
|
+ string desiredUrlPattern = "var url = '(.*?)'";
|
|
|
WebClientUtility client = new()
|
|
WebClientUtility client = new()
|
|
|
{
|
|
{
|
|
|
Proxy = ProxyNodesCore.RandomOne(_account.nodeName),
|
|
Proxy = ProxyNodesCore.RandomOne(_account.nodeName),
|
|
@@ -316,8 +324,10 @@ namespace molilian.core
|
|
|
{
|
|
{
|
|
|
result = match.Groups[1].Value; // 返回匹配的 URL
|
|
result = match.Groups[1].Value; // 返回匹配的 URL
|
|
|
|
|
|
|
|
- if (string.IsNullOrEmpty(result)) return (false, "没有匹配的URL");
|
|
|
|
|
- return (true, result);
|
|
|
|
|
|
|
+ if (string.IsNullOrEmpty(result)) return (false, "没有匹配的URL");
|
|
|
|
|
+ if (result.StartsWith("//")) result = "https:" + result;
|
|
|
|
|
+ TaobaoShortLinkCacheCore.Save(url, result);
|
|
|
|
|
+ return (true, result);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
@@ -338,14 +348,17 @@ namespace molilian.core
|
|
|
return (false, result);
|
|
return (false, result);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public static (bool, string) GetItemUrl(string url, WebProxy proxy = null)
|
|
|
|
|
|
|
+ public static (bool, string) GetItemUrl(string url, WebProxy proxy = null)
|
|
|
{
|
|
{
|
|
|
string result;
|
|
string result;
|
|
|
try
|
|
try
|
|
|
{
|
|
{
|
|
|
- if (!IsShortLink(url)) return (false, "不是淘宝短网址");
|
|
|
|
|
-
|
|
|
|
|
- string desiredUrlPattern = "var url = '(.*?)'";
|
|
|
|
|
|
|
+ if (!IsShortLink(url)) return (false, "不是淘宝短网址");
|
|
|
|
|
+
|
|
|
|
|
+ string? cachedUrl = TaobaoShortLinkCacheCore.Get(url);
|
|
|
|
|
+ if (cachedUrl != null) return (true, cachedUrl);
|
|
|
|
|
+
|
|
|
|
|
+ string desiredUrlPattern = "var url = '(.*?)'";
|
|
|
WebClientUtility client = new()
|
|
WebClientUtility client = new()
|
|
|
{
|
|
{
|
|
|
Proxy = proxy,
|
|
Proxy = proxy,
|
|
@@ -368,8 +381,10 @@ namespace molilian.core
|
|
|
{
|
|
{
|
|
|
result = match.Groups[1].Value; // 返回匹配的 URL
|
|
result = match.Groups[1].Value; // 返回匹配的 URL
|
|
|
|
|
|
|
|
- if (string.IsNullOrEmpty(result)) return (false, "没有匹配的URL");
|
|
|
|
|
- return (true, result);
|
|
|
|
|
|
|
+ if (string.IsNullOrEmpty(result)) return (false, "没有匹配的URL");
|
|
|
|
|
+ if (result.StartsWith("//")) result = "https:" + result;
|
|
|
|
|
+ TaobaoShortLinkCacheCore.Save(url, result);
|
|
|
|
|
+ return (true, result);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
@@ -537,24 +552,12 @@ namespace molilian.core
|
|
|
result.proxy_node = proxy?.Address?.Authority;
|
|
result.proxy_node = proxy?.Address?.Authority;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- var desiredUrlResult = await GetDesiredUrlResultAsync(proxy, url, cancellationToken);
|
|
|
|
|
- success = desiredUrlResult.Success;
|
|
|
|
|
- resultText = desiredUrlResult.Content;
|
|
|
|
|
|
|
+ (success, resultText) = await GetDesiredUrlAsync(proxy, url, cancellationToken);
|
|
|
sw.Stop();
|
|
sw.Stop();
|
|
|
// 获取执行时间
|
|
// 获取执行时间
|
|
|
result.elapsedTime2 = (int)sw.ElapsedMilliseconds;
|
|
result.elapsedTime2 = (int)sw.ElapsedMilliseconds;
|
|
|
swData?.Add("\tGetDesiredUrlAsync", sw.ElapsedMilliseconds);
|
|
swData?.Add("\tGetDesiredUrlAsync", sw.ElapsedMilliseconds);
|
|
|
|
|
|
|
|
- if (desiredUrlResult.UsedGeneralLinkParse && !success)
|
|
|
|
|
- {
|
|
|
|
|
- result.success = false;
|
|
|
|
|
- result.message = "解析失败";
|
|
|
|
|
- result.reason = resultText;
|
|
|
|
|
- result.subCode = TkSubCodeEnum.NoConvert;
|
|
|
|
|
- result.link_type = LinkTypeEnum.unknown;
|
|
|
|
|
- result.content = content;
|
|
|
|
|
- return result;
|
|
|
|
|
- }
|
|
|
|
|
//============================== 放弃转链-请求超时 ==============================
|
|
//============================== 放弃转链-请求超时 ==============================
|
|
|
#if DEBUG
|
|
#if DEBUG
|
|
|
#else
|
|
#else
|