diff options
Diffstat (limited to 'MediaBrowser.Controller')
| -rw-r--r-- | MediaBrowser.Controller/Dto/DtoOptions.cs | 56 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/BaseItem.cs | 23 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Folder.cs | 7 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/TagExtensions.cs | 1 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Video.cs | 7 | ||||
| -rw-r--r-- | MediaBrowser.Controller/IO/IExternalDataManager.cs | 7 |
6 files changed, 76 insertions, 25 deletions
diff --git a/MediaBrowser.Controller/Dto/DtoOptions.cs b/MediaBrowser.Controller/Dto/DtoOptions.cs index a71cdbd62c..d319feb6b2 100644 --- a/MediaBrowser.Controller/Dto/DtoOptions.cs +++ b/MediaBrowser.Controller/Dto/DtoOptions.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Generic; using System.Linq; @@ -8,13 +6,16 @@ using MediaBrowser.Model.Querying; namespace MediaBrowser.Controller.Dto { + /// <summary> + /// Options that control which fields and images are populated when building a <see cref="MediaBrowser.Model.Dto.BaseItemDto"/>. + /// </summary> public class DtoOptions { - private static readonly ItemFields[] DefaultExcludedFields = new[] - { + private static readonly ItemFields[] DefaultExcludedFields = + [ ItemFields.SeasonUserData, ItemFields.RefreshState - }; + ]; private static readonly ImageType[] AllImageTypes = Enum.GetValues<ImageType>(); @@ -22,11 +23,18 @@ namespace MediaBrowser.Controller.Dto .Except(DefaultExcludedFields) .ToArray(); + /// <summary> + /// Initializes a new instance of the <see cref="DtoOptions"/> class with all fields enabled. + /// </summary> public DtoOptions() : this(true) { } + /// <summary> + /// Initializes a new instance of the <see cref="DtoOptions"/> class. + /// </summary> + /// <param name="allFields">Whether to populate all available fields.</param> public DtoOptions(bool allFields) { ImageTypeLimit = int.MaxValue; @@ -38,23 +46,61 @@ namespace MediaBrowser.Controller.Dto ImageTypes = AllImageTypes; } + /// <summary> + /// Gets or sets the fields to populate on the DTO. + /// </summary> public IReadOnlyList<ItemFields> Fields { get; set; } + /// <summary> + /// Gets or sets the image types to populate on the DTO. + /// </summary> public IReadOnlyList<ImageType> ImageTypes { get; set; } + /// <summary> + /// Gets or sets the maximum number of images to return per image type. + /// </summary> public int ImageTypeLimit { get; set; } + /// <summary> + /// Gets or sets a value indicating whether image information is populated. + /// </summary> public bool EnableImages { get; set; } + /// <summary> + /// Gets or sets a value indicating whether program recording information is populated. + /// </summary> public bool AddProgramRecordingInfo { get; set; } + /// <summary> + /// Gets or sets a value indicating whether user data is populated. + /// </summary> public bool EnableUserData { get; set; } + /// <summary> + /// Gets or sets a value indicating whether the currently airing program is populated. + /// </summary> public bool AddCurrentProgram { get; set; } + /// <summary> + /// Gets or sets a value indicating whether an episode's portrait poster (its season's primary + /// image, falling back to the series') should replace the episode's own (16:9) primary image. + /// Used by views that render episodes as poster cards, e.g. "Latest". + /// </summary> + public bool PreferEpisodeParentPoster { get; set; } + + /// <summary> + /// Gets a value indicating whether the specified field is populated. + /// </summary> + /// <param name="field">The field to check.</param> + /// <returns><c>true</c> if the field is populated; otherwise, <c>false</c>.</returns> public bool ContainsField(ItemFields field) => Fields.Contains(field); + /// <summary> + /// Gets the number of images to return for the specified image type. + /// </summary> + /// <param name="type">The image type.</param> + /// <returns>The image limit for the type, or 0 if the type is not enabled.</returns> public int GetImageLimit(ImageType type) { if (EnableImages && ImageTypes.Contains(type)) diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index e24b60f69f..21304768bd 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -23,7 +23,6 @@ using MediaBrowser.Controller.Chapters; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Persistence; @@ -1134,15 +1133,7 @@ namespace MediaBrowser.Controller.Entities ArgumentNullException.ThrowIfNull(item); var protocol = item.PathProtocol; - - // Resolve the item path so everywhere we use the media source it will always point to - // the correct path even if symlinks are in use. Calling ResolveLinkTarget on a non-link - // path will return null, so it's safe to check for all paths. var itemPath = item.Path; - if (protocol is MediaProtocol.File && FileSystemHelper.ResolveLinkTarget(itemPath, returnFinalTarget: true) is { Exists: true } linkInfo) - { - itemPath = linkInfo.FullName; - } var info = new MediaSourceInfo { @@ -2727,7 +2718,7 @@ namespace MediaBrowser.Controller.Entities 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(); + return LibraryManager.Sort(GetExtras(user).Where(e => e.ExtraType == Model.Entities.ExtraType.ThemeSong), user, orderBy).ToArray(); } public IReadOnlyList<BaseItem> GetThemeVideos(User user = null) @@ -2737,16 +2728,17 @@ namespace MediaBrowser.Controller.Entities public IReadOnlyList<BaseItem> GetThemeVideos(User user, IEnumerable<(ItemSortBy SortBy, SortOrder SortOrder)> orderBy) { - return LibraryManager.Sort(GetExtras().Where(e => e.ExtraType == Model.Entities.ExtraType.ThemeVideo), user, orderBy).ToArray(); + return LibraryManager.Sort(GetExtras(user).Where(e => e.ExtraType == Model.Entities.ExtraType.ThemeVideo), user, orderBy).ToArray(); } /// <summary> /// Get all extras associated with this item, sorted by <see cref="SortName"/>. /// </summary> + /// <param name="user">The user to apply parental restrictions for, or <c>null</c> to skip restriction checks.</param> /// <returns>An enumerable containing the items.</returns> - public IEnumerable<BaseItem> GetExtras() + public IEnumerable<BaseItem> GetExtras(User user = null) { - return LibraryManager.GetItemList(new InternalItemsQuery() + return LibraryManager.GetItemList(new InternalItemsQuery(user) { OwnerIds = [Id], OrderBy = [(ItemSortBy.SortName, SortOrder.Ascending)] @@ -2757,10 +2749,11 @@ namespace MediaBrowser.Controller.Entities /// Get all extras with specific types that are associated with this item. /// </summary> /// <param name="extraTypes">The types of extras to retrieve.</param> + /// <param name="user">The user to apply parental restrictions for, or <c>null</c> to skip restriction checks.</param> /// <returns>An enumerable containing the extras.</returns> - public IEnumerable<BaseItem> GetExtras(IReadOnlyCollection<ExtraType> extraTypes) + public IEnumerable<BaseItem> GetExtras(IReadOnlyCollection<ExtraType> extraTypes, User user = null) { - return LibraryManager.GetItemList(new InternalItemsQuery() + return LibraryManager.GetItemList(new InternalItemsQuery(user) { OwnerIds = [Id], ExtraTypes = extraTypes.ToArray(), diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 5fa1213db3..25cbcedc5f 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -906,7 +906,10 @@ namespace MediaBrowser.Controller.Entities query.Parent = this; } - if (query.IncludeItemTypes.Length == 1 && query.IncludeItemTypes[0] == BaseItemKind.BoxSet) + // BoxSets and Playlists can have per-user visibility (shares/open access) that is stored in the + // serialized item data and cannot be evaluated by the database query, so filter them in memory. + if (query.IncludeItemTypes.Length > 0 + && query.IncludeItemTypes.All(t => t == BaseItemKind.BoxSet || t == BaseItemKind.Playlist)) { return QueryWithPostFiltering(query); } @@ -927,7 +930,7 @@ namespace MediaBrowser.Controller.Entities if (user is not null) { - // needed for boxsets + // needed for boxsets and playlists itemsList = itemsList.Where(i => i.IsVisibleStandalone(query.User)); } diff --git a/MediaBrowser.Controller/Entities/TagExtensions.cs b/MediaBrowser.Controller/Entities/TagExtensions.cs index 4ddba9835b..07c2298fce 100644 --- a/MediaBrowser.Controller/Entities/TagExtensions.cs +++ b/MediaBrowser.Controller/Entities/TagExtensions.cs @@ -15,6 +15,7 @@ namespace MediaBrowser.Controller.Entities throw new ArgumentNullException(nameof(name)); } + name = name.Trim(); var current = item.Tags; if (!current.Contains(name, StringComparison.OrdinalIgnoreCase)) diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 44cae5197a..e7a5672ebd 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -10,6 +10,7 @@ using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Enums; +using Jellyfin.Database.Implementations.Entities; using Jellyfin.Extensions; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; @@ -390,13 +391,13 @@ namespace MediaBrowser.Controller.Entities /// <summary> /// Gets the additional parts. /// </summary> + /// <param name="user">The user to apply parental restrictions for, or <c>null</c> to skip restriction checks.</param> /// <returns>IEnumerable{Video}.</returns> - public IOrderedEnumerable<Video> GetAdditionalParts() + public IOrderedEnumerable<Video> GetAdditionalParts(User user = null) { return GetAdditionalPartIds() - .Select(i => LibraryManager.GetItemById(i)) + .Select(i => LibraryManager.GetItemById<Video>(i, user)) .Where(i => i is not null) - .OfType<Video>() .OrderBy(i => i.SortName); } diff --git a/MediaBrowser.Controller/IO/IExternalDataManager.cs b/MediaBrowser.Controller/IO/IExternalDataManager.cs index f69f4586c6..b2eb8fc3f1 100644 --- a/MediaBrowser.Controller/IO/IExternalDataManager.cs +++ b/MediaBrowser.Controller/IO/IExternalDataManager.cs @@ -16,4 +16,11 @@ public interface IExternalDataManager /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> Task DeleteExternalItemDataAsync(BaseItem item, CancellationToken cancellationToken); + + /// <summary> + /// Deletes only the filesystem-side external item data (attachments, subtitles, trickplay, chapter images). + /// Use this when DB-side cleanup is already handled by another code path (e.g. <c>IItemPersistenceService.DeleteItem</c>). + /// </summary> + /// <param name="item">The item.</param> + void DeleteExternalItemFiles(BaseItem item); } |
