aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/Library
diff options
context:
space:
mode:
authorRonan Charles-Lorel <roro.roronoa@gmail.com>2023-06-29 15:08:52 +0200
committerGitHub <noreply@github.com>2023-06-29 15:08:52 +0200
commite108183b138552013bbfd13c36937481228eb9e6 (patch)
tree8e374adf35d64b157ac88e5b84a25d186bd4ccf1 /Emby.Server.Implementations/Library
parent31ac861b8560547c7e0c46513077abf76e6bc618 (diff)
parentb5bbb98175e0542d43c01f80c15e8dce04e58b53 (diff)
Merge branch 'jellyfin:master' into master
Diffstat (limited to 'Emby.Server.Implementations/Library')
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs62
-rw-r--r--Emby.Server.Implementations/Library/MediaSourceManager.cs4
-rw-r--r--Emby.Server.Implementations/Library/PathExtensions.cs98
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs6
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs7
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs15
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs26
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/ExtraResolver.cs17
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/GenericVideoResolver.cs6
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs22
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs18
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs11
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs6
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs26
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs6
-rw-r--r--Emby.Server.Implementations/Library/UserViewManager.cs26
16 files changed, 249 insertions, 107 deletions
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index a3c66dc79..ea45bf0ba 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -113,6 +113,7 @@ namespace Emby.Server.Implementations.Library
/// <param name="imageProcessor">The image processor.</param>
/// <param name="memoryCache">The memory cache.</param>
/// <param name="namingOptions">The naming options.</param>
+ /// <param name="directoryService">The directory service.</param>
public LibraryManager(
IServerApplicationHost appHost,
ILoggerFactory loggerFactory,
@@ -128,7 +129,8 @@ namespace Emby.Server.Implementations.Library
IItemRepository itemRepository,
IImageProcessor imageProcessor,
IMemoryCache memoryCache,
- NamingOptions namingOptions)
+ NamingOptions namingOptions,
+ IDirectoryService directoryService)
{
_appHost = appHost;
_logger = loggerFactory.CreateLogger<LibraryManager>();
@@ -146,7 +148,7 @@ namespace Emby.Server.Implementations.Library
_memoryCache = memoryCache;
_namingOptions = namingOptions;
- _extraResolver = new ExtraResolver(loggerFactory.CreateLogger<ExtraResolver>(), namingOptions);
+ _extraResolver = new ExtraResolver(loggerFactory.CreateLogger<ExtraResolver>(), namingOptions, directoryService);
_configurationManager.ConfigurationUpdated += ConfigurationUpdated;
@@ -356,8 +358,8 @@ namespace Emby.Server.Implementations.Library
}
var children = item.IsFolder
- ? ((Folder)item).GetRecursiveChildren(false).ToList()
- : new List<BaseItem>();
+ ? ((Folder)item).GetRecursiveChildren(false)
+ : Enumerable.Empty<BaseItem>();
foreach (var metadataPath in GetMetadataPaths(item, children))
{
@@ -537,7 +539,7 @@ namespace Emby.Server.Implementations.Library
collectionType = GetContentTypeOverride(fullPath, true);
}
- var args = new ItemResolveArgs(_configurationManager.ApplicationPaths, directoryService)
+ var args = new ItemResolveArgs(_configurationManager.ApplicationPaths, this)
{
Parent = parent,
FileInfo = fileInfo,
@@ -1253,7 +1255,7 @@ namespace Emby.Server.Implementations.Library
var parent = GetItemById(query.ParentId);
if (parent is not null)
{
- SetTopParentIdsOrAncestors(query, new List<BaseItem> { parent });
+ SetTopParentIdsOrAncestors(query, new[] { parent });
}
}
@@ -1262,7 +1264,14 @@ namespace Emby.Server.Implementations.Library
AddUserToQuery(query, query.User, allowExternalContent);
}
- return _itemRepository.GetItemList(query);
+ var itemList = _itemRepository.GetItemList(query);
+ var user = query.User;
+ if (user is not null)
+ {
+ return itemList.Where(i => i.IsVisible(user)).ToList();
+ }
+
+ return itemList;
}
public List<BaseItem> GetItemList(InternalItemsQuery query)
@@ -1277,7 +1286,7 @@ namespace Emby.Server.Implementations.Library
var parent = GetItemById(query.ParentId);
if (parent is not null)
{
- SetTopParentIdsOrAncestors(query, new List<BaseItem> { parent });
+ SetTopParentIdsOrAncestors(query, new[] { parent });
}
}
@@ -1435,7 +1444,7 @@ namespace Emby.Server.Implementations.Library
var parent = GetItemById(query.ParentId);
if (parent is not null)
{
- SetTopParentIdsOrAncestors(query, new List<BaseItem> { parent });
+ SetTopParentIdsOrAncestors(query, new[] { parent });
}
}
@@ -1455,7 +1464,7 @@ namespace Emby.Server.Implementations.Library
_itemRepository.GetItemList(query));
}
- private void SetTopParentIdsOrAncestors(InternalItemsQuery query, List<BaseItem> parents)
+ private void SetTopParentIdsOrAncestors(InternalItemsQuery query, IReadOnlyCollection<BaseItem> parents)
{
if (parents.All(i => i is ICollectionFolder || i is UserView))
{
@@ -1501,6 +1510,12 @@ namespace Emby.Server.Implementations.Library
});
query.TopParentIds = userViews.SelectMany(i => GetTopParentIdsForQuery(i, user)).ToArray();
+
+ // Prevent searching in all libraries due to empty filter
+ if (query.TopParentIds.Length == 0)
+ {
+ query.TopParentIds = new[] { Guid.NewGuid() };
+ }
}
}
@@ -1602,7 +1617,7 @@ namespace Emby.Server.Implementations.Library
{
_logger.LogError(ex, "Error getting intros");
- return new List<IntroInfo>();
+ return Enumerable.Empty<IntroInfo>();
}
}
@@ -1877,7 +1892,7 @@ namespace Emby.Server.Implementations.Library
catch (Exception ex)
{
_logger.LogError(ex, "Cannot get image dimensions for {ImagePath}", image.Path);
- size = new ImageDimensions(0, 0);
+ size = default;
image.Width = 0;
image.Height = 0;
}
@@ -2741,9 +2756,7 @@ namespace Emby.Server.Implementations.Library
}
})
.Where(i => i is not null)
- .Where(i => query.User is null ?
- true :
- i.IsVisible(query.User))
+ .Where(i => query.User is null || i.IsVisible(query.User))
.ToList();
}
@@ -2876,7 +2889,7 @@ namespace Emby.Server.Implementations.Library
private async Task SavePeopleMetadataAsync(IEnumerable<PersonInfo> people, CancellationToken cancellationToken)
{
- var personsToSave = new List<BaseItem>();
+ List<BaseItem> personsToSave = null;
foreach (var person in people)
{
@@ -2918,12 +2931,12 @@ namespace Emby.Server.Implementations.Library
if (saveEntity)
{
- personsToSave.Add(personEntity);
+ (personsToSave ??= new()).Add(personEntity);
await RunMetadataSavers(personEntity, itemUpdateType).ConfigureAwait(false);
}
}
- if (personsToSave.Count > 0)
+ if (personsToSave is not null)
{
CreateItems(personsToSave, null, CancellationToken.None);
}
@@ -3085,22 +3098,19 @@ namespace Emby.Server.Implementations.Library
throw new ArgumentNullException(nameof(path));
}
- var removeList = new List<NameValuePair>();
+ List<NameValuePair> removeList = null;
foreach (var contentType in _configurationManager.Configuration.ContentTypes)
{
- if (string.IsNullOrWhiteSpace(contentType.Name))
- {
- removeList.Add(contentType);
- }
- else if (_fileSystem.AreEqual(path, contentType.Name)
+ if (string.IsNullOrWhiteSpace(contentType.Name)
+ || _fileSystem.AreEqual(path, contentType.Name)
|| _fileSystem.ContainsSubPath(path, contentType.Name))
{
- removeList.Add(contentType);
+ (removeList ??= new()).Add(contentType);
}
}
- if (removeList.Count > 0)
+ if (removeList is not null)
{
_configurationManager.Configuration.ContentTypes = _configurationManager.Configuration.ContentTypes
.Except(removeList)
diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs
index eadfa5dfe..c9a26a30f 100644
--- a/Emby.Server.Implementations/Library/MediaSourceManager.cs
+++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs
@@ -154,8 +154,8 @@ namespace Emby.Server.Implementations.Library
// If file is strm or main media stream is missing, force a metadata refresh with remote probing
if (allowMediaProbe && mediaSources[0].Type != MediaSourceType.Placeholder
&& (item.Path.EndsWith(".strm", StringComparison.OrdinalIgnoreCase)
- || (item.MediaType == MediaType.Video && !mediaSources[0].MediaStreams.Any(i => i.Type == MediaStreamType.Video))
- || (item.MediaType == MediaType.Audio && !mediaSources[0].MediaStreams.Any(i => i.Type == MediaStreamType.Audio))))
+ || (item.MediaType == MediaType.Video && mediaSources[0].MediaStreams.All(i => i.Type != MediaStreamType.Video))
+ || (item.MediaType == MediaType.Audio && mediaSources[0].MediaStreams.All(i => i.Type != MediaStreamType.Audio))))
{
await item.RefreshMetadata(
new MetadataRefreshOptions(_directoryService)
diff --git a/Emby.Server.Implementations/Library/PathExtensions.cs b/Emby.Server.Implementations/Library/PathExtensions.cs
index 64e7d5446..c4b6b3756 100644
--- a/Emby.Server.Implementations/Library/PathExtensions.cs
+++ b/Emby.Server.Implementations/Library/PathExtensions.cs
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics.CodeAnalysis;
+using System.IO;
using MediaBrowser.Common.Providers;
namespace Emby.Server.Implementations.Library
@@ -86,24 +87,8 @@ namespace Emby.Server.Implementations.Library
return false;
}
- char oldDirectorySeparatorChar;
- char newDirectorySeparatorChar;
- // True normalization is still not possible https://github.com/dotnet/runtime/issues/2162
- // The reasoning behind this is that a forward slash likely means it's a Linux path and
- // so the whole path should be normalized to use / and vice versa for Windows (although Windows doesn't care much).
- if (newSubPath.Contains('/', StringComparison.Ordinal))
- {
- oldDirectorySeparatorChar = '\\';
- newDirectorySeparatorChar = '/';
- }
- else
- {
- oldDirectorySeparatorChar = '/';
- newDirectorySeparatorChar = '\\';
- }
-
- path = path.Replace(oldDirectorySeparatorChar, newDirectorySeparatorChar);
- subPath = subPath.Replace(oldDirectorySeparatorChar, newDirectorySeparatorChar);
+ subPath = subPath.NormalizePath(out var newDirectorySeparatorChar);
+ path = path.NormalizePath(newDirectorySeparatorChar);
// We have to ensure that the sub path ends with a directory separator otherwise we'll get weird results
// when the sub path matches a similar but in-complete subpath
@@ -127,5 +112,82 @@ namespace Emby.Server.Implementations.Library
return true;
}
+
+ /// <summary>
+ /// Retrieves the full resolved path and normalizes path separators to the <see cref="Path.DirectorySeparatorChar"/>.
+ /// </summary>
+ /// <param name="path">The path to canonicalize.</param>
+ /// <returns>The fully expanded, normalized path.</returns>
+ public static string Canonicalize(this string path)
+ {
+ return Path.GetFullPath(path).NormalizePath();
+ }
+
+ /// <summary>
+ /// Normalizes the path's directory separator character to the currently defined <see cref="Path.DirectorySeparatorChar"/>.
+ /// </summary>
+ /// <param name="path">The path to normalize.</param>
+ /// <returns>The normalized path string or <see langword="null"/> if the input path is null or empty.</returns>
+ [return: NotNullIfNotNull(nameof(path))]
+ public static string? NormalizePath(this string? path)
+ {
+ return path.NormalizePath(Path.DirectorySeparatorChar);
+ }
+
+ /// <summary>
+ /// Normalizes the path's directory separator character.
+ /// </summary>
+ /// <param name="path">The path to normalize.</param>
+ /// <param name="separator">The separator character the path now uses or <see langword="null"/>.</param>
+ /// <returns>The normalized path string or <see langword="null"/> if the input path is null or empty.</returns>
+ [return: NotNullIfNotNull(nameof(path))]
+ public static string? NormalizePath(this string? path, out char separator)
+ {
+ if (string.IsNullOrEmpty(path))
+ {
+ separator = default;
+ return path;
+ }
+
+ var newSeparator = '\\';
+
+ // True normalization is still not possible https://github.com/dotnet/runtime/issues/2162
+ // The reasoning behind this is that a forward slash likely means it's a Linux path and
+ // so the whole path should be normalized to use / and vice versa for Windows (although Windows doesn't care much).
+ if (path.Contains('/', StringComparison.Ordinal))
+ {
+ newSeparator = '/';
+ }
+
+ separator = newSeparator;
+
+ return path.NormalizePath(newSeparator);
+ }
+
+ /// <summary>
+ /// Normalizes the path's directory separator character to the specified character.
+ /// </summary>
+ /// <param name="path">The path to normalize.</param>
+ /// <param name="newSeparator">The replacement directory separator character. Must be a valid directory separator.</param>
+ /// <returns>The normalized path.</returns>
+ /// <exception cref="ArgumentException">Thrown if the new separator character is not a directory separator.</exception>
+ [return: NotNullIfNotNull(nameof(path))]
+ public static string? NormalizePath(this string? path, char newSeparator)
+ {
+ const char Bs = '\\';
+ const char Fs = '/';
+
+ if (!(newSeparator == Bs || newSeparator == Fs))
+ {
+ throw new ArgumentException("The character must be a directory separator.");
+ }
+
+ if (string.IsNullOrEmpty(path))
+ {
+ return path;
+ }
+
+ return newSeparator == Bs ? path.Replace(Fs, newSeparator) : path.Replace(Bs, newSeparator);
+ }
}
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
index 06621700a..a74f82475 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
@@ -158,7 +158,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
private MultiItemResolverResult ResolveMultipleAudio(Folder parent, IEnumerable<FileSystemMetadata> fileSystemEntries, bool parseName)
{
var files = new List<FileSystemMetadata>();
- var items = new List<BaseItem>();
var leftOver = new List<FileSystemMetadata>();
// Loop through each child file/folder and see if we find a video
@@ -180,7 +179,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
var result = new MultiItemResolverResult
{
ExtraFiles = leftOver,
- Items = items
+ Items = new List<BaseItem>()
};
var isInMixedFolder = resolverResult.Count > 1 || (parent is not null && parent.IsTopParent);
@@ -193,7 +192,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
continue;
}
- if (resolvedItem.Files.Count == 0)
+ // Until multi-part books are handled letting files stack hides them from browsing in the client
+ if (resolvedItem.Files.Count == 0 || resolvedItem.Extras.Count > 0 || resolvedItem.AlternateVersions.Count > 0)
{
continue;
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
index a922e3685..bbc70701c 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
@@ -25,16 +25,19 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
{
private readonly ILogger<MusicAlbumResolver> _logger;
private readonly NamingOptions _namingOptions;
+ private readonly IDirectoryService _directoryService;
/// <summary>
/// Initializes a new instance of the <see cref="MusicAlbumResolver"/> class.
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="namingOptions">The naming options.</param>
- public MusicAlbumResolver(ILogger<MusicAlbumResolver> logger, NamingOptions namingOptions)
+ /// <param name="directoryService">The directory service.</param>
+ public MusicAlbumResolver(ILogger<MusicAlbumResolver> logger, NamingOptions namingOptions, IDirectoryService directoryService)
{
_logger = logger;
_namingOptions = namingOptions;
+ _directoryService = directoryService;
}
/// <summary>
@@ -109,7 +112,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
}
// If args contains music it's a music album
- if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService))
+ if (ContainsMusic(args.FileSystemChildren, true, _directoryService))
{
return true;
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
index 2538c2b5b..c858dc53d 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
using Emby.Naming.Common;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.Entities;
using Microsoft.Extensions.Logging;
@@ -18,19 +19,23 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
public class MusicArtistResolver : ItemResolver<MusicArtist>
{
private readonly ILogger<MusicAlbumResolver> _logger;
- private NamingOptions _namingOptions;
+ private readonly NamingOptions _namingOptions;
+ private readonly IDirectoryService _directoryService;
/// <summary>
/// Initializes a new instance of the <see cref="MusicArtistResolver"/> class.
/// </summary>
/// <param name="logger">Instance of the <see cref="MusicAlbumResolver"/> interface.</param>
/// <param name="namingOptions">The <see cref="NamingOptions"/>.</param>
+ /// <param name="directoryService">The directory service.</param>
public MusicArtistResolver(
ILogger<MusicAlbumResolver> logger,
- NamingOptions namingOptions)
+ NamingOptions namingOptions,
+ IDirectoryService directoryService)
{
_logger = logger;
_namingOptions = namingOptions;
+ _directoryService = directoryService;
}
/// <summary>
@@ -78,9 +83,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
return null;
}
- var directoryService = args.DirectoryService;
-
- var albumResolver = new MusicAlbumResolver(_logger, _namingOptions);
+ var albumResolver = new MusicAlbumResolver(_logger, _namingOptions, _directoryService);
var directories = args.FileSystemChildren.Where(i => i.IsDirectory);
@@ -97,7 +100,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
}
// If we contain a music album assume we are an artist folder
- if (albumResolver.IsMusicAlbum(fileSystemInfo.FullName, directoryService))
+ if (albumResolver.IsMusicAlbum(fileSystemInfo.FullName, _directoryService))
{
// Stop once we see a music album
state.Stop();
diff --git a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
index e8615e7db..381796d0e 100644
--- a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
@@ -25,14 +25,17 @@ namespace Emby.Server.Implementations.Library.Resolvers
{
private readonly ILogger _logger;
- protected BaseVideoResolver(ILogger logger, NamingOptions namingOptions)
+ protected BaseVideoResolver(ILogger logger, NamingOptions namingOptions, IDirectoryService directoryService)
{
_logger = logger;
NamingOptions = namingOptions;
+ DirectoryService = directoryService;
}
protected NamingOptions NamingOptions { get; }
+ protected IDirectoryService DirectoryService { get; }
+
/// <summary>
/// Resolves the specified args.
/// </summary>
@@ -65,13 +68,26 @@ namespace Emby.Server.Implementations.Library.Resolvers
var filename = child.Name;
if (child.IsDirectory)
{
- if (IsDvdDirectory(child.FullName, filename, args.DirectoryService))
+ if (IsDvdDirectory(child.FullName, filename, DirectoryService))
{
- videoType = VideoType.Dvd;
+ var videoTmp = new TVideoType
+ {
+ Path = args.Path,
+ VideoType = VideoType.Dvd
+ };
+ Set3DFormat(videoTmp);
+ return videoTmp;
}
- else if (IsBluRayDirectory(filename))
+
+ if (IsBluRayDirectory(filename))
{
- videoType = VideoType.BluRay;
+ var videoTmp = new TVideoType
+ {
+ Path = args.Path,
+ VideoType = VideoType.BluRay
+ };
+ Set3DFormat(videoTmp);
+ return videoTmp;
}
}
else if (IsDvdFile(filename))
diff --git a/Emby.Server.Implementations/Library/Resolvers/ExtraResolver.cs b/Emby.Server.Implementations/Library/Resolvers/ExtraResolver.cs
index 30c52e19d..b4791b945 100644
--- a/Emby.Server.Implementations/Library/Resolvers/ExtraResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/ExtraResolver.cs
@@ -4,6 +4,8 @@ using System.IO;
using Emby.Naming.Common;
using Emby.Naming.Video;
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.Entities;
using Microsoft.Extensions.Logging;
@@ -14,7 +16,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
/// <summary>
/// Resolves a Path into a Video or Video subclass.
/// </summary>
- internal class ExtraResolver
+ internal class ExtraResolver : BaseVideoResolver<Video>
{
private readonly NamingOptions _namingOptions;
private readonly IItemResolver[] _trailerResolvers;
@@ -25,11 +27,18 @@ namespace Emby.Server.Implementations.Library.Resolvers
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="namingOptions">An instance of <see cref="NamingOptions"/>.</param>
- public ExtraResolver(ILogger<ExtraResolver> logger, NamingOptions namingOptions)
+ /// <param name="directoryService">The directory service.</param>
+ public ExtraResolver(ILogger<ExtraResolver> logger, NamingOptions namingOptions, IDirectoryService directoryService)
+ : base(logger, namingOptions, directoryService)
{
_namingOptions = namingOptions;
- _trailerResolvers = new IItemResolver[] { new GenericVideoResolver<Trailer>(logger, namingOptions) };
- _videoResolvers = new IItemResolver[] { new GenericVideoResolver<Video>(logger, namingOptions) };
+ _trailerResolvers = new IItemResolver[] { new GenericVideoResolver<Trailer>(logger, namingOptions, directoryService) };
+ _videoResolvers = new IItemResolver[] { this };
+ }
+
+ protected override Video Resolve(ItemResolveArgs args)
+ {
+ return ResolveVideo<Video>(args, true);
}
/// <summary>
diff --git a/Emby.Server.Implementations/Library/Resolvers/GenericVideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/GenericVideoResolver.cs
index 5e33b402d..ba320266a 100644
--- a/Emby.Server.Implementations/Library/Resolvers/GenericVideoResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/GenericVideoResolver.cs
@@ -2,6 +2,7 @@
using Emby.Naming.Common;
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Providers;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Resolvers
@@ -18,8 +19,9 @@ namespace Emby.Server.Implementations.Library.Resolvers
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="namingOptions">The naming options.</param>
- public GenericVideoResolver(ILogger logger, NamingOptions namingOptions)
- : base(logger, namingOptions)
+ /// <param name="directoryService">The directory service.</param>
+ public GenericVideoResolver(ILogger logger, NamingOptions namingOptions, IDirectoryService directoryService)
+ : base(logger, namingOptions, directoryService)
{
}
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index 1522cd3ae..ea980b992 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -43,8 +43,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
/// <param name="imageProcessor">The image processor.</param>
/// <param name="logger">The logger.</param>
/// <param name="namingOptions">The naming options.</param>
- public MovieResolver(IImageProcessor imageProcessor, ILogger<MovieResolver> logger, NamingOptions namingOptions)
- : base(logger, namingOptions)
+ /// <param name="directoryService">The directory service.</param>
+ public MovieResolver(IImageProcessor imageProcessor, ILogger<MovieResolver> logger, NamingOptions namingOptions, IDirectoryService directoryService)
+ : base(logger, namingOptions, directoryService)
{
_imageProcessor = imageProcessor;
}
@@ -97,12 +98,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
{
- movie = FindMovie<MusicVideo>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
+ movie = FindMovie<MusicVideo>(args, args.Path, args.Parent, files, DirectoryService, collectionType, false);
}
if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase))
{
- movie = FindMovie<Video>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
+ movie = FindMovie<Video>(args, args.Path, args.Parent, files, DirectoryService, collectionType, false);
}
if (string.IsNullOrEmpty(collectionType))
@@ -118,12 +119,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
return null;
}
- movie = FindMovie<Movie>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
+ movie = FindMovie<Movie>(args, args.Path, args.Parent, files, DirectoryService, collectionType, true);
}
if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
{
- movie = FindMovie<Movie>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
+ movie = FindMovie<Movie>(args, args.Path, args.Parent, files, DirectoryService, collectionType, true);
}
// ignore extras
@@ -313,13 +314,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
return result;
}
- private static bool IsIgnored(string filename)
- {
- // Ignore samples
- Match m = Regex.Match(filename, @"\bsample\b", RegexOptions.IgnoreCase | RegexOptions.Compiled);
-
- return m.Success;
- }
+ private static bool IsIgnored(ReadOnlySpan<char> filename)
+ => Regex.IsMatch(filename, @"\bsample\b", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static bool ContainsFile(IReadOnlyList<VideoInfo> result, FileSystemMetadata file)
{
diff --git a/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
index e11fb262e..9026160ff 100644
--- a/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs
@@ -1,7 +1,5 @@
#nullable disable
-#pragma warning disable CS1591
-
using System;
using System.Collections.Generic;
using System.IO;
@@ -12,15 +10,20 @@ using Jellyfin.Extensions;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.Entities;
namespace Emby.Server.Implementations.Library.Resolvers
{
+ /// <summary>
+ /// Class PhotoResolver.
+ /// </summary>
public class PhotoResolver : ItemResolver<Photo>
{
private readonly IImageProcessor _imageProcessor;
private readonly NamingOptions _namingOptions;
+ private readonly IDirectoryService _directoryService;
private static readonly HashSet<string> _ignoreFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
@@ -35,10 +38,17 @@ namespace Emby.Server.Implementations.Library.Resolvers
"default"
};
- public PhotoResolver(IImageProcessor imageProcessor, NamingOptions namingOptions)
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PhotoResolver"/> class.
+ /// </summary>
+ /// <param name="imageProcessor">The image processor.</param>
+ /// <param name="namingOptions">The naming options.</param>
+ /// <param name="directoryService">The directory service.</param>
+ public PhotoResolver(IImageProcessor imageProcessor, NamingOptions namingOptions, IDirectoryService directoryService)
{
_imageProcessor = imageProcessor;
_namingOptions = namingOptions;
+ _directoryService = directoryService;
}
/// <summary>
@@ -61,7 +71,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
var filename = Path.GetFileNameWithoutExtension(args.Path);
// Make sure the image doesn't belong to a video file
- var files = args.DirectoryService.GetFiles(Path.GetDirectoryName(args.Path));
+ var files = _directoryService.GetFiles(Path.GetDirectoryName(args.Path));
foreach (var file in files)
{
diff --git a/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs
index 7a2b3da3a..5d569009d 100644
--- a/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs
@@ -30,7 +30,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
{
if (args.IsDirectory)
{
- // It's a boxset if the path is a directory with [playlist] in it's the name
+ // It's a boxset if the path is a directory with [playlist] in its name
var filename = Path.GetFileName(Path.TrimEndingDirectorySeparator(args.Path));
if (string.IsNullOrEmpty(filename))
{
@@ -42,7 +42,8 @@ namespace Emby.Server.Implementations.Library.Resolvers
return new Playlist
{
Path = args.Path,
- Name = filename.Replace("[playlist]", string.Empty, StringComparison.OrdinalIgnoreCase).Trim()
+ Name = filename.Replace("[playlist]", string.Empty, StringComparison.OrdinalIgnoreCase).Trim(),
+ OpenAccess = true
};
}
@@ -53,7 +54,8 @@ namespace Emby.Server.Implementations.Library.Resolvers
return new Playlist
{
Path = args.Path,
- Name = filename
+ Name = filename,
+ OpenAccess = true
};
}
}
@@ -70,7 +72,8 @@ namespace Emby.Server.Implementations.Library.Resolvers
Path = args.Path,
Name = Path.GetFileNameWithoutExtension(args.Path),
IsInMixedFolder = true,
- PlaylistMediaType = MediaType.Audio
+ PlaylistMediaType = MediaType.Audio,
+ OpenAccess = true
};
}
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
index 0fcc5070b..392ee4c77 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
@@ -5,6 +5,7 @@ using System.Linq;
using Emby.Naming.Common;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using Microsoft.Extensions.Logging;
@@ -20,8 +21,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="namingOptions">The naming options.</param>
- public EpisodeResolver(ILogger<EpisodeResolver> logger, NamingOptions namingOptions)
- : base(logger, namingOptions)
+ /// <param name="directoryService">The directory service.</param>
+ public EpisodeResolver(ILogger<EpisodeResolver> logger, NamingOptions namingOptions, IDirectoryService directoryService)
+ : base(logger, namingOptions, directoryService)
{
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
index 62a524d2e..e9538a5c9 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
@@ -81,14 +81,24 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
if (season.IndexNumber.HasValue)
{
var seasonNumber = season.IndexNumber.Value;
-
- season.Name = seasonNumber == 0 ?
- args.LibraryOptions.SeasonZeroDisplayName :
- string.Format(
- CultureInfo.InvariantCulture,
- _localization.GetLocalizedString("NameSeasonNumber"),
- seasonNumber,
- args.LibraryOptions.PreferredMetadataLanguage);
+ if (string.IsNullOrEmpty(season.Name))
+ {
+ var seasonNames = series.SeasonNames;
+ if (seasonNames.TryGetValue(seasonNumber, out var seasonName))
+ {
+ season.Name = seasonName;
+ }
+ else
+ {
+ season.Name = seasonNumber == 0 ?
+ args.LibraryOptions.SeasonZeroDisplayName :
+ string.Format(
+ CultureInfo.InvariantCulture,
+ _localization.GetLocalizedString("NameSeasonNumber"),
+ seasonNumber,
+ args.LibraryOptions.PreferredMetadataLanguage);
+ }
+ }
}
return season;
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
index 8f69175d0..d4f275bed 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
@@ -184,6 +184,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
{
var justName = Path.GetFileName(path.AsSpan());
+ var imdbId = justName.GetAttributeValue("imdbid");
+ if (!string.IsNullOrEmpty(imdbId))
+ {
+ item.SetProviderId(MetadataProvider.Imdb, imdbId);
+ }
+
var tvdbId = justName.GetAttributeValue("tvdbid");
if (!string.IsNullOrEmpty(tvdbId))
{
diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs
index 1137625f4..2c3dc1857 100644
--- a/Emby.Server.Implementations/Library/UserViewManager.cs
+++ b/Emby.Server.Implementations/Library/UserViewManager.cs
@@ -46,10 +46,9 @@ namespace Emby.Server.Implementations.Library
public Folder[] GetUserViews(UserViewQuery query)
{
var user = _userManager.GetUserById(query.UserId);
-
if (user is null)
{
- throw new ArgumentException("User Id specified in the query does not exist.", nameof(query));
+ throw new ArgumentException("User id specified in the query does not exist.", nameof(query));
}
var folders = _libraryManager.GetUserRootFolder()
@@ -58,7 +57,6 @@ namespace Emby.Server.Implementations.Library
.ToList();
var groupedFolders = new List<ICollectionFolder>();
-
var list = new List<Folder>();
foreach (var folder in folders)
@@ -66,6 +64,20 @@ namespace Emby.Server.Implementations.Library
var collectionFolder = folder as ICollectionFolder;
var folderViewType = collectionFolder?.CollectionType;
+ // Playlist library requires special handling because the folder only refrences user playlists
+ if (string.Equals(folderViewType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
+ {
+ var items = folder.GetItemList(new InternalItemsQuery(user)
+ {
+ ParentId = folder.ParentId
+ });
+
+ if (!items.Any(item => item.IsVisible(user)))
+ {
+ continue;
+ }
+ }
+
if (UserView.IsUserSpecific(folder))
{
list.Add(_libraryManager.GetNamedView(user, folder.Name, folder.Id, folderViewType, null));
@@ -111,10 +123,10 @@ namespace Emby.Server.Implementations.Library
if (query.IncludeExternalContent)
{
- var channelResult = _channelManager.GetChannelsInternal(new ChannelQuery
+ var channelResult = _channelManager.GetChannelsInternalAsync(new ChannelQuery
{
UserId = query.UserId
- });
+ }).GetAwaiter().GetResult();
var channels = channelResult.Items;
@@ -132,14 +144,12 @@ namespace Emby.Server.Implementations.Library
}
var sorted = _libraryManager.Sort(list, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending).ToList();
-
var orders = user.GetPreferenceValues<Guid>(PreferenceKind.OrderedViews);
return list
.OrderBy(i =>
{
var index = Array.IndexOf(orders, i.Id);
-
if (index == -1
&& i is UserView view
&& !view.DisplayParentId.Equals(default))
@@ -286,7 +296,7 @@ namespace Emby.Server.Implementations.Library
if (parents.Count == 0)
{
- return new List<BaseItem>();
+ return Array.Empty<BaseItem>();
}
if (includeItemTypes.Length == 0)