feat: 视频预览/数据看板/下载配置 三项业务功能
- 新增视频预览:VideoPlayer 组件、VideoController/DyCollectVideoService/Repository、VideoPageRequestDTO 对应后端改动 - 新增数据看板:workplace/statics.vue、RecordTable、相关 store/http/axios 改动 - 新增下载配置:DownloadConfigService、ConfigController、AppSet.vue、AppConfig - 其他:DyHttpClientService / 同步 Job(Collect, Favorit) / Cookie 表 / CommonService / ServiceExtension 的配套调整 - 仓库卫生:.gitignore 追加 feiniu 过滤;运维脚本归档到 docs/scripts/
This commit is contained in:
+76
-61
@@ -82,6 +82,7 @@ namespace dy.net.job
|
||||
|
||||
while (hasMore)
|
||||
{
|
||||
Serilog.Log.Debug($"collect-正在获取第 {index + 1} 页数据,cursor: {cursor}");
|
||||
var data = await _douyinService.SyncCollectVideos(cursor, count, cookie.Cookies);
|
||||
hasMore = data != null && data.HasMore == 1 && cookie.CollHasSyncd == 0;
|
||||
if (cookie.CollHasSyncd == 1)
|
||||
@@ -94,11 +95,15 @@ namespace dy.net.job
|
||||
Serilog.Log.Debug($"collect-Cookie[{cookie.UserName}]获取收藏数据失败,请检查一下Cookie");
|
||||
break;
|
||||
}
|
||||
|
||||
Serilog.Log.Debug($"collect-API返回: HasMore={data.HasMore}, AwemeList数量={data.AwemeList?.Count ?? 0}");
|
||||
|
||||
cursor = data != null && !string.IsNullOrWhiteSpace(data.Cursor) ? data.Cursor : "0";
|
||||
|
||||
|
||||
if (data.AwemeList == null || !data.AwemeList.Any())
|
||||
{
|
||||
Serilog.Log.Debug($"collect-第 {index + 1} 页数据为空,结束同步");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -127,7 +132,27 @@ namespace dy.net.job
|
||||
var fileName = $"{item.AwemeId}.{v.Format}"; // 用ID做文件名,避免特殊字符
|
||||
var savePath = Path.Combine(saveFolder, fileName);
|
||||
|
||||
if (!File.Exists(savePath))
|
||||
// 检查是否应该下载(根据配置)
|
||||
var videoCreateTime = DateTimeUtil.Convert10BitTimestamp(item.CreateTime);
|
||||
var downloadConfigService = new DownloadConfigService(commonService);
|
||||
var shouldDownload = downloadConfigService.ShouldDownload("2", item.Author?.Uid, item.Author?.Nickname, videoCreateTime);
|
||||
|
||||
// 获取作者头像信息(无论是否下载都需要)
|
||||
var avatarImgName = $"{item.Author.Uid}.jpg";
|
||||
var avatarSavePath = Path.Combine(cookie.SavePath, "author", avatarImgName);
|
||||
var avatarUrl = item.Author?.AvatarLarger?.UrlList != null && item.Author.AvatarLarger.UrlList.Any()
|
||||
? item.Author.AvatarLarger.UrlList[0] : null;
|
||||
// 备用头像链接
|
||||
if (string.IsNullOrWhiteSpace(avatarUrl))
|
||||
{
|
||||
avatarUrl = item.Author?.AvatarThumb?.UrlList != null && item.Author.AvatarThumb.UrlList.Any()
|
||||
? item.Author.AvatarThumb.UrlList[0] : null;
|
||||
}
|
||||
|
||||
// 下载视频和封面(如果配置允许)
|
||||
string finalSavePath = null;
|
||||
string finalCoverSavePath = null;
|
||||
if (!File.Exists(savePath) && shouldDownload)
|
||||
{
|
||||
Serilog.Log.Debug($"collect-视频[{SanitizePath(item.Desc)}]开始下载");
|
||||
await Task.Delay(_random.Next(1, 4) * 1000);
|
||||
@@ -135,87 +160,77 @@ namespace dy.net.job
|
||||
|
||||
if (downVideo)
|
||||
{
|
||||
Serilog.Log.Debug($"collect-视频[{SanitizePath(item.Desc)}]下载{(downVideo ? "成功" : "失败")}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serilog.Log.Error($"collect-视频[{SanitizePath(item.Desc)}]下载{(downVideo ? "成功" : "失败")}");
|
||||
|
||||
}
|
||||
if (downVideo)
|
||||
{
|
||||
Serilog.Log.Debug($"collect-视频[{SanitizePath(item.Desc)}]下载成功");
|
||||
await DownVideoCover(item, saveFolder, cookie.Cookies);
|
||||
|
||||
// 用AuthorId做文件名,避免昵称特殊字符
|
||||
var avatarImgName = $"{item.Author.Uid}.jpg";
|
||||
var avatarSavePath = Path.Combine(cookie.SavePath, "author", avatarImgName);
|
||||
await DownAuthorAvatar(cookie.SavePath, item, avatarSavePath, cookie.Cookies);
|
||||
var avatarUrl = item.Author?.AvatarLarger?.UrlList != null && item.Author.AvatarLarger.UrlList.Any()
|
||||
? item.Author.AvatarLarger.UrlList[0] : null;
|
||||
// 备用头像链接
|
||||
if (string.IsNullOrWhiteSpace(avatarUrl))
|
||||
{
|
||||
avatarUrl = item.Author?.AvatarThumb?.UrlList != null && item.Author.AvatarThumb.UrlList.Any()
|
||||
? item.Author.AvatarThumb.UrlList[0] : null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 构造视频数据
|
||||
DyCollectVideo video = new()
|
||||
{
|
||||
ViedoType = "2",
|
||||
AwemeId = item.AwemeId,
|
||||
Author = item.Author?.Nickname,
|
||||
AuthorId = item.Author?.Uid,
|
||||
AuthorAvatar = avatarSavePath,
|
||||
AuthorAvatarUrl = avatarUrl,
|
||||
CreateTime = DateTimeUtil.Convert10BitTimestamp(item.CreateTime),
|
||||
VideoTitle = item.Desc,
|
||||
Id = IdGener.GetLong().ToString(),
|
||||
Resolution = $"{v.PlayAddr.Width}×{v.PlayAddr.Height}",
|
||||
FileSize = v.PlayAddr.DataSize,
|
||||
FileHash = v.PlayAddr.FileHash,
|
||||
Tag1 = tag1,
|
||||
Tag2 = tag2,
|
||||
Tag3 = tag3,
|
||||
VideoUrl = videoUrl,
|
||||
VideoCoverUrl = item.Video.Cover.UrlList != null && item.Video.Cover.UrlList.Any()
|
||||
? item.Video.Cover.UrlList[0] : null,
|
||||
VideoSavePath = savePath,
|
||||
VideoCoverSavePath = Path.Combine(saveFolder, "poster.jpg"),
|
||||
SyncTime = DateTime.Now,
|
||||
DyUserId = data.Uid,
|
||||
CookieId = cookie.Id
|
||||
};
|
||||
videos.Add(video);
|
||||
finalSavePath = savePath;
|
||||
finalCoverSavePath = Path.Combine(saveFolder, "poster.jpg");
|
||||
|
||||
var nfoPath = Path.Combine(saveFolder, $"{item.AwemeId}.nfo");
|
||||
NfoFileGenerator.GenerateNfoFile(new VideoNfo
|
||||
{
|
||||
Author = video.Author,
|
||||
Author = item.Author?.Nickname,
|
||||
Poster = Path.Combine(saveFolder, "poster.jpg"),
|
||||
Title = video.VideoTitle,
|
||||
Title = item.Desc,
|
||||
Thumbnail = Path.Combine(saveFolder, "fanart.jpg"),
|
||||
ReleaseDate = video.CreateTime,
|
||||
ReleaseDate = videoCreateTime,
|
||||
Genres = new List<string> { tag1, tag2, tag3 }.Where(t => !string.IsNullOrWhiteSpace(t)).ToList()
|
||||
}, nfoPath);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Serilog.Log.Error($"collect-视频[{SanitizePath(item.Desc)}]下载失败");
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (!shouldDownload)
|
||||
{
|
||||
//Serilog.Log.Debug($"视频[{item.AwemeId}]已存在,跳过下载");
|
||||
Serilog.Log.Debug($"collect-视频[{SanitizePath(item.Desc)}]不符合下载配置,仅同步信息到数据库");
|
||||
}
|
||||
else if (File.Exists(savePath))
|
||||
{
|
||||
// 文件已存在,使用现有路径
|
||||
finalSavePath = savePath;
|
||||
finalCoverSavePath = Path.Combine(saveFolder, "poster.jpg");
|
||||
}
|
||||
|
||||
// 无论是否下载,都保存视频信息到数据库
|
||||
DyCollectVideo video = new()
|
||||
{
|
||||
ViedoType = "2",
|
||||
AwemeId = item.AwemeId,
|
||||
Author = item.Author?.Nickname,
|
||||
AuthorId = item.Author?.Uid,
|
||||
AuthorAvatar = avatarSavePath,
|
||||
AuthorAvatarUrl = avatarUrl,
|
||||
CreateTime = videoCreateTime,
|
||||
VideoTitle = item.Desc,
|
||||
Id = IdGener.GetLong().ToString(),
|
||||
Resolution = $"{v.PlayAddr.Width}×{v.PlayAddr.Height}",
|
||||
FileSize = v.PlayAddr.DataSize,
|
||||
FileHash = v.PlayAddr.FileHash,
|
||||
Tag1 = tag1,
|
||||
Tag2 = tag2,
|
||||
Tag3 = tag3,
|
||||
VideoUrl = videoUrl,
|
||||
VideoCoverUrl = item.Video.Cover.UrlList != null && item.Video.Cover.UrlList.Any()
|
||||
? item.Video.Cover.UrlList[0] : null,
|
||||
VideoSavePath = finalSavePath, // 如果未下载则为 null
|
||||
VideoCoverSavePath = finalCoverSavePath, // 如果未下载则为 null
|
||||
SyncTime = DateTime.Now,
|
||||
DyUserId = data.Uid,
|
||||
CookieId = cookie.Id
|
||||
};
|
||||
videos.Add(video);
|
||||
}
|
||||
index++;
|
||||
// 批量保存到数据库(减少数据库操作频率)
|
||||
if (videos.Any())
|
||||
{
|
||||
//Serilog.Log.Debug($"处理Cookie[{cookie.UserName}]的第{index}页数据,共{videos.Count}条");
|
||||
Serilog.Log.Debug($"collect-处理Cookie[{cookie.UserName}]的第{index}页数据,共{videos.Count}条,准备保存到数据库");
|
||||
try
|
||||
{
|
||||
await _douyinVideoService.batchInsert(videos);
|
||||
var insertResult = await _douyinVideoService.batchInsert(videos);
|
||||
Serilog.Log.Debug($"collect-batchInsert返回结果: {insertResult}, 本次处理{videos.Count}条视频");
|
||||
syncCount += videos.Count;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
Reference in New Issue
Block a user