代码整理
This commit is contained in:
@@ -20,7 +20,7 @@ namespace dy.net.service
|
||||
return await _userRepository.UpdatePwd(loginUser);
|
||||
}
|
||||
|
||||
public async Task<AdminUserInfo> GetUser(string userName=null)
|
||||
public async Task<AdminUserInfo> GetUser(string userName = null)
|
||||
{
|
||||
return await _userRepository.GetUser(userName);
|
||||
}
|
||||
@@ -30,7 +30,7 @@ namespace dy.net.service
|
||||
return await _userRepository.UpdateAvatar(avatar);
|
||||
}
|
||||
|
||||
public (int code, string erro) InitUser(string UserName,string Password)
|
||||
public (int code, string erro) InitUser(string UserName, string Password)
|
||||
{
|
||||
AdminUserInfo userInfo = new AdminUserInfo
|
||||
{
|
||||
@@ -38,7 +38,7 @@ namespace dy.net.service
|
||||
Password = Password,
|
||||
CreateTime = DateTime.Now
|
||||
};
|
||||
return _userRepository.InitUser(userInfo);
|
||||
return _userRepository.InitUser(userInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.response;
|
||||
using dy.net.repository;
|
||||
using SqlSugar;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace dy.net.service
|
||||
{
|
||||
@@ -26,7 +22,7 @@ namespace dy.net.service
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -45,7 +41,7 @@ namespace dy.net.service
|
||||
/// <param name="ckId"></param>
|
||||
/// <param name="cateType"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<(int add, int update,int delete, bool succ)> Sync(List<DouyinCollectCate> cates, string ckId,VideoTypeEnum cateType)
|
||||
public async Task<(int add, int update, int delete, bool succ)> Sync(List<DouyinCollectCate> cates, string ckId, VideoTypeEnum cateType)
|
||||
{
|
||||
return await _douyinCollectCateRepository.Sync(cates, ckId, cateType);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
using ClockSnowFlake;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using dy.net.utils;
|
||||
using SqlSugar;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
//using static Org.BouncyCastle.Math.EC.ECCurve;
|
||||
|
||||
namespace dy.net.service
|
||||
@@ -157,7 +153,7 @@ namespace dy.net.service
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#region 测试创建数据库
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using dy.net.repository;
|
||||
using SqlSugar;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace dy.net.service
|
||||
{
|
||||
@@ -33,7 +31,7 @@ namespace dy.net.service
|
||||
/// <returns></returns>
|
||||
public async Task<bool> IsInit()
|
||||
{
|
||||
return await _cookieRepository.ExistsAsync(x => !string.IsNullOrEmpty(x.Id));
|
||||
return await _cookieRepository.ExistsAsync(x => !string.IsNullOrEmpty(x.Id));
|
||||
}
|
||||
public async Task<bool> Add(DouyinCookie dyUserCookies)
|
||||
{
|
||||
@@ -52,7 +50,7 @@ namespace dy.net.service
|
||||
}
|
||||
var cookie = new DouyinCookie
|
||||
{
|
||||
UserName = "douyin2026",
|
||||
UserName = "douyin2026",
|
||||
Cookies = "",
|
||||
SecUserId = "",
|
||||
Id = IdGener.GetLong().ToString(),
|
||||
@@ -64,11 +62,11 @@ namespace dy.net.service
|
||||
//CollHasSyncd = 0,
|
||||
//FavHasSyncd = 0,
|
||||
//UperSyncd = 0,
|
||||
MyUserId=""
|
||||
MyUserId = ""
|
||||
};
|
||||
return _cookieRepository.Insert(cookie);
|
||||
return _cookieRepository.Insert(cookie);
|
||||
}
|
||||
|
||||
|
||||
// 查询单个
|
||||
public async Task<DouyinCookie> GetByIdAsync(string id)
|
||||
{
|
||||
|
||||
@@ -4,7 +4,6 @@ using dy.net.model.entity;
|
||||
using dy.net.model.response;
|
||||
using dy.net.repository;
|
||||
using SqlSugar;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace dy.net.service
|
||||
{
|
||||
@@ -32,8 +31,8 @@ namespace dy.net.service
|
||||
/// <returns></returns>
|
||||
public async Task<bool> AddAsync(DouyinFollowed followed)
|
||||
{
|
||||
var foll= await _followRepository.GetFirstAsync(x=>x.SecUid==followed.SecUid && x.mySelfId== followed.mySelfId);
|
||||
if(foll!=null)
|
||||
var foll = await _followRepository.GetFirstAsync(x => x.SecUid == followed.SecUid && x.mySelfId == followed.mySelfId);
|
||||
if (foll != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -59,7 +58,7 @@ namespace dy.net.service
|
||||
/// <returns></returns>
|
||||
public async Task<List<DouyinFollowed>> GetHandFollows()
|
||||
{
|
||||
return await _followRepository.GetListAsync(x=>x.IsNoFollowed);
|
||||
return await _followRepository.GetListAsync(x => x.IsNoFollowed);
|
||||
}
|
||||
/// <summary>
|
||||
/// 导入非关注
|
||||
@@ -114,8 +113,8 @@ namespace dy.net.service
|
||||
return await _followRepository.Sync(followInfos, ck);
|
||||
}
|
||||
|
||||
public async Task<DouyinFollowed> GetByUperId(string uperId,string myUid)
|
||||
{
|
||||
public async Task<DouyinFollowed> GetByUperId(string uperId, string myUid)
|
||||
{
|
||||
return await _followRepository.GetBySecUId(uperId, myUid);
|
||||
}
|
||||
|
||||
@@ -143,7 +142,7 @@ namespace dy.net.service
|
||||
{
|
||||
return await _followRepository.DeleteByIdAsync(dto.Id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 打开或关闭同步
|
||||
|
||||
@@ -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.response;
|
||||
using dy.net.utils;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Newtonsoft.Json;
|
||||
using System.Net.Http;
|
||||
using System.Web;
|
||||
|
||||
namespace dy.net.service
|
||||
{
|
||||
@@ -15,7 +12,7 @@ namespace dy.net.service
|
||||
{
|
||||
|
||||
|
||||
readonly IHttpClientFactory _clientFactory;
|
||||
private readonly IHttpClientFactory _clientFactory;
|
||||
public DouyinHttpClientService(IHttpClientFactory clientFactory)
|
||||
{
|
||||
_clientFactory = clientFactory;
|
||||
@@ -110,7 +107,7 @@ namespace dy.net.service
|
||||
if (respose.IsSuccessStatusCode)
|
||||
{
|
||||
var data = await respose.Content.ReadAsStringAsync();
|
||||
var model= JsonConvert.DeserializeObject<DouyinVideoInfoResponse>(data);
|
||||
var model = JsonConvert.DeserializeObject<DouyinVideoInfoResponse>(data);
|
||||
if (model == null)
|
||||
Serilog.Log.Error($"SyncCollectVideos fail: {data}");
|
||||
return model;
|
||||
@@ -169,7 +166,7 @@ namespace dy.net.service
|
||||
}
|
||||
else
|
||||
{
|
||||
Serilog.Log.Error("SyncCollectFolderList ,{StatusCode}", respose.StatusCode);
|
||||
Serilog.Log.Error("SyncCollectFolderList ,{StatusCode}", respose.StatusCode);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -231,7 +228,7 @@ namespace dy.net.service
|
||||
if (respose.IsSuccessStatusCode)
|
||||
{
|
||||
var data = await respose.Content.ReadAsStringAsync();
|
||||
var model= JsonConvert.DeserializeObject<DouyinVideoInfoResponse>(data);
|
||||
var model = JsonConvert.DeserializeObject<DouyinVideoInfoResponse>(data);
|
||||
if (model == null)
|
||||
Serilog.Log.Error($"SyncCollectVideosByCollectId fail: {data}");
|
||||
return model;
|
||||
@@ -293,7 +290,7 @@ namespace dy.net.service
|
||||
Serilog.Log.Error($"SyncMixList : {respose.StatusCode}");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -352,7 +349,7 @@ namespace dy.net.service
|
||||
if (respose.IsSuccessStatusCode)
|
||||
{
|
||||
var data = await respose.Content.ReadAsStringAsync();
|
||||
var model = JsonConvert.DeserializeObject<DouyinVideoInfoResponse>(data);
|
||||
var model = JsonConvert.DeserializeObject<DouyinVideoInfoResponse>(data);
|
||||
if (model == null)
|
||||
Serilog.Log.Error($"SyncMixViedosByMixId fail: {data}");
|
||||
return model;
|
||||
@@ -413,7 +410,7 @@ namespace dy.net.service
|
||||
Serilog.Log.Error($"SyncShortList fail: {respose.StatusCode}");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -472,7 +469,7 @@ namespace dy.net.service
|
||||
if (respose.IsSuccessStatusCode)
|
||||
{
|
||||
var data = await respose.Content.ReadAsStringAsync();
|
||||
var model= JsonConvert.DeserializeObject<DouyinVideoInfoResponse>(data);
|
||||
var model = JsonConvert.DeserializeObject<DouyinVideoInfoResponse>(data);
|
||||
if (model == null)
|
||||
Serilog.Log.Error($"SyncSeriesViedosByMSeriesId fail: {data}");
|
||||
return model;
|
||||
@@ -544,7 +541,7 @@ namespace dy.net.service
|
||||
if (respose.IsSuccessStatusCode)
|
||||
{
|
||||
var data = await respose.Content.ReadAsStringAsync();
|
||||
var model= JsonConvert.DeserializeObject<DouyinVideoInfoResponse>(data);
|
||||
var model = JsonConvert.DeserializeObject<DouyinVideoInfoResponse>(data);
|
||||
if (model == null)
|
||||
Serilog.Log.Error($"SyncFavoriteVideos fail: {data}");
|
||||
return model;
|
||||
@@ -616,7 +613,7 @@ namespace dy.net.service
|
||||
if (respose.IsSuccessStatusCode)
|
||||
{
|
||||
var data = await respose.Content.ReadAsStringAsync();
|
||||
var model= JsonConvert.DeserializeObject<DouyinVideoInfoResponse>(data);
|
||||
var model = JsonConvert.DeserializeObject<DouyinVideoInfoResponse>(data);
|
||||
if (model == null)
|
||||
Serilog.Log.Error($"SyncUpderPostVideos fail: {data}");
|
||||
return model;
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using ClockSnowFlake;
|
||||
using dy.net.extension;
|
||||
using dy.net.extension;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.utils;
|
||||
using Serilog;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace dy.net.service
|
||||
@@ -37,7 +35,7 @@ namespace dy.net.service
|
||||
/// <param name="savePath"></param>
|
||||
/// <param name="ck"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<(string mp4Path,string mp3Path)> MergeMultipleVideosAsync(
|
||||
public async Task<(string mp4Path, string mp3Path)> MergeMultipleVideosAsync(
|
||||
List<DouyinDynamicVideoDto> videoFilePaths,
|
||||
string audioPath,
|
||||
string savePath,
|
||||
@@ -51,11 +49,11 @@ namespace dy.net.service
|
||||
if (SuccessPaths != null && SuccessPaths.Length > 0)
|
||||
{
|
||||
mergMusicPath = SuccessPaths[0];
|
||||
mp3Path= SuccessPaths[0];
|
||||
mp3Path = SuccessPaths[0];
|
||||
}
|
||||
}
|
||||
var ffmpeg = new FFmpegHelper();
|
||||
var mp4Path= await ffmpeg.MergeMultipleVideosAsync(videoFilePaths, mergMusicPath, savePath);
|
||||
var mp4Path = await ffmpeg.MergeMultipleVideosAsync(videoFilePaths, mergMusicPath, savePath);
|
||||
return (mp4Path, mp3Path);
|
||||
}
|
||||
|
||||
@@ -78,7 +76,7 @@ namespace dy.net.service
|
||||
Path.GetFileNameWithoutExtension(filePath) != "silent_10")
|
||||
.ToList();
|
||||
|
||||
if (customMusics != null && customMusics.Any())
|
||||
if (customMusics != null && customMusics.Any())
|
||||
{
|
||||
if (customMusics.Count() == 1)
|
||||
return customMusics.FirstOrDefault();
|
||||
@@ -136,12 +134,12 @@ namespace dy.net.service
|
||||
// 保存下载的图片(如果需要)
|
||||
if (downImage)
|
||||
{
|
||||
await SaveDownloadedFilesAsync(rawImages, fileNamefolder, "jpg",Path.GetFileNameWithoutExtension(outputVideoPath));
|
||||
await SaveDownloadedFilesAsync(rawImages, fileNamefolder, "jpg", Path.GetFileNameWithoutExtension(outputVideoPath));
|
||||
}
|
||||
|
||||
// 2. 下载音频
|
||||
string[] rawAudios = Array.Empty<string>();
|
||||
if (mergeImg2Viedo && request.AudioUrls != null && request.AudioUrls.Count > 0)
|
||||
if (mergeImg2Viedo && request.AudioUrls != null && request.AudioUrls.Count > 0)
|
||||
{
|
||||
var (audios, audioError) = await DownloadMediaAsync(
|
||||
request.AudioUrls, Path.Combine(tempDir, "raw-audios"), "audio_", "mp3", cookie);
|
||||
@@ -154,7 +152,7 @@ namespace dy.net.service
|
||||
// 保存下载的音频(如果需要)
|
||||
if (downMp3)
|
||||
{
|
||||
var ext= Path.GetExtension(rawAudios[0]);
|
||||
var ext = Path.GetExtension(rawAudios[0]);
|
||||
await SaveDownloadedFilesAsync(rawAudios, fileNamefolder, ext, Path.GetFileNameWithoutExtension(outputVideoPath));
|
||||
}
|
||||
}
|
||||
@@ -162,7 +160,7 @@ namespace dy.net.service
|
||||
// 不合成视频,直接返回成功
|
||||
if (!mergeImg2Viedo)
|
||||
{
|
||||
Log.Debug($"根据系统配置设置不下载图文视频-[{outputVideoPath}],{(downImage?"下载图片":"不下载图片")},{(downMp3?"下载音频":"不下载音频")}");
|
||||
Log.Debug($"根据系统配置设置不下载图文视频-[{outputVideoPath}],{(downImage ? "下载图片" : "不下载图片")},{(downMp3 ? "下载音频" : "不下载音频")}");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -237,7 +235,7 @@ namespace dy.net.service
|
||||
/// <summary>
|
||||
/// 保存下载的文件(图片/音频)到目标目录
|
||||
/// </summary>
|
||||
private static async Task SaveDownloadedFilesAsync(string[] sourcePaths, string targetFolder, string defaultExt,string videoFileName)
|
||||
private static async Task SaveDownloadedFilesAsync(string[] sourcePaths, string targetFolder, string defaultExt, string videoFileName)
|
||||
{
|
||||
if (sourcePaths == null || sourcePaths.Length == 0) return;
|
||||
Directory.CreateDirectory(targetFolder); // 确保目标目录存在
|
||||
@@ -329,7 +327,7 @@ namespace dy.net.service
|
||||
|
||||
/// <summary>通用媒体下载方法</summary>
|
||||
private async Task<(string[] SuccessPaths, string ErrorMsg)> DownloadMediaAsync(
|
||||
List<string> urls, string saveDir, string prefix, string ext,string cookie)
|
||||
List<string> urls, string saveDir, string prefix, string ext, string cookie)
|
||||
{
|
||||
var successPaths = new List<string>();
|
||||
for (var i = 0; i < urls.Count; i++)
|
||||
@@ -341,8 +339,8 @@ namespace dy.net.service
|
||||
|
||||
try
|
||||
{
|
||||
var (Success, ActualSavePath) = await douyinHttpClientService.DownloadAsync(url, savePath, cookie);
|
||||
if(Success)
|
||||
var (Success, ActualSavePath) = await douyinHttpClientService.DownloadAsync(url, savePath, cookie);
|
||||
if (Success)
|
||||
{
|
||||
successPaths.Add(ActualSavePath);
|
||||
}
|
||||
@@ -350,7 +348,7 @@ namespace dy.net.service
|
||||
{
|
||||
Serilog.Log.Error($"下载失败:{url} → {savePath}");
|
||||
}
|
||||
//Console.WriteLine($"下载成功:{url} → {savePath}");
|
||||
//Console.WriteLine($"下载成功:{url} → {savePath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -3,10 +3,6 @@ using dy.net.model.dto;
|
||||
using dy.net.utils;
|
||||
using Quartz;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace dy.net.service
|
||||
{
|
||||
@@ -76,8 +72,8 @@ namespace dy.net.service
|
||||
VideoTypeEnum.dy_series.GetDesc(),
|
||||
new JobConfig(
|
||||
typeof(DouyinSeriesSyncJob),
|
||||
"dy.job.key.series",
|
||||
"dy.trigger.key.series",
|
||||
"dy.job.key.series",
|
||||
"dy.trigger.key.series",
|
||||
"抖音收藏夹短剧同步任务")
|
||||
},
|
||||
{
|
||||
@@ -99,7 +95,6 @@ namespace dy.net.service
|
||||
/// 启动所有抖音相关定时任务(所有任务独立执行)
|
||||
/// </summary>
|
||||
/// <param name="expression">Cron表达式或间隔分钟数(所有任务使用相同的执行频率)</param>
|
||||
/// <param name="isRestart"></param>
|
||||
/// <returns>是否启动成功</returns>
|
||||
public async Task<bool> InitOrReStartAllJobs(string expression)
|
||||
{
|
||||
@@ -120,6 +115,8 @@ namespace dy.net.service
|
||||
// 执行任务启动逻辑
|
||||
foreach (var jobKey in JobConfigs.Keys)
|
||||
{
|
||||
if (jobKey == "follow_user_once")
|
||||
continue;
|
||||
if (jobKey == "follow_user") expression = "60";
|
||||
var startSuccess = await StartJobAsync(jobKey, expression);
|
||||
if (startSuccess)
|
||||
@@ -131,7 +128,7 @@ namespace dy.net.service
|
||||
Log.Error($"启动任务失败:{jobKey}");
|
||||
}
|
||||
}
|
||||
Log.Information($"共启动 {JobConfigs.Count} 个定时任务");
|
||||
Log.Information($"共启动 {JobConfigs.Count - 1} 个定时任务");
|
||||
|
||||
|
||||
//await StartJobAsync(VideoTypeEnum.dy_custom_collect.GetDesc(), expression);
|
||||
|
||||
@@ -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);
|
||||
// }
|
||||
// }
|
||||
|
||||
//}
|
||||
//}
|
||||
@@ -3,13 +3,8 @@ using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using dy.net.repository;
|
||||
using dy.net.utils;
|
||||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
using SqlSugar;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace dy.net.service
|
||||
{
|
||||
@@ -382,7 +377,7 @@ namespace dy.net.service
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<VideoChartItemDto>> GetChartData(int day=7)
|
||||
public async Task<List<VideoChartItemDto>> GetChartData(int day = 7)
|
||||
{
|
||||
|
||||
var date = DateTime.Now.AddDays(-day);
|
||||
@@ -517,7 +512,7 @@ namespace dy.net.service
|
||||
public async Task<bool> HandOldFolderVideos()
|
||||
{
|
||||
// 1. 查询目标数据
|
||||
var list = await _dyCollectVideoRepository.GetListAsync(x=>x.ViedoType == VideoTypeEnum.dy_favorite || x.ViedoType == VideoTypeEnum.dy_collects );
|
||||
var list = await _dyCollectVideoRepository.GetListAsync(x => x.ViedoType == VideoTypeEnum.dy_favorite || x.ViedoType == VideoTypeEnum.dy_collects);
|
||||
// 缓存已处理的「Tag1+下一级文件夹」组合(避免重复移动)
|
||||
var processedFolderPairs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user