From 192865c7e149b331db559da8efcf498454f75cc5 Mon Sep 17 00:00:00 2001 From: cxfksword Date: Wed, 26 Oct 2022 14:27:33 +0800 Subject: [PATCH] Optimize anime name format --- .../EpisodeProviderTest.cs | 48 ++++++++++ .../StringSimilarityTest.cs | 1 + Jellyfin.Plugin.MetaShark/Api/TmdbApi.cs | 31 ++++--- .../Providers/BaseProvider.cs | 5 +- .../Providers/EpisodeImageProvider.cs | 10 +- .../Providers/EpisodeProvider.cs | 60 ++++++++---- .../Providers/SeasonImageProvider.cs | 2 +- .../Providers/SeasonProvider.cs | 93 ++++++++++--------- .../Providers/SeriesProvider.cs | 19 ++-- README.md | 4 + 10 files changed, 182 insertions(+), 91 deletions(-) create mode 100644 Jellyfin.Plugin.MetaShark.Test/EpisodeProviderTest.cs diff --git a/Jellyfin.Plugin.MetaShark.Test/EpisodeProviderTest.cs b/Jellyfin.Plugin.MetaShark.Test/EpisodeProviderTest.cs new file mode 100644 index 0000000..41ff6ff --- /dev/null +++ b/Jellyfin.Plugin.MetaShark.Test/EpisodeProviderTest.cs @@ -0,0 +1,48 @@ +using Jellyfin.Plugin.MetaShark.Api; +using Jellyfin.Plugin.MetaShark.Core; +using Jellyfin.Plugin.MetaShark.Providers; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using Microsoft.Extensions.Logging; +using Moq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Jellyfin.Plugin.MetaShark.Test +{ + [TestClass] + public class EpisodeProviderTest + { + + ILoggerFactory loggerFactory = LoggerFactory.Create(builder => + builder.AddSimpleConsole(options => + { + options.IncludeScopes = true; + options.SingleLine = true; + options.TimestampFormat = "hh:mm:ss "; + })); + + + + [TestMethod] + public void TestGuessEpisodeNumber() + { + var doubanApi = new DoubanApi(loggerFactory); + var tmdbApi = new TmdbApi(loggerFactory); + var omdbApi = new OmdbApi(loggerFactory); + var httpClientFactory = new DefaultHttpClientFactory(); + var libraryManagerStub = new Mock(); + + var provider = new EpisodeProvider(httpClientFactory, loggerFactory, libraryManagerStub.Object, doubanApi, tmdbApi, omdbApi); + var indexNumber = provider.GuessEpisodeNumber("[POPGO][Stand_Alone_Complex][05][1080P][BluRay][x264_FLACx2_AC3x1][chs_jpn][D87C36B6].mkv"); + Assert.AreEqual(indexNumber, 5); + + indexNumber = provider.GuessEpisodeNumber("Fullmetal Alchemist Brotherhood.E05.1920X1080"); + Assert.AreEqual(indexNumber, 5); + } + + } +} diff --git a/Jellyfin.Plugin.MetaShark.Test/StringSimilarityTest.cs b/Jellyfin.Plugin.MetaShark.Test/StringSimilarityTest.cs index 1d40811..1c370fa 100644 --- a/Jellyfin.Plugin.MetaShark.Test/StringSimilarityTest.cs +++ b/Jellyfin.Plugin.MetaShark.Test/StringSimilarityTest.cs @@ -1,5 +1,6 @@ using Jellyfin.Plugin.MetaShark.Core; +using Emby.Naming.TV; namespace Jellyfin.Plugin.MetaShark.Test { diff --git a/Jellyfin.Plugin.MetaShark/Api/TmdbApi.cs b/Jellyfin.Plugin.MetaShark/Api/TmdbApi.cs index b7b0ee3..5f17ec4 100644 --- a/Jellyfin.Plugin.MetaShark/Api/TmdbApi.cs +++ b/Jellyfin.Plugin.MetaShark/Api/TmdbApi.cs @@ -27,7 +27,6 @@ namespace Jellyfin.Plugin.MetaShark.Api private readonly ILogger _logger; private readonly IMemoryCache _memoryCache; private readonly TMDbClient _tmDbClient; - private readonly PluginConfiguration _config; /// /// Initializes a new instance of the class. @@ -36,8 +35,8 @@ namespace Jellyfin.Plugin.MetaShark.Api { _logger = loggerFactory.CreateLogger(); _memoryCache = new MemoryCache(new MemoryCacheOptions()); - _config = Plugin.Instance?.Configuration ?? new PluginConfiguration(); - var apiKey = string.IsNullOrEmpty(_config.TmdbApiKey) ? DEFAULT_API_KEY : _config.TmdbApiKey; + var config = Plugin.Instance?.Configuration ?? new PluginConfiguration(); + var apiKey = string.IsNullOrEmpty(config.TmdbApiKey) ? DEFAULT_API_KEY : config.TmdbApiKey; _tmDbClient = new TMDbClient(apiKey); _tmDbClient.RequestTimeout = TimeSpan.FromSeconds(10); // Not really interested in NotFoundException @@ -54,7 +53,7 @@ namespace Jellyfin.Plugin.MetaShark.Api /// The TMDb movie or null if not found. public async Task GetMovieAsync(int tmdbId, string language, string imageLanguages, CancellationToken cancellationToken) { - if (!this._config.EnableTmdb) + if (!this.IsEnable()) { return null; } @@ -133,7 +132,7 @@ namespace Jellyfin.Plugin.MetaShark.Api /// The TMDb tv show information or null if not found. public async Task GetSeriesAsync(int tmdbId, string language, string imageLanguages, CancellationToken cancellationToken) { - if (!this._config.EnableTmdb) + if (!this.IsEnable()) { return null; } @@ -180,7 +179,7 @@ namespace Jellyfin.Plugin.MetaShark.Api /// The TMDb tv season information or null if not found. public async Task GetSeasonAsync(int tvShowId, int seasonNumber, string language, string imageLanguages, CancellationToken cancellationToken) { - if (!this._config.EnableTmdb) + if (!this.IsEnable()) { return null; } @@ -229,7 +228,7 @@ namespace Jellyfin.Plugin.MetaShark.Api /// The TMDb tv episode information or null if not found. public async Task GetEpisodeAsync(int tvShowId, int seasonNumber, int episodeNumber, string language, string imageLanguages, CancellationToken cancellationToken) { - if (!this._config.EnableTmdb) + if (!this.IsEnable()) { return null; } @@ -275,7 +274,7 @@ namespace Jellyfin.Plugin.MetaShark.Api /// The TMDb person information or null if not found. public async Task GetPersonAsync(int personTmdbId, CancellationToken cancellationToken) { - if (!this._config.EnableTmdb) + if (!this.IsEnable()) { return null; } @@ -324,7 +323,7 @@ namespace Jellyfin.Plugin.MetaShark.Api string language, CancellationToken cancellationToken) { - if (!this._config.EnableTmdb) + if (!this.IsEnable()) { return null; } @@ -368,7 +367,7 @@ namespace Jellyfin.Plugin.MetaShark.Api /// The TMDb tv show information. public async Task> SearchSeriesAsync(string name, string language, CancellationToken cancellationToken) { - if (!this._config.EnableTmdb) + if (!this.IsEnable()) { return new List(); } @@ -408,7 +407,7 @@ namespace Jellyfin.Plugin.MetaShark.Api /// The TMDb person information. public async Task> SearchPersonAsync(string name, CancellationToken cancellationToken) { - if (!this._config.EnableTmdb) + if (!this.IsEnable()) { return new List(); } @@ -463,7 +462,7 @@ namespace Jellyfin.Plugin.MetaShark.Api /// The TMDb movie information. public async Task> SearchMovieAsync(string name, int year, string language, CancellationToken cancellationToken) { - if (!this._config.EnableTmdb) + if (!this.IsEnable()) { return new List(); } @@ -505,7 +504,7 @@ namespace Jellyfin.Plugin.MetaShark.Api /// The TMDb collection information. public async Task> SearchCollectionAsync(string name, string language, CancellationToken cancellationToken) { - if (!this._config.EnableTmdb) + if (!this.IsEnable()) { return new List(); } @@ -648,6 +647,7 @@ namespace Jellyfin.Plugin.MetaShark.Api return language; } + public string GetImageLanguagesParam(string preferredLanguage) { var languages = new List(); @@ -677,5 +677,10 @@ namespace Jellyfin.Plugin.MetaShark.Api return string.Join(',', languages); } + private bool IsEnable() + { + return Plugin.Instance?.Configuration.EnableTmdb ?? true; + } + } } diff --git a/Jellyfin.Plugin.MetaShark/Providers/BaseProvider.cs b/Jellyfin.Plugin.MetaShark/Providers/BaseProvider.cs index 44f04f6..4ded476 100644 --- a/Jellyfin.Plugin.MetaShark/Providers/BaseProvider.cs +++ b/Jellyfin.Plugin.MetaShark/Providers/BaseProvider.cs @@ -115,8 +115,9 @@ namespace Jellyfin.Plugin.MetaShark.Providers var jw = new JaroWinkler(); foreach (var item in result) { - this.Log($"GuestSeasonByDouban: name: {name} item.Name: {item.Name} score: {jw.Similarity(name, item.Name)} "); - if (jw.Similarity(name, item.Name) < 0.8) + var score = jw.Similarity(name, item.Name); + this.Log($"GuestSeasonByDouban: name: {name} douban_name: {item.Name} douban_sid: {item.Sid} douban_year: {item.Year} score: {score} "); + if (score < 0.8) { continue; } diff --git a/Jellyfin.Plugin.MetaShark/Providers/EpisodeImageProvider.cs b/Jellyfin.Plugin.MetaShark/Providers/EpisodeImageProvider.cs index b53cb4a..33d2d35 100644 --- a/Jellyfin.Plugin.MetaShark/Providers/EpisodeImageProvider.cs +++ b/Jellyfin.Plugin.MetaShark/Providers/EpisodeImageProvider.cs @@ -53,7 +53,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers /// public async Task> GetImages(BaseItem item, CancellationToken cancellationToken) { - this.Log($"GetEpisodeImages for item: {item.Name} number: {item.IndexNumber}"); + this.Log($"GetEpisodeImages of [name]: {item.Name} number: {item.IndexNumber} ParentIndexNumber: {item.ParentIndexNumber}"); var episode = (MediaBrowser.Controller.Entities.TV.Episode)item; var series = episode.Series; @@ -62,7 +62,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers if (seriesTmdbId <= 0) { - this.Log($"Got images failed because the seriesTmdbId is empty!"); + this.Log($"[GetEpisodeImages] The seriesTmdbId is empty!"); return Enumerable.Empty(); } @@ -71,7 +71,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers if (!seasonNumber.HasValue || !episodeNumber.HasValue) { - this.Log($"Got images failed because the seasonNumber or episodeNumber is empty! seasonNumber: {seasonNumber} episodeNumber: {episodeNumber}"); + this.Log($"[GetEpisodeImages] The seasonNumber or episodeNumber is empty! seasonNumber: {seasonNumber} episodeNumber: {episodeNumber}"); return Enumerable.Empty(); } var language = item.GetPreferredMetadataLanguage(); @@ -82,7 +82,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers .ConfigureAwait(false); if (seasonResult == null || seasonResult.Episodes.Count < episodeNumber.Value) { - this.Log($"Not valid season data for seasonNumber: {seasonNumber} episodeNumber: {episodeNumber}"); + this.Log($"[GetEpisodeImages] Can't get season data for seasonNumber: {seasonNumber} episodeNumber: {episodeNumber}"); return Enumerable.Empty(); } @@ -105,7 +105,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers /// public Task GetImageResponse(string url, CancellationToken cancellationToken) { - this.Log("GetImageResponse url: {0}", url); + this.Log("[GetEpisodeImages] GetImageResponse url: {0}", url); return this._httpClientFactory.CreateClient().GetAsync(new Uri(url), cancellationToken); } diff --git a/Jellyfin.Plugin.MetaShark/Providers/EpisodeProvider.cs b/Jellyfin.Plugin.MetaShark/Providers/EpisodeProvider.cs index 228cbf3..638333c 100644 --- a/Jellyfin.Plugin.MetaShark/Providers/EpisodeProvider.cs +++ b/Jellyfin.Plugin.MetaShark/Providers/EpisodeProvider.cs @@ -45,36 +45,53 @@ namespace Jellyfin.Plugin.MetaShark.Providers /// public async Task> GetSearchResults(EpisodeInfo info, CancellationToken cancellationToken) { - this.Log($"GetSearchResults of [name]: {info.Name}"); + this.Log($"GetEpisodeSearchResults of [name]: {info.Name}"); return await Task.FromResult(Enumerable.Empty()); } /// public async Task> GetMetadata(EpisodeInfo info, CancellationToken cancellationToken) { - this.Log($"GetEpisodeMetadata of [name]: {info.Name} number: {info.IndexNumber}"); + // 重新识别时,info的IndexNumber和ParentIndexNumber是从文件路径解析出来的,假如命名不规范,就会导致解析出错误值 + // 刷新元数据不覆盖时,IndexNumber和ParentIndexNumber是从当前的元数据获取 + this.Log($"GetEpisodeMetadata of [name]: {info.Name} number: {info.IndexNumber} ParentIndexNumber: {info.ParentIndexNumber}"); var result = new MetadataResult(); + // 剧集信息只有tmdb有 info.SeriesProviderIds.TryGetValue(MetadataProvider.Tmdb.ToString(), out var seriesTmdbId); - var seasonNumber = info.ParentIndexNumber; // 没有season级目录时,会为null + var seasonNumber = info.ParentIndexNumber; var episodeNumber = info.IndexNumber; var indexNumberEnd = info.IndexNumberEnd; - if (episodeNumber is null or 0) + // 修正anime命名格式导致的seasonNumber错误(从season元数据读取) + var parent = _libraryManager.FindByPath(Path.GetDirectoryName(info.Path), true); + if (parent is Season season) { - // 从文件名获取剧集的indexNumber - var fileName = Path.GetFileName(info.Path) ?? string.Empty; - episodeNumber = this.GuessEpisodeNumber(episodeNumber, fileName); - if (episodeNumber.HasValue && episodeNumber.Value > 0) - { - result.HasMetadata = true; - result.Item = new Episode - { - IndexNumber = episodeNumber - }; - } - this.Log("GuessEpisodeNumber: fileName: {0} episodeNumber: {1}", fileName, episodeNumber); + this.Log("FixSeasionNumber: old: {0} new: {1}", seasonNumber, season.IndexNumber); + seasonNumber = season.IndexNumber; } + // 没有season级目录时,会为null + if (seasonNumber is null or 0) + { + seasonNumber = 1; + } + // 修正anime命名格式导致的episodeNumber错误 + var fileName = Path.GetFileName(info.Path) ?? string.Empty; + var newEpisodeNumber = this.GuessEpisodeNumber(fileName); + if (newEpisodeNumber.HasValue && newEpisodeNumber != episodeNumber) + { + episodeNumber = newEpisodeNumber; + + result.HasMetadata = true; + result.Item = new Episode + { + ParentIndexNumber = seasonNumber, + IndexNumber = episodeNumber + }; + this.Log("GuessEpisodeNumber: fileName: {0} episodeNumber: {1}", fileName, newEpisodeNumber); + } + + if (episodeNumber is null or 0 || seasonNumber is null or 0 || string.IsNullOrEmpty(seriesTmdbId)) { @@ -88,6 +105,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers .ConfigureAwait(false); if (seasonResult == null || seasonResult.Episodes.Count < episodeNumber.Value) { + this.Log("Can‘t found episode data from tmdb. Name: {0} seriesTmdbId: {1} seasonNumber: {2} episodeNumber: {3}", info.Name, seriesTmdbId, seasonNumber, episodeNumber); return result; } @@ -128,9 +146,9 @@ namespace Jellyfin.Plugin.MetaShark.Providers return _httpClientFactory.CreateClient().GetAsync(new Uri(url), cancellationToken); } - private int? GuessEpisodeNumber(int? current, string fileName, double max = double.PositiveInfinity) + public int? GuessEpisodeNumber(string fileName, double max = double.PositiveInfinity) { - var episodeIndex = current; + int? episodeIndex = null; var result = AnitomySharp.AnitomySharp.Parse(fileName).FirstOrDefault(x => x.Category == AnitomySharp.Element.ElementCategory.ElementEpisodeNumber); if (result != null) @@ -148,6 +166,12 @@ namespace Jellyfin.Plugin.MetaShark.Providers break; } + if (episodeIndex > 1000) + { + // 可能解析了分辨率,忽略返回 + episodeIndex = null; + } + return episodeIndex; } diff --git a/Jellyfin.Plugin.MetaShark/Providers/SeasonImageProvider.cs b/Jellyfin.Plugin.MetaShark/Providers/SeasonImageProvider.cs index 7bdf7ff..440e893 100644 --- a/Jellyfin.Plugin.MetaShark/Providers/SeasonImageProvider.cs +++ b/Jellyfin.Plugin.MetaShark/Providers/SeasonImageProvider.cs @@ -118,7 +118,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers /// public async Task GetImageResponse(string url, CancellationToken cancellationToken) { - this.Log("GetImageResponse url: {0}", url); + this.Log("[GetSeasonImages] GetImageResponse url: {0}", url); return await this._httpClientFactory.CreateClient().GetAsync(new Uri(url), cancellationToken).ConfigureAwait(false); } diff --git a/Jellyfin.Plugin.MetaShark/Providers/SeasonProvider.cs b/Jellyfin.Plugin.MetaShark/Providers/SeasonProvider.cs index 3ed8fa0..62500c4 100644 --- a/Jellyfin.Plugin.MetaShark/Providers/SeasonProvider.cs +++ b/Jellyfin.Plugin.MetaShark/Providers/SeasonProvider.cs @@ -69,6 +69,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers info.SeriesProviderIds.TryGetValue(Plugin.ProviderId, out var metaSource); info.SeriesProviderIds.TryGetValue(DoubanProviderId, out var sid); var seasonNumber = info.IndexNumber; + var seasonSid = info.GetProviderId(DoubanProviderId); if (metaSource == MetaSource.Douban && !string.IsNullOrEmpty(sid)) { @@ -78,57 +79,63 @@ namespace Jellyfin.Plugin.MetaShark.Providers { return result; } - var seiresName = series.Name; + var seriesName = series.Name; // 存在tmdbid,尝试从tmdb获取对应季的年份信息,用于从豆瓣搜索对应季数据 - int seasonYear = 0; - if (!string.IsNullOrEmpty(seriesTmdbId) && seasonNumber.HasValue) + if (string.IsNullOrEmpty(seasonSid)) { - var season = await this._tmdbApi - .GetSeasonAsync(seriesTmdbId.ToInt(), seasonNumber.Value, info.MetadataLanguage, info.MetadataLanguage, cancellationToken) - .ConfigureAwait(false); - seasonYear = season?.AirDate?.Year ?? 0; - } - - if (!string.IsNullOrEmpty(seiresName) && seasonYear > 0) - { - var seasonSid = await this.GuestSeasonByDoubanAsync(seiresName, seasonYear, cancellationToken).ConfigureAwait(false); - if (!string.IsNullOrEmpty(seasonSid)) + var seasonYear = 0; + if (!string.IsNullOrEmpty(seriesTmdbId) && seasonNumber.HasValue) { - var subject = await this._doubanApi.GetMovieAsync(seasonSid, cancellationToken).ConfigureAwait(false); - if (subject != null) - { - subject.Celebrities = await this._doubanApi.GetCelebritiesBySidAsync(seasonSid, cancellationToken).ConfigureAwait(false); + var season = await this._tmdbApi + .GetSeasonAsync(seriesTmdbId.ToInt(), seasonNumber.Value, info.MetadataLanguage, info.MetadataLanguage, cancellationToken) + .ConfigureAwait(false); + seasonYear = season?.AirDate?.Year ?? 0; + } - var movie = new Season - { - ProviderIds = new Dictionary { { DoubanProviderId, subject.Sid } }, - Name = subject.Name, - OriginalTitle = subject.OriginalName, - CommunityRating = subject.Rating, - Overview = subject.Intro, - ProductionYear = subject.Year, - Genres = subject.Genres, - PremiereDate = subject.ScreenTime, - IndexNumber = info.IndexNumber, - }; - - result.Item = movie; - result.HasMetadata = true; - subject.Celebrities.ForEach(c => result.AddPerson(new PersonInfo - { - Name = c.Name, - Type = c.RoleType, - Role = c.Role, - ImageUrl = c.Img, - ProviderIds = new Dictionary { { DoubanProviderId, c.Id } }, - })); - - return result; - } + if (!string.IsNullOrEmpty(seriesName) && seasonYear > 0) + { + seasonSid = await this.GuestSeasonByDoubanAsync(seriesName, seasonYear, cancellationToken).ConfigureAwait(false); } } + // 获取季豆瓣数据 + if (!string.IsNullOrEmpty(seasonSid)) + { + var subject = await this._doubanApi.GetMovieAsync(seasonSid, cancellationToken).ConfigureAwait(false); + if (subject != null) + { + subject.Celebrities = await this._doubanApi.GetCelebritiesBySidAsync(seasonSid, cancellationToken).ConfigureAwait(false); + + var movie = new Season + { + ProviderIds = new Dictionary { { DoubanProviderId, subject.Sid } }, + Name = subject.Name, + OriginalTitle = subject.OriginalName, + CommunityRating = subject.Rating, + Overview = subject.Intro, + ProductionYear = subject.Year, + Genres = subject.Genres, + PremiereDate = subject.ScreenTime, + IndexNumber = info.IndexNumber, + }; + + result.Item = movie; + result.HasMetadata = true; + subject.Celebrities.ForEach(c => result.AddPerson(new PersonInfo + { + Name = c.Name, + Type = c.RoleType, + Role = c.Role, + ImageUrl = c.Img, + ProviderIds = new Dictionary { { DoubanProviderId, c.Id } }, + })); + + return result; + } + } + + // 从豆瓣获取不到季信息,直接使用series信息 result.Item = new Season { diff --git a/Jellyfin.Plugin.MetaShark/Providers/SeriesProvider.cs b/Jellyfin.Plugin.MetaShark/Providers/SeriesProvider.cs index 70c8fd8..808b1b5 100644 --- a/Jellyfin.Plugin.MetaShark/Providers/SeriesProvider.cs +++ b/Jellyfin.Plugin.MetaShark/Providers/SeriesProvider.cs @@ -78,7 +78,6 @@ namespace Jellyfin.Plugin.MetaShark.Providers public async Task> GetMetadata(SeriesInfo info, CancellationToken cancellationToken) { this.Log($"GetSeriesMetadata of [name]: {info.Name} [providerIds]: {info.ProviderIds.ToJson()}"); - info.Name = this.RemoveMetaSourcePrefix(info.Name); var result = new MetadataResult(); var sid = info.GetProviderId(DoubanProviderId); @@ -120,16 +119,18 @@ namespace Jellyfin.Plugin.MetaShark.Providers if (!string.IsNullOrEmpty(subject.Imdb)) { item.SetProviderId(MetadataProvider.Imdb, subject.Imdb); - - // 通过imdb获取TMDB id (豆瓣的imdb id可能是旧的,需要先从omdb接口获取最新的imdb id - var omdbItem = await this._omdbApi.GetByImdbID(subject.Imdb, cancellationToken).ConfigureAwait(false); - if (omdbItem != null) + if (string.IsNullOrEmpty(tmdbId)) { - var findResult = await this._tmdbApi.FindByExternalIdAsync(omdbItem.ImdbID, FindExternalSource.Imdb, info.MetadataLanguage, cancellationToken).ConfigureAwait(false); - if (findResult?.TvResults != null && findResult.TvResults.Count > 0) + // 通过imdb获取TMDB id (豆瓣的imdb id可能是旧的,需要先从omdb接口获取最新的imdb id + var omdbItem = await this._omdbApi.GetByImdbID(subject.Imdb, cancellationToken).ConfigureAwait(false); + if (omdbItem != null) { - this.Log($"GetSeriesMetadata found tmdb [id]: {findResult.TvResults[0].Id} by imdb id: {subject.Imdb}"); - item.SetProviderId(MetadataProvider.Tmdb, $"{findResult.TvResults[0].Id}"); + var findResult = await this._tmdbApi.FindByExternalIdAsync(omdbItem.ImdbID, FindExternalSource.Imdb, info.MetadataLanguage, cancellationToken).ConfigureAwait(false); + if (findResult?.TvResults != null && findResult.TvResults.Count > 0) + { + this.Log($"GetSeriesMetadata found tmdb [id]: {findResult.TvResults[0].Id} by imdb id: {subject.Imdb}"); + item.SetProviderId(MetadataProvider.Tmdb, $"{findResult.TvResults[0].Id}"); + } } } } diff --git a/README.md b/README.md index bbebb3c..ab3847d 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,10 @@ jellyfin电影元数据插件,影片信息只要从豆瓣获取,并由TheMovieDb补充缺失的季数据和剧集数据。 +功能: +* 支持从豆瓣和TMDB获取元数据 +* 兼容anime动画名称格式 + ![preview](doc/logo.png) ## 安装插件