feat: add fnOS packaging, storage workflows and release pipeline
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
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<VideoBitRate>
|
||||
{
|
||||
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"
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user