代码整理

This commit is contained in:
jianzhichu
2026-01-23 22:24:00 +08:00
parent 60f6e3847d
commit 3f6b1874eb
60 changed files with 348 additions and 991 deletions
+1 -5
View File
@@ -1,8 +1,4 @@
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration.Json;
using Microsoft.Extensions.Configuration.Json;
using System;
using System.Collections.Generic;
using System.Linq;
namespace dy.net namespace dy.net
{ {
+3 -3
View File
@@ -1,13 +1,13 @@
using ClockSnowFlake; using ClockSnowFlake;
using dy.net.model.dto;
using dy.net.service;
using dy.net.utils;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims; using System.Security.Claims;
using System.Text; using System.Text;
using dy.net.service;
using dy.net.utils;
using dy.net.model.dto;
namespace dy.net.Controllers namespace dy.net.Controllers
{ {
-2
View File
@@ -1,9 +1,7 @@
using dy.net.model.dto; using dy.net.model.dto;
using dy.net.model.entity;
using dy.net.service; using dy.net.service;
using dy.net.utils; using dy.net.utils;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace dy.net.Controllers namespace dy.net.Controllers
+75 -72
View File
@@ -6,14 +6,8 @@ using dy.net.service;
using dy.net.utils; using dy.net.utils;
using dy.sync.lib; using dy.sync.lib;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json; using Newtonsoft.Json;
using Quartz.Util;
using System.Text;
using System.Text.Json;
using System.Xml.Linq;
using static Dm.net.buffer.ByteArrayBuffer;
namespace dy.net.Controllers namespace dy.net.Controllers
{ {
@@ -64,50 +58,53 @@ namespace dy.net.Controllers
} }
/// <summary>
/// 导入配置
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[HttpPost("importConf")] [HttpPost("importConf")]
public async Task<IActionResult> ImportConf(AppConfigImportDto dto) public async Task<IActionResult> ImportConf(AppConfigImportDto dto)
{ {
if (dto == null) if (dto == null)
return ApiResult.Fail("json数据为空"); return ApiResult.Fail("json数据为空");
var follows = dto.follows; await HandleFollowsImport(dto.follows);
if (follows != null && follows.Count > 0) await HandleConfigImport(dto.conf);
{ await HandleCookiesImport(dto.cookies);
var add = await douyinFollowService.AddHandFollows(follows);
if (add)
Serilog.Log.Debug("关注列表导入成功");
}
var conf = dto.conf;
if (conf != null)
{
if (conf.BatchCount > 30)
{
Serilog.Log.Debug("$对不起,为了项目能长久稳定运行,还是最大不要超过30吧。。。");
conf.BatchCount = 30;
}
var update = await commonService.UpdateConfig(conf);
if (update)
Serilog.Log.Debug("系统配置导入成功");
}
var cookies = dto.cookies;
if (cookies != null && cookies.Count > 0)
{
var importCookies = await douyinCookieService.ImportCookies(cookies);
if (importCookies)
{
Serilog.Log.Debug("抖音Cookie配置导入成功");
}
}
return ApiResult.Success(); return ApiResult.Success();
} }
private async Task HandleFollowsImport(List<DouyinFollowed> follows)
{
if (follows?.Count > 0)
{
var added = await douyinFollowService.AddHandFollows(follows);
if (added)
Serilog.Log.Debug("关注列表导入成功");
}
}
private async Task HandleConfigImport(AppConfig conf)
{
if (conf == null) return;
if (conf.BatchCount > 30)
{
Serilog.Log.Debug("对不起,为了项目能长久稳定运行,还是最大不要超过30吧。。。");
conf.BatchCount = 30;
}
var updated = await commonService.UpdateConfig(conf);
if (updated)
Serilog.Log.Debug("系统配置导入成功");
}
private async Task HandleCookiesImport(List<DouyinCookie> cookies)
{
if (cookies?.Count > 0)
{
var imported = await douyinCookieService.ImportCookies(cookies);
if (imported)
Serilog.Log.Debug("抖音Cookie配置导入成功");
}
}
/// <summary> /// <summary>
/// 分页查询 /// 分页查询
/// </summary> /// </summary>
@@ -181,45 +178,51 @@ namespace dy.net.Controllers
[AllowAnonymous] [AllowAnonymous]
public async Task<IActionResult> DeskInitAsync([FromBody] DouyinCookie dyUserCookies) public async Task<IActionResult> DeskInitAsync([FromBody] DouyinCookie dyUserCookies)
{ {
// 1. 基础赋值
dyUserCookies.Id = IdGener.GetLong().ToString(); dyUserCookies.Id = IdGener.GetLong().ToString();
if (string.IsNullOrWhiteSpace(dyUserCookies.SavePath)) // 2. 路径权限校验
{ var pathValidationResult = ValidatePaths(dyUserCookies);
return ApiResult.Fail("收藏存储路径不能为空"); if (!pathValidationResult.Success)
} return ApiResult.Fail(pathValidationResult.Message);
if (!DouyinFileUtils.HasDirectoryReadWritePermission(dyUserCookies.SavePath))
{
return ApiResult.Fail($"请在飞牛应用设置里面将{dyUserCookies.SavePath}添加读写权限");
}
if (!string.IsNullOrWhiteSpace(dyUserCookies.FavSavePath) && !DouyinFileUtils.HasDirectoryReadWritePermission(dyUserCookies.FavSavePath)) // 3. Cookie 有效性校验
{ var cookieValid = await httpClientService.CheckCookie(dyUserCookies);
return ApiResult.Fail($"请在飞牛应用设置里面将{dyUserCookies.FavSavePath}添加读写权限"); if (!cookieValid)
}
if (!string.IsNullOrWhiteSpace(dyUserCookies.UpSavePath) && !DouyinFileUtils.HasDirectoryReadWritePermission(dyUserCookies.UpSavePath))
{
return ApiResult.Fail($"请在飞牛应用设置里面将{dyUserCookies.UpSavePath}添加读写权限");
}
//if (!string.IsNullOrWhiteSpace(dyUserCookies.ImgSavePath) && !DouyinFileUtils.HasDirectoryReadWritePermission(dyUserCookies.ImgSavePath))
//{
// return ApiResult.Fail($"请在飞牛应用设置里面将{dyUserCookies.ImgSavePath}添加读写权限");
//}
var checkCk = await httpClientService.CheckCookie(dyUserCookies);
if (!checkCk)
{
return ApiResult.Fail("Cookie无效,请按照文档提示重新获取有效Cookie,不要使用插件获取cookie"); return ApiResult.Fail("Cookie无效,请按照文档提示重新获取有效Cookie,不要使用插件获取cookie");
// 4. 保存到数据库
var saved = await dyCookieService.Add(dyUserCookies);
return saved ? ApiResult.Success() : ApiResult.Fail("添加失败");
} }
var result = await dyCookieService.Add(dyUserCookies); private (bool Success, string Message) ValidatePaths(DouyinCookie cookie)
if (result)
{ {
return ApiResult.Success(); var pathsToCheck = new Dictionary<string, string>
{
{ "收藏存储路径", cookie.SavePath },
{ "喜欢视频存储路径", cookie.FavSavePath },
{ "上传视频存储路径", cookie.UpSavePath },
// { "图片存储路径", cookie.ImgSavePath } // 可随时启用
};
foreach (var (label, path) in pathsToCheck)
{
if (!string.IsNullOrWhiteSpace(path))
{
if (!DouyinFileUtils.HasDirectoryReadWritePermission(path))
{
return (false, $"请在飞牛应用设置里面将 {path} 添加读写权限({label}");
} }
return ApiResult.Fail("添加失败"); }
}
if (string.IsNullOrWhiteSpace(cookie.SavePath))
{
return (false, "收藏存储路径不能为空");
}
return (true, string.Empty);
} }
-1
View File
@@ -3,7 +3,6 @@ using dy.net.model.entity;
using dy.net.service; using dy.net.service;
using dy.net.utils; using dy.net.utils;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace dy.net.Controllers namespace dy.net.Controllers
-3
View File
@@ -1,9 +1,6 @@
using dy.net.model.dto; using dy.net.model.dto;
using dy.net.service; using dy.net.service;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Net.Http;
namespace dy.net.Controllers namespace dy.net.Controllers
{ {
-2
View File
@@ -4,8 +4,6 @@ using dy.net.service;
using dy.net.utils; using dy.net.utils;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System;
using System.Security.Cryptography;
namespace dy.net.Controllers namespace dy.net.Controllers
{ {
-65
View File
@@ -1,7 +1,6 @@
using dy.net.extension; using dy.net.extension;
using dy.net.service; using dy.net.service;
using dy.net.utils; using dy.net.utils;
using dy.sync.lib;
using Serilog; using Serilog;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
@@ -240,69 +239,5 @@ namespace dy.net
} }
} }
private static void PrintApp()
{
Console.ForegroundColor = ConsoleColor.DarkCyan;
// 步骤1:定义原始ASCII艺术字行(无缩进)
List<string> originalArtLines = new List<string>
{
" __ __ ",
" ___/ /_ __ ___ __ _____ ____ ___ ___ / /_",
"/ _ / // / (_-</ // / _ \\__/ / _ \\/ -_) __/",
"\\_,_/\\_, (_)___/\\_, /_//_/\\__(_)_//_/\\__/\\__/ ",
" /___/ /___/ "
};
// 步骤2:设置缩进字符数(可自由修改:4、8、10 等)
int indentCount = 4;
string indent = new string(' ', indentCount); // 生成对应数量的空格
// 步骤3:给每行添加缩进
List<string> indentedArtLines = new List<string>();
foreach (var line in originalArtLines)
{
indentedArtLines.Add(indent + line); // 每行开头拼接缩进空格
}
// 步骤4:找到缩进后最长行的长度(避免越界)
int maxLength = 0;
foreach (var line in indentedArtLines)
{
if (line.Length > maxLength) maxLength = line.Length;
}
// 步骤5:按列推进打印(从左到右,包含缩进)
for (int col = 0; col < maxLength; col++)
{
Console.SetCursorPosition(0, 0); // 重置光标到第一行开头
for (int row = 0; row < indentedArtLines.Count; row++)
{
// 定位到「当前列、当前行」(已包含缩进偏移)
Console.SetCursorPosition(col, row);
// 打印字符(无字符则补空格)
if (col < indentedArtLines[row].Length)
{
Console.Write(indentedArtLines[row][col]);
}
else
{
Console.Write(' ');
}
}
Thread.Sleep(20); // 列推进速度(可调整:10=快,50=慢)
}
// 打印完成后,光标移到艺术字下方
Console.SetCursorPosition(0, indentedArtLines.Count);
Console.WriteLine();
Console.ResetColor();
}
} }
} }
@@ -3,7 +3,7 @@
<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|2026-01-23T05:36:48.4086406Z||;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||;True|2026-01-07T23:47:45.1936189+08:00||;True|2026-01-07T23:35:09.7818611+08:00||;True|2026-01-07T23:20:43.7462863+08:00||;True|2026-01-07T23:04:39.5140429+08:00||;False|2026-01-07T23:04:36.5367611+08:00||;True|2026-01-07T22:53:14.6013449+08:00||;True|2026-01-07T22:49:59.9549006+08:00||;True|2026-01-07T22:36:40.0254856+08:00||;</History> <History>True|2026-01-23T14:14:26.8066324Z||;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||;True|2026-01-07T23:47:45.1936189+08:00||;True|2026-01-07T23:35:09.7818611+08:00||;True|2026-01-07T23:20:43.7462863+08:00||;True|2026-01-07T23:04:39.5140429+08:00||;False|2026-01-07T23:04:36.5367611+08:00||;True|2026-01-07T22:53:14.6013449+08:00||;True|2026-01-07T22:49:59.9549006+08:00||;</History>
<LastFailureDetails /> <LastFailureDetails />
</PropertyGroup> </PropertyGroup>
</Project> </Project>
+1
View File
@@ -73,6 +73,7 @@
<PackageReference Include="Serilog.Sinks.Async" Version="1.4.0" /> <PackageReference Include="Serilog.Sinks.Async" Version="1.4.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" /> <PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Serilog" Version="3.1.1" /> <PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="Serilog.Sinks.Seq" Version="4.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="System.Net.Http" Version="4.3.4" /> <PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" /> <PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
+1 -1
View File
@@ -2,7 +2,7 @@
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<ActiveDebugProfile>dy.net</ActiveDebugProfile> <ActiveDebugProfile>dy.net</ActiveDebugProfile>
<NameOfLastUsedPublishProfile>E:\code\dysync\Properties\PublishProfiles\fn.pubxml</NameOfLastUsedPublishProfile> <NameOfLastUsedPublishProfile>E:\code\dysync\Properties\PublishProfiles\docker.pubxml</NameOfLastUsedPublishProfile>
<Controller_SelectedScaffolderID>ApiControllerEmptyScaffolder</Controller_SelectedScaffolderID> <Controller_SelectedScaffolderID>ApiControllerEmptyScaffolder</Controller_SelectedScaffolderID>
<Controller_SelectedScaffolderCategoryPath>root/Common/Api</Controller_SelectedScaffolderCategoryPath> <Controller_SelectedScaffolderCategoryPath>root/Common/Api</Controller_SelectedScaffolderCategoryPath>
</PropertyGroup> </PropertyGroup>
-1
View File
@@ -1,7 +1,6 @@
using dy.net.model.dto; using dy.net.model.dto;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using System.Net;
namespace dy.net.extension namespace dy.net.extension
{ {
+1 -6
View File
@@ -1,10 +1,6 @@
using dy.net.job; using dy.net.service;
using dy.net.service;
using dy.net.utils; using dy.net.utils;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.ResponseCompression; using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
//using Microsoft.OpenApi.Models; //using Microsoft.OpenApi.Models;
@@ -19,7 +15,6 @@ using SqlSugar;
//using Swashbuckle.AspNetCore.SwaggerGen; //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.Security; using System.Net.Security;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
-111
View File
@@ -1,111 +0,0 @@
using dy.net.model.dto;
using dy.net.service;
using Quartz;
using Serilog;
using static Quartz.Logging.OperationName;
namespace dy.net.job
{
// /// <summary>
///// 抖音任务依赖监听器(独立公共类)
///// 作用:监听任务执行完成事件,触发下一个依赖任务,实现顺序执行
///// </summary>
// public class DouyinJobDependencyListener : IJobListener
// {
// // 监听器名称(唯一标识,不可重复)
// public string Name => "DouyinJobDependencyListener";
// /// <summary>
// /// 任务配置字典(从外部注入)
// /// </summary>
// private readonly Dictionary<string, JobConfig> _jobConfigs;
// /// <summary>
// /// 任务依赖关系(从外部注入,定义执行顺序)
// /// </summary>
// private readonly Dictionary<string, string> _jobDependency;
// /// <summary>
// /// 任务服务(用于触发下一个任务,从外部注入)
// /// </summary>
// private readonly DouyinQuartzJobService _jobService;
// /// <summary>
// /// 构造函数(依赖注入)
// /// </summary>
// /// <param name="jobConfigs">任务配置</param>
// /// <param name="jobDependency">任务依赖关系</param>
// /// <param name="jobService">任务服务</param>
// public DouyinJobDependencyListener(
// Dictionary<string, JobConfig> jobConfigs,
// Dictionary<string, string> jobDependency,
// DouyinQuartzJobService jobService)
// {
// _jobConfigs = jobConfigs ?? throw new ArgumentNullException(nameof(jobConfigs), "任务配置不能为空");
// _jobDependency = jobDependency ?? throw new ArgumentNullException(nameof(jobDependency), "任务依赖关系不能为空");
// _jobService = jobService ?? throw new ArgumentNullException(nameof(jobService), "任务服务不能为空");
// }
// /// <summary>
// /// 任务执行前触发(无需处理)
// /// </summary>
// public Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default)
// {
// return Task.CompletedTask;
// }
// /// <summary>
// /// 任务被否决执行时触发(无需处理)
// /// </summary>
// public Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default)
// {
// return Task.CompletedTask;
// }
// /// <summary>
// /// 任务执行完成后触发(核心逻辑:触发下一个依赖任务)
// /// </summary>
// public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException? jobException, CancellationToken cancellationToken = default)
// {
// var currentJobKey = context.JobDetail.Key;
// Log.Information("【任务监听】任务执行完成 - 任务名称: {JobName}, 执行状态: {Status}",
// currentJobKey.Name, jobException == null ? "成功" : "失败");
// // 1. 若当前任务执行失败,终止后续依赖任务(避免无效执行)
// if (jobException != null)
// {
// Log.Error(jobException, "【任务监听】任务 {JobName} 执行失败,终止后续任务链条", currentJobKey.Name);
// return;
// }
// // 2. 根据当前任务的 JobKey,找到对应的配置 Key(如:dy.job.key.collect → collect
// var currentConfigKey = _jobConfigs.FirstOrDefault(kv => kv.Value.JobKey == currentJobKey.Name).Key;
// if (string.IsNullOrEmpty(currentConfigKey))
// {
// Log.Warning("【任务监听】未找到任务 {JobName} 的配置信息,任务链条终止", currentJobKey.Name);
// return;
// }
// // 3. 查找下一个依赖任务的配置 Key
// if (!_jobDependency.TryGetValue(currentConfigKey, out var nextConfigKey) || string.IsNullOrEmpty(nextConfigKey))
// {
// Log.Information("【任务监听】任务 {JobName} 是最后一个任务,本次任务链条执行完毕", currentJobKey.Name);
// return;
// }
// // 4. 触发下一个任务(标记为「依赖触发」,立即执行)
// Log.Information("【任务监听】准备触发下一个任务: {NextJobName}(依赖触发)", nextConfigKey);
// var triggerSuccess = await _jobService.StartJobAsync(nextConfigKey, "", isDependencyTrigger: true);
// if (triggerSuccess)
// {
// Log.Information("【任务监听】下一个任务 {NextJobName} 触发成功", nextConfigKey);
// }
// else
// {
// Log.Error("【任务监听】下一个任务 {NextJobName} 触发失败,任务链条中断", nextConfigKey);
// }
// }
// }
}
-2
View File
@@ -3,8 +3,6 @@ using dy.net.model.entity;
using dy.net.model.response; using dy.net.model.response;
using dy.net.service; using dy.net.service;
using dy.net.utils; using dy.net.utils;
using Serilog;
using System;
namespace dy.net.job namespace dy.net.job
{ {
+9 -21
View File
@@ -814,8 +814,6 @@ namespace dy.net.job
var videoUrl = v.PlayAddr.UrlList.Where(x => !string.IsNullOrEmpty(x))?.FirstOrDefault(); var videoUrl = v.PlayAddr.UrlList.Where(x => !string.IsNullOrEmpty(x))?.FirstOrDefault();
if (string.IsNullOrWhiteSpace(videoUrl)) return null; if (string.IsNullOrWhiteSpace(videoUrl)) return null;
// 获取视频标签
var (tag1, tag2, tag3) = GetVideoTags(item);
// 创建保存文件夹 // 创建保存文件夹
var saveFolder = CreateSaveFolder(cookie, item, config, followed, cate); var saveFolder = CreateSaveFolder(cookie, item, config, followed, cate);
// 获取视频文件名 // 获取视频文件名
@@ -856,7 +854,7 @@ namespace dy.net.job
var (avatarSavePath, avatarUrl) = await DownAuthorAvatar(cookie, item); var (avatarSavePath, avatarUrl) = await DownAuthorAvatar(cookie, item);
// 创建视频实体 // 创建视频实体
return await CreateVideoEntity(config, cookie, item, v, savePath, saveFolder, tag1, tag2, tag3, avatarUrl, avatarSavePath, null, cate); return await CreateVideoEntity(config, cookie, item, v, savePath, saveFolder, avatarSavePath, null, cate);
} }
/// <summary> /// <summary>
@@ -871,10 +869,6 @@ namespace dy.net.job
/// <returns></returns> /// <returns></returns>
protected async Task<DouyinVideo> ProcessDynamicVideo(List<DouyinDynamicVideoDto> dynamicUrls, DouyinCookie cookie, Aweme item, AppConfig config, DouyinFollowed followed = null, DouyinCollectCate cate = null) protected async Task<DouyinVideo> ProcessDynamicVideo(List<DouyinDynamicVideoDto> dynamicUrls, DouyinCookie cookie, Aweme item, AppConfig config, DouyinFollowed followed = null, DouyinCollectCate cate = null)
{ {
// 获取视频标签
var (tag1, tag2, tag3) = GetVideoTags(item);
// 创建保存文件夹 // 创建保存文件夹
var saveFolder = CreateSaveFolder(cookie, item, config, followed, cate); var saveFolder = CreateSaveFolder(cookie, item, config, followed, cate);
// 获取视频文件名 // 获取视频文件名
@@ -932,7 +926,7 @@ namespace dy.net.job
DataSize = DouyinFileUtils.GetTotalFileSize(dynamicSavePaths.Select(x => x.Path).ToList()) // 合成视频的文件大小 DataSize = DouyinFileUtils.GetTotalFileSize(dynamicSavePaths.Select(x => x.Path).ToList()) // 合成视频的文件大小
} }
}; };
return await CreateVideoEntity(config, cookie, item, virtualBitRate, dynamicSavePaths.FirstOrDefault()?.Path, saveFolder, tag1, tag2, tag3, avatarUrl, avatarSavePath, dynamicSavePaths,cate); return await CreateVideoEntity(config, cookie, item, virtualBitRate, dynamicSavePaths.FirstOrDefault()?.Path, saveFolder, avatarSavePath, dynamicSavePaths, cate);
} }
@@ -1090,7 +1084,7 @@ namespace dy.net.job
} }
var coverUrl = cate is not null && cate.CateType != VideoTypeEnum.dy_custom_collect var coverUrl = cate is not null && cate.CateType != VideoTypeEnum.dy_custom_collect
? item.Music?.CoverHd?.UrlList?.FirstOrDefault() ?? imageUrls.FirstOrDefault() ? (item.MixInfo?.CoverUrl?.UrlList?.FirstOrDefault() ?? imageUrls.FirstOrDefault() ?? item.Music?.CoverHd?.UrlList?.FirstOrDefault())
: imageUrls.FirstOrDefault(); : imageUrls.FirstOrDefault();
// 下载视频封面(使用第一张图片作为封面) // 下载视频封面(使用第一张图片作为封面)
if (!string.IsNullOrWhiteSpace(coverUrl)) if (!string.IsNullOrWhiteSpace(coverUrl))
@@ -1098,8 +1092,6 @@ namespace dy.net.job
// 下载作者头像 // 下载作者头像
var (avatarSavePath, avatarUrl) = await DownAuthorAvatar(cookie, item); var (avatarSavePath, avatarUrl) = await DownAuthorAvatar(cookie, item);
// 获取视频标签
var (tag1, tag2, tag3) = GetVideoTags(item);
// 为合成的视频创建一个“虚拟”的BitRate对象,以便复用CreateVideoEntity方法 // 为合成的视频创建一个“虚拟”的BitRate对象,以便复用CreateVideoEntity方法
var virtualBitRate = new VideoBitRate var virtualBitRate = new VideoBitRate
{ {
@@ -1113,8 +1105,7 @@ namespace dy.net.job
// 创建视频实体 // 创建视频实体
var videoEntity = await CreateVideoEntity(config, var videoEntity = await CreateVideoEntity(config,
cookie, item, virtualBitRate, savePath, fileNamefolder, cookie, item, virtualBitRate, savePath, fileNamefolder, avatarSavePath, null, cate);
tag1, tag2, tag3, avatarUrl,avatarSavePath, null,cate);
// 特殊处理合成视频的字段 // 特殊处理合成视频的字段
videoEntity.FileHash = string.Empty; // 合成视频没有原始文件哈希 videoEntity.FileHash = string.Empty; // 合成视频没有原始文件哈希
@@ -1174,8 +1165,8 @@ namespace dy.net.job
{ {
// cate不为空时:优先MixInfo封面 → 其次Music高清封面 → 最后Video封面 // cate不为空时:优先MixInfo封面 → 其次Music高清封面 → 最后Video封面
coverUrl = item.MixInfo?.CoverUrl?.UrlList?.FirstOrDefault() coverUrl = item.MixInfo?.CoverUrl?.UrlList?.FirstOrDefault()
?? item.Music?.CoverHd?.UrlList?.FirstOrDefault() ?? item.Video.Cover.UrlList?.LastOrDefault()
?? item.Video.Cover.UrlList?.FirstOrDefault(); ?? item.Music?.CoverHd?.UrlList?.FirstOrDefault();
} }
else else
{ {
@@ -1318,18 +1309,15 @@ namespace dy.net.job
/// <param name="bitRate">视频码率信息</param> /// <param name="bitRate">视频码率信息</param>
/// <param name="savePath">视频保存路径</param> /// <param name="savePath">视频保存路径</param>
/// <param name="saveFolder">视频保存文件夹</param> /// <param name="saveFolder">视频保存文件夹</param>
/// <param name="tag1">视频标签1</param>
/// <param name="tag2">视频标签2</param>
/// <param name="tag3">视频标签3</param>
/// <param name="avatorUrl"></param>
/// <param name="avatorPath"></param> /// <param name="avatorPath"></param>
/// <param name="dynamicVideos">动态视频</param> /// <param name="dynamicVideos">动态视频</param>
/// <param name="cate">短剧、合集、自定义收藏夹</param> /// <param name="cate">短剧、合集、自定义收藏夹</param>
/// <returns>创建的视频实体对象</returns> /// <returns>创建的视频实体对象</returns>
private async Task<DouyinVideo> CreateVideoEntity(AppConfig config, private async Task<DouyinVideo> CreateVideoEntity(AppConfig config,
DouyinCookie cookie, Aweme item, VideoBitRate bitRate, string savePath, string saveFolder, DouyinCookie cookie, Aweme item, VideoBitRate bitRate, string savePath, string saveFolder, string avatorPath, List<DouyinDynamicVideoDto> dynamicVideos = null, DouyinCollectCate cate = null)
string tag1, string tag2, string tag3,string avatorUrl,string avatorPath, List<DouyinDynamicVideoDto> dynamicVideos = null,DouyinCollectCate cate=null)
{ {
// 获取视频标签
var (tag1, tag2, tag3) = GetVideoTags(item);
var video = new DouyinVideo var video = new DouyinVideo
{ {
ViedoType = VideoType, ViedoType = VideoType,
-1
View File
@@ -3,7 +3,6 @@ using dy.net.model.entity;
using dy.net.model.response; using dy.net.model.response;
using dy.net.service; using dy.net.service;
using dy.net.utils; using dy.net.utils;
using System;
namespace dy.net.job namespace dy.net.job
{ {
+2 -5
View File
@@ -4,10 +4,6 @@ using dy.net.model.entity;
using dy.net.model.response; using dy.net.model.response;
using dy.net.service; using dy.net.service;
using dy.net.utils; using dy.net.utils;
using Newtonsoft.Json;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace dy.net.job namespace dy.net.job
{ {
@@ -95,7 +91,8 @@ namespace dy.net.job
{ {
//图片合成视频,参数要自己写。 //图片合成视频,参数要自己写。
var image = item.Images?.FirstOrDefault(); var image = item.Images?.FirstOrDefault();
if(image != null){ if (image != null)
{
FileHash = IdGener.GetGuid().ToLower().Replace("-", "");//使用随机值,避免重复 FileHash = IdGener.GetGuid().ToLower().Replace("-", "");//使用随机值,避免重复
Height = image.Height.ToString(); Height = image.Height.ToString();
Width = image.Width.ToString(); Width = image.Width.ToString();
-4
View File
@@ -4,10 +4,6 @@ using dy.net.model.response;
using dy.net.service; using dy.net.service;
using Quartz; using Quartz;
using Serilog; using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace dy.net.job namespace dy.net.job
{ {
-1
View File
@@ -3,7 +3,6 @@ using dy.net.model.entity;
using dy.net.model.response; using dy.net.model.response;
using dy.net.service; using dy.net.service;
using dy.net.utils; using dy.net.utils;
using System.Net;
namespace dy.net.job namespace dy.net.job
{ {
+1 -3
View File
@@ -1,6 +1,4 @@
using Newtonsoft.Json; namespace dy.net.model.dto
namespace dy.net.model.dto
{ {
public class DouyinUpSecUserIdDto public class DouyinUpSecUserIdDto
{ {
+1 -3
View File
@@ -1,6 +1,4 @@
using System.ComponentModel.DataAnnotations; namespace dy.net.model.dto
namespace dy.net.model.dto
{ {
public class DouyinVideoPageRequestDto : PageRequestDto public class DouyinVideoPageRequestDto : PageRequestDto
{ {
+1 -8
View File
@@ -1,11 +1,4 @@
using System; namespace dy.net.model.dto
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace dy.net.model.dto
{ {
public class MediaMergeRequest public class MediaMergeRequest
{ {
+1 -3
View File
@@ -1,6 +1,4 @@
using System.ComponentModel; namespace dy.net.model.dto
namespace dy.net.model.dto
{ {
public enum VideoTypeEnum public enum VideoTypeEnum
{ {
+1 -3
View File
@@ -1,6 +1,4 @@
using System.Diagnostics.CodeAnalysis; namespace dy.net.model.entity
namespace dy.net.model.entity
{ {
[SqlSugar.SugarTable(TableName = "login_user_info")] [SqlSugar.SugarTable(TableName = "login_user_info")]
public class AdminUserInfo public class AdminUserInfo
+1 -3
View File
@@ -1,6 +1,4 @@
using Newtonsoft.Json; using SqlSugar;
using SqlSugar;
using System.Text.RegularExpressions;
namespace dy.net.model.entity namespace dy.net.model.entity
{ {
+1 -2
View File
@@ -1,5 +1,4 @@
using Newtonsoft.Json; using SqlSugar;
using SqlSugar;
namespace dy.net.model.entity namespace dy.net.model.entity
{ {
+1 -2
View File
@@ -1,5 +1,4 @@
using dy.net.extension; using dy.net.model.dto;
using dy.net.model.dto;
using dy.net.utils; using dy.net.utils;
using SqlSugar; using SqlSugar;
@@ -1,5 +1,4 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Collections.Generic;
namespace dy.net.model.response namespace dy.net.model.response
{ {
@@ -3,8 +3,6 @@ using dy.net.model.dto;
using dy.net.model.entity; using dy.net.model.entity;
using dy.net.utils; using dy.net.utils;
using SqlSugar; using SqlSugar;
using System;
using System.Linq.Expressions;
namespace dy.net.repository namespace dy.net.repository
{ {
-1
View File
@@ -1,5 +1,4 @@
using ClockSnowFlake; using ClockSnowFlake;
using dy.net.extension;
using dy.net.model.dto; using dy.net.model.dto;
using dy.net.model.entity; using dy.net.model.entity;
using dy.net.model.response; using dy.net.model.response;
-2
View File
@@ -1,9 +1,7 @@
using dy.net.extension; using dy.net.extension;
using dy.net.model.dto; using dy.net.model.dto;
using dy.net.model.entity; using dy.net.model.entity;
using Quartz.Util;
using SqlSugar; using SqlSugar;
using System.Linq;
namespace dy.net.repository namespace dy.net.repository
{ {
+1 -5
View File
@@ -1,10 +1,6 @@
using ClockSnowFlake; using dy.net.model.dto;
using dy.net.model.dto;
using dy.net.model.entity; using dy.net.model.entity;
using dy.net.model.response;
using dy.net.repository; using dy.net.repository;
using SqlSugar;
using System.Linq.Expressions;
namespace dy.net.service namespace dy.net.service
{ {
-4
View File
@@ -1,10 +1,6 @@
using ClockSnowFlake; using ClockSnowFlake;
using dy.net.model.dto;
using dy.net.model.entity; using dy.net.model.entity;
using dy.net.utils;
using SqlSugar; using SqlSugar;
using System.Reflection;
using System.Threading.Tasks;
//using static Org.BouncyCastle.Math.EC.ECCurve; //using static Org.BouncyCastle.Math.EC.ECCurve;
namespace dy.net.service namespace dy.net.service
-2
View File
@@ -2,9 +2,7 @@
using dy.net.model.dto; using dy.net.model.dto;
using dy.net.model.entity; using dy.net.model.entity;
using dy.net.repository; using dy.net.repository;
using SqlSugar;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Threading.Tasks;
namespace dy.net.service namespace dy.net.service
{ {
-1
View File
@@ -4,7 +4,6 @@ using dy.net.model.entity;
using dy.net.model.response; using dy.net.model.response;
using dy.net.repository; using dy.net.repository;
using SqlSugar; using SqlSugar;
using System.Linq.Expressions;
namespace dy.net.service namespace dy.net.service
{ {
+2 -5
View File
@@ -1,13 +1,10 @@
using Dm; using dy.net.model.dto;
using dy.net.model.dto;
using dy.net.model.entity; using dy.net.model.entity;
using dy.net.model.response; using dy.net.model.response;
using dy.net.utils; using dy.net.utils;
using Microsoft.AspNetCore.WebUtilities; using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Net.Http;
using System.Web;
namespace dy.net.service namespace dy.net.service
{ {
@@ -15,7 +12,7 @@ namespace dy.net.service
{ {
readonly IHttpClientFactory _clientFactory; private readonly IHttpClientFactory _clientFactory;
public DouyinHttpClientService(IHttpClientFactory clientFactory) public DouyinHttpClientService(IHttpClientFactory clientFactory)
{ {
_clientFactory = clientFactory; _clientFactory = clientFactory;
+1 -3
View File
@@ -1,9 +1,7 @@
using ClockSnowFlake; using dy.net.extension;
using dy.net.extension;
using dy.net.model.dto; using dy.net.model.dto;
using dy.net.utils; using dy.net.utils;
using Serilog; using Serilog;
using System.Collections.Generic;
using System.Security.Cryptography; using System.Security.Cryptography;
namespace dy.net.service namespace dy.net.service
+3 -6
View File
@@ -3,10 +3,6 @@ using dy.net.model.dto;
using dy.net.utils; using dy.net.utils;
using Quartz; using Quartz;
using Serilog; using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace dy.net.service namespace dy.net.service
{ {
@@ -99,7 +95,6 @@ namespace dy.net.service
/// 启动所有抖音相关定时任务(所有任务独立执行) /// 启动所有抖音相关定时任务(所有任务独立执行)
/// </summary> /// </summary>
/// <param name="expression">Cron表达式或间隔分钟数(所有任务使用相同的执行频率)</param> /// <param name="expression">Cron表达式或间隔分钟数(所有任务使用相同的执行频率)</param>
/// <param name="isRestart"></param>
/// <returns>是否启动成功</returns> /// <returns>是否启动成功</returns>
public async Task<bool> InitOrReStartAllJobs(string expression) public async Task<bool> InitOrReStartAllJobs(string expression)
{ {
@@ -120,6 +115,8 @@ namespace dy.net.service
// 执行任务启动逻辑 // 执行任务启动逻辑
foreach (var jobKey in JobConfigs.Keys) foreach (var jobKey in JobConfigs.Keys)
{ {
if (jobKey == "follow_user_once")
continue;
if (jobKey == "follow_user") expression = "60"; if (jobKey == "follow_user") expression = "60";
var startSuccess = await StartJobAsync(jobKey, expression); var startSuccess = await StartJobAsync(jobKey, expression);
if (startSuccess) if (startSuccess)
@@ -131,7 +128,7 @@ namespace dy.net.service
Log.Error($"启动任务失败:{jobKey}"); Log.Error($"启动任务失败:{jobKey}");
} }
} }
Log.Information($"共启动 {JobConfigs.Count} 个定时任务"); Log.Information($"共启动 {JobConfigs.Count - 1} 个定时任务");
//await StartJobAsync(VideoTypeEnum.dy_custom_collect.GetDesc(), expression); //await StartJobAsync(VideoTypeEnum.dy_custom_collect.GetDesc(), expression);
-371
View File
@@ -1,371 +0,0 @@
//using dy.net.job;
//using dy.net.model.dto;
//using Quartz;
//using Quartz.Impl.Matchers;
//using Serilog;
//using System;
//using System.Threading.Tasks;
//namespace dy.net.service
//{
// /// <summary>
// /// 抖音相关定时任务服务
// /// </summary>
// public class DouyinQuartzJobService
// {
// private readonly ISchedulerFactory _schedulerFactory;
// private const string DefaultJobGroup = "dysync.net";
// private const int DefaultIntervalMinutes = 30;
// private const int DefaultCronStartDelaySeconds = 30;
// private const int DefaultSimpleStartDelaySeconds = 3;
// // 任务顺序依赖配置(核心:定义执行顺序,供 Listener 使用)
// public Dictionary<string, string> JobDependency { get; } = new()
// {
// {"collect", "favorite"}, // collect 执行完 → 触发 favorite
// {"favorite", "followed"}, // favorite 执行完 → 触发 followed
// {"followed", null}, // followed 执行完 → 一轮任务结束
// };
// // 任务配置信息(保持原有配置不变,改为 public 供 Listener 访问)
// public Dictionary<string, JobConfig> JobConfigs { get; } = new()
// {
// {
// "collect",
// new JobConfig(
// typeof(DouyinCollectSyncJob),
// "dy.job.key.collect",
// "dy.trigger.key.collect",
// "抖音收藏同步任务")
// },
// {
// "favorite",
// new JobConfig(
// typeof(DouyinFavoritSyncJob),
// "dy.job.key.favorite",
// "dy.trigger.key.favorite",
// "抖音点赞同步任务")
// },
// {
// "followed",
// new JobConfig(
// typeof(DouyinFollowedSyncJob),
// "dy.job.key.followed",
// "dy.trigger.key.followed",
// "抖音关注博主作品同步任务")
// },
// {
// "follow_user",
// new JobConfig(
// typeof(DouyinFollowsAndCollnectsSyncJob),
// "dy.job.key.follow_user",
// "dy.trigger.key.follow_user",
// "抖音关注列表同步任务")
// },
// {
// "custom_collect",
// new JobConfig(
// typeof(DouyinCollectCustomSyncJob),
// "dy.job.key.custom_collect",
// "dy.trigger.key.custom_collect",
// "抖音自定义收藏夹列表同步任务")
// },
// {
// "mix",
// new JobConfig(
// typeof(DouyinMixSyncJob),
// "dy.job.key.mix",
// "dy.trigger.key.mix",
// "抖音收藏夹合集同步任务")
// },
// {
// "series",
// new JobConfig(
// typeof(DouyinSeriesSyncJob),
// "dy.job.key.mix",
// "dy.trigger.key.mix",
// "抖音收藏夹短剧同步任务")
// },
// {
// "follow_user_once",
// new JobConfig(
// typeof(DouyinFollowsAndCollnectsSyncJob),
// "dy.job.key.follow_user_once",
// "dy.trigger.key.follow_user_once",
// "抖音关注同步任务(单次执行)")
// }
// };
// public DouyinQuartzJobService(ISchedulerFactory schedulerFactory)
// {
// _schedulerFactory = schedulerFactory ?? throw new ArgumentNullException(nameof(schedulerFactory));
// }
// /// <summary>
// /// 启动所有抖音相关定时任务(顺序执行模式)
// /// </summary>
// /// <param name="expression">Cron表达式或间隔分钟数(控制整个链条的执行频率)</param>
// /// <returns>是否启动成功</returns>
// public async Task<bool> InitOrReStartAllJobs(string expression)
// {
// if (string.IsNullOrWhiteSpace(expression))
// {
// Log.Debug("定时任务表达式为空,使用默认配置({DefaultMinutes}分钟)", DefaultIntervalMinutes);
// expression = DefaultIntervalMinutes.ToString();
// }
// try
// {
// var scheduler = await _schedulerFactory.GetScheduler();
// // 1. 注册独立的 JobListener(核心:注入配置和服务)
// await RegisterJobListener(scheduler);
// // 2. 移除所有已存在的任务(避免重复调度)
// await RemoveAllExistingJobs(scheduler);
// // 3. 只启动第一个任务(collect),后续任务由 Listener 自动触发
// var firstJobConfigKey = "collect";
// //var startSuccess = await StartJobAsync(firstJobConfigKey, expression);
// //if (startSuccess)
// //{
// // Log.Debug($"同步任务执行顺序:collect → favorite → followed-->默认每{expression}分钟执行一次...");
// //}
// //else
// //{
// // Log.Error($"任务执行失败(任务 {firstJobConfigKey} 启动失败)");
// //}
// //启动follow_user--这个与其他几个任务没有依赖关系,所以单独启动
// //await StartJobAsync("collect", expression);
// //await StartJobAsync("follow_user", expression);
// //await StartJobAsync("follow_user", expression);
// //await StartJobAsync("follow_user", expression);
// //await StartJobAsync("custom_collect", expression);
// //await StartJobAsync("mix", expression);
// //await StartJobAsync("series", expression);
// return true;
// }
// catch (Exception ex)
// {
// Log.Error(ex, "【任务服务】初始化任务链条异常");
// return false;
// }
// }
// /// <summary>
// /// 启动关注同步任务(单次执行)
// /// </summary>
// public async Task<bool> StartFollowJobOnceAsync()
// {
// return await StartOneTimeJobAsync("follow_user_once");
// }
// /// <summary>
// /// 注册独立的 JobListener(核心步骤)
// /// </summary>
// private async Task RegisterJobListener(IScheduler scheduler)
// {
// // 创建独立的 Listener 实例,注入依赖(任务配置、依赖关系、当前服务)
// var dependencyListener = new DouyinJobDependencyListener(
// JobConfigs, // 任务配置
// JobDependency, // 依赖顺序
// this // 任务服务(用于触发下一个任务)
// );
// // 注册 Listener:仅监听 DefaultJobGroup 分组的任务(精准匹配,避免影响其他任务)
// scheduler.ListenerManager.AddJobListener(
// dependencyListener,
// GroupMatcher<JobKey>.GroupEquals(DefaultJobGroup)
// );
// Log.Information("【任务服务】JobListener 注册成功:{ListenerName}", dependencyListener.Name);
// }
// /// <summary>
// /// 移除所有已存在的任务(避免重复调度)
// /// </summary>
// private async Task RemoveAllExistingJobs(IScheduler scheduler)
// {
// var jobKeys = JobConfigs.Values.Select(config => new JobKey(config.JobKey, DefaultJobGroup)).ToList();
// foreach (var jobKey in jobKeys)
// {
// if (await scheduler.CheckExists(jobKey))
// {
// Log.Information("【任务服务】移除已存在的任务: {JobKey}", jobKey);
// await scheduler.DeleteJob(jobKey);
// }
// }
// }
// /// <summary>
// /// 启动指定定时任务(public 修饰,供 Listener 调用)
// /// </summary>
// /// <param name="configKey">任务配置Key(如:collect、favorite</param>
// /// <param name="expression">定时表达式(依赖触发时传空)</param>
// /// <param name="isDependencyTrigger">是否为依赖触发(true=立即执行,false=定时执行)</param>
// /// <returns>是否启动成功</returns>
// public async Task<bool> StartJobAsync(string configKey, string expression, bool isDependencyTrigger = false)
// {
// if (!JobConfigs.TryGetValue(configKey, out var jobConfig))
// {
// Log.Error("【任务服务】找不到任务配置: {ConfigKey}", configKey);
// return false;
// }
// try
// {
// var scheduler = await _schedulerFactory.GetScheduler();
// var jobKey = new JobKey(jobConfig.JobKey, DefaultJobGroup);
// // 触发器Key:区分「定时触发」和「依赖触发」,避免冲突
// var triggerKey = new TriggerKey(
// $"{jobConfig.TriggerKey}_{(isDependencyTrigger ? "dependency" : "main")}",
// DefaultJobGroup
// );
// // 移除已存在的任务(防止重复执行)
// await RemoveExistingJobAsync(scheduler, jobKey);
// // 创建任务详情(添加禁止并发执行特性,避免顺序混乱)
// var jobDetail = JobBuilder.Create(jobConfig.JobType)
// .WithIdentity(jobKey)
// .WithDescription(jobConfig.Description)
// .DisallowConcurrentExecution() // 关键:禁止同一任务并发执行
// .Build();
// // 创建立触发器
// ITrigger trigger = isDependencyTrigger
// ? CreateDependencyTrigger(triggerKey, jobConfig.Description) // 依赖触发:立即执行
// : CreateScheduledTrigger(triggerKey, expression, jobConfig.Description); // 定时触发:按表达式执行
// // 调度任务
// await scheduler.ScheduleJob(jobDetail, trigger);
// Log.Information("【任务服务】启动任务成功 - 任务描述: {JobDescription}, 触发类型: {TriggerType}, 表达式: {Expression}",
// jobConfig.Description,
// isDependencyTrigger ? "依赖触发(立即执行)" : "定时触发",
// isDependencyTrigger ? "无" : expression);
// return true;
// }
// catch (Exception ex)
// {
// Log.Error(ex, "【任务服务】启动任务失败 - 任务描述: {JobDescription}", jobConfig.Description);
// return false;
// }
// }
// /// <summary>
// /// 启动单次执行任务(保持原有逻辑不变)
// /// </summary>
// private async Task<bool> StartOneTimeJobAsync(string configKey)
// {
// if (!JobConfigs.TryGetValue(configKey, out var jobConfig))
// {
// Log.Error("【任务服务】找不到任务配置: {ConfigKey}", configKey);
// return false;
// }
// try
// {
// var scheduler = await _schedulerFactory.GetScheduler();
// var jobKey = new JobKey(jobConfig.JobKey, DefaultJobGroup);
// var triggerKey = new TriggerKey(jobConfig.TriggerKey, DefaultJobGroup);
// await RemoveExistingJobAsync(scheduler, jobKey);
// var jobDetail = JobBuilder.Create(jobConfig.JobType)
// .WithIdentity(jobKey)
// .WithDescription(jobConfig.Description)
// .DisallowConcurrentExecution()
// .Build();
// var trigger = TriggerBuilder.Create()
// .WithIdentity(triggerKey)
// .WithDescription($"{jobConfig.Description} - 单次执行")
// .StartNow()
// .Build();
// await scheduler.ScheduleJob(jobDetail, trigger);
// Log.Information("【任务服务】启动单次任务成功 - 任务描述: {JobDescription}", jobConfig.Description);
// return true;
// }
// catch (Exception ex)
// {
// Log.Error(ex, "【任务服务】启动单次任务失败 - 任务描述: {JobDescription}", jobConfig.Description);
// return false;
// }
// }
// /// <summary>
// /// 创建「定时触发器」(按表达式执行,仅第一个任务使用)
// /// </summary>
// private ITrigger CreateScheduledTrigger(TriggerKey triggerKey, string expression, string jobDescription)
// {
// // Cron表达式格式
// if (CronExpression.IsValidExpression(expression))
// {
// return TriggerBuilder.Create()
// .WithIdentity(triggerKey)
// .WithDescription($"{jobDescription} - Cron调度")
// .WithCronSchedule(expression)
// .StartAt(DateTime.Now.AddSeconds(DefaultCronStartDelaySeconds))
// .Build();
// }
// // 数字间隔格式(分钟)
// if (int.TryParse(expression, out int intervalMinutes))
// {
// intervalMinutes = Math.Max(1, intervalMinutes); // 最小间隔1分钟
// return TriggerBuilder.Create()
// .WithIdentity(triggerKey)
// .WithDescription($"{jobDescription} - 间隔{intervalMinutes}分钟调度")
// .StartAt(DateTime.Now.AddSeconds(DefaultSimpleStartDelaySeconds))
// .WithSimpleSchedule(x => x
// .WithIntervalInMinutes(intervalMinutes)
// .RepeatForever())
// .Build();
// }
// // 无效表达式,使用默认配置
// Log.Warning("【任务服务】无效的任务表达式: {Expression},使用默认间隔{DefaultMinutes}分钟",
// expression, DefaultIntervalMinutes);
// return TriggerBuilder.Create()
// .WithIdentity(triggerKey)
// .WithDescription($"{jobDescription} - 默认间隔调度")
// .StartAt(DateTime.Now.AddSeconds(DefaultSimpleStartDelaySeconds))
// .WithSimpleSchedule(x => x
// .WithIntervalInMinutes(DefaultIntervalMinutes)
// .RepeatForever())
// .Build();
// }
// /// <summary>
// /// 创建「依赖触发器」(立即执行,仅执行一次)
// /// </summary>
// private ITrigger CreateDependencyTrigger(TriggerKey triggerKey, string jobDescription)
// {
// return TriggerBuilder.Create()
// .WithIdentity(triggerKey)
// .WithDescription($"{jobDescription} - 依赖触发(立即执行)")
// .StartNow() // 立即触发
// .Build();
// }
// /// <summary>
// /// 移除已存在的任务(保持原有逻辑不变)
// /// </summary>
// private async Task RemoveExistingJobAsync(IScheduler scheduler, JobKey jobKey)
// {
// if (await scheduler.CheckExists(jobKey))
// {
// Log.Information("【任务服务】移除已存在的任务: {JobKey}", jobKey);
// await scheduler.DeleteJob(jobKey);
// }
// }
//}
//}
-5
View File
@@ -3,13 +3,8 @@ using dy.net.model.dto;
using dy.net.model.entity; using dy.net.model.entity;
using dy.net.repository; using dy.net.repository;
using dy.net.utils; using dy.net.utils;
using Newtonsoft.Json;
using Serilog; using Serilog;
using SqlSugar; using SqlSugar;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace dy.net.service namespace dy.net.service
{ {
+1 -3
View File
@@ -1,6 +1,4 @@
using ClockSnowFlake; using System.Text;
using System.IO;
using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace dy.net.utils namespace dy.net.utils
-1
View File
@@ -1,5 +1,4 @@
using dy.net.model.dto; using dy.net.model.dto;
using System.Collections.Generic;
namespace dy.net.utils namespace dy.net.utils
{ {
-6
View File
@@ -1,14 +1,8 @@
using dy.net.model.dto; using dy.net.model.dto;
using Serilog; using Serilog;
using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.IO;
using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace dy.net.utils namespace dy.net.utils
{ {
-1
View File
@@ -1,6 +1,5 @@
using dy.net.model.dto; using dy.net.model.dto;
using dy.net.model.entity; using dy.net.model.entity;
using System.IO;
using System.Text; using System.Text;
using System.Xml.Linq; using System.Xml.Linq;