Optimize season & episode metadata fetch
This commit is contained in:
parent
20f753a826
commit
ae30940672
|
@ -133,6 +133,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var score = jw.Similarity(name, item.Name);
|
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} ");
|
// this.Log($"GuestDoubanSeasonByYear name: {name} douban_name: {item.Name} douban_sid: {item.Sid} douban_year: {item.Year} score: {score} ");
|
||||||
if (score < 0.8)
|
if (score < 0.8)
|
||||||
|
@ -150,6 +151,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通过季数,搜索结果按年份排序后,取对应季数索引项(不适合每季标题差异太大的,如葫芦兄弟和葫芦小金刚)
|
||||||
protected async Task<string?> GuestDoubanSeasonByNumberAsync(string name, int? seasonNumber, CancellationToken cancellationToken)
|
protected async Task<string?> GuestDoubanSeasonByNumberAsync(string name, int? seasonNumber, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (seasonNumber == null || seasonNumber == 0)
|
if (seasonNumber == null || seasonNumber == 0)
|
||||||
|
@ -167,6 +169,7 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var score = jw.Similarity(name, item.Name);
|
var score = jw.Similarity(name, item.Name);
|
||||||
if (score < 0.8)
|
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)
|
protected string GetProxyImageUrl(string url)
|
||||||
|
|
|
@ -9,6 +9,7 @@ using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Providers;
|
using MediaBrowser.Model.Providers;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
@ -22,8 +23,9 @@ using MediaBrowser.Controller.Entities;
|
||||||
|
|
||||||
namespace Jellyfin.Plugin.MetaShark.Providers
|
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 =
|
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)
|
public EpisodeProvider(IHttpClientFactory httpClientFactory, ILoggerFactory loggerFactory, ILibraryManager libraryManager, DoubanApi doubanApi, TmdbApi tmdbApi, OmdbApi omdbApi)
|
||||||
: base(httpClientFactory, loggerFactory.CreateLogger<EpisodeProvider>(), libraryManager, doubanApi, tmdbApi, omdbApi)
|
: base(httpClientFactory, loggerFactory.CreateLogger<EpisodeProvider>(), libraryManager, doubanApi, tmdbApi, omdbApi)
|
||||||
{
|
{
|
||||||
|
this._memoryCache = new MemoryCache(new MemoryCacheOptions());
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name => Plugin.PluginName;
|
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);
|
this.Log("Can‘t found episode data from tmdb. Name: {0} seriesTmdbId: {1} seasonNumber: {2} episodeNumber: {3}", info.Name, seriesTmdbId, seasonNumber, episodeNumber);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 判断tmdb剧集信息数目和视频是否一致,不一致不处理
|
||||||
var videoFilesCount = this.GetVideoFileCount(Path.GetDirectoryName(info.Path));
|
var videoFilesCount = this.GetVideoFileCount(Path.GetDirectoryName(info.Path));
|
||||||
if (videoFilesCount > 0 && seasonResult.Episodes.Count != videoFilesCount)
|
if (videoFilesCount > 0 && seasonResult.Episodes.Count != videoFilesCount)
|
||||||
{
|
{
|
||||||
|
@ -194,5 +199,50 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
return guessInfo;
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
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信息
|
// 从豆瓣获取不到季信息,直接使用series信息
|
||||||
result.Item = new Season
|
result.Item = new Season
|
||||||
{
|
{
|
||||||
|
@ -148,34 +154,11 @@ namespace Jellyfin.Plugin.MetaShark.Providers
|
||||||
// tmdb季级没有对应id,只通过indexNumber区分
|
// tmdb季级没有对应id,只通过indexNumber区分
|
||||||
if (!string.IsNullOrWhiteSpace(seriesTmdbId) && seasonNumber.HasValue)
|
if (!string.IsNullOrWhiteSpace(seriesTmdbId) && seasonNumber.HasValue)
|
||||||
{
|
{
|
||||||
var seasonResult = await this._tmdbApi
|
var tmdbResult = await this.GetMetadataByTmdb(info, seriesTmdbId, seasonNumber.Value, cancellationToken).ConfigureAwait(false);
|
||||||
.GetSeasonAsync(seriesTmdbId.ToInt(), seasonNumber.Value, info.MetadataLanguage, null, cancellationToken)
|
if (tmdbResult != null)
|
||||||
.ConfigureAwait(false);
|
|
||||||
if (seasonResult == null)
|
|
||||||
{
|
{
|
||||||
this.Log($"Not found season from TMDB. {info.Name} seriesTmdbId: {seriesTmdbId} seasonNumber: {seasonNumber}");
|
return tmdbResult;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
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)
|
private IEnumerable<PersonInfo> GetPersons(TvSeason item)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue