aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Controller')
-rw-r--r--MediaBrowser.Controller/Dto/DtoOptions.cs56
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs23
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs7
-rw-r--r--MediaBrowser.Controller/Entities/TagExtensions.cs1
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs7
-rw-r--r--MediaBrowser.Controller/IO/IExternalDataManager.cs7
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);
}