1、永久删除视频时,同时删除原视频所在文件夹

2、图文视频不下载视频,仅下载图片或mp3时,每次都会重新调用下载资源接口bug修复
This commit is contained in:
jianzhichu
2026-01-01 21:09:19 +08:00
parent b9b3731bbe
commit 87f154a8b7
7 changed files with 51 additions and 25 deletions
+3 -3
View File
@@ -84,7 +84,7 @@ Cookie 及 `sec_user_id` 是同步功能的核心,需严格按步骤获取,
## 3. 默认账号密码(首次登录用) ## 3. 默认账号密码(首次登录用)
首次访问后台管理页面时,使用以下默认账号密码: 首次访问后台管理页面时,使用以下默认账号密码:
- **用户名**`douyin` - **用户名**`douyin`
- **密码**`douyin2025` - **密码**`douyin2026`
> ⚠️ **安全建议**:登录后修改密码。 > ⚠️ **安全建议**:登录后修改密码。
@@ -96,8 +96,8 @@ Cookie 及 `sec_user_id` 是同步功能的核心,需严格按步骤获取,
| 镜像标签 | 架构 | | 镜像标签 | 架构 |
| ----------------- | -------------- | | ----------------- | -------------- |
| `beta_1.9.4` | x86_64 (amd64) | | `beta_1.9.5` | x86_64 (amd64) |
| `arm_1.9.4` | ARM64 | | `arm_1.9.5` | ARM64 |
### 构建命令示例 ### 构建命令示例
+20 -11
View File
@@ -646,10 +646,17 @@ namespace dy.net.job
} }
else else
{ {
//记录存在,但本地文件不存在,则继续下载。 if (exitVideo.OnlyImgOrOnlyMp3)
Log.Debug($"{VideoType}-视频-{exitVideo.AwemeId}记录存在,但本地文件缺失,删除记录,重新下载"); {
//删除原来的记录 return true;//说明是图文视频,不需要再下载视频了
await douyinVideoService.DeleteById(exitVideo.Id); }
else
{
//记录存在,但本地文件不存在,则继续下载。
Log.Debug($"{VideoType}-视频-{exitVideo.AwemeId}记录存在,但本地文件缺失,删除记录,重新下载");
//删除原来的记录
await douyinVideoService.DeleteById(exitVideo.Id);
}
} }
} }
} }
@@ -768,7 +775,7 @@ namespace dy.net.job
// 生成NFO文件 // 生成NFO文件
await GenerateNfoFile(saveFolder, item, avatarUrl, cookie, config); await GenerateNfoFile(saveFolder, item, avatarUrl, cookie, config);
// 创建视频实体 // 创建视频实体
return CreateVideoEntity(cookie, item, v, savePath, saveFolder, tag1, tag2, tag3, avatarSavePath, avatarUrl, data); return CreateVideoEntity(config,cookie, item, v, savePath, saveFolder, tag1, tag2, tag3, avatarSavePath, avatarUrl, data);
} }
@@ -837,7 +844,7 @@ namespace dy.net.job
DataSize = DouyinFileUtils.GetTotalFileSize(dynamicSavePaths) // 合成视频的文件大小 DataSize = DouyinFileUtils.GetTotalFileSize(dynamicSavePaths) // 合成视频的文件大小
} }
}; };
return CreateVideoEntity(cookie, item, virtualBitRate, dynamicSavePaths.FirstOrDefault(), saveFolder, tag1, tag2, tag3,"", "", data,dynamicSavePaths); return CreateVideoEntity(config,cookie, item, virtualBitRate, dynamicSavePaths.FirstOrDefault(), saveFolder, tag1, tag2, tag3,"", "", data,dynamicSavePaths);
} }
@@ -978,7 +985,7 @@ namespace dy.net.job
// 获取不带扩展名的完整路径 // 获取不带扩展名的完整路径
string fullPathWithoutExtension = Path.Combine(Path.GetDirectoryName(savePath),Path.GetFileNameWithoutExtension(savePath) ); //string fullPathWithoutExtension = Path.Combine(Path.GetDirectoryName(savePath),Path.GetFileNameWithoutExtension(savePath) );
if (config.DownImageVideo) if (config.DownImageVideo)
{ {
// 检查合成后的视频文件是否有效 // 检查合成后的视频文件是否有效
@@ -1021,7 +1028,7 @@ namespace dy.net.job
}; };
// 创建视频实体 // 创建视频实体
var videoEntity = CreateVideoEntity( var videoEntity = CreateVideoEntity(config,
cookie, item, virtualBitRate, savePath, fileNamefolder, cookie, item, virtualBitRate, savePath, fileNamefolder,
tag1, tag2, tag3, avatarSavePath, avatarUrl, data); tag1, tag2, tag3, avatarSavePath, avatarUrl, data);
@@ -1240,6 +1247,7 @@ namespace dy.net.job
/// 创建视频实体 /// 创建视频实体
/// 根据视频信息、下载路径等创建DouyinVideo实体对象 /// 根据视频信息、下载路径等创建DouyinVideo实体对象
/// </summary> /// </summary>
/// <param name="config">配置</param>
/// <param name="cookie">用户Cookie</param> /// <param name="cookie">用户Cookie</param>
/// <param name="item">视频信息</param> /// <param name="item">视频信息</param>
/// <param name="bitRate">视频码率信息</param> /// <param name="bitRate">视频码率信息</param>
@@ -1253,13 +1261,13 @@ namespace dy.net.job
/// <param name="data">视频信息对象</param> /// <param name="data">视频信息对象</param>
/// <param name="dynamicVideos">动态视频</param> /// <param name="dynamicVideos">动态视频</param>
/// <returns>创建的视频实体对象</returns> /// <returns>创建的视频实体对象</returns>
private DouyinVideo CreateVideoEntity( private DouyinVideo CreateVideoEntity(AppConfig config,
DouyinCookie cookie, Aweme item, VideoBitRate bitRate, string savePath, string saveFolder, DouyinCookie cookie, Aweme item, VideoBitRate bitRate, string savePath, string saveFolder,
string tag1, string tag2, string tag3, string avatarSavePath, string avatarUrl, DouyinVideoInfo data,List<string> dynamicVideos=null) string tag1, string tag2, string tag3, string avatarSavePath, string avatarUrl, DouyinVideoInfo data,List<string> dynamicVideos=null)
{ {
var diffs = GetVideoEntityDifferences(cookie, item); var diffs = GetVideoEntityDifferences(cookie, item);
var video= new DouyinVideo var video = new DouyinVideo
{ {
ViedoType = VideoType, ViedoType = VideoType,
AwemeId = item.AwemeId, AwemeId = item.AwemeId,
@@ -1283,7 +1291,8 @@ namespace dy.net.job
VideoCoverSavePath = Path.Combine(saveFolder, "poster.jpg"), VideoCoverSavePath = Path.Combine(saveFolder, "poster.jpg"),
SyncTime = DateTime.Now, SyncTime = DateTime.Now,
DyUserId = item.AuthorUserId == 0 ? item.Author?.Uid : item.AuthorUserId.ToString(), DyUserId = item.AuthorUserId == 0 ? item.Author?.Uid : item.AuthorUserId.ToString(),
CookieId = cookie.Id CookieId = cookie.Id,
OnlyImgOrOnlyMp3 = string.IsNullOrWhiteSpace(savePath) && !config.DownImageVideo && (config.DownImage || config.DownMp3)
}; };
if (dynamicVideos != null && dynamicVideos.Count > 0) if (dynamicVideos != null && dynamicVideos.Count > 0)
{ {
+5
View File
@@ -154,5 +154,10 @@ namespace dy.net.model
// 普通字符串字段,显式标记为 SQLite TEXT 类型 // 普通字符串字段,显式标记为 SQLite TEXT 类型
[SugarColumn(ColumnDataType = "TEXT", Length = -1,IsNullable =true)] [SugarColumn(ColumnDataType = "TEXT", Length = -1,IsNullable =true)]
public string DynamicVideos { get; set; } public string DynamicVideos { get; set; }
/// <summary>
/// 是否仅下载图片或仅下载音频
/// </summary>
public bool OnlyImgOrOnlyMp3 { get; set; }
} }
} }
+1 -1
View File
@@ -35,7 +35,7 @@ namespace dy.net.service
AdminUserInfo userInfo = new AdminUserInfo AdminUserInfo userInfo = new AdminUserInfo
{ {
UserName = "douyin", UserName = "douyin",
Password = "douyin2025", Password = "douyin2026",
CreateTime = DateTime.Now CreateTime = DateTime.Now
}; };
return _userRepository.InitUser(userInfo); return _userRepository.InitUser(userInfo);
+1 -1
View File
@@ -52,7 +52,7 @@ namespace dy.net.service
} }
var cookie = new DouyinCookie var cookie = new DouyinCookie
{ {
UserName = "douyin2025", UserName = "douyin2026",
Cookies = "-", Cookies = "-",
SecUserId = "-", SecUserId = "-",
Id = IdGener.GetLong().ToString(), Id = IdGener.GetLong().ToString(),
+1 -1
View File
@@ -301,7 +301,7 @@ namespace dy.net.service
/// <summary> /// <summary>
/// 保存下载的文件(图片/音频)到目标目录 /// 保存下载的文件(图片/音频)到目标目录
/// </summary> /// </summary>
private async Task SaveDownloadedFilesAsync(string[] sourcePaths, string targetFolder, string defaultExt,string videoFileName) private static async Task SaveDownloadedFilesAsync(string[] sourcePaths, string targetFolder, string defaultExt,string videoFileName)
{ {
if (sourcePaths == null || sourcePaths.Length == 0) return; if (sourcePaths == null || sourcePaths.Length == 0) return;
Directory.CreateDirectory(targetFolder); // 确保目标目录存在 Directory.CreateDirectory(targetFolder); // 确保目标目录存在
+20 -8
View File
@@ -199,7 +199,7 @@ namespace dy.net.service
// 3. 构建重新下载记录(提前准备数据,避免事务内耗时操作) // 3. 构建重新下载记录(提前准备数据,避免事务内耗时操作)
var reDownList = new List<DouyinReDownload>(); var reDownList = new List<DouyinReDownload>();
var filePathsToDelete = new List<string>(); // 收集待删除文件路径,统一处理 var filePathsToDelete = new List<(string path,bool onlyImgOrMp3)>(); // 收集待删除文件路径,统一处理
foreach (var video in videos) foreach (var video in videos)
{ {
@@ -221,7 +221,7 @@ namespace dy.net.service
CookieId = video.CookieId CookieId = video.CookieId
}); });
filePathsToDelete.Add(video.VideoSavePath); filePathsToDelete.Add((video.VideoSavePath,video.OnlyImgOrOnlyMp3));
} }
// 无有效重新下载记录时直接返回 // 无有效重新下载记录时直接返回
@@ -248,23 +248,35 @@ namespace dy.net.service
// 5. 文件删除(非事务操作,失败不回滚数据库,可根据业务调整) // 5. 文件删除(非事务操作,失败不回滚数据库,可根据业务调整)
// 采用异步文件操作,避免同步IO阻塞线程(需.NET 5+支持) // 采用异步文件操作,避免同步IO阻塞线程(需.NET 5+支持)
foreach (var path in filePathsToDelete) foreach (var video in filePathsToDelete)
{ {
try try
{ {
if (File.Exists(path)) if (File.Exists(video.path))
{ {
File.Delete(path); // 异步删除,提升并发性能 File.Delete(video.path); // 异步删除,提升并发性能
Serilog.Log.Debug("视频文件删除成功:Path={0}", path); Serilog.Log.Debug("视频文件删除成功:Path={0}", video);
if (!video.onlyImgOrMp3)//如果是纯图片或纯音频文件,则不删除所在文件夹
{
//检查这个路径所在文件夹是否还有其他视频文件,如果没有则删除这个文件夹
var dir = Path.GetDirectoryName(video.Item1);
bool hasMp4File = Directory.EnumerateFiles(dir, "*.mp4", SearchOption.TopDirectoryOnly).Any(); // 只要存在一个MP4文件就返回true;
if (!hasMp4File)
{
Directory.Delete(dir, true);
}
}
} }
else else
{ {
Serilog.Log.Error("视频文件不存在,跳过删除:Path={0}", path); Serilog.Log.Error("视频文件不存在,跳过删除:Path={0}", video);
} }
} }
catch (IOException ex) catch (IOException ex)
{ {
Serilog.Log.Error(ex, "视频文件删除失败:Path={0}", path); Serilog.Log.Error(ex, "视频文件删除失败:Path={0}", video);
} }
} }