收藏夹 服务
This commit is contained in:
@@ -222,7 +222,7 @@ namespace dy.net.Controllers
|
||||
/// 快速开启或停止
|
||||
/// </summary>
|
||||
[HttpPost("switch")]
|
||||
public async Task<IActionResult> SwitchAsync([FromBody] DouyinCookieStopDto dto)
|
||||
public async Task<IActionResult> SwitchAsync([FromBody] DouyinCookieSwitchDto dto)
|
||||
{
|
||||
var result = await dyCookieService.Switch(dto);
|
||||
if (result)
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<_PublishTargetUrl>E:\code\dysync\bin\Release\net6.0\publish\</_PublishTargetUrl>
|
||||
<History>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||;</History>
|
||||
<_PublishTargetUrl>E:\gitea\dysync\bin\Release\net6.0\publish\</_PublishTargetUrl>
|
||||
<History>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||;</History>
|
||||
<LastFailureDetails />
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
+12
-2
@@ -8,8 +8,6 @@
|
||||
<SpaRoot>app\</SpaRoot>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
|
||||
|
||||
<ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>
|
||||
<ServerGarbageCollection>false</ServerGarbageCollection>
|
||||
<RetainVMGarbageCollection>true</RetainVMGarbageCollection>
|
||||
@@ -19,6 +17,9 @@
|
||||
<TieredCompilation>true</TieredCompilation>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
<DockerfileContext>.</DockerfileContext>
|
||||
<!-- 2. 强制禁用默认编译项(旧版VS关键配置) -->
|
||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||
<EnableDefaultContentItems>false</EnableDefaultContentItems>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -40,10 +41,19 @@
|
||||
<None Remove="logs\**" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="**/*.cs" Exclude="app\**;db\**;expand\**;logs\**;obj\**;bin\**" />
|
||||
<Content Include="**/*.json;**/*.xml;**/*.config" Exclude="app\**;db\**;expand\**;logs\**;obj\**;bin\**" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Content Remove="wwwroot\index.html" />
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ClockSnowFlake" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.16" />
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ActiveDebugProfile>tiny.ddns</ActiveDebugProfile>
|
||||
<NameOfLastUsedPublishProfile>E:\code\dysync\Properties\PublishProfiles\docker.pubxml</NameOfLastUsedPublishProfile>
|
||||
<NameOfLastUsedPublishProfile>E:\gitea\dysync\Properties\PublishProfiles\docker.pubxml</NameOfLastUsedPublishProfile>
|
||||
<Controller_SelectedScaffolderID>ApiControllerEmptyScaffolder</Controller_SelectedScaffolderID>
|
||||
<Controller_SelectedScaffolderCategoryPath>root/Common/Api</Controller_SelectedScaffolderCategoryPath>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 抖音Cookie服务,用于获取和管理用户Cookie
|
||||
/// </summary>
|
||||
protected readonly DouyinCookieService _dyCookieService;
|
||||
|
||||
/// <summary>
|
||||
/// 抖音HTTP客户端服务,用于发送HTTP请求
|
||||
/// </summary>
|
||||
protected readonly DouyinHttpClientService _douyinService;
|
||||
|
||||
/// <summary>
|
||||
/// 抖音关注服务,用于管理关注数据
|
||||
/// </summary>
|
||||
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<FollowingsItem> follows = new List<FollowingsItem>();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,4 +52,12 @@ namespace dy.net.model.dto
|
||||
public string UperId { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class DouyinCollectCateRequestDto : PageRequestDto
|
||||
{
|
||||
|
||||
public string cookieId { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace dy.net.model.entity
|
||||
/// <summary>
|
||||
/// 关联cookieId
|
||||
/// </summary>
|
||||
public long CookieId { get; set; }
|
||||
public string CookieId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 收藏夹名称
|
||||
@@ -47,6 +47,10 @@ namespace dy.net.model.entity
|
||||
/// <summary>
|
||||
/// 收藏夹类型(0:自定义收藏夹,1:合集,2:短剧)
|
||||
/// </summary>
|
||||
public int CollectType { get; set; }
|
||||
public int CateType { get; set; }
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
public DateTime UpdateTime { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<DouyinCollectCate>
|
||||
{
|
||||
// 注入SQLSugar客户端
|
||||
public DouyinCollectCateRepository(ISqlSugarClient db) : base(db)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 分页查询
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<(List<DouyinCollectCate> list, int totalCount)> GetPagedAsync(DouyinCollectCateRequestDto dto)
|
||||
{
|
||||
var where = this.Db.Queryable<DouyinCollectCate>()
|
||||
.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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量修改状态
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> SwitchBatchAsync(List<DouyinCollectCateSwitchDto> dto)
|
||||
{
|
||||
// 空值/空列表防护 + 提取ID列表
|
||||
var ids = dto?.Select(x => x.Id).ToList() ?? new List<string>();
|
||||
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<DouyinCollectCate> 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<DouyinCollectCate>(); // 空列表则执行删除所有操作
|
||||
}
|
||||
|
||||
|
||||
// 2. 开启SqlSugar事务
|
||||
await Db.Ado.BeginTranAsync();
|
||||
|
||||
// 3. 查询数据库中当前用户的所有分类
|
||||
var dbCates = await Db.Queryable<DouyinCollectCate>()
|
||||
.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<DouyinCollectCate>()
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ namespace dy.net.repository
|
||||
}
|
||||
|
||||
|
||||
public async Task<bool> SwitchAsync(DouyinCookieStopDto dto)
|
||||
public async Task<bool> SwitchAsync(DouyinCookieSwitchDto dto)
|
||||
{
|
||||
var res =await Db.Updateable<DouyinCookie>().SetColumns(x => new DouyinCookie { Status = dto.Status }).Where(x => x.Id == dto.Id).ExecuteCommandAsync();
|
||||
|
||||
|
||||
@@ -107,6 +107,8 @@ namespace dy.net.repository
|
||||
|
||||
try
|
||||
{
|
||||
// 2. 开启SqlSugar事务
|
||||
await Db.Ado.BeginTranAsync();
|
||||
// 1. 提取当前批次的SecUid集合(去重)
|
||||
HashSet<string> 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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<(List<DouyinCollectCate> list, int totalCount)> GetPagedAsync(DouyinCollectCateRequestDto dto)
|
||||
{
|
||||
return await douyinCollectCateRepository.GetPagedAsync(dto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="cates"></param>
|
||||
/// <param name="ckId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<(int add, int update,int delete, bool succ)> Sync(List<DouyinCollectCate> cates, string ckId)
|
||||
{
|
||||
return await douyinCollectCateRepository.Sync(cates, ckId);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 打开或关闭同步
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> BatchSwitchSync(List<DouyinCollectCateSwitchDto> dto)
|
||||
{
|
||||
return await douyinCollectCateRepository.SwitchBatchAsync(dto);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取需要同步的合集、短剧、收藏夹
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<DouyinCollectCate>> GetSyncCates(string cookieId,int cateType)
|
||||
{
|
||||
return await douyinCollectCateRepository.GetListAsync(x => x.CookieId == cookieId && x.CateType == cateType);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ namespace dy.net.service
|
||||
{
|
||||
return await _cookieRepository.InsertAsync(dyUserCookies);
|
||||
}
|
||||
public async Task<bool> Switch(DouyinCookieStopDto dto)
|
||||
public async Task<bool> Switch(DouyinCookieSwitchDto dto)
|
||||
{
|
||||
return await _cookieRepository.SwitchAsync(dto);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user