Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements and fixes tvdb sdk 4.7.9.1 + PR #112 #115

Merged
merged 3 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions Jellyfin.Plugin.Tvdb/ProviderIdsExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using System;
using System.Globalization;

using MediaBrowser.Model.Entities;

namespace Jellyfin.Plugin.Tvdb;

internal static class ProviderIdsExtensions
{
/// <summary>
/// Check whether an item includes an entry for any supported provider IDs.
/// </summary>
/// <param name="item">The <see cref="IHasProviderIds"/>.</param>
/// <returns>True, if <paramref name="item"/> contains any supported provider IDs.</returns>
internal static bool IsSupported(this IHasProviderIds? item)
{
return HasProviderId(item, MetadataProvider.Tvdb)
|| HasProviderId(item, MetadataProvider.Imdb)
|| HasProviderId(item, MetadataProvider.Zap2It);
}

/// <summary>
/// Get the TvDB id stored within the item.
/// </summary>
/// <param name="item">The <see cref="IHasProviderIds"/> item to get the TvDB id from.</param>
/// <returns>The Id, or 0.</returns>
public static int GetTvdbId(this IHasProviderIds item)
=> Convert.ToInt32(item.GetProviderId(TvdbPlugin.ProviderId), CultureInfo.InvariantCulture);

/// <inheritdoc cref="SetTvdbId(IHasProviderIds, string?)" />
public static void SetTvdbId(this IHasProviderIds item, long? value)
=> SetTvdbId(item, value.HasValue && value > 0 ? value.Value.ToString(CultureInfo.InvariantCulture) : null);

/// <summary>
/// Set the TvDB id in the item, if provided <paramref name="value"/> is not <see langword="null"/> or white space.
/// </summary>
/// <param name="item">>The <see cref="IHasProviderIds"/> to set the TvDB id.</param>
/// <param name="value">TvDB id to set.</param>
/// <returns><see langword="true"/> if value was set.</returns>
public static bool SetTvdbId(this IHasProviderIds item, string? value)
=> SetProviderIdIfHasValue(item, TvdbPlugin.ProviderId, value);

/// <inheritdoc cref="SetProviderIdIfHasValue(IHasProviderIds, string, string?)"/>
public static bool SetProviderIdIfHasValue(this IHasProviderIds item, MetadataProvider provider, string? value)
=> SetProviderIdIfHasValue(item, provider.ToString(), value);

/// <summary>
/// Set the provider id in the item, if provided <paramref name="value"/> is not <see langword="null"/> or white space.
/// </summary>
/// <param name="item">>The <see cref="IHasProviderIds"/> to set the TvDB id.</param>
/// <param name="name">Provider name.</param>
/// <param name="value">Provider id to set.</param>
/// <returns><see langword="true"/> if value was set.</returns>
public static bool SetProviderIdIfHasValue(this IHasProviderIds item, string name, string? value)
{
if (!HasValue(value))
{
return false;
}

item.SetProviderId(name, value);
return true;
}

/// <summary>
/// Checks whether the item has TvDB Id stored.
/// </summary>
/// <param name="item">The <see cref="IHasProviderIds"/> item.</param>
/// <returns>True, if item has TvDB Id stored.</returns>
public static bool HasTvdbId(this IHasProviderIds? item)
=> HasTvdbId(item, out var value);

/// <inheritdoc cref="HasProviderId(IHasProviderIds?, string, out string?)"/>
public static bool HasTvdbId(this IHasProviderIds? item, out string? value)
=> HasProviderId(item, TvdbPlugin.ProviderId, out value);

/// <inheritdoc cref="HasProviderId(IHasProviderIds?, string)"/>
public static bool HasProviderId(this IHasProviderIds? item, MetadataProvider provider)
=> HasProviderId(item, provider, out var value);

/// <inheritdoc cref="HasProviderId(IHasProviderIds?, string, out string?)"/>
public static bool HasProviderId(this IHasProviderIds? item, MetadataProvider provider, out string? value)
=> HasProviderId(item, provider.ToString(), out value);

/// <summary>
/// Checks whether the item has provider id stored.
/// </summary>
/// <param name="item">The <see cref="IHasProviderIds"/> item.</param>
/// <param name="name">Provider.</param>
/// <returns>True, if item has provider id stored.</returns>
public static bool HasProviderId(this IHasProviderIds? item, string name)
=> HasProviderId(item, name, out var value);

/// <summary>
/// Checks whether the item has provider id stored.
/// </summary>
/// <param name="item">The <see cref="IHasProviderIds"/> item.</param>
/// <param name="name">Provider.</param>
/// <param name="value">The current provider id value.</param>
/// <returns>True, if item has provider id stored.</returns>
public static bool HasProviderId(this IHasProviderIds? item, string name, out string? value)
{
value = null;
var result = item is { }
&& item.TryGetProviderId(name, out value)
&& HasValue(value);

value = result ? value : null;
return result;
}

private static bool HasValue(string? value)
=> !string.IsNullOrWhiteSpace(value);
}
6 changes: 3 additions & 3 deletions Jellyfin.Plugin.Tvdb/Providers/TvdbEpisodeImageProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, Cancell
var series = episode.Series;
var imageResult = new List<RemoteImageInfo>();
var language = item.GetPreferredMetadataLanguage();
if (series != null && TvdbSeriesProvider.IsValidSeries(series.ProviderIds))
if (series.IsSupported())
{
// Process images
try
Expand All @@ -85,7 +85,7 @@ public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, Cancell
"Episode {SeasonNumber}x{EpisodeNumber} not found for series {SeriesTvdbId}:{Name}",
episode.ParentIndexNumber,
episode.IndexNumber,
series.GetProviderId(TvdbPlugin.ProviderId),
series.GetTvdbId(),
series.Name);
return imageResult;
}
Expand All @@ -99,7 +99,7 @@ await _tvdbClientManager
}
catch (Exception e)
{
_logger.LogError(e, "Failed to retrieve episode images for series {TvDbId}:{Name}", series.GetProviderId(TvdbPlugin.ProviderId), series.Name);
_logger.LogError(e, "Failed to retrieve episode images for series {TvDbId}:{Name}", series.GetTvdbId(), series.Name);
}
}

Expand Down
46 changes: 18 additions & 28 deletions Jellyfin.Plugin.Tvdb/Providers/TvdbEpisodeProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(EpisodeInfo

// Either an episode number or date must be provided; and the dictionary of provider ids must be valid
if ((searchInfo.IndexNumber == null && searchInfo.PremiereDate == null)
|| !TvdbSeriesProvider.IsValidSeries(searchInfo.SeriesProviderIds))
|| !searchInfo.IsSupported())
{
return list;
}
Expand Down Expand Up @@ -82,32 +82,26 @@ public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(EpisodeInfo
/// <inheritdoc />
public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo info, CancellationToken cancellationToken)
{
var result = new MetadataResult<Episode>
{
QueriedById = true
};

if (TvdbSeriesProvider.IsValidSeries(info.SeriesProviderIds) &&
(info.IndexNumber.HasValue || info.PremiereDate.HasValue))
if ((info.IndexNumber == null && info.PremiereDate == null)
|| !info.IsSupported())
{
// Check for multiple episodes per file, if not run one query.
if (info.IndexNumberEnd.HasValue)
_logger.LogDebug("No series identity found for {EpisodeName}", info.Name);
return new MetadataResult<Episode>
{
_logger.LogDebug("Multiple episodes found in {Path}", info.Path);
QueriedById = true
};
}

result = await GetCombinedEpisode(info, cancellationToken).ConfigureAwait(false);
}
else
{
result = await GetEpisode(info, cancellationToken).ConfigureAwait(false);
}
// Check for multiple episodes per file, if not run one query.
if (info.IndexNumberEnd.HasValue)
{
_logger.LogDebug("Multiple episodes found in {Path}", info.Path);
return await GetCombinedEpisode(info, cancellationToken).ConfigureAwait(false);
}
else
{
_logger.LogDebug("No series identity found for {EpisodeName}", info.Name);
return await GetEpisode(info, cancellationToken).ConfigureAwait(false);
}

return result;
}

private async Task<MetadataResult<Episode>> GetCombinedEpisode(EpisodeInfo info, CancellationToken cancellationToken)
Expand Down Expand Up @@ -159,7 +153,6 @@ private async Task<MetadataResult<Episode>> GetEpisode(EpisodeInfo searchInfo, C
QueriedById = true
};

var seriesTvdbId = searchInfo.SeriesProviderIds.FirstOrDefault(x => x.Key == TvdbPlugin.ProviderId).Value;
string? episodeTvdbId = null;
try
{
Expand All @@ -172,7 +165,7 @@ private async Task<MetadataResult<Episode>> GetEpisode(EpisodeInfo searchInfo, C
"Episode S{Season:00}E{Episode:00} not found for series {SeriesTvdbId}:{Name}",
searchInfo.ParentIndexNumber,
searchInfo.IndexNumber,
seriesTvdbId,
searchInfo.GetTvdbId(),
searchInfo.Name);
return result;
}
Expand All @@ -190,7 +183,7 @@ private async Task<MetadataResult<Episode>> GetEpisode(EpisodeInfo searchInfo, C
e,
"Failed to retrieve episode with id {EpisodeTvDbId}, series id {SeriesTvdbId}:{Name}",
episodeTvdbId,
seriesTvdbId,
searchInfo.GetTvdbId(),
searchInfo.Name);
}

Expand Down Expand Up @@ -220,12 +213,9 @@ private static MetadataResult<Episode> MapEpisodeToResult(EpisodeInfo id, Episod
result.ResetPeople();

var item = result.Item;
item.SetProviderId(TvdbPlugin.ProviderId, episode.Id.GetValueOrDefault().ToString(CultureInfo.InvariantCulture));
item.SetTvdbId(episode.Id);
var imdbID = episode.RemoteIds.FirstOrDefault(x => string.Equals(x.SourceName, "IMDB", StringComparison.OrdinalIgnoreCase))?.Id;
if (!string.IsNullOrEmpty(imdbID))
{
item.SetProviderId(MetadataProvider.Imdb, imdbID);
}
item.SetProviderIdIfHasValue(MetadataProvider.Imdb, imdbID);

if (string.Equals(id.SeriesDisplayOrder, "dvd", StringComparison.OrdinalIgnoreCase))
{
Expand Down
30 changes: 16 additions & 14 deletions Jellyfin.Plugin.Tvdb/Providers/TvdbMissingEpisodeProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ private static bool EpisodeExists(EpisodeBaseRecord episodeRecord, IReadOnlyList

private static bool EpisodeEquals(Episode episode, EpisodeBaseRecord otherEpisodeRecord)
{
return episode.ContainsEpisodeNumber(otherEpisodeRecord.Number.GetValueOrDefault())
return otherEpisodeRecord.Number.HasValue
&& episode.ContainsEpisodeNumber(otherEpisodeRecord.Number.Value)
&& episode.ParentIndexNumber == otherEpisodeRecord.SeasonNumber;
}

Expand Down Expand Up @@ -155,13 +156,13 @@ private void OnProviderManagerRefreshComplete(object? sender, GenericEventArgs<B

private async Task HandleSeries(Series series)
{
if (!series.TryGetProviderId(MetadataProvider.Tvdb.ToString(), out var tvdbIdTxt))
if (!series.HasTvdbId())
{
_logger.LogDebug("No TVDB Id available.");
return;
}

var tvdbId = Convert.ToInt32(tvdbIdTxt, CultureInfo.InvariantCulture);
var tvdbId = series.GetTvdbId();

var children = series.GetRecursiveChildren();
var existingSeasons = new List<Season>();
Expand Down Expand Up @@ -191,7 +192,8 @@ private async Task HandleSeries(Series series)

var allEpisodes = await GetAllEpisodes(tvdbId, series.GetPreferredMetadataLanguage()).ConfigureAwait(false);
var allSeasons = allEpisodes
.Select(ep => ep.SeasonNumber.GetValueOrDefault())
.Where(ep => ep.SeasonNumber.HasValue)
.Select(ep => ep.SeasonNumber!.Value)
.Distinct()
.ToList();

Expand All @@ -202,14 +204,14 @@ private async Task HandleSeries(Series series)

private async Task HandleSeason(Season season)
{
if (season.Series == null
|| !season.Series.TryGetProviderId(MetadataProvider.Tvdb.ToString(), out var tvdbIdTxt))
var series = season.Series;
if (series.HasTvdbId())
{
_logger.LogDebug("No TVDB Id available.");
return;
}

var tvdbId = Convert.ToInt32(tvdbIdTxt, CultureInfo.InvariantCulture);
var tvdbId = series.GetTvdbId();
var allEpisodes = await GetAllEpisodes(tvdbId, season.GetPreferredMetadataLanguage())
.ConfigureAwait(false);

Expand Down Expand Up @@ -321,14 +323,13 @@ private void OnLibraryManagerItemRemoved(object? sender, ItemChangeEventArgs ite
}
else if (itemChangeEventArgs.Item is Episode episode)
{
if (episode.Series == null
|| !episode.Series.TryGetProviderId(MetadataProvider.Tvdb.ToString(), out var tvdbIdTxt))
if (!episode.Series.HasTvdbId())
{
_logger.LogDebug("No TVDB Id available.");
return;
}

var tvdbId = Convert.ToInt32(tvdbIdTxt, CultureInfo.InvariantCulture);
var tvdbId = episode.Series.GetTvdbId();

var episodeRecords = GetAllEpisodes(tvdbId, episode.GetPreferredMetadataLanguage()).GetAwaiter().GetResult();

Expand Down Expand Up @@ -385,7 +386,8 @@ private void AddMissingEpisodes(
var episodeRecord = allEpisodeRecords[i];

// skip if it exists already
if (existingEpisodes.TryGetValue(episodeRecord.SeasonNumber.GetValueOrDefault(), out var episodes)
if (episodeRecord.SeasonNumber.HasValue
&& existingEpisodes.TryGetValue(episodeRecord.SeasonNumber.Value, out var episodes)
&& EpisodeExists(episodeRecord, episodes))
{
_logger.LogDebug("{MethodName}: Skip, already existing S{Season:00}E{Episode:00}", nameof(AddMissingEpisodes), episodeRecord.SeasonNumber, episodeRecord.Number);
Expand Down Expand Up @@ -435,7 +437,7 @@ private Season AddVirtualSeason(int season, Series series)

private void AddVirtualEpisode(EpisodeBaseRecord? episode, Season? season)
{
if (episode == null || season == null)
if (episode?.SeasonNumber == null || season == null)
{
return;
}
Expand All @@ -447,7 +449,7 @@ private void AddVirtualEpisode(EpisodeBaseRecord? episode, Season? season)
IndexNumber = episode.Number,
ParentIndexNumber = episode.SeasonNumber,
Id = _libraryManager.GetNewItemId(
season.Series.Id + episode.SeasonNumber.GetValueOrDefault().ToString(CultureInfo.InvariantCulture) + "Episode " + episode.Number,
$"{season.Series.Id}{episode.SeasonNumber}Episode {episode.Number}",
typeof(Episode)),
IsVirtualItem = true,
SeasonId = season.Id,
Expand All @@ -467,7 +469,7 @@ private void AddVirtualEpisode(EpisodeBaseRecord? episode, Season? season)
}

newEpisode.PresentationUniqueKey = newEpisode.GetPresentationUniqueKey();
newEpisode.SetProviderId(MetadataProvider.Tvdb, episode.Id.GetValueOrDefault().ToString(CultureInfo.InvariantCulture));
newEpisode.SetTvdbId(episode.Id);

_logger.LogDebug(
"Creating virtual episode {SeriesName} S{Season:00}E{Episode:00}",
Expand Down
4 changes: 2 additions & 2 deletions Jellyfin.Plugin.Tvdb/Providers/TvdbPersonImageProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, Cancell
EnableImages = false
}
}).Cast<Series>()
.Where(i => TvdbSeriesProvider.IsValidSeries(i.ProviderIds))
.Where(i => i.IsSupported())
.ToList();

var infos = (await Task.WhenAll(seriesWithPerson.Select(async i =>
Expand All @@ -93,7 +93,7 @@ public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken

private async Task<RemoteImageInfo?> GetImageFromSeriesData(Series series, string personName, CancellationToken cancellationToken)
{
var tvdbId = Convert.ToInt32(series.GetProviderId(TvdbPlugin.ProviderId), CultureInfo.InvariantCulture);
var tvdbId = series.GetTvdbId();

try
{
Expand Down
9 changes: 5 additions & 4 deletions Jellyfin.Plugin.Tvdb/Providers/TvdbSeasonImageProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, Cancell
var season = (Season)item;
var series = season.Series;

if (series == null || !season.IndexNumber.HasValue || !TvdbSeriesProvider.IsValidSeries(series.ProviderIds))
if (!series.IsSupported() || season.IndexNumber is null)
{
return Enumerable.Empty<RemoteImageInfo>();
}
Expand All @@ -83,9 +83,10 @@ public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, Cancell
.ConfigureAwait(false);
var seasonArtworkTypeLookup = artworkTypes
.Where(t => string.Equals(t.RecordType, "season", StringComparison.OrdinalIgnoreCase))
.ToDictionary(t => t.Id);
.Where(t => t.Id.HasValue)
.ToDictionary(t => t.Id!.Value);

var seriesTvdbId = Convert.ToInt32(series.GetProviderId(TvdbPlugin.ProviderId), CultureInfo.InvariantCulture);
var seriesTvdbId = series.GetTvdbId();
var seasonNumber = season.IndexNumber.Value;

var seasonArtworks = await GetSeasonArtworks(seriesTvdbId, seasonNumber, cancellationToken)
Expand All @@ -94,7 +95,7 @@ public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, Cancell
var remoteImages = new List<RemoteImageInfo>();
foreach (var artwork in seasonArtworks)
{
var artworkType = seasonArtworkTypeLookup.GetValueOrDefault(artwork.Type);
var artworkType = artwork.Type is null ? null : seasonArtworkTypeLookup.GetValueOrDefault(artwork.Type!.Value);
var imageType = artworkType.GetImageType();
var artworkLanguage = artwork.Language is null ? null : languageLookup.GetValueOrDefault(artwork.Language);

Expand Down
Loading