优化
This commit is contained in:
@@ -169,6 +169,8 @@ namespace dy.net.Controllers
|
||||
if (!cookieValid)
|
||||
return ApiResult.Fail("Cookie无效,请按照文档提示重新获取有效Cookie,不要使用插件获取cookie");
|
||||
|
||||
dyUserCookies.StatusCode = 0;
|
||||
dyUserCookies.StatusMsg = "正常";
|
||||
// 4. 保存到数据库
|
||||
var saved = await dyCookieService.Add(dyUserCookies);
|
||||
return saved ? ApiResult.Success() : ApiResult.Fail("添加失败");
|
||||
@@ -229,7 +231,8 @@ namespace dy.net.Controllers
|
||||
{
|
||||
return ApiResult.Fail("Cookie无效,请按照文档提示重新获取有效Cookie,不要使用插件获取cookie");
|
||||
}
|
||||
|
||||
dyUserCookies.StatusCode = 0;
|
||||
dyUserCookies.StatusMsg = "正常";
|
||||
if (dyUserCookies.Id == "0")
|
||||
{
|
||||
dyUserCookies.Id = IdGener.GetLong().ToString();
|
||||
|
||||
@@ -103,7 +103,11 @@ namespace dy.net.Controllers
|
||||
return await OpenOrCloseSync(dto);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 删除关注对象
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("delete")]
|
||||
public async Task<IActionResult> DeleteFollow(FollowUpdateDto dto)
|
||||
{
|
||||
|
||||
+2
-1
@@ -229,8 +229,9 @@ namespace dy.net
|
||||
var config = commonService.InitConfig();
|
||||
|
||||
//Serilog.Log.Debug("isRestart1=" + config.IsFirstRunning);
|
||||
await cookieService.UpdateCookieToSupportOldVersionAsync();
|
||||
|
||||
//if (!isDevelopment)
|
||||
if (!isDevelopment)
|
||||
{
|
||||
var cookie = await cookieService.GetOpendCookies();
|
||||
if (cookie != null && cookie.Any())
|
||||
|
||||
@@ -17,6 +17,6 @@
|
||||
<SelfContained>false</SelfContained>
|
||||
<!--<DockerArch>x86</DockerArch>-->
|
||||
<!--<DockerArch>arm</DockerArch> -->
|
||||
<!--<DockerCoreVersion>2.0.5</DockerCoreVersion>-->
|
||||
<!--<DockerCoreVersion>2.0.6</DockerCoreVersion>-->
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -3,7 +3,7 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<_PublishTargetUrl>E:\code\dysync\bin\Release\net6.0\publish\</_PublishTargetUrl>
|
||||
<History>True|2026-01-25T13:27:13.9893777Z||;True|2026-01-24T21:45:22.8493624+08:00||;True|2026-01-24T21:31:35.4635265+08:00||;True|2026-01-24T21:27:31.3098506+08:00||;True|2026-01-24T15:47:01.6934638+08:00||;True|2026-01-24T15:32:35.6316009+08:00||;True|2026-01-24T15:16:28.7216639+08:00||;True|2026-01-23T22:14:26.8066324+08:00||;True|2026-01-23T13:36:48.4086406+08:00||;True|2026-01-23T13:30:27.2924204+08:00||;True|2026-01-23T13:02:53.3219368+08:00||;True|2026-01-23T13:01:54.3466638+08:00||;True|2026-01-23T13:01:28.8560809+08:00||;True|2026-01-22T23:18:32.0400436+08:00||;True|2026-01-22T22:29:29.5746209+08:00||;True|2026-01-22T21:32:21.7284081+08:00||;True|2026-01-22T21:20:26.5985955+08:00||;False|2026-01-22T21:20:21.1372539+08:00||;True|2026-01-22T21:11:18.3771739+08:00||;True|2026-01-22T20:58:55.9862778+08:00||;True|2026-01-22T20:51:48.6699461+08:00||;False|2026-01-22T20:51:42.2079210+08:00||;True|2026-01-22T20:50:34.7280114+08:00||;True|2026-01-22T20:50:11.1588492+08:00||;True|2026-01-22T16:11:14.0626037+08:00||;True|2026-01-22T15:53:16.6377347+08:00||;True|2026-01-22T15:45:34.0935091+08:00||;True|2026-01-22T12:44:28.1577014+08:00||;True|2026-01-22T12:40:45.7449335+08:00||;True|2026-01-22T12:39:07.0683214+08:00||;True|2026-01-22T09:55:49.7086190+08:00||;True|2026-01-22T01:37:53.6972395+08:00||;True|2026-01-22T01:34:14.2142463+08:00||;True|2026-01-22T01:32:50.9228911+08:00||;True|2026-01-22T01:29:43.8871986+08:00||;True|2026-01-22T01:29:40.7838709+08:00||;True|2026-01-22T01:27:34.4763970+08:00||;True|2026-01-22T01:26:55.0117367+08:00||;True|2026-01-22T01:23:19.4789587+08:00||;True|2026-01-19T10:19:44.8997385+08:00||;True|2026-01-19T10:11:10.2305307+08:00||;True|2026-01-17T00:52:08.8180346+08:00||;False|2026-01-17T00:52:03.1829000+08:00||;True|2026-01-17T00:45:04.0498090+08:00||;True|2026-01-16T21:00:57.7239379+08:00||;True|2026-01-16T21:00:03.3912989+08:00||;True|2026-01-16T20:56:08.5505592+08:00||;True|2026-01-16T20:46:32.3067302+08:00||;True|2026-01-15T22:18:57.9835738+08:00||;True|2026-01-15T22:07:25.4753938+08:00||;True|2026-01-15T22:07:14.8243754+08:00||;True|2026-01-15T21:40:13.2613927+08:00||;True|2026-01-15T20:57:56.6291682+08:00||;True|2026-01-15T20:57:47.1363536+08:00||;True|2026-01-15T20:08:44.4710883+08:00||;True|2026-01-15T20:04:51.8284314+08:00||;False|2026-01-15T20:04:45.3258155+08:00||;True|2026-01-15T19:59:11.7907672+08:00||;True|2026-01-15T01:10:48.9066941+08:00||;True|2026-01-15T01:03:23.6216975+08:00||;True|2026-01-15T01:03:16.3364591+08:00||;False|2026-01-15T01:03:10.5654436+08:00||;True|2026-01-15T00:49:21.6559622+08:00||;True|2026-01-15T00:10:42.7288439+08:00||;True|2026-01-15T00:06:28.4241682+08:00||;True|2026-01-13T22:34:15.2372411+08:00||;True|2026-01-13T22:26:46.4522947+08:00||;True|2026-01-13T22:15:56.9735179+08:00||;True|2026-01-13T22:15:51.8250677+08:00||;False|2026-01-13T22:15:46.6608690+08:00||;True|2026-01-13T22:03:06.4683237+08:00||;False|2026-01-13T22:03:01.2036027+08:00||;True|2026-01-13T21:36:05.8776209+08:00||;True|2026-01-13T21:33:02.0766289+08:00||;False|2026-01-13T21:32:57.1976141+08:00||;True|2026-01-13T19:14:35.2519439+08:00||;True|2026-01-13T15:07:50.0836745+08:00||;False|2026-01-13T15:06:35.5929685+08:00||;True|2026-01-13T10:21:41.6012776+08:00||;True|2026-01-13T09:57:25.4788847+08:00||;True|2026-01-13T09:53:14.4900360+08:00||;True|2026-01-13T09:23:53.6465295+08:00||;True|2026-01-12T22:04:14.5886955+08:00||;False|2026-01-12T22:04:08.2008101+08:00||;True|2026-01-12T21:53:46.9947176+08:00||;True|2026-01-12T21:11:15.8358024+08:00||;True|2026-01-12T21:09:51.8663228+08:00||;True|2026-01-11T21:25:07.5052845+08:00||;False|2026-01-11T21:24:27.5744557+08:00||;True|2026-01-11T19:59:15.4734611+08:00||;False|2026-01-11T19:59:04.9543339+08:00||;True|2026-01-11T18:51:30.6649269+08:00||;True|2026-01-08T21:07:57.5094466+08:00||;True|2026-01-08T14:51:18.2266231+08:00||;True|2026-01-08T14:31:55.1137120+08:00||;True|2026-01-08T00:16:24.4451490+08:00||;True|2026-01-08T00:14:20.7430793+08:00||;True|2026-01-08T00:07:46.7228194+08:00||;True|2026-01-07T23:52:13.3290082+08:00||;True|2026-01-07T23:49:28.4838650+08:00||;</History>
|
||||
<History>True|2026-01-26T14:30:43.5083924Z||;False|2026-01-26T22:30:33.7355213+08:00||;True|2026-01-26T22:26:26.0218548+08:00||;True|2026-01-26T22:21:32.3171217+08:00||;True|2026-01-26T22:20:40.3916780+08:00||;True|2026-01-26T22:16:19.1017273+08:00||;True|2026-01-26T22:13:34.2028883+08:00||;True|2026-01-26T21:46:23.7117812+08:00||;True|2026-01-26T21:41:19.6963033+08:00||;True|2026-01-25T21:27:13.9893777+08:00||;True|2026-01-24T21:45:22.8493624+08:00||;True|2026-01-24T21:31:35.4635265+08:00||;True|2026-01-24T21:27:31.3098506+08:00||;True|2026-01-24T15:47:01.6934638+08:00||;True|2026-01-24T15:32:35.6316009+08:00||;True|2026-01-24T15:16:28.7216639+08:00||;True|2026-01-23T22:14:26.8066324+08:00||;True|2026-01-23T13:36:48.4086406+08:00||;True|2026-01-23T13:30:27.2924204+08:00||;True|2026-01-23T13:02:53.3219368+08:00||;True|2026-01-23T13:01:54.3466638+08:00||;True|2026-01-23T13:01:28.8560809+08:00||;True|2026-01-22T23:18:32.0400436+08:00||;True|2026-01-22T22:29:29.5746209+08:00||;True|2026-01-22T21:32:21.7284081+08:00||;True|2026-01-22T21:20:26.5985955+08:00||;False|2026-01-22T21:20:21.1372539+08:00||;True|2026-01-22T21:11:18.3771739+08:00||;True|2026-01-22T20:58:55.9862778+08:00||;True|2026-01-22T20:51:48.6699461+08:00||;False|2026-01-22T20:51:42.2079210+08:00||;True|2026-01-22T20:50:34.7280114+08:00||;True|2026-01-22T20:50:11.1588492+08:00||;True|2026-01-22T16:11:14.0626037+08:00||;True|2026-01-22T15:53:16.6377347+08:00||;True|2026-01-22T15:45:34.0935091+08:00||;True|2026-01-22T12:44:28.1577014+08:00||;True|2026-01-22T12:40:45.7449335+08:00||;True|2026-01-22T12:39:07.0683214+08:00||;True|2026-01-22T09:55:49.7086190+08:00||;True|2026-01-22T01:37:53.6972395+08:00||;True|2026-01-22T01:34:14.2142463+08:00||;True|2026-01-22T01:32:50.9228911+08:00||;True|2026-01-22T01:29:43.8871986+08:00||;True|2026-01-22T01:29:40.7838709+08:00||;True|2026-01-22T01:27:34.4763970+08:00||;True|2026-01-22T01:26:55.0117367+08:00||;True|2026-01-22T01:23:19.4789587+08:00||;True|2026-01-19T10:19:44.8997385+08:00||;True|2026-01-19T10:11:10.2305307+08:00||;True|2026-01-17T00:52:08.8180346+08:00||;False|2026-01-17T00:52:03.1829000+08:00||;True|2026-01-17T00:45:04.0498090+08:00||;True|2026-01-16T21:00:57.7239379+08:00||;True|2026-01-16T21:00:03.3912989+08:00||;True|2026-01-16T20:56:08.5505592+08:00||;True|2026-01-16T20:46:32.3067302+08:00||;True|2026-01-15T22:18:57.9835738+08:00||;True|2026-01-15T22:07:25.4753938+08:00||;True|2026-01-15T22:07:14.8243754+08:00||;True|2026-01-15T21:40:13.2613927+08:00||;True|2026-01-15T20:57:56.6291682+08:00||;True|2026-01-15T20:57:47.1363536+08:00||;True|2026-01-15T20:08:44.4710883+08:00||;True|2026-01-15T20:04:51.8284314+08:00||;False|2026-01-15T20:04:45.3258155+08:00||;True|2026-01-15T19:59:11.7907672+08:00||;True|2026-01-15T01:10:48.9066941+08:00||;True|2026-01-15T01:03:23.6216975+08:00||;True|2026-01-15T01:03:16.3364591+08:00||;False|2026-01-15T01:03:10.5654436+08:00||;True|2026-01-15T00:49:21.6559622+08:00||;True|2026-01-15T00:10:42.7288439+08:00||;True|2026-01-15T00:06:28.4241682+08:00||;True|2026-01-13T22:34:15.2372411+08:00||;True|2026-01-13T22:26:46.4522947+08:00||;True|2026-01-13T22:15:56.9735179+08:00||;True|2026-01-13T22:15:51.8250677+08:00||;False|2026-01-13T22:15:46.6608690+08:00||;True|2026-01-13T22:03:06.4683237+08:00||;False|2026-01-13T22:03:01.2036027+08:00||;True|2026-01-13T21:36:05.8776209+08:00||;True|2026-01-13T21:33:02.0766289+08:00||;False|2026-01-13T21:32:57.1976141+08:00||;True|2026-01-13T19:14:35.2519439+08:00||;True|2026-01-13T15:07:50.0836745+08:00||;False|2026-01-13T15:06:35.5929685+08:00||;True|2026-01-13T10:21:41.6012776+08:00||;True|2026-01-13T09:57:25.4788847+08:00||;True|2026-01-13T09:53:14.4900360+08:00||;True|2026-01-13T09:23:53.6465295+08:00||;True|2026-01-12T22:04:14.5886955+08:00||;False|2026-01-12T22:04:08.2008101+08:00||;True|2026-01-12T21:53:46.9947176+08:00||;True|2026-01-12T21:11:15.8358024+08:00||;True|2026-01-12T21:09:51.8663228+08:00||;True|2026-01-11T21:25:07.5052845+08:00||;False|2026-01-11T21:24:27.5744557+08:00||;True|2026-01-11T19:59:15.4734611+08:00||;False|2026-01-11T19:59:04.9543339+08:00||;</History>
|
||||
<LastFailureDetails />
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -95,8 +95,8 @@ Cookie 及 `sec_user_id` 是同步功能的核心,需严格按步骤获取,
|
||||
|
||||
| 镜像标签 | 架构 |
|
||||
| ----------------- | -------------- |
|
||||
| `beta_2.0.5` | x86_64 (amd64) |
|
||||
| `arm_2.0.5` | ARM64 |
|
||||
| `beta_2.0.6` | x86_64 (amd64) |
|
||||
| `arm_2.0.6` | ARM64 |
|
||||
|
||||
|
||||
### 构建命令示例
|
||||
@@ -115,7 +115,7 @@ version: '3.8'
|
||||
|
||||
services:
|
||||
dysync:
|
||||
image: ccr.ccs.tencentyun.com/jianzhichu/dysync:beta_2.0.5
|
||||
image: ccr.ccs.tencentyun.com/jianzhichu/dysync:beta_2.0.6
|
||||
container_name: dysync2026 # 容器名称
|
||||
restart: unless-stopped # 始终重启容器,除非容器被手动停止或Docker服务停止
|
||||
ports:
|
||||
|
||||
+113
-122
@@ -55,12 +55,15 @@ type DataItem = {
|
||||
upSecUserIds?: string;
|
||||
upSavePath?: string;
|
||||
// imgSavePath?: string;
|
||||
useSinglePath?: boolean; // 新增:是否全部用一个地址
|
||||
// useSinglePath?: boolean; // 新增:是否全部用一个地址
|
||||
useCollectFolder?: boolean;
|
||||
downMix?: boolean;
|
||||
downSeries?: boolean;
|
||||
mixPath?: string;
|
||||
seriesPath?: string;
|
||||
downCollect?: boolean;
|
||||
downFavorite?: boolean;
|
||||
downFollowd?: boolean;
|
||||
};
|
||||
|
||||
const loading = ref(false);
|
||||
@@ -120,12 +123,15 @@ const newCookie = (cookie?: DataItem) => {
|
||||
cookie.upSecUserIdsJson = undefined;
|
||||
cookie.upSavePath = undefined;
|
||||
// cookie.imgSavePath = undefined;
|
||||
cookie.useSinglePath = false; // 新增:默认不使用单一路径
|
||||
// cookie.useSinglePath = false; // 新增:默认不使用单一路径
|
||||
cookie.useCollectFolder = false; //是否按收藏夹来下载。
|
||||
cookie.downMix = false; //是否下载收藏夹的合集
|
||||
cookie.downSeries = false; //是否下载短剧
|
||||
cookie.mixPath = undefined; //合集存储路径
|
||||
cookie.seriesPath = undefined; //短剧存储路径
|
||||
cookie.downCollect = false;
|
||||
cookie.downFavorite = false;
|
||||
cookie.downFollowd = false;
|
||||
return cookie;
|
||||
};
|
||||
|
||||
@@ -139,17 +145,17 @@ const copyObject = (target: any, source?: any) => {
|
||||
const form = reactive<DataItem>(newCookie());
|
||||
|
||||
// 新增:监听收藏路径变化,当启用单一路径时同步到其他路径
|
||||
watch(
|
||||
[() => form.savePath, () => form.useSinglePath],
|
||||
([newSavePath, useSinglePath]) => {
|
||||
if (useSinglePath && newSavePath) {
|
||||
form.favSavePath = newSavePath;
|
||||
form.upSavePath = newSavePath;
|
||||
// form.imgSavePath = newSavePath;
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
// watch(
|
||||
// [() => form.savePath, () => form.useSinglePath],
|
||||
// ([newSavePath, useSinglePath]) => {
|
||||
// // if (useSinglePath && newSavePath) {
|
||||
// // form.favSavePath = newSavePath;
|
||||
// // form.upSavePath = newSavePath;
|
||||
// // // form.imgSavePath = newSavePath;
|
||||
// // }
|
||||
// },
|
||||
// { immediate: true }
|
||||
// );
|
||||
|
||||
function reset() {
|
||||
return newCookie(form);
|
||||
@@ -181,11 +187,11 @@ function submit() {
|
||||
loading.value = false;
|
||||
if (res.code === 0) {
|
||||
showModal.value = false;
|
||||
message.success('修改成功,同步任务将在5-10秒按新配置运行...');
|
||||
message.success('保存成功,同步任务将在5-10秒后重新启动...');
|
||||
reset();
|
||||
GetRecords();
|
||||
}else{
|
||||
message.success('修改失败,'+res.message);
|
||||
} else {
|
||||
message.error('保存失败' + res.message);
|
||||
}
|
||||
});
|
||||
})
|
||||
@@ -231,9 +237,9 @@ function edit(record: DataItem) {
|
||||
console.log(record);
|
||||
copyObject(form, record);
|
||||
// 确保useSinglePath有默认值
|
||||
if (form.useSinglePath === undefined) {
|
||||
form.useSinglePath = false;
|
||||
}
|
||||
// if (form.useSinglePath === undefined) {
|
||||
// form.useSinglePath = false;
|
||||
// }
|
||||
showModal.value = true;
|
||||
}
|
||||
|
||||
@@ -311,7 +317,7 @@ const removeRow = (index: number) => {
|
||||
form.upSecUserIdsJson.splice(index, 1);
|
||||
}
|
||||
};
|
||||
const rowCount = 5;
|
||||
const rowCount = 10;
|
||||
|
||||
// 组件挂载时获取配置
|
||||
onMounted(() => {
|
||||
@@ -496,6 +502,10 @@ const saveDrawerData = () => {
|
||||
drawerPagination.loading = false;
|
||||
});
|
||||
};
|
||||
|
||||
const switchdownCollect = (e: any) => {
|
||||
if (!e) form.useCollectFolder = e;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -520,132 +530,113 @@ const saveDrawerData = () => {
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 收藏的存储路径 -->
|
||||
<a-form-item label="收藏的存储路径" name="savePath">
|
||||
<div style="display: flex; align-items: center; gap: 12px; width: 100%;">
|
||||
<a-input v-model:value="form.savePath" class="form-item-div" />
|
||||
<a-alert message="不想同步收藏的视频就空着" type="info" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
</div>
|
||||
</a-form-item>
|
||||
<!-- 新增:是否全部用一个地址开关 -->
|
||||
<a-form-item v-if="form.savePath&&form.savePath.length>0" label="统一存储路径" name="useSinglePath">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<!-- 修复:下载收藏视频 - 拆分Form.Item,用a-form-item-rest包裹非收集字段 -->
|
||||
<a-form-item label="下载收藏视频" name="downCollect">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div class="form-item-div">
|
||||
<a-switch v-model:checked="form.useSinglePath" :checked-value="true" :un-checked-value="false" size="default" />
|
||||
<span style="margin-left:10px;">{{form.useSinglePath ?'':''}}</span>
|
||||
<a-switch v-model:checked="form.downCollect" @change="switchdownCollect" :checked-value="true" :un-checked-value="false" size="default" />
|
||||
<!-- 非收集字段用a-form-item-rest包裹 -->
|
||||
<a-form-item-rest v-if="form.downCollect">
|
||||
<a-form-item name="savePath" noStyle>
|
||||
<a-input v-model:value="form.savePath" placeholder='请输入容器路径' class="form-item-div-input" />
|
||||
</a-form-item>
|
||||
</a-form-item-rest>
|
||||
</div>
|
||||
|
||||
<a-alert message="开启后,喜欢、关注、收藏都存储在一个目录,如果是容器部署:docker-compose配置,只需要映射一个路径 (合集短剧存储路径需要另外设置映射)" :type="form.useSinglePath?'error':'info'" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
<a-alert message="开启后自动下载默认收藏夹视频,记得填写映射路径(容器内部路径)" type="info" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="form.savePath&&form.savePath.length>0" label="下载自定义收藏夹" name="useCollectFolder">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
|
||||
<!-- 修复:自定义收藏夹 - 拆分Form.Item -->
|
||||
<a-form-item v-if="form.savePath && form.savePath.length>0" label="自定义收藏夹" name="useCollectFolder">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div class="form-item-div">
|
||||
<a-switch v-model:checked="form.useCollectFolder" :checked-value="true" :un-checked-value="false" size="default" />
|
||||
<span style="margin-left:10px;">{{ form.useCollectFolder ? '' : '' }}</span>
|
||||
<span>存储路径=“收藏的存储路径”</span>
|
||||
<a-button @click="openCollectFolderSetModal" shape="circle" type="dashed" style="margin-left:10px;" v-if="form.useCollectFolder">
|
||||
<tag-outlined />
|
||||
</a-button>
|
||||
<a-form-item-rest v-if="form.useCollectFolder">
|
||||
<a-input v-model:value="form.savePath" :disabled="form.useCollectFolder&&form.downCollect" placeholder="" class="form-item-div-input" />
|
||||
<a-button @click="openCollectFolderSetModal" shape="circle" type="dashed" style="margin-left:5px;" v-if="form.useCollectFolder">
|
||||
<star-outlined />
|
||||
</a-button>
|
||||
</a-form-item-rest>
|
||||
</div>
|
||||
|
||||
<a-alert message="开启后按照自定义收藏进行下载(需要开启收藏文件夹同步开关)且不再下载默认收藏夹视频" :type="form.useCollectFolder?'error':'info'" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
</div>
|
||||
</a-form-item>
|
||||
<!-- 喜欢的存储路径 -->
|
||||
<a-form-item label="喜欢的存储路径" name="favSavePath">
|
||||
<div style="display: flex; align-items: center; gap: 12px; width: 100%;">
|
||||
<a-input v-model:value="form.favSavePath" :disabled="form.useSinglePath" placeholder="" class="form-item-div" />
|
||||
<a-alert message="不想同步喜欢的视频就空着" type="info" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
<a-alert message="开启后自动下载自定义分类后的收藏夹,开启后不在下载默认收藏夹视频,存储路径与默认收藏夹存储路径一致" :type="form.useCollectFolder?'error':'info'" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 关注的存储路径 -->
|
||||
<a-form-item label="关注的存储路径" name="upSavePath">
|
||||
<div style="display: flex; align-items: center; gap: 12px; width: 100%;">
|
||||
<a-input v-model:value="form.upSavePath" :disabled="form.useSinglePath" placeholder="" class="form-item-div" />
|
||||
<a-alert message="不想同步关注列表博主的视频就空着" type="info" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
<!-- 修复:下载喜欢视频 - 拆分Form.Item -->
|
||||
<a-form-item label="下载喜欢视频" name="downFavorite">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div class="form-item-div">
|
||||
<a-switch v-model:checked="form.downFavorite" :checked-value="true" :un-checked-value="false" size="default" />
|
||||
<a-form-item-rest v-if="form.downFavorite">
|
||||
<a-form-item name="favSavePath" noStyle>
|
||||
<a-input v-model:value="form.favSavePath" placeholder='请输入容器路径' class="form-item-div-input" />
|
||||
</a-form-item>
|
||||
<a-button shape="circle" @click="()=>{message.success('别点了,这只是为了好看的😄')}" type="dashed" style="margin-left:5px;">
|
||||
<like-outlined />
|
||||
</a-button>
|
||||
</a-form-item-rest>
|
||||
</div>
|
||||
<a-alert message="开启后自动下载喜欢(点赞)的视频,记得填写映射路径(容器内部路径)" type="info" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 下载合集 - 新增name="mixPath" -->
|
||||
<a-form-item label="下载合集" name="downMix">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<!-- 修复:下载关注视频 - 拆分Form.Item -->
|
||||
<a-form-item label="下载关注视频" name="downFollowd">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div class="form-item-div">
|
||||
<a-switch v-model:checked="form.downFollowd" :checked-value="true" :un-checked-value="false" size="default" />
|
||||
<a-form-item-rest v-if="form.downFollowd">
|
||||
<a-form-item name="upSavePath" noStyle>
|
||||
<a-input v-model:value="form.upSavePath" placeholder='请输入容器路径' class="form-item-div-input" />
|
||||
</a-form-item>
|
||||
<a-button shape="circle" @click="()=>{message.success('别点了,这只是为了好看的😄')}" type="dashed" style="margin-left:5px;">
|
||||
<heart-outlined />
|
||||
</a-button>
|
||||
</a-form-item-rest>
|
||||
</div>
|
||||
<a-alert message="开启后自动下载关注的博主视频,记得填写映射路径(容器内部路径)" type="info" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 修复:下载合集视频 - 拆分Form.Item -->
|
||||
<a-form-item label="下载合集视频" name="downMix">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div class="form-item-div">
|
||||
<a-switch v-model:checked="form.downMix" :checked-value="true" :un-checked-value="false" size="default" />
|
||||
<span style="margin-left:10px;">{{ form.downMix ? '' : '' }}</span>
|
||||
<!-- 给输入框对应的form-item添加name属性 -->
|
||||
<a-form-item name="mixPath" noStyle v-if="form.downMix">
|
||||
<a-input v-model:value="form.mixPath" class="form-item-div-input" />
|
||||
</a-form-item>
|
||||
|
||||
<a-button @click="openMixDownSetModal" shape="circle" type="dashed" style="margin-left:10px;" v-if="form.downMix"> <tag-outlined />
|
||||
</a-button>
|
||||
<a-form-item-rest v-if="form.downMix">
|
||||
<a-form-item name="mixPath" noStyle>
|
||||
<a-input v-model:value="form.mixPath" class="form-item-div-input" placeholder='默认使用收藏夹路径' />
|
||||
</a-form-item>
|
||||
<a-button @click="openMixDownSetModal" shape="circle" type="dashed" style="margin-left:5px;">
|
||||
<gift-outlined />
|
||||
</a-button>
|
||||
</a-form-item-rest>
|
||||
</div>
|
||||
|
||||
<a-alert message="开启后会同步下载收藏的合集(需要开启合集同步开关,不设置路径默认存储到收藏,设置后记得docker里面加映射)" :type="form.downMix?'error':'info'" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
<a-alert message="开启后自动下载收藏的合集视频(还需要开启合集同步开关,不填目录径默认存储到收藏目录,设置后记得docker里面加映射,注意:付费视频下载后无法播放)" :type="form.downMix?'error':'info'" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 下载短剧 - 新增name="seriesPath" -->
|
||||
<a-form-item label="下载短剧" name="downSeries">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<!-- 修复:下载短剧视频 - 拆分Form.Item -->
|
||||
<a-form-item label="下载短剧视频" name="downSeries">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div class="form-item-div">
|
||||
<a-switch v-model:checked="form.downSeries" :checked-value="true" :un-checked-value="false" size="default" />
|
||||
<span style="margin-left:10px;">{{ form.downSeries ? '' : '' }}</span>
|
||||
<!-- 给输入框对应的form-item添加name属性 -->
|
||||
<a-form-item name="seriesPath" noStyle v-if="form.downSeries">
|
||||
<a-input v-model:value="form.seriesPath" class="form-item-div-input" />
|
||||
</a-form-item>
|
||||
|
||||
<a-button @click="openSeriesDownSetModal" shape="circle" type="dashed" style="margin-left:10px;" v-if="form.downSeries"> <tag-outlined />
|
||||
</a-button>
|
||||
<a-form-item-rest v-if="form.downSeries">
|
||||
<a-form-item name="seriesPath" noStyle>
|
||||
<a-input v-model:value="form.seriesPath" placeholder='默认使用收藏夹路径' class="form-item-div-input" />
|
||||
</a-form-item>
|
||||
<a-button @click="openSeriesDownSetModal" shape="circle" type="dashed" style="margin-left:5px;">
|
||||
<fire-outlined />
|
||||
</a-button>
|
||||
</a-form-item-rest>
|
||||
</div>
|
||||
|
||||
<a-alert message="开启后会同步下载收藏的短剧(需要开启短剧同步开关,不设置路径默认存储到收藏,设置后记得docker里面加映射)" :type="form.downSeries?'error':'info'" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
</div>
|
||||
</a-form-item>
|
||||
<!--
|
||||
<a-form-item v-if="form.savePath&&form.savePath.length>0" label="下载合集" name="downMix">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div class="form-item-div">
|
||||
<a-switch v-model:checked="form.downMix" :checked-value="true" :un-checked-value="false" size="default" />
|
||||
<span style="margin-left:10px;">{{ form.downMix ? '是' : '否' }}</span>
|
||||
<a-input v-model:value="form.mixPath" class="form-item-div-input" />
|
||||
|
||||
<a-button @click="openMixDownSetModal" shape="circle" type="dashed" style="margin-left:10px;" v-if="form.downMix"> <tag-outlined />
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
<a-alert message="开启后会同步下载收藏的合集(需要开启合集同步开关,不设置路径默认存储到收藏,设置后记得docker里面加映射)," :type="form.downMix?'error':'info'" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
<a-alert message="开启后自动下载收藏的短剧视频(还需要开启短剧同步开关,不填目录径默认存储到收藏目录,设置后记得docker里面加映射,注意:付费视频下载后无法播放)
|
||||
" :type="form.downSeries?'error':'info'" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item v-if="form.savePath&&form.savePath.length>0" label="下载短剧" name="downSeries">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div class="form-item-div">
|
||||
<a-switch v-model:checked="form.downSeries" :checked-value="true" :un-checked-value="false" size="default" />
|
||||
<span style="margin-left:10px;">{{ form.downSeries ? '是' : '否' }}</span>
|
||||
<a-input v-model:value="form.seriesPath" class="form-item-div-input" />
|
||||
|
||||
<a-button @click="openSeriesDownSetModal" shape="circle" type="dashed" style="margin-left:10px;" v-if="form.downSeries"> <tag-outlined />
|
||||
</a-button>
|
||||
</div>
|
||||
|
||||
<a-alert message="开启后会同步下载收藏的短剧(需要开启短剧同步开关,不设置路径默认存储到收藏,设置后记得docker里面加映射)" :type="form.downSeries?'error':'info'" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
</div>
|
||||
</a-form-item> -->
|
||||
|
||||
<!-- 图文的存储路径 -->
|
||||
<!-- <a-form-item label="图文的存储路径" name="imgSavePath">
|
||||
<div style="display: flex; align-items: center; gap: 12px; width: 100%;">
|
||||
<a-input v-model:value="form.imgSavePath" :disabled="form.useSinglePath" style="width: 200px;" />
|
||||
<a-alert message="如果系统配置页面开启了同步图文视频,且开启了单独存储,则必填!!!" type="info" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
</div>
|
||||
</a-form-item> -->
|
||||
|
||||
<!-- 同步状态开关 -->
|
||||
<a-form-item label="同步状态" name="status">
|
||||
<!-- 任务同步状态 - 保持原有结构(仅一个Switch,无警告) -->
|
||||
<a-form-item label="任务同步状态" name="status">
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<a-switch v-model:checked="form.status" :checked-value="1" :un-checked-value="0" size="default" />
|
||||
<span>{{ form.status === 1 ? '' : '' }}</span>
|
||||
@@ -825,7 +816,7 @@ const saveDrawerData = () => {
|
||||
width: 300px;
|
||||
}
|
||||
.form-item-div-input {
|
||||
width: 150px;
|
||||
width: 180px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
/* Firefox 透明滚动条适配 */
|
||||
|
||||
+1
-1
@@ -130,7 +130,7 @@
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<!-- 核心配置:仅用核心版本号2.0.5,自动拼接前缀 -->
|
||||
<!-- 核心配置:仅用核心版本号2.0.6,自动拼接前缀 -->
|
||||
<!--<Target Name="DockerBuildAndPushAfterPublish" AfterTargets="Publish">
|
||||
<Exec Command="docker build -t jianzhichu/dysync.net:beta_$(DockerCoreVersion) . && docker tag jianzhichu/dysync.net:beta_$(DockerCoreVersion) ccr.ccs.tencentyun.com/jianzhichu/dysync:beta_$(DockerCoreVersion) && docker push ccr.ccs.tencentyun.com/jianzhichu/dysync:beta_$(DockerCoreVersion)"
|
||||
Condition="'$(DockerArch)' == 'x86'" />
|
||||
|
||||
@@ -34,18 +34,7 @@ namespace dy.net.job
|
||||
return await douyinHttpClientService.SyncCollectVideos(cursor, count, cookie.Cookies);
|
||||
}
|
||||
|
||||
//protected override bool ShouldContinueSync(DouyinCookie cookie, DouyinVideoInfoResponse data, DouyinFollowed followed , AppConfig config)
|
||||
//{
|
||||
// return data != null && data.HasMore == 1 && cookie.CollHasSyncd == 0;
|
||||
//}
|
||||
|
||||
//protected override async Task HandleSyncCompletion(DouyinCookie cookie, int syncCount,DouyinFollowed followed,DouyinCollectCate cate)
|
||||
//{
|
||||
// cookie.CollHasSyncd = 1;
|
||||
// await douyinCookieService.UpdateAsync(cookie);
|
||||
// Log.Debug($"[{VideoType}]-[{cookie.UserName}],本次成功同步{syncCount}条视频");
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
||||
protected override string CreateSaveFolder(DouyinCookie cookie, Aweme item, AppConfig config, DouyinFollowed followed, DouyinCollectCate cate)
|
||||
|
||||
+86
-72
@@ -7,6 +7,7 @@ using dy.net.utils;
|
||||
using Newtonsoft.Json;
|
||||
using Quartz;
|
||||
using Serilog;
|
||||
using System.Net;
|
||||
|
||||
namespace dy.net.job
|
||||
{
|
||||
@@ -125,9 +126,7 @@ namespace dy.net.job
|
||||
/// <returns>一个表示异步操作的任务</returns>
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
//if (VideoType.GetVideoTypeDesc() != VideoType.GetVideoTypeDesc()Enum.dy_follows)
|
||||
// return;
|
||||
|
||||
|
||||
// 获取应用配置
|
||||
var config = douyinCommonService.GetConfig();
|
||||
// 在处理Cookie之前执行的预处理
|
||||
@@ -180,16 +179,6 @@ namespace dy.net.job
|
||||
/// <returns>视频信息对象,包含视频列表和分页信息</returns>
|
||||
protected abstract Task<DouyinVideoInfoResponse> FetchVideoData(DouyinCookie cookie, string cursor, DouyinFollowed followed, DouyinCollectCate cate);
|
||||
|
||||
///// <summary>
|
||||
///// 判断是否应该继续同步下一页数据
|
||||
///// </summary>
|
||||
///// <param name="cookie">用户Cookie</param>
|
||||
///// <param name="data">当前获取到的视频数据</param>
|
||||
///// <param name="followed">关注博主</param>
|
||||
///// <returns>如果应该继续同步,则为true;否则为false</returns>
|
||||
//protected bool ShouldContinueSync(DouyinCookie cookie, DouyinVideoInfoResponse data, DouyinFollowed followed, AppConfig config) {
|
||||
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 获取下一页数据的游标
|
||||
@@ -304,13 +293,12 @@ namespace dy.net.job
|
||||
{
|
||||
try
|
||||
{
|
||||
if (VideoType != VideoTypeEnum.dy_custom_collect || cookie.UseCollectFolder)
|
||||
Log.Debug($"[{VideoType.GetDesc()}][{cookie.UserName}]开始同步...");
|
||||
|
||||
switch (VideoType)
|
||||
{
|
||||
case VideoTypeEnum.dy_follows:
|
||||
if(cookie.DownFollowd)
|
||||
{
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}]开始同步...");
|
||||
//查询关注列表开启了同步的关注
|
||||
var follows = await douyinFollowService.GetSyncFollows(cookie.MyUserId);
|
||||
if (follows != null && follows.Any())
|
||||
@@ -325,15 +313,32 @@ namespace dy.net.job
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}]同步未开启");
|
||||
}
|
||||
break;
|
||||
case VideoTypeEnum.dy_favorite:
|
||||
case VideoTypeEnum.dy_collects:
|
||||
if (VideoType == VideoTypeEnum.dy_collects && cookie.UseCollectFolder)
|
||||
if(cookie.DownFavorite)
|
||||
{
|
||||
Log.Debug($"[{VideoType.GetDesc()}]-已开启自定义收藏夹同步...break;");
|
||||
break;
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}]开始同步...");
|
||||
int syncCount = 0;
|
||||
string cursor = "0";
|
||||
bool hasMore = true;
|
||||
(syncCount, cursor, hasMore) = await GetAndSaveViedos(cookie, config, syncCount, cursor, hasMore);
|
||||
await HandleSyncCompletion(cookie, syncCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}]同步未开启");
|
||||
}
|
||||
break;
|
||||
case VideoTypeEnum.dy_collects:
|
||||
if (cookie.UseCollectFolder)
|
||||
{
|
||||
Log.Debug($"[{VideoType.GetDesc()}]-已开启自定义收藏夹同步...break;");
|
||||
}
|
||||
else if (cookie.DownCollect)
|
||||
{
|
||||
int syncCount = 0;
|
||||
string cursor = "0";
|
||||
@@ -341,19 +346,37 @@ namespace dy.net.job
|
||||
(syncCount, cursor, hasMore) = await GetAndSaveViedos(cookie, config, syncCount, cursor, hasMore);
|
||||
await HandleSyncCompletion(cookie, syncCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}]同步未开启");
|
||||
}
|
||||
break;
|
||||
|
||||
case VideoTypeEnum.dy_mix:
|
||||
if (cookie.DownMix)
|
||||
{
|
||||
await SyncCustomListVideos(cookie, config);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}]同步未开启");
|
||||
}
|
||||
break;
|
||||
case VideoTypeEnum.dy_series:
|
||||
if (cookie.DownSeries)
|
||||
await SyncCustomListVideos(cookie, config);
|
||||
else
|
||||
{
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}]同步未开启");
|
||||
}
|
||||
break;
|
||||
case VideoTypeEnum.dy_custom_collect:
|
||||
if (cookie.UseCollectFolder)
|
||||
await SyncCustomListVideos(cookie, config);
|
||||
else
|
||||
{
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}]同步未开启");
|
||||
}
|
||||
break;
|
||||
case VideoTypeEnum.ImageVideo:
|
||||
default:
|
||||
@@ -364,7 +387,7 @@ namespace dy.net.job
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"[{VideoType.GetDesc()}][{cookie.UserName}]同步出错!!!,{ex.StackTrace}");
|
||||
Log.Error(ex, $"[{cookie.UserName}][{VideoType.GetDesc()}]同步出错!!!,{ex.StackTrace}");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
@@ -390,7 +413,7 @@ namespace dy.net.job
|
||||
}
|
||||
else
|
||||
{
|
||||
Serilog.Log.Debug($"[{VideoType.GetDesc()}]没有查询到已开启的对象");
|
||||
Serilog.Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}]没有查询到已开启的对象");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,9 +426,16 @@ namespace dy.net.job
|
||||
var data = await FetchVideoData(cookie, cursor, followed, cate);
|
||||
if (data == null || data.AwemeList == null || !data.AwemeList.Any())
|
||||
{
|
||||
Serilog.Log.Debug($"[{VideoType.GetDesc()}][{cookie.UserName}] 没有新的视频");
|
||||
Serilog.Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}] 没有新的视频");
|
||||
break;
|
||||
}
|
||||
|
||||
if (data.StatusCode == 0 && cookie.StatusMsg != "正常")
|
||||
{
|
||||
cookie.StatusCode = data.StatusCode;
|
||||
cookie.StatusMsg = "正常";
|
||||
await douyinCookieService.UpdateAsync(cookie);
|
||||
}
|
||||
// 判断是否还有更多数据
|
||||
//hasMore = ShouldContinueSync(cookie, data, followed, config);
|
||||
|
||||
@@ -419,7 +449,7 @@ namespace dy.net.job
|
||||
if (videos != null && videos.Any())
|
||||
{
|
||||
// 保存视频信息到数据库
|
||||
await SaveVideos(videos);
|
||||
await SaveVideos(cookie,videos);
|
||||
}
|
||||
|
||||
syncCount += syncCountx;
|
||||
@@ -451,7 +481,7 @@ namespace dy.net.job
|
||||
{
|
||||
if (syncCount >= 15)
|
||||
{
|
||||
Log.Debug($"[{VideoType.GetDesc()}][{cookie.UserName}]:本次同步数量{syncCount},等下次任务继续同步");
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}]:本次同步数量{syncCount},等下次任务继续同步");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -460,7 +490,7 @@ namespace dy.net.job
|
||||
{
|
||||
if (syncCount >= config.BatchCount)
|
||||
{
|
||||
Log.Debug($"[{VideoType.GetDesc()}][{cookie.UserName}]:本次同步数量{syncCount},已达配置上限{config.BatchCount},等下次任务继续同步");
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}]:本次同步数量{syncCount},已达配置上限{config.BatchCount},等下次任务继续同步");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -480,7 +510,7 @@ namespace dy.net.job
|
||||
//// 状态满足则记录日志并返回「终止循环」
|
||||
//if (isSyncCompleted.Invoke(cookie))
|
||||
//{
|
||||
// Log.Debug($"[{VideoType.GetDesc()}][{cookie.UserName}]本次同步达到上限{config.BatchCount},停止同步!!!");
|
||||
// Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}]本次同步达到上限{config.BatchCount},停止同步!!!");
|
||||
// return true;
|
||||
//}
|
||||
|
||||
@@ -522,7 +552,7 @@ namespace dy.net.job
|
||||
{
|
||||
|
||||
|
||||
bool Goon = await AutoDistinct(config, exitVideo);
|
||||
bool Goon = await AutoDistinct(config, exitVideo, cookie);
|
||||
if (!Goon)
|
||||
{
|
||||
continue;
|
||||
@@ -598,7 +628,7 @@ namespace dy.net.job
|
||||
if (!string.IsNullOrEmpty(dynamicVideo.DynamicVideos))
|
||||
{
|
||||
var dynamicVideos = JsonConvert.DeserializeObject<List<DouyinDynamicVideoDto>>(dynamicVideo.DynamicVideos);
|
||||
Log.Debug($"[{VideoType.GetDesc()}][{cookie.UserName}]-动态视频[{item.Desc}],下载成功 ,共{dynamicVideos?.Count}个视频...");
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}]-动态视频[{item.Desc}],下载成功 ,共{dynamicVideos?.Count}个视频...");
|
||||
if (dynamicVideos != null && dynamicVideos.Count > 0)
|
||||
{
|
||||
|
||||
@@ -640,7 +670,7 @@ namespace dy.net.job
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Debug($"[{VideoType.GetDesc()}][{cookie.UserName}]-动态视频[{item.Desc}],下载失败...");
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}]-动态视频[{item.Desc}],下载失败...");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -665,7 +695,7 @@ namespace dy.net.job
|
||||
return (videos, syncCount);
|
||||
}
|
||||
|
||||
private async Task<bool> AutoDistinct(AppConfig config, DouyinVideo exitVideo)
|
||||
private async Task<bool> AutoDistinct(AppConfig config, DouyinVideo exitVideo,DouyinCookie cookie)
|
||||
{
|
||||
// 去重,检查视频是否已存在(按优先级下载)
|
||||
if (config.AutoDistinct)
|
||||
@@ -724,7 +754,7 @@ namespace dy.net.job
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"[{VideoType.GetDesc()}]-删除重复的旧文件失败:{ex.Message}", ex);
|
||||
Log.Error($"[{cookie.UserName}][{VideoType.GetDesc()}]-删除重复的文件[{exitVideo.VideoTitle}]失败:{ex.Message}", ex);
|
||||
// 即使删除失败,仍继续下载(新文件会覆盖旧文件,或按路径规则重命名)
|
||||
}
|
||||
|
||||
@@ -809,7 +839,6 @@ namespace dy.net.job
|
||||
/// </summary>
|
||||
/// <param name="cookie">用户Cookie</param>
|
||||
/// <param name="item">视频信息</param>
|
||||
/// <param name="data">视频信息对象</param>
|
||||
/// <param name="config">应用配置</param>
|
||||
/// <param name="followed">关注</param>
|
||||
/// <param name="cate"></param>
|
||||
@@ -823,14 +852,14 @@ namespace dy.net.job
|
||||
|
||||
if (v == null)
|
||||
{
|
||||
Serilog.Log.Error($"[{VideoType}][{cookie.UserName}][{item.Desc}]未获取到下载地址");
|
||||
Serilog.Log.Error($"[{cookie.UserName}][{VideoType.GetDesc()}][{item.Desc}]未获取到下载地址");
|
||||
return null;
|
||||
}
|
||||
//Serilog.Log.Debug($"{v.QualityType}-{v.BitRateValue}-{v.IsH265}-{v.HdrBit}");
|
||||
var videoUrl = v.PlayAddr.UrlList.Where(x => !string.IsNullOrEmpty(x))?.LastOrDefault();
|
||||
if (string.IsNullOrWhiteSpace(videoUrl))
|
||||
{
|
||||
Serilog.Log.Error($"[{VideoType}][{cookie.UserName}][{item.Desc}]未获取到下载地址");
|
||||
Serilog.Log.Error($"[{cookie.UserName}][{VideoType.GetDesc()}]未获取到下载地址");
|
||||
return null;
|
||||
}
|
||||
// 创建保存文件夹
|
||||
@@ -848,7 +877,7 @@ namespace dy.net.job
|
||||
return null;
|
||||
}
|
||||
|
||||
Log.Debug($"[{VideoType.GetDesc()}][{item?.Author?.Nickname ?? ""}]-视频[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId)}]开始下载...");
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}][{item?.Author?.Nickname ?? ""}]-视频[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId)}]开始下载...");
|
||||
// 随机延迟
|
||||
await Task.Delay(_random.Next(1, 4) * 1000);
|
||||
|
||||
@@ -856,7 +885,7 @@ namespace dy.net.job
|
||||
var (Success, _) = await douyinHttpClientService.DownloadAsync(videoUrl, savePath, cookie.Cookies);
|
||||
if (!Success)
|
||||
{
|
||||
Log.Error($"[{VideoType.GetDesc()}][{item?.Author?.Nickname ?? ""}]-视频[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId)}]下载失败!!!");
|
||||
Log.Error($"[{cookie.UserName}][{VideoType.GetDesc()}][{item?.Author?.Nickname ?? ""}]-视频[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId)}]下载失败!!!");
|
||||
|
||||
(bool flowControl, DouyinVideo value) = await SwitchOtherUrlAddressDown(cookie, item, videoUrl, savePath);
|
||||
if (!flowControl)
|
||||
@@ -866,7 +895,7 @@ namespace dy.net.job
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Debug($"[{VideoType.GetDesc()}][{item?.Author?.Nickname ?? ""}]-视频[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId)}]下载完成.");
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}][{item?.Author?.Nickname ?? ""}]-视频[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId)}]下载完成.");
|
||||
}
|
||||
// 下载视频封面
|
||||
await GetDownVideoCover(item, saveFolder, cookie, config, cate);
|
||||
@@ -921,7 +950,7 @@ namespace dy.net.job
|
||||
// 拼接视频保存路径
|
||||
var savePath = Path.Combine(saveFolder, fileName);
|
||||
|
||||
Log.Debug($"[{VideoType.GetDesc()}]-动态视频[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId)}]开始下载...");
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}]-动态视频[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId)}]开始下载...");
|
||||
// 随机延迟
|
||||
int i = 1;
|
||||
|
||||
@@ -943,12 +972,12 @@ namespace dy.net.job
|
||||
var (Success, ActualSavePath) = await douyinHttpClientService.DownloadAsync(dynamicUrl.Path, dynamicSavePath, cookie.Cookies);
|
||||
if (!Success)
|
||||
{
|
||||
Log.Error($"[{VideoType.GetDesc()}][{item?.Author?.Nickname ?? ""}]-动态视频[{dynamicSavePath}]-00{i},下载失败!!!");
|
||||
Log.Error($"[{cookie.UserName}][{VideoType.GetDesc()}][{item?.Author?.Nickname ?? ""}]-动态视频[{dynamicSavePath}]-00{i},下载失败!!!");
|
||||
}
|
||||
else
|
||||
{
|
||||
dynamicSavePaths.Add(v);
|
||||
Log.Debug($"[{VideoType.GetDesc()}][{item?.Author?.Nickname ?? ""}]-动态视频[{dynamicSavePath}]-00{i},下载完成.");
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}][{item?.Author?.Nickname ?? ""}]-动态视频[{dynamicSavePath}]-00{i},下载完成.");
|
||||
}
|
||||
await Task.Delay(_random.Next(1, 4) * 1000);
|
||||
}
|
||||
@@ -1013,17 +1042,17 @@ namespace dy.net.job
|
||||
var (Success, ActualSavePath) = await douyinHttpClientService.DownloadAsync(videoUrl, savePath, cookie.Cookies, otherUrls);
|
||||
if (Success)
|
||||
{
|
||||
Log.Debug($"[{VideoType.GetDesc()}]-尝试多个地址后,下载成功,{savePath}");
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}]-尝试多个地址后,下载成功,{savePath}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"[{VideoType.GetDesc()}]-尝试多个地址后,依旧下载失败,{item.Desc}");
|
||||
Log.Error($"[{cookie.UserName}][{VideoType.GetDesc()}]-尝试多个地址后,依旧下载失败,{item.Desc}");
|
||||
return (flowControl: false, value: null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"[{VideoType.GetDesc()}]-没有找到额外下载链接可以下载了," + item.Desc);
|
||||
Log.Error($"[{cookie.UserName}][{VideoType.GetDesc()}]-没有找到额外可以尝试下载链接了," + item.Desc);
|
||||
return (flowControl: false, value: null);
|
||||
}
|
||||
|
||||
@@ -1098,7 +1127,7 @@ namespace dy.net.job
|
||||
var mergeResult = await douyinMergeVideoService.MergeToVideo(cookie.Cookies, AppContext.BaseDirectory, reqParams, savePath, fileNamefolder, config.DownImageVideo, config.DownImage, config.DownMp3);
|
||||
if (!mergeResult)
|
||||
{
|
||||
Log.Error($"[{VideoType.GetDesc()}]-图文视频-[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId)}]合成失败!!!");
|
||||
Log.Error($"[{cookie.UserName}][{VideoType.GetDesc()}]-图文视频-[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId)}]合成失败!!!");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1110,13 +1139,13 @@ namespace dy.net.job
|
||||
// 检查合成后的视频文件是否有效
|
||||
if (!File.Exists(savePath) || new FileInfo(savePath).Length <= 0)
|
||||
{
|
||||
Log.Error($"[{VideoType.GetDesc()}]-图文视频-[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId)}]合成失败!!!");
|
||||
Log.Error($"[{cookie.UserName}][{VideoType.GetDesc()}]-图文视频-[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId)}]合成失败!!!");
|
||||
// 清理无效的文件和文件夹
|
||||
if (Directory.Exists(fileNamefolder))
|
||||
{
|
||||
File.Delete(savePath);
|
||||
Directory.Delete(fileNamefolder, true);
|
||||
Log.Error($"[{VideoType.GetDesc()}]-图文视频-删除合成失败的视频文件和目录...");
|
||||
Log.Error($"[{cookie.UserName}][{VideoType.GetDesc()}]-图文视频-删除合成失败的视频文件和目录...");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -1160,7 +1189,7 @@ namespace dy.net.job
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"[{VideoType.GetDesc()}]-图片视频同步-处理图片集并合成视频时出错");
|
||||
Log.Error(ex, $"[{cookie.UserName}][{VideoType.GetDesc()}]-图片视频同步-处理图片集并合成视频时出错");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1169,9 +1198,10 @@ namespace dy.net.job
|
||||
/// 保存视频信息到数据库
|
||||
/// 批量插入视频实体列表到数据库中
|
||||
/// </summary>
|
||||
/// <param name="cookie"></param>
|
||||
/// <param name="videos">要保存的视频实体列表</param>
|
||||
/// <returns>保存成功的视频数量</returns>
|
||||
protected async Task<int> SaveVideos(List<DouyinVideo> videos)
|
||||
protected async Task<int> SaveVideos(DouyinCookie cookie, List<DouyinVideo> videos)
|
||||
{
|
||||
if (!videos.Any()) return 0;
|
||||
try
|
||||
@@ -1181,9 +1211,9 @@ namespace dy.net.job
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"[{VideoType.GetDesc()}]-批量保存视频到数据库失败");
|
||||
Log.Error(ex, $"[{cookie.UserName}][{VideoType.GetDesc()}]-批量保存视频到数据库失败");
|
||||
// 清理保存失败的视频文件
|
||||
await CleanupFailedVideos(videos);
|
||||
await CleanupFailedVideos(cookie,videos);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1284,11 +1314,12 @@ namespace dy.net.job
|
||||
/// 清理保存失败的视频文件
|
||||
/// 当数据库保存失败时,删除已下载的视频文件和文件夹
|
||||
/// </summary>
|
||||
/// <param name="cookie"></param>
|
||||
/// <param name="videos">保存失败的视频实体列表</param>
|
||||
/// <returns>一个表示异步操作的任务</returns>
|
||||
private async Task CleanupFailedVideos(List<DouyinVideo> videos)
|
||||
private async Task CleanupFailedVideos(DouyinCookie cookie, List<DouyinVideo> videos)
|
||||
{
|
||||
Log.Debug($"[{VideoType.GetDesc()}]-数据库保存失败,开始清理本次下载的视频目录...");
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}]-数据库保存失败,开始清理本次下载的视频目录...");
|
||||
|
||||
foreach (var video in videos)
|
||||
{
|
||||
@@ -1306,12 +1337,12 @@ namespace dy.net.job
|
||||
{
|
||||
Directory.Delete(directory);
|
||||
}
|
||||
Log.Debug($"[{VideoType.GetDesc()}]-清理失败视频文件成功: {video.VideoSavePath}!!!");
|
||||
Log.Debug($"[{cookie.UserName}][{VideoType.GetDesc()}]-清理失败视频文件成功: {video.VideoSavePath}!!!");
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Warning(ex, $"[{VideoType.GetDesc()}]-清理失败视频文件出错: {video.VideoSavePath}!!!");
|
||||
Log.Warning(ex, $"[{cookie.UserName}][{VideoType.GetDesc()}]-清理失败视频文件出错: {video.VideoSavePath}!!!");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1403,23 +1434,6 @@ namespace dy.net.job
|
||||
return video;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
//private string GetVideoSimplifyTitle(Aweme item)
|
||||
//{
|
||||
// var config = douyinCommonService.GetConfig();
|
||||
// string simplifiedTitle = string.Empty;
|
||||
|
||||
// if (config?.UperUseViedoTitle ?? false)
|
||||
// {
|
||||
// simplifiedTitle = DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId);
|
||||
// }
|
||||
// return simplifiedTitle;
|
||||
//}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace dy.net.job
|
||||
LOG_TAG_SERIES);
|
||||
}
|
||||
|
||||
Log.Debug($"[{ck.UserName}]所有[基础数据(list)]同步完成,包括 [收藏列表、关注列表、合集列表、短剧列表] ");
|
||||
Log.Debug($"[{ck.UserName}][基础数据]同步完成,包括 [收藏列表、关注列表、合集列表、短剧列表],这不是同步视频!!! ");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -189,7 +189,7 @@ namespace dy.net.job
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(cookie.SecUserId))
|
||||
{
|
||||
Log.Debug($"[{cookie.UserName}][{LOG_TAG_FOLLOW}]:未设置SecUserId,跳过");
|
||||
Log.Debug($"[{cookie.UserName}][{LOG_TAG_FOLLOW}]:未设置SecUserId,如果要同步关注列表(你关注的博主),需要在授权页面填写你的sce_user_id");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -197,29 +197,25 @@ namespace dy.net.job
|
||||
string offset = "0";
|
||||
bool hasMore = true;
|
||||
int total = 0;
|
||||
FollowErrorDto currentError = null;
|
||||
|
||||
try
|
||||
{
|
||||
while (hasMore)
|
||||
{
|
||||
var data = await _douyinService.SyncMyFollows(
|
||||
DEFAULT_FOLLOW_COUNT, offset, cookie.SecUserId, cookie.Cookies,
|
||||
async (err) =>
|
||||
{
|
||||
currentError = err;
|
||||
cookie.StatusMsg = err.StatusCode == INVALID_COOKIE_STATUS_CODE ? "无效" : "正常";
|
||||
cookie.StatusCode = err.StatusCode;
|
||||
await _dyCookieService.UpdateAsync(cookie);
|
||||
});
|
||||
DEFAULT_FOLLOW_COUNT, offset, cookie.SecUserId, cookie.Cookies);
|
||||
|
||||
if (currentError != null && currentError.StatusCode != 0)
|
||||
if (data == null)
|
||||
{
|
||||
Log.Error($"[{cookie.UserName}] - {LOG_TAG_FOLLOW}:错误 状态码:{currentError.StatusCode} 信息:{currentError.StatusMsg}");
|
||||
if (currentError.StatusCode == INVALID_COOKIE_STATUS_CODE) break;
|
||||
Log.Error($"[{cookie.UserName}] - {LOG_TAG_FOLLOW}同步异常,请检查cookie");
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
cookie.StatusCode = data.StatusCode;
|
||||
cookie.StatusMsg = data.StatusCode == 0 ? "正常" : "异常";
|
||||
await _dyCookieService.UpdateAsync(cookie);
|
||||
}
|
||||
|
||||
if (data == null) break;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(cookie.MyUserId))
|
||||
{
|
||||
@@ -243,7 +239,7 @@ namespace dy.net.job
|
||||
if (followList.Any())
|
||||
{
|
||||
var (add, update, succ) = await _followService.Sync(followList, cookie);
|
||||
Log.Debug($"[{cookie.UserName}][{LOG_TAG_FOLLOW}]:同步完成 新增:{add} 更新:{update} 成功:{succ} 总关注数:{total}");
|
||||
Log.Debug($"[{cookie.UserName}][{LOG_TAG_FOLLOW}]:同步完成 新增:{add} 更新:{update} 成功:{succ} 总关注数:{total},这是同步关注列表,这不是同步视频!!!");
|
||||
}
|
||||
await _douyinCommonService.SetConfigNotFirstRunning();
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class FollowErrorDto
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[JsonProperty("followings")]
|
||||
public object Followings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 8 - 用户未登录
|
||||
/// </summary>
|
||||
[JsonProperty("status_code")]
|
||||
public int StatusCode { get; set; }
|
||||
/// <summary>
|
||||
/// 用户未登录
|
||||
/// </summary>
|
||||
[JsonProperty("status_msg")]
|
||||
public string StatusMsg { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -50,4 +50,6 @@
|
||||
Description = description ?? throw new ArgumentNullException(nameof(description), "任务描述不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -38,6 +38,14 @@
|
||||
/// </summary>
|
||||
//[Description("收藏短剧")]
|
||||
dy_series = 7,
|
||||
/// <summary>
|
||||
/// 同步关注列表--
|
||||
/// </summary>
|
||||
dy_followuser=1000,
|
||||
/// <summary>
|
||||
/// 同步关注列表一次
|
||||
/// </summary>
|
||||
dy_followuser_once = 2000,
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,19 @@ namespace dy.net.model.entity
|
||||
/// </summary>
|
||||
public bool DownSeries { get; set; }
|
||||
/// <summary>
|
||||
/// 是否下载收藏夹视频
|
||||
/// </summary>
|
||||
public bool DownCollect { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否下载点赞(喜欢的)视频
|
||||
/// </summary>
|
||||
public bool DownFavorite { get; set; }
|
||||
/// <summary>
|
||||
/// 是否下载关注的博主的作品
|
||||
/// </summary>
|
||||
public bool DownFollowd { get; set; }
|
||||
/// <summary>
|
||||
/// 1 开启同步 0 关闭同步
|
||||
/// </summary>
|
||||
public int Status { get; set; }
|
||||
|
||||
@@ -72,6 +72,24 @@ namespace dy.net.service
|
||||
return _cookieRepository.Insert(cookie);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增字段,兼容旧版本
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> UpdateCookieToSupportOldVersionAsync()
|
||||
{
|
||||
var cookies = _cookieRepository.GetAll();
|
||||
|
||||
foreach (var item in cookies)
|
||||
{
|
||||
item.DownCollect = !string.IsNullOrWhiteSpace(item.SavePath) && !item.UseCollectFolder;
|
||||
item.DownFavorite = !string.IsNullOrWhiteSpace(item.FavSavePath);
|
||||
item.DownFollowd = !string.IsNullOrWhiteSpace(item.UpSavePath);
|
||||
}
|
||||
await _cookieRepository.UpdateRangeAsync(cookies);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 查询单个
|
||||
public async Task<DouyinCookie> GetByIdAsync(string id)
|
||||
{
|
||||
|
||||
@@ -125,6 +125,13 @@ namespace dy.net.service
|
||||
/// <returns></returns>
|
||||
public async Task<bool> OpenOrCloseSync(FollowUpdateDto dto)
|
||||
{
|
||||
|
||||
var followdOpendCount = await _followRepository.CountAsync(x => x.OpenSync);
|
||||
if (followdOpendCount > 20)
|
||||
{
|
||||
throw new Exception("为了减少被风控的可能,关注列表最多同时开启20个,抱歉");
|
||||
}
|
||||
|
||||
var followed = await _followRepository.GetByIdAsync(dto.Id);
|
||||
if (followed != null)
|
||||
{
|
||||
|
||||
@@ -642,9 +642,8 @@ namespace dy.net.service
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="secUserId"></param>
|
||||
/// <param name="cookie"></param>
|
||||
/// <param name="callBack"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<DouyinFollowInfoResponse> SyncMyFollows(string count, string offset, string secUserId, string cookie, Action<FollowErrorDto> callBack)
|
||||
public async Task<DouyinFollowInfoResponse> SyncMyFollows(string count, string offset, string secUserId, string cookie)
|
||||
{
|
||||
|
||||
#region 检查参数
|
||||
@@ -686,29 +685,6 @@ namespace dy.net.service
|
||||
{
|
||||
var data = await respose.Content.ReadAsStringAsync();
|
||||
var res = JsonConvert.DeserializeObject<DouyinFollowInfoResponse>(data);
|
||||
if (res != null)
|
||||
{
|
||||
if (res.Followings == null)
|
||||
{
|
||||
var err = JsonConvert.DeserializeObject<FollowErrorDto>(data);
|
||||
|
||||
if (err != null)
|
||||
{
|
||||
Serilog.Log.Error($"SyncMyFollows error: {err.StatusMsg}");
|
||||
callBack?.Invoke(err);
|
||||
}
|
||||
Serilog.Log.Error($"SyncMyFollows error: 关注列表为空 :{data}");
|
||||
}
|
||||
else
|
||||
{
|
||||
callBack?.Invoke(new FollowErrorDto { StatusCode = 0 });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serilog.Log.Error($"SyncMyFollows error: 反序列化结果为空,接口返回数据:{data}");
|
||||
callBack?.Invoke(new FollowErrorDto { StatusCode = 8, StatusMsg = "未知" });
|
||||
}
|
||||
return res;
|
||||
}
|
||||
else
|
||||
@@ -739,12 +715,12 @@ namespace dy.net.service
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(douyinCookie.SecUserId))
|
||||
{
|
||||
var res = await SyncMyFollows("1", "1", douyinCookie.SecUserId, douyinCookie.Cookies, null);
|
||||
var res = await SyncMyFollows("1", "10", douyinCookie.SecUserId, douyinCookie.Cookies);
|
||||
return res != null && res.StatusCode == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
var res = await SyncCollectVideos("0", "1", douyinCookie.Cookies);
|
||||
var res = await SyncCollectVideos("0", "10", douyinCookie.Cookies);
|
||||
return res != null && res.StatusCode == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using dy.net.job;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using dy.net.utils;
|
||||
using Quartz;
|
||||
using Serilog;
|
||||
@@ -12,16 +13,17 @@ namespace dy.net.service
|
||||
public class DouyinQuartzJobService
|
||||
{
|
||||
private readonly ISchedulerFactory _schedulerFactory;
|
||||
private readonly DouyinCookieService douyinCookieService;
|
||||
private const string DefaultJobGroup = "dysync.net";
|
||||
private const int DefaultIntervalMinutes = 30;
|
||||
private const int DefaultCronStartDelaySeconds = 30;
|
||||
private const int DefaultSimpleStartDelaySeconds = 3;
|
||||
|
||||
// 任务配置信息(修复了series任务的Key重复问题,确保每个任务Key唯一)
|
||||
public static Dictionary<string, JobConfig> JobConfigs { get; } = new()
|
||||
public static Dictionary<VideoTypeEnum, JobConfig> JobConfigs { get; } = new()
|
||||
{
|
||||
{
|
||||
VideoTypeEnum.dy_collects.GetDesc(),
|
||||
VideoTypeEnum.dy_collects,
|
||||
new JobConfig(
|
||||
typeof(DouyinCollectSyncJob),
|
||||
"dy.job.key.collect",
|
||||
@@ -29,7 +31,7 @@ namespace dy.net.service
|
||||
"抖音收藏同步任务")
|
||||
},
|
||||
{
|
||||
VideoTypeEnum.dy_favorite.GetDesc(),
|
||||
VideoTypeEnum.dy_favorite,
|
||||
new JobConfig(
|
||||
typeof(DouyinFavoritSyncJob),
|
||||
"dy.job.key.favorite",
|
||||
@@ -37,7 +39,7 @@ namespace dy.net.service
|
||||
"抖音点赞同步任务")
|
||||
},
|
||||
{
|
||||
VideoTypeEnum.dy_follows.GetDesc(),
|
||||
VideoTypeEnum.dy_follows,
|
||||
new JobConfig(
|
||||
typeof(DouyinFollowedSyncJob),
|
||||
"dy.job.key.followed",
|
||||
@@ -45,7 +47,7 @@ namespace dy.net.service
|
||||
"抖音关注博主作品同步任务")
|
||||
},
|
||||
{
|
||||
"关注列表",
|
||||
VideoTypeEnum.dy_followuser,
|
||||
new JobConfig(
|
||||
typeof(DouyinFollowsAndCollnectsSyncJob),
|
||||
"dy.job.key.follow_user",
|
||||
@@ -53,7 +55,7 @@ namespace dy.net.service
|
||||
"抖音关注列表同步任务")
|
||||
},
|
||||
{
|
||||
VideoTypeEnum.dy_custom_collect.GetDesc(),
|
||||
VideoTypeEnum.dy_custom_collect,
|
||||
new JobConfig(
|
||||
typeof(DouyinCollectCustomSyncJob),
|
||||
"dy.job.key.custom_collect",
|
||||
@@ -61,7 +63,7 @@ namespace dy.net.service
|
||||
"抖音自定义收藏夹列表同步任务")
|
||||
},
|
||||
{
|
||||
VideoTypeEnum.dy_mix.GetDesc(),
|
||||
VideoTypeEnum.dy_mix,
|
||||
new JobConfig(
|
||||
typeof(DouyinMixSyncJob),
|
||||
"dy.job.key.mix",
|
||||
@@ -69,7 +71,7 @@ namespace dy.net.service
|
||||
"抖音收藏夹合集同步任务")
|
||||
},
|
||||
{
|
||||
VideoTypeEnum.dy_series.GetDesc(),
|
||||
VideoTypeEnum.dy_series,
|
||||
new JobConfig(
|
||||
typeof(DouyinSeriesSyncJob),
|
||||
"dy.job.key.series",
|
||||
@@ -77,7 +79,7 @@ namespace dy.net.service
|
||||
"抖音收藏夹短剧同步任务")
|
||||
},
|
||||
{
|
||||
"sync_follow_user_once",
|
||||
VideoTypeEnum.dy_followuser_once,
|
||||
new JobConfig(
|
||||
typeof(DouyinFollowsAndCollnectsSyncJob),
|
||||
"dy.job.key.sync_follow_user_once",
|
||||
@@ -86,68 +88,160 @@ namespace dy.net.service
|
||||
}
|
||||
};
|
||||
|
||||
public DouyinQuartzJobService(ISchedulerFactory schedulerFactory)
|
||||
public DouyinQuartzJobService(ISchedulerFactory schedulerFactory,DouyinCookieService douyinCookieService)
|
||||
{
|
||||
_schedulerFactory = schedulerFactory ?? throw new ArgumentNullException(nameof(schedulerFactory));
|
||||
this.douyinCookieService = douyinCookieService;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 启动所有抖音相关定时任务(所有任务独立执行)
|
||||
/// 初始化或重启所有抖音定时任务
|
||||
/// </summary>
|
||||
/// <param name="expression">Cron表达式或间隔分钟数(所有任务使用相同的执行频率)</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
public async Task<bool> InitOrReStartAllJobs(string expression)
|
||||
/// <param name="cronExpression">定时任务表达式(分钟数)</param>
|
||||
/// <returns>是否成功初始化</returns>
|
||||
public async Task<bool> InitOrReStartAllJobs(string cronExpression)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(expression))
|
||||
{
|
||||
Log.Debug("定时任务表达式为空,使用默认配置({DefaultMinutes}分钟)", DefaultIntervalMinutes);
|
||||
expression = DefaultIntervalMinutes.ToString();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var scheduler = await _schedulerFactory.GetScheduler();
|
||||
// 1. 获取并验证Cookie
|
||||
var validCookies = await douyinCookieService.GetOpendCookiesAsync();
|
||||
if (validCookies == null || !validCookies.Any())
|
||||
{
|
||||
Serilog.Log.Debug("没有有效的抖音Cookie,无法启动定时任务");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 处理定时任务表达式
|
||||
var taskIntervalExpression = ResolveTaskExpression(cronExpression);
|
||||
|
||||
// 3. 获取调度器并清理现有任务
|
||||
var scheduler = await _schedulerFactory.GetScheduler();
|
||||
if (scheduler == null)
|
||||
{
|
||||
Log.Error("获取任务调度器失败,无法初始化定时任务");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 移除所有已存在的任务(避免重复调度)
|
||||
await RemoveAllExistingJobs(scheduler);
|
||||
|
||||
// 4. 检查各类型任务的启用条件
|
||||
var taskEnableConditions = GetTaskEnableConditions(validCookies);
|
||||
|
||||
// 执行任务启动逻辑
|
||||
// 5. 启动符合条件的定时任务
|
||||
int successfullyStartedJobs = 0;
|
||||
foreach (var jobKey in JobConfigs.Keys)
|
||||
{
|
||||
if (jobKey == "sync_follow_user_once")
|
||||
// 跳过一次性关注用户任务
|
||||
if (jobKey == VideoTypeEnum.dy_followuser_once)
|
||||
continue;
|
||||
if (jobKey == "follow_user") expression = "60";
|
||||
var startSuccess = await StartJobAsync(jobKey, expression);
|
||||
if (startSuccess)
|
||||
|
||||
// 处理关注用户任务(固定60分钟执行频率)
|
||||
if (jobKey == VideoTypeEnum.dy_followuser)
|
||||
{
|
||||
Log.Debug($"成功启动任务:{jobKey},执行频率:{expression}");
|
||||
bool startSuccess = await StartSingleJobAsync(jobKey, "60");
|
||||
if (startSuccess) successfullyStartedJobs++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
||||
// 根据不同任务类型和启用条件启动任务
|
||||
bool isTaskEnabled = jobKey switch
|
||||
{
|
||||
Log.Error($"启动任务失败:{jobKey}");
|
||||
VideoTypeEnum.dy_favorite => taskEnableConditions.IsFavoriteEnabled,
|
||||
VideoTypeEnum.dy_collects => taskEnableConditions.IsCollectEnabled,
|
||||
VideoTypeEnum.dy_follows => taskEnableConditions.IsFollowedEnabled,
|
||||
VideoTypeEnum.dy_custom_collect => taskEnableConditions.IsCustomCollectEnabled,
|
||||
VideoTypeEnum.dy_mix => taskEnableConditions.IsMixEnabled,
|
||||
VideoTypeEnum.dy_series => taskEnableConditions.IsSeriesEnabled,
|
||||
_ => false
|
||||
};
|
||||
|
||||
if (isTaskEnabled)
|
||||
{
|
||||
bool startSuccess = await StartSingleJobAsync(jobKey, taskIntervalExpression);
|
||||
if (startSuccess) successfullyStartedJobs++;
|
||||
}
|
||||
}
|
||||
Log.Information($"共启动 {JobConfigs.Count - 1} 个定时任务");
|
||||
|
||||
// 6. 输出任务启动统计日志
|
||||
Log.Information($"定时任务初始化完成,共尝试启动 {JobConfigs.Count - 1} 个任务,成功启动 {successfullyStartedJobs} 个");
|
||||
|
||||
//await StartJobAsync(VideoTypeEnum.dy_custom_collect.GetDesc(), expression);
|
||||
//await StartFollowJobOnceAsync();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "【任务服务】初始化所有定时任务异常");
|
||||
Log.Error(ex, "【quartz】初始化所有抖音定时任务时发生异常");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 解析任务执行表达式,为空时使用默认值
|
||||
/// </summary>
|
||||
/// <param name="inputExpression">输入的表达式</param>
|
||||
/// <returns>处理后的表达式</returns>
|
||||
private static string ResolveTaskExpression(string inputExpression)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(inputExpression))
|
||||
{
|
||||
Log.Debug("定时任务表达式为空,使用默认配置({DefaultMinutes}分钟)", DefaultIntervalMinutes);
|
||||
return DefaultIntervalMinutes.ToString();
|
||||
}
|
||||
return inputExpression;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取各类型任务的启用条件
|
||||
/// </summary>
|
||||
/// <param name="cookies">有效的抖音Cookie列表</param>
|
||||
/// <returns>任务启用条件集合</returns>
|
||||
private static TaskEnableConditions GetTaskEnableConditions(IEnumerable<DouyinCookie> cookies)
|
||||
{
|
||||
return new TaskEnableConditions
|
||||
{
|
||||
IsCollectEnabled = cookies.Any(x => x.DownCollect && !x.UseCollectFolder && !string.IsNullOrWhiteSpace(x.SavePath)),
|
||||
IsFavoriteEnabled = cookies.Any(x => x.DownFavorite && !string.IsNullOrWhiteSpace(x.FavSavePath)),
|
||||
IsFollowedEnabled = cookies.Any(x => x.DownFollowd && !string.IsNullOrWhiteSpace(x.UpSavePath)),
|
||||
IsMixEnabled = cookies.Any(x => x.DownMix && !string.IsNullOrWhiteSpace(x.MixPath) && !string.IsNullOrWhiteSpace(x.SavePath)),
|
||||
IsSeriesEnabled = cookies.Any(x => x.DownSeries && !string.IsNullOrWhiteSpace(x.SeriesPath) && !string.IsNullOrWhiteSpace(x.SavePath)),
|
||||
IsCustomCollectEnabled = cookies.Any(x => x.UseCollectFolder && !string.IsNullOrWhiteSpace(x.SavePath))
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动单个定时任务(封装重复的启动逻辑)
|
||||
/// </summary>
|
||||
/// <param name="jobKey">任务类型</param>
|
||||
/// <param name="expression">执行频率表达式</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
private async Task<bool> StartSingleJobAsync(VideoTypeEnum jobKey, string expression)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool startSuccess = await StartJobAsync(jobKey, expression);
|
||||
if (startSuccess)
|
||||
{
|
||||
Log.Debug($"【quartz】成功启动任务:{jobKey},执行频率:{expression}分钟");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"【quartz】启动任务失败:{jobKey}");
|
||||
}
|
||||
return startSuccess;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"【quartz】启动任务 {jobKey} 时发生异常");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 启动关注同步任务(单次执行)
|
||||
/// </summary>
|
||||
public async Task<bool> StartFollowJobOnceAsync()
|
||||
{
|
||||
return await StartOneTimeJobAsync("sync_follow_user_once");
|
||||
return await StartOneTimeJobAsync(VideoTypeEnum.dy_followuser_once);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -160,7 +254,7 @@ namespace dy.net.service
|
||||
{
|
||||
if (await scheduler.CheckExists(jobKey))
|
||||
{
|
||||
Log.Information("【任务服务】移除已存在的任务: {JobKey}", jobKey);
|
||||
Log.Debug("【quartz】移除已存在的任务: {JobKey}", jobKey);
|
||||
await scheduler.DeleteJob(jobKey);
|
||||
}
|
||||
}
|
||||
@@ -172,11 +266,11 @@ namespace dy.net.service
|
||||
/// <param name="configKey">任务配置Key(如:collect、favorite)</param>
|
||||
/// <param name="expression">定时表达式(Cron或间隔分钟数)</param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
public async Task<bool> StartJobAsync(string configKey, string expression)
|
||||
public async Task<bool> StartJobAsync(VideoTypeEnum configKey, string expression)
|
||||
{
|
||||
if (!JobConfigs.TryGetValue(configKey, out var jobConfig))
|
||||
{
|
||||
Log.Error("【任务服务】找不到任务配置: {ConfigKey}", configKey);
|
||||
Log.Error("【quartz】找不到任务配置: {ConfigKey}", configKey);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -201,7 +295,7 @@ namespace dy.net.service
|
||||
|
||||
// 调度任务
|
||||
await scheduler.ScheduleJob(jobDetail, trigger);
|
||||
Log.Information("【任务服务】启动任务成功 - 任务描述: {JobDescription}, 执行频率: {Expression}",
|
||||
Log.Information("【quartz】启动任务成功 - 任务描述: {JobDescription}, 执行频率: {Expression}",
|
||||
jobConfig.Description,
|
||||
expression);
|
||||
|
||||
@@ -209,7 +303,7 @@ namespace dy.net.service
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "【任务服务】启动任务失败 - 任务描述: {JobDescription}", jobConfig.Description);
|
||||
Log.Error(ex, "【quartz】启动任务失败 - 任务描述: {JobDescription}", jobConfig.Description);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -217,11 +311,11 @@ namespace dy.net.service
|
||||
/// <summary>
|
||||
/// 启动单次执行任务
|
||||
/// </summary>
|
||||
private async Task<bool> StartOneTimeJobAsync(string configKey)
|
||||
private async Task<bool> StartOneTimeJobAsync(VideoTypeEnum configKey)
|
||||
{
|
||||
if (!JobConfigs.TryGetValue(configKey, out var jobConfig))
|
||||
{
|
||||
Log.Error("【任务服务】找不到任务配置: {ConfigKey}", configKey);
|
||||
Log.Error("【quartz】找不到任务配置: {ConfigKey}", configKey);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -246,13 +340,13 @@ namespace dy.net.service
|
||||
.Build();
|
||||
|
||||
await scheduler.ScheduleJob(jobDetail, trigger);
|
||||
Log.Debug("【任务服务】启动单次任务成功 - 任务描述: {JobDescription}", jobConfig.Description);
|
||||
Log.Debug("【quartz】启动单次任务成功 - 任务描述: {JobDescription}", jobConfig.Description);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "【任务服务】启动单次任务失败 - 任务描述: {JobDescription}", jobConfig.Description);
|
||||
Log.Error(ex, "【quartz】启动单次任务失败 - 任务描述: {JobDescription}", jobConfig.Description);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -288,8 +382,8 @@ namespace dy.net.service
|
||||
}
|
||||
|
||||
// 无效表达式,使用默认配置
|
||||
Log.Warning("【任务服务】无效的任务表达式: {Expression},使用默认间隔{DefaultMinutes}分钟",
|
||||
expression, DefaultIntervalMinutes);
|
||||
//Log.Debug("【任务服务】无效的任务表达式: {Expression},使用默认间隔{DefaultMinutes}分钟",
|
||||
// expression, DefaultIntervalMinutes);
|
||||
|
||||
return TriggerBuilder.Create()
|
||||
.WithIdentity(triggerKey)
|
||||
@@ -308,9 +402,25 @@ namespace dy.net.service
|
||||
{
|
||||
if (await scheduler.CheckExists(jobKey))
|
||||
{
|
||||
Log.Information("【任务服务】移除已存在的任务: {JobKey}", jobKey);
|
||||
Log.Debug("【quartz】移除已存在的任务: {JobKey}", jobKey);
|
||||
await scheduler.DeleteJob(jobKey);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 任务启用条件模型
|
||||
/// </summary>
|
||||
private class TaskEnableConditions
|
||||
{
|
||||
public bool IsCollectEnabled { get; set; }
|
||||
public bool IsFavoriteEnabled { get; set; }
|
||||
public bool IsFollowedEnabled { get; set; }
|
||||
public bool IsMixEnabled { get; set; }
|
||||
public bool IsSeriesEnabled { get; set; }
|
||||
public bool IsCustomCollectEnabled { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user