diff --git a/Jellyfin.Plugin.MetaShark.Test/EpisodeProviderTest.cs b/Jellyfin.Plugin.MetaShark.Test/EpisodeProviderTest.cs index 4bbb86d..7621c07 100644 --- a/Jellyfin.Plugin.MetaShark.Test/EpisodeProviderTest.cs +++ b/Jellyfin.Plugin.MetaShark.Test/EpisodeProviderTest.cs @@ -46,8 +46,9 @@ namespace Jellyfin.Plugin.MetaShark.Test var info = new EpisodeInfo() { Name = "Spice and Wolf", - Path = "/test/Spice and Wolf/Spice and Wolf II/[VCB-Studio] Spice and Wolf II [01][Ma10p_1080p][x265_flac].mp4", + Path = "/test/Spice and Wolf/S00/[VCB-Studio] Spice and Wolf II [01][Hi444pp_1080p][x264_flac].mkv", MetadataLanguage = "zh", + ParentIndexNumber = 0, SeriesProviderIds = new Dictionary() { { MetadataProvider.Tmdb.ToString(), "26707" } }, IsAutomated = false, }; diff --git a/Jellyfin.Plugin.MetaShark.Test/ParseNameTest.cs b/Jellyfin.Plugin.MetaShark.Test/ParseNameTest.cs index 49e52a0..b48461a 100644 --- a/Jellyfin.Plugin.MetaShark.Test/ParseNameTest.cs +++ b/Jellyfin.Plugin.MetaShark.Test/ParseNameTest.cs @@ -220,6 +220,10 @@ namespace Jellyfin.Plugin.MetaShark.Test parseResult = NameParser.Parse(fileName); Assert.IsTrue(parseResult.IsExtra); + fileName = "[VCB-Studio] Spice and Wolf II [Drama02][Ma10p_1080p][x265_flac].mp4"; + parseResult = NameParser.Parse(fileName); + Assert.IsTrue(parseResult.IsExtra); + } diff --git a/Jellyfin.Plugin.MetaShark/Model/ParseNameResult.cs b/Jellyfin.Plugin.MetaShark/Model/ParseNameResult.cs index ef31164..18aae5a 100644 --- a/Jellyfin.Plugin.MetaShark/Model/ParseNameResult.cs +++ b/Jellyfin.Plugin.MetaShark/Model/ParseNameResult.cs @@ -1,3 +1,4 @@ +using System.Collections.Specialized; using System; using System.Collections.Generic; using System.Linq; @@ -65,13 +66,30 @@ namespace Jellyfin.Plugin.MetaShark.Model { if (IndexNumber.HasValue) { - return $"{Name} {AnimeType} {PaddingZeroIndexNumber}"; + return $"{AnimeType} {PaddingZeroIndexNumber}"; } else { - return $"{Name} {AnimeType}"; + return $"{AnimeType}"; } } } + + public string SpecialName + { + get + { + if (!string.IsNullOrEmpty(EpisodeName) && IndexNumber.HasValue) + { + return $"{EpisodeName} {IndexNumber}"; + } + else if (!string.IsNullOrEmpty(EpisodeName)) + { + return EpisodeName; + } + + return Name; + } + } } } diff --git a/Jellyfin.Plugin.MetaShark/Providers/EpisodeProvider.cs b/Jellyfin.Plugin.MetaShark/Providers/EpisodeProvider.cs index c001c20..25ad47b 100644 --- a/Jellyfin.Plugin.MetaShark/Providers/EpisodeProvider.cs +++ b/Jellyfin.Plugin.MetaShark/Providers/EpisodeProvider.cs @@ -28,16 +28,6 @@ namespace Jellyfin.Plugin.MetaShark.Providers { private readonly IMemoryCache _memoryCache; - private static readonly Regex[] EpisodeFileNameRegex = - { - new(@"\[([\d\.]{2,})\]"), - new(@"- ?([\d\.]{2,})"), - new(@"EP?([\d\.]{2,})", RegexOptions.IgnoreCase), - new(@"\[([\d\.]{2,})"), - new(@"#([\d\.]{2,})"), - new(@"(\d{2,})") - }; - public EpisodeProvider(IHttpClientFactory httpClientFactory, ILoggerFactory loggerFactory, ILibraryManager libraryManager, IHttpContextAccessor httpContextAccessor, DoubanApi doubanApi, TmdbApi tmdbApi, OmdbApi omdbApi) : base(httpClientFactory, loggerFactory.CreateLogger(), libraryManager, httpContextAccessor, doubanApi, tmdbApi, omdbApi) { @@ -87,9 +77,9 @@ namespace Jellyfin.Plugin.MetaShark.Providers Name = info.Name, }; - if (episodeNumber is null or 0 || seasonNumber is null or 0 || string.IsNullOrEmpty(seriesTmdbId)) + if (episodeNumber is null or 0 || seasonNumber is null || string.IsNullOrEmpty(seriesTmdbId)) { - this.Log("Lack meta message. episodeNumber: {0} seasonNumber: {1} seriesTmdbId:{2}", episodeNumber, seasonNumber, seriesTmdbId); + this.Log("Lack meta data. episodeNumber: {0} seasonNumber: {1} seriesTmdbId:{2}", episodeNumber, seasonNumber, seriesTmdbId); return result; } @@ -148,8 +138,8 @@ namespace Jellyfin.Plugin.MetaShark.Providers // 使用AnitomySharp进行重新解析,解决anime识别错误 var fileName = Path.GetFileNameWithoutExtension(info.Path) ?? info.Name; var parseResult = NameParser.Parse(fileName); - info.Name = parseResult.Name; info.Year = parseResult.Year; + info.Name = parseResult.Name; // 没有season级目录或文件命名不规范时,ParentIndexNumber会为null if (info.ParentIndexNumber is null) @@ -184,21 +174,19 @@ namespace Jellyfin.Plugin.MetaShark.Providers info.ParentIndexNumber = 1; } - if (NameParser.IsAnime(fileName)) + // 特典 + if (NameParser.IsAnime(fileName) && parseResult.IsSpecial) { - // 特典 - if (parseResult.IsSpecial) - { - info.ParentIndexNumber = 0; - } - - // 动画的OP/ED/MENU等 - if (parseResult.IsExtra) - { - info.ParentIndexNumber = null; - } + info.ParentIndexNumber = 0; } + // 特典优先使用文件名 + if (info.ParentIndexNumber.HasValue && info.ParentIndexNumber == 0) + { + info.Name = parseResult.SpecialName == info.Name ? fileName : parseResult.SpecialName; + } + + // 大于1000,可能错误解析了分辨率 if (parseResult.IndexNumber.HasValue && parseResult.IndexNumber < 1000) { @@ -252,7 +240,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers { ParentIndexNumber = 0, IndexNumber = parseResult.IndexNumber, - Name = parseResult.EpisodeName ?? parseResult.Name, + Name = parseResult.SpecialName == info.Name ? fileName : parseResult.SpecialName, AirsAfterSeasonNumber = 1, }; diff --git a/Jellyfin.Plugin.MetaShark/Vendor/AnitomySharp/Keyword.cs b/Jellyfin.Plugin.MetaShark/Vendor/AnitomySharp/Keyword.cs index 1d7b368..81dcf6e 100644 --- a/Jellyfin.Plugin.MetaShark/Vendor/AnitomySharp/Keyword.cs +++ b/Jellyfin.Plugin.MetaShark/Vendor/AnitomySharp/Keyword.cs @@ -90,7 +90,7 @@ namespace AnitomySharp // 广告 Commercial Message 电视放送广告,时长一般在 7s/15s/30s/45s/... 左右 "CM","SPOT", // 宣传片/预告片 Promotion Video / Trailer 一般时长在 1~2min 命名参考原盘和 jsum - "PV", "Teaser","TRAILER", + "PV", "Teaser","TRAILER", "DRAMA", // 真人特典 Interview/Talk/Stage... 目前我们对于节目、采访、舞台活动、制作等三次元画面的长视频,一概怼成 IV。 "INTERVIEW", "EVENT", "TOKUTEN", "LOGO"});