diff options
| author | Joshua M. Boniface <joshua@boniface.me> | 2020-11-21 17:20:31 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-11-21 17:20:31 -0500 |
| commit | bf54b5579c15bdf8bb6e3dd6934ea23c45a62573 (patch) | |
| tree | 1b2df4bdf89a70f578b72240969416034afc33db /Emby.Server.Implementations/Library | |
| parent | 4a81ee43dc7aed94012c312a8262a1426be9b6d9 (diff) | |
| parent | b707d8e09d776a1dd1f0cdd6cf13cd1f3e638028 (diff) | |
Merge branch 'master' into defer_image_fetching
Diffstat (limited to 'Emby.Server.Implementations/Library')
12 files changed, 115 insertions, 101 deletions
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 74788a320..013781258 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Net; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Emby.Naming.Audio; @@ -1516,7 +1517,7 @@ namespace Emby.Server.Implementations.Library { if (query.AncestorIds.Length == 0 && query.ParentId.Equals(Guid.Empty) && - query.ChannelIds.Length == 0 && + query.ChannelIds.Count == 0 && query.TopParentIds.Length == 0 && string.IsNullOrEmpty(query.AncestorWithPresentationUniqueKey) && string.IsNullOrEmpty(query.SeriesPresentationUniqueKey) && @@ -2459,6 +2460,21 @@ namespace Emby.Server.Implementations.Library new SubtitleResolver(BaseItem.LocalizationManager).AddExternalSubtitleStreams(streams, videoPath, streams.Count, files); } + public BaseItem GetParentItem(string parentId, Guid? userId) + { + if (!string.IsNullOrEmpty(parentId)) + { + return GetItemById(new Guid(parentId)); + } + + if (userId.HasValue && userId != Guid.Empty) + { + return GetUserRootFolder(); + } + + return RootFolder; + } + /// <inheritdoc /> public bool IsVideoFile(string path) { @@ -2489,9 +2505,10 @@ namespace Emby.Server.Implementations.Library var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd; + // TODO nullable - what are we trying to do there with empty episodeInfo? var episodeInfo = episode.IsFileProtocol - ? resolver.Resolve(episode.Path, isFolder, null, null, isAbsoluteNaming) ?? new Naming.TV.EpisodeInfo() - : new Naming.TV.EpisodeInfo(); + ? resolver.Resolve(episode.Path, isFolder, null, null, isAbsoluteNaming) ?? new Naming.TV.EpisodeInfo(episode.Path) + : new Naming.TV.EpisodeInfo(episode.Path); try { @@ -2580,12 +2597,12 @@ namespace Emby.Server.Implementations.Library if (!episode.IndexNumberEnd.HasValue || forceRefresh) { - if (episode.IndexNumberEnd != episodeInfo.EndingEpsiodeNumber) + if (episode.IndexNumberEnd != episodeInfo.EndingEpisodeNumber) { changed = true; } - episode.IndexNumberEnd = episodeInfo.EndingEpsiodeNumber; + episode.IndexNumberEnd = episodeInfo.EndingEpisodeNumber; } if (!episode.ParentIndexNumber.HasValue || forceRefresh) @@ -2709,7 +2726,7 @@ namespace Emby.Server.Implementations.Library var videos = videoListResolver.Resolve(fileSystemChildren); - var currentVideo = videos.FirstOrDefault(i => string.Equals(owner.Path, i.Files.First().Path, StringComparison.OrdinalIgnoreCase)); + var currentVideo = videos.FirstOrDefault(i => string.Equals(owner.Path, i.Files[0].Path, StringComparison.OrdinalIgnoreCase)); if (currentVideo != null) { @@ -2911,7 +2928,7 @@ namespace Emby.Server.Implementations.Library return item.GetImageInfo(image.Type, imageIndex); } - catch (HttpException ex) + catch (HttpRequestException ex) { if (ex.StatusCode.HasValue && (ex.StatusCode.Value == HttpStatusCode.NotFound || ex.StatusCode.Value == HttpStatusCode.Forbidden)) diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 67cf8bf5b..928f5f88e 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -1,6 +1,7 @@ #pragma warning disable CS1591 using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -43,7 +44,7 @@ namespace Emby.Server.Implementations.Library private readonly ILocalizationManager _localizationManager; private readonly IApplicationPaths _appPaths; - private readonly Dictionary<string, ILiveStream> _openStreams = new Dictionary<string, ILiveStream>(StringComparer.OrdinalIgnoreCase); + private readonly ConcurrentDictionary<string, ILiveStream> _openStreams = new ConcurrentDictionary<string, ILiveStream>(StringComparer.OrdinalIgnoreCase); private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1); private IMediaSourceProvider[] _providers; @@ -582,29 +583,20 @@ namespace Emby.Server.Implementations.Library mediaSource.InferTotalBitrate(); } - public async Task<IDirectStreamProvider> GetDirectStreamProviderByUniqueId(string uniqueId, CancellationToken cancellationToken) + public Task<IDirectStreamProvider> GetDirectStreamProviderByUniqueId(string uniqueId, CancellationToken cancellationToken) { - await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - - try + var info = _openStreams.Values.FirstOrDefault(i => { - var info = _openStreams.Values.FirstOrDefault(i => + var liveStream = i as ILiveStream; + if (liveStream != null) { - var liveStream = i as ILiveStream; - if (liveStream != null) - { - return string.Equals(liveStream.UniqueId, uniqueId, StringComparison.OrdinalIgnoreCase); - } + return string.Equals(liveStream.UniqueId, uniqueId, StringComparison.OrdinalIgnoreCase); + } - return false; - }); + return false; + }); - return info as IDirectStreamProvider; - } - finally - { - _liveStreamSemaphore.Release(); - } + return Task.FromResult(info as IDirectStreamProvider); } public async Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, CancellationToken cancellationToken) @@ -793,29 +785,20 @@ namespace Emby.Server.Implementations.Library return new Tuple<MediaSourceInfo, IDirectStreamProvider>(info.MediaSource, info as IDirectStreamProvider); } - private async Task<ILiveStream> GetLiveStreamInfo(string id, CancellationToken cancellationToken) + private Task<ILiveStream> GetLiveStreamInfo(string id, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(id)) { throw new ArgumentNullException(nameof(id)); } - await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - - try + if (_openStreams.TryGetValue(id, out ILiveStream info)) { - if (_openStreams.TryGetValue(id, out ILiveStream info)) - { - return info; - } - else - { - throw new ResourceNotFoundException(); - } + return Task.FromResult(info); } - finally + else { - _liveStreamSemaphore.Release(); + return Task.FromException<ILiveStream>(new ResourceNotFoundException()); } } @@ -844,7 +827,7 @@ namespace Emby.Server.Implementations.Library if (liveStream.ConsumerCount <= 0) { - _openStreams.Remove(id); + _openStreams.TryRemove(id, out _); _logger.LogInformation("Closing live stream {0}", id); @@ -866,7 +849,7 @@ namespace Emby.Server.Implementations.Library throw new ArgumentException("Key can't be empty.", nameof(key)); } - var keys = key.Split(new[] { LiveStreamIdDelimeter }, 2); + var keys = key.Split(LiveStreamIdDelimeter, 2); var provider = _providers.FirstOrDefault(i => string.Equals(i.GetType().FullName.GetMD5().ToString("N", CultureInfo.InvariantCulture), keys[0], StringComparison.OrdinalIgnoreCase)); diff --git a/Emby.Server.Implementations/Library/MediaStreamSelector.cs b/Emby.Server.Implementations/Library/MediaStreamSelector.cs index 179e0ed98..28fa06239 100644 --- a/Emby.Server.Implementations/Library/MediaStreamSelector.cs +++ b/Emby.Server.Implementations/Library/MediaStreamSelector.cs @@ -101,7 +101,7 @@ namespace Emby.Server.Implementations.Library private static IEnumerable<MediaStream> GetSortedStreams(IEnumerable<MediaStream> streams, MediaStreamType type, string[] languagePreferences) { - // Give some preferance to external text subs for better performance + // Give some preference to external text subs for better performance return streams.Where(i => i.Type == type) .OrderBy(i => { diff --git a/Emby.Server.Implementations/Library/MusicManager.cs b/Emby.Server.Implementations/Library/MusicManager.cs index 877fdec86..658c53f28 100644 --- a/Emby.Server.Implementations/Library/MusicManager.cs +++ b/Emby.Server.Implementations/Library/MusicManager.cs @@ -49,7 +49,7 @@ namespace Emby.Server.Implementations.Library var genres = item .GetRecursiveChildren(user, new InternalItemsQuery(user) { - IncludeItemTypes = new[] { typeof(Audio).Name }, + IncludeItemTypes = new[] { nameof(Audio) }, DtoOptions = dtoOptions }) .Cast<Audio>() @@ -86,7 +86,7 @@ namespace Emby.Server.Implementations.Library { return _libraryManager.GetItemList(new InternalItemsQuery(user) { - IncludeItemTypes = new[] { typeof(Audio).Name }, + IncludeItemTypes = new[] { nameof(Audio) }, GenreIds = genreIds.ToArray(), diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs index 03059e6d3..2c4497c69 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs @@ -32,7 +32,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio /// <value>The priority.</value> public override ResolverPriority Priority => ResolverPriority.Fourth; - public MultiItemResolverResult ResolveMultiple(Folder parent, + public MultiItemResolverResult ResolveMultiple( + Folder parent, List<FileSystemMetadata> files, string collectionType, IDirectoryService directoryService) @@ -50,7 +51,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio return result; } - private MultiItemResolverResult ResolveMultipleInternal(Folder parent, + private MultiItemResolverResult ResolveMultipleInternal( + Folder parent, List<FileSystemMetadata> files, string collectionType, IDirectoryService directoryService) @@ -199,7 +201,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio continue; } - var firstMedia = resolvedItem.Files.First(); + var firstMedia = resolvedItem.Files[0]; var libraryItem = new T { diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs index 79b6dded3..18ceb5e76 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs @@ -1,5 +1,8 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; using Emby.Naming.Audio; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; @@ -113,52 +116,48 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio IFileSystem fileSystem, ILibraryManager libraryManager) { + // check for audio files before digging down into directories + var foundAudioFile = list.Any(fileSystemInfo => !fileSystemInfo.IsDirectory && libraryManager.IsAudioFile(fileSystemInfo.FullName)); + if (foundAudioFile) + { + // at least one audio file exists + return true; + } + + if (!allowSubfolders) + { + // not music since no audio file exists and we're not looking into subfolders + return false; + } + var discSubfolderCount = 0; - var notMultiDisc = false; var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions(); var parser = new AlbumParser(namingOptions); - foreach (var fileSystemInfo in list) + + var directories = list.Where(fileSystemInfo => fileSystemInfo.IsDirectory); + + var result = Parallel.ForEach(directories, (fileSystemInfo, state) => { - if (fileSystemInfo.IsDirectory) + var path = fileSystemInfo.FullName; + var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService, logger, fileSystem, libraryManager); + + if (hasMusic) { - if (allowSubfolders) + if (parser.IsMultiPart(path)) { - if (notMultiDisc) - { - continue; - } - - var path = fileSystemInfo.FullName; - var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService, logger, fileSystem, libraryManager); - - if (hasMusic) - { - if (parser.IsMultiPart(path)) - { - logger.LogDebug("Found multi-disc folder: " + path); - discSubfolderCount++; - } - else - { - // If there are folders underneath with music that are not multidisc, then this can't be a multi-disc album - notMultiDisc = true; - } - } + logger.LogDebug("Found multi-disc folder: " + path); + Interlocked.Increment(ref discSubfolderCount); } - } - else - { - var fullName = fileSystemInfo.FullName; - - if (libraryManager.IsAudioFile(fullName)) + else { - return true; + // If there are folders underneath with music that are not multidisc, then this can't be a multi-disc album + state.Stop(); } } - } + }); - if (notMultiDisc) + if (!result.IsCompleted) { return false; } diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs index 5f5cd0e92..e9e688fa6 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading.Tasks; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; @@ -94,7 +95,18 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio var albumResolver = new MusicAlbumResolver(_logger, _fileSystem, _libraryManager); // If we contain an album assume we are an artist folder - return args.FileSystemChildren.Where(i => i.IsDirectory).Any(i => albumResolver.IsMusicAlbum(i.FullName, directoryService)) ? new MusicArtist() : null; + var directories = args.FileSystemChildren.Where(i => i.IsDirectory); + + var result = Parallel.ForEach(directories, (fileSystemInfo, state) => + { + if (albumResolver.IsMusicAlbum(fileSystemInfo.FullName, directoryService)) + { + // stop once we see a music album + state.Stop(); + } + }); + + return !result.IsCompleted ? new MusicArtist() : null; } } } diff --git a/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs index 86a5d8b7d..59af7ce8a 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs @@ -50,7 +50,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books var fileExtension = Path.GetExtension(f.FullName) ?? string.Empty; - return _validExtensions.Contains(fileExtension, + return _validExtensions.Contains( + fileExtension, StringComparer .OrdinalIgnoreCase); }).ToList(); diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs index 9a69bce0e..c850e3a08 100644 --- a/Emby.Server.Implementations/Library/SearchEngine.cs +++ b/Emby.Server.Implementations/Library/SearchEngine.cs @@ -87,61 +87,61 @@ namespace Emby.Server.Implementations.Library var excludeItemTypes = query.ExcludeItemTypes.ToList(); var includeItemTypes = (query.IncludeItemTypes ?? Array.Empty<string>()).ToList(); - excludeItemTypes.Add(typeof(Year).Name); - excludeItemTypes.Add(typeof(Folder).Name); + excludeItemTypes.Add(nameof(Year)); + excludeItemTypes.Add(nameof(Folder)); if (query.IncludeGenres && (includeItemTypes.Count == 0 || includeItemTypes.Contains("Genre", StringComparer.OrdinalIgnoreCase))) { if (!query.IncludeMedia) { - AddIfMissing(includeItemTypes, typeof(Genre).Name); - AddIfMissing(includeItemTypes, typeof(MusicGenre).Name); + AddIfMissing(includeItemTypes, nameof(Genre)); + AddIfMissing(includeItemTypes, nameof(MusicGenre)); } } else { - AddIfMissing(excludeItemTypes, typeof(Genre).Name); - AddIfMissing(excludeItemTypes, typeof(MusicGenre).Name); + AddIfMissing(excludeItemTypes, nameof(Genre)); + AddIfMissing(excludeItemTypes, nameof(MusicGenre)); } if (query.IncludePeople && (includeItemTypes.Count == 0 || includeItemTypes.Contains("People", StringComparer.OrdinalIgnoreCase) || includeItemTypes.Contains("Person", StringComparer.OrdinalIgnoreCase))) { if (!query.IncludeMedia) { - AddIfMissing(includeItemTypes, typeof(Person).Name); + AddIfMissing(includeItemTypes, nameof(Person)); } } else { - AddIfMissing(excludeItemTypes, typeof(Person).Name); + AddIfMissing(excludeItemTypes, nameof(Person)); } if (query.IncludeStudios && (includeItemTypes.Count == 0 || includeItemTypes.Contains("Studio", StringComparer.OrdinalIgnoreCase))) { if (!query.IncludeMedia) { - AddIfMissing(includeItemTypes, typeof(Studio).Name); + AddIfMissing(includeItemTypes, nameof(Studio)); } } else { - AddIfMissing(excludeItemTypes, typeof(Studio).Name); + AddIfMissing(excludeItemTypes, nameof(Studio)); } if (query.IncludeArtists && (includeItemTypes.Count == 0 || includeItemTypes.Contains("MusicArtist", StringComparer.OrdinalIgnoreCase))) { if (!query.IncludeMedia) { - AddIfMissing(includeItemTypes, typeof(MusicArtist).Name); + AddIfMissing(includeItemTypes, nameof(MusicArtist)); } } else { - AddIfMissing(excludeItemTypes, typeof(MusicArtist).Name); + AddIfMissing(excludeItemTypes, nameof(MusicArtist)); } - AddIfMissing(excludeItemTypes, typeof(CollectionFolder).Name); - AddIfMissing(excludeItemTypes, typeof(Folder).Name); + AddIfMissing(excludeItemTypes, nameof(CollectionFolder)); + AddIfMissing(excludeItemTypes, nameof(Folder)); var mediaTypes = query.MediaTypes.ToList(); if (includeItemTypes.Count > 0) diff --git a/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs b/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs index d4c8c35e6..f9a3e2c64 100644 --- a/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs @@ -81,7 +81,7 @@ namespace Emby.Server.Implementations.Library.Validators var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery { - IncludeItemTypes = new[] { typeof(MusicArtist).Name }, + IncludeItemTypes = new[] { nameof(MusicArtist) }, IsDeadArtist = true, IsLocked = false }).Cast<MusicArtist>().ToList(); diff --git a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs index 8275c873a..8739a9e1b 100644 --- a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs @@ -91,7 +91,7 @@ namespace Emby.Server.Implementations.Library.Validators var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery { - IncludeItemTypes = new[] { typeof(Person).Name }, + IncludeItemTypes = new[] { nameof(Person) }, IsDeadPerson = true, IsLocked = false }); diff --git a/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs b/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs index ca35adfff..9a8c5f39d 100644 --- a/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs @@ -80,7 +80,7 @@ namespace Emby.Server.Implementations.Library.Validators var deadEntities = _libraryManager.GetItemList(new InternalItemsQuery { - IncludeItemTypes = new[] { typeof(Studio).Name }, + IncludeItemTypes = new[] { nameof(Studio) }, IsDeadStudio = true, IsLocked = false }); |
