mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-07-10 00:02:56 +01:00
Merge branch 'master' into comparisons
This commit is contained in:
@@ -201,7 +201,7 @@ namespace MediaBrowser.Providers.Manager
|
||||
}
|
||||
|
||||
// Save to database
|
||||
await SaveItemAsync(metadataResult, libraryOptions, updateType, cancellationToken).ConfigureAwait(false);
|
||||
await SaveItemAsync(metadataResult, updateType, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await AfterMetadataRefresh(itemOfType, refreshOptions, cancellationToken).ConfigureAwait(false);
|
||||
@@ -216,66 +216,18 @@ namespace MediaBrowser.Providers.Manager
|
||||
lookupInfo.Year = result.ProductionYear;
|
||||
}
|
||||
|
||||
protected async Task SaveItemAsync(MetadataResult<TItemType> result, LibraryOptions libraryOptions, ItemUpdateType reason, CancellationToken cancellationToken)
|
||||
protected async Task SaveItemAsync(MetadataResult<TItemType> result, ItemUpdateType reason, CancellationToken cancellationToken)
|
||||
{
|
||||
if (result.Item.SupportsPeople && result.People != null)
|
||||
{
|
||||
var baseItem = result.Item;
|
||||
|
||||
LibraryManager.UpdatePeople(baseItem, result.People);
|
||||
await SavePeopleMetadataAsync(result.People, libraryOptions, cancellationToken).ConfigureAwait(false);
|
||||
await LibraryManager.UpdatePeopleAsync(baseItem, result.People, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await result.Item.UpdateToRepositoryAsync(reason, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task SavePeopleMetadataAsync(List<PersonInfo> people, LibraryOptions libraryOptions, CancellationToken cancellationToken)
|
||||
{
|
||||
var personsToSave = new List<BaseItem>();
|
||||
|
||||
foreach (var person in people)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (person.ProviderIds.Count > 0 || !string.IsNullOrWhiteSpace(person.ImageUrl))
|
||||
{
|
||||
var itemUpdateType = ItemUpdateType.MetadataDownload;
|
||||
var saveEntity = false;
|
||||
var personEntity = LibraryManager.GetPerson(person.Name);
|
||||
foreach (var id in person.ProviderIds)
|
||||
{
|
||||
if (!string.Equals(personEntity.GetProviderId(id.Key), id.Value, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
personEntity.SetProviderId(id.Key, id.Value);
|
||||
saveEntity = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(person.ImageUrl) && !personEntity.HasImage(ImageType.Primary))
|
||||
{
|
||||
personEntity.SetImage(
|
||||
new ItemImageInfo
|
||||
{
|
||||
Path = person.ImageUrl,
|
||||
Type = ImageType.Primary
|
||||
},
|
||||
0);
|
||||
|
||||
saveEntity = true;
|
||||
itemUpdateType = ItemUpdateType.ImageUpdate;
|
||||
}
|
||||
|
||||
if (saveEntity)
|
||||
{
|
||||
personsToSave.Add(personEntity);
|
||||
await LibraryManager.RunMetadataSavers(personEntity, itemUpdateType).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LibraryManager.CreateItems(personsToSave, null, CancellationToken.None);
|
||||
}
|
||||
|
||||
protected virtual Task AfterMetadataRefresh(TItemType item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken)
|
||||
{
|
||||
item.AfterMetadataRefresh();
|
||||
@@ -329,8 +281,7 @@ namespace MediaBrowser.Providers.Manager
|
||||
return true;
|
||||
}
|
||||
|
||||
var folder = item as Folder;
|
||||
if (folder != null)
|
||||
if (item is Folder folder)
|
||||
{
|
||||
return folder.SupportsDateLastMediaAdded || folder.SupportsCumulativeRunTimeTicks;
|
||||
}
|
||||
@@ -384,8 +335,7 @@ namespace MediaBrowser.Providers.Manager
|
||||
|
||||
private ItemUpdateType UpdateCumulativeRunTimeTicks(TItemType item, IList<BaseItem> children)
|
||||
{
|
||||
var folder = item as Folder;
|
||||
if (folder != null && folder.SupportsCumulativeRunTimeTicks)
|
||||
if (item is Folder folder && folder.SupportsCumulativeRunTimeTicks)
|
||||
{
|
||||
long ticks = 0;
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ using MediaBrowser.Controller.Subtitles;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Priority_Queue;
|
||||
@@ -1022,26 +1021,26 @@ namespace MediaBrowser.Providers.Manager
|
||||
// TODO: Need to hunt down the conditions for this happening
|
||||
_activeRefreshes.AddOrUpdate(
|
||||
id,
|
||||
(_) => throw new Exception(
|
||||
(_) => throw new InvalidOperationException(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"Cannot update refresh progress of item '{0}' ({1}) because a refresh for this item is not running",
|
||||
item.GetType().Name,
|
||||
item.Id.ToString("N", CultureInfo.InvariantCulture))),
|
||||
(_, __) => progress);
|
||||
(_, _) => progress);
|
||||
|
||||
RefreshProgress?.Invoke(this, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(item, progress)));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void QueueRefresh(Guid id, MetadataRefreshOptions options, RefreshPriority priority)
|
||||
public void QueueRefresh(Guid itemId, MetadataRefreshOptions options, RefreshPriority priority)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_refreshQueue.Enqueue(new Tuple<Guid, MetadataRefreshOptions>(id, options), (int)priority);
|
||||
_refreshQueue.Enqueue(new Tuple<Guid, MetadataRefreshOptions>(itemId, options), (int)priority);
|
||||
|
||||
lock (_refreshQueueLock)
|
||||
{
|
||||
@@ -1074,17 +1073,16 @@ namespace MediaBrowser.Providers.Manager
|
||||
try
|
||||
{
|
||||
var item = libraryManager.GetItemById(refreshItem.Item1);
|
||||
if (item != null)
|
||||
if (item == null)
|
||||
{
|
||||
// Try to throttle this a little bit.
|
||||
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var task = item is MusicArtist artist
|
||||
? RefreshArtist(artist, refreshItem.Item2, cancellationToken)
|
||||
: RefreshItem(item, refreshItem.Item2, cancellationToken);
|
||||
|
||||
await task.ConfigureAwait(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
var task = item is MusicArtist artist
|
||||
? RefreshArtist(artist, refreshItem.Item2, cancellationToken)
|
||||
: RefreshItem(item, refreshItem.Item2, cancellationToken);
|
||||
|
||||
await task.ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="OptimizedPriorityQueue" Version="5.0.0" />
|
||||
<PackageReference Include="PlaylistsNET" Version="1.1.3" />
|
||||
<PackageReference Include="TMDbLib" Version="1.8.1" />
|
||||
|
||||
@@ -137,9 +137,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
return false;
|
||||
}
|
||||
|
||||
var audio = item as Audio;
|
||||
|
||||
return audio != null;
|
||||
return item is Audio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,8 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
}
|
||||
}
|
||||
|
||||
streamFileNames ??= Array.Empty<string>();
|
||||
|
||||
mediaInfoResult = await GetMediaInfo(item, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
@@ -172,9 +172,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
SubtitleFetcherOrder = subtitleFetcherOrder
|
||||
};
|
||||
|
||||
var episode = video as Episode;
|
||||
|
||||
if (episode != null)
|
||||
if (video is Episode episode)
|
||||
{
|
||||
request.IndexNumberEnd = episode.IndexNumberEnd;
|
||||
request.SeriesName = episode.SeriesName;
|
||||
|
||||
@@ -154,9 +154,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
return false;
|
||||
}
|
||||
|
||||
var video = item as Video;
|
||||
|
||||
if (video != null && !video.IsPlaceHolder && video.IsCompleteMedia)
|
||||
if (item is Video video && !video.IsPlaceHolder && video.IsCompleteMedia)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
||||
namespace MediaBrowser.Providers.Plugins.AudioDb
|
||||
{
|
||||
|
||||
@@ -19,7 +19,6 @@ using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Providers.Music;
|
||||
|
||||
namespace MediaBrowser.Providers.Plugins.AudioDb
|
||||
|
||||
@@ -14,7 +14,6 @@ using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
||||
namespace MediaBrowser.Providers.Plugins.AudioDb
|
||||
{
|
||||
|
||||
@@ -18,7 +18,6 @@ using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Providers.Music;
|
||||
|
||||
namespace MediaBrowser.Providers.Plugins.AudioDb
|
||||
|
||||
@@ -6,9 +6,7 @@ using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common;
|
||||
|
||||
@@ -7,8 +7,6 @@ using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using TMDbLib.Objects.Find;
|
||||
using TMDbLib.Objects.Search;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
@@ -16,6 +14,8 @@ using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using TMDbLib.Objects.Find;
|
||||
using TMDbLib.Objects.Search;
|
||||
|
||||
namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
|
||||
{
|
||||
|
||||
@@ -49,37 +49,36 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
|
||||
{
|
||||
var person = (Person)item;
|
||||
var personTmdbId = Convert.ToInt32(person.GetProviderId(MetadataProvider.Tmdb), CultureInfo.InvariantCulture);
|
||||
|
||||
if (personTmdbId > 0)
|
||||
if (!person.TryGetProviderId(MetadataProvider.Tmdb, out var personTmdbId))
|
||||
{
|
||||
var personResult = await _tmdbClientManager.GetPersonAsync(personTmdbId, cancellationToken).ConfigureAwait(false);
|
||||
if (personResult?.Images?.Profiles == null)
|
||||
{
|
||||
return Enumerable.Empty<RemoteImageInfo>();
|
||||
}
|
||||
|
||||
var remoteImages = new List<RemoteImageInfo>();
|
||||
var language = item.GetPreferredMetadataLanguage();
|
||||
|
||||
for (var i = 0; i < personResult.Images.Profiles.Count; i++)
|
||||
{
|
||||
var image = personResult.Images.Profiles[i];
|
||||
remoteImages.Add(new RemoteImageInfo
|
||||
{
|
||||
ProviderName = Name,
|
||||
Type = ImageType.Primary,
|
||||
Width = image.Width,
|
||||
Height = image.Height,
|
||||
Language = TmdbUtils.AdjustImageLanguage(image.Iso_639_1, language),
|
||||
Url = _tmdbClientManager.GetProfileUrl(image.FilePath)
|
||||
});
|
||||
}
|
||||
|
||||
return remoteImages.OrderByLanguageDescending(language);
|
||||
return Enumerable.Empty<RemoteImageInfo>();
|
||||
}
|
||||
|
||||
return Enumerable.Empty<RemoteImageInfo>();
|
||||
var personResult = await _tmdbClientManager.GetPersonAsync(int.Parse(personTmdbId, CultureInfo.InvariantCulture), cancellationToken).ConfigureAwait(false);
|
||||
if (personResult?.Images?.Profiles == null)
|
||||
{
|
||||
return Enumerable.Empty<RemoteImageInfo>();
|
||||
}
|
||||
|
||||
var remoteImages = new RemoteImageInfo[personResult.Images.Profiles.Count];
|
||||
var language = item.GetPreferredMetadataLanguage();
|
||||
|
||||
for (var i = 0; i < personResult.Images.Profiles.Count; i++)
|
||||
{
|
||||
var image = personResult.Images.Profiles[i];
|
||||
remoteImages[i] = new RemoteImageInfo
|
||||
{
|
||||
ProviderName = Name,
|
||||
Type = ImageType.Primary,
|
||||
Width = image.Width,
|
||||
Height = image.Height,
|
||||
Language = TmdbUtils.AdjustImageLanguage(image.Iso_639_1, language),
|
||||
Url = _tmdbClientManager.GetProfileUrl(image.FilePath)
|
||||
};
|
||||
}
|
||||
|
||||
return remoteImages.OrderByLanguageDescending(language);
|
||||
}
|
||||
|
||||
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
|
||||
@@ -30,11 +30,9 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
|
||||
|
||||
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(PersonLookupInfo searchInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
var personTmdbId = Convert.ToInt32(searchInfo.GetProviderId(MetadataProvider.Tmdb), CultureInfo.InvariantCulture);
|
||||
|
||||
if (personTmdbId <= 0)
|
||||
if (searchInfo.TryGetProviderId(MetadataProvider.Tmdb, out var personTmdbId))
|
||||
{
|
||||
var personResult = await _tmdbClientManager.GetPersonAsync(personTmdbId, cancellationToken).ConfigureAwait(false);
|
||||
var personResult = await _tmdbClientManager.GetPersonAsync(int.Parse(personTmdbId, CultureInfo.InvariantCulture), cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (personResult != null)
|
||||
{
|
||||
@@ -51,19 +49,15 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
|
||||
}
|
||||
|
||||
result.SetProviderId(MetadataProvider.Tmdb, personResult.Id.ToString(CultureInfo.InvariantCulture));
|
||||
result.SetProviderId(MetadataProvider.Imdb, personResult.ExternalIds.ImdbId);
|
||||
if (!string.IsNullOrEmpty(personResult.ExternalIds.ImdbId))
|
||||
{
|
||||
result.SetProviderId(MetadataProvider.Imdb, personResult.ExternalIds.ImdbId);
|
||||
}
|
||||
|
||||
return new[] { result };
|
||||
}
|
||||
}
|
||||
|
||||
// TODO why? Because of the old rate limit?
|
||||
if (searchInfo.IsAutomated)
|
||||
{
|
||||
// Don't hammer moviedb searching by name
|
||||
return Enumerable.Empty<RemoteSearchResult>();
|
||||
}
|
||||
|
||||
var personSearchResult = await _tmdbClientManager.SearchPersonAsync(searchInfo.Name, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var remoteSearchResults = new List<RemoteSearchResult>();
|
||||
|
||||
@@ -65,7 +65,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, null, null, cancellationToken)
|
||||
.GetEpisodeAsync(seriesTmdbId, seasonNumber.Value, episodeNumber.Value, series.DisplayOrder, null, null, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var stills = episodeResult?.Images?.Stills;
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
|
||||
}
|
||||
|
||||
var episodeResult = await _tmdbClientManager
|
||||
.GetEpisodeAsync(seriesTmdbId, seasonNumber.Value, episodeNumber.Value, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken)
|
||||
.GetEpisodeAsync(seriesTmdbId, seasonNumber.Value, episodeNumber.Value, info.SeriesDisplayOrder, info.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(info.MetadataLanguage), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (episodeResult == null)
|
||||
@@ -121,9 +121,20 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
|
||||
CommunityRating = Convert.ToSingle(episodeResult.VoteAverage)
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(episodeResult.ExternalIds?.TvdbId))
|
||||
var externalIds = episodeResult.ExternalIds;
|
||||
if (!string.IsNullOrEmpty(externalIds?.TvdbId))
|
||||
{
|
||||
item.SetProviderId(MetadataProvider.Tvdb, episodeResult.ExternalIds.TvdbId);
|
||||
item.SetProviderId(MetadataProvider.Tvdb, externalIds.TvdbId);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(externalIds?.ImdbId))
|
||||
{
|
||||
item.SetProviderId(MetadataProvider.Imdb, externalIds.ImdbId);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(externalIds?.TvrageId))
|
||||
{
|
||||
item.SetProviderId(MetadataProvider.TvRage, externalIds.TvrageId);
|
||||
}
|
||||
|
||||
if (episodeResult.Videos?.Results != null)
|
||||
|
||||
@@ -125,7 +125,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
|
||||
tmdbId,
|
||||
language: TmdbUtils.NormalizeLanguage(language),
|
||||
includeImageLanguage: imageLanguages,
|
||||
extraMethods: TvShowMethods.Credits | TvShowMethods.Images | TvShowMethods.Keywords | TvShowMethods.ExternalIds | TvShowMethods.Videos | TvShowMethods.ContentRatings,
|
||||
extraMethods: TvShowMethods.Credits | TvShowMethods.Images | TvShowMethods.Keywords | TvShowMethods.ExternalIds | TvShowMethods.Videos | TvShowMethods.ContentRatings | TvShowMethods.EpisodeGroups,
|
||||
cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (series != null)
|
||||
@@ -136,6 +136,56 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
|
||||
return series;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a tv show episode group from the TMDb API based on the show id and the display order.
|
||||
/// </summary>
|
||||
/// <param name="tvShowId">The tv show's TMDb id.</param>
|
||||
/// <param name="displayOrder">The display order.</param>
|
||||
/// <param name="language">The tv show's language.</param>
|
||||
/// <param name="imageLanguages">A comma-separated list of image languages.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The TMDb tv show episode group information or null if not found.</returns>
|
||||
private async Task<TvGroupCollection> GetSeriesGroupAsync(int tvShowId, string displayOrder, string language, string imageLanguages, CancellationToken cancellationToken)
|
||||
{
|
||||
TvGroupType? groupType =
|
||||
string.Equals(displayOrder, "absolute", StringComparison.Ordinal) ? TvGroupType.Absolute :
|
||||
string.Equals(displayOrder, "dvd", StringComparison.Ordinal) ? TvGroupType.DVD :
|
||||
null;
|
||||
|
||||
if (groupType == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var key = $"group-{tvShowId.ToString(CultureInfo.InvariantCulture)}-{displayOrder}-{language}";
|
||||
if (_memoryCache.TryGetValue(key, out TvGroupCollection group))
|
||||
{
|
||||
return group;
|
||||
}
|
||||
|
||||
await EnsureClientConfigAsync().ConfigureAwait(false);
|
||||
|
||||
var series = await GetSeriesAsync(tvShowId, language, imageLanguages, cancellationToken).ConfigureAwait(false);
|
||||
var episodeGroupId = series?.EpisodeGroups.Results.Find(g => g.Type == groupType)?.Id;
|
||||
|
||||
if (episodeGroupId == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
group = await _tmDbClient.GetTvEpisodeGroupsAsync(
|
||||
episodeGroupId,
|
||||
language: TmdbUtils.NormalizeLanguage(language),
|
||||
cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (group != null)
|
||||
{
|
||||
_memoryCache.Set(key, group, TimeSpan.FromHours(CacheDurationInHours));
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a tv season from the TMDb API based on the tv show's TMDb id.
|
||||
/// </summary>
|
||||
@@ -177,13 +227,14 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
|
||||
/// <param name="tvShowId">The tv show's TMDb id.</param>
|
||||
/// <param name="seasonNumber">The season number.</param>
|
||||
/// <param name="episodeNumber">The episode number.</param>
|
||||
/// <param name="displayOrder">The display order.</param>
|
||||
/// <param name="language">The episode's language.</param>
|
||||
/// <param name="imageLanguages">A comma-separated list of image languages.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The TMDb tv episode information or null if not found.</returns>
|
||||
public async Task<TvEpisode> GetEpisodeAsync(int tvShowId, int seasonNumber, int episodeNumber, string language, string imageLanguages, CancellationToken cancellationToken)
|
||||
public async Task<TvEpisode> GetEpisodeAsync(int tvShowId, int seasonNumber, int episodeNumber, string displayOrder, string language, string imageLanguages, CancellationToken cancellationToken)
|
||||
{
|
||||
var key = $"episode-{tvShowId.ToString(CultureInfo.InvariantCulture)}-s{seasonNumber.ToString(CultureInfo.InvariantCulture)}e{episodeNumber.ToString(CultureInfo.InvariantCulture)}-{language}";
|
||||
var key = $"episode-{tvShowId.ToString(CultureInfo.InvariantCulture)}-s{seasonNumber.ToString(CultureInfo.InvariantCulture)}e{episodeNumber.ToString(CultureInfo.InvariantCulture)}-{displayOrder}-{language}";
|
||||
if (_memoryCache.TryGetValue(key, out TvEpisode episode))
|
||||
{
|
||||
return episode;
|
||||
@@ -191,6 +242,19 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
|
||||
|
||||
await EnsureClientConfigAsync().ConfigureAwait(false);
|
||||
|
||||
var group = await GetSeriesGroupAsync(tvShowId, displayOrder, language, imageLanguages, cancellationToken);
|
||||
if (group != null)
|
||||
{
|
||||
var season = group.Groups.Find(s => s.Order == seasonNumber);
|
||||
// Episode order starts at 0
|
||||
var ep = season?.Episodes.Find(e => e.Order == episodeNumber - 1);
|
||||
if (ep != null)
|
||||
{
|
||||
seasonNumber = ep.SeasonNumber;
|
||||
episodeNumber = ep.EpisodeNumber;
|
||||
}
|
||||
}
|
||||
|
||||
episode = await _tmDbClient.GetTvEpisodeAsync(
|
||||
tvShowId,
|
||||
seasonNumber,
|
||||
|
||||
@@ -63,19 +63,19 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
|
||||
/// <returns>The Jellyfin person type.</returns>
|
||||
public static string MapCrewToPersonType(Crew crew)
|
||||
{
|
||||
if (crew.Department.Equals("production", StringComparison.InvariantCultureIgnoreCase)
|
||||
&& crew.Job.Contains("director", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (crew.Department.Equals("production", StringComparison.OrdinalIgnoreCase)
|
||||
&& crew.Job.Contains("director", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return PersonType.Director;
|
||||
}
|
||||
|
||||
if (crew.Department.Equals("production", StringComparison.InvariantCultureIgnoreCase)
|
||||
&& crew.Job.Contains("producer", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (crew.Department.Equals("production", StringComparison.OrdinalIgnoreCase)
|
||||
&& crew.Job.Contains("producer", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return PersonType.Producer;
|
||||
}
|
||||
|
||||
if (crew.Department.Equals("writing", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (crew.Department.Equals("writing", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return PersonType.Writer;
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ namespace MediaBrowser.Providers.Subtitles
|
||||
{
|
||||
var mediaFolderPath = Path.GetFullPath(Path.Combine(video.ContainingFolderPath, saveFileName));
|
||||
// TODO: Add some error handling to the API user: return BadRequest("Could not save subtitle, bad path.");
|
||||
if (mediaFolderPath.StartsWith(video.ContainingFolderPath))
|
||||
if (mediaFolderPath.StartsWith(video.ContainingFolderPath, StringComparison.Ordinal))
|
||||
{
|
||||
savePaths.Add(mediaFolderPath);
|
||||
}
|
||||
@@ -216,7 +216,7 @@ namespace MediaBrowser.Providers.Subtitles
|
||||
var internalPath = Path.GetFullPath(Path.Combine(video.GetInternalMetadataPath(), saveFileName));
|
||||
|
||||
// TODO: Add some error to the user: return BadRequest("Could not save subtitle, bad path.");
|
||||
if (internalPath.StartsWith(video.GetInternalMetadataPath()))
|
||||
if (internalPath.StartsWith(video.GetInternalMetadataPath(), StringComparison.Ordinal))
|
||||
{
|
||||
savePaths.Add(internalPath);
|
||||
}
|
||||
@@ -234,7 +234,7 @@ namespace MediaBrowser.Providers.Subtitles
|
||||
|
||||
private async Task TrySaveToFiles(Stream stream, List<string> savePaths)
|
||||
{
|
||||
Exception exceptionToThrow = null;
|
||||
List<Exception> exs = null;
|
||||
|
||||
foreach (var savePath in savePaths)
|
||||
{
|
||||
@@ -256,10 +256,7 @@ namespace MediaBrowser.Providers.Subtitles
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (exceptionToThrow == null)
|
||||
{
|
||||
exceptionToThrow = ex;
|
||||
}
|
||||
(exs ??= new List<Exception>()).Add(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -269,9 +266,9 @@ namespace MediaBrowser.Providers.Subtitles
|
||||
stream.Position = 0;
|
||||
}
|
||||
|
||||
if (exceptionToThrow != null)
|
||||
if (exs != null)
|
||||
{
|
||||
throw exceptionToThrow;
|
||||
throw new AggregateException(exs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user