diff options
5 files changed, 84 insertions, 35 deletions
diff --git a/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs index 5e672f221..fa6d57466 100644 --- a/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs @@ -1,65 +1,68 @@ -#pragma warning disable CS1591 -#pragma warning disable SA1600 - using System; using System.IO; using System.Linq; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Playlists; +using MediaBrowser.Controller.Resolvers; +using MediaBrowser.LocalMetadata.Savers; using MediaBrowser.Model.Entities; namespace Emby.Server.Implementations.Library.Resolvers { + /// <summary> + /// <see cref="IItemResolver"/> for <see cref="Playlist"/> library items. + /// </summary> public class PlaylistResolver : FolderResolver<Playlist> { - private string[] SupportedCollectionTypes = new string[] { - + private string[] _musicPlaylistCollectionTypes = new string[] { string.Empty, CollectionType.Music }; - /// <summary> - /// Resolves the specified args. - /// </summary> - /// <param name="args">The args.</param> - /// <returns>BoxSet.</returns> + /// <inheritdoc/> protected override Playlist Resolve(ItemResolveArgs args) { - // It's a boxset if all of the following conditions are met: - // Is a Directory - // Contains [playlist] in the path if (args.IsDirectory) { - var filename = Path.GetFileName(args.Path); - - if (string.IsNullOrEmpty(filename)) + // It's a boxset if the path is a directory with [playlist] in it's the name + // TODO: Should this use Path.GetDirectoryName() instead? + bool isBoxSet = Path.GetFileName(args.Path) + ?.Contains("[playlist]", StringComparison.OrdinalIgnoreCase) + ?? false; + if (isBoxSet) { - return null; + return new Playlist + { + Path = args.Path, + Name = Path.GetFileName(args.Path).Replace("[playlist]", string.Empty, StringComparison.OrdinalIgnoreCase).Trim() + }; } - if (filename.IndexOf("[playlist]", StringComparison.OrdinalIgnoreCase) != -1) + // It's a directory-based playlist if the directory contains a playlist file + var filePaths = Directory.EnumerateFiles(args.Path); + if (filePaths.Any(f => f.EndsWith(PlaylistXmlSaver.DefaultPlaylistFilename, StringComparison.OrdinalIgnoreCase))) { return new Playlist { Path = args.Path, - Name = Path.GetFileName(args.Path).Replace("[playlist]", string.Empty, StringComparison.OrdinalIgnoreCase).Trim() + Name = Path.GetFileName(args.Path) }; } } - else + + // Check if this is a music playlist file + // It should have the correct collection type and a supported file extension + else if (_musicPlaylistCollectionTypes.Contains(args.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase)) { - if (SupportedCollectionTypes.Contains(args.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase)) + var extension = Path.GetExtension(args.Path); + if (Playlist.SupportedExtensions.Contains(extension ?? string.Empty, StringComparer.OrdinalIgnoreCase)) { - var extension = Path.GetExtension(args.Path); - if (Playlist.SupportedExtensions.Contains(extension ?? string.Empty, StringComparer.OrdinalIgnoreCase)) + return new Playlist { - return new Playlist - { - Path = args.Path, - Name = Path.GetFileNameWithoutExtension(args.Path), - IsInMixedFolder = true - }; - } + Path = args.Path, + Name = Path.GetFileNameWithoutExtension(args.Path), + IsInMixedFolder = true + }; } } diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 3d1e4a363..15284958d 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -815,7 +815,7 @@ namespace MediaBrowser.Api.Library if (!string.IsNullOrWhiteSpace(filename)) { // Kestrel doesn't support non-ASCII characters in headers - if (Regex.IsMatch(filename, "[^[:ascii:]]")) + if (Regex.IsMatch(filename, @"[^\p{IsBasicLatin}]")) { // Manually encoding non-ASCII characters, following https://tools.ietf.org/html/rfc5987#section-3.2.2 headers[HeaderNames.ContentDisposition] = "attachment; filename*=UTF-8''" + WebUtility.UrlEncode(filename); diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index a892be7a9..c72bd487e 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -807,11 +807,45 @@ namespace MediaBrowser.Controller.Entities return false; } + private static BaseItem[] SortItemsByRequest(InternalItemsQuery query, IReadOnlyList<BaseItem> items) + { + var ids = query.ItemIds; + int size = items.Count; + + // ids can potentially contain non-unique guids, but query result cannot, + // so we include only first occurrence of each guid + var positions = new Dictionary<Guid, int>(size); + int index = 0; + for (int i = 0; i < ids.Length; i++) + { + if (positions.TryAdd(ids[i], index)) + { + index++; + } + } + + var newItems = new BaseItem[size]; + for (int i = 0; i < size; i++) + { + var item = items[i]; + newItems[positions[item.Id]] = item; + } + + return newItems; + } + public QueryResult<BaseItem> GetItems(InternalItemsQuery query) { if (query.ItemIds.Length > 0) { - return LibraryManager.GetItemsResult(query); + var result = LibraryManager.GetItemsResult(query); + + if (query.OrderBy.Count == 0 && query.ItemIds.Length > 1) + { + result.Items = SortItemsByRequest(query, result.Items); + } + + return result; } return GetItemsInternal(query); @@ -823,7 +857,14 @@ namespace MediaBrowser.Controller.Entities if (query.ItemIds.Length > 0) { - return LibraryManager.GetItemList(query); + var result = LibraryManager.GetItemList(query); + + if (query.OrderBy.Count == 0 && query.ItemIds.Length > 1) + { + return SortItemsByRequest(query, result); + } + + return result.ToArray(); } return GetItemsInternal(query).Items; diff --git a/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs index 35a431fa4..1a661edef 100644 --- a/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs @@ -11,6 +11,11 @@ namespace MediaBrowser.LocalMetadata.Savers { public class PlaylistXmlSaver : BaseXmlSaver { + /// <summary> + /// The default file name to use when creating a new playlist. + /// </summary> + public const string DefaultPlaylistFilename = "playlist.xml"; + public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType) { if (!item.SupportsLocalMetadata) @@ -45,7 +50,7 @@ namespace MediaBrowser.LocalMetadata.Savers return Path.ChangeExtension(itemPath, ".xml"); } - return Path.Combine(path, "playlist.xml"); + return Path.Combine(path, DefaultPlaylistFilename); } public PlaylistXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger) diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs index ff431e44c..b3a784de7 100644 --- a/MediaBrowser.Model/Configuration/EncodingOptions.cs +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -34,7 +34,7 @@ namespace MediaBrowser.Model.Configuration public EncodingOptions() { DownMixAudioBoost = 2; - EnableThrottling = true; + EnableThrottling = false; ThrottleDelaySeconds = 180; EncodingThreadCount = -1; // This is a DRM device that is almost guaranteed to be there on every intel platform, plus it's the default one in ffmpeg if you don't specify anything |
