结构调整

This commit is contained in:
jianzhichu
2026-01-19 09:57:40 +08:00
parent d9cb721f64
commit f5449f3ace
77 changed files with 4060 additions and 1516 deletions
+1 -49
View File
@@ -7,7 +7,7 @@ using System.Security.Claims;
using System.Text; using System.Text;
using dy.net.service; using dy.net.service;
using dy.net.utils; using dy.net.utils;
using dy.net.dto; using dy.net.model.dto;
namespace dy.net.Controllers namespace dy.net.Controllers
{ {
@@ -50,54 +50,6 @@ namespace dy.net.Controllers
return ApiResult.Success(new { user?.Avatar, user?.Id, user?.UserName }); return ApiResult.Success(new { user?.Avatar, user?.Id, user?.UserName });
} }
/// <summary>
/// 修改用户头像
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
[Authorize]
[HttpPost]
public async Task<IActionResult> UpdateUserAvatar(IFormFile file)
{
if (file != null && file.Length > 0)
{
long maxFileSize = 5 * 1024 * 1024; // 限制文件大小为5MB
if (file.Length > maxFileSize)
{
return ApiResult.Fail("文件最大只能上传5M");
}
var fileName = $"{IdGener.GetGuid()}_{file.FileName}";
var filePath = webHostEnvironment.IsProduction() ?
Path.Combine(Md5Util.UPLOAD_PATH_PRO, fileName) : Path.Combine(Md5Util.UPLOAD_PATH_DEV, fileName);
using (var stream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(stream);
try
{
// 问了节约空间,删除文件夹下的所有文件
string[] files = Directory.GetFiles(webHostEnvironment.IsProduction() ? Md5Util.UPLOAD_PATH_PRO : Md5Util.UPLOAD_PATH_DEV);
foreach (string mfile in files)
{
if (!mfile.Contains(fileName))
System.IO.File.Delete(mfile);
}
}
catch (Exception ex)
{
Serilog.Log.Error($"delete file error ,{ex.Message}");
return ApiResult.Fail(ex.Message);
}
var update = await _userService.UpdateAvatar(fileName);
return ApiResult.SuccOrFail(update , update ? fileName : "", update ? "" : "上传失败");
}
}
else
{
return ApiResult.Fail("无效的文件");
}
}
+24 -29
View File
@@ -1,7 +1,7 @@
using ClockSnowFlake; using ClockSnowFlake;
using dy.net.dto;
using dy.net.extension; using dy.net.extension;
using dy.net.model; using dy.net.model.dto;
using dy.net.model.entity;
using dy.net.service; using dy.net.service;
using dy.net.utils; using dy.net.utils;
using dy.sync.lib; using dy.sync.lib;
@@ -28,26 +28,18 @@ namespace dy.net.Controllers
private readonly DouyinQuartzJobService quartzJobService; private readonly DouyinQuartzJobService quartzJobService;
private readonly DouyinFollowService douyinFollowService; private readonly DouyinFollowService douyinFollowService;
private readonly DouyinCookieService douyinCookieService; private readonly DouyinCookieService douyinCookieService;
private readonly DouyinHttpClientService httpClientService;
//// 定义允许上传的音频扩展名(小写)
//private readonly string[] _allowedAudioExtensions = { ".mp3", ".wav" };
//// 定义允许的音频 MIME 类型(增强验证)
//private readonly string[] _allowedAudioMimeTypes = {
// "audio/mpeg", "audio/wav"
//};
// 最大文件大小:20MB(可根据需求调整)
//private const long _maxFileSize = 20 * 1024 * 1024;
public ConfigController(DouyinCookieService dyCookieService, DouyinCommonService commonService, DouyinQuartzJobService quartzJobService, DouyinFollowService douyinFollowService, DouyinCookieService douyinCookieService)
public ConfigController(DouyinCookieService dyCookieService, DouyinCommonService commonService, DouyinQuartzJobService quartzJobService, DouyinFollowService douyinFollowService, DouyinCookieService douyinCookieService, DouyinHttpClientService httpClientService)
{ {
this.dyCookieService = dyCookieService; this.dyCookieService = dyCookieService;
this.commonService = commonService; this.commonService = commonService;
this.quartzJobService = quartzJobService; this.quartzJobService = quartzJobService;
this.douyinFollowService = douyinFollowService; this.douyinFollowService = douyinFollowService;
this.douyinCookieService = douyinCookieService; this.douyinCookieService = douyinCookieService;
this.httpClientService = httpClientService;
} }
@@ -161,6 +153,12 @@ namespace dy.net.Controllers
public async Task<IActionResult> AddAsync([FromBody] DouyinCookie dyUserCookies) 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); var result = await dyCookieService.Add(dyUserCookies);
if (result) if (result)
{ {
@@ -204,29 +202,21 @@ namespace dy.net.Controllers
return ApiResult.Fail($"请在飞牛应用设置里面将{dyUserCookies.ImgSavePath}添加读写权限"); return ApiResult.Fail($"请在飞牛应用设置里面将{dyUserCookies.ImgSavePath}添加读写权限");
} }
var checkCk = await httpClientService.CheckCookie(dyUserCookies);
if (!checkCk)
{
return ApiResult.Fail("Cookie无效,请按照文档提示重新获取有效Cookie,不要使用插件获取cookie");
}
var result = await dyCookieService.Add(dyUserCookies); var result = await dyCookieService.Add(dyUserCookies);
if (result) if (result)
{ {
return ApiResult.Success(); return ApiResult.Success();
} }
return ApiResult.Fail("添加失败"); return ApiResult.Fail("添加失败");
} }
/// <summary>
///
/// </summary>
/// <returns></returns>
[HttpGet("appport")]
[AllowAnonymous]
public async Task<IActionResult> GetAppPort()
{
//return ApiResult.Success(10105);
return ApiResult.Success(string.IsNullOrWhiteSpace(Appsettings.Get("appPort")) ? 10101 : Convert.ToInt32(Appsettings.Get("appPort")));
}
/// <summary> /// <summary>
/// 快速开启或停止 /// 快速开启或停止
@@ -248,6 +238,11 @@ namespace dy.net.Controllers
[HttpPost("update")] [HttpPost("update")]
public async Task<IActionResult> UpdateAsync([FromBody] DouyinCookie dyUserCookies) public async Task<IActionResult> UpdateAsync([FromBody] DouyinCookie dyUserCookies)
{ {
var checkCk = await httpClientService.CheckCookie(dyUserCookies);
if (!checkCk)
{
return ApiResult.Fail("Cookie无效,请按照文档提示重新获取有效Cookie,不要使用插件获取cookie");
}
if (dyUserCookies.Id == "0") if (dyUserCookies.Id == "0")
{ {
+2 -2
View File
@@ -1,5 +1,5 @@
using dy.net.dto; using dy.net.model.dto;
using dy.net.model; using dy.net.model.entity;
using dy.net.service; using dy.net.service;
using dy.net.utils; using dy.net.utils;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
+1 -1
View File
@@ -1,4 +1,4 @@
using dy.net.dto; using dy.net.model.dto;
using dy.net.service; using dy.net.service;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
+2 -2
View File
@@ -1,5 +1,5 @@
using dy.net.dto; using dy.net.model.dto;
using dy.net.model; using dy.net.model.entity;
using dy.net.service; using dy.net.service;
using dy.net.utils; using dy.net.utils;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
+1 -2
View File
@@ -11,7 +11,7 @@ namespace dy.net
public class Program public class Program
{ {
// 常量定义 // 常量定义
private static string DefaultListenUrl = "10101"; private static string DefaultListenUrl = "http://*:10101";
private const string SpaRootPath = "app/dist"; private const string SpaRootPath = "app/dist";
private const string SpaSourcePath = "app/"; private const string SpaSourcePath = "app/";
private const string SwaggerDocTitle = "dy.net WebApi Docs"; private const string SwaggerDocTitle = "dy.net WebApi Docs";
@@ -49,7 +49,6 @@ namespace dy.net
{ {
InitAppsettings(builder); InitAppsettings(builder);
//from docker yaml file 环境变量 或者 dockerfile 或appsettings.json //from docker yaml file 环境变量 或者 dockerfile 或appsettings.json
DefaultListenUrl = $"http://*:{builder.Configuration.GetValue<string>(SystemStaticUtil.APP_PORT) ?? DefaultListenUrl}";
// 设置监听地址 // 设置监听地址
builder.WebHost.UseUrls(DefaultListenUrl); builder.WebHost.UseUrls(DefaultListenUrl);
// 配置日志 // 配置日志
@@ -3,7 +3,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<_PublishTargetUrl>E:\code\dysync\bin\Release\net6.0\publish\</_PublishTargetUrl> <_PublishTargetUrl>E:\code\dysync\bin\Release\net6.0\publish\</_PublishTargetUrl>
<History>True|2026-01-16T16:45:04.0498090Z||;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||;True|2025-12-25T00:48:27.3087708+08:00||;True|2025-12-25T00:47:38.4835720+08:00||;</History> <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>
<LastFailureDetails /> <LastFailureDetails />
</PropertyGroup> </PropertyGroup>
</Project> </Project>
+1 -1
View File
@@ -44,7 +44,7 @@ onMounted(() => {
</div> --> </div> -->
<!-- 新增显示当前版本号增加样式分隔提升美观度 --> <!-- 新增显示当前版本号增加样式分隔提升美观度 -->
<span class="version-text">{{currentVersion.deploy}}_{{ currentVersion.tag }}</span> <span class="version-text" v-if="currentVersion">{{currentVersion.deploy}}_{{ currentVersion.tag }}</span>
</div> </div>
</div> </div>
</footer> </footer>
+475 -47
View File
@@ -1,8 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
// 原有代码不变,此处省略(仅保留模板相关修改,脚本逻辑无变化)
import { getBase64 } from '@/utils/file'; import { getBase64 } from '@/utils/file';
import { FormInstance } from 'ant-design-vue'; import { FormInstance } from 'ant-design-vue';
import { reactive, ref, onMounted, UnwrapRef, watch } from 'vue'; import { reactive, ref, onMounted, UnwrapRef, watch, nextTick } from 'vue';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { Dayjs } from 'dayjs'; import { Dayjs } from 'dayjs';
import { import {
@@ -26,14 +25,14 @@ columns.value = [
dataIndex: 'userName', dataIndex: 'userName',
width: 180, width: 180,
}, },
{ title: 'Cookie状态', dataIndex: 'statusMsg' },
{ title: '收藏路径', dataIndex: 'savePath' }, { title: '收藏路径', dataIndex: 'savePath' },
{ title: '喜欢路径', dataIndex: 'favSavePath' }, { title: '喜欢路径', dataIndex: 'favSavePath' },
{ title: '博主路径', dataIndex: 'upSavePath' }, { title: '博主路径', dataIndex: 'upSavePath' },
{ title: '图文视频', dataIndex: 'imgSavePath' }, { title: '图文视频', dataIndex: 'imgSavePath' },
{ title: 'Cookie', dataIndex: 'cookies' }, // { title: 'Cookie', dataIndex: 'cookies' },
{ title: '有效状态', dataIndex: 'statusMsg' },
{ title: '状态', dataIndex: 'status', width: 180 }, { title: '状态', dataIndex: 'status', width: 180 },
{ title: '操作', dataIndex: 'edit', width: 350 }, // 加宽操作列宽度 { title: '操作', dataIndex: 'edit', width: 200 }, // 加宽操作列宽度
]; ];
// 定义数组中单个对象的类型:包含uper和uid字段(可选字符串类型,根据实际需求调整是否可选) // 定义数组中单个对象的类型:包含uper和uid字段(可选字符串类型,根据实际需求调整是否可选)
@@ -57,6 +56,9 @@ type DataItem = {
upSavePath?: string; upSavePath?: string;
imgSavePath?: string; imgSavePath?: string;
useSinglePath?: boolean; // 新增:是否全部用一个地址 useSinglePath?: boolean; // 新增:是否全部用一个地址
useCollectFolder?: boolean;
downMix?: boolean;
downSeries?: boolean;
}; };
const loading = ref(false); const loading = ref(false);
@@ -117,6 +119,9 @@ const newCookie = (cookie?: DataItem) => {
cookie.upSavePath = undefined; cookie.upSavePath = undefined;
cookie.imgSavePath = undefined; cookie.imgSavePath = undefined;
cookie.useSinglePath = false; // 新增:默认不使用单一路径 cookie.useSinglePath = false; // 新增:默认不使用单一路径
cookie.useCollectFolder = false; //是否按收藏夹来下载。
cookie.downMix = false; //是否下载收藏夹的合集
cookie.downSeries = false; //是否下载短剧
return cookie; return cookie;
}; };
@@ -216,6 +221,7 @@ const deleted = (id: string) => {
function edit(record: DataItem) { function edit(record: DataItem) {
editRecord.value = record; editRecord.value = record;
console.log(record);
copyObject(form, record); copyObject(form, record);
// 确保useSinglePath有默认值 // 确保useSinglePath有默认值
if (form.useSinglePath === undefined) { if (form.useSinglePath === undefined) {
@@ -225,9 +231,10 @@ function edit(record: DataItem) {
} }
// 新增:切换同步状态方法 // 新增:切换同步状态方法
const switchSyncStatus = (record: DataItem) => { const switchSyncStatus = (record: DataItem) => {
const targetStatus = record.status === 1 ? 0 : 1; // 保存原始状态,用于弹窗取消后还原
const statusText = targetStatus === 1 ? '开启' : '停止'; const statusText = record.status === 1 ? '开启' : '停止';
const title = `确认${statusText}同步`; const title = `确认${statusText}同步`;
const content = `确定要${statusText}${record.userName || '该'}】Cookie的同步任务吗?`; const content = `确定要${statusText}${record.userName || '该'}】Cookie的同步任务吗?`;
@@ -241,33 +248,33 @@ const switchSyncStatus = (record: DataItem) => {
useApiStore() useApiStore()
.SwitchCookieStatus({ .SwitchCookieStatus({
id: record.id, id: record.id,
status: targetStatus, status: record.status,
}) })
.then((res) => { .then((res) => {
loading.value = false; loading.value = false;
if (res.code === 0) { if (res.code === 0) {
message.success(`${statusText}同步成功`); message.success(`${statusText}同步成功`);
GetRecords(); // 刷新列表 GetRecords(); // 刷新列表,更新 switch 状态
} else { } else {
message.error(`${statusText}同步失败:${res.message || '未知错误'}`); message.error(`${statusText}同步失败:${res.message || '未知错误'}`);
record.status = record.status === 1 ? 0 : 1;
} }
}) })
.catch((err) => { .catch((err) => {
loading.value = false; loading.value = false;
console.error('切换同步状态失败:', err); console.error('切换同步状态失败:', err);
message.error('切换同步状态失败,请稍后重试'); message.error('切换同步状态失败,请稍后重试');
record.status = record.status === 1 ? 0 : 1;
}); });
}, },
onCancel: () => { onCancel: () => {
console.log(`已取消${statusText}同步`); console.log(`已取消${statusText}同步`);
record.status = record.status === 1 ? 0 : 1;
}, },
}); });
}; };
type Status = 0 | 1;
const StatusDict = { const StatusDict = {
0: '同步已关闭', 0: '同步已停止',
1: '同步已开启', 1: '同步已开启',
}; };
@@ -297,17 +304,183 @@ const removeRow = (index: number) => {
form.upSecUserIdsJson.splice(index, 1); form.upSecUserIdsJson.splice(index, 1);
} }
}; };
const rowCount = 8; const rowCount = 5;
// 组件挂载时获取配置 // 组件挂载时获取配置
onMounted(() => { onMounted(() => {
GetRecords(); GetRecords();
}); });
const downImgVideo = ref(true);
// ========== 抽屉相关响应式数据 ==========
// 抽屉显示状态
const showDrawer = ref(false);
// 抽屉类型(区分收藏夹/合集/短剧)
type DrawerType = 'collect' | 'mix' | 'series';
const drawerType = ref<DrawerType>('collect');
// 抽屉滚动容器引用(用于监听触底分页)
const drawerScrollRef = ref<HTMLDivElement | null>(null);
// 抽屉数据列表
const drawerDataList = ref<DrawerItem[]>([]);
// 抽屉分页配置
const drawerPagination = reactive({
current: 1,
pageSize: 20,
total: 0,
loading: false,
hasMore: true, // 是否还有更多数据
});
// ========== 定义抽屉数据项接口 ==========
interface DrawerItem {
Id: string; // 不显示
Name: string; // 名称
SaveFolder: string; // 保存文件夹
Sync: boolean; // 是否同步
CoverUrl: string; // 封面
CookieId: string; // 不显示
XId: string; // 不显示
}
// ========== 3个打开抽屉的方法 ==========
const openCollectFolderSetModal = () => {
drawerType.value = 'collect';
openCommonDrawer();
};
const openMixDownSetModal = () => {
drawerType.value = 'mix';
openCommonDrawer();
};
const openSeriesDownSetModal = () => {
drawerType.value = 'series';
openCommonDrawer();
};
// ========== 公用抽屉打开逻辑 ==========
const openCommonDrawer = () => {
// 重置抽屉状态
drawerDataList.value = [];
drawerPagination.current = 1;
drawerPagination.total = 0;
drawerPagination.hasMore = true;
// 显示抽屉
showDrawer.value = true;
// 加载第一页数据
loadDrawerData();
// 监听滚动触底(延迟绑定,确保DOM已渲染)
nextTick(() => {
bindDrawerScrollEvent();
});
};
// ========== 绑定抽屉滚动触底事件 ==========
const bindDrawerScrollEvent = () => {
const scrollContainer = drawerScrollRef.value;
if (!scrollContainer) return;
// 先移除原有事件,避免重复绑定
scrollContainer.removeEventListener('scroll', handleDrawerScroll);
// 添加滚动事件
scrollContainer.addEventListener('scroll', handleDrawerScroll);
};
// ========== 滚动触底处理逻辑 ==========
const handleDrawerScroll = () => {
const scrollContainer = drawerScrollRef.value;
if (!scrollContainer || drawerPagination.loading || !drawerPagination.hasMore) return;
// 计算滚动位置(触底阈值20px,避免精准触底才触发)
const { scrollTop, clientHeight, scrollHeight } = scrollContainer;
const isBottom = scrollTop + clientHeight >= scrollHeight - 20;
if (isBottom) {
// 加载下一页
drawerPagination.current += 1;
loadDrawerData();
}
};
// ========== 加载抽屉数据(模拟接口请求,可替换为真实接口) ==========
const loadDrawerData = () => {
if (drawerPagination.loading || !drawerPagination.hasMore) return;
drawerPagination.loading = true;
// 模拟接口请求(实际项目中替换为真实API调用)
setTimeout(() => {
// 模拟数据(可根据drawerType返回不同类型数据)
const mockData: DrawerItem[] = Array.from({ length: drawerPagination.pageSize }, (_, index) => ({
Id: `${drawerPagination.current}-${index}`,
Name: `${getDrawerTypeName()} ${(drawerPagination.current - 1) * drawerPagination.pageSize + index + 1}`,
SaveFolder: `./${drawerType.value}/${(drawerPagination.current - 1) * drawerPagination.pageSize + index + 1}`,
Sync: Math.random() > 0.5,
CoverUrl: `https://picsum.photos/120/180?random=${
// 改为竖向图片尺寸 120x180
(drawerPagination.current - 1) * drawerPagination.pageSize + index + 1
}`,
CookieId: form.id || '0',
XId: `X-${drawerPagination.current}-${index}`,
}));
// 拼接数据列表
drawerDataList.value = [...drawerDataList.value, ...mockData];
// 更新分页状态
drawerPagination.total = 100; // 模拟总条数
drawerPagination.loading = false;
// 判断是否还有更多数据
drawerPagination.hasMore = drawerDataList.value.length < drawerPagination.total;
}, 800);
};
// ========== 获取抽屉类型名称(用于页面展示) ==========
const getDrawerTypeName = () => {
switch (drawerType.value) {
case 'collect':
return '收藏夹';
case 'mix':
return '合集';
case 'series':
return '短剧';
default:
return '数据';
}
};
// ========== 切换同步状态(可根据需求对接真实接口) ==========
const toggleDrawerItemSync = (item: DrawerItem, index: number) => {
if (drawerDataList.value[index]) {
drawerDataList.value[index].Sync = !item.Sync;
console.log(`切换${getDrawerTypeName()}${item.Name}】的同步状态为:${!item.Sync}`);
}
};
// ========== 关闭抽屉清理资源 ==========
const closeDrawer = () => {
showDrawer.value = false;
// 移除滚动事件监听
const scrollContainer = drawerScrollRef.value;
if (scrollContainer) {
scrollContainer.removeEventListener('scroll', handleDrawerScroll);
}
};
// 2. 新增:抽屉右上角保存按钮的点击方法(仅抽屉相关,不影响其他逻辑)
const saveDrawerData = () => {
if (drawerDataList.value.length === 0) {
message.info('暂无需要保存的配置数据');
return;
}
// 模拟保存逻辑(实际项目中可替换为真实接口,提交 drawerDataList.value 数据)
drawerPagination.loading = true;
setTimeout(() => {
drawerPagination.loading = false;
message.success(`${getDrawerTypeName()}配置保存成功`);
}, 800);
};
</script> </script>
<template> <template>
<a-modal :title="form._isNew ? '新增' : '编辑'" v-model:visible="showModal" @ok="submit" @cancel="cancel" width="1000px"> <a-modal :title="form._isNew ? '新增' : '编辑'" v-model:visible="showModal" @ok="submit" @cancel="cancel" width="100%" wrap-class-name="full-modal">
<a-form ref="formModel" :model="form" :labelCol="{ span: 3 }" :wrapperCol="{ span: 20 }"> <a-form ref="formModel" :model="form" :labelCol="{ span: 3 }" :wrapperCol="{ span: 20 }">
<a-form-item label="Cookie名称" required name="userName"> <a-form-item label="Cookie名称" required name="userName">
<a-input v-model:value="form.userName" /> <a-input v-model:value="form.userName" />
@@ -321,7 +494,7 @@ const downImgVideo = ref(true);
<a-form-item label="我的secUserId" name="secUserId"> <a-form-item label="我的secUserId" name="secUserId">
<div style="display: flex; align-items: center; gap: 6px;"> <div style="display: flex; align-items: center; gap: 6px;">
<a-input v-model:value="form.secUserId" style="flex: 1;" placeholder="如果要同步“我喜欢”的视频和关注列表时,必填!!!" /> <a-input v-model:value="form.secUserId" style="flex: 1;" placeholder="" />
<a-tooltip title="如果要同步“我喜欢”的视频和关注列表时,必填!!!"> <a-tooltip title="如果要同步“我喜欢”的视频和关注列表时,必填!!!">
<ExclamationCircleOutlined style="color: #faad14;font-size: 16px;" /> <ExclamationCircleOutlined style="color: #faad14;font-size: 16px;" />
</a-tooltip> </a-tooltip>
@@ -335,12 +508,54 @@ const downImgVideo = ref(true);
<a-alert message="不想同步收藏的视频就空着" type="info" size="small" style="flex: 1; margin-bottom: 0;" /> <a-alert message="不想同步收藏的视频就空着" type="info" size="small" style="flex: 1; margin-bottom: 0;" />
</div> </div>
</a-form-item> </a-form-item>
<!-- 新增是否全部用一个地址开关 --> <!-- 新增是否全部用一个地址开关 -->
<a-form-item label="统一存储路径" name="useSinglePath"> <a-form-item v-if="form.savePath&&form.savePath.length>0" label="是否统一存储路径" name="useSinglePath">
<div style="display: flex; align-items: center; gap: 8px;"> <div style="display: flex; align-items: center; gap: 12px;">
<a-switch v-model:checked="form.useSinglePath" :checked-value="true" :un-checked-value="false" size="default" /> <div style="width: 200px;">
<span>{{ form.useSinglePath ? '共用收藏视频路径,如果是容器部署-docker-compose配置,只需要映射一个路径就行了' : '各类视频路径分开独立配置' }}</span> <a-switch v-model:checked="form.useSinglePath" :checked-value="true" :un-checked-value="false" size="default" />
<span style="margin-left:10px;">{{form.useSinglePath ?'是':'否'}}</span>
</div>
<a-alert message="开启后,所有视频都存储在收藏视频存储的路径,如果是容器部署:docker-compose配置,此时只需要映射一个路径' " :type="form.useSinglePath?'success':'info'" size="small" style="flex: 1; margin-bottom: 0;" />
</div>
</a-form-item>
<a-form-item v-if="form.savePath&&form.savePath.length>0" label="下载收藏夹" name="useCollectFolder">
<div style="display: flex; align-items: center; gap: 12px;">
<div style="width: 200px;">
<a-switch v-model:checked="form.useCollectFolder" :checked-value="true" :un-checked-value="false" size="default" />
<span style="margin-left:10px;">{{ form.useCollectFolder ? '是' : '否' }}</span>
<a-button @click="openCollectFolderSetModal" shape="circle" type="dashed" style="margin-left:10px;" v-if="form.useCollectFolder">
<setting-outlined />
</a-button>
</div>
<a-alert message="开启后按照设置的自定义收藏文件夹进行下载(需要开启收藏文件夹同步开关)" :type="form.useCollectFolder?'success':'info'" size="small" style="flex: 1; margin-bottom: 0;" />
</div>
</a-form-item>
<a-form-item v-if="form.savePath&&form.savePath.length>0" label="下载合集" name="downMix">
<div style="display: flex; align-items: center; gap: 12px;">
<div style="width: 200px;">
<a-switch v-model:checked="form.downMix" :checked-value="true" :un-checked-value="false" size="default" />
<span style="margin-left:10px;">{{ form.downMix ? '是' : '否' }}</span>
<a-button @click="openMixDownSetModal" shape="circle" type="dashed" style="margin-left:10px;" v-if="form.downMix"> <setting-outlined />
</a-button>
</div>
<a-alert message="开启后会同步下载收藏的合集(需要开启合集同步开关)" :type="form.downMix?'success':'info'" size="small" style="flex: 1; margin-bottom: 0;" />
</div>
</a-form-item>
<a-form-item v-if="form.savePath&&form.savePath.length>0" label="下载短剧" name="downSeries">
<div style="display: flex; align-items: center; gap: 12px;">
<div style="width: 200px;">
<a-switch v-model:checked="form.downSeries" :checked-value="true" :un-checked-value="false" size="default" />
<span style="margin-left:10px;">{{ form.downSeries ? '是' : '否' }}</span>
<a-button @click="openSeriesDownSetModal" shape="circle" type="dashed" style="margin-left:10px;" v-if="form.downSeries"> <setting-outlined />
</a-button>
</div>
<a-alert message="开启后会同步下载收藏的短剧(需要开启短剧同步开关)" :type="form.downSeries?'success':'info'" size="small" style="flex: 1; margin-bottom: 0;" />
</div> </div>
</a-form-item> </a-form-item>
@@ -355,7 +570,7 @@ const downImgVideo = ref(true);
<!-- 关注的存储路径 --> <!-- 关注的存储路径 -->
<a-form-item label="关注的存储路径" name="upSavePath"> <a-form-item label="关注的存储路径" name="upSavePath">
<div style="display: flex; align-items: center; gap: 12px; width: 100%;"> <div style="display: flex; align-items: center; gap: 12px; width: 100%;">
<a-input v-model:value="form.upSavePath" :disabled="form.useSinglePath" placeholder="开启统一存储路径模式后将自动同步收藏路径的值" style="width: 200px;" /> <a-input v-model:value="form.upSavePath" :disabled="form.useSinglePath" placeholder="" style="width: 200px;" />
<a-alert message="不想同步关注列表博主的视频就空着" type="info" size="small" style="flex: 1; margin-bottom: 0;" /> <a-alert message="不想同步关注列表博主的视频就空着" type="info" size="small" style="flex: 1; margin-bottom: 0;" />
</div> </div>
</a-form-item> </a-form-item>
@@ -363,7 +578,7 @@ const downImgVideo = ref(true);
<!-- 图文的存储路径 --> <!-- 图文的存储路径 -->
<a-form-item label="图文的存储路径" name="imgSavePath"> <a-form-item label="图文的存储路径" name="imgSavePath">
<div style="display: flex; align-items: center; gap: 12px; width: 100%;"> <div style="display: flex; align-items: center; gap: 12px; width: 100%;">
<a-input v-model:value="form.imgSavePath" :disabled="form.useSinglePath" placeholder="开启统一存储路径模式后将自动同步收藏路径的值" style="width: 200px;" /> <a-input v-model:value="form.imgSavePath" :disabled="form.useSinglePath" style="width: 200px;" />
<a-alert message="如果系统配置页面开启了同步图文视频,且开启了单独存储,则必填!!!" type="info" size="small" style="flex: 1; margin-bottom: 0;" /> <a-alert message="如果系统配置页面开启了同步图文视频,且开启了单独存储,则必填!!!" type="info" size="small" style="flex: 1; margin-bottom: 0;" />
</div> </div>
</a-form-item> </a-form-item>
@@ -378,6 +593,65 @@ const downImgVideo = ref(true);
</a-form> </a-form>
</a-modal> </a-modal>
<!-- 公用抽屉组件层级高于原有弹窗- 优化后 -->
<a-drawer :title="getDrawerTypeName()+'配置'" v-model:visible="showDrawer" placement="right" width="800px" :z-index="10010" :mask-z-index="10009" @close="closeDrawer" class="common-drawer">
<!-- 抽屉右上角添加保存按钮利用 extra 插槽不改动其他模板 -->
<template #extra>
<a-button type="primary" :loading="drawerPagination.loading" @click="saveDrawerData" class="drawer-save-btn">
<template #icon>
<SaveOutlined />
</template>
保存
</a-button>
</template>
<!-- 抽屉滚动容器绑定ref和滚动样式 -->
<div ref="drawerScrollRef" class="drawer-scroll-container">
<!-- 加载中状态 -->
<div v-if="drawerPagination.loading && drawerDataList.length === 0" class="drawer-loading">
<Spin size="large" />
</div>
<!-- 卡片网格展示 - 优化布局横向一行展示名称保存路径 -->
<a-card v-else :bordered="false" class="drawer-card-container grid-container">
<a-card-grid v-for="(item, index) in drawerDataList" :key="item.Id" class="drawer-card-grid">
<!-- 竖向封面移除预览功能仅保留基础展示 -->
<div class="grid-cover vertical-cover" v-if="drawerType!='collect'">
<a-image :preview="false" :src="item.CoverUrl" fallback="https://placeholder.picsum.photos/120/180" fit="cover" />
</div>
<!-- 名称横向一行展示标签 + 内容 在同一行 -->
<div class="grid-item horizontal-item name">
<label class="drawer-label">名称</label>
<span>{{ item.Name || '未命名' }}</span>
</div>
<!-- 保存文件夹横向一行展示标签 + 输入框 在同一行 -->
<div class="grid-item horizontal-item save-folder">
<label class="drawer-label">保存路径</label>
<a-input v-model:value="item.SaveFolder" size="small" placeholder="请输入保存路径" class="save-path-input" />
</div>
<!-- 同步开关保持原有逻辑横向对齐 -->
<div class="grid-item horizontal-item sync-switch">
<label class="drawer-label">是否同步</label>
<a-switch :checked="item.Sync" @change="() => toggleDrawerItemSync(item, index)" size="small" />
</div>
</a-card-grid>
</a-card>
<!-- 无更多数据提示 -->
<div v-if="!drawerPagination.hasMore && drawerDataList.length > 0" class="no-more-data">
已加载全部{{ getDrawerTypeName() }}数据
</div>
<!-- 加载下一页中 -->
<div v-if="drawerPagination.loading && drawerDataList.length > 0" class="loading-more">
<Spin size="small" />
<span>加载中...</span>
</div>
</div>
</a-drawer>
<!-- 成员表格 --> <!-- 成员表格 -->
<a-table v-bind="$attrs" :columns="columns" :dataSource="dataSource" :pagination="false"> <a-table v-bind="$attrs" :columns="columns" :dataSource="dataSource" :pagination="false">
<template #title> <template #title>
@@ -399,11 +673,16 @@ const downImgVideo = ref(true);
</template> </template>
<template #bodyCell="{ column, text, record }"> <template #bodyCell="{ column, text, record }">
<template v-if="column.dataIndex === 'status'"> <template v-if="column.dataIndex === 'status'">
<a-badge class="text-subtext" :color="text === 1 ? 'green' : 'red'"> <!-- a-switch 显示状态绑定切换逻辑 -->
<template #text> <div style="display: flex; align-items: center; gap: 8px;">
<span class="text-subtext">{{ StatusDict[text as Status] }}</span> <a-switch v-model:checked="record.status" :checked-value="1" :un-checked-value="0" size="small" :disabled="loading" @change="() => switchSyncStatus(record)" />
</template> <span :style="{
</a-badge> fontSize: '12px',
color: record.status === 1 ? '#52c41a' : '#ff4d4f'
}">
{{ StatusDict[record.status] }}
</span>
</div>
</template> </template>
<template v-else-if="column.dataIndex === 'cookies'"> <template v-else-if="column.dataIndex === 'cookies'">
<a-button @click="showCookies(record)">查看</a-button> <a-button @click="showCookies(record)">查看</a-button>
@@ -412,19 +691,7 @@ const downImgVideo = ref(true);
<a-button @click="showUpers(record)">查看</a-button> <a-button @click="showUpers(record)">查看</a-button>
</template> </template>
<template v-else-if="column.dataIndex === 'edit'"> <template v-else-if="column.dataIndex === 'edit'">
<!-- 同步状态切换按钮 --> <!-- 已删除开启/停止按钮仅保留编辑和删除 -->
<a-button :disabled="loading" type="link" @click="switchSyncStatus(record)" :style="{ color: record.status === 1 ? '#ff4d4f' : 'green' }">
<template #icon>
<span v-if="record.status === 1" style="margin-right:5px;">
<StopOutlined />
</span>
<span v-else style="margin-right:5px;">
<ClockCircleOutlined />
</span>
</template>
{{ record.status === 1 ? '停止同步' : '开启同步' }}
</a-button>
<a-button :disabled="showModal || loading" type="link" @click="edit(record)"> <a-button :disabled="showModal || loading" type="link" @click="edit(record)">
<template #icon> <template #icon>
<EditFilled /> <EditFilled />
@@ -459,8 +726,8 @@ const downImgVideo = ref(true);
</div> </div>
</a-modal> </a-modal>
</template> </template>
<style scoped lang="less">
<style scoped> // 原有非抽屉样式(保留,不改动)
.cookie-content { .cookie-content {
white-space: pre-wrap; white-space: pre-wrap;
word-break: break-all; word-break: break-all;
@@ -526,16 +793,168 @@ const downImgVideo = ref(true);
} }
/* 修复:移除对alert的自定义样式修改,还原官方默认样式 */ /* 修复:移除对alert的自定义样式修改,还原官方默认样式 */
/* 删除了原有的ant-alert-small和ant-alert-message自定义样式,避免覆盖官方主题 */
/* 如需调整alert间距,仅修改外层容器,不修改alert内部样式 */
.alert-wrapper { .alert-wrapper {
flex: 1; flex: 1;
margin-bottom: 0 !important; margin-bottom: 0 !important;
} }
// ========== 精准匹配模板:a-card-grid 样式优化 ==========
/* 父容器:解决卡片间隙,避免换行(不改动模板,仅样式控制) */
.drawer-card-container.grid-container {
// 清除 a-card 自带内边距,避免与卡片间隙冲突
:deep(.ant-card-body) {
padding: 16px;
margin: 0;
}
// 启用 Flex 布局,实现卡片均匀间隙(核心:gap 不与组件自带样式冲突)
display: flex;
flex-wrap: wrap;
gap: 20px; /* 卡片之间的横向/纵向间隙(可自定义,不会换行) */
box-sizing: border-box;
}
/* a-card-grid 核心样式:圆角 + 固定宽度 + 内边距 */
:deep(.drawer-card-grid) {
// 精确宽度计算:3列均分,减去 gap 分摊值,避免换行
width: calc(33.333% - 10.333px) !important; /* 20px gap 分摊到3列,每列减 ~13.333px */
margin: 5px !important; /* 清除组件自带 margin,避免间隙重复 */
border-radius: 12px !important; /* 卡片圆角(可自定义大小) */
padding: 16px !important; /* 卡片内部整体内边距 */
box-sizing: border-box;
border: 1px solid #f0f0f0; /* 卡片边框,增强圆角视觉感 */
// 卡片内部竖向排列,确保每个内容块独占一行
display: flex;
flex-direction: column;
gap: 12px; /* 卡片内部元素之间的间距(可自定义) */
}
/* 图片容器:横向铺满卡片 + 自带内边距 */
:deep(.drawer-card-grid .grid-cover.vertical-cover) {
width: 100% !important; /* 横向铺满卡片 */
padding: 4px; /* 图片内部内边距(可自定义,实现图片与卡片边框的间距) */
box-sizing: border-box;
border-radius: 8px; /* 图片容器轻微圆角,与卡片圆角呼应 */
overflow: hidden;
}
/* 图片:强制铺满容器,不拉伸 */
:deep(.drawer-card-grid .vertical-cover .ant-image) {
width: 100% !important;
height: auto !important; /* 高度自适应,保持图片比例 */
display: block;
}
:deep(.drawer-card-grid .vertical-cover .ant-image-img) {
width: 100% !important;
height: 100% !important;
object-fit: cover !important; /* 保持图片比例,裁剪多余部分 */
}
/* 名称、保存路径、同步开关:独占一行样式 */
:deep(.drawer-card-grid .grid-item.horizontal-item) {
width: 100% !important; /* 独占一行,横向铺满卡片 */
display: flex;
align-items: center; /* 标签与内容垂直居中 */
margin: 0 !important; /* 清除多余间距,确保独占一行 */
padding: 4px 0; /* 上下轻微内边距,增强可读性 */
}
// 亮色模式(保留)
:deep(.drawer-label) {
flex-shrink: 0;
font-size: 12px;
color: rgba(0, 0, 0, 0.6);
}
/* 名称内容、输入框:占满剩余宽度 */
:deep(.drawer-card-grid .horizontal-item span) {
flex: 1;
font-size: 12px;
color: rgba(0, 0, 0, 0.88);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
:deep(.drawer-card-grid .horizontal-item .save-path-input) {
flex: 1;
width: 100% !important;
font-size: 12px;
}
/* 同步开关:两端对齐,保持独占一行 */
:deep(.drawer-card-grid .sync-switch) {
justify-content: space-between; /* 标签左对齐,开关右对齐 */
}
/* 响应式适配:小屏幕自动调整列数,保持间隙不换行 */
@media (max-width: 768px) {
:deep(.drawer-card-grid) {
width: calc(50% - 10px) !important; /* 2列均分,20px gap 每列减10px */
}
}
@media (max-width: 480px) {
:deep(.drawer-card-grid) {
width: 100% !important; /* 1列铺满,无间距分摊 */
}
}
// ========== 黑暗模式样式(html.dark-mode + 链式类名,光效增强 + hover 效果) ==========
/* 卡片:深色背景 + 隐式边框 + 增强光效(默认状态) */
html.dark-mode .drawer-card-container.grid-container .drawer-card-grid {
border-color: rgba(142, 140, 140, 0.1) !important; /* 边框透明化(隐掉) */
background-color: #1a1a2e !important;
/* 增强光效:双层阴影+浅蓝紫微光,更醒目且不刺眼(核心修改) */
box-shadow: 0 6px 16px rgba(0, 20, 60, 0.4),
/* 主阴影:加深蓝紫调,增大模糊半径,光效更明显 */ 0 2px 6px rgba(100, 120, 255, 0.2),
/* 辅阴影:新增浅蓝紫微光,光效更突出 */ inset 0 1px 0 rgba(255, 255, 255, 0.05) !important; /* 内阴影:轻微高光,增强卡片质感 */
/* 可选:完全隐藏边框 */
/* border: none !important; */
transition: all 0.3s ease-in-out !important; /* 过渡动画:hover 效果平滑切换,不生硬 */
}
/* 卡片 hover 效果:悬浮时光效更突出,层次感拉满 */
html.dark-mode .drawer-card-container.grid-container .drawer-card-grid:hover {
box-shadow: 0 8px 24px rgba(0, 30, 80, 0.5),
/* 主阴影:进一步加深、扩大,立体感更强 */ 0 4px 12px rgba(120, 140, 255, 0.35),
/* 辅阴影:蓝紫微光更亮,光效更醒目 */ inset 0 1px 0 rgba(255, 255, 255, 0.08) !important; /* 内阴影:高光增强,质感更优 */
transform: translateY(-2px) !important; /* 可选:轻微上浮,增强交互感(可删除) */
}
/* label:强制纯白色(核心需求,格式不变) */
html.dark-mode .drawer-card-container.grid-container .drawer-card-grid .horizontal-item label {
color: #ffffff !important;
}
/* 名称内容:浅白色(格式不变) */
html.dark-mode .drawer-card-container.grid-container .drawer-card-grid .horizontal-item span {
color: rgba(255, 255, 255, 0.88) !important;
}
/* 输入框:深色适配(格式不变) */
html.dark-mode .drawer-card-container.grid-container .drawer-card-grid .ant-input {
background-color: #2f2f2f !important;
border-color: #404040 !important;
color: rgba(255, 255, 255, 0.88) !important;
}
</style> </style>
<!-- 新增全局样式块确保alert样式不受scoped影响仅针对alert还原默认 --> <!-- 新增全局样式块确保alert样式不受scoped影响仅针对alert还原默认 -->
<style> <style lang="less">
.full-modal {
.ant-modal {
max-width: 100%;
top: 0;
padding-bottom: 0;
margin: 0;
}
.ant-modal-content {
display: flex;
flex-direction: column;
height: calc(100vh);
}
.ant-modal-body {
flex: 1;
}
}
/* 还原Ant Design Vue alert官方默认样式,消除scoped样式的间接影响 */ /* 还原Ant Design Vue alert官方默认样式,消除scoped样式的间接影响 */
.ant-alert { .ant-alert {
box-sizing: border-box; box-sizing: border-box;
@@ -563,6 +982,15 @@ const downImgVideo = ref(true);
.ant-alert-info .ant-alert-message { .ant-alert-info .ant-alert-message {
color: #1677ff; color: #1677ff;
} }
/* 还原alert不同类型的官方默认颜色 */
.ant-alert-success {
background-color: #daf1d3;
border: 1px solid #5bbc51;
}
.ant-alert-success .ant-alert-message {
color: #228b22;
}
.ant-alert-warning { .ant-alert-warning {
background-color: #fffbe6; background-color: #fffbe6;
border: 1px solid #ffe58f; border: 1px solid #ffe58f;
-22
View File
@@ -1,26 +1,6 @@
<template> <template>
<a-drawer v-model:visible="visible" class="custom-class" title="个人设置" placement="right" @after-visible-change="afterVisibleChange" :maskClosable="true"> <a-drawer v-model:visible="visible" class="custom-class" title="个人设置" placement="right" @after-visible-change="afterVisibleChange" :maskClosable="true">
<a-tabs v-model:activeKey="activeKey"> <a-tabs v-model:activeKey="activeKey">
<!-- <a-tab-pane key="1" style="height:100%">
<template #tab>
<span>
<user-outlined />
修改头像
</span>
</template>
<a-upload style="" v-model:file-list="fileList" name="file" list-type="picture-card" class="avatar-uploader" :show-upload-list="false" :action="uploadAction" :before-upload="beforeUpload" @change="handleChange" accept=".jpg, .jpeg, .png">
<img v-if="imageUrl" :src="imageUrl" alt="avatar" style="height: 112px; width: 112px; border-radius: 50%;" />
<div v-else>
<loading-outlined v-if="loading"></loading-outlined>
<plus-outlined v-else></plus-outlined>
<div class="ant-upload-text">选择图片</div>
</div>
</a-upload>
<div style="margin-top:20px;">
上传成功即修改成功
</div>
</a-tab-pane> -->
<a-tab-pane key="2"> <a-tab-pane key="2">
<template #tab> <template #tab>
<span> <span>
@@ -60,7 +40,6 @@ import { checkPass } from '@/utils/regexHelper';
import type { Rule } from 'ant-design-vue/es/form'; import type { Rule } from 'ant-design-vue/es/form';
const activeKey = ref<string>('2'); const activeKey = ref<string>('2');
const uploadAction = ref<string>('');
const visible = ref<boolean>(false); const visible = ref<boolean>(false);
function show(vis: boolean) { function show(vis: boolean) {
@@ -122,7 +101,6 @@ const loadUserInfo = () => {
if (res.code === 0) { if (res.code === 0) {
if (res.data.avatar != null && res.data.avatar !== '') imageUrl.value = `/upload/${res.data.avatar}`; if (res.data.avatar != null && res.data.avatar !== '') imageUrl.value = `/upload/${res.data.avatar}`;
passwordFormData.UserId = res.data.id; passwordFormData.UserId = res.data.id;
uploadAction.value = `/api/auth/UpdateUserAvatar?Uid=${res.data.id}`;
} }
}); });
}; };
+23 -33
View File
@@ -151,15 +151,6 @@ export const useApiStore = defineStore('coreapi', () => {
}); });
} }
async function GetAppPort() {
return http.request<any, Response<any>>('/api/config/appport', 'get').then(r => {
return r;
}).finally(() => {
});
}
async function deleteCookie(id: string) { async function deleteCookie(id: string) {
return http.request<any, Response<any>>('/api/config/delete?id=' + id, 'get').then(r => { return http.request<any, Response<any>>('/api/config/delete?id=' + id, 'get').then(r => {
@@ -347,28 +338,28 @@ export const useApiStore = defineStore('coreapi', () => {
} }
// 音频文件上传接口 // // 音频文件上传接口
async function apiUploadAudio(formData: FormData, options?: { onUploadProgress?: (progressEvent: ProgressEvent) => void }) { // async function apiUploadAudio(formData: FormData, options?: { onUploadProgress?: (progressEvent: ProgressEvent) => void }) {
return http // return http
.request<any, Response<any>>( // .request<any, Response<any>>(
'/api/config/UploadAudio', // 请求地址 // '/api/config/UploadAudio', // 请求地址
'post_form', // 使用新增的 post_form 类型 // 'post_form', // 使用新增的 post_form 类型
formData, // FormData 参数(文件+其他参数) // formData, // FormData 参数(文件+其他参数)
{ // {
onUploadProgress: options?.onUploadProgress, // 上传进度回调(原生 ProgressEvent // onUploadProgress: options?.onUploadProgress, // 上传进度回调(原生 ProgressEvent
timeout: 120000 // 上传文件超时时间设为2分钟(可选) // timeout: 120000 // 上传文件超时时间设为2分钟(可选)
} // }
) // )
.then((res) => { // .then((res) => {
// console.log('音频上传结果:', res); // // console.log('音频上传结果:', res);
// 适配你的响应格式(如果响应是包裹层,取 data) // // 适配你的响应格式(如果响应是包裹层,取 data)
return res; // return res;
}) // })
.catch((err) => { // .catch((err) => {
console.error('音频上传失败:', err); // console.error('音频上传失败:', err);
throw err; // 抛出错误让前端捕获 // throw err; // 抛出错误让前端捕获
}); // });
} // }
return { return {
getVer, getVer,
@@ -376,8 +367,7 @@ export const useApiStore = defineStore('coreapi', () => {
BathRealDelete, BathRealDelete,
DeleteByAuthor, DeleteByAuthor,
Renfo, Renfo,
apiUploadAudio, // apiUploadAudio,
GetAppPort,
AppisInit, AppisInit,
DeskInitAsync, DeskInitAsync,
SwitchCookieStatus, SwitchCookieStatus,
+1 -1
View File
@@ -1,4 +1,4 @@
using dy.net.dto; using dy.net.model.dto;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using System.Net; using System.Net;
+1 -1
View File
@@ -1,4 +1,4 @@
using dy.net.dto; using dy.net.model.dto;
using System.ComponentModel; using System.ComponentModel;
using System.Reflection; using System.Reflection;
+11 -93
View File
@@ -91,7 +91,7 @@ namespace dy.net.extension
string conn = $"DataSource={filePath}"; string conn = $"DataSource={filePath}";
if (!File.Exists(filePath)) if (!File.Exists(filePath))
{ {
File.Create(filePath).Close();//.Close(); File.Create(filePath).Close();
} }
return conn; return conn;
@@ -166,7 +166,7 @@ namespace dy.net.extension
Type[] types = assembly.GetTypes(); // 获取程序集中的所有类型 Type[] types = assembly.GetTypes(); // 获取程序集中的所有类型
var targetClasses = types var targetClasses = types
.Where(t => t.Namespace != null && t.Namespace.StartsWith("dy.net.model")) .Where(t => t.Namespace != null && t.Namespace.StartsWith("dy.net.model.entity"))
.ToList(); .ToList();
db.CodeFirst.InitTables(targetClasses.ToArray()); db.CodeFirst.InitTables(targetClasses.ToArray());
}); });
@@ -193,59 +193,11 @@ namespace dy.net.extension
} }
//public static void AddHttpClients(this IServiceCollection services)
//{
// services.AddHttpClient("dy_collect", client =>
// {
// client.DefaultRequestHeaders.Add("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
// client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36");
// client.DefaultRequestHeaders.Add("Referer", "https://www.douyin.com");
// });
// services.AddHttpClient("dy_follow", client =>
// {
// client.DefaultRequestHeaders.Referrer = new Uri("https://www.douyin.com/user/self?showTab=like");
// });
// services.AddHttpClient("dy_favorite", client =>
// {
// client.DefaultRequestHeaders.Referrer = new Uri("https://www.douyin.com/user/self?showTab=like");
// });
// services.AddHttpClient("dy_uper", client =>
// {
// client.DefaultRequestHeaders.Referrer = new Uri("https://www.douyin.com/user/MS4wLjABAAAA1zFIBhWG-3qS8MiggDMhyCpqDnvfGYf_mtsdgtBzV7A?from_tab_name=main&showTab=post&vid=7576282367263807451");
// });
// // 配置HttpClientStartup.cs或Program.cs
// services.AddHttpClient("dy_download")
// .ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
// {
// // 控制并发连接数(根据服务器承受能力调整,建议5-20)
// MaxConnectionsPerServer = 5,
// // 禁用代理自动检测(减少不必要的延迟)
// UseProxy = false,
// // 连接超时(建立连接的超时时间)
// ConnectTimeout = TimeSpan.FromSeconds(60)
// })
// .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
// {
// ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true
// })
// // 配置客户端默认请求头
// .ConfigureHttpClient(client =>
// {
// client.DefaultRequestHeaders.Add("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
// client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36");
// client.DefaultRequestHeaders.Add("Referer", "https://www.douyin.com");
// });
//}
public static void AddHttpClients(this IServiceCollection services) public static void AddHttpClients(this IServiceCollection services)
{ {
// 通用的忽略SSL证书验证的HttpMessageHandler配置 // 通用的忽略SSL证书验证的HttpMessageHandler配置
Func<HttpMessageHandler> ignoreSslHandlerFactory = () => static HttpMessageHandler ignoreSslHandlerFactory()
{ {
var handler = new SocketsHttpHandler var handler = new SocketsHttpHandler
{ {
@@ -254,7 +206,7 @@ namespace dy.net.extension
// 禁用代理自动检测(减少不必要的延迟) // 禁用代理自动检测(减少不必要的延迟)
UseProxy = false, UseProxy = false,
// 连接超时(建立连接的超时时间) // 连接超时(建立连接的超时时间)
ConnectTimeout = TimeSpan.FromSeconds(60), ConnectTimeout = TimeSpan.FromSeconds(120),
// 忽略HTTPS证书验证 // 忽略HTTPS证书验证
SslOptions = new SslClientAuthenticationOptions SslOptions = new SslClientAuthenticationOptions
{ {
@@ -263,56 +215,22 @@ namespace dy.net.extension
}; };
return handler; return handler;
}; }
// 抖音数据接口请求客户端
// 抖音采集客户端 services.AddHttpClient(DouyinRequestParamManager.DY_HTTP_CLIENT, client =>
services.AddHttpClient("dy_collect", client =>
{ {
client.DefaultRequestHeaders.Add("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2"); client.DefaultRequestHeaders.Add("User-Agent", DouyinRequestParamManager.DY_USER_AGENT);
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36");
client.DefaultRequestHeaders.Add("Referer", "https://www.douyin.com");
}).ConfigurePrimaryHttpMessageHandler(ignoreSslHandlerFactory);
// 抖音关注客户端
services.AddHttpClient("dy_follow", client =>
{
client.DefaultRequestHeaders.Referrer = new Uri("https://www.douyin.com/user/self?showTab=like");
}).ConfigurePrimaryHttpMessageHandler(ignoreSslHandlerFactory);
// 抖音收藏客户端
services.AddHttpClient("dy_favorite", client =>
{
client.DefaultRequestHeaders.Referrer = new Uri("https://www.douyin.com/user/self?showTab=like");
}).ConfigurePrimaryHttpMessageHandler(ignoreSslHandlerFactory);
// 抖音UP主客户端
services.AddHttpClient("dy_uper", client =>
{
client.DefaultRequestHeaders.Referrer = new Uri("https://www.douyin.com/user/MS4wLjABAAAA1zFIBhWG-3qS8MiggDMhyCpqDnvfGYf_mtsdgtBzV7A?from_tab_name=main&showTab=post&vid=7576282367263807451");
}).ConfigurePrimaryHttpMessageHandler(ignoreSslHandlerFactory); }).ConfigurePrimaryHttpMessageHandler(ignoreSslHandlerFactory);
// 抖音下载客户端(单独配置,保持原有特性) // 抖音下载客户端(单独配置,保持原有特性)
services.AddHttpClient("dy_download") services.AddHttpClient(DouyinRequestParamManager.DY_HTTP_CLIENT_DOWN)
.ConfigurePrimaryHttpMessageHandler(ignoreSslHandlerFactory) .ConfigurePrimaryHttpMessageHandler(ignoreSslHandlerFactory)
.ConfigureHttpClient(client => .ConfigureHttpClient(client =>
{ {
client.DefaultRequestHeaders.Add("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2"); client.DefaultRequestHeaders.Add("User-Agent", DouyinRequestParamManager.DY_USER_AGENT);
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36");
client.DefaultRequestHeaders.Add("Referer", "https://www.douyin.com"); client.DefaultRequestHeaders.Add("Referer", "https://www.douyin.com");
}); });
// 如果你需要兼容旧版.NET(使用HttpClientHandler而非SocketsHttpHandler),可以使用以下配置:
// Func<HttpMessageHandler> legacyIgnoreSslHandlerFactory = () =>
// {
// var handler = new HttpClientHandler
// {
// ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true,
// MaxConnectionsPerServer = 5,
// UseProxy = false,
// ConnectTimeout = TimeSpan.FromSeconds(60)
// };
// return handler;
// };
} }
/// <summary> /// <summary>
@@ -346,7 +264,7 @@ namespace dy.net.extension
{ {
// 获取服务的生命周期(优先使用特性,默认 Transient) // 获取服务的生命周期(优先使用特性,默认 Transient)
var lifetime = type.GetCustomAttribute<ServiceLifetimeAttribute>()?.Lifetime var lifetime = type.GetCustomAttribute<ServiceLifetimeAttribute>()?.Lifetime
?? ServiceLifetime.Transient; ?? ServiceLifetime.Scoped;
// 查找该类实现的接口(优先注册为接口服务) // 查找该类实现的接口(优先注册为接口服务)
//var interfaces = type.GetInterfaces() //var interfaces = type.GetInterfaces()
+1 -1
View File
@@ -1,4 +1,4 @@
using dy.net.dto; using dy.net.model.dto;
using dy.net.service; using dy.net.service;
using Quartz; using Quartz;
using Serilog; using Serilog;
+30 -11
View File
@@ -1,5 +1,6 @@
using dy.net.dto; using dy.net.model.dto;
using dy.net.model; using dy.net.model.entity;
using dy.net.model.response;
using dy.net.service; using dy.net.service;
using dy.net.utils; using dy.net.utils;
using System; using System;
@@ -36,21 +37,26 @@ namespace dy.net.job
} }
protected override bool IsCookieValid(DouyinCookie cookie) protected override bool IsCookieValid(DouyinCookie cookie)
{ {
return !string.IsNullOrWhiteSpace(cookie.Cookies)&& !string.IsNullOrWhiteSpace(cookie.SavePath); return !string.IsNullOrWhiteSpace(cookie.Cookies)&& !string.IsNullOrWhiteSpace(cookie.SavePath);
} }
protected override async Task<DouyinVideoInfo> FetchVideoData(DouyinCookie cookie, string cursor,string uperUid) protected override async Task<DouyinVideoInfoResponse> FetchVideoData(DouyinCookie cookie, string cursor, DouyinFollowed followed,DouyinCollectItem collectItem=null)
{ {
if (cookie.UseCollectFolder && collectItem != null && !string.IsNullOrWhiteSpace(collectItem.CollectsId))
{
return await douyinHttpClientService.SyncCollectVideosByCollectId(cursor, count, cookie.Cookies, collectItem);
}
return await douyinHttpClientService.SyncCollectVideos(cursor, count, cookie.Cookies); return await douyinHttpClientService.SyncCollectVideos(cursor, count, cookie.Cookies);
} }
protected override bool ShouldContinueSync(DouyinCookie cookie, DouyinVideoInfo data, DouyinFollowed followed = null) protected override bool ShouldContinueSync(DouyinCookie cookie, DouyinVideoInfoResponse data, DouyinFollowed followed = null)
{ {
return data != null && data.HasMore == 1 && cookie.CollHasSyncd == 0; return data != null && data.HasMore == 1 && cookie.CollHasSyncd == 0;
} }
protected override string GetNextCursor(DouyinVideoInfo data) protected override string GetNextCursor(DouyinVideoInfoResponse data)
{ {
return data?.Cursor ?? "0"; return data?.Cursor ?? "0";
} }
@@ -80,13 +86,26 @@ namespace dy.net.job
return new VideoEntityDifferences(); return new VideoEntityDifferences();
} }
protected override string CreateSaveFolder(DouyinCookie cookie, Aweme item, AppConfig config, DouyinFollowed followed) protected override string CreateSaveFolder(DouyinCookie cookie, Aweme item, AppConfig config, DouyinFollowed followed, DouyinCollectItem collectItem)
{ {
var (tag1, _, _) = GetVideoTags(item); if(collectItem!=null&&cookie.UseCollectFolder &&!string.IsNullOrWhiteSpace(collectItem.CollectsId))
var safeTag1 = string.IsNullOrWhiteSpace(tag1) ? "other" : DouyinFileNameHelper.SanitizeLinuxFileName(tag1,"",true); {
var folder = Path.Combine(cookie.SavePath, safeTag1, $"{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId,true)}"); var safeCollectName = DouyinFileNameHelper.SanitizeLinuxFileName(collectItem.CollectsName, "", true);
if (!Directory.Exists(folder)) Directory.CreateDirectory(folder); var folderCollect = Path.Combine(cookie.SavePath, safeCollectName);
return folder; var safeVideoDesc = DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId, true);
var folder = Path.Combine(folderCollect, safeVideoDesc);
if (!Directory.Exists(folder)) Directory.CreateDirectory(folder);
return folder;
}
else
{
var (tag1, _, _) = GetVideoTags(item);
var safeTag1 = string.IsNullOrWhiteSpace(tag1) ? "other" : DouyinFileNameHelper.SanitizeLinuxFileName(tag1, "", true);
var folder = Path.Combine(cookie.SavePath, safeTag1, $"{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId, true)}");
if (!Directory.Exists(folder)) Directory.CreateDirectory(folder);
return folder;
}
} }
} }
} }
+7 -9
View File
@@ -1,10 +1,8 @@
using dy.net.dto; using dy.net.model.dto;
using dy.net.model; using dy.net.model.entity;
using dy.net.model.response;
using dy.net.service; using dy.net.service;
using dy.net.utils; using dy.net.utils;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace dy.net.job namespace dy.net.job
{ {
@@ -32,17 +30,17 @@ namespace dy.net.job
!string.IsNullOrWhiteSpace(cookie.SecUserId) && cookie.SecUserId.Length >= 10; !string.IsNullOrWhiteSpace(cookie.SecUserId) && cookie.SecUserId.Length >= 10;
} }
protected override async Task<DouyinVideoInfo> FetchVideoData(DouyinCookie cookie, string cursor,string uperUid) protected override async Task<DouyinVideoInfoResponse> FetchVideoData(DouyinCookie cookie, string cursor,DouyinFollowed followed, DouyinCollectItem collectId)
{ {
return await douyinHttpClientService.SyncFavoriteVideos(count, cursor, cookie.SecUserId, cookie.Cookies); return await douyinHttpClientService.SyncFavoriteVideos(count, cursor, cookie.SecUserId, cookie.Cookies);
} }
protected override bool ShouldContinueSync(DouyinCookie cookie, DouyinVideoInfo data, DouyinFollowed followed=null) protected override bool ShouldContinueSync(DouyinCookie cookie, DouyinVideoInfoResponse data, DouyinFollowed followed=null)
{ {
return data != null && data.HasMore == 1 && cookie.FavHasSyncd == 0; return data != null && data.HasMore == 1 && cookie.FavHasSyncd == 0;
} }
protected override string GetNextCursor(DouyinVideoInfo data) protected override string GetNextCursor(DouyinVideoInfoResponse data)
{ {
return data?.MaxCursor ?? "0"; return data?.MaxCursor ?? "0";
} }
@@ -67,7 +65,7 @@ namespace dy.net.job
} }
} }
protected override string CreateSaveFolder(DouyinCookie cookie, Aweme item, AppConfig config, DouyinFollowed followed) protected override string CreateSaveFolder(DouyinCookie cookie, Aweme item, AppConfig config, DouyinFollowed followed, DouyinCollectItem collectItem)
{ {
var (tag1, _, _) = GetVideoTags(item); var (tag1, _, _) = GetVideoTags(item);
var safeTag1 = string.IsNullOrWhiteSpace(tag1) ? "other" : DouyinFileNameHelper.SanitizeLinuxFileName(tag1,"",true); var safeTag1 = string.IsNullOrWhiteSpace(tag1) ? "other" : DouyinFileNameHelper.SanitizeLinuxFileName(tag1,"",true);
+84 -51
View File
@@ -1,17 +1,12 @@
using ClockSnowFlake; using ClockSnowFlake;
using dy.net.dto; using dy.net.model.dto;
using dy.net.model; using dy.net.model.entity;
using dy.net.model.response;
using dy.net.service; using dy.net.service;
using dy.net.utils; using dy.net.utils;
using Newtonsoft.Json; using Newtonsoft.Json;
using Quartz; using Quartz;
using Quartz.Util;
using Serilog; using Serilog;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace dy.net.job namespace dy.net.job
{ {
@@ -133,26 +128,22 @@ namespace dy.net.job
/// <returns>一个表示异步操作的任务</returns> /// <returns>一个表示异步操作的任务</returns>
public async Task Execute(IJobExecutionContext context) public async Task Execute(IJobExecutionContext context)
{ {
// 1. 获取应用配置 //if (VideoType != VideoTypeEnum.dy_follows)
// return;
// 获取应用配置
var config = douyinCommonService.GetConfig(); var config = douyinCommonService.GetConfig();
if (config == null) if (config == null)
{ {
Log.Debug($"{VideoType}-未获取到系统配置,任务终止!!!"); Log.Debug($"{VideoType}-未获取到系统配置,任务终止!!!");
return; return;
} }
//if(VideoType!= VideoTypeEnum.dy_follows)
//{
// return;
//}
// 2. 从配置中获取每页请求数量--固定18
//if (config.BatchCount > 0)
// count = config.BatchCount.ToString();
// 3. 在处理Cookie之前执行的预处理操作 // 在处理Cookie之前执行的预处理
await BeforeProcessCookies(); await BeforeProcessCookies();
// 4. 获取所有有效的Cookie // 获取所有有效的Cookie
var cookies = await GetValidCookies(); var cookies = await GetValidCookies();
if (cookies == null || !cookies.Any()) if (cookies == null || !cookies.Any())
{ {
@@ -161,7 +152,7 @@ namespace dy.net.job
} }
Log.Debug($"{VideoType}-共发现{cookies.Count}个有效的cookie,同步即将开始..."); Log.Debug($"{VideoType}-共发现{cookies.Count}个有效的cookie,同步即将开始...");
// 6. 遍历每个有效的Cookie,执行同步操作 // 遍历每个有效的Cookie,执行同步
foreach (var cookie in cookies) foreach (var cookie in cookies)
{ {
await ProcessSyncUserCookie(cookie, config); await ProcessSyncUserCookie(cookie, config);
@@ -202,8 +193,9 @@ namespace dy.net.job
/// <param name="cookie">用户Cookie</param> /// <param name="cookie">用户Cookie</param>
/// <param name="cursor">分页游标,用于获取下一页数据</param> /// <param name="cursor">分页游标,用于获取下一页数据</param>
/// <param name="uperUid">关注的人</param> /// <param name="uperUid">关注的人</param>
/// <param name="collectId">收藏夹ID</param>
/// <returns>视频信息对象,包含视频列表和分页信息</returns> /// <returns>视频信息对象,包含视频列表和分页信息</returns>
protected abstract Task<DouyinVideoInfo> FetchVideoData(DouyinCookie cookie, string cursor, string uperUid = ""); protected abstract Task<DouyinVideoInfoResponse> FetchVideoData(DouyinCookie cookie, string cursor, DouyinFollowed uperUid , DouyinCollectItem collectId);
/// <summary> /// <summary>
/// 判断是否应该继续同步下一页数据 /// 判断是否应该继续同步下一页数据
@@ -213,7 +205,7 @@ namespace dy.net.job
/// <param name="data">当前获取到的视频数据</param> /// <param name="data">当前获取到的视频数据</param>
/// <param name="followed">关注博主</param> /// <param name="followed">关注博主</param>
/// <returns>如果应该继续同步,则为true;否则为false</returns> /// <returns>如果应该继续同步,则为true;否则为false</returns>
protected abstract bool ShouldContinueSync(DouyinCookie cookie, DouyinVideoInfo data, DouyinFollowed followed); protected abstract bool ShouldContinueSync(DouyinCookie cookie, DouyinVideoInfoResponse data, DouyinFollowed followed);
/// <summary> /// <summary>
/// 获取下一页数据的游标 /// 获取下一页数据的游标
@@ -221,7 +213,7 @@ namespace dy.net.job
/// </summary> /// </summary>
/// <param name="data">当前获取到的视频数据</param> /// <param name="data">当前获取到的视频数据</param>
/// <returns>下一页数据的游标</returns> /// <returns>下一页数据的游标</returns>
protected abstract string GetNextCursor(DouyinVideoInfo data); protected abstract string GetNextCursor(DouyinVideoInfoResponse data);
/// <summary> /// <summary>
/// 创建视频保存文件夹 /// 创建视频保存文件夹
@@ -230,9 +222,10 @@ namespace dy.net.job
/// <param name="cookie">用户Cookie</param> /// <param name="cookie">用户Cookie</param>
/// <param name="item">视频信息</param> /// <param name="item">视频信息</param>
/// <param name="followed">关注用户</param> /// <param name="followed">关注用户</param>
/// <param name="collectItem">收藏夹Item</param>
/// <param name="config">应用配置</param> /// <param name="config">应用配置</param>
/// <returns>创建的视频保存文件夹路径</returns> /// <returns>创建的视频保存文件夹路径</returns>
protected abstract string CreateSaveFolder(DouyinCookie cookie, Aweme item, AppConfig config, DouyinFollowed followed); protected abstract string CreateSaveFolder(DouyinCookie cookie, Aweme item, AppConfig config, DouyinFollowed followed,DouyinCollectItem collectItem);
/// <summary> /// <summary>
/// 获取视频文件名,默认就用id作文件名 /// 获取视频文件名,默认就用id作文件名
@@ -279,7 +272,6 @@ namespace dy.net.job
/// <summary> /// <summary>
/// 获取NFO文件中的图片(如海报)文件名 /// 获取NFO文件中的图片(如海报)文件名
/// 子类可以重写此方法来自定义NFO图片的命名规则
/// </summary> /// </summary>
/// <param name="cookie">当前操作的Cookie</param> /// <param name="cookie">当前操作的Cookie</param>
/// <param name="item">视频信息</param> /// <param name="item">视频信息</param>
@@ -343,16 +335,57 @@ namespace dy.net.job
} }
else else
{ {
int syncCount = 0; // 本次同步成功的视频数量 // 仅在视频类型为抖音收藏时执行对应逻辑
string cursor = "0"; // 初始游标 if (VideoType == VideoTypeEnum.dy_collects)
bool hasMore = true; // 是否还有更多数据 {
(syncCount, cursor, hasMore) = await GetViedos(cookie, config, syncCount, cursor, hasMore); // 统一声明变量,避免分散定义,提升可读性
int syncCount = 0; // 本次同步成功的视频数量
string cursor = "0"; // 初始游标
bool hasMore = true; // 是否还有更多数据
// 处理同步完成后的操作 // 处理「使用收藏文件夹」和「不使用收藏文件夹」的统一逻辑
await HandleSyncCompletion(cookie, syncCount); if (cookie.UseCollectFolder)
{
// 获取收藏文件夹列表
var folders = await douyinHttpClientService.SyncCollectFolderList(cookie.Cookies,"");
Log.Debug("获取收藏文件夹列表完成,共计{Count}个包含视频的收藏夹", folders?.CollectsList?.Count(x => x.TotalNumber > 0) ?? 0);
// 文件夹为空时,执行默认同步逻辑(与不使用文件夹逻辑一致)
if (folders?.CollectsList == null || !folders.CollectsList.Any(x => x.TotalNumber > 0))
{
(syncCount, cursor, hasMore) = await GetViedos(cookie, config, syncCount, cursor, hasMore);
await HandleSyncCompletion(cookie, syncCount);
}
// 文件夹不为空时,遍历每个文件夹同步视频
else
{
foreach (var item in folders.CollectsList.Where(x=>x.TotalNumber>0))
{
// 重置游标,每个文件夹独立从头同步
string folderCursor = "0";
await GetViedos(cookie, config, syncCount, folderCursor, hasMore, null, item);
await HandleSyncCompletion(cookie, syncCount, null);
}
}
}
// 不使用收藏文件夹,直接执行默认同步逻辑
else
{
(syncCount, cursor, hasMore) = await GetViedos(cookie, config, syncCount, cursor, hasMore);
await HandleSyncCompletion(cookie, syncCount);
}
}
// 非抖音收藏类型,执行统一的默认同步逻辑
else
{
// 提取重复变量,与上方逻辑保持一致命名
int syncCount = 0;
string cursor = "0";
bool hasMore = true;
(syncCount, cursor, hasMore) = await GetViedos(cookie, config, syncCount, cursor, hasMore);
await HandleSyncCompletion(cookie, syncCount);
}
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -360,13 +393,13 @@ namespace dy.net.job
} }
} }
private async Task<(int syncCount, string cursor, bool hasMore)> GetViedos(DouyinCookie cookie, AppConfig config, int syncCount, string cursor, bool hasMore, DouyinFollowed followed = null) private async Task<(int syncCount, string cursor, bool hasMore)> GetViedos(DouyinCookie cookie, AppConfig config, int syncCount, string cursor, bool hasMore, DouyinFollowed followed = null,DouyinCollectItem collectItem=null)
{ {
// 循环获取视频数据 // 循环获取视频数据
while (hasMore) while (hasMore)
{ {
// 获取视频数据 // 获取视频数据
var data = await FetchVideoData(cookie, cursor, followed == null ? "" : followed?.SecUid); var data = await FetchVideoData(cookie, cursor, followed,collectItem);
if (data == null) if (data == null)
{ {
Log.Debug($"{VideoType}-Cookie[{cookie.UserName}]同步数据失败!!!"); Log.Debug($"{VideoType}-Cookie[{cookie.UserName}]同步数据失败!!!");
@@ -383,7 +416,7 @@ namespace dy.net.job
break; break;
// 处理视频列表 // 处理视频列表
var videos = await ProcessVideoList(cookie, data, config, followed); var videos = await ProcessVideoList(cookie, data, config, followed, collectItem);
// 保存视频信息到数据库 // 保存视频信息到数据库
syncCount += await SaveVideos(videos); syncCount += await SaveVideos(videos);
@@ -435,23 +468,23 @@ namespace dy.net.job
return false; return false;
} }
/// <summary> /// <summary>
/// 处理视频列表
/// 遍历视频列表,分别处理每个视频和图片集 /// 遍历视频列表,分别处理每个视频和图片集
/// </summary> /// </summary>
/// <param name="cookie">用户Cookie</param> /// <param name="cookie">用户Cookie</param>
/// <param name="data">视频信息对象</param> /// <param name="data">视频信息对象</param>
/// <param name="config">应用配置</param> /// <param name="config">应用配置</param>
/// <param name="followed">关注的</param> /// <param name="followed">关注的</param>
/// <param name="collectItem">收藏夹Item</param>
/// <returns>处理后的视频实体列表</returns> /// <returns>处理后的视频实体列表</returns>
protected async Task<List<DouyinVideo>> ProcessVideoList(DouyinCookie cookie, DouyinVideoInfo data, AppConfig config, DouyinFollowed followed = null) protected async Task<List<DouyinVideo>> ProcessVideoList(DouyinCookie cookie, DouyinVideoInfoResponse data, AppConfig config, DouyinFollowed followed = null,DouyinCollectItem collectItem=null)
{ {
var videos = new List<DouyinVideo>(); var videos = new List<DouyinVideo>();
foreach (var item in data.AwemeList) foreach (var item in data.AwemeList)
{ {
if (item.AwemeId != "7440444948844956985") //if (item.AwemeId != "7440444948844956985")
{ //{
continue; // continue;
} //}
//if (!item.Desc.Contains("小房车正式启程")) //if (!item.Desc.Contains("小房车正式启程"))
//{ //{
// continue; // continue;
@@ -488,7 +521,7 @@ namespace dy.net.job
} }
} }
// 处理单个视频 // 处理单个视频
var video = await ProcessSingleVideo(cookie, item, data, config, followed); var video = await ProcessSingleVideo(cookie, item, data, config, followed,collectItem);
if (video != null) if (video != null)
videos.Add(video); videos.Add(video);
else else
@@ -578,7 +611,7 @@ namespace dy.net.job
// 统一处理图文视频逻辑 // 统一处理图文视频逻辑
if (config.DownImageVideo || config.DownMp3 || config.DownImage) if (config.DownImageVideo || config.DownMp3 || config.DownImage)
{ {
var mergevideo = await ProcessImageSetAndMergeToVideo(cookie, item, data, config, followed); var mergevideo = await ProcessImageSetAndMergeToVideo(cookie, item, data, config, followed, collectItem);
if (mergevideo != null) if (mergevideo != null)
videos.Add(mergevideo); videos.Add(mergevideo);
} }
@@ -773,8 +806,9 @@ namespace dy.net.job
/// <param name="data">视频信息对象</param> /// <param name="data">视频信息对象</param>
/// <param name="config">应用配置</param> /// <param name="config">应用配置</param>
/// <param name="followed">关注</param> /// <param name="followed">关注</param>
/// <param name="collectItem">收藏夹Item</param>
/// <returns>处理后的视频实体,如果处理失败则为null</returns> /// <returns>处理后的视频实体,如果处理失败则为null</returns>
protected async Task<DouyinVideo> ProcessSingleVideo(DouyinCookie cookie, Aweme item, DouyinVideoInfo data, AppConfig config, DouyinFollowed followed = null) protected async Task<DouyinVideo> ProcessSingleVideo(DouyinCookie cookie, Aweme item, DouyinVideoInfoResponse data, AppConfig config, DouyinFollowed followed = null,DouyinCollectItem collectItem=null)
{ {
// 检查视频数据是否有效 // 检查视频数据是否有效
if (!IsAwemeValid(item)) return null; if (!IsAwemeValid(item)) return null;
@@ -790,7 +824,7 @@ namespace dy.net.job
// 获取视频标签 // 获取视频标签
var (tag1, tag2, tag3) = GetVideoTags(item); var (tag1, tag2, tag3) = GetVideoTags(item);
// 创建保存文件夹 // 创建保存文件夹
var saveFolder = CreateSaveFolder(cookie, item, config, followed); var saveFolder = CreateSaveFolder(cookie, item, config, followed,collectItem);
// 获取视频文件名 // 获取视频文件名
var fileName = GetVideoFileName(cookie, item, config); var fileName = GetVideoFileName(cookie, item, config);
// 拼接视频保存路径 // 拼接视频保存路径
@@ -836,14 +870,14 @@ namespace dy.net.job
protected async Task<DouyinVideo> ProcessDynamicVideo(List<DouyinDynamicVideoDto> dynamicUrls, DouyinCookie cookie, Aweme item, DouyinVideoInfo data, AppConfig config, DouyinFollowed followed = null) protected async Task<DouyinVideo> ProcessDynamicVideo(List<DouyinDynamicVideoDto> dynamicUrls, DouyinCookie cookie, Aweme item, DouyinVideoInfoResponse data, AppConfig config, DouyinFollowed followed = null,DouyinCollectItem collectItem=null)
{ {
// 获取视频标签 // 获取视频标签
var (tag1, tag2, tag3) = GetVideoTags(item); var (tag1, tag2, tag3) = GetVideoTags(item);
// 创建保存文件夹 // 创建保存文件夹
var saveFolder = CreateSaveFolder(cookie, item, config, followed); var saveFolder = CreateSaveFolder(cookie, item, config, followed,collectItem);
// 获取视频文件名 // 获取视频文件名
//var fileName = DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId) + ".mp4"; //var fileName = DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId) + ".mp4";
@@ -969,7 +1003,6 @@ namespace dy.net.job
} }
/// <summary> /// <summary>
/// 处理图片集并合成为视频
/// 负责下载图片、合成视频、处理封面和头像等 /// 负责下载图片、合成视频、处理封面和头像等
/// </summary> /// </summary>
/// <param name="cookie">用户Cookie</param> /// <param name="cookie">用户Cookie</param>
@@ -978,7 +1011,7 @@ namespace dy.net.job
/// <param name="config">应用配置</param> /// <param name="config">应用配置</param>
/// <param name="followed">应用配置</param> /// <param name="followed">应用配置</param>
/// <returns>合成后的视频实体,如果处理失败则为null</returns> /// <returns>合成后的视频实体,如果处理失败则为null</returns>
protected async Task<DouyinVideo> ProcessImageSetAndMergeToVideo(DouyinCookie cookie, Aweme item, DouyinVideoInfo data, AppConfig config, DouyinFollowed followed) protected async Task<DouyinVideo> ProcessImageSetAndMergeToVideo(DouyinCookie cookie, Aweme item, DouyinVideoInfoResponse data, AppConfig config, DouyinFollowed followed,DouyinCollectItem collectItem)
{ {
try try
{ {
@@ -1010,7 +1043,7 @@ namespace dy.net.job
} }
else else
{ {
fileNamefolder = CreateSaveFolder(cookie, item, config, followed); fileNamefolder = CreateSaveFolder(cookie, item, config, followed,collectItem);
} }
if (!Directory.Exists(fileNamefolder)) Directory.CreateDirectory(fileNamefolder); if (!Directory.Exists(fileNamefolder)) Directory.CreateDirectory(fileNamefolder);
@@ -1293,7 +1326,7 @@ namespace dy.net.job
/// <returns>创建的视频实体对象</returns> /// <returns>创建的视频实体对象</returns>
private async Task<DouyinVideo> CreateVideoEntity(AppConfig config, private async Task<DouyinVideo> CreateVideoEntity(AppConfig config,
DouyinCookie cookie, Aweme item, VideoBitRate bitRate, string savePath, string saveFolder, DouyinCookie cookie, Aweme item, VideoBitRate bitRate, string savePath, string saveFolder,
string tag1, string tag2, string tag3, string avatarSavePath, string avatarUrl, DouyinVideoInfo data, List<DouyinDynamicVideoDto> dynamicVideos = null) string tag1, string tag2, string tag3, string avatarSavePath, string avatarUrl, DouyinVideoInfoResponse data, List<DouyinDynamicVideoDto> dynamicVideos = null)
{ {
var diffs = GetVideoEntityDifferences(cookie, item); var diffs = GetVideoEntityDifferences(cookie, item);
+3 -3
View File
@@ -1,5 +1,5 @@
using dy.net.dto; using dy.net.model.entity;
using dy.net.model; using dy.net.model.response;
using dy.net.service; using dy.net.service;
using Quartz; using Quartz;
using System.Collections.Generic; using System.Collections.Generic;
@@ -70,7 +70,7 @@ namespace dy.net.job
{ {
hasmore = false; hasmore = false;
} }
ck.StatusMsg = err.StatusCode == 8 ? "无效" : "正 常"; ck.StatusMsg = err.StatusCode == 8 ? "无效" : "正常";
ck.StatusCode = err.StatusCode; ck.StatusCode = err.StatusCode;
await _dyCookieService.UpdateAsync(ck); await _dyCookieService.UpdateAsync(ck);
}); });
+8 -7
View File
@@ -1,6 +1,7 @@
using ClockSnowFlake; using ClockSnowFlake;
using dy.net.dto; using dy.net.model.dto;
using dy.net.model; using dy.net.model.entity;
using dy.net.model.response;
using dy.net.service; using dy.net.service;
using dy.net.utils; using dy.net.utils;
using Newtonsoft.Json; using Newtonsoft.Json;
@@ -29,17 +30,17 @@ namespace dy.net.job
return !string.IsNullOrWhiteSpace(cookie.Cookies)&&!string.IsNullOrWhiteSpace(cookie.UpSavePath); return !string.IsNullOrWhiteSpace(cookie.Cookies)&&!string.IsNullOrWhiteSpace(cookie.UpSavePath);
} }
protected override async Task<DouyinVideoInfo> FetchVideoData(DouyinCookie cookie, string cursor, string uperUid = "") protected override async Task<DouyinVideoInfoResponse> FetchVideoData(DouyinCookie cookie, string cursor, DouyinFollowed followed, DouyinCollectItem collectId)
{ {
return await douyinHttpClientService.SyncUpderPostVideos(count, cursor, uperUid, cookie.Cookies); return await douyinHttpClientService.SyncUpderPostVideos(count, cursor, followed.SecUid, cookie.Cookies);
} }
protected override bool ShouldContinueSync(DouyinCookie cookie, DouyinVideoInfo data, DouyinFollowed followed) protected override bool ShouldContinueSync(DouyinCookie cookie, DouyinVideoInfoResponse data, DouyinFollowed followed)
{ {
return data != null && data.HasMore == 1 && cookie.UperSyncd == 0 && followed.FullSync; return data != null && data.HasMore == 1 && cookie.UperSyncd == 0 && followed.FullSync;
} }
protected override string GetNextCursor(DouyinVideoInfo data) protected override string GetNextCursor(DouyinVideoInfoResponse data)
{ {
return data?.MaxCursor ?? "0"; return data?.MaxCursor ?? "0";
} }
@@ -52,7 +53,7 @@ namespace dy.net.job
/// <param name="followed"></param> /// <param name="followed"></param>
/// <param name="config"></param> /// <param name="config"></param>
/// <returns></returns> /// <returns></returns>
protected override string CreateSaveFolder(DouyinCookie cookie, Aweme item, AppConfig config, DouyinFollowed followed) protected override string CreateSaveFolder(DouyinCookie cookie, Aweme item, AppConfig config, DouyinFollowed followed, DouyinCollectItem collectItem)
{ {
#region 使UP主名称作为文件夹名称使 #region 使UP主名称作为文件夹名称使
// 1. 优先获取有效的作者名称(遵循原有优先级:followed.UperName > item.Author.Nickname > 默认值) // 1. 优先获取有效的作者名称(遵循原有优先级:followed.UperName > item.Author.Nickname > 默认值)
@@ -1,4 +1,4 @@
namespace dy.net.dto namespace dy.net.model.dto
{ {
@@ -1,6 +1,6 @@
using dy.net.model; using dy.net.model.entity;
namespace dy.net.dto namespace dy.net.model.dto
{ {
public class AppConfigImportDto public class AppConfigImportDto
{ {
@@ -1,4 +1,4 @@
namespace dy.net.dto namespace dy.net.model.dto
{ {
public class DeleteInvalidVideoDto public class DeleteInvalidVideoDto
{ {
@@ -1,4 +1,4 @@
namespace dy.net.dto namespace dy.net.model.dto
{ {
public class DouyinCookieStopDto public class DouyinCookieStopDto
{ {
@@ -1,4 +1,4 @@
namespace dy.net.dto namespace dy.net.model.dto
{ {
public class DouyinDynamicVideoDto public class DouyinDynamicVideoDto
{ {
@@ -1,4 +1,4 @@
namespace dy.net.dto namespace dy.net.model.dto
{ {
public class DouyinFollowGroupDto public class DouyinFollowGroupDto
{ {
@@ -1,7 +1,7 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace dy.net.dto namespace dy.net.model.dto
{ {
public class DouyinApiResponse<T> public class DouyinApiResponse<T>
{ {
@@ -1,6 +1,6 @@
using Newtonsoft.Json; using Newtonsoft.Json;
namespace dy.net.dto namespace dy.net.model.dto
{ {
public class DouyinUpSecUserIdDto public class DouyinUpSecUserIdDto
{ {
@@ -1,4 +1,4 @@
namespace dy.net.dto namespace dy.net.model.dto
{ {
// Actor.cs // Actor.cs
@@ -1,6 +1,6 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace dy.net.dto namespace dy.net.model.dto
{ {
public class DouyinVideoPageRequestDto : PageRequestDto public class DouyinVideoPageRequestDto : PageRequestDto
{ {
@@ -1,4 +1,4 @@
namespace dy.net.dto namespace dy.net.model.dto
{ {
public class DouyinVideoRequestDto public class DouyinVideoRequestDto
{ {
@@ -1,4 +1,4 @@
namespace dy.net.dto namespace dy.net.model.dto
{ {
public class DouyinVideoTopDto public class DouyinVideoTopDto
{ {
@@ -1,6 +1,6 @@
using Newtonsoft.Json; using Newtonsoft.Json;
namespace dy.net.dto namespace dy.net.model.dto
{ {
public class FollowErrorDto public class FollowErrorDto
{ {
@@ -1,6 +1,6 @@
using SqlSugar; using SqlSugar;
namespace dy.net.dto namespace dy.net.model.dto
{ {
public class InitSystemInfo public class InitSystemInfo
{ {
+1 -1
View File
@@ -1,4 +1,4 @@
namespace dy.net.dto namespace dy.net.model.dto
{ {
/// <summary> /// <summary>
/// 任务配置实体 /// 任务配置实体
@@ -1,6 +1,6 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace dy.net.dto namespace dy.net.model.dto
{ {
public class LogFileInfoDto public class LogFileInfoDto
{ {
@@ -5,7 +5,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace dy.net.dto namespace dy.net.model.dto
{ {
public class MediaMergeRequest public class MediaMergeRequest
{ {
@@ -1,4 +1,4 @@
namespace dy.net.dto namespace dy.net.model.dto
{ {
public class PriorityLevelDto public class PriorityLevelDto
{ {
@@ -1,4 +1,4 @@
namespace dy.net.dto namespace dy.net.model.dto
{ {
public class ReDownViedoDto public class ReDownViedoDto
{ {
@@ -1,4 +1,4 @@
namespace dy.net.dto namespace dy.net.model.dto
{ {
//如果好用,请收藏地址,帮忙分享。 //如果好用,请收藏地址,帮忙分享。
public class ImageTagInfoItem public class ImageTagInfoItem
@@ -1,4 +1,4 @@
namespace dy.net.dto namespace dy.net.model.dto
{ {
public class VideoStaticsItemDto public class VideoStaticsItemDto
{ {
@@ -1,4 +1,4 @@
namespace dy.net.dto namespace dy.net.model.dto
{ {
public class VideoTitleDataTemplate public class VideoTitleDataTemplate
{ {
@@ -1,6 +1,6 @@
using System.ComponentModel; using System.ComponentModel;
namespace dy.net.dto namespace dy.net.model.dto
{ {
public enum VideoTypeEnum public enum VideoTypeEnum
{ {
@@ -1,6 +1,6 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
namespace dy.net.model namespace dy.net.model.entity
{ {
[SqlSugar.SugarTable(TableName = "login_user_info")] [SqlSugar.SugarTable(TableName = "login_user_info")]
public class AdminUserInfo public class AdminUserInfo
@@ -2,7 +2,7 @@
using SqlSugar; using SqlSugar;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace dy.net.model namespace dy.net.model.entity
{ {
[SugarTable(TableName = "dy_app_config")] [SugarTable(TableName = "dy_app_config")]
+52
View File
@@ -0,0 +1,52 @@
using SqlSugar;
namespace dy.net.model.entity
{
/// <summary>
/// 收藏夹-自定义收藏夹、合集、短剧
/// </summary>
[SugarTable(TableName = "dy_collect_cate")]
public class DouyinCollectCate
{
/// <summary>
///
/// </summary>
[SugarColumn(IsPrimaryKey = true)]
public string Id { get; set; }
/// <summary>
/// 关联cookieId
/// </summary>
public long CookieId { get; set; }
/// <summary>
/// 收藏夹名称
/// </summary>
[SugarColumn(Length = 500, IsNullable = false)]
public string Name { get; set; }
/// <summary>
/// 收藏夹Id
/// </summary>
[SugarColumn(Length =60,IsNullable =false)]
public string XId { get; set; }
/// <summary>
/// 封面
/// </summary>
public string CoverUrl { get; set; }
/// <summary>
/// 保存文件夹
/// </summary>
public string SaveFolder { get; set; }
/// <summary>
/// 是否开启同步
/// </summary>
public bool Sync { get; set; }
/// <summary>
/// 收藏夹类型(0:自定义收藏夹,1:合集,2:短剧)
/// </summary>
public int CollectType { get; set; }
}
}
@@ -1,8 +1,6 @@
using dy.net.dto; using SqlSugar;
using Newtonsoft.Json;
using SqlSugar;
namespace dy.net.model namespace dy.net.model.entity
{ {
[SugarTable(TableName = "dy_cookie")] [SugarTable(TableName = "dy_cookie")]
public class DouyinCookie public class DouyinCookie
@@ -26,10 +24,24 @@ namespace dy.net.model
[SugarColumn(Length =-1,IsNullable =true)] [SugarColumn(Length =-1,IsNullable =true)]
public string Cookies { get; set; } public string Cookies { get; set; }
/// <summary> /// <summary>
/// 存储路径 /// 存储路径(收藏视频的存储路径)
/// </summary> /// </summary>
[SugarColumn(Length =255,IsNullable =true)] [SugarColumn(Length =255,IsNullable =true)]
public string SavePath { get; set; } public string SavePath { get; set; }
/// <summary>
/// 是否按收藏夹文件夹来存储视频
/// </summary>
public bool UseCollectFolder { get; set; }
/// <summary>
/// 是否下载合集
/// </summary>
public bool DownMix { get; set; }
/// <summary>
/// 是否下载短剧
/// </summary>
public bool DownSeries { get; set; }
/// <summary> /// <summary>
/// 1 开启同步 0 关闭同步 /// 1 开启同步 0 关闭同步
/// </summary> /// </summary>
@@ -98,15 +110,10 @@ namespace dy.net.model
[SugarColumn(Length = 100, IsNullable = true)] [SugarColumn(Length = 100, IsNullable = true)]
public string StatusMsg { get; set; } public string StatusMsg { get; set; }
/// <summary> /// <summary>
/// 是否统一一个路径-用 SavePath /// 是否统一一个路径(savepath)
/// </summary> /// </summary>
public bool useSinglePath { get; set; } public bool useSinglePath { get; set; }
/// <summary>
/// 服务端口--不存数据库
/// </summary>
[SugarColumn(IsIgnore =true)]
public int AppPort { get; set; }
} }
} }
@@ -1,7 +1,7 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using SqlSugar; using SqlSugar;
namespace dy.net.model namespace dy.net.model.entity
{ {
[SugarTable(TableName = "dy_follow")] [SugarTable(TableName = "dy_follow")]
public class DouyinFollowed public class DouyinFollowed
@@ -1,6 +1,6 @@
using SqlSugar; using SqlSugar;
namespace dy.net.model namespace dy.net.model.entity
{ {
/// <summary> /// <summary>
/// 重新下载的列表 /// 重新下载的列表
@@ -1,8 +1,8 @@
using dy.net.dto; using dy.net.extension;
using dy.net.extension; using dy.net.model.dto;
using SqlSugar; using SqlSugar;
namespace dy.net.model namespace dy.net.model.entity
{ {
[SugarTable(TableName = "dy_collect_video")] [SugarTable(TableName = "dy_collect_video")]
@@ -1,6 +1,6 @@
using SqlSugar; using SqlSugar;
namespace dy.net.model namespace dy.net.model.entity
{ {
/// <summary> /// <summary>
/// 永久删除的视频记录-不再下载 /// 永久删除的视频记录-不再下载
+298
View File
@@ -0,0 +1,298 @@
using Newtonsoft.Json;
namespace dy.net.model.response
{
/// <summary>
/// 收藏夹列表
/// </summary>
public class DouyinCollectListResponse
{
/// <summary>
/// 收藏列表数据
/// </summary>
[JsonProperty("collects_list")]
public List<DouyinCollectItem> CollectsList { get; set; } = new List<DouyinCollectItem>();
/// <summary>
/// 分页游标
/// </summary>
[JsonProperty("cursor")]
public int Cursor { get; set; }
/// <summary>
/// 额外扩展信息
/// </summary>
//[JsonProperty("extra")]
//public ExtraInfo Extra { get; set; } = new ExtraInfo();
/// <summary>
/// 是否还有更多数据
/// </summary>
[JsonProperty("has_more")]
public bool HasMore { get; set; }
/// <summary>
/// 日志相关信息
/// </summary>
//[JsonProperty("log_pb")]
//public LogPb LogPb { get; set; } = new LogPb();
/// <summary>
/// 响应状态码(0表示成功)
/// </summary>
[JsonProperty("status_code")]
public int StatusCode { get; set; }
/// <summary>
/// 收藏列表总数
/// </summary>
[JsonProperty("total_number")]
public int TotalNumber { get; set; }
}
/// <summary>
/// 单个收藏项实体
/// </summary>
public class DouyinCollectItem
{
/// <summary>
/// 应用ID
/// </summary>
[JsonProperty("app_id")]
public int AppId { get; set; }
/// <summary>
/// 收藏封面信息
/// </summary>
//[JsonProperty("collects_cover")]
//public CollectsCover CollectsCover { get; set; } = new CollectsCover();
/// <summary>
/// 收藏ID(数值型)
/// </summary>
[JsonProperty("collects_id")]
public string CollectsId { get; set; }
/// <summary>
/// 收藏ID(字符串型)
/// </summary>
[JsonProperty("collects_id_str")]
public string CollectsIdStr { get; set; } = string.Empty;
/// <summary>
/// 收藏名称
/// </summary>
[JsonProperty("collects_name")]
public string CollectsName { get; set; } = string.Empty;
/// <summary>
/// 创建时间(时间戳)
/// </summary>
[JsonProperty("create_time")]
public long CreateTime { get; set; }
/// <summary>
/// 关注状态
/// </summary>
[JsonProperty("follow_status")]
public int FollowStatus { get; set; }
/// <summary>
/// 被关注数量
/// </summary>
[JsonProperty("followed_count")]
public int FollowedCount { get; set; }
/// <summary>
/// 是否为正常状态
/// </summary>
[JsonProperty("is_normal_status")]
public bool IsNormalStatus { get; set; }
/// <summary>
/// 项目类型
/// </summary>
[JsonProperty("item_type")]
public int ItemType { get; set; }
/// <summary>
/// 最后收藏时间(时间戳)
/// </summary>
[JsonProperty("last_collect_time")]
public long LastCollectTime { get; set; }
/// <summary>
/// 播放数量
/// </summary>
[JsonProperty("play_count")]
public int PlayCount { get; set; }
/// <summary>
/// 西西里收藏封面列表(暂为null,用可空对象接收)
/// </summary>
[JsonProperty("sicily_collects_cover_list")]
public object? SicilyCollectsCoverList { get; set; }
/// <summary>
/// 状态标识
/// </summary>
[JsonProperty("states")]
public int States { get; set; }
/// <summary>
/// 状态
/// </summary>
[JsonProperty("status")]
public int Status { get; set; }
/// <summary>
/// 系统类型
/// </summary>
[JsonProperty("system_type")]
public int SystemType { get; set; }
/// <summary>
/// 该收藏下的项目总数
/// </summary>
[JsonProperty("total_number")]
public int TotalNumber { get; set; }
/// <summary>
/// 用户ID(数值型)
/// </summary>
[JsonProperty("user_id")]
public long UserId { get; set; }
/// <summary>
/// 用户ID(字符串型)
/// </summary>
[JsonProperty("user_id_str")]
public string UserIdStr { get; set; } = string.Empty;
/// <summary>
/// 用户信息
/// </summary>
//[JsonProperty("user_info")]
//public UserInfo UserInfo { get; set; } = new UserInfo();
}
/// <summary>
/// 收藏封面信息实体
/// </summary>
//public class CollectsCover
//{
// /// <summary>
// /// 封面资源URI
// /// </summary>
// [JsonProperty("uri")]
// public string Uri { get; set; } = string.Empty;
// /// <summary>
// /// 封面URL列表
// /// </summary>
// [JsonProperty("url_list")]
// public List<string> UrlList { get; set; } = new List<string>();
//}
/// <summary>
/// 用户信息实体
/// </summary>
//public class UserInfo
//{
// /// <summary>
// /// 大尺寸头像信息
// /// </summary>
// [JsonProperty("avatar_larger")]
// public AvatarInfo AvatarLarger { get; set; } = new AvatarInfo();
// /// <summary>
// /// 中等尺寸头像信息
// /// </summary>
// [JsonProperty("avatar_medium")]
// public AvatarInfo AvatarMedium { get; set; } = new AvatarInfo();
// /// <summary>
// /// 缩略图尺寸头像信息
// /// </summary>
// [JsonProperty("avatar_thumb")]
// public AvatarInfo AvatarThumb { get; set; } = new AvatarInfo();
// /// <summary>
// /// 用户昵称
// /// </summary>
// [JsonProperty("nickname")]
// public string Nickname { get; set; } = string.Empty;
// /// <summary>
// /// 用户唯一标识
// /// </summary>
// [JsonProperty("uid")]
// public string Uid { get; set; } = string.Empty;
//}
/// <summary>
/// 头像信息实体
/// </summary>
//public class AvatarInfo
//{
// /// <summary>
// /// 头像高度
// /// </summary>
// [JsonProperty("height")]
// public int Height { get; set; }
// /// <summary>
// /// 头像资源URI
// /// </summary>
// [JsonProperty("uri")]
// public string Uri { get; set; } = string.Empty;
// /// <summary>
// /// 头像URL列表
// /// </summary>
// [JsonProperty("url_list")]
// public List<string> UrlList { get; set; } = new List<string>();
// /// <summary>
// /// 头像宽度
// /// </summary>
// [JsonProperty("width")]
// public int Width { get; set; }
//}
/// <summary>
/// 额外扩展信息实体
/// </summary>
//public class ExtraInfo
//{
// /// <summary>
// /// 异常项目ID列表
// /// </summary>
// [JsonProperty("fatal_item_ids")]
// public List<long> FatalItemIds { get; set; } = new List<long>();
// /// <summary>
// /// 日志ID
// /// </summary>
// [JsonProperty("logid")]
// public string Logid { get; set; } = string.Empty;
// /// <summary>
// /// 当前时间戳(带毫秒)
// /// </summary>
// [JsonProperty("now")]
// public long Now { get; set; }
//}
/// <summary>
/// 日志PB实体
/// </summary>
public class LogPb
{
/// <summary>
/// 曝光ID
/// </summary>
[JsonProperty("impr_id")]
public string ImprId { get; set; } = string.Empty;
}
}
@@ -1,7 +1,153 @@
using Newtonsoft.Json; using Newtonsoft.Json;
namespace dy.net.dto namespace dy.net.model.response
{ {
/// <summary>
/// 关注列表
/// </summary>
public class DouyinFollowInfoResponse
{
/// <summary>
///
/// </summary>
//public Extra extra { get; set; }
/// <summary>
///
/// </summary>
///
[JsonProperty("followings")]
public List<FollowingsItem> Followings { get; set; }
/// <summary>
///
/// </summary>
[JsonProperty("has_more")]
public bool HasMore { get; set; }
///// <summary>
/////
///// </summary>
//[JsonProperty("hotsoon_has_more")]
//public int hotsoon_has_more { get; set; }
///// <summary>
/////
///// </summary>
//public string hotsoon_text { get; set; }
///// <summary>
///
/// </summary>
//public Log_pb log_pb { get; set; }
/// <summary>
///
/// </summary>
//public int max_time { get; set; }
/// <summary>
///
/// </summary>
//public int min_time { get; set; }
/// <summary>
///
/// </summary>
//public int mix_count { get; set; }
/// <summary>
/// 当前登陆人的用户ID
/// </summary>
[JsonProperty("myself_user_id")]
public string MySelfUserId { get; set; }
/// <summary>
///
/// </summary>
[JsonProperty("offset")]
public int Offset { get; set; }
///// <summary>
/////
///// </summary>
//public string rec_has_more { get; set; }
/// <summary>
///
/// </summary>
public int status_code { get; set; }
/// <summary>
///
/// </summary>
//public string store_page { get; set; }
/// <summary>
/// 总关注人数
/// </summary>
[JsonProperty("total")]
public int Total { get; set; }
/// <summary>
///
/// </summary>
//public int vcd_count { get; set; }
}
public class FollowingsItem
{
/// <summary>
/// 头像
/// </summary>
[JsonProperty("avatar_larger")]
public AvatarLarger Avatar { get; set; }
/// <summary>
/// 官方账号(企业认证)
/// </summary>
[JsonProperty("enterprise_verify_reason")]
public string EnterpriseVerifyReason { get; set; }
/// <summary>
/// 伊朗驻华大使馆
/// </summary>
[JsonProperty("nickname")]
public string NickName { get; set; }
/// <summary>
/// 关键--唯一标识符
/// </summary>
[JsonProperty("sec_uid")]
public string SecUid { get; set; }
///// <summary>
/////
///// </summary>
//[JsonProperty("short_id")]
//public string ShortId { get; set; }
/// <summary>
/// 签名
/// </summary>
[JsonProperty("signature")]
public string Signature { get; set; }
[JsonProperty("uid")]
public string UperId { get; set; }
}
/// <summary>
/// 头像
/// </summary>
public class AvatarLarger
{
/// <summary>
///
/// </summary>
//public int height { get; set; }
///// <summary>
/////
///// </summary>
//public string uri { get; set; }
/// <summary>
///
/// </summary>
[JsonProperty("url_list")]
public List<string> UrlList { get; set; }
/// <summary>
///
/// </summary>
//public int width { get; set; }
}
//public class Extra //public class Extra
//{ //{
// /// <summary> // /// <summary>
@@ -1648,146 +1794,4 @@ namespace dy.net.dto
// //public int width { get; set; } // //public int width { get; set; }
//} //}
public class DouyinFollowInfo
{
/// <summary>
///
/// </summary>
//public Extra extra { get; set; }
/// <summary>
///
/// </summary>
///
[JsonProperty("followings")]
public List<FollowingsItem> Followings { get; set; }
/// <summary>
///
/// </summary>
[JsonProperty("has_more")]
public bool HasMore { get; set; }
///// <summary>
/////
///// </summary>
//[JsonProperty("hotsoon_has_more")]
//public int hotsoon_has_more { get; set; }
///// <summary>
/////
///// </summary>
//public string hotsoon_text { get; set; }
///// <summary>
///
/// </summary>
//public Log_pb log_pb { get; set; }
/// <summary>
///
/// </summary>
//public int max_time { get; set; }
/// <summary>
///
/// </summary>
//public int min_time { get; set; }
/// <summary>
///
/// </summary>
//public int mix_count { get; set; }
/// <summary>
/// 当前登陆人的用户ID
/// </summary>
[JsonProperty("myself_user_id")]
public string MySelfUserId { get; set; }
/// <summary>
///
/// </summary>
[JsonProperty("offset")]
public int Offset { get; set; }
///// <summary>
/////
///// </summary>
//public string rec_has_more { get; set; }
/// <summary>
///
/// </summary>
public int status_code { get; set; }
/// <summary>
///
/// </summary>
//public string store_page { get; set; }
/// <summary>
/// 总关注人数
/// </summary>
[JsonProperty("total")]
public int Total { get; set; }
/// <summary>
///
/// </summary>
//public int vcd_count { get; set; }
}
public class FollowingsItem
{
/// <summary>
/// 头像
/// </summary>
[JsonProperty("avatar_larger")]
public AvatarLarger Avatar { get; set; }
/// <summary>
/// 官方账号(企业认证)
/// </summary>
[JsonProperty("enterprise_verify_reason")]
public string EnterpriseVerifyReason { get; set; }
/// <summary>
/// 伊朗驻华大使馆
/// </summary>
[JsonProperty("nickname")]
public string NickName { get; set; }
/// <summary>
/// 关键--唯一标识符
/// </summary>
[JsonProperty("sec_uid")]
public string SecUid { get; set; }
///// <summary>
/////
///// </summary>
//[JsonProperty("short_id")]
//public string ShortId { get; set; }
/// <summary>
/// 签名
/// </summary>
[JsonProperty("signature")]
public string Signature { get; set; }
[JsonProperty("uid")]
public string UperId { get; set; }
}
/// <summary>
/// 头像
/// </summary>
public class AvatarLarger
{
/// <summary>
///
/// </summary>
//public int height { get; set; }
///// <summary>
/////
///// </summary>
//public string uri { get; set; }
/// <summary>
///
/// </summary>
[JsonProperty("url_list")]
public List<string> UrlList { get; set; }
/// <summary>
///
/// </summary>
//public int width { get; set; }
}
} }
+628
View File
@@ -0,0 +1,628 @@
using Newtonsoft.Json;
namespace dy.net.model.response
{
/// <summary>
/// 抖音合集列表响应根实体
/// </summary>
public class DouyinMixListResponse
{
/// <summary>
/// 分页游标
/// </summary>
[JsonProperty("cursor")]
public long Cursor { get; set; }
///// <summary>
///// 额外信息
///// </summary>
//[JsonProperty("extra")]
//public DouyinExtra Extra { get; set; }
/// <summary>
/// 是否有更多数据(0=无,1=有)
/// </summary>
[JsonProperty("has_more")]
public int HasMore { get; set; }
///// <summary>
///// 日志信息
///// </summary>
//[JsonProperty("log_pb")]
//public DouyinLogPb LogPb { get; set; }
/// <summary>
/// 合集信息列表
/// </summary>
[JsonProperty("mix_infos")]
public List<DouyinMixInfo> MixInfos { get; set; }
/// <summary>
/// 响应状态码(0=成功)
/// </summary>
[JsonProperty("status_code")]
public int StatusCode { get; set; }
}
///// <summary>
///// 额外信息实体
///// </summary>
//public class DouyinExtra
//{
// /// <summary>
// /// 致命项ID列表
// /// </summary>
// [JsonProperty("fatal_item_ids")]
// public List<object> FatalItemIds { get; set; }
// ///// <summary>
// ///// 日志ID
// ///// </summary>
// //[JsonProperty("logid")]
// //public string Logid { get; set; }
// /// <summary>
// /// 当前时间戳(毫秒)
// /// </summary>
// [JsonProperty("now")]
// public long Now { get; set; }
//}
///// <summary>
///// 日志PB实体
///// </summary>
//public class DouyinLogPb
//{
// /// <summary>
// /// 曝光ID
// /// </summary>
// [JsonProperty("impr_id")]
// public string ImprId { get; set; }
//}
/// <summary>
/// 合集信息实体
/// </summary>
public class DouyinMixInfo
{
/// <summary>
/// 作者信息
/// </summary>
[JsonProperty("author")]
public DouyinAuthor Author { get; set; }
/// <summary>
/// 合集封面
/// </summary>
[JsonProperty("cover_url")]
public DouyinImageInfo CoverUrl { get; set; }
/// <summary>
/// 创建时间戳(秒)
/// </summary>
[JsonProperty("create_time")]
public long CreateTime { get; set; }
/// <summary>
/// 合集描述
/// </summary>
[JsonProperty("desc")]
public string Desc { get; set; }
///// <summary>
///// 合集额外信息(JSON字符串)
///// </summary>
//[JsonProperty("extra")]
//public string Extra { get; set; }
///// <summary>
///// ID列表(预留)
///// </summary>
//[JsonProperty("ids")]
//public object Ids { get; set; }
///// <summary>
///// 是否为IAA内容
///// </summary>
//[JsonProperty("is_iaa")]
//public int IsIaa { get; set; }
///// <summary>
///// 是否为系列合集
///// </summary>
//[JsonProperty("is_serial_mix")]
//public int IsSerialMix { get; set; }
/// <summary>
/// 合集ID
/// </summary>
[JsonProperty("mix_id")]
public string MixId { get; set; }
/// <summary>
/// 合集名称
/// </summary>
[JsonProperty("mix_name")]
public string MixName { get; set; }
///// <summary>
///// 合集图片类型
///// </summary>
//[JsonProperty("mix_pic_type")]
//public int MixPicType { get; set; }
///// <summary>
///// 合集类型
///// </summary>
//[JsonProperty("mix_type")]
//public int MixType { get; set; }
///// <summary>
///// 付费剧集(预留)
///// </summary>
//[JsonProperty("paid_episodes")]
//public object PaidEpisodes { get; set; }
///// <summary>
///// 分享信息
///// </summary>
//[JsonProperty("share_info")]
//public DouyinShareInfo ShareInfo { get; set; }
///// <summary>
///// 统计信息
///// </summary>
//[JsonProperty("statis")]
//public DouyinMixStatis Statis { get; set; }
///// <summary>
///// 状态信息
///// </summary>
//[JsonProperty("status")]
//public DouyinMixStatus Status { get; set; }
///// <summary>
///// 更新时间戳(秒)
///// </summary>
//[JsonProperty("update_time")]
//public long UpdateTime { get; set; }
///// <summary>
///// 已观看剧集数
///// </summary>
//[JsonProperty("watched_episode")]
//public int WatchedEpisode { get; set; }
///// <summary>
///// 已观看项ID
///// </summary>
//[JsonProperty("watched_item")]
//public string WatchedItem { get; set; }
}
/// <summary>
/// 作者信息实体
/// </summary>
public class DouyinAuthor
{
///// <summary>
///// 是否接受隐私政策
///// </summary>
//[JsonProperty("accept_private_policy")]
//public bool AcceptPrivatePolicy { get; set; }
///// <summary>
///// 账号地区
///// </summary>
//[JsonProperty("account_region")]
//public string AccountRegion { get; set; }
///// <summary>
///// 广告封面URL(预留)
///// </summary>
//[JsonProperty("ad_cover_url")]
//public object AdCoverUrl { get; set; }
///// <summary>
///// Apple账号(预留)
///// </summary>
//[JsonProperty("apple_account")]
//public int AppleAccount { get; set; }
///// <summary>
///// 权限状态
///// </summary>
//[JsonProperty("authority_status")]
//public int AuthorityStatus { get; set; }
///// <summary>
///// 168x168头像
///// </summary>
//[JsonProperty("avatar_168x168")]
//public DouyinImageInfo Avatar168x168 { get; set; }
///// <summary>
///// 300x300头像
///// </summary>
//[JsonProperty("avatar_300x300")]
//public DouyinImageInfo Avatar300x300 { get; set; }
///// <summary>
///// 大尺寸头像
///// </summary>
//[JsonProperty("avatar_larger")]
//public DouyinImageInfo AvatarLarger { get; set; }
/// <summary>
/// 中等尺寸头像
/// </summary>
[JsonProperty("avatar_medium")]
public DouyinImageInfo AvatarMedium { get; set; }
///// <summary>
///// 头像方案列表(预留)
///// </summary>
//[JsonProperty("avatar_schema_list")]
//public object AvatarSchemaList { get; set; }
///// <summary>
///// 缩略头像
///// </summary>
//[JsonProperty("avatar_thumb")]
//public DouyinImageInfo AvatarThumb { get; set; }
///// <summary>
///// 头像URI
///// </summary>
//[JsonProperty("avatar_uri")]
//public string AvatarUri { get; set; }
/// <summary>
/// 作品控制权限
/// </summary>
[JsonProperty("aweme_control")]
public DouyinAwemeControl AwemeControl { get; set; }
/// <summary>
/// 作品数量
/// </summary>
[JsonProperty("aweme_count")]
public int AwemeCount { get; set; }
/// <summary>
/// 火山小视频认证
/// </summary>
[JsonProperty("aweme_hotsoon_auth")]
public int AwemeHotsoonAuth { get; set; }
/// <summary>
/// 火山小视频认证关系
/// </summary>
[JsonProperty("aweme_hotsoon_auth_relation")]
public int AwemeHotsoonAuthRelation { get; set; }
/// <summary>
/// 火山小视频问候信息
/// </summary>
[JsonProperty("awemehts_greet_info")]
public string AwemehtsGreetInfo { get; set; }
/// <summary>
/// 禁用用户功能列表
/// </summary>
[JsonProperty("ban_user_functions")]
public List<object> BanUserFunctions { get; set; }
/// <summary>
/// 星座
/// </summary>
[JsonProperty("constellation")]
public int Constellation { get; set; }
/// <summary>
/// 联系人状态
/// </summary>
[JsonProperty("contacts_status")]
public int ContactsStatus { get; set; }
/// <summary>
/// 封面URL列表
/// </summary>
[JsonProperty("cover_url")]
public List<DouyinImageInfo> CoverUrl { get; set; }
/// <summary>
/// 创建时间
/// </summary>
[JsonProperty("create_time")]
public int CreateTime { get; set; }
/// <summary>
/// 自定义认证
/// </summary>
[JsonProperty("custom_verify")]
public string CustomVerify { get; set; }
/// <summary>
/// CV等级
/// </summary>
[JsonProperty("cv_level")]
public string CvLevel { get; set; }
/// <summary>
/// 下载设置
/// </summary>
[JsonProperty("download_setting")]
public int DownloadSetting { get; set; }
/// <summary>
/// 合拍设置
/// </summary>
[JsonProperty("duet_setting")]
public int DuetSetting { get; set; }
/// <summary>
/// 企业认证理由
/// </summary>
[JsonProperty("enterprise_verify_reason")]
public string EnterpriseVerifyReason { get; set; }
/// <summary>
/// 关注状态
/// </summary>
[JsonProperty("follow_status")]
public int FollowStatus { get; set; }
/// <summary>
/// 粉丝数量
/// </summary>
[JsonProperty("follower_count")]
public long FollowerCount { get; set; }
/// <summary>
/// 关注数量
/// </summary>
[JsonProperty("following_count")]
public long FollowingCount { get; set; }
/// <summary>
/// 是否隐藏位置
/// </summary>
[JsonProperty("hide_location")]
public bool HideLocation { get; set; }
/// <summary>
/// 是否隐藏搜索
/// </summary>
[JsonProperty("hide_search")]
public bool HideSearch { get; set; }
/// <summary>
/// 是否为合集用户
/// </summary>
[JsonProperty("is_mix_user")]
public bool IsMixUser { get; set; }
/// <summary>
/// 是否已认证
/// </summary>
[JsonProperty("is_verified")]
public bool IsVerified { get; set; }
/// <summary>
/// 语言
/// </summary>
[JsonProperty("language")]
public string Language { get; set; }
/// <summary>
/// 昵称
/// </summary>
[JsonProperty("nickname")]
public string Nickname { get; set; }
/// <summary>
/// 安全UID
/// </summary>
[JsonProperty("sec_uid")]
public string SecUid { get; set; }
/// <summary>
/// 短ID
/// </summary>
[JsonProperty("short_id")]
public string ShortId { get; set; }
/// <summary>
/// 个性签名
/// </summary>
[JsonProperty("signature")]
public string Signature { get; set; }
/// <summary>
/// 状态
/// </summary>
[JsonProperty("status")]
public int Status { get; set; }
/// <summary>
/// UID
/// </summary>
[JsonProperty("uid")]
public string Uid { get; set; }
/// <summary>
/// 唯一ID
/// </summary>
[JsonProperty("unique_id")]
public string UniqueId { get; set; }
/// <summary>
/// 认证类型
/// </summary>
[JsonProperty("verification_type")]
public int VerificationType { get; set; }
}
/// <summary>
/// 作品控制权限实体
/// </summary>
public class DouyinAwemeControl
{
/// <summary>
/// 是否可评论
/// </summary>
[JsonProperty("can_comment")]
public bool CanComment { get; set; }
/// <summary>
/// 是否可转发
/// </summary>
[JsonProperty("can_forward")]
public bool CanForward { get; set; }
/// <summary>
/// 是否可分享
/// </summary>
[JsonProperty("can_share")]
public bool CanShare { get; set; }
/// <summary>
/// 是否可显示评论
/// </summary>
[JsonProperty("can_show_comment")]
public bool CanShowComment { get; set; }
}
/// <summary>
/// 图片信息实体(头像/封面通用)
/// </summary>
public class DouyinImageInfo
{
/// <summary>
/// 图片高度
/// </summary>
[JsonProperty("height")]
public int Height { get; set; }
/// <summary>
/// 图片URI
/// </summary>
[JsonProperty("uri")]
public string Uri { get; set; }
/// <summary>
/// 图片URL列表(多CDN节点)
/// </summary>
[JsonProperty("url_list")]
public List<string> UrlList { get; set; }
/// <summary>
/// 图片宽度
/// </summary>
[JsonProperty("width")]
public int Width { get; set; }
}
/// <summary>
/// 分享信息实体
/// </summary>
public class DouyinShareInfo
{
/// <summary>
/// 分享描述
/// </summary>
[JsonProperty("share_desc")]
public string ShareDesc { get; set; }
/// <summary>
/// 分享详细描述
/// </summary>
[JsonProperty("share_desc_info")]
public string ShareDescInfo { get; set; }
/// <summary>
/// 分享标题
/// </summary>
[JsonProperty("share_title")]
public string ShareTitle { get; set; }
/// <summary>
/// 自己查看的分享标题
/// </summary>
[JsonProperty("share_title_myself")]
public string ShareTitleMyself { get; set; }
/// <summary>
/// 他人查看的分享标题
/// </summary>
[JsonProperty("share_title_other")]
public string ShareTitleOther { get; set; }
/// <summary>
/// 分享URL
/// </summary>
[JsonProperty("share_url")]
public string ShareUrl { get; set; }
/// <summary>
/// 微博分享描述
/// </summary>
[JsonProperty("share_weibo_desc")]
public string ShareWeiboDesc { get; set; }
}
/// <summary>
/// 合集统计信息实体
/// </summary>
public class DouyinMixStatis
{
/// <summary>
/// 收藏播放量
/// </summary>
[JsonProperty("collect_vv")]
public long CollectVv { get; set; }
/// <summary>
/// 当前剧集
/// </summary>
[JsonProperty("current_episode")]
public int CurrentEpisode { get; set; }
/// <summary>
/// 是否有更新剧集
/// </summary>
[JsonProperty("has_updated_episode")]
public int HasUpdatedEpisode { get; set; }
/// <summary>
/// 播放总量
/// </summary>
[JsonProperty("play_vv")]
public long PlayVv { get; set; }
/// <summary>
/// 更新至剧集数
/// </summary>
[JsonProperty("updated_to_episode")]
public int UpdatedToEpisode { get; set; }
}
/// <summary>
/// 合集状态信息实体
/// </summary>
public class DouyinMixStatus
{
/// <summary>
/// 是否已收藏(1=是,0=否)
/// </summary>
[JsonProperty("is_collected")]
public int IsCollected { get; set; }
/// <summary>
/// 合集状态(2=正常)
/// </summary>
[JsonProperty("status")]
public int Status { get; set; }
}
}
File diff suppressed because it is too large Load Diff
@@ -1,10 +1,13 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Collections.Generic; using System.Collections.Generic;
namespace dy.net.dto namespace dy.net.model.response
{ {
public class DouyinVideoInfo /// <summary>
/// 视频列表
/// </summary>
public class DouyinVideoInfoResponse
{ {
[JsonProperty("aweme_list")] [JsonProperty("aweme_list")]
public List<Aweme> AwemeList { get; set; } public List<Aweme> AwemeList { get; set; }
+2 -2
View File
@@ -1,6 +1,6 @@
using ClockSnowFlake; using ClockSnowFlake;
using dy.net.dto; using dy.net.model.dto;
using dy.net.model; using dy.net.model.entity;
using dy.net.utils; using dy.net.utils;
using SqlSugar; using SqlSugar;
+2 -2
View File
@@ -1,5 +1,5 @@
using dy.net.dto; using dy.net.model.dto;
using dy.net.model; using dy.net.model.entity;
using SqlSugar; using SqlSugar;
using System.Linq.Expressions; using System.Linq.Expressions;
+3 -2
View File
@@ -1,7 +1,8 @@
using ClockSnowFlake; using ClockSnowFlake;
using dy.net.dto;
using dy.net.extension; using dy.net.extension;
using dy.net.model; using dy.net.model.dto;
using dy.net.model.entity;
using dy.net.model.response;
using SqlSugar; using SqlSugar;
namespace dy.net.repository namespace dy.net.repository
+3 -3
View File
@@ -1,6 +1,6 @@
using dy.net.dto; using dy.net.extension;
using dy.net.extension; using dy.net.model.dto;
using dy.net.model; using dy.net.model.entity;
using Quartz.Util; using Quartz.Util;
using SqlSugar; using SqlSugar;
using System.Linq; using System.Linq;
+2 -2
View File
@@ -1,5 +1,5 @@
using dy.net.dto; using dy.net.model.dto;
using dy.net.model; using dy.net.model.entity;
using dy.net.repository; using dy.net.repository;
namespace dy.net.service namespace dy.net.service
+2 -2
View File
@@ -1,6 +1,6 @@
using ClockSnowFlake; using ClockSnowFlake;
using dy.net.dto; using dy.net.model.dto;
using dy.net.model; using dy.net.model.entity;
using dy.net.utils; using dy.net.utils;
using SqlSugar; using SqlSugar;
using System.Reflection; using System.Reflection;
+2 -2
View File
@@ -1,6 +1,6 @@
using ClockSnowFlake; using ClockSnowFlake;
using dy.net.dto; using dy.net.model.dto;
using dy.net.model; using dy.net.model.entity;
using dy.net.repository; using dy.net.repository;
using SqlSugar; using SqlSugar;
using System.Linq.Expressions; using System.Linq.Expressions;
+3 -2
View File
@@ -1,6 +1,7 @@
using ClockSnowFlake; using ClockSnowFlake;
using dy.net.dto; using dy.net.model.dto;
using dy.net.model; using dy.net.model.entity;
using dy.net.model.response;
using dy.net.repository; using dy.net.repository;
using SqlSugar; using SqlSugar;
using System.Linq.Expressions; using System.Linq.Expressions;
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
using ClockSnowFlake; using ClockSnowFlake;
using dy.net.dto;
using dy.net.extension; using dy.net.extension;
using dy.net.model.dto;
using dy.net.utils; using dy.net.utils;
using Serilog; using Serilog;
using System.Collections.Generic; using System.Collections.Generic;
+2 -2
View File
@@ -1,5 +1,5 @@
using dy.net.dto; using dy.net.job;
using dy.net.job; using dy.net.model.dto;
using Quartz; using Quartz;
using Quartz.Impl.Matchers; using Quartz.Impl.Matchers;
using Serilog; using Serilog;
+2 -2
View File
@@ -1,6 +1,6 @@
using ClockSnowFlake; using ClockSnowFlake;
using dy.net.dto; using dy.net.model.dto;
using dy.net.model; using dy.net.model.entity;
using dy.net.repository; using dy.net.repository;
using dy.net.utils; using dy.net.utils;
using Newtonsoft.Json; using Newtonsoft.Json;
+1 -1
View File
@@ -1,4 +1,4 @@
using dy.net.dto; using dy.net.model.dto;
using System.Globalization; using System.Globalization;
namespace dy.net.service namespace dy.net.service
-174
View File
@@ -1,174 +0,0 @@
using Newtonsoft.Json;
using System.Text;
using System.Web;
namespace dy.net.utils
{
public class BogusManager
{
/// <summary>
/// 字符串方法生成X-Bogus参数
/// </summary>
/// <param name="endpoint">请求端点</param>
/// <param name="userAgent">用户代理</param>
/// <returns>带X-Bogus的完整端点</returns>
public static string XbStr2Endpoint(string endpoint, string userAgent)
{
try
{
var (finalEndpoint, _) = XBogusManager.GetXBogus(endpoint, userAgent);
return finalEndpoint;
}
catch (Exception ex)
{
throw new InvalidOperationException($"生成X-Bogus失败: {ex.Message}");
}
}
/// <summary>
/// 字典方法生成X-Bogus参数
/// </summary>
/// <param name="baseEndpoint">基础端点</param>
/// <param name="parameters">请求参数</param>
/// <param name="userAgent">用户代理</param>
/// <returns>带X-Bogus的完整端点</returns>
public static string XbModel2Endpoint(string baseEndpoint, Dictionary<string, string> parameters, string userAgent)
{
if (parameters == null)
throw new ArgumentException("参数必须是字典类型");
// 构建参数字符串
var paramStr = string.Join("&", parameters.Select(kv => $"{kv.Key}={HttpUtility.UrlEncode(kv.Value)}"));
try
{
var (_, xbValue) = XBogusManager.GetXBogus(paramStr, userAgent);
// 检查基础端点是否已有查询参数
var separator = baseEndpoint.Contains("?") ? "&" : "?";
return $"{baseEndpoint}{separator}{paramStr}&X-Bogus={xbValue}";
}
catch (Exception ex)
{
throw new InvalidOperationException($"生成X-Bogus失败: {ex.Message}");
}
}
}
public static class XBogusManager
{
/// <summary>
/// 生成X-Bogus签名
/// </summary>
/// <param name="input">输入字符串(参数或完整URL</param>
/// <param name="userAgent">用户代理</param>
/// <returns>(带签名的URL,签名值)</returns>
public static (string, string) GetXBogus(string input, string userAgent)
{
// X-Bogus核心算法实现(参考公开逆向分析结果)
// 注意:该算法可能随版本更新而变化,需根据实际情况调整
// 1. 提取关键信息
var isUrl = input.Contains("http") || input.Contains("?");
string queryString = isUrl ? HttpUtility.ParseQueryString(new Uri(input).Query).ToString() : input;
// 2. 生成基础哈希
var hash = GenerateBaseHash(queryString, userAgent);
// 3. 应用签名算法
var xbValue = ComputeXBogus(hash, userAgent);
// 4. 构建结果
if (isUrl)
{
var uri = new Uri(input);
var newQuery = string.IsNullOrWhiteSpace(uri.Query)
? $"X-Bogus={xbValue}"
: $"{uri.Query.Substring(1)}&X-Bogus={xbValue}";
return ($"{uri.Scheme}://{uri.Host}{uri.AbsolutePath}?{newQuery}", xbValue);
}
else
{
return ($"X-Bogus={xbValue}", xbValue);
}
}
private static string GenerateBaseHash(string input, string userAgent)
{
// 基础哈希计算逻辑
using (var sha1 = System.Security.Cryptography.SHA1.Create())
{
var bytes = Encoding.UTF8.GetBytes($"{input}_{userAgent}_3.0.0");
var hashBytes = sha1.ComputeHash(bytes);
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
}
}
private static string ComputeXBogus(string baseHash, string userAgent)
{
// 核心签名计算(模拟算法,实际需根据最新逆向结果调整)
var time = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
var rand = new Random();
var randStr = new string(Enumerable.Repeat("abcdefghijklmnopqrstuvwxyz0123456789", 6)
.Select(s => s[rand.Next(s.Length)]).ToArray());
// 组合签名
return $"DFSz{time:x8}{randStr}{baseHash.Substring(0, 16)}";
}
}
// 其他辅助类示例
public class TokenManager
{
/// <summary>
/// 生成msToken
/// </summary>
public static async Task<string> GenRealMsTokenAsync()
{
try
{
using HttpClient _httpClient = new HttpClient();
var payload = new
{
magic = 538969122,
version = 1,
dataType = 8,
strData = @"fWOdJTQR3/jwmZqBBsPO6tdNEc1jX7YTwPg0Z8CT+j3HScLFbj2Zm1XQ7/lqgSutntVKLJWaY3Hc/+vc0h+So9N1t6EqiImu5jKyUa+S4NPy6cNP0x9CUQQgb4+RRihCgsn4QyV8jivEFOsj3N5zFQbzXRyOV+9aG5B5EAnwpn8C70llsWq0zJz1VjN6y2KZiBZRyonAHE8feSGpwMDeUTllvq6BG3AQZz7RrORLWNCLEoGzM6bMovYVPRAJipuUML4Hq/568bNb5vqAo0eOFpvTZjQFgbB7f/CtAYYmnOYlvfrHKBKvb0TX6AjYrw2qmNNEer2ADJosmT5kZeBsogDui8rNiI/OOdX9PVotmcSmHOLRfw1cYXTgwHXr6cJeJveuipgwtUj2FNT4YCdZfUGGyRDz5bR5bdBuYiSRteSX12EktobsKPksdhUPGGv99SI1QRVmR0ETdWqnKWOj/7ujFZsNnfCLxNfqxQYEZEp9/U01CHhWLVrdzlrJ1v+KJH9EA4P1Wo5/2fuBFVdIz2upFqEQ11DJu8LSyD43qpTok+hFG3Moqrr81uPYiyPHnUvTFgwA/TIE11mTc/pNvYIb8IdbE4UAlsR90eYvPkI+rK9KpYN/l0s9ti9sqTth12VAw8tzCQvhKtxevJRQntU3STeZ3coz9Dg8qkvaSNFWuBDuyefZBGVSgILFdMy33//l/eTXhQpFrVc9OyxDNsG6cvdFwu7trkAENHU5eQEWkFSXBx9Ml54+fa3LvJBoacfPViyvzkJworlHcYYTG392L4q6wuMSSpYUconb+0c5mwqnnLP6MvRdm/bBTaY2Q6RfJcCxyLW0xsJMO6fgLUEjAg/dcqGxl6gDjUVRWbCcG1NAwPCfmYARTuXQYbFc8LO+r6WQTWikO9Q7Cgda78pwH07F8bgJ8zFBbWmyrghilNXENNQkyIzBqOQ1V3w0WXF9+Z3vG3aBKCjIENqAQM9qnC14WMrQkfCHosGbQyEH0n/5R2AaVTE/ye2oPQBWG1m0Gfcgs/96f6yYrsxbDcSnMvsA+okyd6GfWsdZYTIK1E97PYHlncFeOjxySjPpfy6wJc4UlArJEBZYmgveo1SZAhmXl3pJY3yJa9CmYImWkhbpwsVkSmG3g11JitJXTGLIfqKXSAhh+7jg4HTKe+5KNir8xmbBI/DF8O/+diFAlD+BQd3cV0G4mEtCiPEhOvVLKV1pE+fv7nKJh0t38wNVdbs3qHtiQNN7JhY4uWZAosMuBXSjpEtoNUndI+o0cjR8XJ8tSFnrAY8XihiRzLMfeisiZxWCvVwIP3kum9MSHXma75cdCQGFBfFRj0jPn1JildrTh2vRgwG+KeDZ33BJ2VGw9PgRkztZ2l/W5d32jc7H91FftFFhwXil6sA23mr6nNp6CcrO7rOblcm5SzXJ5MA601+WVicC/g3p6A0lAnhjsm37qP+xGT+cbCFOfjexDYEhnqz0QZm94CCSnilQ9B/HBLhWOddp9GK0SABIk5i3xAH701Xb4HCcgAulvfO5EK0RL2eN4fb+CccgZQeO1Zzo4qsMHc13UG0saMgBEH8SqYlHz2S0CVHuDY5j1MSV0nsShjM01vIynw6K0T8kmEyNjt1eRGlleJ5lvE8vonJv7rAeaVRZ06rlYaxrMT6cK3RSHd2liE50Z3ik3xezwWoaY6zBXvCzljyEmqjNFgAPU3gI+N1vi0MsFmwAwFzYqqWdk3jwRoWLp//FnawQX0g5T64CnfAe/o2e/8o5/bvz83OsAAwZoR48GZzPu7KCIN9q4GBjyrePNx5Csq2srblifmzSKwF5MP/RLYsk6mEE15jpCMKOVlHcu0zhJybNP3AKMVllF6pvn+HWvUnLXNkt0A6zsfvjAva/tbLQiiiYi6vtheasIyDz3HpODlI+BCkV6V8lkTt7m8QJ1IcgTfqjQBummyjYTSwsQji3DdNCnlKYd13ZQa545utqu837FFAzOZQhbnC3bKqeJqO2sE3m7WBUMbRWLflPRqp/PsklN+9jBPADKxKPl8g6/NZVq8fB1w68D5EJlGExdDhglo4B0aihHhb1u3+zJ2DqkxkPCGBAZ2AcuFIDzD53yS4NssoWb4HJ7YyzPaJro+tgG9TshWRBtUw8Or3m0OtQtX+rboYn3+GxvD1O8vWInrg5qxnepelRcQzmnor4rHF6ZNhAJZAf18Rjncra00HPJBugY5rD+EwnN9+mGQo43b01qBBRYEnxy9JJYuvXxNXxe47/MEPOw6qsxN+dmyIWZSuzkw8K+iBM/anE11yfU4qTFt0veCaVprK6tXaFK0ZhGXDOYJd70sjIP4UrPhatp8hqIXSJ2cwi70B+TvlDk/o19CA3bH6YxrAAVeag1P9hmNlfJ7NxK3Jp7+Ny1Vd7JHWVF+R6rSJiXXPfsXi3ZEy0klJAjI51NrDAnzNtgIQf0V8OWeEVv7F8Rsm3/GKnjdNOcDKymi9agZUgtctENWbCXGFnI40NHuVHtBRZeYAYtwfV7v6U0bP9s7uZGpkp+OETHMv3AyV0MVbZwQvarnjmct4Z3Vma+DvT+Z4VlMVnkC2x2FLt26K3SIMz+KV2XLv5ocEdPFSn1vMR7zruCWC8XqAG288biHo/soldmb/nlw8o8qlfZj4h296K3hfdFubGIUtqgsrZCrLCkkRC08Cv1ozEX/y6t2YrQepwiNmwDVk5IufStVvJMj+y2r9TcYLv7UKWXx3P6aySvM2ZHPaZhv+6Z/A/jIMBSvOizn4qG11iK7Oo6JYhxCSMJZsetjsnL4ecSIAufEmoFlAScWBh6nFArRpVLvkAZ3tej7H2lWFRXIU7x7mdBfGqU82PpM6znKMMZCpEsvHqpkSPSL+Kwz2z1f5wW7BKcKK4kNZ8iveg9VzY1NNjs91qU8DJpUnGyM04C7KNMpeilEmoOxvyelMQdi85ndOVmigVKmy5JYlODNX744sHpeqmMEK/ux3xY5O406lm7dZlyGPSMrFWbm4rzqvSEIskP43+9xVP8L84GeHE4RpOHg3qh/shx+/WnT1UhKuKpByHCpLoEo144udpzZswCYSMp58uPrlwdVF31//AacTRk8dUP3tBlnSQPa1eTpXWFCn7vIiqOTXaRL//YQK+e7ssrgSUnwhuGKJ8aqNDgdsL+haVZnV9g5Qrju643adyNixvYFEp0uxzOzVkekOMh2FYnFVIL2mJYGpZEXlAIC0zQbb54rSP89j0G7soJ2HcOkD0NmMEWj/7hUdTuMin1lRNde/qmHjwhbhqL8Z9MEO/YG3iLMgFTgSNQQhyE8AZAAKnehmzjORJfbK+qxyiJ07J843EDduzOoYt9p/YLqyTFmAgpdfK0uYrtAJ47cbl5WWhVXp5/XUxwWdL7TvQB0Xh6ir1/XBRcsVSDrR7cPE221ThmW1EPzD+SPf2L2gS0WromZqj1PhLgk92YnnR9s7/nLBXZHPKy+fDbJT16QqabFKqAl9G0blyf+R5UGX2kN+iQp4VGXEoH5lXxNNTlgRskzrW7KliQXcac20oimAHUE8Phf+rXXglpmSv4XN3eiwfXwvOaAMVjMRmRxsKitl5iZnwpcdbsC4jt16g2r/ihlKzLIYju+XZej4dNMlkftEidyNg24IVimJthXY1H15RZ8Hm7mAM/JZrsxiAVI0A49pWEiUk3cyZcBzq/vVEjHUy4r6IZnKkRvLjqsvqWE95nAGMor+F0GLHWfBCVkuI51EIOknwSB1eTvLgwgRepV4pdy9cdp6iR8TZndPVCikflXYVMlMEJ2bJ2c0Swiq57ORJW6vQwnkxtPudpFRc7tNNDzz4LKEznJxAwGi6pBR7/co2IUgRw1ijLFTHWHQJOjgc7KaduHI0C6a+BJb4Y8IWuIk2u2qCMF1HNKFAUn/J1gTcqtIJcvK5uykpfJFCYc899TmUc8LMKI9nu57m0S44Y2hPPYeW4XSakScsg8bJHMkcXk3Tbs9b4eqiD+kHUhTS2BGfsHadR3d5j8lNhBPzA5e+mE==",
tspFromClient = DateTimeUtil.GetUnixTimestampMilliseconds()
};
var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json");
_httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.47");
var response = await _httpClient.PostAsync("https://mssdk.bytedance.com/web/report", content);
response.EnsureSuccessStatusCode();
var sss = await response.Content.ReadAsStringAsync();
//var cookies = response.Headers.GetValues("Set-Cookie");
var msToken = response.Headers.GetValues("X-Ms-Token").FirstOrDefault();
//var msToken = cookies.FirstOrDefault(c => c.StartsWith("msToken="))?.Split(';')[0].Split('=')[1];
if (msToken != null && (msToken.Length != 120 || msToken.Length != 128))
return msToken;
throw new Exception("msToken格式不正确");
}
catch (Exception ex)
{
// 生成虚假token
return GenFalseMsToken();
}
}
public static string GenFalseMsToken()
{
var rand = new Random();
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
return new string(Enumerable.Repeat(chars, 126)
.Select(s => s[rand.Next(s.Length)]).ToArray()) + "==";
}
}
}
-337
View File
@@ -1,337 +0,0 @@
using System.Collections.Generic;
namespace dy.net.utils
{
/// <summary>
/// 抖音网页端请求参数字典管理类
/// 提供各类接口的标准化参数字典,对外暴露的属性名称和返回类型保持不变
/// </summary>
public static class DouyinBaseParamDics
{
/// <summary>
/// 收藏列表参数(用户收藏的内容)
/// </summary>
public static Dictionary<string, string> CollectParams { get; } = InitializeUserCollectParams();
/// <summary>
/// 用户收藏参数(与 CollectParams 功能区分,保留原始定义)
/// </summary>
public static Dictionary<string, string> FavoriteParams { get; } = InitializeUserFavoriteParams();
/// <summary>
/// 博主发布作品参数
/// </summary>
public static Dictionary<string, string> UpderPostParams { get; } = InitializeUpderPostParams();
/// <summary>
/// 我关注的博主列表参数
/// </summary>
public static Dictionary<string, string> MyFollowParams { get; } = InitializeMyFollowParams();
/// <summary>
/// 视频详情
/// </summary>
public static Dictionary<string, string> ViedoDetailParam { get; } = InitializeViedoDetailParam();
/// <summary>
/// 抖音作品列表请求参数(适配接口:https://www.douyin.com/aweme/v1/web/aweme/post/
/// </summary>
public static Dictionary<string, string> InitializeDouyinPostParams()
{
// 基于基础参数扩展,减少冗余
var parameters = GetBaseParameters();
// 覆盖基础参数中不同的值
parameters["version_code"] = "290100";
parameters["version_name"] = "29.1.0";
parameters["screen_width"] = "1707";
parameters["screen_height"] = "1067";
parameters["browser_name"] = "Chrome";
parameters["browser_version"] = "142.0.0.0";
parameters["engine_version"] = "142.0.0.0";
parameters["cpu_core_num"] = "32";
parameters["support_h265"] = "1";
parameters["support_dash"] = "1";
// 添加特有参数
parameters.AddRange(new Dictionary<string, string>
{
{"sec_user_id", ""},
{"max_cursor", "0"},
{"locate_item_id", "7576282367263807451"},
{"locate_query", "false"},
{"count", "18"},
{"show_live_replay_strategy", "1"},
{"need_time_list", "1"},
{"time_list_query", "0"},
{"publish_video_strategy_type", "2"},
{"from_user_page", "1"},
{"webid", "7574080345697584675"},
{"uifid", ""},
{"msToken", ""},
{"a_bogus", ""},
{"verifyFp", ""},
{"fp", ""},
{"x-secsdk-web-expire", ""},
{"x-secsdk-web-signature", ""},
{"cut_version", "1"}
});
return parameters;
}
#region
/// <summary>
/// 初始化收藏列表参数
/// </summary>
private static Dictionary<string, string> InitializeUserCollectParams()
{
var parameters = GetBaseParameters();
// 覆盖基础参数
parameters["version_code"] = "290100";
parameters["version_name"] = "29.1.0";
parameters["screen_width"] = "1920";
parameters["screen_height"] = "1080";
parameters["browser_version"] = "130.0.0.0";
parameters["engine_version"] = "130.0.0.0";
parameters["cpu_core_num"] = "12";
// 添加特有参数
parameters.AddRange(new Dictionary<string, string>
{
{"from_user_page", "1"},
{"locate_query", "false"},
{"need_time_list", "1"},
{"show_live_replay_strategy", "1"},
{"time_list_query", "0"}
});
return parameters;
}
/// <summary>
/// 初始化用户收藏参数
/// </summary>
private static Dictionary<string, string> InitializeUserFavoriteParams()
{
var parameters = GetBaseParameters();
// 覆盖基础参数
parameters["version_code"] = "170400";
parameters["version_name"] = "17.4.0";
parameters["screen_width"] = "1536";
parameters["screen_height"] = "960";
parameters["browser_version"] = "140.0.0.0";
parameters["engine_version"] = "140.0.0.0";
parameters["cpu_core_num"] = "20";
parameters["support_h265"] = "1";
parameters["support_dash"] = "1";
// 添加特有参数
parameters.AddRange(new Dictionary<string, string>
{
{"min_cursor", "0"},
{"cut_version", "1"},
{"count", "18"}
});
return parameters;
}
/// <summary>
/// 初始化博主发布作品参数
/// </summary>
private static Dictionary<string, string> InitializeUpderPostParams()
{
// 该接口参数差异较大,单独初始化(保留原始参数完整)
return new Dictionary<string, string>
{
{"WebIdLastTime", "1714385892"},
{"aid", "1988"},
{"app_language", "zh-Hans"},
{"app_name", "tiktok_web"},
{"browser_language", "zh-CN"},
{"browser_name", "Mozilla"},
{"browser_online", "true"},
{"browser_platform", "Win32"},
{"browser_version", "5.0%20%28Windows%29"},
{"cookie_enabled", "true"},
{"count", "18"},
{"coverFormat", "2"},
{"cursor", "0"},
{"data_collection_enabled", "true"},
{"device_id", "7380187414842836523"},
{"device_platform", "webapp"},
{"channel", "channel_pc_web"},
{"focus_state", "true"},
{"from_page", "user"},
{"history_len", "3"},
{"is_fullscreen", "false"},
{"is_page_visible", "true"},
{"language", "zh-Hans"},
{"locate_item_id", ""},
{"needPinnedItemIds", "true"},
{"odinId", "7404669909585003563"},
{"os", "windows"},
{"post_item_list_request_type", "0"},
{"priority_region", "US"},
{"referer", ""},
{"region", "US"},
{"screen_height", "827"},
{"screen_width", "1323"},
{"secUid", ""},
{"sec_user_id", ""},
{"tz_name", "America%2FLos_Angeles"},
{"user_is_login", "true"},
{"webcast_language", "zh-Hans"},
{"msToken", ""}
};
}
/// <summary>
/// 初始化我关注的博主列表参数
/// </summary>
private static Dictionary<string, string> InitializeMyFollowParams()
{
var parameters = GetBaseParameters();
// 覆盖基础参数
parameters["version_code"] = "170400";
parameters["version_name"] = "17.4.0";
parameters["screen_width"] = "1707";
parameters["screen_height"] = "1067";
parameters["browser_name"] = "Edge";
parameters["browser_version"] = "141.0.0.0";
parameters["engine_version"] = "141.0.0.0";
parameters["cpu_core_num"] = "32";
parameters["support_h265"] = "1";
parameters["support_dash"] = "1";
// 添加特有参数
parameters.AddRange(new Dictionary<string, string>
{
{"user_id", ""},//空着
{"sec_user_id", ""},
{"offset", "40"},
{"min_time", "0"},
{"max_time", "0"},
{"count", "20"},
{"source_type", "4"},
{"gps_access", "0"},
{"address_book_access", "0"},
{"is_top", "1"},
{"webid", "7577203855940994560"},
{"uifid", ""},
{"msToken", ""},
{"a_bogus", ""},
{"verifyFp", ""},
{"fp", ""}
});
return parameters;
}
#endregion
#region
/// <summary>
/// 获取抖音网页端基础参数字典(所有接口的公共参数)
/// </summary>
private static Dictionary<string, string> GetBaseParameters()
{
return new Dictionary<string, string>
{
{"device_platform", "webapp"},
{"aid", "6383"},
{"channel", "channel_pc_web"},
{"pc_client_type", "1"},
{"pc_libra_divert", "Windows"},
{"cookie_enabled", "true"},
{"browser_language", "zh-CN"},
{"browser_platform", "Win32"},
{"browser_name", "Chrome"},
{"browser_online", "true"},
{"engine_name", "Blink"},
{"os_name", "Windows"},
{"os_version", "10"},
{"device_memory", "8"},
{"platform", "PC"},
{"downlink", "10"},
{"effective_type", "4g"},
{"round_trip_time", "0"},
{"update_version_code", "170400"},
{"whale_cut_token", ""}
};
}
private static Dictionary<string, string> InitializeViedoDetailParam()
{
Dictionary<string, string> requestParams = new Dictionary<string, string>
{
{ "device_platform", "webapp" },
{ "aid", "6383" },
{ "channel", "channel_pc_web" },
{ "aweme_id", "" },
{ "request_source", "600" },
{ "origin_type", "video_page" },
{ "update_version_code", "170400" },
{ "pc_client_type", "1" },
{ "pc_libra_divert", "Windows" },
{ "support_h265", "1" },
{ "support_dash", "1" },
{ "cpu_core_num", "32" },
{ "version_code", "190500" },
{ "version_name", "19.5.0" },
{ "cookie_enabled", "true" },
{ "screen_width", "1707" },
{ "screen_height", "1067" },
{ "browser_language", "zh-CN" },
{ "browser_platform", "Win32" },
{ "browser_name", "Edge" },
{ "browser_version", "141.0.0.0" },
{ "browser_online", "true" },
{ "engine_name", "Blink" },
{ "engine_version", "141.0.0.0" },
{ "os_name", "Windows" },
{ "os_version", "10" },
{ "device_memory", "8" },
{ "platform", "PC" },
{ "downlink", "10" },
{ "effective_type", "4g" },
{ "round_trip_time", "0" },
{ "webid", "7577203855940994560" },
{ "uifid", "0e81ba593d64ebaca259bdbe302de8d7e55ac2e982f7412f10fbc5c77c64bb8b8830ffed112ea8b3bc54f3b6e2af3856daafa4efaafef18953612820da493aeaebdeac0537b99b8e68f343c2476cf6347f7751a87d92952128116470f147215cf46b949f43f31aedcb660fd3c5c7eb2145183cc93d1b4202205b4af7d7c69ab55e860f96e315899a2ee74a262273694ec973ba682bb6fdc351e0e66250b21cf9aef3ccaa3e0c28b085fd095e947d92a5336b9e65706d649a7b79541feab3487f" },
{ "verifyFp", "verify_migsr5je_BJ1YiVbY_uR2U_4VXu_8Uje_GgwhVf7Y6hb8" },
{ "fp", "verify_migsr5je_BJ1YiVbY_uR2U_4VXu_8Uje_GgwhVf7Y6hb8" },
//{ "msToken", "zVKqVOb-uBF-Opse1B5y9u0hw7SlRa49w8HB56cVSY0Uymjqs17JJ9qOUXv7IK0j3de1ErBjSVAm0JSd5SH1sYg7jeriVvGNJoDUM3dKwVCrqlapZgU9g2aYAeHs5oHddTGtZ3Pri9MIRltXVRdirZWMewfH8MlqmIVaCiTuGzRcZ6va9aWe0CyR" },
//{ "a_bogus", "dy45kFWjOxRfOdFtmOnc9WxlY8L%2FNTuy6Pi2SYAP9PKGcwFcaWNpBNCfrxLuRUd%2FzuBzhe3HqdlMYDnc0zX0ZenkKmkkupv6Bt%2FC9L0LZZHvbBJZ7rgiemSxzk4O8KsOmAIbiM75AsBEIxo5VrCwAdlCu%2F-xBbmD%2Fp3vVATCE2ysUAujwn%2FVa-JDNw7qaf%3D%3D" },
//{ "x-secsdk-web-expire", "1764378577130" },
//{ "x-secsdk-web-signature", "3b8aa32e9457ebe3b65afdae11e2fe86" }
};
return requestParams;
}
/// <summary>
/// 字典扩展方法:批量添加键值对(避免重复 Add 调用)
/// </summary>
private static void AddRange(this Dictionary<string, string> target, Dictionary<string, string> source)
{
foreach (var item in source)
{
// 避免键重复(如果有重复以源字典为准)
if (target.ContainsKey(item.Key))
target[item.Key] = item.Value;
else
target.Add(item.Key, item.Value);
}
}
#endregion
}
}
+440
View File
@@ -0,0 +1,440 @@
using System.Collections.Generic;
namespace dy.net.utils
{
/// <summary>
/// 抖音网页端请求参数字典管理类
/// 统一管理各类接口的标准化参数字典,提供全局常量和静态只读参数属性
/// </summary>
public static class DouyinRequestParamManager
{
#region
/// <summary>
/// 抖音全局域名
/// </summary>
public static readonly string DouyinHost = "https://www.douyin.com";
/// <summary>
/// 数据请求客户端标识
/// </summary>
public const string DY_HTTP_CLIENT = "douyin-client";
/// <summary>
/// 下载客户端标识
/// </summary>
public const string DY_HTTP_CLIENT_DOWN = "douyin-client_down";
/// <summary>
/// 请求头User-Agent标识
/// </summary>
public const string DY_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36";
#endregion
#region
/// <summary>
/// 收藏列表参数(用户收藏的内容)
/// </summary>
public static Dictionary<string, string> DouyinCollectParams { get; } = InitUserCollectParams();
/// <summary>
/// 用户喜欢参数(用户点赞的内容)
/// </summary>
public static Dictionary<string, string> DouyinFavoriteParams { get; } = InitUserFavoriteParams();
/// <summary>
/// 博主发布作品参数
/// </summary>
public static Dictionary<string, string> DouyinUpderPostParams { get; } = InitDouyinPostParams();
/// <summary>
/// 我的关注列表参数
/// </summary>
public static Dictionary<string, string> DouyinMyFollowParams { get; } = InitMyFollowParams();
/// <summary>
/// 收藏夹按收藏文件夹名称获取作品列表完整请求参数字典
/// </summary>
public static Dictionary<string, string> DouyinFolderCollectParams { get; } = InitCollectFolderParams();
/// <summary>
/// 抖音收藏列表接口完整参数字典(对应目标URL)
/// </summary>
public static Dictionary<string, string> DouyinCollectListParams { get; } = InitCollectListParams();
/// <summary>
/// 抖音合集列表参数
/// </summary>
public static Dictionary<string, string> DouyinMixListParams { get; } = InitMixListParams();
/// <summary>
/// 合集视频请求参数字典
/// </summary>
public static Dictionary<string, string> DouyinMixVideoParams { get; } = InitMixVideoParams();
/// <summary>
/// 抖音短剧列表参数
/// </summary>
public static Dictionary<string, string> DouyinSeriesListParams { get; } = InitSeriesListParams();
/// <summary>
/// 抖音短剧视频参数(修正拼写:Viedos→Videos
/// </summary>
public static Dictionary<string, string> DouyinSeriesVideosParams { get; } = InitSeriesVideosParams();
#endregion
#region
/// <summary>
/// 初始化抖音短剧视频参数(获取短剧内的视频列表)
/// </summary>
private static Dictionary<string, string> InitSeriesVideosParams()
{
var parameters = InitBaseParams();
// 覆盖基础参数(直接赋值,仅修改与基础参数不一致的项)
parameters["version_code"] = "170400";
parameters["version_name"] = "17.4.0";
parameters["screen_width"] = "1707";
parameters["screen_height"] = "1067";
parameters["browser_name"] = "Edge";
parameters["browser_version"] = "141.0.0.0";
parameters["engine_version"] = "141.0.0.0";
parameters["cpu_core_num"] = "32";
parameters["support_h265"] = "1";
parameters["support_dash"] = "1";
parameters["round_trip_time"] = "50";
parameters["webid"] = "7584476599598188067";
// 新增特有参数(使用Add方法,明确区分"覆盖"与"新增",提高可读性)
parameters.Add("pull_type", "2");
parameters.Add("series_id", ""); // 动态参数:短剧系列唯一标识,后续赋值
parameters.Add("cursor", "0"); // 动态参数:分页游标,默认从0开始
parameters.Add("count", "20"); // 动态参数:每页获取数量,默认20条
return parameters;
}
/// <summary>
/// 初始化抖音短剧列表参数
/// </summary>
private static Dictionary<string, string> InitSeriesListParams()
{
var parameters = InitBaseParams();
// 直接赋值覆盖基础参数
parameters["version_code"] = "170400";
parameters["version_name"] = "17.4.0";
parameters["screen_width"] = "1707";
parameters["screen_height"] = "1067";
parameters["browser_name"] = "Edge";
parameters["browser_version"] = "141.0.0.0";
parameters["engine_version"] = "141.0.0.0";
parameters["cpu_core_num"] = "32";
parameters["support_h265"] = "1";
parameters["support_dash"] = "1";
parameters["round_trip_time"] = "50";
parameters["webid"] = "7584476599598188067";
// 新增特有分页参数
parameters.Add("cursor", "0");
parameters.Add("count", "20");
return parameters;
}
#endregion
#region
/// <summary>
/// 初始化抖音合集列表请求参数
/// </summary>
private static Dictionary<string, string> InitMixListParams()
{
var parameters = InitBaseParams();
// 直接赋值覆盖基础参数(严格对应目标接口)
parameters["version_code"] = "170400";
parameters["version_name"] = "17.4.0";
parameters["screen_width"] = "1707";
parameters["screen_height"] = "1067";
parameters["browser_name"] = "Edge";
parameters["browser_version"] = "141.0.0.0";
parameters["engine_version"] = "141.0.0.0";
parameters["cpu_core_num"] = "32";
parameters["support_h265"] = "1";
parameters["support_dash"] = "1";
parameters["webid"] = "7584476599598188067";
// 新增特有分页参数
parameters.Add("cursor", "0");
parameters.Add("count", "20");
return parameters;
}
/// <summary>
/// 初始化合集视频请求参数(复用基础参数,消除冗余)
/// </summary>
private static Dictionary<string, string> InitMixVideoParams()
{
var parameters = InitBaseParams();
// 覆盖基础参数,无需重复定义全部公共参数
parameters["version_code"] = "170400";
parameters["version_name"] = "17.4.0";
parameters["screen_width"] = "1707";
parameters["screen_height"] = "1067";
parameters["browser_name"] = "Edge";
parameters["browser_version"] = "141.0.0.0";
parameters["engine_version"] = "141.0.0.0";
parameters["cpu_core_num"] = "32";
parameters["support_h265"] = "1";
parameters["support_dash"] = "1";
parameters["webid"] = "7584476599598188067";
// 新增特有参数
parameters.Add("mix_id", ""); // 动态参数:合集唯一标识,后续赋值
parameters.Add("cursor", "0"); // 动态参数:分页游标,默认从0开始
parameters.Add("count", "20"); // 动态参数:每页获取数量,默认20条
return parameters;
}
#endregion
#region
/// <summary>
/// 初始化抖音收藏列表接口参数
/// </summary>
private static Dictionary<string, string> InitCollectListParams()
{
var parameters = InitBaseParams();
// 覆盖基础参数
parameters["version_code"] = "170400";
parameters["version_name"] = "17.4.0";
parameters["screen_width"] = "1707";
parameters["screen_height"] = "1067";
parameters["browser_name"] = "Edge";
parameters["browser_version"] = "141.0.0.0";
parameters["engine_version"] = "141.0.0.0";
parameters["cpu_core_num"] = "32";
parameters["support_h265"] = "1";
parameters["support_dash"] = "1";
parameters["webid"] = "7584476599598188067";
// 新增特有动态参数
parameters.Add("cursor", "0"); // 默认分页游标为0,后续可修改
parameters.Add("count", ""); // 动态参数:每页获取数量,后续赋值
return parameters;
}
/// <summary>
/// 初始化收藏夹按文件夹查询作品参数
/// </summary>
private static Dictionary<string, string> InitCollectFolderParams()
{
var parameters = InitBaseParams();
// 覆盖基础参数
parameters["version_code"] = "170400";
parameters["version_name"] = "17.4.0";
parameters["screen_width"] = "1707";
parameters["screen_height"] = "1067";
parameters["browser_name"] = "Edge";
parameters["browser_version"] = "141.0.0.0";
parameters["engine_version"] = "141.0.0.0";
parameters["cpu_core_num"] = "32";
parameters["support_h265"] = "1";
parameters["support_dash"] = "1";
parameters["webid"] = "7584476599598188067";
// 新增特有动态参数
parameters.Add("collects_id", ""); // 动态参数:收藏夹ID,后续赋值 collect.CollectsId
parameters.Add("cursor", ""); // 动态参数:分页游标,后续赋值
parameters.Add("count", ""); // 动态参数:每页获取数量,后续赋值
return parameters;
}
#endregion
#region //
/// <summary>
/// 初始化抖音博主发布作品参数(修正访问修饰符:public→private
/// </summary>
private static Dictionary<string, string> InitDouyinPostParams()
{
var parameters = InitBaseParams();
// 覆盖基础参数
parameters["version_code"] = "290100";
parameters["version_name"] = "29.1.0";
parameters["screen_width"] = "1707";
parameters["screen_height"] = "1067";
parameters["browser_name"] = "Chrome";
parameters["browser_version"] = "142.0.0.0";
parameters["engine_version"] = "142.0.0.0";
parameters["cpu_core_num"] = "32";
parameters["support_h265"] = "1";
parameters["support_dash"] = "1";
parameters["webid"] = "7574080345697584675";
// 新增特有参数(含签名相关空参数,后续补充)
parameters.Add("locate_item_id", "7576282367263807451");
parameters.Add("locate_query", "false");
parameters.Add("show_live_replay_strategy", "1");
parameters.Add("need_time_list", "1");
parameters.Add("time_list_query", "0");
parameters.Add("publish_video_strategy_type", "2");
parameters.Add("from_user_page", "1");
parameters.Add("uifid", "");
parameters.Add("msToken", "");
parameters.Add("a_bogus", "");
parameters.Add("verifyFp", "");
parameters.Add("fp", "");
parameters.Add("x-secsdk-web-expire", "");
parameters.Add("x-secsdk-web-signature", "");
parameters.Add("cut_version", "1");
parameters.Add("sec_user_id", ""); // 动态参数:博主加密ID,后续赋值
parameters.Add("max_cursor", "0"); // 分页游标,默认从0开始
parameters.Add("count", "18"); // 每页默认获取18条作品
return parameters;
}
/// <summary>
/// 初始化默认的收藏列表参数
/// </summary>
private static Dictionary<string, string> InitUserCollectParams()
{
var parameters = InitBaseParams();
// 覆盖基础参数
parameters["version_code"] = "290100";
parameters["version_name"] = "29.1.0";
parameters["screen_width"] = "1920";
parameters["screen_height"] = "1080";
parameters["browser_version"] = "130.0.0.0";
parameters["engine_version"] = "130.0.0.0";
parameters["cpu_core_num"] = "12";
parameters["from_user_page"] = "1";
parameters["locate_query"] = "false";
parameters["need_time_list"] = "1";
parameters["show_live_replay_strategy"] = "1";
parameters["time_list_query"] = "0";
return parameters;
}
/// <summary>
/// 初始化用户喜欢(点赞)列表参数
/// </summary>
private static Dictionary<string, string> InitUserFavoriteParams()
{
var parameters = InitBaseParams();
// 覆盖基础参数
parameters["version_code"] = "170400";
parameters["version_name"] = "17.4.0";
parameters["screen_width"] = "1536";
parameters["screen_height"] = "960";
parameters["browser_version"] = "140.0.0.0";
parameters["engine_version"] = "140.0.0.0";
parameters["cpu_core_num"] = "20";
parameters["support_h265"] = "1";
parameters["support_dash"] = "1";
// 新增特有参数
parameters.Add("min_cursor", "0");
parameters.Add("cut_version", "1");
parameters.Add("count", "18");
return parameters;
}
/// <summary>
/// 初始化我关注的博主列表参数
/// </summary>
private static Dictionary<string, string> InitMyFollowParams()
{
var parameters = InitBaseParams();
// 覆盖基础参数
parameters["version_code"] = "170400";
parameters["version_name"] = "17.4.0";
parameters["screen_width"] = "1707";
parameters["screen_height"] = "1067";
parameters["browser_name"] = "Edge";
parameters["browser_version"] = "141.0.0.0";
parameters["engine_version"] = "141.0.0.0";
parameters["cpu_core_num"] = "32";
parameters["support_h265"] = "1";
parameters["support_dash"] = "1";
parameters["webid"] = "7577203855940994560";
// 新增特有参数(含动态用户ID和签名参数)
parameters.Add("min_time", "0");
parameters.Add("max_time", "0");
parameters.Add("source_type", "4");
parameters.Add("gps_access", "0");
parameters.Add("address_book_access", "0");
parameters.Add("is_top", "1");
//parameters.Add("uifid", "");
//parameters.Add("msToken", "");
//parameters.Add("a_bogus", "");
//parameters.Add("verifyFp", "");
//parameters.Add("fp", "");
parameters.Add("user_id", ""); // 动态参数:用户ID,后续赋值
parameters.Add("sec_user_id", ""); // 动态参数:加密用户ID,后续赋值
parameters.Add("offset", "0"); // 分页偏移量,默认从0开始
parameters.Add("count", "20"); // 每页默认获取20个关注博主
return parameters;
}
#endregion
#region
/// <summary>
/// 私有静态只读基础参数模板(仅创建1次)
/// </summary>
private static readonly Dictionary<string, string> _baseParamTemplate = new Dictionary<string, string>
{
{"device_platform", "webapp"},
{"aid", "6383"},
{"channel", "channel_pc_web"},
{"pc_client_type", "1"},
{"pc_libra_divert", "Windows"},
{"cookie_enabled", "true"},
{"browser_language", "zh-CN"},
{"browser_platform", "Win32"},
{"browser_name", "Chrome"},
{"browser_online", "true"},
{"engine_name", "Blink"},
{"os_name", "Windows"},
{"os_version", "10"},
{"device_memory", "8"},
{"platform", "PC"},
{"downlink", "10"},
{"effective_type", "4g"},
{"round_trip_time", "0"},
{"update_version_code", "170400"},
{"whale_cut_token", ""}
};
/// <summary>
///
/// </summary>
/// <returns></returns>
private static Dictionary<string, string> InitBaseParams()
{
return new Dictionary<string, string>(_baseParamTemplate);
}
#endregion
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
using dy.net.dto; using dy.net.model.dto;
using Serilog; using Serilog;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
-5
View File
@@ -28,10 +28,5 @@ namespace dy.net.utils
string hashString = sb.ToString(); string hashString = sb.ToString();
return hashString; return hashString;
} }
public static string UPLOAD_PATH_PRO = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "upload");
public static string UPLOAD_PATH_DEV = Path.Combine(Directory.GetCurrentDirectory(), "upload");
} }
} }
+2 -2
View File
@@ -1,5 +1,5 @@
using dy.net.dto; using dy.net.model.dto;
using dy.net.model; using dy.net.model.entity;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Xml.Linq; using System.Xml.Linq;
-16
View File
@@ -1,16 +0,0 @@
namespace dy.net.utils
{
public class SystemStaticUtil
{
//public static string DOWN_IMAGE_VIDEO_ENABLE="DOWN_IMGVIDEO";
public static string APP_PORT = "appPort";
public static string DY_FOLLOWEDS = "dy_followeds";
public static string DY_COLLECTS = "dy_collects";
public static string DY_FAVORITES = "dy_favorites";
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
using dy.net.dto; using dy.net.model.dto;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace dy.net.utils namespace dy.net.utils