1、修复关注同步时报https证书错误问题

2、关注列表点头像跳抖音博主首页
This commit is contained in:
jianzhichu
2025-12-04 22:01:38 +08:00
parent 385e53561a
commit c03dc5beff
12 changed files with 370 additions and 134 deletions
+1 -1
View File
@@ -197,7 +197,7 @@ ____/ _|_)_____/ _| _| \_|\____|
// 重置博主作品同步状态为未同步 // 重置博主作品同步状态为未同步
commonService.UpdateAllCookieSyncedToZero(); commonService.UpdateAllCookieSyncedToZero();
if (!isDevelopment) //if (!isDevelopment)
{ {
// 启动定时任务 // 启动定时任务
var quartzJobService = services.GetRequiredService<DouyinQuartzJobService>(); var quartzJobService = services.GetRequiredService<DouyinQuartzJobService>();
@@ -5,7 +5,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<_PublishTargetUrl>E:\code\dysync\bin\Release\net6.0\publish\</_PublishTargetUrl> <_PublishTargetUrl>E:\code\dysync\bin\Release\net6.0\publish\</_PublishTargetUrl>
<History>True|2025-12-04T00:22:47.9617427Z||;False|2025-12-04T08:22:41.3759733+08:00||;True|2025-12-04T08:14:02.2478893+08:00||;True|2025-12-04T07:57:00.2208139+08:00||;True|2025-12-03T23:58:13.3693303+08:00||;True|2025-12-03T23:57:40.4257893+08:00||;True|2025-12-03T23:56:38.8717769+08:00||;True|2025-12-03T23:56:24.0663568+08:00||;False|2025-12-03T23:55:36.1902974+08:00||;True|2025-12-03T23:51:30.6688504+08:00||;True|2025-12-03T23:34:17.1648971+08:00||;False|2025-12-03T23:34:07.7649161+08:00||;True|2025-12-03T22:32:56.2435003+08:00||;True|2025-12-03T22:27:45.6059666+08:00||;True|2025-12-03T15:55:28.0186597+08:00||;False|2025-12-03T15:54:17.5032724+08:00||;True|2025-12-03T15:53:10.2273509+08:00||;True|2025-12-02T22:11:37.4645042+08:00||;False|2025-12-02T22:10:47.1320259+08:00||;True|2025-12-02T14:39:58.8932130+08:00||;True|2025-12-02T14:36:37.1529072+08:00||;True|2025-12-02T12:58:22.0951548+08:00||;True|2025-12-02T09:30:33.7066474+08:00||;True|2025-12-02T09:30:14.5481844+08:00||;True|2025-12-02T09:30:00.3123364+08:00||;False|2025-12-02T09:29:54.4615520+08:00||;True|2025-12-02T09:13:01.7995414+08:00||;False|2025-12-02T09:12:55.8360281+08:00||;True|2025-12-02T09:12:31.0156791+08:00||;True|2025-12-02T08:55:11.3773395+08:00||;True|2025-12-02T08:53:21.3927713+08:00||;False|2025-12-02T08:48:55.8638037+08:00||;True|2025-12-02T07:29:25.2192447+08:00||;False|2025-12-02T07:29:10.2504665+08:00||;True|2025-12-02T07:28:29.0769286+08:00||;True|2025-12-01T21:53:07.6474834+08:00||;True|2025-12-01T21:44:28.1674315+08:00||;True|2025-12-01T21:18:47.2119609+08:00||;True|2025-12-01T20:51:19.9948301+08:00||;True|2025-12-01T20:50:36.9904697+08:00||;True|2025-12-01T20:44:10.1695142+08:00||;True|2025-12-01T19:27:58.0479456+08:00||;True|2025-12-01T19:16:02.2288214+08:00||;False|2025-12-01T19:15:56.0372115+08:00||;True|2025-12-01T19:15:16.4854821+08:00||;False|2025-12-01T19:15:06.7001019+08:00||;True|2025-12-01T17:10:38.9739466+08:00||;False|2025-12-01T17:10:18.8928139+08:00||;True|2025-12-01T17:03:59.3171589+08:00||;True|2025-12-01T17:03:12.5681656+08:00||;True|2025-12-01T16:42:51.4415025+08:00||;True|2025-12-01T01:29:59.6975567+08:00||;True|2025-12-01T01:29:45.1898652+08:00||;False|2025-12-01T01:29:33.1787721+08:00||;True|2025-12-01T01:27:33.1297605+08:00||;True|2025-12-01T01:27:27.3976862+08:00||;False|2025-12-01T01:27:20.5193052+08:00||;True|2025-12-01T01:11:11.0210582+08:00||;True|2025-12-01T01:04:04.3307782+08:00||;True|2025-12-01T00:55:49.8018864+08:00||;True|2025-12-01T00:27:25.1323561+08:00||;True|2025-11-30T23:58:20.7284116+08:00||;True|2025-11-30T23:57:58.3027622+08:00||;True|2025-11-30T23:57:43.0829614+08:00||;False|2025-11-30T23:57:33.5606716+08:00||;True|2025-11-30T23:54:29.6203368+08:00||;True|2025-11-30T23:54:27.5383120+08:00||;False|2025-11-30T23:54:17.0823982+08:00||;True|2025-11-30T22:41:11.4538820+08:00||;True|2025-11-30T22:38:19.7064566+08:00||;True|2025-11-30T22:37:35.2889186+08:00||;True|2025-11-30T21:42:31.1408314+08:00||;True|2025-11-30T21:42:19.5385333+08:00||;False|2025-11-30T21:42:13.3290237+08:00||;True|2025-11-30T21:33:28.0806806+08:00||;True|2025-11-30T21:16:56.7088027+08:00||;False|2025-11-30T21:16:46.1444944+08:00||;True|2025-11-30T20:21:24.4059664+08:00||;False|2025-11-30T20:21:17.6006098+08:00||;True|2025-11-30T20:20:08.2030141+08:00||;False|2025-11-30T20:16:12.3608968+08:00||;True|2025-11-30T20:15:35.6048313+08:00||;True|2025-11-30T19:45:18.7229552+08:00||;True|2025-11-30T19:45:08.6083368+08:00||;False|2025-11-30T19:44:54.7824905+08:00||;True|2025-11-30T19:44:17.0179491+08:00||;True|2025-11-30T19:44:06.7073484+08:00||;False|2025-11-30T19:43:58.2896556+08:00||;True|2025-11-30T19:42:08.2261927+08:00||;True|2025-11-30T19:28:15.7115077+08:00||;False|2025-11-30T19:28:10.2280725+08:00||;True|2025-11-30T19:23:31.7859158+08:00||;True|2025-11-30T19:23:20.7788277+08:00||;True|2025-11-30T19:17:11.8583296+08:00||;False|2025-11-30T19:10:41.8369574+08:00||;True|2025-11-30T19:02:08.8184758+08:00||;False|2025-11-30T19:01:59.4711045+08:00||;True|2025-11-30T18:16:01.8372242+08:00||;True|2025-11-30T14:50:31.9356543+08:00||;True|2025-11-30T14:48:27.1833064+08:00||;</History> <History>True|2025-12-04T13:58:29.4112766Z||;True|2025-12-04T21:58:10.0382218+08:00||;True|2025-12-04T21:57:55.3894059+08:00||;True|2025-12-04T21:10:38.8943797+08:00||;True|2025-12-04T21:09:31.5024569+08:00||;True|2025-12-04T08:22:47.9617427+08:00||;False|2025-12-04T08:22:41.3759733+08:00||;True|2025-12-04T08:14:02.2478893+08:00||;True|2025-12-04T07:57:00.2208139+08:00||;True|2025-12-03T23:58:13.3693303+08:00||;True|2025-12-03T23:57:40.4257893+08:00||;True|2025-12-03T23:56:38.8717769+08:00||;True|2025-12-03T23:56:24.0663568+08:00||;False|2025-12-03T23:55:36.1902974+08:00||;True|2025-12-03T23:51:30.6688504+08:00||;True|2025-12-03T23:34:17.1648971+08:00||;False|2025-12-03T23:34:07.7649161+08:00||;True|2025-12-03T22:32:56.2435003+08:00||;True|2025-12-03T22:27:45.6059666+08:00||;True|2025-12-03T15:55:28.0186597+08:00||;False|2025-12-03T15:54:17.5032724+08:00||;True|2025-12-03T15:53:10.2273509+08:00||;True|2025-12-02T22:11:37.4645042+08:00||;False|2025-12-02T22:10:47.1320259+08:00||;True|2025-12-02T14:39:58.8932130+08:00||;True|2025-12-02T14:36:37.1529072+08:00||;True|2025-12-02T12:58:22.0951548+08:00||;True|2025-12-02T09:30:33.7066474+08:00||;True|2025-12-02T09:30:14.5481844+08:00||;True|2025-12-02T09:30:00.3123364+08:00||;False|2025-12-02T09:29:54.4615520+08:00||;True|2025-12-02T09:13:01.7995414+08:00||;False|2025-12-02T09:12:55.8360281+08:00||;True|2025-12-02T09:12:31.0156791+08:00||;True|2025-12-02T08:55:11.3773395+08:00||;True|2025-12-02T08:53:21.3927713+08:00||;False|2025-12-02T08:48:55.8638037+08:00||;True|2025-12-02T07:29:25.2192447+08:00||;False|2025-12-02T07:29:10.2504665+08:00||;True|2025-12-02T07:28:29.0769286+08:00||;True|2025-12-01T21:53:07.6474834+08:00||;True|2025-12-01T21:44:28.1674315+08:00||;True|2025-12-01T21:18:47.2119609+08:00||;True|2025-12-01T20:51:19.9948301+08:00||;True|2025-12-01T20:50:36.9904697+08:00||;True|2025-12-01T20:44:10.1695142+08:00||;True|2025-12-01T19:27:58.0479456+08:00||;True|2025-12-01T19:16:02.2288214+08:00||;False|2025-12-01T19:15:56.0372115+08:00||;True|2025-12-01T19:15:16.4854821+08:00||;False|2025-12-01T19:15:06.7001019+08:00||;True|2025-12-01T17:10:38.9739466+08:00||;False|2025-12-01T17:10:18.8928139+08:00||;True|2025-12-01T17:03:59.3171589+08:00||;True|2025-12-01T17:03:12.5681656+08:00||;True|2025-12-01T16:42:51.4415025+08:00||;True|2025-12-01T01:29:59.6975567+08:00||;True|2025-12-01T01:29:45.1898652+08:00||;False|2025-12-01T01:29:33.1787721+08:00||;True|2025-12-01T01:27:33.1297605+08:00||;True|2025-12-01T01:27:27.3976862+08:00||;False|2025-12-01T01:27:20.5193052+08:00||;True|2025-12-01T01:11:11.0210582+08:00||;True|2025-12-01T01:04:04.3307782+08:00||;True|2025-12-01T00:55:49.8018864+08:00||;True|2025-12-01T00:27:25.1323561+08:00||;True|2025-11-30T23:58:20.7284116+08:00||;True|2025-11-30T23:57:58.3027622+08:00||;True|2025-11-30T23:57:43.0829614+08:00||;False|2025-11-30T23:57:33.5606716+08:00||;True|2025-11-30T23:54:29.6203368+08:00||;True|2025-11-30T23:54:27.5383120+08:00||;False|2025-11-30T23:54:17.0823982+08:00||;True|2025-11-30T22:41:11.4538820+08:00||;True|2025-11-30T22:38:19.7064566+08:00||;True|2025-11-30T22:37:35.2889186+08:00||;True|2025-11-30T21:42:31.1408314+08:00||;True|2025-11-30T21:42:19.5385333+08:00||;False|2025-11-30T21:42:13.3290237+08:00||;True|2025-11-30T21:33:28.0806806+08:00||;True|2025-11-30T21:16:56.7088027+08:00||;False|2025-11-30T21:16:46.1444944+08:00||;True|2025-11-30T20:21:24.4059664+08:00||;False|2025-11-30T20:21:17.6006098+08:00||;True|2025-11-30T20:20:08.2030141+08:00||;False|2025-11-30T20:16:12.3608968+08:00||;True|2025-11-30T20:15:35.6048313+08:00||;True|2025-11-30T19:45:18.7229552+08:00||;True|2025-11-30T19:45:08.6083368+08:00||;False|2025-11-30T19:44:54.7824905+08:00||;True|2025-11-30T19:44:17.0179491+08:00||;True|2025-11-30T19:44:06.7073484+08:00||;False|2025-11-30T19:43:58.2896556+08:00||;True|2025-11-30T19:42:08.2261927+08:00||;True|2025-11-30T19:28:15.7115077+08:00||;False|2025-11-30T19:28:10.2280725+08:00||;True|2025-11-30T19:23:31.7859158+08:00||;True|2025-11-30T19:23:20.7788277+08:00||;True|2025-11-30T19:17:11.8583296+08:00||;False|2025-11-30T19:10:41.8369574+08:00||;</History>
<LastFailureDetails /> <LastFailureDetails />
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
+4 -4
View File
@@ -97,8 +97,8 @@ Cookie 及 `sec_user_id` 是同步功能的核心,需严格按步骤获取,
| 镜像标签 | 架构 | | 镜像标签 | 架构 |
| ----------------- | -------------- | | ----------------- | -------------- |
| `beta_1.7.5` | x86_64 (amd64) | | `beta_1.7.6` | x86_64 (amd64) |
| `arm_1.7.5` | ARM64 | | `arm_1.7.6` | ARM64 |
### 最新镜像查看 ### 最新镜像查看
[镜像列表](http://nas.synology2023.online:10108/api/docker/dysync/1) [镜像列表](http://nas.synology2023.online:10108/api/docker/dysync/1)
@@ -116,7 +116,7 @@ docker run -d --restart=always \
-v /opt/dysync/uper:/app/uper \ -v /opt/dysync/uper:/app/uper \
-p 10103:10101 \ -p 10103:10101 \
--name dysync2025 \ --name dysync2025 \
ccr.ccs.tencentyun.com/jianzhichu/dysync:beta_1.7.5 ccr.ccs.tencentyun.com/jianzhichu/dysync:beta_1.7.6
# 注意:-p 后面的容器端口,可以用环境变量类似:ASPNETCORE_URLS = http://+:10108 指定 # 注意:-p 后面的容器端口,可以用环境变量类似:ASPNETCORE_URLS = http://+:10108 指定
``` ```
@@ -130,7 +130,7 @@ version: '3.8'
services: services:
dysync: dysync:
image: ccr.ccs.tencentyun.com/jianzhichu/dysync:beta_1.7.5 image: ccr.ccs.tencentyun.com/jianzhichu/dysync:beta_1.7.6
container_name: dysync2025 # 容器名称 container_name: dysync2025 # 容器名称
restart: unless-stopped # 始终重启容器,除非容器被手动停止或Docker服务停止 restart: unless-stopped # 始终重启容器,除非容器被手动停止或Docker服务停止
ports: ports:
+5 -1
View File
@@ -43,7 +43,7 @@
</div> </div>
<div class="card-main-content"> <div class="card-main-content">
<div class="avatar-wrapper"> <div class="avatar-wrapper" @click="goDouyinUp(item)">
<a-avatar shape="circle" size="large" :src="item.uperAvatar" v-if="item.uperAvatar" /> <a-avatar shape="circle" size="large" :src="item.uperAvatar" v-if="item.uperAvatar" />
<a-avatar shape="circle" size="large" v-else class="avatar-placeholder"> <a-avatar shape="circle" size="large" v-else class="avatar-placeholder">
{{ item.uperName.charAt(0) }} {{ item.uperName.charAt(0) }}
@@ -667,6 +667,10 @@ const handleDeleteItem = (item: FollowItem) => {
}, },
}); });
}; };
const goDouyinUp = (item) => {
window.open('https://www.douyin.com/user/' + item.secUid, '_blank', 'noopener noreferrer');
};
</script> </script>
<style scoped> <style scoped>
+2 -1
View File
@@ -1,5 +1,6 @@
{ {
"dbconn": "", "dbconn": "",
"dbtype": "Sqlite", "dbtype": "Sqlite",
"tagName": "beta_1.7.5" "tagName": "beta_1.7.6",
//"tagName": "dev_1.2"
} }
+107 -31
View File
@@ -18,6 +18,7 @@ using Swashbuckle.AspNetCore.SwaggerGen;
using Swashbuckle.AspNetCore.SwaggerUI; using Swashbuckle.AspNetCore.SwaggerUI;
using System.IO.Compression; using System.IO.Compression;
using System.Net.Http; using System.Net.Http;
using System.Net.Security;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
@@ -171,51 +172,126 @@ namespace dy.net.extension
} }
//public static void AddHttpClients(this IServiceCollection services)
//{
// services.AddHttpClient("dy_collect", client =>
// {
// client.DefaultRequestHeaders.Add("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
// client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36");
// client.DefaultRequestHeaders.Add("Referer", "https://www.douyin.com");
// });
// services.AddHttpClient("dy_follow", client =>
// {
// client.DefaultRequestHeaders.Referrer = new Uri("https://www.douyin.com/user/self?showTab=like");
// });
// services.AddHttpClient("dy_favorite", client =>
// {
// client.DefaultRequestHeaders.Referrer = new Uri("https://www.douyin.com/user/self?showTab=like");
// });
// services.AddHttpClient("dy_uper", client =>
// {
// client.DefaultRequestHeaders.Referrer = new Uri("https://www.douyin.com/user/MS4wLjABAAAA1zFIBhWG-3qS8MiggDMhyCpqDnvfGYf_mtsdgtBzV7A?from_tab_name=main&showTab=post&vid=7576282367263807451");
// });
// // 配置HttpClientStartup.cs或Program.cs
// services.AddHttpClient("dy_download")
// .ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
// {
// // 控制并发连接数(根据服务器承受能力调整,建议5-20)
// MaxConnectionsPerServer = 5,
// // 禁用代理自动检测(减少不必要的延迟)
// UseProxy = false,
// // 连接超时(建立连接的超时时间)
// ConnectTimeout = TimeSpan.FromSeconds(60)
// })
// .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
// {
// ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true
// })
// // 配置客户端默认请求头
// .ConfigureHttpClient(client =>
// {
// client.DefaultRequestHeaders.Add("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
// client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36");
// client.DefaultRequestHeaders.Add("Referer", "https://www.douyin.com");
// });
//}
public static void AddHttpClients(this IServiceCollection services) public static void AddHttpClients(this IServiceCollection services)
{ {
services.AddHttpClient("dy_collect", client => // 通用的忽略SSL证书验证的HttpMessageHandler配置
Func<HttpMessageHandler> ignoreSslHandlerFactory = () =>
{ {
client.DefaultRequestHeaders.Add("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2"); var handler = new SocketsHttpHandler
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36");
client.DefaultRequestHeaders.Add("Referer", "https://www.douyin.com");
});
services.AddHttpClient("dy_follow", client =>
{
client.DefaultRequestHeaders.Referrer = new Uri("https://www.douyin.com/user/self?showTab=like");
});
services.AddHttpClient("dy_favorite", client =>
{
client.DefaultRequestHeaders.Referrer = new Uri("https://www.douyin.com/user/self?showTab=like");
});
services.AddHttpClient("dy_uper", client =>
{
client.DefaultRequestHeaders.Referrer = new Uri("https://www.douyin.com/user/MS4wLjABAAAA1zFIBhWG-3qS8MiggDMhyCpqDnvfGYf_mtsdgtBzV7A?from_tab_name=main&showTab=post&vid=7576282367263807451");
});
// 配置HttpClientStartup.cs或Program.cs
services.AddHttpClient("dy_download")
.ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
{ {
// 控制并发连接数(根据服务器承受能力调整,建议5-20) // 控制并发连接数(根据服务器承受能力调整,建议5-20)
MaxConnectionsPerServer = 5, MaxConnectionsPerServer = 5,
// 禁用代理自动检测(减少不必要的延迟) // 禁用代理自动检测(减少不必要的延迟)
UseProxy = false, UseProxy = false,
// 连接超时(建立连接的超时时间) // 连接超时(建立连接的超时时间)
ConnectTimeout = TimeSpan.FromSeconds(60) ConnectTimeout = TimeSpan.FromSeconds(60),
}) // 忽略HTTPS证书验证
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler SslOptions = new SslClientAuthenticationOptions
{ {
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true RemoteCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true
}) }
// 配置客户端默认请求头 };
return handler;
};
// 抖音采集客户端
services.AddHttpClient("dy_collect", client =>
{
client.DefaultRequestHeaders.Add("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36");
client.DefaultRequestHeaders.Add("Referer", "https://www.douyin.com");
}).ConfigurePrimaryHttpMessageHandler(ignoreSslHandlerFactory);
// 抖音关注客户端
services.AddHttpClient("dy_follow", client =>
{
client.DefaultRequestHeaders.Referrer = new Uri("https://www.douyin.com/user/self?showTab=like");
}).ConfigurePrimaryHttpMessageHandler(ignoreSslHandlerFactory);
// 抖音收藏客户端
services.AddHttpClient("dy_favorite", client =>
{
client.DefaultRequestHeaders.Referrer = new Uri("https://www.douyin.com/user/self?showTab=like");
}).ConfigurePrimaryHttpMessageHandler(ignoreSslHandlerFactory);
// 抖音UP主客户端
services.AddHttpClient("dy_uper", client =>
{
client.DefaultRequestHeaders.Referrer = new Uri("https://www.douyin.com/user/MS4wLjABAAAA1zFIBhWG-3qS8MiggDMhyCpqDnvfGYf_mtsdgtBzV7A?from_tab_name=main&showTab=post&vid=7576282367263807451");
}).ConfigurePrimaryHttpMessageHandler(ignoreSslHandlerFactory);
// 抖音下载客户端(单独配置,保持原有特性)
services.AddHttpClient("dy_download")
.ConfigurePrimaryHttpMessageHandler(ignoreSslHandlerFactory)
.ConfigureHttpClient(client => .ConfigureHttpClient(client =>
{ {
client.DefaultRequestHeaders.Add("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2"); client.DefaultRequestHeaders.Add("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"); client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36");
client.DefaultRequestHeaders.Add("Referer", "https://www.douyin.com"); client.DefaultRequestHeaders.Add("Referer", "https://www.douyin.com");
}); });
// 如果你需要兼容旧版.NET(使用HttpClientHandler而非SocketsHttpHandler),可以使用以下配置:
// Func<HttpMessageHandler> legacyIgnoreSslHandlerFactory = () =>
// {
// var handler = new HttpClientHandler
// {
// ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true,
// MaxConnectionsPerServer = 5,
// UseProxy = false,
// ConnectTimeout = TimeSpan.FromSeconds(60)
// };
// return handler;
// };
} }
/// <summary> /// <summary>
+45 -26
View File
@@ -26,11 +26,14 @@ namespace dy.net.job
/// </summary> /// </summary>
protected readonly DouyinFollowService _followService; protected readonly DouyinFollowService _followService;
public DouyinFollowedUsersSyncJob(DouyinCookieService dyCookieService, DouyinHttpClientService douyinService, DouyinFollowService followService) protected readonly DouyinCommonService douyinCommonService;
public DouyinFollowedUsersSyncJob(DouyinCookieService dyCookieService, DouyinHttpClientService douyinService, DouyinFollowService followService, DouyinCommonService douyinCommonService)
{ {
_dyCookieService = dyCookieService; _dyCookieService = dyCookieService;
_douyinService = douyinService; _douyinService = douyinService;
_followService = followService; _followService = followService;
this.douyinCommonService = douyinCommonService;
} }
public async Task Execute(IJobExecutionContext context) public async Task Execute(IJobExecutionContext context)
@@ -38,6 +41,7 @@ namespace dy.net.job
var cookies = await _dyCookieService.GetAllOpendAsync(); var cookies = await _dyCookieService.GetAllOpendAsync();
if (cookies != null && cookies.Any()) if (cookies != null && cookies.Any())
{ {
AppConfig conf = douyinCommonService.GetConfig();
foreach (var ck in cookies) foreach (var ck in cookies)
{ {
@@ -48,37 +52,52 @@ namespace dy.net.job
List<FollowingsItem> follows = new List<FollowingsItem>(); List<FollowingsItem> follows = new List<FollowingsItem>();
while (hasmore) while (hasmore)
{ {
var data = await _douyinService.SyncMyFollows(count, offset, ck.SecUserId, ck.Cookies, async err => try
{ {
if (err.StatusCode != 0) var data = await _douyinService.SyncMyFollows(count, offset, ck.SecUserId, ck.Cookies, async err =>
{ {
Serilog.Log.Error($"同步用户[{ck.UserName}]关注列表时发生错误,错误信息:{err.StatusMsg},状态码:{err.StatusCode}"); if (err.StatusCode != 0)
{
Serilog.Log.Error($"同步用户[{ck.UserName}]关注列表时发生错误,错误信息:{err.StatusMsg},状态码:{err.StatusCode}");
}
// 如果是未登录错误,则跳出循环
if (err.StatusCode == 8)
{
hasmore = false;
}
ck.StatusMsg = err.StatusCode == 8 ? "已过期" : "正 常";
ck.StatusCode = err.StatusCode;
await _dyCookieService.UpdateAsync(ck);
});
if (data != null)
{
// 绑定我的用户ID--之前没有这个字段
if (string.IsNullOrWhiteSpace(ck.MyUserId))
{
ck.MyUserId = data.MySelfUserId;
await _dyCookieService.UpdateAsync(ck);
}
total = data.Total;
hasmore = data.HasMore;
offset = data.Offset.ToString();
if (data.Followings != null && data.Followings.Count > 0)
{
follows.AddRange(data.Followings);
}
} }
// 如果是未登录错误,则跳出循环
if (err.StatusCode == 8) // 只有第一次启动时,才进行全部同步
if (!conf.IsFirstRunning)
{ {
hasmore = false; hasmore = false;
} }
ck.StatusMsg = err.StatusCode == 8 ? "已过期" : "正 常"; }
ck.StatusCode = err.StatusCode; catch (Exception ex)
await _dyCookieService.UpdateAsync(ck);
});
if (data != null)
{ {
// 绑定我的用户ID--之前没有这个字段 Serilog.Log.Error($"关注列表同步失败,{ex.Message}");
if (string.IsNullOrWhiteSpace(ck.MyUserId)) hasmore = false;
{ break;
ck.MyUserId = data.MySelfUserId;
await _dyCookieService.UpdateAsync(ck);
}
total = data.Total;
hasmore = data.HasMore;
offset = data.Offset.ToString();
if (data.Followings != null && data.Followings.Count > 0)
{
follows.AddRange(data.Followings);
}
} }
} }
@@ -87,8 +106,8 @@ namespace dy.net.job
await _followService.Sync(follows, ck ); await _followService.Sync(follows, ck );
} }
//Serilog.Log.Debug($"当前Cookie-[{ck.UserName}],本次同步关注列表完成,当前共关注{total}人。");
} }
await douyinCommonService.SetConfigNotFirstRunning();
} }
} }
} }
+4 -1
View File
@@ -8,7 +8,10 @@ namespace dy.net.model
[SugarTable(TableName = "dy_app_config")] [SugarTable(TableName = "dy_app_config")]
public class AppConfig public class AppConfig
{ {
/// <summary>
/// 是否是程序启动时...
/// </summary>
public bool IsFirstRunning { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
+172 -52
View File
@@ -87,17 +87,18 @@ namespace dy.net.repository
.ToListAsync(); .ToListAsync();
} }
/// <summary> /// <summary>
/// 同步关注列表(新增名字和签名变更检测) /// 同步关注列表(新增名字和签名变更检测)
/// </summary> /// </summary>
/// <param name="followInfos"></param> /// <param name="followInfos"></param>
/// <param name="myselfUserId"></param> /// <param name="ck"></param>
/// <returns></returns> /// <returns></returns>
public async Task<bool> Sync(List<FollowingsItem> followInfos, DouyinCookie ck) public async Task<bool> Sync(List<FollowingsItem> followInfos, DouyinCookie ck)
{ {
// 基础参数校验 // 基础参数校验
if (followInfos == null) followInfos = new List<FollowingsItem>(); if (followInfos == null) followInfos = new List<FollowingsItem>();
if (ck==null || string.IsNullOrWhiteSpace(ck.MyUserId)) if (ck == null || string.IsNullOrWhiteSpace(ck.MyUserId))
{ {
Serilog.Log.Error("同步关注列表失败:当前用户ID为空"); Serilog.Log.Error("同步关注列表失败:当前用户ID为空");
return false; return false;
@@ -105,51 +106,51 @@ namespace dy.net.repository
try try
{ {
// 1. 查询现有关注列表 // 1. 提取当前批次的SecUid集合(去重)
HashSet<string> currentSecUids = followInfos.Select(x => x.SecUid).ToHashSet();
if (!currentSecUids.Any())
{
Serilog.Log.Debug($"同步关注列表:当前批次无有效数据({ck.UserName}),直接返回成功");
return true;
}
// 2. 查询当前批次对应的现有记录(仅查需要对比的,减少数据量)
List<DouyinFollowed> existFollows = await Db.Queryable<DouyinFollowed>() List<DouyinFollowed> existFollows = await Db.Queryable<DouyinFollowed>()
.Where(x => x.mySelfId == ck.MyUserId) .Where(x => x.mySelfId == ck.MyUserId)
.Where(x=>!x.IsNoFollowed) //排除手动添加但未关注的用户 .Where(x => !x.IsNoFollowed)
.Where(x => currentSecUids.Contains(x.SecUid)) // 仅查当前批次的SecUid
.ToListAsync() ?? new List<DouyinFollowed>(); .ToListAsync() ?? new List<DouyinFollowed>();
// 2. 提取现有和当前的SecUid集合(去重优化) // 3. 拆分:新增(当前批次有,数据库无) + 更新(当前批次有,数据库也有且字段变化)
HashSet<string> existSecUids = existFollows.Select(x => x.SecUid).ToHashSet(); HashSet<string> existSecUids = existFollows.Select(x => x.SecUid).ToHashSet();
HashSet<string> currentSecUids = followInfos.Select(x => x.SecUid).ToHashSet();
// 3. 计算新增、待删除和需要更新的记录
var toAddFollows = followInfos.Where(x => !existSecUids.Contains(x.SecUid)).ToList(); var toAddFollows = followInfos.Where(x => !existSecUids.Contains(x.SecUid)).ToList();
var toRemoveFollows = existFollows.Where(x => !currentSecUids.Contains(x.SecUid)).ToList();
// 3.1 筛选需要更新的记录(SecUid存在但名字或签名有变更)
var toUpdateFollows = new List<DouyinFollowed>(); var toUpdateFollows = new List<DouyinFollowed>();
// 3.1 筛选需要更新的记录
foreach (var existFollow in existFollows) foreach (var existFollow in existFollows)
{ {
var newFollow = followInfos.FirstOrDefault(x => x.SecUid == existFollow.SecUid); var newFollow = followInfos.FirstOrDefault(x => x.SecUid == existFollow.SecUid);
if (newFollow == null) continue; if (newFollow == null) continue;
// 检查名字或签名是否变更(精确匹配,区分大小写和空格 // 检查字段是否变更(精确匹配)
bool nameChanged = !string.Equals(existFollow.UperName, newFollow.NickName, StringComparison.Ordinal); bool nameChanged = !string.Equals(existFollow.UperName, newFollow.NickName, StringComparison.Ordinal);
bool signatureChanged = !string.Equals(existFollow.Signature, newFollow.Signature, StringComparison.Ordinal); bool signatureChanged = !string.Equals(existFollow.Signature, newFollow.Signature, StringComparison.Ordinal);
bool enterpriseChanged = !string.Equals(existFollow.Enterprise, newFollow.EnterpriseVerifyReason, StringComparison.Ordinal); bool enterpriseChanged = !string.Equals(existFollow.Enterprise, newFollow.EnterpriseVerifyReason, StringComparison.Ordinal);
bool uperAvatarChanged = !string.Equals(existFollow.UperAvatar, newFollow.Avatar.UrlList?.FirstOrDefault()??"", StringComparison.Ordinal); bool uperAvatarChanged = !string.Equals(existFollow.UperAvatar, newFollow.Avatar?.UrlList?.FirstOrDefault() ?? "", StringComparison.Ordinal);
//bool uperIdChanged = !string.Equals(existFollow.UperId, newFollow.UperId, StringComparison.Ordinal);
if (nameChanged || signatureChanged|| uperAvatarChanged|| enterpriseChanged) if (nameChanged || signatureChanged || uperAvatarChanged || enterpriseChanged)
{ {
// 构造更新实体(仅赋值变更字段和必要字段) toUpdateFollows.Add(new DouyinFollowed
var updateEntity = new DouyinFollowed
{ {
Id = existFollow.Id, // 主键必须保留,用于匹配 Id = existFollow.Id, // 主键用于匹配
mySelfId = existFollow.mySelfId, mySelfId = ck.MyUserId,
SecUid = existFollow.SecUid, SecUid = existFollow.SecUid,
UperName = newFollow.NickName, // 新名字 UperName = newFollow.NickName,
Signature = newFollow.Signature, // 新签名 Signature = newFollow.Signature,
UperId = newFollow.UperId, // 新的UperId Enterprise = newFollow.EnterpriseVerifyReason,
UperAvatar = newFollow.Avatar?.UrlList?.FirstOrDefault() ?? "", // 新头像 UperAvatar = newFollow.Avatar?.UrlList?.FirstOrDefault() ?? "",
Enterprise = newFollow.EnterpriseVerifyReason, // 新企业认证
LastSyncTime = DateTime.UtcNow // 更新同步时间 LastSyncTime = DateTime.UtcNow // 更新同步时间
// 其他字段(如Enterprise、UperAvatar、OpenSync)保留原有值,无需赋值 });
};
toUpdateFollows.Add(updateEntity);
} }
} }
@@ -180,19 +181,17 @@ namespace dy.net.repository
} }
} }
// 5. 分批处理更新(适配 SQLSugar 语法UpdateColumns + WhereColumns // 5. 分批处理更新(适配SQLSugar语法)
if (toUpdateFollows.Any()) if (toUpdateFollows.Any())
{ {
bool batchUpdateSuccess = await BatchProcessAsync(toUpdateFollows, 200, bool batchUpdateSuccess = await BatchProcessAsync(toUpdateFollows, 200,
async batch => async batch =>
{ {
// SQLSugar 正确用法:实体集合更新 + UpdateColumns(指定更新字段) + WhereColumns(指定匹配字段/主键) int affectedRows = await Db.Updateable(batch)
int affectedRows = await Db.Updateable(batch) // 传入更新实体集合 .UpdateColumns(x => new { x.UperName, x.Signature, x.LastSyncTime, x.Enterprise, x.UperAvatar })
.UpdateColumns(x => new { x.UperName, x.Signature, x.LastSyncTime,x.Enterprise,x.UperAvatar}) // 仅更新这3个字段 .WhereColumns(x => x.Id) // 按主键匹配
.WhereColumns(x => x.Id) // 按主键Id匹配现有记录
.ExecuteCommandAsync(); .ExecuteCommandAsync();
// 受影响行数 > 0 或 批次无数据(正常),返回true;否则返回false
return affectedRows >= 0; return affectedRows >= 0;
}); });
@@ -203,25 +202,8 @@ namespace dy.net.repository
} }
} }
// 6. 分批处理删除(单批200条) // 【重要】删除逻辑已移除:增量场景下不能通过批次对比删除,需单独设计取消关注逻辑
if (toRemoveFollows.Any()) Serilog.Log.Debug($"dy_followed_users{ck.UserName})关注列表同步完成:新增{toAddFollows.Count}条,更新{toUpdateFollows.Count}条");
{
bool batchDeleteSuccess = await BatchProcessAsync(toRemoveFollows, 200,
async batch =>
{
var secUids = batch.Select(x => x.SecUid).ToList();
await DeleteAsync(x => x.mySelfId == ck.MyUserId && secUids.Contains(x.SecUid));
return true;
});
if (!batchDeleteSuccess)
{
Serilog.Log.Error("同步关注列表失败:取消关注分批删除异常");
return false;
}
}
Serilog.Log.Debug($"dy_followed_users{ck.UserName})关注列表同步完成:新增{toAddFollows.Count}条,更新{toUpdateFollows.Count}条,删除{toRemoveFollows.Count}条");
return true; return true;
} }
catch (Exception ex) catch (Exception ex)
@@ -230,6 +212,144 @@ namespace dy.net.repository
return false; return false;
} }
} }
//public async Task<bool> Sync(List<FollowingsItem> followInfos, DouyinCookie ck)
//{
// // 基础参数校验
// if (followInfos == null) followInfos = new List<FollowingsItem>();
// if (ck==null || string.IsNullOrWhiteSpace(ck.MyUserId))
// {
// Serilog.Log.Error("同步关注列表失败:当前用户ID为空");
// return false;
// }
// try
// {
// // 1. 查询现有关注列表
// List<DouyinFollowed> existFollows = await Db.Queryable<DouyinFollowed>()
// .Where(x => x.mySelfId == ck.MyUserId)
// .Where(x=>!x.IsNoFollowed) //排除手动添加但未关注的用户
// .ToListAsync() ?? new List<DouyinFollowed>();
// // 2. 提取现有和当前的SecUid集合(去重优化)
// HashSet<string> existSecUids = existFollows.Select(x => x.SecUid).ToHashSet();
// HashSet<string> currentSecUids = followInfos.Select(x => x.SecUid).ToHashSet();
// // 3. 计算新增、待删除和需要更新的记录
// var toAddFollows = followInfos.Where(x => !existSecUids.Contains(x.SecUid)).ToList();
// var toRemoveFollows = existFollows.Where(x => !currentSecUids.Contains(x.SecUid)).ToList();
// // 3.1 筛选需要更新的记录(SecUid存在但名字或签名有变更)
// var toUpdateFollows = new List<DouyinFollowed>();
// foreach (var existFollow in existFollows)
// {
// var newFollow = followInfos.FirstOrDefault(x => x.SecUid == existFollow.SecUid);
// if (newFollow == null) continue;
// // 检查名字或签名是否变更(精确匹配,区分大小写和空格)
// bool nameChanged = !string.Equals(existFollow.UperName, newFollow.NickName, StringComparison.Ordinal);
// bool signatureChanged = !string.Equals(existFollow.Signature, newFollow.Signature, StringComparison.Ordinal);
// bool enterpriseChanged = !string.Equals(existFollow.Enterprise, newFollow.EnterpriseVerifyReason, StringComparison.Ordinal);
// bool uperAvatarChanged = !string.Equals(existFollow.UperAvatar, newFollow.Avatar.UrlList?.FirstOrDefault()??"", StringComparison.Ordinal);
// //bool uperIdChanged = !string.Equals(existFollow.UperId, newFollow.UperId, StringComparison.Ordinal);
// if (nameChanged || signatureChanged|| uperAvatarChanged|| enterpriseChanged)
// {
// // 构造更新实体(仅赋值变更字段和必要字段)
// var updateEntity = new DouyinFollowed
// {
// Id = existFollow.Id, // 主键必须保留,用于匹配
// mySelfId = existFollow.mySelfId,
// SecUid = existFollow.SecUid,
// UperName = newFollow.NickName, // 新名字
// Signature = newFollow.Signature, // 新签名
// UperId = newFollow.UperId, // 新的UperId
// UperAvatar = newFollow.Avatar?.UrlList?.FirstOrDefault() ?? "", // 新头像
// Enterprise = newFollow.EnterpriseVerifyReason, // 新企业认证
// LastSyncTime = DateTime.UtcNow // 更新同步时间
// // 其他字段(如Enterprise、UperAvatar、OpenSync)保留原有值,无需赋值
// };
// toUpdateFollows.Add(updateEntity);
// }
// }
// // 4. 分批处理新增(单批200条)
// if (toAddFollows.Any())
// {
// Func<FollowingsItem, DouyinFollowed> mapToDouyinFollowed = follow => new DouyinFollowed
// {
// Id = IdGener.GetLong().ToString(),
// Enterprise = follow.EnterpriseVerifyReason,
// LastSyncTime = DateTime.UtcNow,
// mySelfId = ck.MyUserId,
// SecUid = follow.SecUid,
// OpenSync = false,
// UperAvatar = follow.Avatar?.UrlList?.FirstOrDefault() ?? "",
// UperName = follow.NickName,
// Signature = follow.Signature,
// UperId = follow.UperId
// };
// bool batchAddSuccess = await BatchProcessAsync(toAddFollows, 200,
// async batch => await BatchInsert(batch.Select(mapToDouyinFollowed).ToList()));
// if (!batchAddSuccess)
// {
// Serilog.Log.Error("同步关注列表失败:新增关注分批插入异常");
// return false;
// }
// }
// // 5. 分批处理更新(适配 SQLSugar 语法:UpdateColumns + WhereColumns
// if (toUpdateFollows.Any())
// {
// bool batchUpdateSuccess = await BatchProcessAsync(toUpdateFollows, 200,
// async batch =>
// {
// // SQLSugar 正确用法:实体集合更新 + UpdateColumns(指定更新字段) + WhereColumns(指定匹配字段/主键)
// int affectedRows = await Db.Updateable(batch) // 传入更新实体集合
// .UpdateColumns(x => new { x.UperName, x.Signature, x.LastSyncTime,x.Enterprise,x.UperAvatar}) // 仅更新这3个字段
// .WhereColumns(x => x.Id) // 按主键Id匹配现有记录
// .ExecuteCommandAsync();
// // 受影响行数 > 0 或 批次无数据(正常),返回true;否则返回false
// return affectedRows >= 0;
// });
// if (!batchUpdateSuccess)
// {
// Serilog.Log.Error("同步关注列表失败:关注信息更新异常");
// return false;
// }
// }
// // 6. 分批处理删除(单批200条)
// if (toRemoveFollows.Any())
// {
// bool batchDeleteSuccess = await BatchProcessAsync(toRemoveFollows, 200,
// async batch =>
// {
// var secUids = batch.Select(x => x.SecUid).ToList();
// await DeleteAsync(x => x.mySelfId == ck.MyUserId && secUids.Contains(x.SecUid));
// return true;
// });
// if (!batchDeleteSuccess)
// {
// Serilog.Log.Error("同步关注列表失败:取消关注分批删除异常");
// return false;
// }
// }
// Serilog.Log.Debug($"dy_followed_users{ck.UserName})关注列表同步完成:新增{toAddFollows.Count}条,更新{toUpdateFollows.Count}条,删除{toRemoveFollows.Count}条");
// return true;
// }
// catch (Exception ex)
// {
// Serilog.Log.Error(ex, $"同步关注列表失败({ck.UserName}):{ex.Message}");
// return false;
// }
//}
/// <summary> /// <summary>
/// 通用分批处理工具方法 /// 通用分批处理工具方法
+24 -4
View File
@@ -24,7 +24,6 @@ namespace dy.net.service
/// <summary> /// <summary>
/// 初始化并返回配置 /// 初始化并返回配置
/// </summary> /// </summary>
/// <param name="downLoadImage"></param>
/// <returns></returns> /// <returns></returns>
public AppConfig InitConfig() public AppConfig InitConfig()
{ {
@@ -34,9 +33,10 @@ namespace dy.net.service
if (string.IsNullOrWhiteSpace(conf.PriorityLevel)) if (string.IsNullOrWhiteSpace(conf.PriorityLevel))
{ {
conf.PriorityLevel = "[{\"id\":1,\"name\":\"喜欢的视频\",\"sort\":1},{\"id\":2,\"name\":\"收藏的视频\",\"sort\":2},{\"id\":3,\"name\":\"关注的视频\",\"sort\":3}]"; conf.PriorityLevel = "[{\"id\":1,\"name\":\"喜欢的视频\",\"sort\":1},{\"id\":2,\"name\":\"收藏的视频\",\"sort\":2},{\"id\":3,\"name\":\"关注的视频\",\"sort\":3}]";
sqlSugarClient.Updateable(conf).ExecuteCommand();
//兼容旧版本
} }
conf.IsFirstRunning = true;//标记为程序刚启动第一次运行
sqlSugarClient.Updateable(conf).ExecuteCommand();
//兼容旧版本
return conf; return conf;
} }
else else
@@ -57,7 +57,8 @@ namespace dy.net.service
FullFollowedTitleTemplate = "", FullFollowedTitleTemplate = "",
FollowedTitleSeparator = "", FollowedTitleSeparator = "",
AutoDistinct = true,//默认开启 AutoDistinct = true,//默认开启
PriorityLevel= "[{\"id\":1,\"name\":\"喜欢的视频\",\"sort\":1},{\"id\":2,\"name\":\"收藏的视频\",\"sort\":2},{\"id\":3,\"name\":\"关注的视频\",\"sort\":3}]" PriorityLevel = "[{\"id\":1,\"name\":\"喜欢的视频\",\"sort\":1},{\"id\":2,\"name\":\"收藏的视频\",\"sort\":2},{\"id\":3,\"name\":\"关注的视频\",\"sort\":3}]",
IsFirstRunning = true
}; };
sqlSugarClient.Insertable(config).ExecuteCommand(); sqlSugarClient.Insertable(config).ExecuteCommand();
return config; return config;
@@ -66,6 +67,25 @@ namespace dy.net.service
} }
/// <summary>
/// 更新AppConfig的IsFirstRunning属性为fasle
/// </summary>
/// <returns></returns>
public async Task SetConfigNotFirstRunning()
{
//更新IsFirstRunning为false
await sqlSugarClient.Updateable<AppConfig>()
.SetColumns(x => x.IsFirstRunning == false)
.Where(x => x.IsFirstRunning == true)
.ExecuteCommandAsync();
}
/// <summary>
/// 更新配置
/// </summary>
/// <param name="config"></param>
/// <returns></returns>
public async Task<bool> UpdateConfig(AppConfig config) public async Task<bool> UpdateConfig(AppConfig config)
{ {
+2 -9
View File
@@ -293,25 +293,18 @@ namespace dy.net.service
catch (Exception ex) catch (Exception ex)
{ {
Serilog.Log.Error($"SyncMyFollows error: {ex.Message}"); Serilog.Log.Error($"SyncMyFollows error: {ex.Message}");
return null; throw;
} }
} }
public async Task<bool> SyncReDown(string awemeId,string cookie) //
{
return false;
//有空再研究把.a_bogus算法有问题
}
//AI优化2
/// <summary> /// <summary>
/// 下载文件并保存到本地(支持重试机制,优化批量下载稳定性) /// 下载文件并保存到本地(支持重试机制,优化批量下载稳定性)
/// </summary> /// </summary>
/// <param name="videoUrl">文件地址</param> /// <param name="videoUrl">文件地址</param>
/// <param name="savePath">保存路径</param> /// <param name="savePath">保存路径</param>
/// <param name="cookie">请求Cookie</param> /// <param name="cookie">请求Cookie</param>
/// <param name="httpclientName">HttpClient名称(默认"dy_down1"</param>
/// <param name="cancellationToken">取消令牌(用于终止任务)</param> /// <param name="cancellationToken">取消令牌(用于终止任务)</param>
/// <param name="streamTimeout">流读取超时时间(默认60秒)</param> /// <param name="streamTimeout">流读取超时时间(默认60秒)</param>
/// <param name="maxRetryCount">最大重试次数(默认3次)</param> /// <param name="maxRetryCount">最大重试次数(默认3次)</param>
+3 -3
View File
@@ -102,15 +102,15 @@ namespace dy.net.service
// 3. 只启动第一个任务(collect),后续任务由 Listener 自动触发 // 3. 只启动第一个任务(collect),后续任务由 Listener 自动触发
var firstJobConfigKey = "collect"; var firstJobConfigKey = "collect";
var startSuccess = await StartJobAsync(firstJobConfigKey, expression); var startSuccess = await StartJobAsync(firstJobConfigKey, expression);
if (startSuccess) if (startSuccess)
{ {
Log.Debug("【任务服务】任务链条启动成功!执行顺序collect → favorite → followed → follow_user", expression); Log.Debug($"任务开始执行collect → favorite → followed → follow_user-->每{expression}分钟执行一次...");
} }
else else
{ {
Log.Error("【任务服务】任务链条启动失败(第一个任务 {FirstJob} 启动失败)", firstJobConfigKey); Log.Error($"任务执行失败(任务 {firstJobConfigKey} 启动失败)");
} }
//启动follow_user--这个与其他几个任务没有依赖关系,所以单独启动 //启动follow_user--这个与其他几个任务没有依赖关系,所以单独启动
await StartJobAsync("follow_user", expression); await StartJobAsync("follow_user", expression);