From ae309406721b578923d2c8c6d540fe83004c2704 Mon Sep 17 00:00:00 2001 From: cxfksword Date: Tue, 1 Nov 2022 22:43:11 +0800 Subject: [PATCH] Optimize season & episode metadata fetch --- .../Providers/BaseProvider.cs | 23 +----- .../Providers/EpisodeProvider.cs | 52 +++++++++++- .../Providers/SeasonProvider.cs | 79 +++++++++++-------- 3 files changed, 102 insertions(+), 52 deletions(-) diff --git a/Jellyfin.Plugin.MetaShark/Providers/BaseProvider.cs b/Jellyfin.Plugin.MetaShark/Providers/BaseProvider.cs index 77bcb98..1e9f6b2 100644 --- a/Jellyfin.Plugin.MetaShark/Providers/BaseProvider.cs +++ b/Jellyfin.Plugin.MetaShark/Providers/BaseProvider.cs @@ -133,6 +133,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers { continue; } + var score = jw.Similarity(name, item.Name); // this.Log($"GuestDoubanSeasonByYear name: {name} douban_name: {item.Name} douban_sid: {item.Sid} douban_year: {item.Year} score: {score} "); if (score < 0.8) @@ -150,6 +151,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers return null; } + // 通过季数,搜索结果按年份排序后,取对应季数索引项(不适合每季标题差异太大的,如葫芦兄弟和葫芦小金刚) protected async Task GuestDoubanSeasonByNumberAsync(string name, int? seasonNumber, CancellationToken cancellationToken) { if (seasonNumber == null || seasonNumber == 0) @@ -167,6 +169,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers { continue; } + var score = jw.Similarity(name, item.Name); if (score < 0.8) { @@ -227,26 +230,6 @@ namespace Jellyfin.Plugin.MetaShark.Providers } - protected int GetVideoFileCount(string? dir) - { - if (dir == null) - { - return 0; - } - - var dirInfo = new DirectoryInfo(dir); - var files = dirInfo.GetFiles(); - var nameOptions = new Emby.Naming.Common.NamingOptions(); - var videoFilesCount = 0; - foreach (var fileInfo in files.Where(f => !f.Attributes.HasFlag(FileAttributes.Hidden))) - { - if (Emby.Naming.Video.VideoResolver.IsVideoFile(fileInfo.FullName, nameOptions)) - { - videoFilesCount++; - } - } - return videoFilesCount; - } protected string GetProxyImageUrl(string url) diff --git a/Jellyfin.Plugin.MetaShark/Providers/EpisodeProvider.cs b/Jellyfin.Plugin.MetaShark/Providers/EpisodeProvider.cs index 5867877..04aaf71 100644 --- a/Jellyfin.Plugin.MetaShark/Providers/EpisodeProvider.cs +++ b/Jellyfin.Plugin.MetaShark/Providers/EpisodeProvider.cs @@ -9,6 +9,7 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Caching.Memory; using System; using System.Collections.Generic; using System.IO; @@ -22,8 +23,9 @@ using MediaBrowser.Controller.Entities; namespace Jellyfin.Plugin.MetaShark.Providers { - public class EpisodeProvider : BaseProvider, IRemoteMetadataProvider + public class EpisodeProvider : BaseProvider, IRemoteMetadataProvider, IDisposable { + private readonly IMemoryCache _memoryCache; private static readonly Regex[] EpisodeFileNameRegex = { @@ -38,6 +40,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers public EpisodeProvider(IHttpClientFactory httpClientFactory, ILoggerFactory loggerFactory, ILibraryManager libraryManager, DoubanApi doubanApi, TmdbApi tmdbApi, OmdbApi omdbApi) : base(httpClientFactory, loggerFactory.CreateLogger(), libraryManager, doubanApi, tmdbApi, omdbApi) { + this._memoryCache = new MemoryCache(new MemoryCacheOptions()); } public string Name => Plugin.PluginName; @@ -112,6 +115,8 @@ namespace Jellyfin.Plugin.MetaShark.Providers this.Log("Can‘t found episode data from tmdb. Name: {0} seriesTmdbId: {1} seasonNumber: {2} episodeNumber: {3}", info.Name, seriesTmdbId, seasonNumber, episodeNumber); return result; } + + // 判断tmdb剧集信息数目和视频是否一致,不一致不处理 var videoFilesCount = this.GetVideoFileCount(Path.GetDirectoryName(info.Path)); if (videoFilesCount > 0 && seasonResult.Episodes.Count != videoFilesCount) { @@ -194,5 +199,50 @@ namespace Jellyfin.Plugin.MetaShark.Providers return guessInfo; } + + + protected int GetVideoFileCount(string? dir) + { + if (dir == null) + { + return 0; + } + + var cacheKey = $"filecount_{dir}"; + if (this._memoryCache.TryGetValue(cacheKey, out var videoFilesCount)) + { + return videoFilesCount; + } + + var dirInfo = new DirectoryInfo(dir); + var files = dirInfo.GetFiles(); + var nameOptions = new Emby.Naming.Common.NamingOptions(); + + foreach (var fileInfo in files.Where(f => !f.Attributes.HasFlag(FileAttributes.Hidden))) + { + if (Emby.Naming.Video.VideoResolver.IsVideoFile(fileInfo.FullName, nameOptions)) + { + videoFilesCount++; + } + } + + var expiredOption = new MemoryCacheEntryOptions() { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1) }; + this._memoryCache.Set(cacheKey, videoFilesCount, expiredOption); + return videoFilesCount; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _memoryCache.Dispose(); + } + } } } diff --git a/Jellyfin.Plugin.MetaShark/Providers/SeasonProvider.cs b/Jellyfin.Plugin.MetaShark/Providers/SeasonProvider.cs index 50e721f..f52388a 100644 --- a/Jellyfin.Plugin.MetaShark/Providers/SeasonProvider.cs +++ b/Jellyfin.Plugin.MetaShark/Providers/SeasonProvider.cs @@ -82,11 +82,6 @@ namespace Jellyfin.Plugin.MetaShark.Providers } } - // 尝试通过豆瓣按年份排序后,按季数索引取对应一个 - if (string.IsNullOrEmpty(seasonSid) && !string.IsNullOrEmpty(seriesName) && seasonNumber.HasValue) - { - seasonSid = await this.GuestDoubanSeasonByNumberAsync(seriesName, seasonNumber, cancellationToken).ConfigureAwait(false); - } // 获取季豆瓣数据 if (!string.IsNullOrEmpty(seasonSid)) @@ -125,6 +120,17 @@ namespace Jellyfin.Plugin.MetaShark.Providers } + // tmdb有数据,豆瓣找不到,尝试获取tmdb的季数据 + if (string.IsNullOrEmpty(seasonSid) && !string.IsNullOrWhiteSpace(seriesTmdbId) && seasonNumber.HasValue) + { + var tmdbResult = await this.GetMetadataByTmdb(info, seriesTmdbId, seasonNumber.Value, cancellationToken).ConfigureAwait(false); + if (tmdbResult != null) + { + return tmdbResult; + } + } + + // 从豆瓣获取不到季信息,直接使用series信息 result.Item = new Season { @@ -148,34 +154,11 @@ namespace Jellyfin.Plugin.MetaShark.Providers // tmdb季级没有对应id,只通过indexNumber区分 if (!string.IsNullOrWhiteSpace(seriesTmdbId) && seasonNumber.HasValue) { - var seasonResult = await this._tmdbApi - .GetSeasonAsync(seriesTmdbId.ToInt(), seasonNumber.Value, info.MetadataLanguage, null, cancellationToken) - .ConfigureAwait(false); - if (seasonResult == null) + var tmdbResult = await this.GetMetadataByTmdb(info, seriesTmdbId, seasonNumber.Value, cancellationToken).ConfigureAwait(false); + if (tmdbResult != null) { - this.Log($"Not found season from TMDB. {info.Name} seriesTmdbId: {seriesTmdbId} seasonNumber: {seasonNumber}"); - return result; + return tmdbResult; } - - result.HasMetadata = true; - result.Item = new Season - { - IndexNumber = seasonNumber, - Overview = seasonResult.Overview, - PremiereDate = seasonResult.AirDate, - ProductionYear = seasonResult.AirDate?.Year, - }; - - if (!string.IsNullOrEmpty(seasonResult.ExternalIds?.TvdbId)) - { - result.Item.SetProviderId(MetadataProvider.Tvdb, seasonResult.ExternalIds.TvdbId); - } - foreach (var person in GetPersons(seasonResult)) - { - result.AddPerson(person); - } - - return result; } @@ -222,6 +205,40 @@ namespace Jellyfin.Plugin.MetaShark.Providers return result; } + public async Task?> GetMetadataByTmdb(SeasonInfo info, string seriesTmdbId, int seasonNumber, CancellationToken cancellationToken) + { + var seasonResult = await this._tmdbApi + .GetSeasonAsync(seriesTmdbId.ToInt(), seasonNumber, info.MetadataLanguage, info.MetadataLanguage, cancellationToken) + .ConfigureAwait(false); + if (seasonResult == null) + { + this.Log($"Not found season from TMDB. {info.Name} seriesTmdbId: {seriesTmdbId} seasonNumber: {seasonNumber}"); + return null; + } + + + var result = new MetadataResult(); + result.HasMetadata = true; + result.Item = new Season + { + IndexNumber = seasonNumber, + Overview = seasonResult.Overview, + PremiereDate = seasonResult.AirDate, + ProductionYear = seasonResult.AirDate?.Year, + }; + + if (!string.IsNullOrEmpty(seasonResult.ExternalIds?.TvdbId)) + { + result.Item.SetProviderId(MetadataProvider.Tvdb, seasonResult.ExternalIds.TvdbId); + } + foreach (var person in GetPersons(seasonResult)) + { + result.AddPerson(person); + } + + return result; + } + private IEnumerable GetPersons(TvSeason item) {