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

Tvdb v4 migration #93

Merged
merged 36 commits into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
8579648
Start migration to TVDB v4 api
scampower3 Aug 6, 2023
fba4de6
Incomplete migration
scampower3 Aug 6, 2023
ef76d65
Migration P2
scampower3 Aug 7, 2023
0e9d48a
Migration push Part 3. Used my fork of TVDbSharper
scampower3 Aug 7, 2023
10395cf
Migration Part 4
scampower3 Aug 7, 2023
6bfc16d
Bug fixes
scampower3 Aug 7, 2023
28347f9
Done Migration
scampower3 Aug 7, 2023
40fa75c
Removed redundant searchbyremoteid function
scampower3 Aug 7, 2023
0303f6b
Fixed Incorrect retrieval of episodeId
scampower3 Aug 8, 2023
bfb5eb9
Updated to use a more reliable way of converting ISO 639-2 to ISO 639-1
scampower3 Aug 8, 2023
ed769e8
Fixed TvdbSeriesProvider
scampower3 Aug 8, 2023
6299099
Fixed actors info and removed unneeded GetImages
scampower3 Aug 8, 2023
3e5d9b1
Removed unneeded api calls when getting season and series images.
scampower3 Aug 8, 2023
dd8d0c1
Changed to just convert from ISO 639-1 to ISO 639-2
scampower3 Aug 8, 2023
e0ddbaf
Switched to use GetCultureInfo instead of constructing
scampower3 Aug 8, 2023
f695718
TvdbMissingEpisodeProvider is now working some of the times
scampower3 Aug 8, 2023
b266443
Fixed TvdbMissingEpisodeProvider to work properly
scampower3 Aug 9, 2023
9394bc2
Remove some unneeded Api calls
scampower3 Aug 9, 2023
8e7aa3e
Added Content Rating retrieval
scampower3 Aug 11, 2023
8efb0d6
Fixed missing season number for absolute in GetEpisodeTvdbId
scampower3 Aug 11, 2023
3e43a2d
Added PR #91 fix
scampower3 Aug 13, 2023
2caf689
Added suggested changes
scampower3 Aug 16, 2023
6babd3b
Add TvdbCultureInfo. Dupe of iso6382.txt from Jellyfin repo
scampower3 Aug 18, 2023
172f2d3
Added Country info
scampower3 Aug 18, 2023
cf0930a
Preliminary switch to tvdb-sdk-csharp
scampower3 Dec 2, 2023
f9f7b7c
Fixed csproj grouping
scampower3 Dec 2, 2023
538bc73
Fixed login bug
scampower3 Dec 2, 2023
647ba15
Re-add check for AverageRuntime for null
scampower3 Dec 3, 2023
99ad0e2
Removed maxSeasonNumber in TvdbSeriesProvider
scampower3 Dec 3, 2023
ce438c9
Update to tvdb-sdk-csharp to 4.7.9
scampower3 Feb 11, 2024
f13b727
Change to Tvdb.Sdk.dll
scampower3 Feb 11, 2024
5ea6634
Fixes series.AirDays assignment
scampower3 Feb 11, 2024
d0c6d63
Comments
scampower3 Feb 11, 2024
3dafff0
Added Suggested changes and removed commented out code
scampower3 Feb 11, 2024
0e21d70
Removed IsValidEpisode function
scampower3 Feb 11, 2024
6d1a8f5
Refactor to use HttpClientFactory
crobibero Feb 11, 2024
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
16 changes: 12 additions & 4 deletions Jellyfin.Plugin.Tvdb/Configuration/PluginConfiguration.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using MediaBrowser.Model.Plugins;
using MediaBrowser.Model.Plugins;

scampower3 marked this conversation as resolved.
Show resolved Hide resolved
namespace Jellyfin.Plugin.Tvdb.Configuration
{
Expand All @@ -8,8 +8,16 @@ namespace Jellyfin.Plugin.Tvdb.Configuration
public class PluginConfiguration : BasePluginConfiguration
{
/// <summary>
/// Gets or sets the tvdb api key.
/// Gets the tvdb api key for project.
/// </summary>
public string ApiKey { get; set; } = "OG4V3YJ3FAP7FP2K";
public const string ProjectApiKey = "";

/// <summary>
/// Gets or sets the tvdb api key for user.
/// </summary>
/// <remarks>
/// This is the subscriber's pin.
/// </remarks>
public string ApiKey { get; set; } = string.Empty;
}
}
}
4 changes: 2 additions & 2 deletions Jellyfin.Plugin.Tvdb/Configuration/config.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>TheTVDB</title>
Expand All @@ -18,7 +18,7 @@ <h2 class="sectionTitle">TheTVDB Settings:</h2>
<label for="txtTvdbApiKey">TheTvdb API Key:</label>
<input type="text" id="txtTvdbApiKey" required="required" is="emby-input"/>
<div class="fieldDescription">
TheTVDB Api Key
TheTVDB Api Key from Subscriptions.
</div>
</div>
<br/>
Expand Down
6 changes: 5 additions & 1 deletion Jellyfin.Plugin.Tvdb/Jellyfin.Plugin.Tvdb.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@

<ItemGroup>
<None Remove="Configuration\config.html" />
<None Remove="countries.json" />
<None Remove="iso6392.txt" />
<EmbeddedResource Include="Configuration\config.html" />
<EmbeddedResource Include="countries.json" />
<EmbeddedResource Include="iso6392.txt" />
</ItemGroup>

<ItemGroup>
Expand All @@ -21,7 +25,7 @@
<PackageReference Include="Jellyfin.Common" Version="10.*-*" />
<PackageReference Include="Jellyfin.Model" Version="10.*-*" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="TvDbSharper" Version="3.2.2" />
<PackageReference Include="Tvdb.Sdk" Version="4.7.9" />
</ItemGroup>

<!-- Code Analyzers-->
Expand Down
15 changes: 6 additions & 9 deletions Jellyfin.Plugin.Tvdb/Providers/TvdbEpisodeImageProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using Microsoft.Extensions.Logging;
using TvDbSharper;
using TvDbSharper.Dto;
using Tvdb.Sdk;

namespace Jellyfin.Plugin.Tvdb.Providers
{
Expand Down Expand Up @@ -95,16 +94,16 @@
.GetEpisodesAsync(Convert.ToInt32(episodeTvdbId, CultureInfo.InvariantCulture), language, cancellationToken)
.ConfigureAwait(false);

var image = GetImageInfo(episodeResult.Data);
var image = GetImageInfo(episodeResult);
if (image != null)
{
imageResult.Add(image);
}
}
catch (TvDbServerException e)
catch (Exception e)
{
_logger.LogError(e, "Failed to retrieve episode images for series {TvDbId}:{Name}", series.GetProviderId(TvdbPlugin.ProviderId), series.Name);
}

Check notice

Code scanning / CodeQL

Generic catch clause Note

Generic catch clause.
}

return imageResult;
Expand All @@ -116,19 +115,17 @@
return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(new Uri(url), cancellationToken);
}

private RemoteImageInfo? GetImageInfo(EpisodeRecord episode)
private RemoteImageInfo? GetImageInfo(EpisodeExtendedRecord episode)
{
if (string.IsNullOrEmpty(episode.Filename))
if (string.IsNullOrEmpty(episode.Image))
{
return null;
}

return new RemoteImageInfo
{
Width = Convert.ToInt32(episode.ThumbWidth, CultureInfo.InvariantCulture),
Height = Convert.ToInt32(episode.ThumbHeight, CultureInfo.InvariantCulture),
ProviderName = Name,
Url = TvdbUtils.BannerUrl + episode.Filename,
Url = episode.Image,
Type = ImageType.Primary
};
}
Expand Down
156 changes: 70 additions & 86 deletions Jellyfin.Plugin.Tvdb/Providers/TvdbEpisodeProvider.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using Microsoft.Extensions.Logging;
using TvDbSharper;
using TvDbSharper.Dto;
using Tvdb.Sdk;

namespace Jellyfin.Plugin.Tvdb.Providers
{
Expand Down Expand Up @@ -124,12 +125,12 @@
results.Add(await GetEpisode(tempEpisodeInfo, cancellationToken).ConfigureAwait(false));
}

var result = CombineResults(info, results);
var result = CombineResults(results);

return result;
}

private MetadataResult<Episode> CombineResults(EpisodeInfo id, List<MetadataResult<Episode>> results)
private MetadataResult<Episode> CombineResults(List<MetadataResult<Episode>> results)
{
// Use first result as baseline
var result = results[0];
Expand Down Expand Up @@ -158,7 +159,7 @@
QueriedById = true
};

var seriesTvdbId = searchInfo.GetProviderId(TvdbPlugin.ProviderId);
var seriesTvdbId = searchInfo.SeriesProviderIds.FirstOrDefault(x => x.Key == TvdbPlugin.ProviderId).Value;
string? episodeTvdbId = null;
try
{
Expand All @@ -181,22 +182,22 @@
searchInfo.MetadataLanguage,
cancellationToken).ConfigureAwait(false);

result = MapEpisodeToResult(searchInfo, episodeResult.Data);
result = MapEpisodeToResult(searchInfo, episodeResult);
}
catch (TvDbServerException e)
catch (Exception e)
{
_logger.LogError(
e,
"Failed to retrieve episode with id {EpisodeTvDbId}, series id {SeriesTvdbId}:{Name}",
episodeTvdbId,
seriesTvdbId,
searchInfo.Name);
}

Check notice

Code scanning / CodeQL

Generic catch clause Note

Generic catch clause.

return result;
}

private static MetadataResult<Episode> MapEpisodeToResult(EpisodeInfo id, EpisodeRecord episode)
private static MetadataResult<Episode> MapEpisodeToResult(EpisodeInfo id, EpisodeExtendedRecord episode)
{
var result = new MetadataResult<Episode>
{
Expand All @@ -209,116 +210,99 @@
AirsBeforeEpisodeNumber = episode.AirsBeforeEpisode,
AirsAfterSeasonNumber = episode.AirsAfterSeason,
AirsBeforeSeasonNumber = episode.AirsBeforeSeason,
Name = episode.EpisodeName,
Overview = episode.Overview,
CommunityRating = (float?)episode.SiteRating,
OfficialRating = episode.ContentRating,
// Tvdb uses 3 letter code for language (prob ISO 639-2)
// Reverts to OriginalName if no translation is found
Name = episode.Translations.NameTranslations.FirstOrDefault(x => string.Equals(x.Language, TvdbUtils.NormalizeLanguageToTvdb(id.MetadataLanguage), StringComparison.OrdinalIgnoreCase))?.Name ?? episode.Name,
Overview = episode.Translations.OverviewTranslations?.FirstOrDefault(x => string.Equals(x.Language, TvdbUtils.NormalizeLanguageToTvdb(id.MetadataLanguage), StringComparison.OrdinalIgnoreCase))?.Overview ?? episode.Overview
}
};
result.ResetPeople();

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

if (string.Equals(id.SeriesDisplayOrder, "dvd", StringComparison.OrdinalIgnoreCase))
{
item.IndexNumber = Convert.ToInt32(episode.DvdEpisodeNumber ?? episode.AiredEpisodeNumber, CultureInfo.InvariantCulture);
item.ParentIndexNumber = episode.DvdSeason ?? episode.AiredSeason;
var dvdInfo = episode.Seasons.FirstOrDefault(x => string.Equals(x.Type.Name, "dvd", StringComparison.OrdinalIgnoreCase));
if (dvdInfo is null)
{
item.IndexNumber = episode.Number;
}
else
{
item.IndexNumber = Convert.ToInt32(dvdInfo.Number, CultureInfo.InvariantCulture);
}
Comment on lines +232 to +239

Check notice

Code scanning / CodeQL

Missed ternary opportunity Note

Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.

item.ParentIndexNumber = episode.SeasonNumber;
}
else if (string.Equals(id.SeriesDisplayOrder, "absolute", StringComparison.OrdinalIgnoreCase))
{
if (episode.AbsoluteNumber.GetValueOrDefault() != 0)
var absoluteInfo = episode.Seasons.FirstOrDefault(x => string.Equals(x.Type.Name, "absolute", StringComparison.OrdinalIgnoreCase));
if (absoluteInfo is not null)
{
item.IndexNumber = episode.AbsoluteNumber;
item.IndexNumber = Convert.ToInt32(absoluteInfo.Number, CultureInfo.InvariantCulture);
}
}
else if (episode.AiredEpisodeNumber.HasValue)
{
item.IndexNumber = episode.AiredEpisodeNumber;
}
else if (episode.AiredSeason.HasValue)
else
{
item.ParentIndexNumber = episode.AiredSeason;
item.IndexNumber = episode.Number;
item.ParentIndexNumber = episode.SeasonNumber;
}

if (DateTime.TryParse(episode.FirstAired, out var date))
if (DateTime.TryParse(episode.Aired, out var date))
{
// dates from tvdb are UTC but without offset or Z
item.PremiereDate = date;
item.ProductionYear = date.Year;
}

foreach (var director in episode.Directors)
{
result.AddPerson(new PersonInfo
{
Name = director,
Type = PersonType.Director
});
}

// GuestStars is a weird list of names and roles
// Example:
// 1: Some Actor (Role1
// 2: Role2
// 3: Role3)
// 4: Another Actor (Role1
// ...
for (var i = 0; i < episode.GuestStars.Length; ++i)
if (episode.Characters is not null)
{
var currentActor = episode.GuestStars[i];
var roleStartIndex = currentActor.IndexOf('(', StringComparison.Ordinal);

if (roleStartIndex == -1)
for (var i = 0; i < episode.Characters.Count; ++i)
{
result.AddPerson(new PersonInfo
var currentActor = episode.Characters[i];
if (string.Equals(currentActor.PeopleType, "Actor", StringComparison.OrdinalIgnoreCase))
{
Type = PersonType.GuestStar,
Name = currentActor,
Role = string.Empty
});
continue;
}

var roles = new List<string> { currentActor.Substring(roleStartIndex + 1) };

// Fetch all roles
for (var j = i + 1; j < episode.GuestStars.Length; ++j)
{
var currentRole = episode.GuestStars[j];
var roleEndIndex = currentRole.Contains(')', StringComparison.Ordinal);

if (!roleEndIndex)
result.AddPerson(new PersonInfo
{
Type = PersonType.Actor,
Name = currentActor.PersonName,
Role = currentActor.Name
});
}
else if (string.Equals(currentActor.PeopleType, "Director", StringComparison.OrdinalIgnoreCase))
{
roles.Add(currentRole);
continue;
result.AddPerson(new PersonInfo
{
Type = PersonType.Director,
Name = currentActor.PersonName
});
}
else if (string.Equals(currentActor.PeopleType, "Writer", StringComparison.OrdinalIgnoreCase))
{
result.AddPerson(new PersonInfo
{
Type = PersonType.Writer,
Name = currentActor.PersonName
});
}
else if (string.Equals(currentActor.PeopleType, "Guest Star", StringComparison.OrdinalIgnoreCase))
{
result.AddPerson(new PersonInfo
{
Type = PersonType.GuestStar,
Name = currentActor.PersonName,
Role = currentActor.Name
});
}

roles.Add(currentRole.TrimEnd(')'));
// Update the outer index (keep in mind it adds 1 after the iteration)
i = j;
break;
}

result.AddPerson(new PersonInfo
{
Type = PersonType.GuestStar,
Name = currentActor.Substring(0, roleStartIndex).Trim(),
Role = string.Join(", ", roles)
});
}

foreach (var writer in episode.Writers)
{
result.AddPerson(new PersonInfo
{
Name = writer,
Type = PersonType.Writer
});
}

result.ResultLanguage = episode.Language.EpisodeName;
return result;
}

Expand Down
Loading