diff options
Diffstat (limited to 'MediaBrowser.Providers')
9 files changed, 117 insertions, 41 deletions
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 6d767914f..5a2936bd8 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -655,8 +655,6 @@ namespace MediaBrowser.Providers.Manager }; temp.Item.Path = item.Path; - var userDataList = new List<UserItemData>(); - // If replacing all metadata, run internet providers first if (options.ReplaceAllMetadata) { @@ -670,7 +668,7 @@ namespace MediaBrowser.Providers.Manager var hasLocalMetadata = false; - foreach (var provider in providers.OfType<ILocalMetadataProvider<TItemType>>().ToList()) + foreach (var provider in providers.OfType<ILocalMetadataProvider<TItemType>>()) { var providerName = provider.GetType().Name; Logger.LogDebug("Running {Provider} for {Item}", providerName, logName); @@ -687,6 +685,11 @@ namespace MediaBrowser.Providers.Manager { try { + if (!options.IsReplacingImage(remoteImage.Type)) + { + continue; + } + await ProviderManager.SaveImage(item, remoteImage.Url, remoteImage.Type, null, cancellationToken).ConfigureAwait(false); refreshResult.UpdateType |= ItemUpdateType.ImageUpdate; } @@ -701,11 +704,6 @@ namespace MediaBrowser.Providers.Manager refreshResult.UpdateType |= ItemUpdateType.ImageUpdate; } - if (localItem.UserDataList != null) - { - userDataList.AddRange(localItem.UserDataList); - } - MergeData(localItem, temp, Array.Empty<MetadataField>(), !options.ReplaceAllMetadata, true); refreshResult.UpdateType |= ItemUpdateType.MetadataImport; @@ -764,15 +762,11 @@ namespace MediaBrowser.Providers.Manager } } - // var isUnidentified = failedProviderCount > 0 && successfulProviderCount == 0; - foreach (var provider in customProviders.Where(i => i is not IPreRefreshProvider)) { await RunCustomProvider(provider, item, logName, options, refreshResult, cancellationToken).ConfigureAwait(false); } - // ImportUserData(item, userDataList, cancellationToken); - return refreshResult; } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 01ff473f0..bbb33ddf0 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -926,7 +926,7 @@ namespace MediaBrowser.Providers.Manager } catch (Exception ex) { - _logger.LogError(ex, "Error in {0}.Suports", i.GetType().Name); + _logger.LogError(ex, "Error in {0}.Supports", i.GetType().Name); return false; } }); diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index f31445c06..9864db9ac 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -20,7 +20,7 @@ <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> - <PackageReference Include="OptimizedPriorityQueue" Version="5.0.0" /> + <PackageReference Include="OptimizedPriorityQueue" Version="5.1.0" /> <PackageReference Include="PlaylistsNET" Version="1.2.1" /> <PackageReference Include="TMDbLib" Version="1.9.2" /> </ItemGroup> diff --git a/MediaBrowser.Providers/MediaInfo/AudioResolver.cs b/MediaBrowser.Providers/MediaInfo/AudioResolver.cs index 0bdf447ba..17164ee5c 100644 --- a/MediaBrowser.Providers/MediaInfo/AudioResolver.cs +++ b/MediaBrowser.Providers/MediaInfo/AudioResolver.cs @@ -4,6 +4,7 @@ using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; +using Microsoft.Extensions.Logging; namespace MediaBrowser.Providers.MediaInfo { @@ -15,16 +16,19 @@ namespace MediaBrowser.Providers.MediaInfo /// <summary> /// Initializes a new instance of the <see cref="AudioResolver"/> class for external audio file processing. /// </summary> + /// <param name="logger">The logger.</param> /// <param name="localizationManager">The localization manager.</param> /// <param name="mediaEncoder">The media encoder.</param> /// <param name="fileSystem">The file system.</param> /// <param name="namingOptions">The <see cref="NamingOptions"/> object containing FileExtensions, MediaDefaultFlags, MediaForcedFlags and MediaFlagDelimiters.</param> public AudioResolver( + ILogger<AudioResolver> logger, ILocalizationManager localizationManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, NamingOptions namingOptions) : base( + logger, localizationManager, mediaEncoder, fileSystem, diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs index fcd3f28d4..e58c0e281 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs @@ -47,7 +47,6 @@ namespace MediaBrowser.Providers.MediaInfo private readonly Task<ItemUpdateType> _cachedTask = Task.FromResult(ItemUpdateType.None); public FFProbeProvider( - ILogger<FFProbeProvider> logger, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, @@ -59,11 +58,12 @@ namespace MediaBrowser.Providers.MediaInfo IChapterManager chapterManager, ILibraryManager libraryManager, IFileSystem fileSystem, + ILoggerFactory loggerFactory, NamingOptions namingOptions) { - _logger = logger; - _audioResolver = new AudioResolver(localization, mediaEncoder, fileSystem, namingOptions); - _subtitleResolver = new SubtitleResolver(localization, mediaEncoder, fileSystem, namingOptions); + _logger = loggerFactory.CreateLogger<FFProbeProvider>(); + _audioResolver = new AudioResolver(loggerFactory.CreateLogger<AudioResolver>(), localization, mediaEncoder, fileSystem, namingOptions); + _subtitleResolver = new SubtitleResolver(loggerFactory.CreateLogger<SubtitleResolver>(), localization, mediaEncoder, fileSystem, namingOptions); _videoProber = new FFProbeVideoInfo( _logger, mediaSourceManager, diff --git a/MediaBrowser.Providers/MediaInfo/MediaInfoResolver.cs b/MediaBrowser.Providers/MediaInfo/MediaInfoResolver.cs index 1421d0183..d55cc4491 100644 --- a/MediaBrowser.Providers/MediaInfo/MediaInfoResolver.cs +++ b/MediaBrowser.Providers/MediaInfo/MediaInfoResolver.cs @@ -15,6 +15,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; +using Microsoft.Extensions.Logging; namespace MediaBrowser.Providers.MediaInfo { @@ -33,6 +34,7 @@ namespace MediaBrowser.Providers.MediaInfo /// </summary> private readonly IMediaEncoder _mediaEncoder; + private readonly ILogger _logger; private readonly IFileSystem _fileSystem; /// <summary> @@ -48,18 +50,21 @@ namespace MediaBrowser.Providers.MediaInfo /// <summary> /// Initializes a new instance of the <see cref="MediaInfoResolver"/> class. /// </summary> + /// <param name="logger">The logger.</param> /// <param name="localizationManager">The localization manager.</param> /// <param name="mediaEncoder">The media encoder.</param> /// <param name="fileSystem">The file system.</param> /// <param name="namingOptions">The <see cref="NamingOptions"/> object containing FileExtensions, MediaDefaultFlags, MediaForcedFlags and MediaFlagDelimiters.</param> /// <param name="type">The <see cref="DlnaProfileType"/> of the parsed file.</param> protected MediaInfoResolver( + ILogger logger, ILocalizationManager localizationManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, NamingOptions namingOptions, DlnaProfileType type) { + _logger = logger; _mediaEncoder = mediaEncoder; _fileSystem = fileSystem; _namingOptions = namingOptions; @@ -101,26 +106,44 @@ namespace MediaBrowser.Providers.MediaInfo { if (!pathInfo.Path.AsSpan().EndsWith(".strm", StringComparison.OrdinalIgnoreCase)) { - var mediaInfo = await GetMediaInfo(pathInfo.Path, _type, cancellationToken).ConfigureAwait(false); - - if (mediaInfo.MediaStreams.Count == 1) + try { - MediaStream mediaStream = mediaInfo.MediaStreams[0]; - mediaStream.Index = startIndex++; - mediaStream.IsDefault = pathInfo.IsDefault || mediaStream.IsDefault; - mediaStream.IsForced = pathInfo.IsForced || mediaStream.IsForced; + var mediaInfo = await GetMediaInfo(pathInfo.Path, _type, cancellationToken).ConfigureAwait(false); - mediaStreams.Add(MergeMetadata(mediaStream, pathInfo)); - } - else - { - foreach (MediaStream mediaStream in mediaInfo.MediaStreams) + if (mediaInfo.MediaStreams.Count == 1) { - mediaStream.Index = startIndex++; + MediaStream mediaStream = mediaInfo.MediaStreams[0]; - mediaStreams.Add(MergeMetadata(mediaStream, pathInfo)); + if ((mediaStream.Type == MediaStreamType.Audio && _type == DlnaProfileType.Audio) + || (mediaStream.Type == MediaStreamType.Subtitle && _type == DlnaProfileType.Subtitle)) + { + mediaStream.Index = startIndex++; + mediaStream.IsDefault = pathInfo.IsDefault || mediaStream.IsDefault; + mediaStream.IsForced = pathInfo.IsForced || mediaStream.IsForced; + + mediaStreams.Add(MergeMetadata(mediaStream, pathInfo)); + } + } + else + { + foreach (MediaStream mediaStream in mediaInfo.MediaStreams) + { + if ((mediaStream.Type == MediaStreamType.Audio && _type == DlnaProfileType.Audio) + || (mediaStream.Type == MediaStreamType.Subtitle && _type == DlnaProfileType.Subtitle)) + { + mediaStream.Index = startIndex++; + + mediaStreams.Add(MergeMetadata(mediaStream, pathInfo)); + } + } } } + catch (Exception ex) + { + _logger.LogError(ex, "Error getting external streams from {Path}", pathInfo.Path); + + continue; + } } } @@ -222,13 +245,6 @@ namespace MediaBrowser.Providers.MediaInfo mediaStream.Title = string.IsNullOrEmpty(mediaStream.Title) ? (string.IsNullOrEmpty(pathInfo.Title) ? null : pathInfo.Title) : mediaStream.Title; mediaStream.Language = string.IsNullOrEmpty(mediaStream.Language) ? (string.IsNullOrEmpty(pathInfo.Language) ? null : pathInfo.Language) : mediaStream.Language; - mediaStream.Type = _type switch - { - DlnaProfileType.Audio => MediaStreamType.Audio, - DlnaProfileType.Subtitle => MediaStreamType.Subtitle, - _ => mediaStream.Type - }; - return mediaStream; } } diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs index 4b9ba944a..70e5bd783 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs +++ b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs @@ -4,6 +4,7 @@ using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; +using Microsoft.Extensions.Logging; namespace MediaBrowser.Providers.MediaInfo { @@ -15,16 +16,19 @@ namespace MediaBrowser.Providers.MediaInfo /// <summary> /// Initializes a new instance of the <see cref="SubtitleResolver"/> class for external subtitle file processing. /// </summary> + /// <param name="logger">The logger.</param> /// <param name="localizationManager">The localization manager.</param> /// <param name="mediaEncoder">The media encoder.</param> /// <param name="fileSystem">The file system.</param> /// <param name="namingOptions">The <see cref="NamingOptions"/> object containing FileExtensions, MediaDefaultFlags, MediaForcedFlags and MediaFlagDelimiters.</param> public SubtitleResolver( + ILogger<SubtitleResolver> logger, ILocalizationManager localizationManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, NamingOptions namingOptions) : base( + logger, localizationManager, mediaEncoder, fileSystem, diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs index 5ae5ff3be..915fb97fd 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs @@ -36,7 +36,7 @@ namespace MediaBrowser.Providers.Music /// <summary> /// The Jellyfin user-agent is unrestricted but source IP must not exceed /// one request per second, therefore we rate limit to avoid throttling. - /// Be prudent, use a value slightly above the minimun required. + /// Be prudent, use a value slightly above the minimum required. /// https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting. /// </summary> private readonly long _musicBrainzQueryIntervalMs; @@ -465,7 +465,8 @@ namespace MediaBrowser.Providers.Music ValidationType = ValidationType.None, CheckCharacters = false, IgnoreProcessingInstructions = true, - IgnoreComments = true + IgnoreComments = true, + Async = true }; using var reader = XmlReader.Create(oReader, settings); diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs index f49492f33..c09b6d813 100644 --- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs +++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; @@ -40,6 +41,7 @@ namespace MediaBrowser.Providers.TV { await base.AfterMetadataRefresh(item, refreshOptions, cancellationToken).ConfigureAwait(false); + RemoveObsoleteEpisodes(item); RemoveObsoleteSeasons(item); await FillInMissingSeasonsAsync(item, cancellationToken).ConfigureAwait(false); } @@ -121,6 +123,61 @@ namespace MediaBrowser.Providers.TV } } + private void RemoveObsoleteEpisodes(Series series) + { + var episodes = series.GetEpisodes(null, new DtoOptions()).OfType<Episode>().ToList(); + var numberOfEpisodes = episodes.Count; + // TODO: O(n^2), but can it be done faster without overcomplicating it? + for (var i = 0; i < numberOfEpisodes; i++) + { + var currentEpisode = episodes[i]; + // The outer loop only examines virtual episodes + if (!currentEpisode.IsVirtualItem) + { + continue; + } + + // Virtual episodes without an episode number are practically orphaned and should be deleted + if (!currentEpisode.IndexNumber.HasValue) + { + DeleteEpisode(currentEpisode); + continue; + } + + for (var j = i + 1; j < numberOfEpisodes; j++) + { + var comparisonEpisode = episodes[j]; + // The inner loop is only for "physical" episodes + if (comparisonEpisode.IsVirtualItem + || currentEpisode.ParentIndexNumber != comparisonEpisode.ParentIndexNumber + || !comparisonEpisode.ContainsEpisodeNumber(currentEpisode.IndexNumber.Value)) + { + continue; + } + + DeleteEpisode(currentEpisode); + break; + } + } + } + + private void DeleteEpisode(Episode episode) + { + Logger.LogInformation( + "Removing virtual episode S{SeasonNumber}E{EpisodeNumber} in series {SeriesName}", + episode.ParentIndexNumber, + episode.IndexNumber, + episode.SeriesName); + + LibraryManager.DeleteItem( + episode, + new DeleteOptions + { + DeleteFileLocation = true + }, + false); + } + /// <summary> /// Creates seasons for all episodes that aren't in a season folder. /// If no season number can be determined, a dummy season will be created. |
