aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller/Entities/BaseItem.cs
diff options
context:
space:
mode:
authorShadowghost <Ghost_of_Stone@web.de>2026-05-04 21:26:26 +0200
committerShadowghost <Ghost_of_Stone@web.de>2026-05-04 21:26:26 +0200
commit57c0fcd674c659c658369f0aebfd5d9d6787a9d4 (patch)
tree7aff23d6f54e913a6a34cb5a2568a07298582444 /MediaBrowser.Controller/Entities/BaseItem.cs
parent68ab58589444091925c15ad20d36f935b7bc2e21 (diff)
parentec04313317bed62728b059108cd232e9744f6354 (diff)
Merge remote-tracking branch 'upstream/master' into epg-fixes
Diffstat (limited to 'MediaBrowser.Controller/Entities/BaseItem.cs')
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs146
1 files changed, 111 insertions, 35 deletions
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index e312e9d80b..822b21c062 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -106,7 +106,6 @@ namespace MediaBrowser.Controller.Entities
ImageInfos = Array.Empty<ItemImageInfo>();
ProductionLocations = Array.Empty<string>();
RemoteTrailers = Array.Empty<MediaUrl>();
- ExtraIds = Array.Empty<Guid>();
UserData = [];
}
@@ -397,8 +396,6 @@ namespace MediaBrowser.Controller.Entities
public int Height { get; set; }
- public Guid[] ExtraIds { get; set; }
-
/// <summary>
/// Gets the primary image path.
/// </summary>
@@ -491,6 +488,8 @@ namespace MediaBrowser.Controller.Entities
public static IItemRepository ItemRepository { get; set; }
+ public static IItemCountService ItemCountService { get; set; }
+
public static IChapterManager ChapterManager { get; set; }
public static IFileSystem FileSystem { get; set; }
@@ -1340,14 +1339,15 @@ namespace MediaBrowser.Controller.Entities
return false;
}
- if (GetParents().Any(i => !i.IsVisible(user, true)))
+ var parents = GetParents().ToList();
+ if (parents.Any(i => !i.IsVisible(user, true)))
{
return false;
}
if (checkFolders)
{
- var topParent = GetParents().LastOrDefault() ?? this;
+ var topParent = parents.Count > 0 ? parents[^1] : this;
if (string.IsNullOrEmpty(topParent.Path))
{
@@ -1358,8 +1358,27 @@ namespace MediaBrowser.Controller.Entities
if (itemCollectionFolders.Count > 0)
{
- var userCollectionFolders = LibraryManager.GetUserRootFolder().GetChildren(user, true).Select(i => i.Id).ToList();
- if (!itemCollectionFolders.Any(userCollectionFolders.Contains))
+ var blockedMediaFolders = user.GetPreferenceValues<Guid>(PreferenceKind.BlockedMediaFolders);
+ IEnumerable<Guid> userCollectionFolderIds;
+ if (blockedMediaFolders.Length > 0)
+ {
+ // User has blocked folders - get all library folders and exclude blocked ones
+ userCollectionFolderIds = LibraryManager.GetUserRootFolder().Children
+ .Select(i => i.Id)
+ .Where(id => !blockedMediaFolders.Contains(id));
+ }
+ else if (user.HasPermission(PermissionKind.EnableAllFolders))
+ {
+ // User can access all folders - no need to filter
+ return true;
+ }
+ else
+ {
+ // User has specific enabled folders
+ userCollectionFolderIds = user.GetPreferenceValues<Guid>(PreferenceKind.EnabledFolders);
+ }
+
+ if (!itemCollectionFolders.Any(userCollectionFolderIds.Contains))
{
return false;
}
@@ -1401,7 +1420,13 @@ namespace MediaBrowser.Controller.Entities
{
var extras = LibraryManager.FindExtras(item, fileSystemChildren, options.DirectoryService).ToArray();
var newExtraIds = Array.ConvertAll(extras, x => x.Id);
- var extrasChanged = !item.ExtraIds.SequenceEqual(newExtraIds);
+
+ var currentExtraIds = LibraryManager.GetItemList(new InternalItemsQuery()
+ {
+ OwnerIds = [item.Id]
+ }).Select(e => e.Id).ToArray();
+
+ var extrasChanged = !currentExtraIds.OrderBy(x => x).SequenceEqual(newExtraIds.OrderBy(x => x));
if (!extrasChanged && !options.ReplaceAllMetadata && options.MetadataRefreshMode != MetadataRefreshMode.FullRefresh)
{
@@ -1415,16 +1440,15 @@ namespace MediaBrowser.Controller.Entities
var subOptions = new MetadataRefreshOptions(options);
if (!i.OwnerId.Equals(ownerId) || !i.ParentId.IsEmpty())
{
- i.OwnerId = ownerId;
- i.ParentId = Guid.Empty;
subOptions.ForceSave = true;
}
+ i.OwnerId = ownerId;
+ i.ParentId = Guid.Empty;
return RefreshMetadataForOwnedItem(i, true, subOptions, cancellationToken);
});
- // Cleanup removed extras
- var removedExtraIds = item.ExtraIds.Where(e => !newExtraIds.Contains(e)).ToArray();
+ var removedExtraIds = currentExtraIds.Where(e => !newExtraIds.Contains(e)).ToArray();
if (removedExtraIds.Length > 0)
{
var removedExtras = LibraryManager.GetItemList(new InternalItemsQuery()
@@ -1433,17 +1457,20 @@ namespace MediaBrowser.Controller.Entities
});
foreach (var removedExtra in removedExtras)
{
- LibraryManager.DeleteItem(removedExtra, new DeleteOptions()
+ // Only delete items that are actual extras (have ExtraType set)
+ // Items with OwnerId but no ExtraType might be alternate versions, not extras
+ if (removedExtra.ExtraType.HasValue)
{
- DeleteFileLocation = false
- });
+ LibraryManager.DeleteItem(removedExtra, new DeleteOptions()
+ {
+ DeleteFileLocation = false
+ });
+ }
}
}
await Task.WhenAll(tasks).ConfigureAwait(false);
- item.ExtraIds = newExtraIds;
-
return true;
}
@@ -1673,10 +1700,28 @@ namespace MediaBrowser.Controller.Entities
return list.Distinct(StringComparer.OrdinalIgnoreCase).ToList();
}
- private bool IsVisibleViaTags(User user, bool skipAllowedTagsCheck)
+ protected bool IsVisibleViaTags(User user, bool skipAllowedTagsCheck)
{
- var allTags = GetInheritedTags();
- if (user.GetPreference(PreferenceKind.BlockedTags).Any(i => allTags.Contains(i, StringComparison.OrdinalIgnoreCase)))
+ var blockedTags = user.GetPreference(PreferenceKind.BlockedTags);
+ var allowedTags = user.GetPreference(PreferenceKind.AllowedTags);
+
+ if (blockedTags.Length == 0 && allowedTags.Length == 0)
+ {
+ return true;
+ }
+
+ // Normalize tags using the same logic as database queries
+ var normalizedBlockedTags = blockedTags
+ .Where(t => !string.IsNullOrWhiteSpace(t))
+ .Select(t => t.GetCleanValue())
+ .ToHashSet(StringComparer.Ordinal);
+
+ var normalizedItemTags = GetInheritedTags()
+ .Select(t => t.GetCleanValue())
+ .ToHashSet(StringComparer.Ordinal);
+
+ // Check blocked tags - item is hidden if it has any blocked tag
+ if (normalizedBlockedTags.Overlaps(normalizedItemTags))
{
return false;
}
@@ -1687,10 +1732,18 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- var allowedTagsPreference = user.GetPreference(PreferenceKind.AllowedTags);
- if (!skipAllowedTagsCheck && allowedTagsPreference.Length != 0 && !allowedTagsPreference.Any(i => allTags.Contains(i, StringComparison.OrdinalIgnoreCase)))
+ // Check allowed tags - item must have at least one allowed tag
+ if (!skipAllowedTagsCheck && allowedTags.Length > 0)
{
- return false;
+ var normalizedAllowedTags = allowedTags
+ .Where(t => !string.IsNullOrWhiteSpace(t))
+ .Select(t => t.GetCleanValue())
+ .ToHashSet(StringComparer.Ordinal);
+
+ if (!normalizedAllowedTags.Overlaps(normalizedItemTags))
+ {
+ return false;
+ }
}
return true;
@@ -1803,10 +1856,23 @@ namespace MediaBrowser.Controller.Entities
return item;
}
+#pragma warning disable CS0618 // Type or member is obsolete - fallback for legacy LinkedChild data
private BaseItem FindLinkedChild(LinkedChild info)
{
- var path = info.Path;
+ // First try to find by ItemId (new preferred method)
+ if (info.ItemId.HasValue && !info.ItemId.Value.Equals(Guid.Empty))
+ {
+ var item = LibraryManager.GetItemById(info.ItemId.Value);
+ if (item is not null)
+ {
+ return item;
+ }
+
+ Logger.LogWarning("Unable to find linked item by ItemId {0}", info.ItemId);
+ }
+ // Fall back to Path (legacy method)
+ var path = info.Path;
if (!string.IsNullOrEmpty(path))
{
path = FileSystem.MakeAbsolutePath(ContainingFolderPath, path);
@@ -1821,13 +1887,14 @@ namespace MediaBrowser.Controller.Entities
return itemByPath;
}
+ // Fall back to LibraryItemId (legacy method)
if (!string.IsNullOrEmpty(info.LibraryItemId))
{
var item = LibraryManager.GetItemById(info.LibraryItemId);
if (item is null)
{
- Logger.LogWarning("Unable to find linked item at path {0}", info.Path);
+ Logger.LogWarning("Unable to find linked item by LibraryItemId {0}", info.LibraryItemId);
}
return item;
@@ -1835,6 +1902,7 @@ namespace MediaBrowser.Controller.Entities
return null;
}
+#pragma warning restore CS0618
/// <summary>
/// Adds a studio to the item.
@@ -2415,7 +2483,13 @@ namespace MediaBrowser.Controller.Entities
return path;
}
- public virtual void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, DtoOptions fields)
+ public virtual void FillUserDataDtoValues(
+ UserItemDataDto dto,
+ UserItemData userData,
+ BaseItemDto itemDto,
+ User user,
+ DtoOptions fields,
+ (int Played, int Total)? precomputedCounts = null)
{
if (RunTimeTicks.HasValue)
{
@@ -2654,10 +2728,11 @@ namespace MediaBrowser.Controller.Entities
/// <returns>An enumerable containing the items.</returns>
public IEnumerable<BaseItem> GetExtras()
{
- return ExtraIds
- .Select(LibraryManager.GetItemById)
- .Where(i => i is not null)
- .OrderBy(i => i.SortName);
+ return LibraryManager.GetItemList(new InternalItemsQuery()
+ {
+ OwnerIds = [Id],
+ OrderBy = [(ItemSortBy.SortName, SortOrder.Ascending)]
+ });
}
/// <summary>
@@ -2667,11 +2742,12 @@ namespace MediaBrowser.Controller.Entities
/// <returns>An enumerable containing the extras.</returns>
public IEnumerable<BaseItem> GetExtras(IReadOnlyCollection<ExtraType> extraTypes)
{
- return ExtraIds
- .Select(LibraryManager.GetItemById)
- .Where(i => i is not null)
- .Where(i => i.ExtraType.HasValue && extraTypes.Contains(i.ExtraType.Value))
- .OrderBy(i => i.SortName);
+ return LibraryManager.GetItemList(new InternalItemsQuery()
+ {
+ OwnerIds = [Id],
+ ExtraTypes = extraTypes.ToArray(),
+ OrderBy = [(ItemSortBy.SortName, SortOrder.Ascending)]
+ });
}
public virtual long GetRunTimeTicksForPlayState()