using dy.net.model.dto; using dy.net.model.entity; using dy.net.model.response; using dy.net.storage; using dy.net.utils; namespace dy.net.Tests; public class StorageMigrationPathPolicyTests { private readonly DouyinCookie _cookie = new() { Id = "cookie", WebDavCollectPath = "/账号/收藏", WebDavFavoritePath = "/账号/喜欢", WebDavFollowPath = "/账号/关注", WebDavMixPath = "/账号/合集", WebDavSeriesPath = "/账号/短剧" }; [Theory] [InlineData(VideoTypeEnum.dy_collects, "/账号/收藏")] [InlineData(VideoTypeEnum.dy_favorite, "/账号/喜欢")] public void Build_CollectionTypes_UseAuthorTitleAndStableAwemeSuffix(VideoTypeEnum type, string root) { var plan = StorageMigrationPathPolicy.Build(Video(type), _cookie, null, null, new AppConfig()); Assert.StartsWith(root + "/测试博主/Unicode标题123_aweme-1/", plan.VideoPath); Assert.EndsWith("/aweme-1.mp4", plan.VideoPath); Assert.EndsWith("/aweme-1-poster.jpg", plan.CoverPath); } [Fact] public void Build_CustomCollection_UsesCurrentCategoryFolderRule() { var video = Video(VideoTypeEnum.dy_custom_collect); var category = new DouyinCollectCate { SaveFolder = "专题 / 一", Name = "fallback" }; var plan = StorageMigrationPathPolicy.Build(video, _cookie, category, null, new AppConfig()); Assert.StartsWith("/账号/收藏/专题一/Unicode标题123_aweme-1/", plan.VideoPath); } [Theory] [InlineData(VideoTypeEnum.dy_mix, "/账号/合集")] [InlineData(VideoTypeEnum.dy_series, "/账号/短剧")] public void Build_SeriesTypes_PreserveExistingEpisodeNumber(VideoTypeEnum type, string root) { var video = Video(type); video.VideoSavePath = "/old/S01E07.mp4"; var category = new DouyinCollectCate { SaveFolder = "第一季", Name = "剧名" }; var plan = StorageMigrationPathPolicy.Build(video, _cookie, category, null, new AppConfig(), 2); Assert.Equal(root + "/第一季/S01E07.mp4", plan.VideoPath); Assert.Equal(root + "/第一季/poster.jpg", plan.CoverPath); } [Fact] public void Build_Followed_UsesCustomFolderAndCurrentTitleTemplate() { var video = Video(VideoTypeEnum.dy_follows); var followed = new DouyinFollowed { SavePath = "自定义博主目录" }; var config = new AppConfig { FullFollowedTitleTemplate = "{ReleaseTime}-{Author}-{Id}" }; var plan = StorageMigrationPathPolicy.Build(video, _cookie, null, followed, config); Assert.Contains("/账号/关注/自定义博主目录/Unicode标题123/", plan.VideoPath); Assert.EndsWith("/20260728-测试博主-aweme-1.mp4", plan.VideoPath); } [Theory] [InlineData(VideoTypeEnum.dy_collects)] [InlineData(VideoTypeEnum.dy_favorite)] [InlineData(VideoTypeEnum.dy_follows)] [InlineData(VideoTypeEnum.dy_custom_collect)] [InlineData(VideoTypeEnum.dy_mix)] [InlineData(VideoTypeEnum.dy_series)] public void Build_CurrentSyncAndMigrationUseTheSameRemotePolicy(VideoTypeEnum type) { var timestamp = new DateTimeOffset(2026, 7, 28, 0, 0, 0, TimeSpan.Zero).ToUnixTimeSeconds(); var aweme = new Aweme { AwemeId = "aweme-1", Desc = "Unicode 标题 / 123", CreateTime = timestamp, Author = new Author { Uid = "author-1", Nickname = "测试 博主" }, MixInfo = new MixInfo { Statis = new MixStatis { CurrentEpisode = 7 } }, Video = new Video { BitRate = new List { new() { Format = "mp4", PlayAddr = new PlayAddr { FileHash = "hash", Width = 1080, Height = 1920 } } } } }; var category = new DouyinCollectCate { SaveFolder = "第一季", Name = "剧名", CateType = type }; var followed = new DouyinFollowed { SavePath = "自定义博主目录" }; var config = new AppConfig { FullFollowedTitleTemplate = "{ReleaseTime}-{Author}-{Id}" }; var currentSync = StorageMigrationPathPolicy.Build(aweme, type, _cookie, category, followed, config); var persisted = new DouyinVideo { Id = "record-1", AwemeId = aweme.AwemeId, ViedoType = type, VideoTitle = aweme.Desc, VideoSavePath = currentSync.VideoPath, Author = aweme.Author.Nickname, AuthorId = aweme.Author.Uid, CreateTime = DateTimeUtil.Convert10BitTimestamp(timestamp), FileHash = "hash", Resolution = "1080×1920" }; var migration = StorageMigrationPathPolicy.Build(persisted, _cookie, category, followed, config, 7); Assert.Equal(currentSync.VideoPath, migration.VideoPath); Assert.Equal(currentSync.CoverPath, migration.CoverPath); } private static DouyinVideo Video(VideoTypeEnum type) => new() { Id = "record-1", AwemeId = "aweme-1", ViedoType = type, VideoTitle = "Unicode 标题 / 123", VideoSavePath = "/old/video.mp4", Author = "测试 博主", AuthorId = "author-1", CreateTime = new DateTime(2026, 7, 28), Resolution = "1080×1920" }; }