aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Providers/Plugins/Tmdb
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Providers/Plugins/Tmdb')
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs15
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html34
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs60
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs6
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs107
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs82
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs3
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs62
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TmdbExternalUrlProvider.cs98
-rw-r--r--MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs2
14 files changed, 379 insertions, 101 deletions
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs
index d453a4ff44..2076589d34 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/BoxSets/TmdbBoxSetExternalId.cs
@@ -21,9 +21,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets
public ExternalIdMediaType? Type => ExternalIdMediaType.BoxSet;
/// <inheritdoc />
- public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "collection/{0}";
-
- /// <inheritdoc />
public bool Supports(IHasProviderIds item)
{
return item is Movie || item is MusicVideo || item is Trailer;
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs b/MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs
index 99b759ae29..f11b1d95aa 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Configuration/PluginConfiguration.cs
@@ -39,6 +39,21 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
public int MaxCastMembers { get; set; } = 15;
/// <summary>
+ /// Gets or sets a value indicating the maximum number of crew members to fetch for an item.
+ /// </summary>
+ public int MaxCrewMembers { get; set; } = 15;
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to hide cast members without profile images.
+ /// </summary>
+ public bool HideMissingCastMembers { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to hide crew members without profile images.
+ /// </summary>
+ public bool HideMissingCrewMembers { get; set; }
+
+ /// <summary>
/// Gets or sets a value indicating the poster image size to fetch.
/// </summary>
public string? PosterSize { get; set; }
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html b/MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html
index f3c24e7b42..89d380ec1f 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Configuration/config.html
@@ -25,9 +25,24 @@
<input is="emby-checkbox" type="checkbox" id="importSeasonName" />
<span>Import season name from metadata fetched for series.</span>
</label>
- <div class="inputContainer">
- <input is="emby-input" type="number" id="maxCastMembers" pattern="[0-9]*" required min="0" max="1000" label="Max Cast Members" />
- <div class="fieldDescription">The maximum number of cast members to fetch for an item.</div>
+ <div class="verticalSection">
+ <h2>Cast & Crew Settings</h2>
+ <div class="inputContainer">
+ <input is="emby-input" type="number" id="maxCastMembers" pattern="[0-9]*" required min="0" max="1000" label="Max Cast Members" />
+ <div class="fieldDescription">The maximum number of cast members to fetch for an item.</div>
+ </div>
+ <div class="inputContainer">
+ <input is="emby-input" type="number" id="maxCrewMembers" pattern="[0-9]*" required min="0" max="1000" label="Max Crew Members" />
+ <div class="fieldDescription">The maximum number of crew members to fetch for an item.</div>
+ </div>
+ <label class="checkboxContainer">
+ <input is="emby-checkbox" type="checkbox" id="hideMissingCastMembers" />
+ <span>Hide cast members without profile images.</span>
+ </label>
+ <label class="checkboxContainer">
+ <input is="emby-checkbox" type="checkbox" id="hideMissingCrewMembers" />
+ <span>Hide crew members without profile images.</span>
+ </label>
</div>
<div class="verticalSection verticalSection-extrabottompadding">
<h2>Image Scaling</h2>
@@ -129,6 +144,8 @@
document.querySelector('#excludeTagsSeries').checked = config.ExcludeTagsSeries;
document.querySelector('#excludeTagsMovies').checked = config.ExcludeTagsMovies;
document.querySelector('#importSeasonName').checked = config.ImportSeasonName;
+ document.querySelector('#hideMissingCastMembers').checked = config.HideMissingCastMembers;
+ document.querySelector('#hideMissingCrewMembers').checked = config.HideMissingCrewMembers;
var maxCastMembers = document.querySelector('#maxCastMembers');
maxCastMembers.value = config.MaxCastMembers;
@@ -137,12 +154,18 @@
cancelable: false
}));
+ var maxCrewMembers = document.querySelector('#maxCrewMembers');
+ maxCrewMembers.value = config.MaxCrewMembers;
+ maxCrewMembers.dispatchEvent(new Event('change', {
+ bubbles: true,
+ cancelable: false
+ }));
+
pluginConfig = config;
configureImageScaling();
});
});
-
document.querySelector('.configForm')
.addEventListener('submit', function (e) {
Dashboard.showLoadingMsg();
@@ -153,6 +176,9 @@
config.ExcludeTagsMovies = document.querySelector('#excludeTagsMovies').checked;
config.ImportSeasonName = document.querySelector('#importSeasonName').checked;
config.MaxCastMembers = document.querySelector('#maxCastMembers').value;
+ config.MaxCrewMembers = document.querySelector('#maxCrewMembers').value;
+ config.HideMissingCastMembers = document.querySelector('#hideMissingCastMembers').checked;
+ config.HideMissingCrewMembers = document.querySelector('#hideMissingCrewMembers').checked;
config.PosterSize = document.querySelector('#selectPosterSize').value;
config.BackdropSize = document.querySelector('#selectBackdropSize').value;
config.LogoSize = document.querySelector('#selectLogoSize').value;
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs
index 6d6032e8f6..9a1d872ec2 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieExternalId.cs
@@ -21,9 +21,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
public ExternalIdMediaType? Type => ExternalIdMediaType.Movie;
/// <inheritdoc />
- public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "movie/{0}";
-
- /// <inheritdoc />
public bool Supports(IHasProviderIds item)
{
// Supports images for tv movies
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
index eef08b251f..2f8cb68ef5 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
@@ -144,6 +144,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
{
var tmdbId = info.GetProviderId(MetadataProvider.Tmdb);
var imdbId = info.GetProviderId(MetadataProvider.Imdb);
+ var config = Plugin.Instance.Configuration;
if (string.IsNullOrEmpty(tmdbId) && string.IsNullOrEmpty(imdbId))
{
@@ -234,7 +235,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
var genres = movieResult.Genres;
- foreach (var genre in genres.Select(g => g.Name))
+ foreach (var genre in genres.Select(g => g.Name).Trimmed())
{
movie.AddGenre(genre);
}
@@ -249,12 +250,26 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
if (movieResult.Credits?.Cast is not null)
{
- foreach (var actor in movieResult.Credits.Cast.OrderBy(a => a.Order).Take(Plugin.Instance.Configuration.MaxCastMembers))
+ var castQuery = movieResult.Credits.Cast.AsEnumerable();
+
+ if (config.HideMissingCastMembers)
{
+ castQuery = castQuery.Where(a => !string.IsNullOrEmpty(a.ProfilePath));
+ }
+
+ castQuery = castQuery.OrderBy(a => a.Order).Take(config.MaxCastMembers);
+
+ foreach (var actor in castQuery)
+ {
+ if (string.IsNullOrWhiteSpace(actor.Name))
+ {
+ continue;
+ }
+
var personInfo = new PersonInfo
{
Name = actor.Name.Trim(),
- Role = actor.Character,
+ Role = actor.Character?.Trim() ?? string.Empty,
Type = PersonKind.Actor,
SortOrder = actor.Order
};
@@ -275,32 +290,47 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
if (movieResult.Credits?.Crew is not null)
{
- foreach (var person in movieResult.Credits.Crew)
+ var crewQuery = movieResult.Credits.Crew
+ .Select(crewMember => new
+ {
+ CrewMember = crewMember,
+ PersonType = TmdbUtils.MapCrewToPersonType(crewMember)
+ })
+ .Where(entry =>
+ TmdbUtils.WantedCrewKinds.Contains(entry.PersonType) ||
+ TmdbUtils.WantedCrewTypes.Contains(entry.CrewMember.Job ?? string.Empty, StringComparison.OrdinalIgnoreCase));
+
+ if (config.HideMissingCrewMembers)
+ {
+ crewQuery = crewQuery.Where(entry => !string.IsNullOrEmpty(entry.CrewMember.ProfilePath));
+ }
+
+ crewQuery = crewQuery.Take(config.MaxCrewMembers);
+
+ foreach (var entry in crewQuery)
{
- // Normalize this
- var type = TmdbUtils.MapCrewToPersonType(person);
+ var crewMember = entry.CrewMember;
- if (!TmdbUtils.WantedCrewKinds.Contains(type)
- && !TmdbUtils.WantedCrewTypes.Contains(person.Job ?? string.Empty, StringComparison.OrdinalIgnoreCase))
+ if (string.IsNullOrWhiteSpace(crewMember.Name))
{
continue;
}
var personInfo = new PersonInfo
{
- Name = person.Name.Trim(),
- Role = person.Job,
- Type = type
+ Name = crewMember.Name.Trim(),
+ Role = crewMember.Job?.Trim() ?? string.Empty,
+ Type = entry.PersonType
};
- if (!string.IsNullOrWhiteSpace(person.ProfilePath))
+ if (!string.IsNullOrWhiteSpace(crewMember.ProfilePath))
{
- personInfo.ImageUrl = _tmdbClientManager.GetProfileUrl(person.ProfilePath);
+ personInfo.ImageUrl = _tmdbClientManager.GetProfileUrl(crewMember.ProfilePath);
}
- if (person.Id > 0)
+ if (crewMember.Id > 0)
{
- personInfo.SetProviderId(MetadataProvider.Tmdb, person.Id.ToString(CultureInfo.InvariantCulture));
+ personInfo.SetProviderId(MetadataProvider.Tmdb, crewMember.Id.ToString(CultureInfo.InvariantCulture));
}
metadataResult.AddPerson(personInfo);
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs
index d26a70028c..2c0787b15d 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonExternalId.cs
@@ -20,9 +20,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
public ExternalIdMediaType? Type => ExternalIdMediaType.Person;
/// <inheritdoc />
- public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "person/{0}";
-
- /// <inheritdoc />
public bool Supports(IHasProviderIds item)
{
return item is Person;
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs
index d1fec7cb13..7de0e430f2 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeImageProvider.cs
@@ -63,10 +63,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
return Enumerable.Empty<RemoteImageInfo>();
}
- var seasonNumber = episode.ParentIndexNumber;
+ var seasonNumber = episode.ParentIndexNumber ?? 1;
var episodeNumber = episode.IndexNumber;
- if (!seasonNumber.HasValue || !episodeNumber.HasValue)
+ if (!episodeNumber.HasValue)
{
return Enumerable.Empty<RemoteImageInfo>();
}
@@ -75,7 +75,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
// TODO use image languages if All Languages isn't toggled, but there's currently no way to get that value in here
var episodeResult = await _tmdbClientManager
- .GetEpisodeAsync(seriesTmdbId, seasonNumber.Value, episodeNumber.Value, series.DisplayOrder, null, null, cancellationToken)
+ .GetEpisodeAsync(seriesTmdbId, seasonNumber, episodeNumber.Value, series.DisplayOrder, null, null, cancellationToken)
.ConfigureAwait(false);
var stills = episodeResult?.Images?.Stills;
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs
index e628abde55..7d0900cfda 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbEpisodeProvider.cs
@@ -47,7 +47,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken)
{
// The search query must either provide an episode number or date
- if (!searchInfo.IndexNumber.HasValue || !searchInfo.ParentIndexNumber.HasValue)
+ if (!searchInfo.IndexNumber.HasValue)
{
return Enumerable.Empty<RemoteSearchResult>();
}
@@ -81,6 +81,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo info, CancellationToken cancellationToken)
{
var metadataResult = new MetadataResult<Episode>();
+ var config = Plugin.Instance.Configuration;
// Allowing this will dramatically increase scan times
if (info.IsMissingEpisode)
@@ -96,10 +97,10 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
return metadataResult;
}
- var seasonNumber = info.ParentIndexNumber;
+ var seasonNumber = info.ParentIndexNumber ?? 1;
var episodeNumber = info.IndexNumber;
- if (!seasonNumber.HasValue || !episodeNumber.HasValue)
+ if (!episodeNumber.HasValue)
{
return metadataResult;
}
@@ -112,7 +113,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
List<TvEpisode>? result = null;
for (int? episode = startindex; episode <= endindex; episode++)
{
- var episodeInfo = await _tmdbClientManager.GetEpisodeAsync(seriesTmdbId, seasonNumber.Value, episode.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken).ConfigureAwait(false);
+ var episodeInfo = await _tmdbClientManager.GetEpisodeAsync(seriesTmdbId, seasonNumber, episode.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken).ConfigureAwait(false);
if (episodeInfo is not null)
{
(result ??= new List<TvEpisode>()).Add(episodeInfo);
@@ -156,7 +157,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
else
{
episodeResult = await _tmdbClientManager
- .GetEpisodeAsync(seriesTmdbId, seasonNumber.Value, episodeNumber.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken)
+ .GetEpisodeAsync(seriesTmdbId, seasonNumber, episodeNumber.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken)
.ConfigureAwait(false);
}
@@ -206,52 +207,106 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
if (credits?.Cast is not null)
{
- foreach (var actor in credits.Cast.OrderBy(a => a.Order).Take(Plugin.Instance.Configuration.MaxCastMembers))
+ var castQuery = config.HideMissingCastMembers
+ ? credits.Cast.Where(a => !string.IsNullOrEmpty(a.ProfilePath)).OrderBy(a => a.Order)
+ : credits.Cast.OrderBy(a => a.Order);
+
+ foreach (var actor in castQuery.Take(config.MaxCastMembers))
{
- metadataResult.AddPerson(new PersonInfo
+ if (string.IsNullOrWhiteSpace(actor.Name))
+ {
+ continue;
+ }
+
+ var personInfo = new PersonInfo
{
Name = actor.Name.Trim(),
- Role = actor.Character,
+ Role = actor.Character?.Trim() ?? string.Empty,
Type = PersonKind.Actor,
- SortOrder = actor.Order
- });
+ SortOrder = actor.Order,
+ ImageUrl = _tmdbClientManager.GetProfileUrl(actor.ProfilePath)
+ };
+
+ if (actor.Id > 0)
+ {
+ personInfo.SetProviderId(MetadataProvider.Tmdb, actor.Id.ToString(CultureInfo.InvariantCulture));
+ }
+
+ metadataResult.AddPerson(personInfo);
}
}
if (credits?.GuestStars is not null)
{
- foreach (var guest in credits.GuestStars.OrderBy(a => a.Order).Take(Plugin.Instance.Configuration.MaxCastMembers))
+ var guestQuery = config.HideMissingCastMembers
+ ? credits.GuestStars.Where(a => !string.IsNullOrEmpty(a.ProfilePath)).OrderBy(a => a.Order)
+ : credits.GuestStars.OrderBy(a => a.Order);
+
+ foreach (var guest in guestQuery.Take(config.MaxCastMembers))
{
- metadataResult.AddPerson(new PersonInfo
+ if (string.IsNullOrWhiteSpace(guest.Name))
+ {
+ continue;
+ }
+
+ var personInfo = new PersonInfo
{
Name = guest.Name.Trim(),
- Role = guest.Character,
+ Role = guest.Character?.Trim() ?? string.Empty,
Type = PersonKind.GuestStar,
- SortOrder = guest.Order
- });
+ SortOrder = guest.Order,
+ ImageUrl = _tmdbClientManager.GetProfileUrl(guest.ProfilePath)
+ };
+
+ if (guest.Id > 0)
+ {
+ personInfo.SetProviderId(MetadataProvider.Tmdb, guest.Id.ToString(CultureInfo.InvariantCulture));
+ }
+
+ metadataResult.AddPerson(personInfo);
}
}
- // and the rest from crew
if (credits?.Crew is not null)
{
- foreach (var person in credits.Crew)
+ var crewQuery = credits.Crew
+ .Select(crewMember => new
+ {
+ CrewMember = crewMember,
+ PersonType = TmdbUtils.MapCrewToPersonType(crewMember)
+ })
+ .Where(entry =>
+ TmdbUtils.WantedCrewKinds.Contains(entry.PersonType) ||
+ TmdbUtils.WantedCrewTypes.Contains(entry.CrewMember.Job ?? string.Empty, StringComparison.OrdinalIgnoreCase));
+
+ if (config.HideMissingCrewMembers)
+ {
+ crewQuery = crewQuery.Where(entry => !string.IsNullOrEmpty(entry.CrewMember.ProfilePath));
+ }
+
+ foreach (var entry in crewQuery.Take(config.MaxCrewMembers))
{
- // Normalize this
- var type = TmdbUtils.MapCrewToPersonType(person);
+ var crewMember = entry.CrewMember;
- if (!TmdbUtils.WantedCrewKinds.Contains(type)
- && !TmdbUtils.WantedCrewTypes.Contains(person.Job ?? string.Empty, StringComparison.OrdinalIgnoreCase))
+ if (string.IsNullOrWhiteSpace(crewMember.Name))
{
continue;
}
- metadataResult.AddPerson(new PersonInfo
+ var personInfo = new PersonInfo
{
- Name = person.Name.Trim(),
- Role = person.Job,
- Type = type
- });
+ Name = crewMember.Name.Trim(),
+ Role = crewMember.Job?.Trim() ?? string.Empty,
+ Type = entry.PersonType,
+ ImageUrl = _tmdbClientManager.GetProfileUrl(crewMember.ProfilePath)
+ };
+
+ if (crewMember.Id > 0)
+ {
+ personInfo.SetProviderId(MetadataProvider.Tmdb, crewMember.Id.ToString(CultureInfo.InvariantCulture));
+ }
+
+ metadataResult.AddPerson(personInfo);
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs
index 3f208b5993..cfef0d6561 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeasonProvider.cs
@@ -42,6 +42,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
public async Task<MetadataResult<Season>> GetMetadata(SeasonInfo info, CancellationToken cancellationToken)
{
var result = new MetadataResult<Season>();
+ var config = Plugin.Instance.Configuration;
info.SeriesProviderIds.TryGetValue(MetadataProvider.Tmdb.ToString(), out string? seriesTmdbId);
@@ -65,10 +66,12 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
result.Item = new Season
{
IndexNumber = seasonNumber,
- Overview = seasonResult.Overview
+ Overview = seasonResult.Overview,
+ PremiereDate = seasonResult.AirDate,
+ ProductionYear = seasonResult.AirDate?.Year
};
- if (Plugin.Instance.Configuration.ImportSeasonName)
+ if (config.ImportSeasonName)
{
result.Item.Name = seasonResult.Name;
}
@@ -77,46 +80,81 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
// TODO why was this disabled?
var credits = seasonResult.Credits;
+
if (credits?.Cast is not null)
{
- var cast = credits.Cast.OrderBy(c => c.Order).Take(Plugin.Instance.Configuration.MaxCastMembers).ToList();
- for (var i = 0; i < cast.Count; i++)
+ var castQuery = config.HideMissingCastMembers
+ ? credits.Cast.Where(a => !string.IsNullOrEmpty(a.ProfilePath)).OrderBy(a => a.Order)
+ : credits.Cast.OrderBy(a => a.Order);
+
+ foreach (var actor in castQuery.Take(config.MaxCastMembers))
{
- result.AddPerson(new PersonInfo
+ if (string.IsNullOrWhiteSpace(actor.Name))
+ {
+ continue;
+ }
+
+ var personInfo = new PersonInfo
{
- Name = cast[i].Name.Trim(),
- Role = cast[i].Character,
+ Name = actor.Name.Trim(),
+ Role = actor.Character?.Trim() ?? string.Empty,
Type = PersonKind.Actor,
- SortOrder = cast[i].Order
- });
+ SortOrder = actor.Order,
+ ImageUrl = _tmdbClientManager.GetProfileUrl(actor.ProfilePath)
+ };
+
+ if (actor.Id > 0)
+ {
+ personInfo.SetProviderId(MetadataProvider.Tmdb, actor.Id.ToString(CultureInfo.InvariantCulture));
+ }
+
+ result.AddPerson(personInfo);
}
}
if (credits?.Crew is not null)
{
- foreach (var person in credits.Crew)
+ var crewQuery = credits.Crew
+ .Select(crewMember => new
+ {
+ CrewMember = crewMember,
+ PersonType = TmdbUtils.MapCrewToPersonType(crewMember)
+ })
+ .Where(entry =>
+ TmdbUtils.WantedCrewKinds.Contains(entry.PersonType) ||
+ TmdbUtils.WantedCrewTypes.Contains(entry.CrewMember.Job ?? string.Empty, StringComparison.OrdinalIgnoreCase));
+
+ if (config.HideMissingCrewMembers)
{
- // Normalize this
- var type = TmdbUtils.MapCrewToPersonType(person);
+ crewQuery = crewQuery.Where(entry => !string.IsNullOrEmpty(entry.CrewMember.ProfilePath));
+ }
- if (!TmdbUtils.WantedCrewKinds.Contains(type)
- && !TmdbUtils.WantedCrewTypes.Contains(person.Job ?? string.Empty, StringComparison.OrdinalIgnoreCase))
+ foreach (var entry in crewQuery.Take(config.MaxCrewMembers))
+ {
+ var crewMember = entry.CrewMember;
+
+ if (string.IsNullOrWhiteSpace(crewMember.Name))
{
continue;
}
- result.AddPerson(new PersonInfo
+ var personInfo = new PersonInfo
{
- Name = person.Name.Trim(),
- Role = person.Job,
- Type = type
- });
+ Name = crewMember.Name.Trim(),
+ Role = crewMember.Job?.Trim() ?? string.Empty,
+ Type = entry.PersonType,
+ ImageUrl = _tmdbClientManager.GetProfileUrl(crewMember.ProfilePath)
+ };
+
+ if (crewMember.Id > 0)
+ {
+ personInfo.SetProviderId(MetadataProvider.Tmdb, crewMember.Id.ToString(CultureInfo.InvariantCulture));
+ }
+
+ result.AddPerson(personInfo);
}
}
- result.Item.PremiereDate = seasonResult.AirDate;
- result.Item.ProductionYear = seasonResult.AirDate?.Year;
-
return result;
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs
index 5f2d7909a9..840cec9841 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesExternalId.cs
@@ -20,9 +20,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
public ExternalIdMediaType? Type => ExternalIdMediaType.Series;
/// <inheritdoc />
- public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "tv/{0}";
-
- /// <inheritdoc />
public bool Supports(IHasProviderIds item)
{
return item is Series;
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs
index e4062740fe..8791712c71 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TV/TmdbSeriesProvider.cs
@@ -323,17 +323,31 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
private IEnumerable<PersonInfo> GetPersons(TvShow seriesResult)
{
+ var config = Plugin.Instance.Configuration;
+
if (seriesResult.Credits?.Cast is not null)
{
- foreach (var actor in seriesResult.Credits.Cast.OrderBy(a => a.Order).Take(Plugin.Instance.Configuration.MaxCastMembers))
+ IEnumerable<Cast> castQuery = seriesResult.Credits.Cast.OrderBy(a => a.Order);
+
+ if (config.HideMissingCastMembers)
+ {
+ castQuery = castQuery.Where(a => !string.IsNullOrEmpty(a.ProfilePath));
+ }
+
+ foreach (var actor in castQuery.Take(config.MaxCastMembers))
{
+ if (string.IsNullOrWhiteSpace(actor.Name))
+ {
+ continue;
+ }
+
var personInfo = new PersonInfo
{
Name = actor.Name.Trim(),
- Role = actor.Character,
+ Role = actor.Character?.Trim() ?? string.Empty,
Type = PersonKind.Actor,
SortOrder = actor.Order,
- ImageUrl = _tmdbClientManager.GetPosterUrl(actor.ProfilePath)
+ ImageUrl = _tmdbClientManager.GetProfileUrl(actor.ProfilePath)
};
if (actor.Id > 0)
@@ -347,30 +361,44 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
if (seriesResult.Credits?.Crew is not null)
{
- var keepTypes = new[]
+ var crewQuery = seriesResult.Credits.Crew
+ .Select(crewMember => new
+ {
+ CrewMember = crewMember,
+ PersonType = TmdbUtils.MapCrewToPersonType(crewMember)
+ })
+ .Where(entry =>
+ TmdbUtils.WantedCrewKinds.Contains(entry.PersonType) ||
+ TmdbUtils.WantedCrewTypes.Contains(entry.CrewMember.Job ?? string.Empty, StringComparison.OrdinalIgnoreCase));
+
+ if (config.HideMissingCrewMembers)
{
- PersonType.Director,
- PersonType.Writer,
- PersonType.Producer
- };
+ crewQuery = crewQuery.Where(entry => !string.IsNullOrEmpty(entry.CrewMember.ProfilePath));
+ }
- foreach (var person in seriesResult.Credits.Crew)
+ foreach (var entry in crewQuery.Take(config.MaxCrewMembers))
{
- // Normalize this
- var type = TmdbUtils.MapCrewToPersonType(person);
+ var crewMember = entry.CrewMember;
- if (!TmdbUtils.WantedCrewKinds.Contains(type)
- && !TmdbUtils.WantedCrewTypes.Contains(person.Job ?? string.Empty, StringComparison.OrdinalIgnoreCase))
+ if (string.IsNullOrWhiteSpace(crewMember.Name))
{
continue;
}
- yield return new PersonInfo
+ var personInfo = new PersonInfo
{
- Name = person.Name.Trim(),
- Role = person.Job,
- Type = type
+ Name = crewMember.Name.Trim(),
+ Role = crewMember.Job?.Trim() ?? string.Empty,
+ Type = entry.PersonType,
+ ImageUrl = _tmdbClientManager.GetProfileUrl(crewMember.ProfilePath)
};
+
+ if (crewMember.Id > 0)
+ {
+ personInfo.SetProviderId(MetadataProvider.Tmdb, crewMember.Id.ToString(CultureInfo.InvariantCulture));
+ }
+
+ yield return personInfo;
}
}
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs b/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
index 4916a95d90..767004c9e5 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
@@ -374,7 +374,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
/// <returns>The TMDb tv show information.</returns>
public async Task<IReadOnlyList<SearchTv>> SearchSeriesAsync(string name, string language, int year = 0, CancellationToken cancellationToken = default)
{
- var key = $"searchseries-{name}-{language}";
+ var key = $"searchseries-{name}-{year.ToString(CultureInfo.InvariantCulture)}-{language}";
if (_memoryCache.TryGetValue(key, out SearchContainer<SearchTv>? series) && series is not null)
{
return series.Results;
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TmdbExternalUrlProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/TmdbExternalUrlProvider.cs
new file mode 100644
index 0000000000..8d9ec10c11
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TmdbExternalUrlProvider.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using TMDbLib.Objects.TvShows;
+
+namespace MediaBrowser.Providers.Plugins.Tmdb;
+
+/// <summary>
+/// External URLs for TMDb.
+/// </summary>
+public class TmdbExternalUrlProvider : IExternalUrlProvider
+{
+ /// <inheritdoc/>
+ public string Name => "TMDB";
+
+ /// <inheritdoc/>
+ public IEnumerable<string> GetExternalUrls(BaseItem item)
+ {
+ switch (item)
+ {
+ case Series:
+ if (item.TryGetProviderId(MetadataProvider.Tmdb, out var externalId))
+ {
+ yield return TmdbUtils.BaseTmdbUrl + $"tv/{externalId}";
+ }
+
+ break;
+ case Season season:
+ if (season.Series?.TryGetProviderId(MetadataProvider.Tmdb, out var seriesExternalId) == true)
+ {
+ var orderString = season.Series.DisplayOrder;
+ var seasonNumber = season.IndexNumber;
+ if (string.IsNullOrEmpty(orderString) && seasonNumber is not null)
+ {
+ // Default order is airdate
+ yield return TmdbUtils.BaseTmdbUrl + $"tv/{seriesExternalId}/season/{seasonNumber}";
+ }
+
+ if (Enum.TryParse<TvGroupType>(season.Series.DisplayOrder, out var order))
+ {
+ if (order.Equals(TvGroupType.OriginalAirDate) && seasonNumber is not null)
+ {
+ yield return TmdbUtils.BaseTmdbUrl + $"tv/{seriesExternalId}/season/{seasonNumber}";
+ }
+ }
+ }
+
+ break;
+ case Episode episode:
+ if (episode.Series?.TryGetProviderId(MetadataProvider.Tmdb, out seriesExternalId) == true)
+ {
+ var orderString = episode.Series.DisplayOrder;
+ var seasonNumber = episode.Season?.IndexNumber;
+ var episodeNumber = episode.IndexNumber;
+ if (string.IsNullOrEmpty(orderString) && seasonNumber is not null && episodeNumber is not null)
+ {
+ // Default order is airdate
+ yield return TmdbUtils.BaseTmdbUrl + $"tv/{seriesExternalId}/season/{seasonNumber}/episode/{episodeNumber}";
+ }
+
+ if (Enum.TryParse<TvGroupType>(orderString, out var order))
+ {
+ if (order.Equals(TvGroupType.OriginalAirDate) && seasonNumber is not null && episodeNumber is not null)
+ {
+ yield return TmdbUtils.BaseTmdbUrl + $"tv/{seriesExternalId}/season/{seasonNumber}/episode/{episodeNumber}";
+ }
+ }
+ }
+
+ break;
+ case Movie:
+ if (item.TryGetProviderId(MetadataProvider.Tmdb, out externalId))
+ {
+ yield return TmdbUtils.BaseTmdbUrl + $"movie/{externalId}";
+ }
+
+ break;
+ case Person:
+ if (item.TryGetProviderId(MetadataProvider.Tmdb, out externalId))
+ {
+ yield return TmdbUtils.BaseTmdbUrl + $"person/{externalId}";
+ }
+
+ break;
+ case BoxSet:
+ if (item.TryGetProviderId(MetadataProvider.Tmdb, out externalId))
+ {
+ yield return TmdbUtils.BaseTmdbUrl + $"collection/{externalId}";
+ }
+
+ break;
+ }
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs b/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs
index a7c93ac4c8..afbada3b30 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TmdbUtils.cs
@@ -48,7 +48,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
PersonKind.Producer
};
- [GeneratedRegex(@"[\W_]+")]
+ [GeneratedRegex(@"[\W_-[ยท]]+")]
private static partial Regex NonWordRegex();
/// <summary>