diff --git a/README.md b/README.md index ed4350a..c65e8e7 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ Cookie 及 `sec_user_id` 是同步功能的核心,需严格按步骤获取, ## 3. 默认账号密码(首次登录用) 首次访问后台管理页面时,使用以下默认账号密码: - **用户名**:`douyin` -- **密码**:`douyin2025` +- **密码**:`douyin2026` > ⚠️ **安全建议**:登录后修改密码。 @@ -96,8 +96,8 @@ Cookie 及 `sec_user_id` 是同步功能的核心,需严格按步骤获取, | 镜像标签 | 架构 | | ----------------- | -------------- | -| `beta_1.9.4` | x86_64 (amd64) | -| `arm_1.9.4` | ARM64 | +| `beta_1.9.5` | x86_64 (amd64) | +| `arm_1.9.5` | ARM64 | ### 构建命令示例 diff --git a/job/DouyinBasicSyncJob.cs b/job/DouyinBasicSyncJob.cs index 47c493e..3e9a589 100644 --- a/job/DouyinBasicSyncJob.cs +++ b/job/DouyinBasicSyncJob.cs @@ -646,10 +646,17 @@ namespace dy.net.job } else { - //记录存在,但本地文件不存在,则继续下载。 - Log.Debug($"{VideoType}-视频-{exitVideo.AwemeId}记录存在,但本地文件缺失,删除记录,重新下载"); - //删除原来的记录 - await douyinVideoService.DeleteById(exitVideo.Id); + if (exitVideo.OnlyImgOrOnlyMp3) + { + return true;//说明是图文视频,不需要再下载视频了 + } + else + { + //记录存在,但本地文件不存在,则继续下载。 + Log.Debug($"{VideoType}-视频-{exitVideo.AwemeId}记录存在,但本地文件缺失,删除记录,重新下载"); + //删除原来的记录 + await douyinVideoService.DeleteById(exitVideo.Id); + } } } } @@ -768,7 +775,7 @@ namespace dy.net.job // 生成NFO文件 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) // 合成视频的文件大小 } }; - 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) { // 检查合成后的视频文件是否有效 @@ -1021,7 +1028,7 @@ namespace dy.net.job }; // 创建视频实体 - var videoEntity = CreateVideoEntity( + var videoEntity = CreateVideoEntity(config, cookie, item, virtualBitRate, savePath, fileNamefolder, tag1, tag2, tag3, avatarSavePath, avatarUrl, data); @@ -1240,6 +1247,7 @@ namespace dy.net.job /// 创建视频实体 /// 根据视频信息、下载路径等创建DouyinVideo实体对象 /// + /// 配置 /// 用户Cookie /// 视频信息 /// 视频码率信息 @@ -1253,13 +1261,13 @@ namespace dy.net.job /// 视频信息对象 /// 动态视频 /// 创建的视频实体对象 - private DouyinVideo CreateVideoEntity( + private 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 dynamicVideos=null) { var diffs = GetVideoEntityDifferences(cookie, item); - var video= new DouyinVideo + var video = new DouyinVideo { ViedoType = VideoType, AwemeId = item.AwemeId, @@ -1283,7 +1291,8 @@ namespace dy.net.job VideoCoverSavePath = Path.Combine(saveFolder, "poster.jpg"), SyncTime = DateTime.Now, 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) { diff --git a/model/DouyinVideo.cs b/model/DouyinVideo.cs index 0365a0e..d65c4cc 100644 --- a/model/DouyinVideo.cs +++ b/model/DouyinVideo.cs @@ -154,5 +154,10 @@ namespace dy.net.model // 普通字符串字段,显式标记为 SQLite TEXT 类型 [SugarColumn(ColumnDataType = "TEXT", Length = -1,IsNullable =true)] public string DynamicVideos { get; set; } + + /// + /// 是否仅下载图片或仅下载音频 + /// + public bool OnlyImgOrOnlyMp3 { get; set; } } } diff --git a/service/AdminUserService.cs b/service/AdminUserService.cs index ef93824..75e5054 100644 --- a/service/AdminUserService.cs +++ b/service/AdminUserService.cs @@ -35,7 +35,7 @@ namespace dy.net.service AdminUserInfo userInfo = new AdminUserInfo { UserName = "douyin", - Password = "douyin2025", + Password = "douyin2026", CreateTime = DateTime.Now }; return _userRepository.InitUser(userInfo); diff --git a/service/DouyinCookieService.cs b/service/DouyinCookieService.cs index a55fbe9..33eb951 100644 --- a/service/DouyinCookieService.cs +++ b/service/DouyinCookieService.cs @@ -52,7 +52,7 @@ namespace dy.net.service } var cookie = new DouyinCookie { - UserName = "douyin2025", + UserName = "douyin2026", Cookies = "-", SecUserId = "-", Id = IdGener.GetLong().ToString(), diff --git a/service/DouyinMergeVideoService.cs b/service/DouyinMergeVideoService.cs index d3cb1ac..5450cc0 100644 --- a/service/DouyinMergeVideoService.cs +++ b/service/DouyinMergeVideoService.cs @@ -301,7 +301,7 @@ namespace dy.net.service /// /// 保存下载的文件(图片/音频)到目标目录 /// - 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; Directory.CreateDirectory(targetFolder); // 确保目标目录存在 diff --git a/service/DouyinVideoService.cs b/service/DouyinVideoService.cs index 0e3ff62..89e06e4 100644 --- a/service/DouyinVideoService.cs +++ b/service/DouyinVideoService.cs @@ -199,7 +199,7 @@ namespace dy.net.service // 3. 构建重新下载记录(提前准备数据,避免事务内耗时操作) var reDownList = new List(); - var filePathsToDelete = new List(); // 收集待删除文件路径,统一处理 + var filePathsToDelete = new List<(string path,bool onlyImgOrMp3)>(); // 收集待删除文件路径,统一处理 foreach (var video in videos) { @@ -221,7 +221,7 @@ namespace dy.net.service CookieId = video.CookieId }); - filePathsToDelete.Add(video.VideoSavePath); + filePathsToDelete.Add((video.VideoSavePath,video.OnlyImgOrOnlyMp3)); } // 无有效重新下载记录时直接返回 @@ -248,23 +248,35 @@ namespace dy.net.service // 5. 文件删除(非事务操作,失败不回滚数据库,可根据业务调整) // 采用异步文件操作,避免同步IO阻塞线程(需.NET 5+支持) - foreach (var path in filePathsToDelete) + foreach (var video in filePathsToDelete) { try { - if (File.Exists(path)) + if (File.Exists(video.path)) { - File.Delete(path); // 异步删除,提升并发性能 - Serilog.Log.Debug("视频文件删除成功:Path={0}", path); + File.Delete(video.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 { - Serilog.Log.Error("视频文件不存在,跳过删除:Path={0}", path); + Serilog.Log.Error("视频文件不存在,跳过删除:Path={0}", video); } } catch (IOException ex) { - Serilog.Log.Error(ex, "视频文件删除失败:Path={0}", path); + Serilog.Log.Error(ex, "视频文件删除失败:Path={0}", video); } }