diff options
Diffstat (limited to 'MediaBrowser.Controller/Entities')
17 files changed, 118 insertions, 196 deletions
diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index b225f22df..40cdd6c91 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -155,11 +155,11 @@ namespace MediaBrowser.Controller.Entities return base.GetNonCachedChildren(directoryService).Concat(_virtualChildren); } - protected override async Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) + protected override async Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, bool allowRemoveRoot, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) { ClearCache(); - await base.ValidateChildrenInternal(progress, recursive, refreshChildMetadata, refreshOptions, directoryService, cancellationToken) + await base.ValidateChildrenInternal(progress, recursive, refreshChildMetadata, allowRemoveRoot, refreshOptions, directoryService, cancellationToken) .ConfigureAwait(false); ClearCache(); diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 237345206..a0aae8769 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -169,8 +169,7 @@ namespace MediaBrowser.Controller.Entities.Audio var childUpdateType = ItemUpdateType.None; - // Refresh songs only and not m3u files in album folder - foreach (var item in items.OfType<Audio>()) + foreach (var item in items) { cancellationToken.ThrowIfCancellationRequested(); @@ -183,14 +182,13 @@ namespace MediaBrowser.Controller.Entities.Audio progress.Report(percent * 95); } - // get album LUFS - LUFS = items.OfType<Audio>().Max(item => item.LUFS); - var parentRefreshOptions = refreshOptions; if (childUpdateType > ItemUpdateType.None) { - parentRefreshOptions = new MetadataRefreshOptions(refreshOptions); - parentRefreshOptions.MetadataRefreshMode = MetadataRefreshMode.FullRefresh; + parentRefreshOptions = new MetadataRefreshOptions(refreshOptions) + { + MetadataRefreshMode = MetadataRefreshMode.FullRefresh + }; } // Refresh current item diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 11cdf8444..1ab6c9706 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -110,7 +110,7 @@ namespace MediaBrowser.Controller.Entities.Audio return base.IsSaveLocalMetadataEnabled(); } - protected override Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) + protected override Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, bool allowRemoveRoot, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) { if (IsAccessedByName) { @@ -118,7 +118,7 @@ namespace MediaBrowser.Controller.Entities.Audio return Task.CompletedTask; } - return base.ValidateChildrenInternal(progress, recursive, refreshChildMetadata, refreshOptions, directoryService, cancellationToken); + return base.ValidateChildrenInternal(progress, recursive, refreshChildMetadata, false, refreshOptions, directoryService, cancellationToken); } public override List<string> GetUserDataKeys() diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index ac9698ec9..7b6f364f7 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -135,7 +135,14 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <value>The LUFS Value.</value> [JsonIgnore] - public float LUFS { get; set; } + public float? LUFS { get; set; } + + /// <summary> + /// Gets or sets the gain required for audio normalization. + /// </summary> + /// <value>The gain required for audio normalization.</value> + [JsonIgnore] + public float? NormalizationGain { get; set; } /// <summary> /// Gets or sets the channel identifier. @@ -745,9 +752,6 @@ namespace MediaBrowser.Controller.Entities public virtual bool SupportsAncestors => true; [JsonIgnore] - public virtual bool StopRefreshIfLocalMetadataFound => true; - - [JsonIgnore] protected virtual bool SupportsOwnedItems => !ParentId.IsEmpty() && IsFileProtocol; [JsonIgnore] @@ -833,7 +837,7 @@ namespace MediaBrowser.Controller.Entities return CanDelete() && IsAuthorizedToDelete(user, allCollectionFolders); } - public bool CanDelete(User user) + public virtual bool CanDelete(User user) { var allCollectionFolders = LibraryManager.GetUserRootFolder().Children.OfType<Folder>().ToList(); @@ -1602,6 +1606,12 @@ namespace MediaBrowser.Controller.Entities return false; } + var parent = GetParents().FirstOrDefault() ?? this; + if (parent is UserRootFolder or AggregateFolder) + { + return true; + } + var allowedTagsPreference = user.GetPreference(PreferenceKind.AllowedTags); if (allowedTagsPreference.Length != 0 && !allowedTagsPreference.Any(i => allTags.Contains(i, StringComparison.OrdinalIgnoreCase))) { @@ -1766,14 +1776,11 @@ namespace MediaBrowser.Controller.Entities int curLen = current.Length; if (curLen == 0) { - Studios = new[] { name }; + Studios = [name]; } else { - var newArr = new string[curLen + 1]; - current.CopyTo(newArr, 0); - newArr[curLen] = name; - Studios = newArr; + Studios = [..current, name]; } } } @@ -1795,9 +1802,7 @@ namespace MediaBrowser.Controller.Entities var genres = Genres; if (!genres.Contains(name, StringComparison.OrdinalIgnoreCase)) { - var list = genres.ToList(); - list.Add(name); - Genres = list.ToArray(); + Genres = [..genres, name]; } } @@ -1944,14 +1949,15 @@ namespace MediaBrowser.Controller.Entities return; } - // Remove it from the item - RemoveImage(info); - + // Remove from file system if (info.IsLocalFile) { FileSystem.DeleteFile(info.Path); } + // Remove from item + RemoveImage(info); + await UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); } @@ -1967,12 +1973,7 @@ namespace MediaBrowser.Controller.Entities public void AddImage(ItemImageInfo image) { - var current = ImageInfos; - var currentCount = current.Length; - var newArr = new ItemImageInfo[currentCount + 1]; - current.CopyTo(newArr, 0); - newArr[currentCount] = image; - ImageInfos = newArr; + ImageInfos = [..ImageInfos, image]; } public virtual Task UpdateToRepositoryAsync(ItemUpdateType updateReason, CancellationToken cancellationToken) @@ -2496,11 +2497,6 @@ namespace MediaBrowser.Controller.Entities return new[] { Id }; } - public virtual List<ExternalUrl> GetRelatedUrls() - { - return new List<ExternalUrl>(); - } - public virtual double? GetRefreshProgress() { return null; @@ -2548,14 +2544,24 @@ namespace MediaBrowser.Controller.Entities StringComparison.OrdinalIgnoreCase); } - public IReadOnlyList<BaseItem> GetThemeSongs() + public IReadOnlyList<BaseItem> GetThemeSongs(User user = null) + { + return GetThemeSongs(user, Array.Empty<(ItemSortBy, SortOrder)>()); + } + + public IReadOnlyList<BaseItem> GetThemeSongs(User user, IEnumerable<(ItemSortBy SortBy, SortOrder SortOrder)> orderBy) + { + return LibraryManager.Sort(GetExtras().Where(e => e.ExtraType == Model.Entities.ExtraType.ThemeSong), user, orderBy).ToArray(); + } + + public IReadOnlyList<BaseItem> GetThemeVideos(User user = null) { - return GetExtras().Where(e => e.ExtraType == Model.Entities.ExtraType.ThemeSong).ToArray(); + return GetThemeVideos(user, Array.Empty<(ItemSortBy, SortOrder)>()); } - public IReadOnlyList<BaseItem> GetThemeVideos() + public IReadOnlyList<BaseItem> GetThemeVideos(User user, IEnumerable<(ItemSortBy SortBy, SortOrder SortOrder)> orderBy) { - return GetExtras().Where(e => e.ExtraType == Model.Entities.ExtraType.ThemeVideo).ToArray(); + return LibraryManager.Sort(GetExtras().Where(e => e.ExtraType == Model.Entities.ExtraType.ThemeVideo), user, orderBy).ToArray(); } /// <summary> diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index 676a47c88..4ead477f8 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -316,11 +316,12 @@ namespace MediaBrowser.Controller.Entities /// <param name="progress">The progress.</param> /// <param name="recursive">if set to <c>true</c> [recursive].</param> /// <param name="refreshChildMetadata">if set to <c>true</c> [refresh child metadata].</param> + /// <param name="allowRemoveRoot">remove item even this folder is root.</param> /// <param name="refreshOptions">The refresh options.</param> /// <param name="directoryService">The directory service.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - protected override Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) + protected override Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, bool allowRemoveRoot, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) { return Task.CompletedTask; } diff --git a/MediaBrowser.Controller/Entities/Extensions.cs b/MediaBrowser.Controller/Entities/Extensions.cs index 3005bee0a..c56603a3e 100644 --- a/MediaBrowser.Controller/Entities/Extensions.cs +++ b/MediaBrowser.Controller/Entities/Extensions.cs @@ -30,15 +30,11 @@ namespace MediaBrowser.Controller.Entities if (item.RemoteTrailers.Count == 0) { - item.RemoteTrailers = new[] { mediaUrl }; + item.RemoteTrailers = [mediaUrl]; } else { - var oldIds = item.RemoteTrailers; - var newIds = new MediaUrl[oldIds.Count + 1]; - oldIds.CopyTo(newIds); - newIds[oldIds.Count] = mediaUrl; - item.RemoteTrailers = newIds; + item.RemoteTrailers = [..item.RemoteTrailers, mediaUrl]; } } } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index a2957cdca..b2e5d7263 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Security; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; @@ -269,11 +270,12 @@ namespace MediaBrowser.Controller.Entities /// <param name="progress">The progress.</param> /// <param name="metadataRefreshOptions">The metadata refresh options.</param> /// <param name="recursive">if set to <c>true</c> [recursive].</param> + /// <param name="allowRemoveRoot">remove item even this folder is root.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - public Task ValidateChildren(IProgress<double> progress, MetadataRefreshOptions metadataRefreshOptions, bool recursive = true, CancellationToken cancellationToken = default) + public Task ValidateChildren(IProgress<double> progress, MetadataRefreshOptions metadataRefreshOptions, bool recursive = true, bool allowRemoveRoot = false, CancellationToken cancellationToken = default) { - return ValidateChildrenInternal(progress, recursive, true, metadataRefreshOptions, metadataRefreshOptions.DirectoryService, cancellationToken); + return ValidateChildrenInternal(progress, recursive, true, allowRemoveRoot, metadataRefreshOptions, metadataRefreshOptions.DirectoryService, cancellationToken); } private Dictionary<Guid, BaseItem> GetActualChildrenDictionary() @@ -307,11 +309,12 @@ namespace MediaBrowser.Controller.Entities /// <param name="progress">The progress.</param> /// <param name="recursive">if set to <c>true</c> [recursive].</param> /// <param name="refreshChildMetadata">if set to <c>true</c> [refresh child metadata].</param> + /// <param name="allowRemoveRoot">remove item even this folder is root.</param> /// <param name="refreshOptions">The refresh options.</param> /// <param name="directoryService">The directory service.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - protected virtual async Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) + protected virtual async Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, bool allowRemoveRoot, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) { if (recursive) { @@ -320,7 +323,7 @@ namespace MediaBrowser.Controller.Entities try { - await ValidateChildrenInternal2(progress, recursive, refreshChildMetadata, refreshOptions, directoryService, cancellationToken).ConfigureAwait(false); + await ValidateChildrenInternal2(progress, recursive, refreshChildMetadata, allowRemoveRoot, refreshOptions, directoryService, cancellationToken).ConfigureAwait(false); } finally { @@ -331,8 +334,13 @@ namespace MediaBrowser.Controller.Entities } } - private static bool IsLibraryFolderAccessible(IDirectoryService directoryService, BaseItem item) + private static bool IsLibraryFolderAccessible(IDirectoryService directoryService, BaseItem item, bool checkCollection) { + if (!checkCollection && (item is BoxSet || string.Equals(item.FileNameWithoutExtension, "collections", StringComparison.OrdinalIgnoreCase))) + { + return true; + } + // For top parents i.e. Library folders, skip the validation if it's empty or inaccessible if (item.IsTopParent && !directoryService.IsAccessible(item.ContainingFolderPath)) { @@ -343,9 +351,9 @@ namespace MediaBrowser.Controller.Entities return true; } - private async Task ValidateChildrenInternal2(IProgress<double> progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) + private async Task ValidateChildrenInternal2(IProgress<double> progress, bool recursive, bool refreshChildMetadata, bool allowRemoveRoot, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) { - if (!IsLibraryFolderAccessible(directoryService, this)) + if (!IsLibraryFolderAccessible(directoryService, this, allowRemoveRoot)) { return; } @@ -357,15 +365,23 @@ namespace MediaBrowser.Controller.Entities if (IsFileProtocol) { - IEnumerable<BaseItem> nonCachedChildren; + IEnumerable<BaseItem> nonCachedChildren = []; try { nonCachedChildren = GetNonCachedChildren(directoryService); } + catch (IOException ex) + { + Logger.LogError(ex, "Error retrieving children from file system"); + } + catch (SecurityException ex) + { + Logger.LogError(ex, "Error retrieving children from file system"); + } catch (Exception ex) { - Logger.LogError(ex, "Error retrieving children folder"); + Logger.LogError(ex, "Error retrieving children"); return; } @@ -386,7 +402,7 @@ namespace MediaBrowser.Controller.Entities foreach (var child in nonCachedChildren) { - if (!IsLibraryFolderAccessible(directoryService, child)) + if (!IsLibraryFolderAccessible(directoryService, child, allowRemoveRoot)) { continue; } @@ -414,12 +430,12 @@ namespace MediaBrowser.Controller.Entities validChildren.Add(child); } + // That's all the new and changed ones - now see if any have been removed and need cleanup + var itemsRemoved = currentChildren.Values.Except(validChildren).ToList(); + var shouldRemove = !IsRoot || allowRemoveRoot; // If it's an AggregateFolder, don't remove - if (!IsRoot && currentChildren.Count != validChildren.Count) + if (shouldRemove && itemsRemoved.Count > 0) { - // That's all the new and changed ones - now see if there are any that are missing - var itemsRemoved = currentChildren.Values.Except(validChildren).ToList(); - foreach (var item in itemsRemoved) { if (item.IsFileProtocol) @@ -460,15 +476,7 @@ namespace MediaBrowser.Controller.Entities progress.Report(percent); - // TODO: this is sometimes being called after the refresh has completed. - try - { - ProviderManager.OnRefreshProgress(folder, percent); - } - catch (InvalidOperationException e) - { - Logger.LogError(e, "Error refreshing folder"); - } + ProviderManager.OnRefreshProgress(folder, percent); }); if (validChildrenNeedGeneration) @@ -500,15 +508,7 @@ namespace MediaBrowser.Controller.Entities if (recursive) { - // TODO: this is sometimes being called after the refresh has completed. - try - { - ProviderManager.OnRefreshProgress(folder, percent); - } - catch (InvalidOperationException e) - { - Logger.LogError(e, "Error refreshing folder"); - } + ProviderManager.OnRefreshProgress(folder, percent); } }); @@ -578,7 +578,7 @@ namespace MediaBrowser.Controller.Entities private Task ValidateSubFolders(IList<Folder> children, IDirectoryService directoryService, IProgress<double> progress, CancellationToken cancellationToken) { return RunTasks( - (folder, innerProgress) => folder.ValidateChildrenInternal(innerProgress, true, false, null, directoryService, cancellationToken), + (folder, innerProgress) => folder.ValidateChildrenInternal(innerProgress, true, false, false, null, directoryService, cancellationToken), children, progress, cancellationToken); @@ -603,7 +603,7 @@ namespace MediaBrowser.Controller.Entities } var fanoutConcurrency = ConfigurationManager.Configuration.LibraryScanFanoutConcurrency; - var parallelism = fanoutConcurrency > 0 ? fanoutConcurrency : 2 * Environment.ProcessorCount; + var parallelism = fanoutConcurrency > 0 ? fanoutConcurrency : Environment.ProcessorCount; var actionBlock = new ActionBlock<int>( async i => diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 555dd050c..1461a3680 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -51,6 +51,7 @@ namespace MediaBrowser.Controller.Entities TrailerTypes = Array.Empty<TrailerType>(); VideoTypes = Array.Empty<VideoType>(); Years = Array.Empty<int>(); + SkipDeserialization = false; } public InternalItemsQuery(User? user) @@ -358,6 +359,8 @@ namespace MediaBrowser.Controller.Entities public string? SeriesTimerId { get; set; } + public bool SkipDeserialization { get; set; } + public void SetUser(User user) { MaxParentalRating = user.MaxParentalAgeRating; diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 81f6248fa..710b05e7f 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -45,9 +45,6 @@ namespace MediaBrowser.Controller.Entities.Movies set => TmdbCollectionName = value; } - [JsonIgnore] - public override bool StopRefreshIfLocalMetadataFound => false; - public override double GetDefaultPrimaryImageAspectRatio() { // hack for tv plugins @@ -124,23 +121,5 @@ namespace MediaBrowser.Controller.Entities.Movies return hasChanges; } - - /// <inheritdoc /> - public override List<ExternalUrl> GetRelatedUrls() - { - var list = base.GetRelatedUrls(); - - var imdbId = this.GetProviderId(MetadataProvider.Imdb); - if (!string.IsNullOrEmpty(imdbId)) - { - list.Add(new ExternalUrl - { - Name = "Trakt", - Url = string.Format(CultureInfo.InvariantCulture, "https://trakt.tv/movies/{0}", imdbId) - }); - } - - return list; - } } } diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index 37e241414..5c54f014c 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -344,22 +344,5 @@ namespace MediaBrowser.Controller.Entities.TV return hasChanges; } - - public override List<ExternalUrl> GetRelatedUrls() - { - var list = base.GetRelatedUrls(); - - var imdbId = this.GetProviderId(MetadataProvider.Imdb); - if (!string.IsNullOrEmpty(imdbId)) - { - list.Add(new ExternalUrl - { - Name = "Trakt", - Url = string.Format(CultureInfo.InvariantCulture, "https://trakt.tv/episodes/{0}", imdbId) - }); - } - - return list; - } } } diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index c29cefc15..083f12746 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -159,7 +159,7 @@ namespace MediaBrowser.Controller.Entities.TV Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); - var items = GetEpisodes(user, query.DtoOptions).Where(filter); + var items = GetEpisodes(user, query.DtoOptions, true).Where(filter); return PostFilterAndSort(items, query, false); } @@ -169,30 +169,31 @@ namespace MediaBrowser.Controller.Entities.TV /// </summary> /// <param name="user">The user.</param> /// <param name="options">The options to use.</param> + /// <param name="shouldIncludeMissingEpisodes">If missing episodes should be included.</param> /// <returns>Set of episodes.</returns> - public List<BaseItem> GetEpisodes(User user, DtoOptions options) + public List<BaseItem> GetEpisodes(User user, DtoOptions options, bool shouldIncludeMissingEpisodes) { - return GetEpisodes(Series, user, options); + return GetEpisodes(Series, user, options, shouldIncludeMissingEpisodes); } - public List<BaseItem> GetEpisodes(Series series, User user, DtoOptions options) + public List<BaseItem> GetEpisodes(Series series, User user, DtoOptions options, bool shouldIncludeMissingEpisodes) { - return GetEpisodes(series, user, null, options); + return GetEpisodes(series, user, null, options, shouldIncludeMissingEpisodes); } - public List<BaseItem> GetEpisodes(Series series, User user, IEnumerable<Episode> allSeriesEpisodes, DtoOptions options) + public List<BaseItem> GetEpisodes(Series series, User user, IEnumerable<Episode> allSeriesEpisodes, DtoOptions options, bool shouldIncludeMissingEpisodes) { - return series.GetSeasonEpisodes(this, user, allSeriesEpisodes, options); + return series.GetSeasonEpisodes(this, user, allSeriesEpisodes, options, shouldIncludeMissingEpisodes); } public List<BaseItem> GetEpisodes() { - return Series.GetSeasonEpisodes(this, null, null, new DtoOptions(true)); + return Series.GetSeasonEpisodes(this, null, null, new DtoOptions(true), true); } public override List<BaseItem> GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query) { - return GetEpisodes(user, new DtoOptions(true)); + return GetEpisodes(user, new DtoOptions(true), true); } protected override bool GetBlockUnratedValue(User user) diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index a49c1609d..a324f79ef 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -28,7 +28,6 @@ namespace MediaBrowser.Controller.Entities.TV public Series() { AirDays = Array.Empty<DayOfWeek>(); - SeasonNames = new Dictionary<int, string>(); } public DayOfWeek[] AirDays { get; set; } @@ -36,9 +35,6 @@ namespace MediaBrowser.Controller.Entities.TV public string AirTime { get; set; } [JsonIgnore] - public Dictionary<int, string> SeasonNames { get; set; } - - [JsonIgnore] public override bool SupportsAddingToPlaylist => true; [JsonIgnore] @@ -73,9 +69,6 @@ namespace MediaBrowser.Controller.Entities.TV /// <value>The status.</value> public SeriesStatus? Status { get; set; } - [JsonIgnore] - public override bool StopRefreshIfLocalMetadataFound => false; - public override double GetDefaultPrimaryImageAspectRatio() { double value = 2; @@ -257,7 +250,7 @@ namespace MediaBrowser.Controller.Entities.TV return LibraryManager.GetItemsResult(query); } - public IEnumerable<BaseItem> GetEpisodes(User user, DtoOptions options) + public IEnumerable<BaseItem> GetEpisodes(User user, DtoOptions options, bool shouldIncludeMissingEpisodes) { var seriesKey = GetUniqueSeriesKey(this); @@ -267,10 +260,10 @@ namespace MediaBrowser.Controller.Entities.TV SeriesPresentationUniqueKey = seriesKey, IncludeItemTypes = new[] { BaseItemKind.Episode, BaseItemKind.Season }, OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) }, - DtoOptions = options + DtoOptions = options, }; - if (user is null || !user.DisplayMissingEpisodes) + if (!shouldIncludeMissingEpisodes) { query.IsMissing = false; } @@ -280,7 +273,7 @@ namespace MediaBrowser.Controller.Entities.TV var allSeriesEpisodes = allItems.OfType<Episode>().ToList(); var allEpisodes = allItems.OfType<Season>() - .SelectMany(i => i.GetEpisodes(this, user, allSeriesEpisodes, options)) + .SelectMany(i => i.GetEpisodes(this, user, allSeriesEpisodes, options, shouldIncludeMissingEpisodes)) .Reverse(); // Specials could appear twice based on above - once in season 0, once in the aired season @@ -292,8 +285,7 @@ namespace MediaBrowser.Controller.Entities.TV public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken) { - // Refresh bottom up, children first, then the boxset - // By then hopefully the movies within will have Tmdb collection values + // Refresh bottom up, seasons and episodes first, then the series var items = GetRecursiveChildren(); var totalItems = items.Count; @@ -356,7 +348,7 @@ namespace MediaBrowser.Controller.Entities.TV await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false); } - public List<BaseItem> GetSeasonEpisodes(Season parentSeason, User user, DtoOptions options) + public List<BaseItem> GetSeasonEpisodes(Season parentSeason, User user, DtoOptions options, bool shouldIncludeMissingEpisodes) { var queryFromSeries = ConfigurationManager.Configuration.DisplaySpecialsWithinSeasons; @@ -373,24 +365,22 @@ namespace MediaBrowser.Controller.Entities.TV OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) }, DtoOptions = options }; - if (user is not null) + + if (!shouldIncludeMissingEpisodes) { - if (!user.DisplayMissingEpisodes) - { - query.IsMissing = false; - } + query.IsMissing = false; } var allItems = LibraryManager.GetItemList(query); - return GetSeasonEpisodes(parentSeason, user, allItems, options); + return GetSeasonEpisodes(parentSeason, user, allItems, options, shouldIncludeMissingEpisodes); } - public List<BaseItem> GetSeasonEpisodes(Season parentSeason, User user, IEnumerable<BaseItem> allSeriesEpisodes, DtoOptions options) + public List<BaseItem> GetSeasonEpisodes(Season parentSeason, User user, IEnumerable<BaseItem> allSeriesEpisodes, DtoOptions options, bool shouldIncludeMissingEpisodes) { if (allSeriesEpisodes is null) { - return GetSeasonEpisodes(parentSeason, user, options); + return GetSeasonEpisodes(parentSeason, user, options, shouldIncludeMissingEpisodes); } var episodes = FilterEpisodesBySeason(allSeriesEpisodes, parentSeason, ConfigurationManager.Configuration.DisplaySpecialsWithinSeasons); @@ -499,22 +489,5 @@ namespace MediaBrowser.Controller.Entities.TV return hasChanges; } - - public override List<ExternalUrl> GetRelatedUrls() - { - var list = base.GetRelatedUrls(); - - var imdbId = this.GetProviderId(MetadataProvider.Imdb); - if (!string.IsNullOrEmpty(imdbId)) - { - list.Add(new ExternalUrl - { - Name = "Trakt", - Url = string.Format(CultureInfo.InvariantCulture, "https://trakt.tv/shows/{0}", imdbId) - }); - } - - return list; - } } } diff --git a/MediaBrowser.Controller/Entities/TagExtensions.cs b/MediaBrowser.Controller/Entities/TagExtensions.cs index ec3eb0f70..c1e4d1db2 100644 --- a/MediaBrowser.Controller/Entities/TagExtensions.cs +++ b/MediaBrowser.Controller/Entities/TagExtensions.cs @@ -21,11 +21,11 @@ namespace MediaBrowser.Controller.Entities { if (current.Length == 0) { - item.Tags = new[] { name }; + item.Tags = [name]; } else { - item.Tags = current.Concat(new[] { name }).ToArray(); + item.Tags = [..current, name]; } } } diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index 1c558d419..939709215 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -23,9 +23,6 @@ namespace MediaBrowser.Controller.Entities TrailerTypes = Array.Empty<TrailerType>(); } - [JsonIgnore] - public override bool StopRefreshIfLocalMetadataFound => false; - public TrailerType[] TrailerTypes { get; set; } public override double GetDefaultPrimaryImageAspectRatio() @@ -83,22 +80,5 @@ namespace MediaBrowser.Controller.Entities return hasChanges; } - - public override List<ExternalUrl> GetRelatedUrls() - { - var list = base.GetRelatedUrls(); - - var imdbId = this.GetProviderId(MetadataProvider.Imdb); - if (!string.IsNullOrEmpty(imdbId)) - { - list.Add(new ExternalUrl - { - Name = "Trakt", - Url = string.Format(CultureInfo.InvariantCulture, "https://trakt.tv/movies/{0}", imdbId) - }); - } - - return list; - } } } diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index 69743b926..fc8a29763 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -117,11 +117,11 @@ namespace MediaBrowser.Controller.Entities return base.GetNonCachedChildren(directoryService); } - protected override async Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) + protected override async Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, bool allowRemoveRoot, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) { ClearCache(); - await base.ValidateChildrenInternal(progress, recursive, refreshChildMetadata, refreshOptions, directoryService, cancellationToken) + await base.ValidateChildrenInternal(progress, recursive, refreshChildMetadata, allowRemoveRoot, refreshOptions, directoryService, cancellationToken) .ConfigureAwait(false); ClearCache(); diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index c93488a85..e4fb340f7 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -6,10 +6,12 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text.Json.Serialization; +using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Extensions; +using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.TV; using MediaBrowser.Model.Querying; @@ -180,7 +182,7 @@ namespace MediaBrowser.Controller.Entities return _originalFolderViewTypes.Contains(viewType); } - protected override Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, Providers.MetadataRefreshOptions refreshOptions, Providers.IDirectoryService directoryService, System.Threading.CancellationToken cancellationToken) + protected override Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, bool allowRemoveRoot, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken) { return Task.CompletedTask; } diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 4af000557..3a1d0c070 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -744,7 +744,7 @@ namespace MediaBrowser.Controller.Entities { var filterValue = query.HasThemeSong.Value; - var themeCount = item.GetThemeSongs().Count; + var themeCount = item.GetThemeSongs(user).Count; var ok = filterValue ? themeCount > 0 : themeCount == 0; if (!ok) @@ -757,7 +757,7 @@ namespace MediaBrowser.Controller.Entities { var filterValue = query.HasThemeVideo.Value; - var themeCount = item.GetThemeVideos().Count; + var themeCount = item.GetThemeVideos(user).Count; var ok = filterValue ? themeCount > 0 : themeCount == 0; if (!ok) |
