jellyfin-plugin-metashark/Jellyfin.Plugin.MetaShark/Providers/SeasonProvider.cs

331 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Jellyfin.Plugin.MetaShark.Api;
using Jellyfin.Plugin.MetaShark.Core;
using Jellyfin.Plugin.MetaShark.Model;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TMDbLib.Objects.Find;
using TMDbLib.Objects.TvShows;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Http;
namespace Jellyfin.Plugin.MetaShark.Providers
{
public class SeasonProvider : BaseProvider, IRemoteMetadataProvider<Season, SeasonInfo>
{
public SeasonProvider(IHttpClientFactory httpClientFactory, ILoggerFactory loggerFactory, ILibraryManager libraryManager, IHttpContextAccessor httpContextAccessor, DoubanApi doubanApi, TmdbApi tmdbApi, OmdbApi omdbApi)
: base(httpClientFactory, loggerFactory.CreateLogger<SeasonProvider>(), libraryManager, httpContextAccessor, doubanApi, tmdbApi, omdbApi)
{
}
public string Name => Plugin.PluginName;
/// <inheritdoc />
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeasonInfo info, CancellationToken cancellationToken)
{
this.Log($"GetSeasonSearchResults of [name]: {info.Name}");
return await Task.FromResult(Enumerable.Empty<RemoteSearchResult>());
}
/// <inheritdoc />
public async Task<MetadataResult<Season>> GetMetadata(SeasonInfo info, CancellationToken cancellationToken)
{
var result = new MetadataResult<Season>();
info.SeriesProviderIds.TryGetValue(MetadataProvider.Tmdb.ToString(), out var seriesTmdbId);
info.SeriesProviderIds.TryGetValue(Plugin.ProviderId, out var metaSource);
info.SeriesProviderIds.TryGetValue(DoubanProviderId, out var sid);
var seasonNumber = info.IndexNumber; // S00/Season 00特典目录会为0
var seasonSid = info.GetProviderId(DoubanProviderId);
this.Log($"GetSeasonMetaData of [name]: {info.Name} number: {info.IndexNumber} seriesTmdbId: {seriesTmdbId} sid: {sid} metaSource: {metaSource}");
if (metaSource != MetaSource.Tmdb && !string.IsNullOrEmpty(sid))
{
// 从sereis获取正确名称季名称有时不对
var series = await this._doubanApi.GetMovieAsync(sid, cancellationToken).ConfigureAwait(false);
if (series == null)
{
return result;
}
var seriesName = series.Name;
// 没有季id但存在tmdbid尝试从tmdb获取对应季的年份信息用于从豆瓣搜索对应季数据
if (string.IsNullOrEmpty(seasonSid))
{
var seasonYear = 0;
if (!string.IsNullOrEmpty(seriesTmdbId) && (seasonNumber.HasValue && seasonNumber > 0))
{
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(seriesName) && seasonYear > 0)
{
seasonSid = await this.GuestDoubanSeasonByYearAsync(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<string, string> { { 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.LimitDirectorCelebrities.Take(this.config.MaxCastMembers).ToList().ForEach(c => result.AddPerson(new PersonInfo
{
Name = c.Name,
Type = c.RoleType,
Role = c.Role,
ImageUrl = c.Img,
ProviderIds = new Dictionary<string, string> { { DoubanProviderId, c.Id } },
}));
return result;
}
}
// tmdb有数据豆瓣找不到尝试获取tmdb的季数据
if (string.IsNullOrEmpty(seasonSid) && !string.IsNullOrWhiteSpace(seriesTmdbId) && (seasonNumber.HasValue && seasonNumber > 0))
{
var tmdbResult = await this.GetMetadataByTmdb(info, seriesTmdbId, seasonNumber.Value, cancellationToken).ConfigureAwait(false);
if (tmdbResult != null)
{
return tmdbResult;
}
}
// 从豆瓣获取不到季信息直接使用series信息还是不替换旧有信息好
result.Item = new Season
{
ProviderIds = new Dictionary<string, string> { { DoubanProviderId, sid } },
Name = series.Name,
OriginalTitle = series.OriginalName,
CommunityRating = series.Rating,
Overview = series.Intro,
ProductionYear = series.Year,
Genres = series.Genres,
PremiereDate = series.ScreenTime,
};
result.QueriedById = true;
result.HasMetadata = true;
return result;
}
// series使用TMDB元数据来源
// tmdb季级没有对应id只通过indexNumber区分
if (!string.IsNullOrWhiteSpace(seriesTmdbId) && (seasonNumber.HasValue && seasonNumber > 0))
{
var tmdbResult = await this.GetMetadataByTmdb(info, seriesTmdbId, seasonNumber.Value, cancellationToken).ConfigureAwait(false);
if (tmdbResult != null)
{
return tmdbResult;
}
}
// 季手工修正(先手工修改元数据,再刷新元数据->覆盖所有元数据),通过季名称重新搜索
// var guessName = Regex.Replace(info.Name, Pattern, " ");
// this.Log($"Try search season by name. original name: {info.Name} guess name: {guessName}");
// var guessSid = await this.GuestByDoubanAsync(info, cancellationToken).ConfigureAwait(false);
// if (!string.IsNullOrEmpty(guessSid))
// {
// var subject = await this._doubanApi.GetMovieAsync(guessSid, cancellationToken).ConfigureAwait(false);
// if (subject != null)
// {
// subject.Celebrities = await this._doubanApi.GetCelebritiesBySidAsync(guessSid, cancellationToken).ConfigureAwait(false);
// var movie = new Season
// {
// ProviderIds = new Dictionary<string, string> { { 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.Take(this.config.MaxCastMembers).ToList().ForEach(c => result.AddPerson(new PersonInfo
// {
// Name = c.Name,
// Type = c.RoleType,
// Role = c.Role,
// ImageUrl = c.Img,
// ProviderIds = new Dictionary<string, string> { { DoubanProviderId, c.Id } },
// }));
// 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)
{
// 演员
if (item.Credits?.Cast != null)
{
foreach (var actor in item.Credits.Cast.OrderBy(a => a.Order).Take(this.config.MaxCastMembers))
{
var personInfo = new PersonInfo
{
Name = actor.Name.Trim(),
Role = actor.Character,
Type = PersonType.Actor,
SortOrder = actor.Order,
};
if (!string.IsNullOrWhiteSpace(actor.ProfilePath))
{
personInfo.ImageUrl = this._tmdbApi.GetProfileUrl(actor.ProfilePath);
}
if (actor.Id > 0)
{
personInfo.SetProviderId(MetadataProvider.Tmdb, actor.Id.ToString(CultureInfo.InvariantCulture));
}
yield return personInfo;
}
}
// 导演
if (item.Credits?.Crew != null)
{
var keepTypes = new[]
{
PersonType.Director,
PersonType.Writer,
PersonType.Producer
};
foreach (var person in item.Credits.Crew)
{
// Normalize this
var type = MapCrewToPersonType(person);
if (!keepTypes.Contains(type, StringComparer.OrdinalIgnoreCase)
&& !keepTypes.Contains(person.Job ?? string.Empty, StringComparer.OrdinalIgnoreCase))
{
continue;
}
var personInfo = new PersonInfo
{
Name = person.Name.Trim(),
Role = person.Job,
Type = type
};
if (!string.IsNullOrWhiteSpace(person.ProfilePath))
{
personInfo.ImageUrl = this._tmdbApi.GetPosterUrl(person.ProfilePath);
}
if (person.Id > 0)
{
personInfo.SetProviderId(MetadataProvider.Tmdb, person.Id.ToString(CultureInfo.InvariantCulture));
}
yield return personInfo;
}
}
}
/// <inheritdoc />
public async Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
{
this.Log("GetImageResponse url: {0}", url);
return await this._httpClientFactory.CreateClient().GetAsync(new Uri(url), cancellationToken).ConfigureAwait(false);
}
private void Log(string? message, params object?[] args)
{
this._logger.LogInformation($"[MetaShark] {message}", args);
}
}
}