Skip to content

Commit

Permalink
Merge pull request #115 from BobSilent/improvements-tvdb-sdk-4.7.9.1
Browse files Browse the repository at this point in the history
Improvements and fixes tvdb sdk 4.7.9.1 + PR #112
  • Loading branch information
Shadowghost authored Feb 29, 2024
2 parents dbe5456 + 500b855 commit 1e7864f
Show file tree
Hide file tree
Showing 10 changed files with 248 additions and 184 deletions.
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

0 comments on commit 1e7864f

Please sign in to comment.