quartz数据库持久化

This commit is contained in:
jianzhichu
2026-01-26 18:29:19 +08:00
parent f13d73e023
commit 85986cdaa3
16 changed files with 514 additions and 131 deletions
+2 -24
View File
@@ -114,6 +114,7 @@ namespace dy.net.Controllers
PageRequestDto dto)
{
var (list, totalCount) = await dyCookieService.GetPagedAsync(dto.PageIndex, dto.PageSize);
return ApiResult.Success(new
{
data = list,
@@ -148,29 +149,6 @@ namespace dy.net.Controllers
}
/// <summary>
/// 新增用户Cookie
/// </summary>
[HttpPost("add")]
public async Task<IActionResult> AddAsync([FromBody] DouyinCookie dyUserCookies)
{
var checkCk = await httpClientService.CheckCookie(dyUserCookies);
if (!checkCk)
{
return ApiResult.Fail("Cookie无效,请按照文档提示重新获取有效Cookie,不要使用插件获取cookie");
}
var result = await dyCookieService.Add(dyUserCookies);
if (result)
{
ReStartJob();
return ApiResult.Success();
}
return ApiResult.Fail("添加失败");
}
/// <summary>
/// 非docker初始化
/// </summary>
@@ -244,7 +222,7 @@ namespace dy.net.Controllers
/// 更新用户Cookie
/// </summary>
[HttpPost("update")]
public async Task<IActionResult> UpdateAsync([FromBody] DouyinCookie dyUserCookies)
public async Task<IActionResult> AddOrUpdateAsync([FromBody] DouyinCookie dyUserCookies)
{
var checkCk = await httpClientService.CheckCookie(dyUserCookies);
if (!checkCk)
+9 -9
View File
@@ -10,7 +10,7 @@ namespace dy.net
public class Program
{
// 常量定义
private static string DefaultListenUrl = "http://*:10101";
private static readonly string DefaultListenUrl = "http://*:10101";
private const string SpaRootPath = "app/dist";
private const string SpaSourcePath = "app/";
private const string SwaggerDocTitle = "dy.net WebApi Docs";
@@ -18,7 +18,7 @@ namespace dy.net
/// <summary>
///
/// </summary>
public static void Main(string[] args)
public static async Task Main(string[] args)
{
// 初始化编码提供器
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
@@ -35,10 +35,10 @@ namespace dy.net
ConfigureMiddleware(app, builder.Environment);
Log.Debug($"dy.sync app is started successfully on {DefaultListenUrl}");
// 初始化应用服务
InitApplicationServices(app, isDevelopment);
await InitApplicationServices(app, isDevelopment);
Console.WriteLine();
app.Run();
await app.RunAsync();
}
/// <summary>
@@ -136,7 +136,7 @@ namespace dy.net
services.AddSqlsugar(dbPath);
// 定时任务
services.AddQuartzService();
services.AddQuartzService(dbPath);
// 仓储和服务注册
services.AddServicesFromNamespace("dy.net.repository")
@@ -201,7 +201,7 @@ namespace dy.net
/// <summary>
/// 初始化应用服务数据
/// </summary>
private static void InitApplicationServices(WebApplication app, bool isDevelopment)
private static async Task InitApplicationServices(WebApplication app, bool isDevelopment)
{
using var scope = app.Services.CreateScope();
var services = scope.ServiceProvider;
@@ -230,14 +230,14 @@ namespace dy.net
//Serilog.Log.Debug("isRestart1=" + config.IsFirstRunning);
if (!isDevelopment)
//if (!isDevelopment)
{
var cookie = cookieService.GetOpendCookies();
var cookie = await cookieService.GetOpendCookies();
if (cookie != null && cookie.Any())
{
// 启动定时任务
var quartzJobService = services.GetRequiredService<DouyinQuartzJobService>();
quartzJobService.InitOrReStartAllJobs(config?.Cron <= 0 ? "30" : config.Cron.ToString());
await quartzJobService.InitOrReStartAllJobs(config?.Cron <= 0 ? "30" : config.Cron.ToString());
}
}
}
+2
View File
@@ -184,6 +184,8 @@ function submit() {
message.success('修改成功,同步任务将在5-10秒按新配置运行...');
reset();
GetRecords();
}else{
message.success('修改失败,'+res.message);
}
});
})
+4 -3
View File
@@ -59,11 +59,12 @@
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.16" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.10" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.0" />
<PackageReference Include="Quartz" Version="3.8.0" />
<PackageReference Include="Quartz" Version="3.15.1" />
<PackageReference Include="Quartz.AspNetCore" Version="3.8.0" />
<PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.8.0" />
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.8.0" />
<PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.15.1" />
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.15.1" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.128" />
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.119" />
<!--<PackageReference Include="SqlSugarCoreNoDrive" Version="5.1.4.124" />-->
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.0.1" />
<!--<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.6.3" />
+41 -12
View File
@@ -1,15 +1,17 @@
using dy.net.service;
using dy.net.job;
using dy.net.service;
using dy.net.utils;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.IdentityModel.Tokens;
//using Microsoft.OpenApi.Models;
using Quartz;
using Quartz.Impl;
using Quartz.Spi;
using Serilog;
using Serilog.Events;
using Serilog.Filters;
using Serilog.Formatting.Compact;
//using Serilog.Formatting.Compact;
using SqlSugar;
//using Swashbuckle.AspNetCore.SwaggerGen;
@@ -57,7 +59,7 @@ namespace dy.net.extension
// return connectionString;
//}
private static string CreateSqliteDBConn(string dbPath = "")
static string CreateSqliteDBConn(string dbPath = "")
{
string fileFloder = Path.Combine(Environment.CurrentDirectory, "db");
if (!string.IsNullOrEmpty(dbPath))
@@ -90,7 +92,6 @@ namespace dy.net.extension
}
return conn;
}
@@ -173,16 +174,44 @@ namespace dy.net.extension
///
/// </summary>
/// <param name="services"></param>
public static void AddQuartzService(this IServiceCollection services)
public static void AddQuartzService(this IServiceCollection services,string dbPath)
{
//services.AddTransient<DouyinCollectSyncJob>();
//services.AddTransient<DouyinFavoritSyncJob>();
//services.AddTransient<DouyinUperPostSyncJob>();
// 注册Quartz服务
services.AddQuartz();
// 1. 注册所有 Job 到 DI 容器,推荐使用 Scoped(最符合 Job 执行特性)
services.AddScoped<DouyinCollectSyncJob>();
services.AddScoped<DouyinFavoritSyncJob>();
services.AddScoped<DouyinFollowedSyncJob>();
services.AddScoped<DouyinFollowsAndCollnectsSyncJob>();
services.AddScoped<DouyinCollectCustomSyncJob>();
services.AddScoped<DouyinMixSyncJob>();
services.AddScoped<DouyinSeriesSyncJob>();
services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);
// 3. 配置 Quartz
services.AddQuartz(q =>
{
q.SchedulerId = "DouyinQuartzScheduler";
q.SchedulerName = "DouyinSyncScheduler";
q.InterruptJobsOnShutdownWithWait = false;
q.UseDedicatedThreadPool(5); // 建议增加线程数,1个太少容易阻塞
q.MisfireThreshold = TimeSpan.FromMinutes(2);
q.UsePersistentStore(s =>
{
s.UseSQLite(config =>
{
config.ConnectionString = CreateSqliteDBConn(dbPath);
config.TablePrefix = "QRTZ_";
});
s.UseProperties = false;
s.UseBinarySerializer();
});
});
services.AddQuartzHostedService(q =>
{
q.WaitForJobsToComplete = true;
q.AwaitApplicationStarted = true;
});
services.AddTransient<DouyinQuartzJobService>();
}
@@ -201,7 +230,7 @@ namespace dy.net.extension
// 禁用代理自动检测(减少不必要的延迟)
UseProxy = false,
// 连接超时(建立连接的超时时间)
ConnectTimeout = TimeSpan.FromSeconds(120),
ConnectTimeout = Timeout.InfiniteTimeSpan,// TimeSpan.FromSeconds(120),
// 忽略HTTPS证书验证
SslOptions = new SslClientAuthenticationOptions
{
+32 -24
View File
@@ -213,7 +213,8 @@ namespace dy.net.job
/// <returns>创建的视频保存文件夹路径</returns>
protected virtual string CreateSaveFolder(DouyinCookie cookie, Aweme item, AppConfig config, DouyinFollowed followed, DouyinCollectCate cate)
{
var folder = Path.Combine(cookie.SavePath, DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId, true));
var subFolder = DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId, true);
var folder = Path.Combine(cookie.SavePath, subFolder);
if (!Directory.Exists(folder)) Directory.CreateDirectory(folder);
return folder;
@@ -289,7 +290,7 @@ namespace dy.net.job
/// <returns>封面图片的文件名</returns>
protected virtual string GetNfoFileName(DouyinCookie cookie, Aweme item, AppConfig config, string fileName, DouyinCollectCate cate)
{
return fileName;
return $"{item.AwemeId}_{fileName}";
}
/// <summary>
@@ -314,7 +315,6 @@ namespace dy.net.job
var follows = await douyinFollowService.GetSyncFollows(cookie.MyUserId);
if (follows != null && follows.Any())
{
//int totalSyncCount = 0;
foreach (var followed in follows)
{
int syncCount = 0; // 本次同步成功的视频数量
@@ -322,12 +322,6 @@ namespace dy.net.job
bool hasMore = true;
(syncCount, cursor, hasMore) = await GetAndSaveViedos(cookie, config, syncCount, cursor, hasMore, followed);
await HandleSyncCompletion(cookie, syncCount, followed);
//totalSyncCount += syncCount;
//if (totalSyncCount >= config.BatchCount)
//{
// Log.Debug($"[{VideoType.GetVideoTypeDesc()}][{cookie.UserName}]:本次同步数量{totalSyncCount},已达配置上限,等下次任务继续同步");
// break;
//}
}
}
}
@@ -336,7 +330,7 @@ namespace dy.net.job
case VideoTypeEnum.dy_collects:
if (VideoType == VideoTypeEnum.dy_collects && cookie.UseCollectFolder)
{
Serilog.Log.Debug($"[{VideoType.GetDesc()}]-已开启自定义收藏夹同步...break;");
Log.Debug($"[{VideoType.GetDesc()}]-已开启自定义收藏夹同步...break;");
break;
}
else
@@ -350,10 +344,37 @@ namespace dy.net.job
break;
case VideoTypeEnum.dy_mix:
if (cookie.DownMix)
await SyncCustomListVideos(cookie, config);
break;
case VideoTypeEnum.dy_series:
if (cookie.DownSeries)
await SyncCustomListVideos(cookie, config);
break;
case VideoTypeEnum.dy_custom_collect:
{
if (cookie.UseCollectFolder)
await SyncCustomListVideos(cookie, config);
break;
case VideoTypeEnum.ImageVideo:
default:
break;
}
}
catch (Exception ex)
{
Log.Error(ex, $"[{VideoType.GetDesc()}][{cookie.UserName}]同步出错!!!,{ex.StackTrace}");
}
}
/// <summary>
/// 同步下载自定义收藏夹、合集、短剧
/// </summary>
/// <param name="cookie"></param>
/// <param name="config"></param>
/// <returns></returns>
private async Task SyncCustomListVideos(DouyinCookie cookie, AppConfig config)
{
var cates = await douyinCollectCateService.GetSyncCates(cookie.Id, VideoType);
if (cates != null && cates.Any())
{
@@ -372,19 +393,6 @@ namespace dy.net.job
Serilog.Log.Debug($"[{VideoType.GetDesc()}]没有查询到已开启的对象");
}
}
break;
case VideoTypeEnum.ImageVideo:
default:
break;
}
}
catch (Exception ex)
{
Log.Error(ex, $"[{VideoType.GetDesc()}][{cookie.UserName}]同步出错!!!,{ex.StackTrace}");
}
}
private async Task<(int syncCount, string cursor, bool hasMore)> GetAndSaveViedos(DouyinCookie cookie, AppConfig config, int syncCount, string cursor, bool hasMore, DouyinFollowed followed = null, DouyinCollectCate cate = null)
{
+3 -24
View File
@@ -53,15 +53,15 @@ namespace dy.net.job
: DouyinFileNameHelper.SanitizeLinuxFileName(rawAuthorName, "", true);
// 2. 确定最终文件夹路径(遵循原有优先级:followed.SavePath > authorName > 基础路径)
var targetFolderName = !string.IsNullOrWhiteSpace(followed?.SavePath) ? followed.SavePath : authorName;
var folder = Path.Combine(cookie.UpSavePath, targetFolderName);
var rootFolder = Path.Combine(cookie.UpSavePath, targetFolderName);
if (!Directory.Exists(folder)) Directory.CreateDirectory(folder);
if (!Directory.Exists(rootFolder)) Directory.CreateDirectory(rootFolder);
#endregion
var sampleName = DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId, true);
var (existingName, _) = douyinVideoService.GetUperLastViedoFileName(item.Author.Uid, sampleName);
var fileNameFolder = string.IsNullOrWhiteSpace(existingName) ? sampleName : existingName;
return Path.Combine(folder, fileNameFolder);
return Path.Combine(rootFolder, fileNameFolder);
}
/// <summary>
/// 关注的视频,生成文件名称
@@ -134,27 +134,6 @@ namespace dy.net.job
}
/// <summary>
///
/// </summary>
/// <param name="cookie"></param>
/// <param name="item"></param>
/// <param name="config"></param>
/// <param name="imageType"></param>
/// <param name="cate"></param>
/// <returns></returns>
protected override string GetNfoFileName(DouyinCookie cookie, Aweme item, AppConfig config, string imageType, DouyinCollectCate cate)
{
return base.GetNfoFileName(cookie, item, config, imageType, cate);
}
//protected override async Task HandleSyncCompletion(DouyinCookie cookie, int syncCount, DouyinFollowed followed, DouyinCollectCate cate)
//{
// cookie.UperSyncd = 1;
// await douyinCookieService.UpdateAsync(cookie);
// await base.HandleSyncCompletion(cookie, syncCount, followed, cate);
//}
}
}
+2 -1
View File
@@ -53,6 +53,8 @@ namespace dy.net.job
foreach (var ck in cookies)
{
//同步关注列表
await SyncFollowListAsync(ck, conf);
if (ck.UseCollectFolder)
{
@@ -113,7 +115,6 @@ namespace dy.net.job
LOG_TAG_SERIES);
}
await SyncFollowListAsync(ck, conf);
Log.Debug($"[{ck.UserName}]所有[基础数据(list)]同步完成,包括 [收藏列表、关注列表、合集列表、短剧列表] ");
}
+378
View File
@@ -0,0 +1,378 @@
using SqlSugar;
namespace dy.net.model.entity
{
#region QRTZ_JOB_DETAILS
[SugarTable("QRTZ_JOB_DETAILS")]
public class QrtzJobDetails
{
[SugarColumn(ColumnName = "SCHED_NAME", IsPrimaryKey = true, Length = 120, IsNullable = true)]
public string SchedName { get; set; }
[SugarColumn(ColumnName = "JOB_NAME", IsPrimaryKey = true, Length = 150, IsNullable = true)]
public string JobName { get; set; }
[SugarColumn(ColumnName = "JOB_GROUP", IsPrimaryKey = true, Length = 150, IsNullable = true)]
public string JobGroup { get; set; }
[SugarColumn(ColumnName = "DESCRIPTION", Length = 250, IsNullable = true)]
public string? Description { get; set; }
[SugarColumn(ColumnName = "JOB_CLASS_NAME", Length = 250, IsNullable = true)]
public string JobClassName { get; set; }
[SugarColumn(ColumnName = "IS_DURABLE", IsNullable = true)]
public bool IsDurable { get; set; }
[SugarColumn(ColumnName = "IS_NONCONCURRENT", IsNullable = true)]
public bool IsNonConcurrent { get; set; }
[SugarColumn(ColumnName = "IS_UPDATE_DATA", IsNullable = true)]
public bool IsUpdateData { get; set; }
[SugarColumn(ColumnName = "REQUESTS_RECOVERY", IsNullable = true)]
public bool RequestsRecovery { get; set; }
[SugarColumn(ColumnName = "JOB_DATA", IsNullable = true, ColumnDataType = "BLOB")]
public byte[]? JobData { get; set; }
// 导航属性:关联触发器(一对多)
[Navigate(NavigateType.OneToMany,
nameof(QrtzTriggers.SchedName),
nameof(QrtzTriggers.JobName),
nameof(QrtzTriggers.JobGroup))]
public List<QrtzTriggers> Triggers { get; set; } = new List<QrtzTriggers>();
}
#endregion
#region QRTZ_TRIGGERS
[SugarTable("QRTZ_TRIGGERS")]
public class QrtzTriggers
{
[SugarColumn(ColumnName = "SCHED_NAME", IsPrimaryKey = true, Length = 120, IsNullable = true)]
public string SchedName { get; set; }
[SugarColumn(ColumnName = "TRIGGER_NAME", IsPrimaryKey = true, Length = 150, IsNullable = true)]
public string TriggerName { get; set; }
[SugarColumn(ColumnName = "TRIGGER_GROUP", IsPrimaryKey = true, Length = 150, IsNullable = true)]
public string TriggerGroup { get; set; }
[SugarColumn(ColumnName = "JOB_NAME", Length = 150, IsNullable = true)]
public string JobName { get; set; }
[SugarColumn(ColumnName = "JOB_GROUP", Length = 150, IsNullable = true)]
public string JobGroup { get; set; }
[SugarColumn(ColumnName = "DESCRIPTION", Length = 250, IsNullable = true)]
public string? Description { get; set; }
[SugarColumn(ColumnName = "NEXT_FIRE_TIME", IsNullable = true)]
public long? NextFireTime { get; set; }
[SugarColumn(ColumnName = "PREV_FIRE_TIME", IsNullable = true)]
public long? PrevFireTime { get; set; }
[SugarColumn(ColumnName = "PRIORITY", IsNullable = true)]
public int? Priority { get; set; }
[SugarColumn(ColumnName = "TRIGGER_STATE", Length = 16, IsNullable = true)]
public string TriggerState { get; set; }
[SugarColumn(ColumnName = "TRIGGER_TYPE", Length = 8, IsNullable = true)]
public string TriggerType { get; set; }
[SugarColumn(ColumnName = "START_TIME", IsNullable = true)]
public long StartTime { get; set; }
[SugarColumn(ColumnName = "END_TIME", IsNullable = true)]
public long? EndTime { get; set; }
[SugarColumn(ColumnName = "CALENDAR_NAME", Length = 200, IsNullable = true)]
public string? CalendarName { get; set; }
[SugarColumn(ColumnName = "MISFIRE_INSTR", IsNullable = true)]
public int? MisfireInstr { get; set; }
[SugarColumn(ColumnName = "JOB_DATA", IsNullable = true, ColumnDataType = "BLOB")]
public byte[]? JobData { get; set; }
// 导航属性:关联任务详情(多对一)
[Navigate(NavigateType.ManyToOne,
nameof(SchedName),
nameof(JobName),
nameof(JobGroup))]
public QrtzJobDetails? JobDetails { get; set; }
// 导航属性:关联各类触发器(一对一)
[Navigate(NavigateType.OneToOne,
nameof(SchedName),
nameof(TriggerName),
nameof(TriggerGroup))]
public QrtzSimpleTriggers? SimpleTrigger { get; set; }
[Navigate(NavigateType.OneToOne,
nameof(SchedName),
nameof(TriggerName),
nameof(TriggerGroup))]
public QrtzSimpropTriggers? SimpropTrigger { get; set; }
[Navigate(NavigateType.OneToOne,
nameof(SchedName),
nameof(TriggerName),
nameof(TriggerGroup))]
public QrtzCronTriggers? CronTrigger { get; set; }
[Navigate(NavigateType.OneToOne,
nameof(SchedName),
nameof(TriggerName),
nameof(TriggerGroup))]
public QrtzBlobTriggers? BlobTrigger { get; set; }
}
#endregion
#region QRTZ_SIMPLE_TRIGGERS
[SugarTable("QRTZ_SIMPLE_TRIGGERS")]
public class QrtzSimpleTriggers
{
[SugarColumn(ColumnName = "SCHED_NAME", IsPrimaryKey = true, Length = 120, IsNullable = true)]
public string SchedName { get; set; }
[SugarColumn(ColumnName = "TRIGGER_NAME", IsPrimaryKey = true, Length = 150, IsNullable = true)]
public string TriggerName { get; set; }
[SugarColumn(ColumnName = "TRIGGER_GROUP", IsPrimaryKey = true, Length = 150, IsNullable = true)]
public string TriggerGroup { get; set; }
[SugarColumn(ColumnName = "REPEAT_COUNT", IsNullable = true)]
public long RepeatCount { get; set; }
[SugarColumn(ColumnName = "REPEAT_INTERVAL", IsNullable = true)]
public long RepeatInterval { get; set; }
[SugarColumn(ColumnName = "TIMES_TRIGGERED", IsNullable = true)]
public long TimesTriggered { get; set; }
// 导航属性:关联触发器(多对一)
[Navigate(NavigateType.ManyToOne,
nameof(SchedName),
nameof(TriggerName),
nameof(TriggerGroup))]
public QrtzTriggers? Trigger { get; set; }
}
#endregion
#region QRTZ_SIMPROP_TRIGGERS
[SugarTable("QRTZ_SIMPROP_TRIGGERS")]
public class QrtzSimpropTriggers
{
[SugarColumn(ColumnName = "SCHED_NAME", IsPrimaryKey = true, Length = 120, IsNullable = true)]
public string SchedName { get; set; }
[SugarColumn(ColumnName = "TRIGGER_NAME", IsPrimaryKey = true, Length = 150, IsNullable = true)]
public string TriggerName { get; set; }
[SugarColumn(ColumnName = "TRIGGER_GROUP", IsPrimaryKey = true, Length = 150, IsNullable = true)]
public string TriggerGroup { get; set; }
[SugarColumn(ColumnName = "STR_PROP_1", Length = 512, IsNullable = true)]
public string? StrProp1 { get; set; }
[SugarColumn(ColumnName = "STR_PROP_2", Length = 512, IsNullable = true)]
public string? StrProp2 { get; set; }
[SugarColumn(ColumnName = "STR_PROP_3", Length = 512, IsNullable = true)]
public string? StrProp3 { get; set; }
[SugarColumn(ColumnName = "INT_PROP_1", IsNullable = true)]
public int? IntProp1 { get; set; }
[SugarColumn(ColumnName = "INT_PROP_2", IsNullable = true)]
public int? IntProp2 { get; set; }
[SugarColumn(ColumnName = "LONG_PROP_1", IsNullable = true)]
public long? LongProp1 { get; set; }
[SugarColumn(ColumnName = "LONG_PROP_2", IsNullable = true)]
public long? LongProp2 { get; set; }
[SugarColumn(ColumnName = "DEC_PROP_1", IsNullable = true)]
public decimal? DecProp1 { get; set; }
[SugarColumn(ColumnName = "DEC_PROP_2", IsNullable = true)]
public decimal? DecProp2 { get; set; }
[SugarColumn(ColumnName = "BOOL_PROP_1", IsNullable = true)]
public bool? BoolProp1 { get; set; }
[SugarColumn(ColumnName = "BOOL_PROP_2", IsNullable = true)]
public bool? BoolProp2 { get; set; }
[SugarColumn(ColumnName = "TIME_ZONE_ID", Length = 80, IsNullable = true)]
public string? TimeZoneId { get; set; }
// 导航属性:关联触发器(多对一)
[Navigate(NavigateType.ManyToOne,
nameof(SchedName),
nameof(TriggerName),
nameof(TriggerGroup))]
public QrtzTriggers? Trigger { get; set; }
}
#endregion
#region QRTZ_CRON_TRIGGERSCron触发器表
[SugarTable("QRTZ_CRON_TRIGGERS")]
public class QrtzCronTriggers
{
[SugarColumn(ColumnName = "SCHED_NAME", IsPrimaryKey = true, Length = 120, IsNullable = true)]
public string SchedName { get; set; }
[SugarColumn(ColumnName = "TRIGGER_NAME", IsPrimaryKey = true, Length = 150, IsNullable = true)]
public string TriggerName { get; set; }
[SugarColumn(ColumnName = "TRIGGER_GROUP", IsPrimaryKey = true, Length = 150, IsNullable = true)]
public string TriggerGroup { get; set; }
[SugarColumn(ColumnName = "CRON_EXPRESSION", Length = 250, IsNullable = true)]
public string CronExpression { get; set; }
[SugarColumn(ColumnName = "TIME_ZONE_ID", Length = 80, IsNullable = true)]
public string? TimeZoneId { get; set; }
// 导航属性:关联触发器(多对一)
[Navigate(NavigateType.ManyToOne,
nameof(SchedName),
nameof(TriggerName),
nameof(TriggerGroup))]
public QrtzTriggers? Trigger { get; set; }
}
#endregion
#region QRTZ_BLOB_TRIGGERSBlob触发器表
[SugarTable("QRTZ_BLOB_TRIGGERS")]
public class QrtzBlobTriggers
{
[SugarColumn(ColumnName = "SCHED_NAME", IsPrimaryKey = true, Length = 120, IsNullable = true)]
public string SchedName { get; set; }
[SugarColumn(ColumnName = "TRIGGER_NAME", IsPrimaryKey = true, Length = 150, IsNullable = true)]
public string TriggerName { get; set; }
[SugarColumn(ColumnName = "TRIGGER_GROUP", IsPrimaryKey = true, Length = 150, IsNullable = true)]
public string TriggerGroup { get; set; }
[SugarColumn(ColumnName = "BLOB_DATA", IsNullable = true, ColumnDataType = "BLOB")]
public byte[]? BlobData { get; set; }
// 导航属性:关联触发器(多对一)
[Navigate(NavigateType.ManyToOne,
nameof(SchedName),
nameof(TriggerName),
nameof(TriggerGroup))]
public QrtzTriggers? Trigger { get; set; }
}
#endregion
#region QRTZ_CALENDARS
[SugarTable("QRTZ_CALENDARS")]
public class QrtzCalendars
{
[SugarColumn(ColumnName = "SCHED_NAME", IsPrimaryKey = true, Length = 120, IsNullable = true)]
public string SchedName { get; set; }
[SugarColumn(ColumnName = "CALENDAR_NAME", IsPrimaryKey = true, Length = 200, IsNullable = true)]
public string CalendarName { get; set; }
[SugarColumn(ColumnName = "CALENDAR", IsNullable = true, ColumnDataType = "BLOB")]
public byte[] Calendar { get; set; }
}
#endregion
#region QRTZ_PAUSED_TRIGGER_GRPS
[SugarTable("QRTZ_PAUSED_TRIGGER_GRPS")]
public class QrtzPausedTriggerGrps
{
[SugarColumn(ColumnName = "SCHED_NAME", IsPrimaryKey = true, Length = 120, IsNullable = true)]
public string SchedName { get; set; }
[SugarColumn(ColumnName = "TRIGGER_GROUP", IsPrimaryKey = true, Length = 150, IsNullable = true)]
public string TriggerGroup { get; set; }
}
#endregion
#region QRTZ_FIRED_TRIGGERS
[SugarTable("QRTZ_FIRED_TRIGGERS")]
public class QrtzFiredTriggers
{
[SugarColumn(ColumnName = "SCHED_NAME", IsPrimaryKey = true, Length = 120, IsNullable = true)]
public string SchedName { get; set; }
[SugarColumn(ColumnName = "ENTRY_ID", IsPrimaryKey = true, Length = 140, IsNullable = true)]
public string EntryId { get; set; }
[SugarColumn(ColumnName = "TRIGGER_NAME", Length = 150, IsNullable = true)]
public string TriggerName { get; set; }
[SugarColumn(ColumnName = "TRIGGER_GROUP", Length = 150, IsNullable = true)]
public string TriggerGroup { get; set; }
[SugarColumn(ColumnName = "INSTANCE_NAME", Length = 200, IsNullable = true)]
public string InstanceName { get; set; }
[SugarColumn(ColumnName = "FIRED_TIME", IsNullable = true)]
public long FiredTime { get; set; }
[SugarColumn(ColumnName = "SCHED_TIME", IsNullable = true)]
public long SchedTime { get; set; }
[SugarColumn(ColumnName = "PRIORITY", IsNullable = true)]
public int Priority { get; set; }
[SugarColumn(ColumnName = "STATE", Length = 16, IsNullable = true)]
public string State { get; set; }
[SugarColumn(ColumnName = "JOB_NAME", Length = 150, IsNullable = true)]
public string? JobName { get; set; }
[SugarColumn(ColumnName = "JOB_GROUP", Length = 150, IsNullable = true)]
public string? JobGroup { get; set; }
[SugarColumn(ColumnName = "IS_NONCONCURRENT", IsNullable = true)]
public bool? IsNonConcurrent { get; set; }
[SugarColumn(ColumnName = "REQUESTS_RECOVERY", IsNullable = true)]
public bool? RequestsRecovery { get; set; }
}
#endregion
#region QRTZ_SCHEDULER_STATE
[SugarTable("QRTZ_SCHEDULER_STATE")]
public class QrtzSchedulerState
{
[SugarColumn(ColumnName = "SCHED_NAME", IsPrimaryKey = true, Length = 120, IsNullable = true)]
public string SchedName { get; set; }
[SugarColumn(ColumnName = "INSTANCE_NAME", IsPrimaryKey = true, Length = 200, IsNullable = true)]
public string InstanceName { get; set; }
[SugarColumn(ColumnName = "LAST_CHECKIN_TIME", IsNullable = true)]
public long LastCheckinTime { get; set; }
[SugarColumn(ColumnName = "CHECKIN_INTERVAL", IsNullable = true)]
public long CheckinInterval { get; set; }
}
#endregion
#region QRTZ_LOCKS
[SugarTable("QRTZ_LOCKS")]
public class QrtzLocks
{
[SugarColumn(ColumnName = "SCHED_NAME", IsPrimaryKey = true, Length = 120, IsNullable = true)]
public string SchedName { get; set; }
[SugarColumn(ColumnName = "LOCK_NAME", IsPrimaryKey = true, Length = 40, IsNullable = true)]
public string LockName { get; set; }
}
#endregion
}
+2 -1
View File
@@ -64,7 +64,8 @@ namespace dy.net.model.response
/// <summary>
///
/// </summary>
public int status_code { get; set; }
[JsonProperty("status_code")]
public int StatusCode { get; set; }
/// <summary>
///
/// </summary>
@@ -21,6 +21,12 @@ namespace dy.net.model.response
[JsonProperty("has_more")]
public int HasMore { get; set; }
/// <summary>
///
/// </summary>
[JsonProperty("status_code")]
public int StatusCode { get; set; }
}
public class Aweme
+2 -2
View File
@@ -29,7 +29,7 @@ namespace dy.net.repository
return await query.ToListAsync();
}
public List<DouyinCookie> GetAllCookies(Expression<Func<DouyinCookie, bool>> whereExpression = null)
public async Task<List<DouyinCookie>> GetAllCookies(Expression<Func<DouyinCookie, bool>> whereExpression = null)
{
// 1. 初始化查询:先加固定条件 Status == 1
var query = Db.Queryable<DouyinCookie>()
@@ -43,7 +43,7 @@ namespace dy.net.repository
}
// 3. 执行查询(SqlSugar 自动合并所有 Where 条件)
return query.ToList();
return await query.ToListAsync();
}
+2 -2
View File
@@ -22,9 +22,9 @@ namespace dy.net.service
}
public List<DouyinCookie> GetOpendCookies()
public async Task<List<DouyinCookie>> GetOpendCookies()
{
return _cookieRepository.GetAllCookies();
return await _cookieRepository.GetAllCookies();
}
public Task<List<DouyinCookie>> GetAllAsync()
{
+11 -11
View File
@@ -35,7 +35,7 @@ namespace dy.net.service
string refererValue,
string cookie)
{
string fullUrl = "{requestUrl}";
string fullUrl = $"{requestUrl}";
if (requestParameters != null && requestParameters.Count > 0)
{
fullUrl = QueryHelpers.AddQueryString(
@@ -109,7 +109,7 @@ namespace dy.net.service
var data = await respose.Content.ReadAsStringAsync();
var model = JsonConvert.DeserializeObject<DouyinVideoInfoResponse>(data);
if (model == null)
Serilog.Log.Error($"SyncCollectVideos fail: {data}");
Serilog.Log.Error($"SyncCollectVideos fail, data= {data}");
return model;
}
else
@@ -161,7 +161,7 @@ namespace dy.net.service
var data = await respose.Content.ReadAsStringAsync();
var model = JsonConvert.DeserializeObject<DouyinCollectListResponse>(data);
if (model == null)
Serilog.Log.Error($"SyncCollectFolderList fail: {data}");
Serilog.Log.Error($"SyncCollectFolderList fail, data= {data}");
return model;
}
else
@@ -282,7 +282,7 @@ namespace dy.net.service
var data = await respose.Content.ReadAsStringAsync();
var model = JsonConvert.DeserializeObject<DouyinMixListResponse>(data);
if (model == null)
Serilog.Log.Error($"SyncMixList fail: {data}");
Serilog.Log.Error($"SyncMixList fail, data= {data}");
return model;
}
else
@@ -402,7 +402,7 @@ namespace dy.net.service
var data = await respose.Content.ReadAsStringAsync();
var model = JsonConvert.DeserializeObject<DouyinSeriesListResponse>(data);
if (model == null)
Serilog.Log.Error($"SyncShortList fail: {data}");
Serilog.Log.Error($"SyncShortList fail, data= {data}");
return model;
}
else
@@ -543,7 +543,7 @@ namespace dy.net.service
var data = await respose.Content.ReadAsStringAsync();
var model = JsonConvert.DeserializeObject<DouyinVideoInfoResponse>(data);
if (model == null)
Serilog.Log.Error($"SyncFavoriteVideos fail: {data}");
Serilog.Log.Error($"SyncFavoriteVideos fail, data= {data}");
return model;
}
else
@@ -601,7 +601,7 @@ namespace dy.net.service
var requestUrl = "/aweme/v1/web/aweme/post";
var refererValue = "https://www.douyin.com/user/";
var requestParameters = DouyinRequestParamManager.DouyinUpderPostParams;//修复关注的不下载图文视频
var requestParameters = DouyinRequestParamManager.DouyinUpderPostParams;
{
// 添加动态参数
requestParameters["max_cursor"] = cursor;
@@ -615,12 +615,12 @@ namespace dy.net.service
var data = await respose.Content.ReadAsStringAsync();
var model = JsonConvert.DeserializeObject<DouyinVideoInfoResponse>(data);
if (model == null)
Serilog.Log.Error($"SyncUpderPostVideos fail: {data}");
Serilog.Log.Error($"SyncUpderPostVideos fail, data= {data}");
return model;
}
else
{
Serilog.Log.Error($"SyncUpderPostVideos fail: {respose.StatusCode}");
Serilog.Log.Error($"SyncUpderPostVideos StatusCode fail: {respose.StatusCode}");
return null;
}
}
@@ -740,12 +740,12 @@ namespace dy.net.service
if (!string.IsNullOrWhiteSpace(douyinCookie.SecUserId))
{
var res = await SyncMyFollows("1", "1", douyinCookie.SecUserId, douyinCookie.Cookies, null);
return res != null && res.status_code == 0 && res.Followings != null && res.Followings.Any();
return res != null && res.StatusCode == 0;
}
else
{
var res = await SyncCollectVideos("0", "1", douyinCookie.Cookies);
return res != null && res.AwemeList != null && res.AwemeList.Any();
return res != null && res.StatusCode == 0;
}
}
+7 -7
View File
@@ -77,11 +77,11 @@ namespace dy.net.service
"抖音收藏夹短剧同步任务")
},
{
"follow_user_once",
"sync_follow_user_once",
new JobConfig(
typeof(DouyinFollowsAndCollnectsSyncJob),
"dy.job.key.follow_user_once",
"dy.trigger.key.follow_user_once",
"dy.job.key.sync_follow_user_once",
"dy.trigger.key.sync_follow_user_once",
"抖音关注同步任务(单次执行)")
}
};
@@ -115,7 +115,7 @@ namespace dy.net.service
// 执行任务启动逻辑
foreach (var jobKey in JobConfigs.Keys)
{
if (jobKey == "follow_user_once")
if (jobKey == "sync_follow_user_once")
continue;
if (jobKey == "follow_user") expression = "60";
var startSuccess = await StartJobAsync(jobKey, expression);
@@ -147,13 +147,13 @@ namespace dy.net.service
/// </summary>
public async Task<bool> StartFollowJobOnceAsync()
{
return await StartOneTimeJobAsync("follow_user_once");
return await StartOneTimeJobAsync("sync_follow_user_once");
}
/// <summary>
/// 移除所有已存在的任务(避免重复调度)
/// </summary>
private async Task RemoveAllExistingJobs(IScheduler scheduler)
private static async Task RemoveAllExistingJobs(IScheduler scheduler)
{
var jobKeys = JobConfigs.Values.Select(config => new JobKey(config.JobKey, DefaultJobGroup)).ToList();
foreach (var jobKey in jobKeys)
@@ -246,7 +246,7 @@ namespace dy.net.service
.Build();
await scheduler.ScheduleJob(jobDetail, trigger);
Log.Information("【任务服务】启动单次任务成功 - 任务描述: {JobDescription}", jobConfig.Description);
Log.Debug("【任务服务】启动单次任务成功 - 任务描述: {JobDescription}", jobConfig.Description);
return true;
}
+2 -2
View File
@@ -64,9 +64,9 @@ namespace dy.net.utils
}
},
Author = DouyinFileNameHelper.SanitizeLinuxFileName(video.Author, "", true),
Poster = "poster.jpg",
Poster = $"{video.AwemeId}_poster.jpg",
Title = video.VideoTitle,
Thumbnail = "poster.jpg",// 使用poster作为缩略图
Thumbnail = $"{video.AwemeId}_poster.jpg",// 使用poster作为缩略图
ReleaseDate = video.CreateTime,
Genres = new List<string> { video.Tag1, video.Tag2, video.Tag3 }.Where(t => !string.IsNullOrWhiteSpace(t)).ToList()
};