Optimize season & episode metadata fetch

This commit is contained in:
cxfksword 2022-11-01 22:43:11 +08:00
parent 20f753a826
commit ae30940672
3 changed files with 102 additions and 52 deletions

View File

@ -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<string?> 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)

View File

@ -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<Episode, EpisodeInfo>
public class EpisodeProvider : BaseProvider, IRemoteMetadataProvider<Episode, EpisodeInfo>, 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<EpisodeProvider>(), 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("Cant 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<int>(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<int>(cacheKey, videoFilesCount, expiredOption);
return videoFilesCount;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_memoryCache.Dispose();
}
}
}
}

View File

@ -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<MetadataResult<Season>?> 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<Season>();
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<PersonInfo> GetPersons(TvSeason item)
{