结构调整
This commit is contained in:
@@ -7,7 +7,7 @@ using System.Security.Claims;
|
||||
using System.Text;
|
||||
using dy.net.service;
|
||||
using dy.net.utils;
|
||||
using dy.net.dto;
|
||||
using dy.net.model.dto;
|
||||
|
||||
namespace dy.net.Controllers
|
||||
{
|
||||
@@ -50,54 +50,6 @@ namespace dy.net.Controllers
|
||||
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("无效的文件");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using ClockSnowFlake;
|
||||
using dy.net.dto;
|
||||
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.utils;
|
||||
using dy.sync.lib;
|
||||
@@ -28,26 +28,18 @@ namespace dy.net.Controllers
|
||||
private readonly DouyinQuartzJobService quartzJobService;
|
||||
private readonly DouyinFollowService douyinFollowService;
|
||||
private readonly DouyinCookieService douyinCookieService;
|
||||
|
||||
//// 定义允许上传的音频扩展名(小写)
|
||||
//private readonly string[] _allowedAudioExtensions = { ".mp3", ".wav" };
|
||||
|
||||
//// 定义允许的音频 MIME 类型(增强验证)
|
||||
//private readonly string[] _allowedAudioMimeTypes = {
|
||||
// "audio/mpeg", "audio/wav"
|
||||
//};
|
||||
|
||||
// 最大文件大小:20MB(可根据需求调整)
|
||||
//private const long _maxFileSize = 20 * 1024 * 1024;
|
||||
private readonly DouyinHttpClientService httpClientService;
|
||||
|
||||
|
||||
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.commonService = commonService;
|
||||
this.quartzJobService = quartzJobService;
|
||||
this.douyinFollowService = douyinFollowService;
|
||||
this.douyinCookieService = douyinCookieService;
|
||||
this.httpClientService = httpClientService;
|
||||
}
|
||||
|
||||
|
||||
@@ -161,6 +153,12 @@ namespace dy.net.Controllers
|
||||
public async Task<IActionResult> AddAsync([FromBody] DouyinCookie dyUserCookies)
|
||||
{
|
||||
|
||||
var checkCk = await httpClientService.CheckCookie(dyUserCookies);
|
||||
if (!checkCk)
|
||||
{
|
||||
return ApiResult.Fail("Cookie无效,请按照文档提示重新获取有效Cookie,不要使用插件获取cookie");
|
||||
}
|
||||
|
||||
var result = await dyCookieService.Add(dyUserCookies);
|
||||
if (result)
|
||||
{
|
||||
@@ -204,29 +202,21 @@ namespace dy.net.Controllers
|
||||
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);
|
||||
if (result)
|
||||
{
|
||||
|
||||
return ApiResult.Success();
|
||||
}
|
||||
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>
|
||||
/// 快速开启或停止
|
||||
@@ -248,6 +238,11 @@ namespace dy.net.Controllers
|
||||
[HttpPost("update")]
|
||||
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")
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using dy.net.dto;
|
||||
using dy.net.model;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using dy.net.service;
|
||||
using dy.net.utils;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using dy.net.dto;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.service;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using dy.net.dto;
|
||||
using dy.net.model;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using dy.net.service;
|
||||
using dy.net.utils;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
+1
-2
@@ -11,7 +11,7 @@ namespace dy.net
|
||||
public class Program
|
||||
{
|
||||
// 常量定义
|
||||
private static string DefaultListenUrl = "10101";
|
||||
private static string DefaultListenUrl = "http://*:10101";
|
||||
private const string SpaRootPath = "app/dist";
|
||||
private const string SpaSourcePath = "app/";
|
||||
private const string SwaggerDocTitle = "dy.net WebApi Docs";
|
||||
@@ -49,7 +49,6 @@ namespace dy.net
|
||||
{
|
||||
InitAppsettings(builder);
|
||||
//from docker yaml file 环境变量 或者 dockerfile 或appsettings.json
|
||||
DefaultListenUrl = $"http://*:{builder.Configuration.GetValue<string>(SystemStaticUtil.APP_PORT) ?? DefaultListenUrl}";
|
||||
// 设置监听地址
|
||||
builder.WebHost.UseUrls(DefaultListenUrl);
|
||||
// 配置日志
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<_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 />
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -44,7 +44,7 @@ onMounted(() => {
|
||||
</div> -->
|
||||
|
||||
<!-- 新增:显示当前版本号,增加样式分隔提升美观度 -->
|
||||
<span class="version-text">{{currentVersion.deploy}}_{{ currentVersion.tag }}</span>
|
||||
<span class="version-text" v-if="currentVersion">{{currentVersion.deploy}}_{{ currentVersion.tag }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
// 原有代码不变,此处省略(仅保留模板相关修改,脚本逻辑无变化)
|
||||
import { getBase64 } from '@/utils/file';
|
||||
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 {
|
||||
@@ -26,14 +25,14 @@ columns.value = [
|
||||
dataIndex: 'userName',
|
||||
width: 180,
|
||||
},
|
||||
{ title: 'Cookie状态', dataIndex: 'statusMsg' },
|
||||
{ title: '收藏路径', dataIndex: 'savePath' },
|
||||
{ title: '喜欢路径', dataIndex: 'favSavePath' },
|
||||
{ title: '博主路径', dataIndex: 'upSavePath' },
|
||||
{ title: '图文视频', dataIndex: 'imgSavePath' },
|
||||
{ title: 'Cookie', dataIndex: 'cookies' },
|
||||
{ title: '有效状态', dataIndex: 'statusMsg' },
|
||||
// { title: 'Cookie', dataIndex: 'cookies' },
|
||||
{ title: '状态', dataIndex: 'status', width: 180 },
|
||||
{ title: '操作', dataIndex: 'edit', width: 350 }, // 加宽操作列宽度
|
||||
{ title: '操作', dataIndex: 'edit', width: 200 }, // 加宽操作列宽度
|
||||
];
|
||||
|
||||
// 定义数组中单个对象的类型:包含uper和uid字段(可选字符串类型,根据实际需求调整是否可选)
|
||||
@@ -57,6 +56,9 @@ type DataItem = {
|
||||
upSavePath?: string;
|
||||
imgSavePath?: string;
|
||||
useSinglePath?: boolean; // 新增:是否全部用一个地址
|
||||
useCollectFolder?: boolean;
|
||||
downMix?: boolean;
|
||||
downSeries?: boolean;
|
||||
};
|
||||
|
||||
const loading = ref(false);
|
||||
@@ -117,6 +119,9 @@ const newCookie = (cookie?: DataItem) => {
|
||||
cookie.upSavePath = undefined;
|
||||
cookie.imgSavePath = undefined;
|
||||
cookie.useSinglePath = false; // 新增:默认不使用单一路径
|
||||
cookie.useCollectFolder = false; //是否按收藏夹来下载。
|
||||
cookie.downMix = false; //是否下载收藏夹的合集
|
||||
cookie.downSeries = false; //是否下载短剧
|
||||
return cookie;
|
||||
};
|
||||
|
||||
@@ -216,6 +221,7 @@ const deleted = (id: string) => {
|
||||
|
||||
function edit(record: DataItem) {
|
||||
editRecord.value = record;
|
||||
console.log(record);
|
||||
copyObject(form, record);
|
||||
// 确保useSinglePath有默认值
|
||||
if (form.useSinglePath === undefined) {
|
||||
@@ -225,9 +231,10 @@ function edit(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 content = `确定要${statusText}【${record.userName || '该'}】Cookie的同步任务吗?`;
|
||||
|
||||
@@ -241,33 +248,33 @@ const switchSyncStatus = (record: DataItem) => {
|
||||
useApiStore()
|
||||
.SwitchCookieStatus({
|
||||
id: record.id,
|
||||
status: targetStatus,
|
||||
status: record.status,
|
||||
})
|
||||
.then((res) => {
|
||||
loading.value = false;
|
||||
if (res.code === 0) {
|
||||
message.success(`${statusText}同步成功`);
|
||||
GetRecords(); // 刷新列表
|
||||
GetRecords(); // 刷新列表,更新 switch 状态
|
||||
} else {
|
||||
message.error(`${statusText}同步失败:${res.message || '未知错误'}`);
|
||||
record.status = record.status === 1 ? 0 : 1;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
loading.value = false;
|
||||
console.error('切换同步状态失败:', err);
|
||||
message.error('切换同步状态失败,请稍后重试');
|
||||
record.status = record.status === 1 ? 0 : 1;
|
||||
});
|
||||
},
|
||||
onCancel: () => {
|
||||
console.log(`已取消${statusText}同步`);
|
||||
record.status = record.status === 1 ? 0 : 1;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
type Status = 0 | 1;
|
||||
|
||||
const StatusDict = {
|
||||
0: '同步已关闭',
|
||||
0: '同步已停止',
|
||||
1: '同步已开启',
|
||||
};
|
||||
|
||||
@@ -297,17 +304,183 @@ const removeRow = (index: number) => {
|
||||
form.upSecUserIdsJson.splice(index, 1);
|
||||
}
|
||||
};
|
||||
const rowCount = 8;
|
||||
const rowCount = 5;
|
||||
|
||||
// 组件挂载时获取配置
|
||||
onMounted(() => {
|
||||
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>
|
||||
|
||||
<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-item label="Cookie名称" required name="userName">
|
||||
<a-input v-model:value="form.userName" />
|
||||
@@ -321,7 +494,7 @@ const downImgVideo = ref(true);
|
||||
|
||||
<a-form-item label="我的secUserId" name="secUserId">
|
||||
<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="如果要同步“我喜欢”的视频和关注列表时,必填!!!">
|
||||
<ExclamationCircleOutlined style="color: #faad14;font-size: 16px;" />
|
||||
</a-tooltip>
|
||||
@@ -335,12 +508,54 @@ const downImgVideo = ref(true);
|
||||
<a-alert message="不想同步收藏的视频就空着" type="info" size="small" style="flex: 1; margin-bottom: 0;" />
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 新增:是否全部用一个地址开关 -->
|
||||
<a-form-item label="统一存储路径" name="useSinglePath">
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<a-form-item v-if="form.savePath&&form.savePath.length>0" label="是否统一存储路径" name="useSinglePath">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div style="width: 200px;">
|
||||
<a-switch v-model:checked="form.useSinglePath" :checked-value="true" :un-checked-value="false" size="default" />
|
||||
<span>{{ form.useSinglePath ? '共用收藏视频路径,如果是容器部署-docker-compose配置,只需要映射一个路径就行了' : '各类视频路径分开独立配置' }}</span>
|
||||
<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>
|
||||
</a-form-item>
|
||||
|
||||
@@ -355,7 +570,7 @@ const downImgVideo = ref(true);
|
||||
<!-- 关注的存储路径 -->
|
||||
<a-form-item label="关注的存储路径" name="upSavePath">
|
||||
<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;" />
|
||||
</div>
|
||||
</a-form-item>
|
||||
@@ -363,7 +578,7 @@ const downImgVideo = ref(true);
|
||||
<!-- 图文的存储路径 -->
|
||||
<a-form-item label="图文的存储路径" name="imgSavePath">
|
||||
<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;" />
|
||||
</div>
|
||||
</a-form-item>
|
||||
@@ -378,6 +593,65 @@ const downImgVideo = ref(true);
|
||||
</a-form>
|
||||
</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">
|
||||
<template #title>
|
||||
@@ -399,11 +673,16 @@ const downImgVideo = ref(true);
|
||||
</template>
|
||||
<template #bodyCell="{ column, text, record }">
|
||||
<template v-if="column.dataIndex === 'status'">
|
||||
<a-badge class="text-subtext" :color="text === 1 ? 'green' : 'red'">
|
||||
<template #text>
|
||||
<span class="text-subtext">{{ StatusDict[text as Status] }}</span>
|
||||
</template>
|
||||
</a-badge>
|
||||
<!-- 新:a-switch 显示状态,绑定切换逻辑 -->
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<a-switch v-model:checked="record.status" :checked-value="1" :un-checked-value="0" size="small" :disabled="loading" @change="() => switchSyncStatus(record)" />
|
||||
<span :style="{
|
||||
fontSize: '12px',
|
||||
color: record.status === 1 ? '#52c41a' : '#ff4d4f'
|
||||
}">
|
||||
{{ StatusDict[record.status] }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'cookies'">
|
||||
<a-button @click="showCookies(record)">查看</a-button>
|
||||
@@ -412,19 +691,7 @@ const downImgVideo = ref(true);
|
||||
<a-button @click="showUpers(record)">查看</a-button>
|
||||
</template>
|
||||
<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)">
|
||||
<template #icon>
|
||||
<EditFilled />
|
||||
@@ -459,8 +726,8 @@ const downImgVideo = ref(true);
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
<style scoped lang="less">
|
||||
// 原有非抽屉样式(保留,不改动)
|
||||
.cookie-content {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
@@ -526,16 +793,168 @@ const downImgVideo = ref(true);
|
||||
}
|
||||
|
||||
/* 修复:移除对alert的自定义样式修改,还原官方默认样式 */
|
||||
/* 删除了原有的ant-alert-small和ant-alert-message自定义样式,避免覆盖官方主题 */
|
||||
/* 如需调整alert间距,仅修改外层容器,不修改alert内部样式 */
|
||||
.alert-wrapper {
|
||||
flex: 1;
|
||||
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>
|
||||
|
||||
<!-- 新增全局样式块,确保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-alert {
|
||||
box-sizing: border-box;
|
||||
@@ -563,6 +982,15 @@ const downImgVideo = ref(true);
|
||||
.ant-alert-info .ant-alert-message {
|
||||
color: #1677ff;
|
||||
}
|
||||
/* 还原alert不同类型的官方默认颜色 */
|
||||
.ant-alert-success {
|
||||
background-color: #daf1d3;
|
||||
border: 1px solid #5bbc51;
|
||||
}
|
||||
.ant-alert-success .ant-alert-message {
|
||||
color: #228b22;
|
||||
}
|
||||
|
||||
.ant-alert-warning {
|
||||
background-color: #fffbe6;
|
||||
border: 1px solid #ffe58f;
|
||||
|
||||
@@ -1,26 +1,6 @@
|
||||
<template>
|
||||
<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-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">
|
||||
<template #tab>
|
||||
<span>
|
||||
@@ -60,7 +40,6 @@ import { checkPass } from '@/utils/regexHelper';
|
||||
import type { Rule } from 'ant-design-vue/es/form';
|
||||
|
||||
const activeKey = ref<string>('2');
|
||||
const uploadAction = ref<string>('');
|
||||
const visible = ref<boolean>(false);
|
||||
|
||||
function show(vis: boolean) {
|
||||
@@ -122,7 +101,6 @@ const loadUserInfo = () => {
|
||||
if (res.code === 0) {
|
||||
if (res.data.avatar != null && res.data.avatar !== '') imageUrl.value = `/upload/${res.data.avatar}`;
|
||||
passwordFormData.UserId = res.data.id;
|
||||
uploadAction.value = `/api/auth/UpdateUserAvatar?Uid=${res.data.id}`;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
+23
-33
@@ -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) {
|
||||
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 }) {
|
||||
return http
|
||||
.request<any, Response<any>>(
|
||||
'/api/config/UploadAudio', // 请求地址
|
||||
'post_form', // 使用新增的 post_form 类型
|
||||
formData, // FormData 参数(文件+其他参数)
|
||||
{
|
||||
onUploadProgress: options?.onUploadProgress, // 上传进度回调(原生 ProgressEvent)
|
||||
timeout: 120000 // 上传文件超时时间设为2分钟(可选)
|
||||
}
|
||||
)
|
||||
.then((res) => {
|
||||
// console.log('音频上传结果:', res);
|
||||
// 适配你的响应格式(如果响应是包裹层,取 data)
|
||||
return res;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('音频上传失败:', err);
|
||||
throw err; // 抛出错误让前端捕获
|
||||
});
|
||||
}
|
||||
// // 音频文件上传接口
|
||||
// async function apiUploadAudio(formData: FormData, options?: { onUploadProgress?: (progressEvent: ProgressEvent) => void }) {
|
||||
// return http
|
||||
// .request<any, Response<any>>(
|
||||
// '/api/config/UploadAudio', // 请求地址
|
||||
// 'post_form', // 使用新增的 post_form 类型
|
||||
// formData, // FormData 参数(文件+其他参数)
|
||||
// {
|
||||
// onUploadProgress: options?.onUploadProgress, // 上传进度回调(原生 ProgressEvent)
|
||||
// timeout: 120000 // 上传文件超时时间设为2分钟(可选)
|
||||
// }
|
||||
// )
|
||||
// .then((res) => {
|
||||
// // console.log('音频上传结果:', res);
|
||||
// // 适配你的响应格式(如果响应是包裹层,取 data)
|
||||
// return res;
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// console.error('音频上传失败:', err);
|
||||
// throw err; // 抛出错误让前端捕获
|
||||
// });
|
||||
// }
|
||||
|
||||
return {
|
||||
getVer,
|
||||
@@ -376,8 +367,7 @@ export const useApiStore = defineStore('coreapi', () => {
|
||||
BathRealDelete,
|
||||
DeleteByAuthor,
|
||||
Renfo,
|
||||
apiUploadAudio,
|
||||
GetAppPort,
|
||||
// apiUploadAudio,
|
||||
AppisInit,
|
||||
DeskInitAsync,
|
||||
SwitchCookieStatus,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using dy.net.dto;
|
||||
using dy.net.model.dto;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System.Net;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using dy.net.dto;
|
||||
using dy.net.model.dto;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace dy.net.extension
|
||||
string conn = $"DataSource={filePath}";
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
File.Create(filePath).Close();//.Close();
|
||||
File.Create(filePath).Close();
|
||||
}
|
||||
|
||||
return conn;
|
||||
@@ -166,7 +166,7 @@ namespace dy.net.extension
|
||||
Type[] types = assembly.GetTypes(); // 获取程序集中的所有类型
|
||||
|
||||
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();
|
||||
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");
|
||||
// });
|
||||
// // 配置HttpClient(Startup.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)
|
||||
{
|
||||
// 通用的忽略SSL证书验证的HttpMessageHandler配置
|
||||
Func<HttpMessageHandler> ignoreSslHandlerFactory = () =>
|
||||
static HttpMessageHandler ignoreSslHandlerFactory()
|
||||
{
|
||||
var handler = new SocketsHttpHandler
|
||||
{
|
||||
@@ -254,7 +206,7 @@ namespace dy.net.extension
|
||||
// 禁用代理自动检测(减少不必要的延迟)
|
||||
UseProxy = false,
|
||||
// 连接超时(建立连接的超时时间)
|
||||
ConnectTimeout = TimeSpan.FromSeconds(60),
|
||||
ConnectTimeout = TimeSpan.FromSeconds(120),
|
||||
// 忽略HTTPS证书验证
|
||||
SslOptions = new SslClientAuthenticationOptions
|
||||
{
|
||||
@@ -263,56 +215,22 @@ namespace dy.net.extension
|
||||
};
|
||||
|
||||
return handler;
|
||||
};
|
||||
|
||||
// 抖音采集客户端
|
||||
services.AddHttpClient("dy_collect", client =>
|
||||
}
|
||||
// 抖音数据接口请求客户端
|
||||
services.AddHttpClient(DouyinRequestParamManager.DY_HTTP_CLIENT, 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");
|
||||
}).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");
|
||||
client.DefaultRequestHeaders.Add("User-Agent", DouyinRequestParamManager.DY_USER_AGENT);
|
||||
}).ConfigurePrimaryHttpMessageHandler(ignoreSslHandlerFactory);
|
||||
|
||||
// 抖音下载客户端(单独配置,保持原有特性)
|
||||
services.AddHttpClient("dy_download")
|
||||
services.AddHttpClient(DouyinRequestParamManager.DY_HTTP_CLIENT_DOWN)
|
||||
.ConfigurePrimaryHttpMessageHandler(ignoreSslHandlerFactory)
|
||||
.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("User-Agent", DouyinRequestParamManager.DY_USER_AGENT);
|
||||
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>
|
||||
@@ -346,7 +264,7 @@ namespace dy.net.extension
|
||||
{
|
||||
// 获取服务的生命周期(优先使用特性,默认 Transient)
|
||||
var lifetime = type.GetCustomAttribute<ServiceLifetimeAttribute>()?.Lifetime
|
||||
?? ServiceLifetime.Transient;
|
||||
?? ServiceLifetime.Scoped;
|
||||
|
||||
// 查找该类实现的接口(优先注册为接口服务)
|
||||
//var interfaces = type.GetInterfaces()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using dy.net.dto;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.service;
|
||||
using Quartz;
|
||||
using Serilog;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using dy.net.dto;
|
||||
using dy.net.model;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using dy.net.model.response;
|
||||
using dy.net.service;
|
||||
using dy.net.utils;
|
||||
using System;
|
||||
@@ -36,21 +37,26 @@ namespace dy.net.job
|
||||
}
|
||||
|
||||
protected override bool IsCookieValid(DouyinCookie cookie)
|
||||
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
protected override string GetNextCursor(DouyinVideoInfo data)
|
||||
protected override string GetNextCursor(DouyinVideoInfoResponse data)
|
||||
{
|
||||
return data?.Cursor ?? "0";
|
||||
}
|
||||
@@ -80,13 +86,26 @@ namespace dy.net.job
|
||||
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);
|
||||
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(collectItem!=null&&cookie.UseCollectFolder &&!string.IsNullOrWhiteSpace(collectItem.CollectsId))
|
||||
{
|
||||
var safeCollectName = DouyinFileNameHelper.SanitizeLinuxFileName(collectItem.CollectsName, "", true);
|
||||
var folderCollect = Path.Combine(cookie.SavePath, safeCollectName);
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
using dy.net.dto;
|
||||
using dy.net.model;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using dy.net.model.response;
|
||||
using dy.net.service;
|
||||
using dy.net.utils;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace dy.net.job
|
||||
{
|
||||
@@ -32,17 +30,17 @@ namespace dy.net.job
|
||||
!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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
protected override string GetNextCursor(DouyinVideoInfo data)
|
||||
protected override string GetNextCursor(DouyinVideoInfoResponse data)
|
||||
{
|
||||
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 safeTag1 = string.IsNullOrWhiteSpace(tag1) ? "other" : DouyinFileNameHelper.SanitizeLinuxFileName(tag1,"",true);
|
||||
|
||||
+79
-46
@@ -1,17 +1,12 @@
|
||||
using ClockSnowFlake;
|
||||
using dy.net.dto;
|
||||
using dy.net.model;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using dy.net.model.response;
|
||||
using dy.net.service;
|
||||
using dy.net.utils;
|
||||
using Newtonsoft.Json;
|
||||
using Quartz;
|
||||
using Quartz.Util;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace dy.net.job
|
||||
{
|
||||
@@ -133,26 +128,22 @@ namespace dy.net.job
|
||||
/// <returns>一个表示异步操作的任务</returns>
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
// 1. 获取应用配置
|
||||
//if (VideoType != VideoTypeEnum.dy_follows)
|
||||
// return;
|
||||
|
||||
// 获取应用配置
|
||||
var config = douyinCommonService.GetConfig();
|
||||
if (config == null)
|
||||
{
|
||||
Log.Debug($"{VideoType}-未获取到系统配置,任务终止!!!");
|
||||
return;
|
||||
}
|
||||
//if(VideoType!= VideoTypeEnum.dy_follows)
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
|
||||
// 2. 从配置中获取每页请求数量--固定18
|
||||
//if (config.BatchCount > 0)
|
||||
// count = config.BatchCount.ToString();
|
||||
|
||||
// 3. 在处理Cookie之前执行的预处理操作
|
||||
// 在处理Cookie之前执行的预处理
|
||||
await BeforeProcessCookies();
|
||||
|
||||
// 4. 获取所有有效的Cookie
|
||||
// 获取所有有效的Cookie
|
||||
var cookies = await GetValidCookies();
|
||||
if (cookies == null || !cookies.Any())
|
||||
{
|
||||
@@ -161,7 +152,7 @@ namespace dy.net.job
|
||||
}
|
||||
Log.Debug($"{VideoType}-共发现{cookies.Count}个有效的cookie,同步即将开始...");
|
||||
|
||||
// 6. 遍历每个有效的Cookie,执行同步操作
|
||||
// 遍历每个有效的Cookie,执行同步
|
||||
foreach (var cookie in cookies)
|
||||
{
|
||||
await ProcessSyncUserCookie(cookie, config);
|
||||
@@ -202,8 +193,9 @@ namespace dy.net.job
|
||||
/// <param name="cookie">用户Cookie</param>
|
||||
/// <param name="cursor">分页游标,用于获取下一页数据</param>
|
||||
/// <param name="uperUid">关注的人</param>
|
||||
/// <param name="collectId">收藏夹ID</param>
|
||||
/// <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>
|
||||
/// 判断是否应该继续同步下一页数据
|
||||
@@ -213,7 +205,7 @@ namespace dy.net.job
|
||||
/// <param name="data">当前获取到的视频数据</param>
|
||||
/// <param name="followed">关注博主</param>
|
||||
/// <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>
|
||||
/// 获取下一页数据的游标
|
||||
@@ -221,7 +213,7 @@ namespace dy.net.job
|
||||
/// </summary>
|
||||
/// <param name="data">当前获取到的视频数据</param>
|
||||
/// <returns>下一页数据的游标</returns>
|
||||
protected abstract string GetNextCursor(DouyinVideoInfo data);
|
||||
protected abstract string GetNextCursor(DouyinVideoInfoResponse data);
|
||||
|
||||
/// <summary>
|
||||
/// 创建视频保存文件夹
|
||||
@@ -230,9 +222,10 @@ namespace dy.net.job
|
||||
/// <param name="cookie">用户Cookie</param>
|
||||
/// <param name="item">视频信息</param>
|
||||
/// <param name="followed">关注用户</param>
|
||||
/// <param name="collectItem">收藏夹Item</param>
|
||||
/// <param name="config">应用配置</param>
|
||||
/// <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>
|
||||
/// 获取视频文件名,默认就用id作文件名
|
||||
@@ -279,7 +272,6 @@ namespace dy.net.job
|
||||
|
||||
/// <summary>
|
||||
/// 获取NFO文件中的图片(如海报)文件名
|
||||
/// 子类可以重写此方法来自定义NFO图片的命名规则
|
||||
/// </summary>
|
||||
/// <param name="cookie">当前操作的Cookie</param>
|
||||
/// <param name="item">视频信息</param>
|
||||
@@ -343,16 +335,57 @@ namespace dy.net.job
|
||||
}
|
||||
else
|
||||
{
|
||||
// 仅在视频类型为抖音收藏时执行对应逻辑
|
||||
if (VideoType == VideoTypeEnum.dy_collects)
|
||||
{
|
||||
// 统一声明变量,避免分散定义,提升可读性
|
||||
int syncCount = 0; // 本次同步成功的视频数量
|
||||
string cursor = "0"; // 初始游标
|
||||
bool hasMore = true; // 是否还有更多数据
|
||||
(syncCount, cursor, hasMore) = await GetViedos(cookie, config, syncCount, cursor, hasMore);
|
||||
|
||||
// 处理同步完成后的操作
|
||||
// 处理「使用收藏文件夹」和「不使用收藏文件夹」的统一逻辑
|
||||
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)
|
||||
{
|
||||
@@ -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)
|
||||
{
|
||||
// 获取视频数据
|
||||
var data = await FetchVideoData(cookie, cursor, followed == null ? "" : followed?.SecUid);
|
||||
var data = await FetchVideoData(cookie, cursor, followed,collectItem);
|
||||
if (data == null)
|
||||
{
|
||||
Log.Debug($"{VideoType}-Cookie[{cookie.UserName}]同步数据失败!!!");
|
||||
@@ -383,7 +416,7 @@ namespace dy.net.job
|
||||
break;
|
||||
|
||||
// 处理视频列表
|
||||
var videos = await ProcessVideoList(cookie, data, config, followed);
|
||||
var videos = await ProcessVideoList(cookie, data, config, followed, collectItem);
|
||||
// 保存视频信息到数据库
|
||||
syncCount += await SaveVideos(videos);
|
||||
|
||||
@@ -435,23 +468,23 @@ namespace dy.net.job
|
||||
return false;
|
||||
}
|
||||
/// <summary>
|
||||
/// 处理视频列表
|
||||
/// 遍历视频列表,分别处理每个视频和图片集
|
||||
/// </summary>
|
||||
/// <param name="cookie">用户Cookie</param>
|
||||
/// <param name="data">视频信息对象</param>
|
||||
/// <param name="config">应用配置</param>
|
||||
/// <param name="followed">关注的</param>
|
||||
/// <param name="collectItem">收藏夹Item</param>
|
||||
/// <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>();
|
||||
foreach (var item in data.AwemeList)
|
||||
{
|
||||
if (item.AwemeId != "7440444948844956985")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//if (item.AwemeId != "7440444948844956985")
|
||||
//{
|
||||
// continue;
|
||||
//}
|
||||
//if (!item.Desc.Contains("小房车正式启程"))
|
||||
//{
|
||||
// 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)
|
||||
videos.Add(video);
|
||||
else
|
||||
@@ -578,7 +611,7 @@ namespace dy.net.job
|
||||
// 统一处理图文视频逻辑
|
||||
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)
|
||||
videos.Add(mergevideo);
|
||||
}
|
||||
@@ -773,8 +806,9 @@ namespace dy.net.job
|
||||
/// <param name="data">视频信息对象</param>
|
||||
/// <param name="config">应用配置</param>
|
||||
/// <param name="followed">关注</param>
|
||||
/// <param name="collectItem">收藏夹Item</param>
|
||||
/// <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;
|
||||
@@ -790,7 +824,7 @@ namespace dy.net.job
|
||||
// 获取视频标签
|
||||
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);
|
||||
// 拼接视频保存路径
|
||||
@@ -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 saveFolder = CreateSaveFolder(cookie, item, config, followed);
|
||||
var saveFolder = CreateSaveFolder(cookie, item, config, followed,collectItem);
|
||||
// 获取视频文件名
|
||||
//var fileName = DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId) + ".mp4";
|
||||
|
||||
@@ -969,7 +1003,6 @@ namespace dy.net.job
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理图片集并合成为视频
|
||||
/// 负责下载图片、合成视频、处理封面和头像等
|
||||
/// </summary>
|
||||
/// <param name="cookie">用户Cookie</param>
|
||||
@@ -978,7 +1011,7 @@ namespace dy.net.job
|
||||
/// <param name="config">应用配置</param>
|
||||
/// <param name="followed">应用配置</param>
|
||||
/// <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
|
||||
{
|
||||
@@ -1010,7 +1043,7 @@ namespace dy.net.job
|
||||
}
|
||||
else
|
||||
{
|
||||
fileNamefolder = CreateSaveFolder(cookie, item, config, followed);
|
||||
fileNamefolder = CreateSaveFolder(cookie, item, config, followed,collectItem);
|
||||
}
|
||||
if (!Directory.Exists(fileNamefolder)) Directory.CreateDirectory(fileNamefolder);
|
||||
|
||||
@@ -1293,7 +1326,7 @@ namespace dy.net.job
|
||||
/// <returns>创建的视频实体对象</returns>
|
||||
private async Task<DouyinVideo> CreateVideoEntity(AppConfig config,
|
||||
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);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using dy.net.dto;
|
||||
using dy.net.model;
|
||||
using dy.net.model.entity;
|
||||
using dy.net.model.response;
|
||||
using dy.net.service;
|
||||
using Quartz;
|
||||
using System.Collections.Generic;
|
||||
@@ -70,7 +70,7 @@ namespace dy.net.job
|
||||
{
|
||||
hasmore = false;
|
||||
}
|
||||
ck.StatusMsg = err.StatusCode == 8 ? "无效" : "正 常";
|
||||
ck.StatusMsg = err.StatusCode == 8 ? "无效" : "正常";
|
||||
ck.StatusCode = err.StatusCode;
|
||||
await _dyCookieService.UpdateAsync(ck);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using ClockSnowFlake;
|
||||
using dy.net.dto;
|
||||
using dy.net.model;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using dy.net.model.response;
|
||||
using dy.net.service;
|
||||
using dy.net.utils;
|
||||
using Newtonsoft.Json;
|
||||
@@ -29,17 +30,17 @@ namespace dy.net.job
|
||||
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;
|
||||
}
|
||||
|
||||
protected override string GetNextCursor(DouyinVideoInfo data)
|
||||
protected override string GetNextCursor(DouyinVideoInfoResponse data)
|
||||
{
|
||||
return data?.MaxCursor ?? "0";
|
||||
}
|
||||
@@ -52,7 +53,7 @@ namespace dy.net.job
|
||||
/// <param name="followed"></param>
|
||||
/// <param name="config"></param>
|
||||
/// <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主名称作为文件夹名称,若关注列表中有自定义保存路径则使用自定义路径
|
||||
// 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
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class DeleteInvalidVideoDto
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class DouyinCookieStopDto
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class DouyinDynamicVideoDto
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class DouyinFollowGroupDto
|
||||
{
|
||||
@@ -1,7 +1,7 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class DouyinApiResponse<T>
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class DouyinUpSecUserIdDto
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
|
||||
// Actor.cs
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class DouyinVideoPageRequestDto : PageRequestDto
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class DouyinVideoRequestDto
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class DouyinVideoTopDto
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class FollowErrorDto
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using SqlSugar;
|
||||
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class InitSystemInfo
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
/// <summary>
|
||||
/// 任务配置实体
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class LogFileInfoDto
|
||||
{
|
||||
@@ -5,7 +5,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class MediaMergeRequest
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class PriorityLevelDto
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class ReDownViedoDto
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
//如果好用,请收藏地址,帮忙分享。
|
||||
public class ImageTagInfoItem
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class VideoStaticsItemDto
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public class VideoTitleDataTemplate
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.dto
|
||||
{
|
||||
public enum VideoTypeEnum
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace dy.net.model
|
||||
namespace dy.net.model.entity
|
||||
{
|
||||
[SqlSugar.SugarTable(TableName = "login_user_info")]
|
||||
public class AdminUserInfo
|
||||
@@ -2,7 +2,7 @@
|
||||
using SqlSugar;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace dy.net.model
|
||||
namespace dy.net.model.entity
|
||||
{
|
||||
|
||||
[SugarTable(TableName = "dy_app_config")]
|
||||
@@ -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 Newtonsoft.Json;
|
||||
using SqlSugar;
|
||||
using SqlSugar;
|
||||
|
||||
namespace dy.net.model
|
||||
namespace dy.net.model.entity
|
||||
{
|
||||
[SugarTable(TableName = "dy_cookie")]
|
||||
public class DouyinCookie
|
||||
@@ -26,10 +24,24 @@ namespace dy.net.model
|
||||
[SugarColumn(Length =-1,IsNullable =true)]
|
||||
public string Cookies { get; set; }
|
||||
/// <summary>
|
||||
/// 存储路径
|
||||
/// 存储路径(收藏视频的存储路径)
|
||||
/// </summary>
|
||||
[SugarColumn(Length =255,IsNullable =true)]
|
||||
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>
|
||||
/// 1 开启同步 0 关闭同步
|
||||
/// </summary>
|
||||
@@ -98,15 +110,10 @@ namespace dy.net.model
|
||||
[SugarColumn(Length = 100, IsNullable = true)]
|
||||
public string StatusMsg { get; set; }
|
||||
/// <summary>
|
||||
/// 是否统一一个路径-用 SavePath
|
||||
/// 是否统一一个路径(savepath)
|
||||
/// </summary>
|
||||
public bool useSinglePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务端口--不存数据库
|
||||
/// </summary>
|
||||
[SugarColumn(IsIgnore =true)]
|
||||
public int AppPort { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using Newtonsoft.Json;
|
||||
using SqlSugar;
|
||||
|
||||
namespace dy.net.model
|
||||
namespace dy.net.model.entity
|
||||
{
|
||||
[SugarTable(TableName = "dy_follow")]
|
||||
public class DouyinFollowed
|
||||
@@ -1,6 +1,6 @@
|
||||
using SqlSugar;
|
||||
|
||||
namespace dy.net.model
|
||||
namespace dy.net.model.entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 重新下载的列表
|
||||
@@ -1,8 +1,8 @@
|
||||
using dy.net.dto;
|
||||
using dy.net.extension;
|
||||
using dy.net.extension;
|
||||
using dy.net.model.dto;
|
||||
using SqlSugar;
|
||||
|
||||
namespace dy.net.model
|
||||
namespace dy.net.model.entity
|
||||
{
|
||||
|
||||
[SugarTable(TableName = "dy_collect_video")]
|
||||
@@ -1,6 +1,6 @@
|
||||
using SqlSugar;
|
||||
|
||||
namespace dy.net.model
|
||||
namespace dy.net.model.entity
|
||||
{
|
||||
/// <summary>
|
||||
/// 永久删除的视频记录-不再下载
|
||||
@@ -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;
|
||||
|
||||
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
|
||||
//{
|
||||
// /// <summary>
|
||||
@@ -1648,146 +1794,4 @@ namespace dy.net.dto
|
||||
// //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; }
|
||||
}
|
||||
}
|
||||
@@ -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 System.Collections.Generic;
|
||||
namespace dy.net.dto
|
||||
namespace dy.net.model.response
|
||||
{
|
||||
|
||||
|
||||
public class DouyinVideoInfo
|
||||
/// <summary>
|
||||
/// 视频列表
|
||||
/// </summary>
|
||||
public class DouyinVideoInfoResponse
|
||||
{
|
||||
[JsonProperty("aweme_list")]
|
||||
public List<Aweme> AwemeList { get; set; }
|
||||
@@ -1,6 +1,6 @@
|
||||
using ClockSnowFlake;
|
||||
using dy.net.dto;
|
||||
using dy.net.model;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using dy.net.utils;
|
||||
using SqlSugar;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using dy.net.dto;
|
||||
using dy.net.model;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using SqlSugar;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
using ClockSnowFlake;
|
||||
using dy.net.dto;
|
||||
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;
|
||||
|
||||
namespace dy.net.repository
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using dy.net.dto;
|
||||
using dy.net.extension;
|
||||
using dy.net.model;
|
||||
using dy.net.extension;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using Quartz.Util;
|
||||
using SqlSugar;
|
||||
using System.Linq;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using dy.net.dto;
|
||||
using dy.net.model;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using dy.net.repository;
|
||||
|
||||
namespace dy.net.service
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using ClockSnowFlake;
|
||||
using dy.net.dto;
|
||||
using dy.net.model;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using dy.net.utils;
|
||||
using SqlSugar;
|
||||
using System.Reflection;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using ClockSnowFlake;
|
||||
using dy.net.dto;
|
||||
using dy.net.model;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using dy.net.repository;
|
||||
using SqlSugar;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using ClockSnowFlake;
|
||||
using dy.net.dto;
|
||||
using dy.net.model;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using dy.net.model.response;
|
||||
using dy.net.repository;
|
||||
using SqlSugar;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
+535
-330
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
using ClockSnowFlake;
|
||||
using dy.net.dto;
|
||||
using dy.net.extension;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.utils;
|
||||
using Serilog;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -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.Impl.Matchers;
|
||||
using Serilog;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using ClockSnowFlake;
|
||||
using dy.net.dto;
|
||||
using dy.net.model;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using dy.net.repository;
|
||||
using dy.net.utils;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using dy.net.dto;
|
||||
using dy.net.model.dto;
|
||||
using System.Globalization;
|
||||
|
||||
namespace dy.net.service
|
||||
|
||||
@@ -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()) + "==";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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,4 +1,4 @@
|
||||
using dy.net.dto;
|
||||
using dy.net.model.dto;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -28,10 +28,5 @@ namespace dy.net.utils
|
||||
string hashString = sb.ToString();
|
||||
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");
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using dy.net.dto;
|
||||
using dy.net.model;
|
||||
using dy.net.model.dto;
|
||||
using dy.net.model.entity;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
@@ -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,4 +1,4 @@
|
||||
using dy.net.dto;
|
||||
using dy.net.model.dto;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace dy.net.utils
|
||||
|
||||
Reference in New Issue
Block a user