aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/Library
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations/Library')
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs50
-rw-r--r--Emby.Server.Implementations/Library/UserViewManager.cs50
2 files changed, 72 insertions, 28 deletions
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index caba304888..6f3df084c0 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -1354,7 +1354,6 @@ namespace Emby.Server.Implementations.Library
{
IncludeItemTypes = [BaseItemKind.MusicArtist],
Name = name,
- UseRawName = true,
DtoOptions = options
}).Cast<MusicArtist>()
.OrderBy(i => i.IsAccessedByName ? 1 : 0)
@@ -3467,6 +3466,7 @@ namespace Emby.Server.Implementations.Library
var extras = new List<BaseItem>();
var typeCounters = new Dictionary<ExtraType, int>();
+ var generatedNames = new Dictionary<ExtraType, HashSet<string>>();
// Order by path so that the numbering handed out below does not depend on the
// order the file system happened to list the folder in
@@ -3503,10 +3503,12 @@ namespace Emby.Server.Implementations.Library
extra = itemById;
}
- // An extra is named after its file, so the file is the source of truth. Items created
- // by older versions, or renamed by a metadata provider, are corrected here;
- // RefreshExtras persists the change.
- if (!string.IsNullOrEmpty(name) && extra.LockedFields?.Contains(MetadataField.Name) != true)
+ // The name derived from the file is only a default. A name that came from anywhere else,
+ // such as a local metadata file, is the user's and has to survive the scan, so only a
+ // name this method handed out itself is renewed; RefreshExtras persists the change.
+ if (!string.IsNullOrEmpty(name)
+ && extra.LockedFields?.Contains(MetadataField.Name) != true
+ && (itemById is null || IsGeneratedExtraName(extra.Name, candidate)))
{
extra.Name = name;
}
@@ -3528,6 +3530,31 @@ namespace Emby.Server.Implementations.Library
return null;
}
+
+ bool IsGeneratedExtraName(string currentName, ExtraCandidate candidate)
+ {
+ // The file name is what an extra was called before it was given a name of its type
+ if (string.Equals(currentName, candidate.Extra.Name, StringComparison.Ordinal))
+ {
+ return true;
+ }
+
+ if (!generatedNames.TryGetValue(candidate.ExtraType, out var names))
+ {
+ // Any of the numbers of this type may have been handed out, as the order the extras
+ // of a type are numbered in shifts as files appear beside them or are taken away
+ names = new HashSet<string>(StringComparer.Ordinal);
+ var count = candidates.Count(c => c.ExtraType == candidate.ExtraType);
+ for (var seen = 0; seen < count; seen++)
+ {
+ names.Add(GetNumberedExtraName(candidate.ExtraType, seen));
+ }
+
+ generatedNames[candidate.ExtraType] = names;
+ }
+
+ return names.Contains(currentName);
+ }
}
/// <summary>
@@ -3554,7 +3581,18 @@ namespace Emby.Server.Implementations.Library
typeCounters.TryGetValue(candidate.ExtraType, out var seen);
typeCounters[candidate.ExtraType] = seen + 1;
- var typeName = _localization.GetServerLocalizedString(GetExtraTypeNameKey(candidate.ExtraType));
+ return GetNumberedExtraName(candidate.ExtraType, seen);
+ }
+
+ /// <summary>
+ /// Gets the name given to the n-th extra of a type that is named after its type.
+ /// </summary>
+ /// <param name="extraType">The extra type.</param>
+ /// <param name="seen">Number of extras of the type named before this one.</param>
+ /// <returns>The name.</returns>
+ private string GetNumberedExtraName(ExtraType extraType, int seen)
+ {
+ var typeName = _localization.GetServerLocalizedString(GetExtraTypeNameKey(extraType));
return seen == 0
? typeName
diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs
index cfb2dd53d3..6d52ce7440 100644
--- a/Emby.Server.Implementations/Library/UserViewManager.cs
+++ b/Emby.Server.Implementations/Library/UserViewManager.cs
@@ -60,10 +60,16 @@ namespace Emby.Server.Implementations.Library
var folderViewType = collectionFolder?.CollectionType;
// Playlist and BoxSet libraries require special handling because the folder only references linked items
- if ((folderViewType == CollectionType.playlists || folderViewType == CollectionType.boxsets)
- && !HasVisibleChild(folder, user))
+ if (folderViewType == CollectionType.playlists || folderViewType == CollectionType.boxsets)
{
- continue;
+ var itemKind = folderViewType == CollectionType.playlists
+ ? BaseItemKind.Playlist
+ : BaseItemKind.BoxSet;
+
+ if (!HasVisibleItem(itemKind, folders, user))
+ {
+ continue;
+ }
}
if (UserView.IsUserSpecific(folder))
@@ -152,30 +158,30 @@ namespace Emby.Server.Implementations.Library
.ToArray();
}
- private bool HasVisibleChild(Folder folder, User user)
+ private bool HasVisibleItem(BaseItemKind itemKind, IReadOnlyList<Folder> folders, User user)
{
- // Folder.Children answers this too, but a collection folder delegates it to its physical
- // folders, which resolve and then hold on to every child with every field.
- var parentIds = folder is CollectionFolder collectionFolder && collectionFolder.PhysicalFolderIds.Length > 0
- ? collectionFolder.PhysicalFolderIds
- : [folder.Id];
+ var topParentIds = folders.SelectMany(GetTopParentIds).ToArray();
+ if (topParentIds.Length == 0)
+ {
+ return false;
+ }
- foreach (var parentId in parentIds)
+ var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
{
- var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
- {
- ParentId = parentId,
- GroupByPresentationUniqueKey = false,
- DtoOptions = DtoOptions.StoredColumnsOnly
- });
+ IncludeItemTypes = [itemKind],
+ TopParentIds = topParentIds,
+ GroupByPresentationUniqueKey = false,
+ DtoOptions = DtoOptions.StoredColumnsOnly
+ });
- if (items.Any(item => item.IsVisible(user)))
- {
- return true;
- }
- }
+ return items.Any(item => item.IsVisible(user));
+ }
- return false;
+ private static IEnumerable<Guid> GetTopParentIds(Folder folder)
+ {
+ return folder is CollectionFolder collectionFolder && collectionFolder.PhysicalFolderIds.Length > 0
+ ? collectionFolder.PhysicalFolderIds
+ : [folder.Id];
}
public UserView GetUserSubViewWithName(string name, Guid parentId, CollectionType? type, string sortName)