From edd0e71f8b3dd9c838e5f33ae701e67a701ab678 Mon Sep 17 00:00:00 2001 From: jianzhichu Date: Thu, 4 Dec 2025 08:27:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=A4=B9=EF=BC=8C=E6=A0=87?= =?UTF-8?q?=E9=A2=98=20=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PublishProfiles/FolderProfile.pubxml.user | 2 +- appsettings.json | 2 +- job/DouYinCollectSyncJob.cs | 4 +- job/DouYinFavoritSyncJob.cs | 4 +- job/DouyinBasicSyncJob.cs | 21 ++---- job/DouyinFollowedViedoSyncJob.cs | 6 +- utils/DouyinFileNameHelper.cs | 69 +++++++++++++------ utils/VideoTitleGenerator.cs | 4 +- 8 files changed, 65 insertions(+), 47 deletions(-) diff --git a/Properties/PublishProfiles/FolderProfile.pubxml.user b/Properties/PublishProfiles/FolderProfile.pubxml.user index 0337b8e..2a0b7c2 100644 --- a/Properties/PublishProfiles/FolderProfile.pubxml.user +++ b/Properties/PublishProfiles/FolderProfile.pubxml.user @@ -5,7 +5,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. <_PublishTargetUrl>E:\code\dysync\bin\Release\net6.0\publish\ - True|2025-12-03T15:58:13.3693303Z||;True|2025-12-03T23:57:40.4257893+08:00||;True|2025-12-03T23:56:38.8717769+08:00||;True|2025-12-03T23:56:24.0663568+08:00||;False|2025-12-03T23:55:36.1902974+08:00||;True|2025-12-03T23:51:30.6688504+08:00||;True|2025-12-03T23:34:17.1648971+08:00||;False|2025-12-03T23:34:07.7649161+08:00||;True|2025-12-03T22:32:56.2435003+08:00||;True|2025-12-03T22:27:45.6059666+08:00||;True|2025-12-03T15:55:28.0186597+08:00||;False|2025-12-03T15:54:17.5032724+08:00||;True|2025-12-03T15:53:10.2273509+08:00||;True|2025-12-02T22:11:37.4645042+08:00||;False|2025-12-02T22:10:47.1320259+08:00||;True|2025-12-02T14:39:58.8932130+08:00||;True|2025-12-02T14:36:37.1529072+08:00||;True|2025-12-02T12:58:22.0951548+08:00||;True|2025-12-02T09:30:33.7066474+08:00||;True|2025-12-02T09:30:14.5481844+08:00||;True|2025-12-02T09:30:00.3123364+08:00||;False|2025-12-02T09:29:54.4615520+08:00||;True|2025-12-02T09:13:01.7995414+08:00||;False|2025-12-02T09:12:55.8360281+08:00||;True|2025-12-02T09:12:31.0156791+08:00||;True|2025-12-02T08:55:11.3773395+08:00||;True|2025-12-02T08:53:21.3927713+08:00||;False|2025-12-02T08:48:55.8638037+08:00||;True|2025-12-02T07:29:25.2192447+08:00||;False|2025-12-02T07:29:10.2504665+08:00||;True|2025-12-02T07:28:29.0769286+08:00||;True|2025-12-01T21:53:07.6474834+08:00||;True|2025-12-01T21:44:28.1674315+08:00||;True|2025-12-01T21:18:47.2119609+08:00||;True|2025-12-01T20:51:19.9948301+08:00||;True|2025-12-01T20:50:36.9904697+08:00||;True|2025-12-01T20:44:10.1695142+08:00||;True|2025-12-01T19:27:58.0479456+08:00||;True|2025-12-01T19:16:02.2288214+08:00||;False|2025-12-01T19:15:56.0372115+08:00||;True|2025-12-01T19:15:16.4854821+08:00||;False|2025-12-01T19:15:06.7001019+08:00||;True|2025-12-01T17:10:38.9739466+08:00||;False|2025-12-01T17:10:18.8928139+08:00||;True|2025-12-01T17:03:59.3171589+08:00||;True|2025-12-01T17:03:12.5681656+08:00||;True|2025-12-01T16:42:51.4415025+08:00||;True|2025-12-01T01:29:59.6975567+08:00||;True|2025-12-01T01:29:45.1898652+08:00||;False|2025-12-01T01:29:33.1787721+08:00||;True|2025-12-01T01:27:33.1297605+08:00||;True|2025-12-01T01:27:27.3976862+08:00||;False|2025-12-01T01:27:20.5193052+08:00||;True|2025-12-01T01:11:11.0210582+08:00||;True|2025-12-01T01:04:04.3307782+08:00||;True|2025-12-01T00:55:49.8018864+08:00||;True|2025-12-01T00:27:25.1323561+08:00||;True|2025-11-30T23:58:20.7284116+08:00||;True|2025-11-30T23:57:58.3027622+08:00||;True|2025-11-30T23:57:43.0829614+08:00||;False|2025-11-30T23:57:33.5606716+08:00||;True|2025-11-30T23:54:29.6203368+08:00||;True|2025-11-30T23:54:27.5383120+08:00||;False|2025-11-30T23:54:17.0823982+08:00||;True|2025-11-30T22:41:11.4538820+08:00||;True|2025-11-30T22:38:19.7064566+08:00||;True|2025-11-30T22:37:35.2889186+08:00||;True|2025-11-30T21:42:31.1408314+08:00||;True|2025-11-30T21:42:19.5385333+08:00||;False|2025-11-30T21:42:13.3290237+08:00||;True|2025-11-30T21:33:28.0806806+08:00||;True|2025-11-30T21:16:56.7088027+08:00||;False|2025-11-30T21:16:46.1444944+08:00||;True|2025-11-30T20:21:24.4059664+08:00||;False|2025-11-30T20:21:17.6006098+08:00||;True|2025-11-30T20:20:08.2030141+08:00||;False|2025-11-30T20:16:12.3608968+08:00||;True|2025-11-30T20:15:35.6048313+08:00||;True|2025-11-30T19:45:18.7229552+08:00||;True|2025-11-30T19:45:08.6083368+08:00||;False|2025-11-30T19:44:54.7824905+08:00||;True|2025-11-30T19:44:17.0179491+08:00||;True|2025-11-30T19:44:06.7073484+08:00||;False|2025-11-30T19:43:58.2896556+08:00||;True|2025-11-30T19:42:08.2261927+08:00||;True|2025-11-30T19:28:15.7115077+08:00||;False|2025-11-30T19:28:10.2280725+08:00||;True|2025-11-30T19:23:31.7859158+08:00||;True|2025-11-30T19:23:20.7788277+08:00||;True|2025-11-30T19:17:11.8583296+08:00||;False|2025-11-30T19:10:41.8369574+08:00||;True|2025-11-30T19:02:08.8184758+08:00||;False|2025-11-30T19:01:59.4711045+08:00||;True|2025-11-30T18:16:01.8372242+08:00||;True|2025-11-30T14:50:31.9356543+08:00||;True|2025-11-30T14:48:27.1833064+08:00||;True|2025-11-30T02:06:06.6099669+08:00||;True|2025-11-30T01:49:46.4358206+08:00||;False|2025-11-30T01:49:34.4884036+08:00||;True|2025-11-30T01:43:41.1028753+08:00||; + True|2025-12-04T00:22:47.9617427Z||;False|2025-12-04T08:22:41.3759733+08:00||;True|2025-12-04T08:14:02.2478893+08:00||;True|2025-12-04T07:57:00.2208139+08:00||;True|2025-12-03T23:58:13.3693303+08:00||;True|2025-12-03T23:57:40.4257893+08:00||;True|2025-12-03T23:56:38.8717769+08:00||;True|2025-12-03T23:56:24.0663568+08:00||;False|2025-12-03T23:55:36.1902974+08:00||;True|2025-12-03T23:51:30.6688504+08:00||;True|2025-12-03T23:34:17.1648971+08:00||;False|2025-12-03T23:34:07.7649161+08:00||;True|2025-12-03T22:32:56.2435003+08:00||;True|2025-12-03T22:27:45.6059666+08:00||;True|2025-12-03T15:55:28.0186597+08:00||;False|2025-12-03T15:54:17.5032724+08:00||;True|2025-12-03T15:53:10.2273509+08:00||;True|2025-12-02T22:11:37.4645042+08:00||;False|2025-12-02T22:10:47.1320259+08:00||;True|2025-12-02T14:39:58.8932130+08:00||;True|2025-12-02T14:36:37.1529072+08:00||;True|2025-12-02T12:58:22.0951548+08:00||;True|2025-12-02T09:30:33.7066474+08:00||;True|2025-12-02T09:30:14.5481844+08:00||;True|2025-12-02T09:30:00.3123364+08:00||;False|2025-12-02T09:29:54.4615520+08:00||;True|2025-12-02T09:13:01.7995414+08:00||;False|2025-12-02T09:12:55.8360281+08:00||;True|2025-12-02T09:12:31.0156791+08:00||;True|2025-12-02T08:55:11.3773395+08:00||;True|2025-12-02T08:53:21.3927713+08:00||;False|2025-12-02T08:48:55.8638037+08:00||;True|2025-12-02T07:29:25.2192447+08:00||;False|2025-12-02T07:29:10.2504665+08:00||;True|2025-12-02T07:28:29.0769286+08:00||;True|2025-12-01T21:53:07.6474834+08:00||;True|2025-12-01T21:44:28.1674315+08:00||;True|2025-12-01T21:18:47.2119609+08:00||;True|2025-12-01T20:51:19.9948301+08:00||;True|2025-12-01T20:50:36.9904697+08:00||;True|2025-12-01T20:44:10.1695142+08:00||;True|2025-12-01T19:27:58.0479456+08:00||;True|2025-12-01T19:16:02.2288214+08:00||;False|2025-12-01T19:15:56.0372115+08:00||;True|2025-12-01T19:15:16.4854821+08:00||;False|2025-12-01T19:15:06.7001019+08:00||;True|2025-12-01T17:10:38.9739466+08:00||;False|2025-12-01T17:10:18.8928139+08:00||;True|2025-12-01T17:03:59.3171589+08:00||;True|2025-12-01T17:03:12.5681656+08:00||;True|2025-12-01T16:42:51.4415025+08:00||;True|2025-12-01T01:29:59.6975567+08:00||;True|2025-12-01T01:29:45.1898652+08:00||;False|2025-12-01T01:29:33.1787721+08:00||;True|2025-12-01T01:27:33.1297605+08:00||;True|2025-12-01T01:27:27.3976862+08:00||;False|2025-12-01T01:27:20.5193052+08:00||;True|2025-12-01T01:11:11.0210582+08:00||;True|2025-12-01T01:04:04.3307782+08:00||;True|2025-12-01T00:55:49.8018864+08:00||;True|2025-12-01T00:27:25.1323561+08:00||;True|2025-11-30T23:58:20.7284116+08:00||;True|2025-11-30T23:57:58.3027622+08:00||;True|2025-11-30T23:57:43.0829614+08:00||;False|2025-11-30T23:57:33.5606716+08:00||;True|2025-11-30T23:54:29.6203368+08:00||;True|2025-11-30T23:54:27.5383120+08:00||;False|2025-11-30T23:54:17.0823982+08:00||;True|2025-11-30T22:41:11.4538820+08:00||;True|2025-11-30T22:38:19.7064566+08:00||;True|2025-11-30T22:37:35.2889186+08:00||;True|2025-11-30T21:42:31.1408314+08:00||;True|2025-11-30T21:42:19.5385333+08:00||;False|2025-11-30T21:42:13.3290237+08:00||;True|2025-11-30T21:33:28.0806806+08:00||;True|2025-11-30T21:16:56.7088027+08:00||;False|2025-11-30T21:16:46.1444944+08:00||;True|2025-11-30T20:21:24.4059664+08:00||;False|2025-11-30T20:21:17.6006098+08:00||;True|2025-11-30T20:20:08.2030141+08:00||;False|2025-11-30T20:16:12.3608968+08:00||;True|2025-11-30T20:15:35.6048313+08:00||;True|2025-11-30T19:45:18.7229552+08:00||;True|2025-11-30T19:45:08.6083368+08:00||;False|2025-11-30T19:44:54.7824905+08:00||;True|2025-11-30T19:44:17.0179491+08:00||;True|2025-11-30T19:44:06.7073484+08:00||;False|2025-11-30T19:43:58.2896556+08:00||;True|2025-11-30T19:42:08.2261927+08:00||;True|2025-11-30T19:28:15.7115077+08:00||;False|2025-11-30T19:28:10.2280725+08:00||;True|2025-11-30T19:23:31.7859158+08:00||;True|2025-11-30T19:23:20.7788277+08:00||;True|2025-11-30T19:17:11.8583296+08:00||;False|2025-11-30T19:10:41.8369574+08:00||;True|2025-11-30T19:02:08.8184758+08:00||;False|2025-11-30T19:01:59.4711045+08:00||;True|2025-11-30T18:16:01.8372242+08:00||;True|2025-11-30T14:50:31.9356543+08:00||;True|2025-11-30T14:48:27.1833064+08:00||; diff --git a/appsettings.json b/appsettings.json index 9b69890..224871a 100644 --- a/appsettings.json +++ b/appsettings.json @@ -1,5 +1,5 @@ { "dbconn": "", "dbtype": "Sqlite", - "tagName": "beta_1.7.4" + "tagName": "beta_1.7.5" } \ No newline at end of file diff --git a/job/DouYinCollectSyncJob.cs b/job/DouYinCollectSyncJob.cs index 3a54028..3feb9f9 100644 --- a/job/DouYinCollectSyncJob.cs +++ b/job/DouYinCollectSyncJob.cs @@ -83,8 +83,8 @@ namespace dy.net.job protected override string CreateSaveFolder(DouyinCookie cookie, Aweme item, AppConfig config, DouyinFollowed followed) { var (tag1, _, _) = GetVideoTags(item); - var safeTag1 = string.IsNullOrWhiteSpace(tag1) ? "other" : DouyinFileNameHelper.SanitizeLinuxFileName(tag1); - var folder = Path.Combine(cookie.SavePath, safeTag1, $"{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc)}@{item.AwemeId}"); + 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; } diff --git a/job/DouYinFavoritSyncJob.cs b/job/DouYinFavoritSyncJob.cs index 59b1ec4..22a710b 100644 --- a/job/DouYinFavoritSyncJob.cs +++ b/job/DouYinFavoritSyncJob.cs @@ -70,8 +70,8 @@ namespace dy.net.job protected override string CreateSaveFolder(DouyinCookie cookie, Aweme item, AppConfig config, DouyinFollowed followed) { var (tag1, _, _) = GetVideoTags(item); - var safeTag1 = string.IsNullOrWhiteSpace(tag1) ? "other" : DouyinFileNameHelper.SanitizeLinuxFileName(tag1); - var folder = Path.Combine(cookie.FavSavePath, safeTag1, $"{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc)}@{item.AwemeId}"); + var safeTag1 = string.IsNullOrWhiteSpace(tag1) ? "other" : DouyinFileNameHelper.SanitizeLinuxFileName(tag1,"",true); + var folder = Path.Combine(cookie.FavSavePath, safeTag1, $"{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId,true)}"); if (!Directory.Exists(folder)) Directory.CreateDirectory(folder); return folder; } diff --git a/job/DouyinBasicSyncJob.cs b/job/DouyinBasicSyncJob.cs index f061354..f65907d 100644 --- a/job/DouyinBasicSyncJob.cs +++ b/job/DouyinBasicSyncJob.cs @@ -176,15 +176,6 @@ namespace dy.net.job /// 有效的Cookie列表 protected abstract Task> GetValidCookies(); - /// - /// 获取关注列表 - /// - /// - protected virtual Task> GetFollows() - { - return Task.FromResult(new List()); - } - /// /// 检查指定的Cookie是否有效 /// @@ -662,18 +653,18 @@ namespace dy.net.job return null; } - Log.Debug($"{VideoType}-视频[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc)}]开始下载..."); + Log.Debug($"{VideoType}-视频[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc,item.AwemeId)}]开始下载..."); // 随机延迟,模拟人类操作 await Task.Delay(_random.Next(1, 4) * 1000); // 下载视频 if (!await douyinHttpClientService.DownloadAsync(videoUrl, savePath, cookie.Cookies)) { - Log.Error($"{VideoType}-{item?.Author?.Nickname ?? ""}-视频[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc)}]下载失败!!!"); + Log.Error($"{VideoType}-{item?.Author?.Nickname ?? ""}-视频[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId)}]下载失败!!!"); return null; } else { - Log.Debug($"{VideoType}-{item?.Author?.Nickname ?? ""}-视频[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc)}]下载完成."); + Log.Debug($"{VideoType}-{item?.Author?.Nickname ?? ""}-视频[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId)}]下载完成."); } // 下载视频封面 @@ -724,7 +715,7 @@ namespace dy.net.job Log.Error($"{VideoType}-图文视频同步-没有配置图片存储路径,任务终止!!!"); return null; } - fileNamefolder = Path.Combine(cookie.ImgSavePath, DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId)); + fileNamefolder = Path.Combine(cookie.ImgSavePath, DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId,true)); } else { @@ -762,7 +753,7 @@ namespace dy.net.job var mergeResult = await douyinMergeVideoService.MergeToVideo(cookie.Cookies, AppContext.BaseDirectory, reqParams, savePath, fileNamefolder, config.DownImageVideo, config.DownImage, config.DownMp3); if (!mergeResult) { - Log.Error($"{VideoType}-图文视频-[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc)}]合成失败!!!"); + Log.Error($"{VideoType}-图文视频-[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc,item.AwemeId)}]合成失败!!!"); return null; } @@ -771,7 +762,7 @@ namespace dy.net.job // 检查合成后的视频文件是否有效 if (!File.Exists(savePath) || new FileInfo(savePath).Length <= 0) { - Log.Error($"{VideoType}-图文视频-[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc)}]合成失败!!!"); + Log.Error($"{VideoType}-图文视频-[{DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId)}]合成失败!!!"); // 清理无效的文件和文件夹 if (Directory.Exists(fileNamefolder)) { diff --git a/job/DouyinFollowedViedoSyncJob.cs b/job/DouyinFollowedViedoSyncJob.cs index 169a226..747331d 100644 --- a/job/DouyinFollowedViedoSyncJob.cs +++ b/job/DouyinFollowedViedoSyncJob.cs @@ -55,7 +55,7 @@ namespace dy.net.job protected override string CreateSaveFolder(DouyinCookie cookie, Aweme item, AppConfig config, DouyinFollowed followed) { #region 默认使用UP主名称作为文件夹名称,若关注列表中有自定义保存路径则使用自定义路径 - var authorName = string.IsNullOrWhiteSpace(item.Author?.Nickname) ? "UnknownAuthor" : DouyinFileNameHelper.SanitizeLinuxFileName(item.Author.Nickname); + var authorName = string.IsNullOrWhiteSpace(item.Author?.Nickname) ? "UnknownAuthor" : DouyinFileNameHelper.SanitizeLinuxFileName(item.Author.Nickname,"",true); var folder = Path.Combine(cookie.UpSavePath, authorName); if (!string.IsNullOrWhiteSpace(followed.SavePath)) { @@ -70,7 +70,7 @@ namespace dy.net.job } else { - var sampleName = DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId); + var sampleName = DouyinFileNameHelper.SanitizeLinuxFileName(item.Desc, item.AwemeId,true); var (existingName, _) = douyinVideoService.GetUperLastViedoFileName(item.Author.Uid, sampleName).Result; var fileNameFolder = string.IsNullOrWhiteSpace(existingName) ? sampleName : existingName; return Path.Combine(folder, fileNameFolder); @@ -133,7 +133,7 @@ namespace dy.net.job Author = item.Author.Nickname }); - fileName= $"{DouyinFileNameHelper.SanitizeLinuxFileName(fullName)}.{Format}"; + fileName= $"{fullName}.{Format}"; } else { diff --git a/utils/DouyinFileNameHelper.cs b/utils/DouyinFileNameHelper.cs index 003a861..eb6c2fb 100644 --- a/utils/DouyinFileNameHelper.cs +++ b/utils/DouyinFileNameHelper.cs @@ -15,37 +15,64 @@ namespace dy.net.utils /// /// 原始名称(支持英文、中文、混合字符) /// 截取后为空时的默认名称(默认 "default") + /// 是否是创建文件夹 命名 /// 符合 Linux 规则的合法名称 - public static string SanitizeLinuxFileName(string originalName, string defaultName = "default") + public static string SanitizeLinuxFileName(string originalName, string defaultName, bool isfolder = false) { + string result = string.Empty; // 1. 空值处理:直接返回默认名 if (string.IsNullOrWhiteSpace(originalName)) - return defaultName.Replace(" ",""); - - // 2. 过滤 Linux 非法字符: - // - 禁止:/(路径分隔符)、\0(空字符) - // - 替换:其他特殊字符(如 :*?"<>|\\ )为下划线 _,避免创建失败 - var invalidChars = new[] { '/', '\0', ':', '*', '?', '"', '<', '>', '|', '\\' }; - string sanitizedName = originalName; - foreach (var c in invalidChars) + result= defaultName.Replace(" ",""); + else { - sanitizedName = sanitizedName.Replace(c, '_'); + // 2. 过滤 Linux 非法字符: + // - 禁止:/(路径分隔符)、\0(空字符) + // - 替换:其他特殊字符(如 :*?"<>|\\ )为下划线 _,避免创建失败 + var invalidChars = new[] { '/', '\0', ':', '*', '?', '"', '<', '>', '|', '\\' }; + string sanitizedName = originalName; + foreach (var c in invalidChars) + { + sanitizedName = sanitizedName.Replace(c, '_'); + } + + // 3. 计算 UTF-8 字节数,若未超 255 字节,直接返回 + byte[] utf8Bytes = Encoding.UTF8.GetBytes(sanitizedName); + if (utf8Bytes.Length <= 100) + result= sanitizedName.Replace(" ", ""); + else + { + // 4. 超过 255 字节,截取前 255 字节(避免破坏 UTF-8 字符) + byte[] truncatedBytes = new byte[100]; + Array.Copy(utf8Bytes, truncatedBytes, 100); + + // 5. 字节数组转回字符串(自动忽略不完整的尾部字节,避免乱码) + string truncatedName = Encoding.UTF8.GetString(truncatedBytes).TrimEnd('\0').Replace(" ", ""); // 移除可能的空字符 + + // 6. 极端情况:截取后为空(如全是非法字符替换后无有效内容),返回默认名 + result= string.IsNullOrWhiteSpace(truncatedName) ? defaultName : truncatedName; + } + if (isfolder) + { + result = KeepChineseLettersAndNumbers(result); + } } + return result; + } - // 3. 计算 UTF-8 字节数,若未超 255 字节,直接返回 - byte[] utf8Bytes = Encoding.UTF8.GetBytes(sanitizedName); - if (utf8Bytes.Length <= 100) - return sanitizedName.Replace(" ", ""); ; - // 4. 超过 255 字节,截取前 255 字节(避免破坏 UTF-8 字符) - byte[] truncatedBytes = new byte[100]; - Array.Copy(utf8Bytes, truncatedBytes, 100); - // 5. 字节数组转回字符串(自动忽略不完整的尾部字节,避免乱码) - string truncatedName = Encoding.UTF8.GetString(truncatedBytes).TrimEnd('\0').Replace(" ",""); // 移除可能的空字符 + /// 保留字符串中的中文、字母、数字,去除其他所有字符 + /// + /// 原始字符串 + /// 处理后的字符串 + public static string KeepChineseLettersAndNumbers(string input) + { + if (string.IsNullOrEmpty(input)) + return input; // 空字符串/Null直接返回,避免异常 - // 6. 极端情况:截取后为空(如全是非法字符替换后无有效内容),返回默认名 - return string.IsNullOrWhiteSpace(truncatedName) ? defaultName : truncatedName; + // 正则表达式:匹配非中文(\u4e00-\u9fa5)、非字母(a-zA-Z)、非数字(0-9)的字符 + string pattern = @"[^\u4e00-\u9fa5a-zA-Z0-9]"; + return Regex.Replace(input, pattern, string.Empty); } diff --git a/utils/VideoTitleGenerator.cs b/utils/VideoTitleGenerator.cs index 073c21a..f9785ad 100644 --- a/utils/VideoTitleGenerator.cs +++ b/utils/VideoTitleGenerator.cs @@ -33,10 +33,10 @@ namespace dy.net.utils { // 普通字段 ["Id"] = data.Id.ToString(), - ["VideoTitle"] = string.IsNullOrWhiteSpace(data.VideoTitle) ? emptyPlaceholder : data.VideoTitle, + ["VideoTitle"] = string.IsNullOrWhiteSpace(DouyinFileNameHelper.KeepChineseLettersAndNumbers(data.VideoTitle)) ? emptyPlaceholder : DouyinFileNameHelper.KeepChineseLettersAndNumbers(data.VideoTitle), ["FileHash"] = string.IsNullOrWhiteSpace(data.FileHash) ? emptyPlaceholder : data.FileHash, ["Resolution"] = string.IsNullOrWhiteSpace(data.Resolution) ? emptyPlaceholder : data.Resolution, - ["Author"] = string.IsNullOrWhiteSpace(data.Author) ? emptyPlaceholder : data.Author, + ["Author"] = string.IsNullOrWhiteSpace(DouyinFileNameHelper.KeepChineseLettersAndNumbers(data.Author)) ? emptyPlaceholder : DouyinFileNameHelper.KeepChineseLettersAndNumbers(data.Author), // 时间字段(支持空值处理) //["SyncTime"] = data.SyncTime.HasValue ? data.SyncTime.Value.ToString(timeFormat) : emptyPlaceholder,