From 65e6b48d8e7186e6bd3e01c13b174b341b26e149 Mon Sep 17 00:00:00 2001 From: jianzhichu <279225040@.com> Date: Mon, 19 Jan 2026 14:11:23 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B6=E8=97=8F=E5=A4=B9=20=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Controllers/ConfigController.cs | 2 +- Properties/PublishProfiles/docker.pubxml.user | 4 +- dy.net.csproj | 22 ++- dy.net.csproj.user | 2 +- job/DouyinCollectCatesSyncJob.cs | 124 ++++++++++++++ model/dto/DouyinCookieStopDto.cs | 9 +- model/dto/DouyinVideoPageRequestDto.cs | 8 + model/entity/DouyinCollectCate.cs | 8 +- repository/DouyinCollectCateRepository.cs | 157 ++++++++++++++++++ repository/DouyinCookieRepository.cs | 2 +- repository/DouyinFollowRepository.cs | 5 + service/DouyinCollectCateService.cs | 71 ++++++++ service/DouyinCookieService.cs | 2 +- 13 files changed, 401 insertions(+), 15 deletions(-) create mode 100644 job/DouyinCollectCatesSyncJob.cs create mode 100644 repository/DouyinCollectCateRepository.cs create mode 100644 service/DouyinCollectCateService.cs diff --git a/Controllers/ConfigController.cs b/Controllers/ConfigController.cs index da3252d..9311aba 100644 --- a/Controllers/ConfigController.cs +++ b/Controllers/ConfigController.cs @@ -222,7 +222,7 @@ namespace dy.net.Controllers /// 快速开启或停止 /// [HttpPost("switch")] - public async Task SwitchAsync([FromBody] DouyinCookieStopDto dto) + public async Task SwitchAsync([FromBody] DouyinCookieSwitchDto dto) { var result = await dyCookieService.Switch(dto); if (result) diff --git a/Properties/PublishProfiles/docker.pubxml.user b/Properties/PublishProfiles/docker.pubxml.user index e20470b..8813048 100644 --- a/Properties/PublishProfiles/docker.pubxml.user +++ b/Properties/PublishProfiles/docker.pubxml.user @@ -2,8 +2,8 @@ - <_PublishTargetUrl>E:\code\dysync\bin\Release\net6.0\publish\ - True|2026-01-16T16:52:08.8180346Z||;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||;False|2026-01-07T22:36:28.8275903+08:00||;True|2026-01-07T21:59:51.4355171+08:00||;True|2026-01-03T21:38:51.4307034+08:00||;True|2026-01-02T19:09:16.9668906+08:00||;False|2026-01-02T19:09:11.7496369+08:00||;True|2026-01-02T15:42:08.2215697+08:00||;True|2026-01-02T09:46:56.1654861+08:00||;True|2026-01-02T09:35:28.0211225+08:00||;True|2026-01-01T23:07:01.9022045+08:00||;False|2026-01-01T23:06:56.0537216+08:00||;True|2026-01-01T22:16:10.2974067+08:00||;True|2026-01-01T22:16:06.2123787+08:00||;False|2026-01-01T22:15:33.3626979+08:00||;True|2026-01-01T22:01:30.7161900+08:00||;True|2026-01-01T21:10:19.3664263+08:00||;True|2026-01-01T21:09:38.6071080+08:00||;True|2025-12-30T11:45:54.5543034+08:00||;True|2025-12-30T09:19:08.3178124+08:00||;True|2025-12-29T18:57:29.7032246+08:00||;True|2025-12-27T14:52:24.4780776+08:00||;False|2025-12-27T14:52:19.5635794+08:00||;True|2025-12-27T14:48:01.6252748+08:00||;False|2025-12-27T14:47:55.7976192+08:00||;True|2025-12-27T14:38:23.9723838+08:00||;True|2025-12-27T13:00:29.8583858+08:00||;True|2025-12-26T22:18:42.4015637+08:00||;True|2025-12-26T22:10:58.5274572+08:00||;True|2025-12-26T22:06:26.3129600+08:00||;True|2025-12-26T22:03:55.6718618+08:00||;False|2025-12-26T22:03:48.3809954+08:00||;True|2025-12-26T22:02:33.1840390+08:00||;True|2025-12-26T22:01:16.1660100+08:00||;True|2025-12-25T00:50:26.1116465+08:00||; + <_PublishTargetUrl>E:\gitea\dysync\bin\Release\net6.0\publish\ + True|2026-01-19T02:19:44.8997385Z||;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||;False|2026-01-07T22:36:28.8275903+08:00||;True|2026-01-07T21:59:51.4355171+08:00||;True|2026-01-03T21:38:51.4307034+08:00||;True|2026-01-02T19:09:16.9668906+08:00||;False|2026-01-02T19:09:11.7496369+08:00||;True|2026-01-02T15:42:08.2215697+08:00||;True|2026-01-02T09:46:56.1654861+08:00||;True|2026-01-02T09:35:28.0211225+08:00||;True|2026-01-01T23:07:01.9022045+08:00||;False|2026-01-01T23:06:56.0537216+08:00||;True|2026-01-01T22:16:10.2974067+08:00||;True|2026-01-01T22:16:06.2123787+08:00||;False|2026-01-01T22:15:33.3626979+08:00||;True|2026-01-01T22:01:30.7161900+08:00||;True|2026-01-01T21:10:19.3664263+08:00||;True|2026-01-01T21:09:38.6071080+08:00||;True|2025-12-30T11:45:54.5543034+08:00||;True|2025-12-30T09:19:08.3178124+08:00||;True|2025-12-29T18:57:29.7032246+08:00||;True|2025-12-27T14:52:24.4780776+08:00||;False|2025-12-27T14:52:19.5635794+08:00||;True|2025-12-27T14:48:01.6252748+08:00||;False|2025-12-27T14:47:55.7976192+08:00||;True|2025-12-27T14:38:23.9723838+08:00||;True|2025-12-27T13:00:29.8583858+08:00||;True|2025-12-26T22:18:42.4015637+08:00||;True|2025-12-26T22:10:58.5274572+08:00||;True|2025-12-26T22:06:26.3129600+08:00||;True|2025-12-26T22:03:55.6718618+08:00||;False|2025-12-26T22:03:48.3809954+08:00||;True|2025-12-26T22:02:33.1840390+08:00||; \ No newline at end of file diff --git a/dy.net.csproj b/dy.net.csproj index 0b073c7..110bd28 100644 --- a/dy.net.csproj +++ b/dy.net.csproj @@ -6,10 +6,8 @@ enable Linux app\ - $(DefaultItemExcludes);$(SpaRoot)node_modules\** + $(DefaultItemExcludes);$(SpaRoot)node_modules\** True - - true false true @@ -19,6 +17,9 @@ true true . + + false + false @@ -40,11 +41,20 @@ - - - + + + + + + + + + + + + diff --git a/dy.net.csproj.user b/dy.net.csproj.user index b37b1e2..11f5f52 100644 --- a/dy.net.csproj.user +++ b/dy.net.csproj.user @@ -2,7 +2,7 @@ tiny.ddns - E:\code\dysync\Properties\PublishProfiles\docker.pubxml + E:\gitea\dysync\Properties\PublishProfiles\docker.pubxml ApiControllerEmptyScaffolder root/Common/Api diff --git a/job/DouyinCollectCatesSyncJob.cs b/job/DouyinCollectCatesSyncJob.cs new file mode 100644 index 0000000..f69b708 --- /dev/null +++ b/job/DouyinCollectCatesSyncJob.cs @@ -0,0 +1,124 @@ +using dy.net.model.entity; +using dy.net.model.response; +using dy.net.service; +using Quartz; +using System.Collections.Generic; + +namespace dy.net.job +{ + [DisallowConcurrentExecution] // 禁止并发执行,确保同一时间只有一个实例在运行 + public class DouyinCollectCatesSyncJob : IJob + { + + + /// + /// 抖音Cookie服务,用于获取和管理用户Cookie + /// + protected readonly DouyinCookieService _dyCookieService; + + /// + /// 抖音HTTP客户端服务,用于发送HTTP请求 + /// + protected readonly DouyinHttpClientService _douyinService; + + /// + /// 抖音关注服务,用于管理关注数据 + /// + protected readonly DouyinFollowService _followService; + + protected readonly DouyinCommonService douyinCommonService; + + public DouyinCollectCatesSyncJob(DouyinCookieService dyCookieService, DouyinHttpClientService douyinService, DouyinFollowService followService, DouyinCommonService douyinCommonService) + { + _dyCookieService = dyCookieService; + _douyinService = douyinService; + _followService = followService; + this.douyinCommonService = douyinCommonService; + } + + public async Task Execute(IJobExecutionContext context) + { + var cookies = await _dyCookieService.GetAllOpendAsync(); + if (cookies != null && cookies.Any()) + { + AppConfig conf = douyinCommonService.GetConfig(); + + foreach (var ck in cookies) + { + if (string.IsNullOrWhiteSpace(ck.SecUserId)) + { + Serilog.Log.Debug($"同步关注列表博主[{ck.UserName}]-未设置secuserid,跳过."); + continue; + } + string count = "20"; + string offset = "0"; + bool hasmore = true; + int total= 0; + List follows = new List(); + while (hasmore) + { + try + { + var data = await _douyinService.SyncMyFollows(count, offset, ck.SecUserId, ck.Cookies, async err => + { + if (err.StatusCode != 0) + { + Serilog.Log.Error($"同步关注列表博主[{ck.UserName}]关注列表时发生错误,错误信息:{err.StatusMsg},状态码:{err.StatusCode}"); + } + // 如果是未登录错误,则跳出循环 + if (err.StatusCode == 8) + { + hasmore = false; + } + ck.StatusMsg = err.StatusCode == 8 ? "无效" : "正常"; + ck.StatusCode = err.StatusCode; + await _dyCookieService.UpdateAsync(ck); + }); + + if (data != null) + { + // 绑定我的用户ID--之前没有这个字段 + if (string.IsNullOrWhiteSpace(ck.MyUserId)) + { + ck.MyUserId = data.MySelfUserId; + await _dyCookieService.UpdateAsync(ck); + } + total = data.Total; + hasmore = data.HasMore; + offset = data.Offset.ToString(); + if (data.Followings != null && data.Followings.Count > 0) + { + follows.AddRange(data.Followings); + } + } + + // 只有第一次启动时,才进行全部同步 + if (!conf.IsFirstRunning) + { + hasmore = false; + } + } + catch (Exception ex) + { + Serilog.Log.Error($"关注列表同步失败,{ex.Message}"); + hasmore = false; + break; + } + } + + if (follows.Count > 0) + { + var (add, update, succ) = await _followService.Sync(follows, ck); + if (!succ) hasmore = false; + else + { + hasmore = add > 100|| update > 100;//一次最多100条数据 + } + } + + } + await douyinCommonService.SetConfigNotFirstRunning(); + } + } + } +} diff --git a/model/dto/DouyinCookieStopDto.cs b/model/dto/DouyinCookieStopDto.cs index a505ed8..cff3766 100644 --- a/model/dto/DouyinCookieStopDto.cs +++ b/model/dto/DouyinCookieStopDto.cs @@ -1,9 +1,16 @@ namespace dy.net.model.dto { - public class DouyinCookieStopDto + public class DouyinCookieSwitchDto { public string Id { get; set; } public int Status { get; set; } } + + public class DouyinCollectCateSwitchDto + { + public string Id { get; set; } + + public bool Sync { get; set; } + } } diff --git a/model/dto/DouyinVideoPageRequestDto.cs b/model/dto/DouyinVideoPageRequestDto.cs index f10c215..fd0462d 100644 --- a/model/dto/DouyinVideoPageRequestDto.cs +++ b/model/dto/DouyinVideoPageRequestDto.cs @@ -52,4 +52,12 @@ namespace dy.net.model.dto public string UperId { get; set; } } + + + + public class DouyinCollectCateRequestDto : PageRequestDto + { + + public string cookieId { get; set; } + } } diff --git a/model/entity/DouyinCollectCate.cs b/model/entity/DouyinCollectCate.cs index 638ca2e..d1253ef 100644 --- a/model/entity/DouyinCollectCate.cs +++ b/model/entity/DouyinCollectCate.cs @@ -18,7 +18,7 @@ namespace dy.net.model.entity /// /// 关联cookieId /// - public long CookieId { get; set; } + public string CookieId { get; set; } /// /// 收藏夹名称 @@ -47,6 +47,10 @@ namespace dy.net.model.entity /// /// 收藏夹类型(0:自定义收藏夹,1:合集,2:短剧) /// - public int CollectType { get; set; } + public int CateType { get; set; } + + public DateTime CreateTime { get; set; } + + public DateTime UpdateTime { get; set; } } } diff --git a/repository/DouyinCollectCateRepository.cs b/repository/DouyinCollectCateRepository.cs new file mode 100644 index 0000000..fc2ec10 --- /dev/null +++ b/repository/DouyinCollectCateRepository.cs @@ -0,0 +1,157 @@ +using ClockSnowFlake; +using dy.net.model.dto; +using dy.net.model.entity; +using SqlSugar; +using System.Linq.Expressions; + +namespace dy.net.repository +{ + public class DouyinCollectCateRepository : BaseRepository + { + // 注入SQLSugar客户端 + public DouyinCollectCateRepository(ISqlSugarClient db) : base(db) + { + } + + + /// + /// 分页查询 + /// + /// + /// + public async Task<(List list, int totalCount)> GetPagedAsync(DouyinCollectCateRequestDto dto) + { + var where = this.Db.Queryable() + .WhereIF(!string.IsNullOrWhiteSpace(dto.cookieId), x => x.CookieId == dto.cookieId); + + var totalCount = await where.CountAsync(); + var list = await where.Skip((dto.PageIndex - 1) * dto.PageSize).Take(dto.PageSize).ToListAsync(); + return (list, totalCount); + } + + /// + /// 批量修改状态 + /// + /// + /// + public async Task SwitchBatchAsync(List dto) + { + // 空值/空列表防护 + 提取ID列表 + var ids = dto?.Select(x => x.Id).ToList() ?? new List(); + if (!ids.Any()) return false; + + // 1. 查询需要更新的分类数据 + var cates = await GetListAsync(x => ids.Contains(x.Id)); + + // 2. 用字典优化查找(避免循环内FirstOrDefault,提升性能) + var dtoDict = dto.ToDictionary(x => x.Id); + + // 3. 批量更新状态(简化循环写法) + cates.ForEach(item => + { + if (dtoDict.TryGetValue(item.Id, out var dtocate)) + { + item.Sync = dtocate.Sync; + } + }); + + // 4. 执行更新并返回结果 + return await Db.Updateable(cates).ExecuteCommandAsync() > 0; + } + + internal async Task<(int add, int update, int delete, bool succ)> Sync(List cates, string ckId,int cateType) + { + // 初始化返回结果 + int addCount = 0; + int updateCount = 0; + int deleteCount = 0; + bool isSuccess = false; + + try + { + // 1. 参数校验 + if (string.IsNullOrWhiteSpace(ckId)) + { + throw new ArgumentNullException(nameof(ckId), "CookieId信息不能为空"); + } + if (cates == null) + { + cates = new List(); // 空列表则执行删除所有操作 + } + + + // 2. 开启SqlSugar事务 + await Db.Ado.BeginTranAsync(); + + // 3. 查询数据库中当前用户的所有分类 + var dbCates = await Db.Queryable() + .Where(c => c.CookieId == ckId && c.CateType == cateType) + .ToListAsync(); + + // 4. 处理新增和更新逻辑 + var cateIds = cates.Select(c => c.Id).ToList(); + foreach (var cate in cates) + { + + cate.UpdateTime = DateTime.Now; // 更新时间戳 + + // 检查是否已存在 + if (string.IsNullOrWhiteSpace(cate.Id)) + { + cate.CreateTime = DateTime.Now; + cate.Id = IdGener.GetLong().ToString(); + // 新增 + await Db.Insertable(cate).ExecuteCommandAsync(); + addCount++; + } + else + { + var existCate = dbCates.FirstOrDefault(x => x.Id == cate.Id); + if (existCate == null) + { + Serilog.Log.Error($" cate {cate.Id} id 不存在"); + continue; + } + // 对比字段是否有变化(根据实际业务字段调整) + bool isChanged = !string.Equals(existCate.Name, cate.Name, StringComparison.Ordinal); + + if (isChanged) + { + // 更新(只更新有变化的字段,或全量更新) + await Db.Updateable(cate) + .IgnoreColumns(ignoreAllNullColumns: true) // 忽略空值字段 + .Where(c => c.Id == cate.Id) + .ExecuteCommandAsync(); + updateCount++; + } + } + } + + // 5. 处理删除逻辑:数据库中有但传入列表中没有的分类 + var deleteCates = dbCates.Where(c => !cateIds.Contains(c.Id)).ToList(); + if (deleteCates.Any()) + { + var deleteIds = deleteCates.Select(c => c.Id).ToList(); + deleteCount = await Db.Deleteable() + .Where(c => deleteIds.Contains(c.Id) && c.CookieId == ckId) + .ExecuteCommandAsync(); + } + + // 6. 提交事务 + await Db.Ado.CommitTranAsync(); + isSuccess = true; + } + catch (Exception ex) + { + // 异常时回滚事务 + await Db.Ado.RollbackTranAsync(); + isSuccess = false; + // throw; + Serilog.Log.Error($"同步收藏夹:类型-{cateType}异常,{ex.StackTrace}" ); + } + + // 7. 返回最终结果 + return (addCount, updateCount, deleteCount, isSuccess); + } + } +} diff --git a/repository/DouyinCookieRepository.cs b/repository/DouyinCookieRepository.cs index 68d79dc..1891254 100644 --- a/repository/DouyinCookieRepository.cs +++ b/repository/DouyinCookieRepository.cs @@ -44,7 +44,7 @@ namespace dy.net.repository } - public async Task SwitchAsync(DouyinCookieStopDto dto) + public async Task SwitchAsync(DouyinCookieSwitchDto dto) { var res =await Db.Updateable().SetColumns(x => new DouyinCookie { Status = dto.Status }).Where(x => x.Id == dto.Id).ExecuteCommandAsync(); diff --git a/repository/DouyinFollowRepository.cs b/repository/DouyinFollowRepository.cs index 75e9dbb..b89cdda 100644 --- a/repository/DouyinFollowRepository.cs +++ b/repository/DouyinFollowRepository.cs @@ -107,6 +107,8 @@ namespace dy.net.repository try { + // 2. 开启SqlSugar事务 + await Db.Ado.BeginTranAsync(); // 1. 提取当前批次的SecUid集合(去重) HashSet currentSecUids = followInfos.Select(x => x.SecUid).ToHashSet(); if (!currentSecUids.Any()) @@ -203,12 +205,15 @@ namespace dy.net.repository } } + // 6. 提交事务 + await Db.Ado.CommitTranAsync(); // 【重要】删除逻辑已移除:增量场景下不能通过批次对比删除,需单独设计取消关注逻辑 Serilog.Log.Debug($"dy_followed_users({ck.UserName})关注列表同步完成:新增{toAddFollows.Count}条,更新{toUpdateFollows.Count}条"); return (toAddFollows.Count, toUpdateFollows.Count, true); } catch (Exception ex) { + await Db.Ado.RollbackTranAsync(); Serilog.Log.Error(ex, $"同步关注列表失败({ck.UserName}):{ex.Message}"); return (0, 0, false); diff --git a/service/DouyinCollectCateService.cs b/service/DouyinCollectCateService.cs new file mode 100644 index 0000000..fee2ed5 --- /dev/null +++ b/service/DouyinCollectCateService.cs @@ -0,0 +1,71 @@ +using ClockSnowFlake; +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 +{ + public class DouyinCollectCateService + { + + private readonly DouyinCollectCateRepository douyinCollectCateRepository; + + public DouyinCollectCateService(DouyinCollectCateRepository douyinCollectCateRepository) + { + douyinCollectCateRepository = douyinCollectCateRepository; + } + + + + + + + /// + /// + /// + /// + /// + public async Task<(List list, int totalCount)> GetPagedAsync(DouyinCollectCateRequestDto dto) + { + return await douyinCollectCateRepository.GetPagedAsync(dto); + } + + /// + /// + /// + /// + /// + /// + public async Task<(int add, int update,int delete, bool succ)> Sync(List cates, string ckId) + { + return await douyinCollectCateRepository.Sync(cates, ckId); + } + + + /// + /// 打开或关闭同步 + /// + /// + /// + public async Task BatchSwitchSync(List dto) + { + return await douyinCollectCateRepository.SwitchBatchAsync(dto); + } + + + + + /// + /// 获取需要同步的合集、短剧、收藏夹 + /// + /// + public async Task> GetSyncCates(string cookieId,int cateType) + { + return await douyinCollectCateRepository.GetListAsync(x => x.CookieId == cookieId && x.CateType == cateType); + } + + } +} diff --git a/service/DouyinCookieService.cs b/service/DouyinCookieService.cs index 68e7f11..8ea3368 100644 --- a/service/DouyinCookieService.cs +++ b/service/DouyinCookieService.cs @@ -39,7 +39,7 @@ namespace dy.net.service { return await _cookieRepository.InsertAsync(dyUserCookies); } - public async Task Switch(DouyinCookieStopDto dto) + public async Task Switch(DouyinCookieSwitchDto dto) { return await _cookieRepository.SwitchAsync(dto); }