From f53472584eedbf21dfb43902fedda89aff57ff77 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 29 Apr 2017 02:22:33 -0400 Subject: update environment detection --- Emby.Server.Implementations/Channels/ChannelManager.cs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'Emby.Server.Implementations/Channels') diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 8f03fa7a47..9ac6459a12 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -275,17 +275,7 @@ namespace Emby.Server.Implementations.Channels public async Task> GetStaticMediaSources(BaseItem item, CancellationToken cancellationToken) { - IEnumerable results = new List(); - var video = item as Video; - if (video != null) - { - results = video.ChannelMediaSources; - } - var audio = item as Audio; - if (audio != null) - { - results = audio.ChannelMediaSources ?? GetSavedMediaSources(audio); - } + IEnumerable results = GetSavedMediaSources(item); return SortMediaInfoResults(results) .Select(i => GetMediaSource(item, i)) @@ -1378,7 +1368,6 @@ namespace Emby.Server.Implementations.Channels if (channelVideoItem != null) { channelVideoItem.ExtraType = info.ExtraType; - channelVideoItem.ChannelMediaSources = info.MediaSources; var mediaSource = info.MediaSources.FirstOrDefault(); item.Path = mediaSource == null ? null : mediaSource.Path; -- cgit v1.2.3 From a9b041a7e62f408e07d15cb7cf253d76919b6fa1 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 29 Apr 2017 22:37:51 -0400 Subject: rework refresh queue --- .../Channels/ChannelManager.cs | 2 +- .../Collections/CollectionManager.cs | 6 +- .../Library/LibraryManager.cs | 11 +- .../LiveTv/LiveTvManager.cs | 7 +- .../Playlists/PlaylistManager.cs | 6 +- MediaBrowser.Api/ItemRefreshService.cs | 9 +- MediaBrowser.Api/Subtitles/SubtitleService.cs | 2 +- MediaBrowser.Controller/Entities/BaseItem.cs | 2 +- .../Providers/IProviderManager.cs | 11 +- .../Manager/GenericPriorityQueue.cs | 426 +++++++++++++++++++++ .../Manager/GenericPriorityQueueNode.cs | 28 ++ .../Manager/IFixedSizePriorityQueue.cs | 28 ++ MediaBrowser.Providers/Manager/IPriorityQueue.cs | 59 +++ MediaBrowser.Providers/Manager/ProviderManager.cs | 22 +- .../Manager/SimplePriorityQueue.cs | 243 ++++++++++++ .../MediaBrowser.Providers.csproj | 5 + .../Movies/FanartMovieImageProvider.cs | 1 - MediaBrowser.Providers/Movies/MovieDbProvider.cs | 7 - .../Music/AudioDbArtistProvider.cs | 2 - .../Music/FanArtArtistProvider.cs | 2 - .../Music/MusicBrainzAlbumProvider.cs | 6 - MediaBrowser.Providers/Omdb/OmdbProvider.cs | 2 - .../Subtitles/SubtitleManager.cs | 7 +- .../TV/FanArt/FanartSeriesProvider.cs | 1 - .../TV/TheMovieDb/MovieDbProviderBase.cs | 3 +- .../TV/TheTVDB/TvdbEpisodeImageProvider.cs | 3 +- .../TV/TheTVDB/TvdbEpisodeProvider.cs | 3 +- .../TV/TheTVDB/TvdbPrescanTask.cs | 2 - .../TV/TheTVDB/TvdbSeasonImageProvider.cs | 3 +- .../TV/TheTVDB/TvdbSeriesImageProvider.cs | 3 +- .../TV/TheTVDB/TvdbSeriesProvider.cs | 5 - 31 files changed, 838 insertions(+), 79 deletions(-) create mode 100644 MediaBrowser.Providers/Manager/GenericPriorityQueue.cs create mode 100644 MediaBrowser.Providers/Manager/GenericPriorityQueueNode.cs create mode 100644 MediaBrowser.Providers/Manager/IFixedSizePriorityQueue.cs create mode 100644 MediaBrowser.Providers/Manager/IPriorityQueue.cs create mode 100644 MediaBrowser.Providers/Manager/SimplePriorityQueue.cs (limited to 'Emby.Server.Implementations/Channels') diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 9ac6459a12..de76157ba7 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -1416,7 +1416,7 @@ namespace Emby.Server.Implementations.Channels if (!_refreshedItems.ContainsKey(program.Id)) { _refreshedItems.TryAdd(program.Id, true); - _providerManager.QueueRefresh(program.Id, new MetadataRefreshOptions(_fileSystem)); + _providerManager.QueueRefresh(program.Id, new MetadataRefreshOptions(_fileSystem), RefreshPriority.Low); } } diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs index d0bd76c354..9c26655fc7 100644 --- a/Emby.Server.Implementations/Collections/CollectionManager.cs +++ b/Emby.Server.Implementations/Collections/CollectionManager.cs @@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.Collections } else { - _providerManager.QueueRefresh(collection.Id, new MetadataRefreshOptions(_fileSystem)); + _providerManager.QueueRefresh(collection.Id, new MetadataRefreshOptions(_fileSystem), RefreshPriority.High); } EventHelper.FireEventIfNotNull(CollectionCreated, this, new CollectionCreatedEventArgs @@ -191,7 +191,7 @@ namespace Emby.Server.Implementations.Collections await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); - _providerManager.QueueRefresh(collection.Id, refreshOptions); + _providerManager.QueueRefresh(collection.Id, refreshOptions, RefreshPriority.High); if (fireEvent) { @@ -244,7 +244,7 @@ namespace Emby.Server.Implementations.Collections collection.UpdateRatingToContent(); await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); - _providerManager.QueueRefresh(collection.Id, new MetadataRefreshOptions(_fileSystem)); + _providerManager.QueueRefresh(collection.Id, new MetadataRefreshOptions(_fileSystem), RefreshPriority.High); EventHelper.FireEventIfNotNull(ItemsRemovedFromCollection, this, new CollectionModifiedEventArgs { diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 16a73f3922..684ad6284a 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -2126,7 +2126,8 @@ namespace Emby.Server.Implementations.Library // Not sure why this is necessary but need to figure it out // View images are not getting utilized without this ForceSave = true - }); + + }, RefreshPriority.Normal); } return item; @@ -2188,7 +2189,8 @@ namespace Emby.Server.Implementations.Library { // Need to force save to increment DateLastSaved ForceSave = true - }); + + }, RefreshPriority.Normal); } return item; @@ -2252,7 +2254,8 @@ namespace Emby.Server.Implementations.Library { // Need to force save to increment DateLastSaved ForceSave = true - }); + + }, RefreshPriority.Normal); } return item; @@ -2328,7 +2331,7 @@ namespace Emby.Server.Implementations.Library { // Need to force save to increment DateLastSaved ForceSave = true - }); + }, RefreshPriority.Normal); } return item; diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index a898d30844..fa86ac36d0 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -857,7 +857,8 @@ namespace Emby.Server.Implementations.LiveTv _providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem) { MetadataRefreshMode = metadataRefreshMode - }); + + }, RefreshPriority.Normal); } return item.Id; @@ -1395,11 +1396,11 @@ namespace Emby.Server.Implementations.LiveTv foreach (var program in newPrograms) { - _providerManager.QueueRefresh(program.Id, new MetadataRefreshOptions(_fileSystem)); + _providerManager.QueueRefresh(program.Id, new MetadataRefreshOptions(_fileSystem), RefreshPriority.Low); } foreach (var program in updatedPrograms) { - _providerManager.QueueRefresh(program.Id, new MetadataRefreshOptions(_fileSystem)); + _providerManager.QueueRefresh(program.Id, new MetadataRefreshOptions(_fileSystem), RefreshPriority.Low); } currentChannel.IsMovie = isMovie; diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index 386da73c64..18042b5870 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -201,7 +201,8 @@ namespace Emby.Server.Implementations.Playlists _providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions(_fileSystem) { ForceSave = true - }); + + }, RefreshPriority.High); } public async Task RemoveFromPlaylist(string playlistId, IEnumerable entryIds) @@ -228,7 +229,8 @@ namespace Emby.Server.Implementations.Playlists _providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions(_fileSystem) { ForceSave = true - }); + + }, RefreshPriority.High); } public async Task MoveItem(string playlistId, string entryId, int newIndex) diff --git a/MediaBrowser.Api/ItemRefreshService.cs b/MediaBrowser.Api/ItemRefreshService.cs index 81547637ef..bca292241b 100644 --- a/MediaBrowser.Api/ItemRefreshService.cs +++ b/MediaBrowser.Api/ItemRefreshService.cs @@ -62,14 +62,7 @@ namespace MediaBrowser.Api var options = GetRefreshOptions(request); - if (item is Folder) - { - _providerManager.QueueRefresh(item.Id, options); - } - else - { - _providerManager.RefreshFullItem(item, options, CancellationToken.None); - } + _providerManager.QueueRefresh(item.Id, options, RefreshPriority.High); } private MetadataRefreshOptions GetRefreshOptions(BaseRefreshRequest request) diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs index 47d442e796..798004a5ef 100644 --- a/MediaBrowser.Api/Subtitles/SubtitleService.cs +++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs @@ -288,7 +288,7 @@ namespace MediaBrowser.Api.Subtitles await _subtitleManager.DownloadSubtitles(video, request.SubtitleId, CancellationToken.None) .ConfigureAwait(false); - _providerManager.QueueRefresh(video.Id, new MetadataRefreshOptions(_fileSystem)); + _providerManager.QueueRefresh(video.Id, new MetadataRefreshOptions(_fileSystem), RefreshPriority.High); } catch (Exception ex) { diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 31b0783b2b..04ddb2729c 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1817,7 +1817,7 @@ namespace MediaBrowser.Controller.Entities /// Task. public virtual Task ChangedExternally() { - ProviderManager.QueueRefresh(Id, new MetadataRefreshOptions(FileSystem)); + ProviderManager.QueueRefresh(Id, new MetadataRefreshOptions(FileSystem), RefreshPriority.High); return Task.FromResult(true); } diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index f4d45c7e0c..c0bc902140 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -20,9 +20,7 @@ namespace MediaBrowser.Controller.Providers /// /// Queues the refresh. /// - /// The item identifier. - /// The options. - void QueueRefresh(Guid itemId, MetadataRefreshOptions options); + void QueueRefresh(Guid itemId, MetadataRefreshOptions options, RefreshPriority priority); /// /// Refreshes the full item. @@ -161,4 +159,11 @@ namespace MediaBrowser.Controller.Providers /// Task{HttpResponseInfo}. Task GetSearchImage(string providerName, string url, CancellationToken cancellationToken); } + + public enum RefreshPriority + { + High = 0, + Normal = 1, + Low = 2 + } } \ No newline at end of file diff --git a/MediaBrowser.Providers/Manager/GenericPriorityQueue.cs b/MediaBrowser.Providers/Manager/GenericPriorityQueue.cs new file mode 100644 index 0000000000..18998fd599 --- /dev/null +++ b/MediaBrowser.Providers/Manager/GenericPriorityQueue.cs @@ -0,0 +1,426 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Priority_Queue +{ + /// + /// Credit: https://github.com/BlueRaja/High-Speed-Priority-Queue-for-C-Sharp + /// A copy of StablePriorityQueue which also has generic priority-type + /// + /// The values in the queue. Must extend the GenericPriorityQueue class + /// The priority-type. Must extend IComparable<TPriority> + public sealed class GenericPriorityQueue : IFixedSizePriorityQueue + where TItem : GenericPriorityQueueNode + where TPriority : IComparable + { + private int _numNodes; + private TItem[] _nodes; + private long _numNodesEverEnqueued; + + /// + /// Instantiate a new Priority Queue + /// + /// The max nodes ever allowed to be enqueued (going over this will cause undefined behavior) + public GenericPriorityQueue(int maxNodes) + { +#if DEBUG + if (maxNodes <= 0) + { + throw new InvalidOperationException("New queue size cannot be smaller than 1"); + } +#endif + + _numNodes = 0; + _nodes = new TItem[maxNodes + 1]; + _numNodesEverEnqueued = 0; + } + + /// + /// Returns the number of nodes in the queue. + /// O(1) + /// + public int Count + { + get + { + return _numNodes; + } + } + + /// + /// Returns the maximum number of items that can be enqueued at once in this queue. Once you hit this number (ie. once Count == MaxSize), + /// attempting to enqueue another item will cause undefined behavior. O(1) + /// + public int MaxSize + { + get + { + return _nodes.Length - 1; + } + } + + /// + /// Removes every node from the queue. + /// O(n) (So, don't do this often!) + /// +#if NET_VERSION_4_5 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void Clear() + { + Array.Clear(_nodes, 1, _numNodes); + _numNodes = 0; + } + + /// + /// Returns (in O(1)!) whether the given node is in the queue. O(1) + /// +#if NET_VERSION_4_5 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public bool Contains(TItem node) + { +#if DEBUG + if (node == null) + { + throw new ArgumentNullException("node"); + } + if (node.QueueIndex < 0 || node.QueueIndex >= _nodes.Length) + { + throw new InvalidOperationException("node.QueueIndex has been corrupted. Did you change it manually? Or add this node to another queue?"); + } +#endif + + return (_nodes[node.QueueIndex] == node); + } + + /// + /// Enqueue a node to the priority queue. Lower values are placed in front. Ties are broken by first-in-first-out. + /// If the queue is full, the result is undefined. + /// If the node is already enqueued, the result is undefined. + /// O(log n) + /// +#if NET_VERSION_4_5 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void Enqueue(TItem node, TPriority priority) + { +#if DEBUG + if (node == null) + { + throw new ArgumentNullException("node"); + } + if (_numNodes >= _nodes.Length - 1) + { + throw new InvalidOperationException("Queue is full - node cannot be added: " + node); + } + if (Contains(node)) + { + throw new InvalidOperationException("Node is already enqueued: " + node); + } +#endif + + node.Priority = priority; + _numNodes++; + _nodes[_numNodes] = node; + node.QueueIndex = _numNodes; + node.InsertionIndex = _numNodesEverEnqueued++; + CascadeUp(_nodes[_numNodes]); + } + +#if NET_VERSION_4_5 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private void Swap(TItem node1, TItem node2) + { + //Swap the nodes + _nodes[node1.QueueIndex] = node2; + _nodes[node2.QueueIndex] = node1; + + //Swap their indicies + int temp = node1.QueueIndex; + node1.QueueIndex = node2.QueueIndex; + node2.QueueIndex = temp; + } + + //Performance appears to be slightly better when this is NOT inlined o_O + private void CascadeUp(TItem node) + { + //aka Heapify-up + int parent = node.QueueIndex / 2; + while (parent >= 1) + { + TItem parentNode = _nodes[parent]; + if (HasHigherPriority(parentNode, node)) + break; + + //Node has lower priority value, so move it up the heap + Swap(node, parentNode); //For some reason, this is faster with Swap() rather than (less..?) individual operations, like in CascadeDown() + + parent = node.QueueIndex / 2; + } + } + +#if NET_VERSION_4_5 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private void CascadeDown(TItem node) + { + //aka Heapify-down + TItem newParent; + int finalQueueIndex = node.QueueIndex; + while (true) + { + newParent = node; + int childLeftIndex = 2 * finalQueueIndex; + + //Check if the left-child is higher-priority than the current node + if (childLeftIndex > _numNodes) + { + //This could be placed outside the loop, but then we'd have to check newParent != node twice + node.QueueIndex = finalQueueIndex; + _nodes[finalQueueIndex] = node; + break; + } + + TItem childLeft = _nodes[childLeftIndex]; + if (HasHigherPriority(childLeft, newParent)) + { + newParent = childLeft; + } + + //Check if the right-child is higher-priority than either the current node or the left child + int childRightIndex = childLeftIndex + 1; + if (childRightIndex <= _numNodes) + { + TItem childRight = _nodes[childRightIndex]; + if (HasHigherPriority(childRight, newParent)) + { + newParent = childRight; + } + } + + //If either of the children has higher (smaller) priority, swap and continue cascading + if (newParent != node) + { + //Move new parent to its new index. node will be moved once, at the end + //Doing it this way is one less assignment operation than calling Swap() + _nodes[finalQueueIndex] = newParent; + + int temp = newParent.QueueIndex; + newParent.QueueIndex = finalQueueIndex; + finalQueueIndex = temp; + } + else + { + //See note above + node.QueueIndex = finalQueueIndex; + _nodes[finalQueueIndex] = node; + break; + } + } + } + + /// + /// Returns true if 'higher' has higher priority than 'lower', false otherwise. + /// Note that calling HasHigherPriority(node, node) (ie. both arguments the same node) will return false + /// +#if NET_VERSION_4_5 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + private bool HasHigherPriority(TItem higher, TItem lower) + { + var cmp = higher.Priority.CompareTo(lower.Priority); + return (cmp < 0 || (cmp == 0 && higher.InsertionIndex < lower.InsertionIndex)); + } + + /// + /// Removes the head of the queue (node with minimum priority; ties are broken by order of insertion), and returns it. + /// If queue is empty, result is undefined + /// O(log n) + /// + public TItem Dequeue() + { +#if DEBUG + if (_numNodes <= 0) + { + throw new InvalidOperationException("Cannot call Dequeue() on an empty queue"); + } + + if (!IsValidQueue()) + { + throw new InvalidOperationException("Queue has been corrupted (Did you update a node priority manually instead of calling UpdatePriority()?" + + "Or add the same node to two different queues?)"); + } +#endif + + TItem returnMe = _nodes[1]; + Remove(returnMe); + return returnMe; + } + + /// + /// Resize the queue so it can accept more nodes. All currently enqueued nodes are remain. + /// Attempting to decrease the queue size to a size too small to hold the existing nodes results in undefined behavior + /// O(n) + /// + public void Resize(int maxNodes) + { +#if DEBUG + if (maxNodes <= 0) + { + throw new InvalidOperationException("Queue size cannot be smaller than 1"); + } + + if (maxNodes < _numNodes) + { + throw new InvalidOperationException("Called Resize(" + maxNodes + "), but current queue contains " + _numNodes + " nodes"); + } +#endif + + TItem[] newArray = new TItem[maxNodes + 1]; + int highestIndexToCopy = Math.Min(maxNodes, _numNodes); + for (int i = 1; i <= highestIndexToCopy; i++) + { + newArray[i] = _nodes[i]; + } + _nodes = newArray; + } + + /// + /// Returns the head of the queue, without removing it (use Dequeue() for that). + /// If the queue is empty, behavior is undefined. + /// O(1) + /// + public TItem First + { + get + { +#if DEBUG + if (_numNodes <= 0) + { + throw new InvalidOperationException("Cannot call .First on an empty queue"); + } +#endif + + return _nodes[1]; + } + } + + /// + /// This method must be called on a node every time its priority changes while it is in the queue. + /// Forgetting to call this method will result in a corrupted queue! + /// Calling this method on a node not in the queue results in undefined behavior + /// O(log n) + /// +#if NET_VERSION_4_5 + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public void UpdatePriority(TItem node, TPriority priority) + { +#if DEBUG + if (node == null) + { + throw new ArgumentNullException("node"); + } + if (!Contains(node)) + { + throw new InvalidOperationException("Cannot call UpdatePriority() on a node which is not enqueued: " + node); + } +#endif + + node.Priority = priority; + OnNodeUpdated(node); + } + + private void OnNodeUpdated(TItem node) + { + //Bubble the updated node up or down as appropriate + int parentIndex = node.QueueIndex / 2; + TItem parentNode = _nodes[parentIndex]; + + if (parentIndex > 0 && HasHigherPriority(node, parentNode)) + { + CascadeUp(node); + } + else + { + //Note that CascadeDown will be called if parentNode == node (that is, node is the root) + CascadeDown(node); + } + } + + /// + /// Removes a node from the queue. The node does not need to be the head of the queue. + /// If the node is not in the queue, the result is undefined. If unsure, check Contains() first + /// O(log n) + /// + public void Remove(TItem node) + { +#if DEBUG + if (node == null) + { + throw new ArgumentNullException("node"); + } + if (!Contains(node)) + { + throw new InvalidOperationException("Cannot call Remove() on a node which is not enqueued: " + node); + } +#endif + + //If the node is already the last node, we can remove it immediately + if (node.QueueIndex == _numNodes) + { + _nodes[_numNodes] = null; + _numNodes--; + return; + } + + //Swap the node with the last node + TItem formerLastNode = _nodes[_numNodes]; + Swap(node, formerLastNode); + _nodes[_numNodes] = null; + _numNodes--; + + //Now bubble formerLastNode (which is no longer the last node) up or down as appropriate + OnNodeUpdated(formerLastNode); + } + + public IEnumerator GetEnumerator() + { + for (int i = 1; i <= _numNodes; i++) + yield return _nodes[i]; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// Should not be called in production code. + /// Checks to make sure the queue is still in a valid state. Used for testing/debugging the queue. + /// + public bool IsValidQueue() + { + for (int i = 1; i < _nodes.Length; i++) + { + if (_nodes[i] != null) + { + int childLeftIndex = 2 * i; + if (childLeftIndex < _nodes.Length && _nodes[childLeftIndex] != null && HasHigherPriority(_nodes[childLeftIndex], _nodes[i])) + return false; + + int childRightIndex = childLeftIndex + 1; + if (childRightIndex < _nodes.Length && _nodes[childRightIndex] != null && HasHigherPriority(_nodes[childRightIndex], _nodes[i])) + return false; + } + } + return true; + } + } +} diff --git a/MediaBrowser.Providers/Manager/GenericPriorityQueueNode.cs b/MediaBrowser.Providers/Manager/GenericPriorityQueueNode.cs new file mode 100644 index 0000000000..e6e93e4433 --- /dev/null +++ b/MediaBrowser.Providers/Manager/GenericPriorityQueueNode.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Priority_Queue +{ + /// Credit: https://github.com/BlueRaja/High-Speed-Priority-Queue-for-C-Sharp + public class GenericPriorityQueueNode + { + /// + /// The Priority to insert this node at. Must be set BEFORE adding a node to the queue (ideally just once, in the node's constructor). + /// Should not be manually edited once the node has been enqueued - use queue.UpdatePriority() instead + /// + public TPriority Priority { get; protected internal set; } + + /// + /// Represents the current position in the queue + /// + public int QueueIndex { get; internal set; } + + /// + /// Represents the order the node was inserted in + /// + public long InsertionIndex { get; internal set; } + } +} diff --git a/MediaBrowser.Providers/Manager/IFixedSizePriorityQueue.cs b/MediaBrowser.Providers/Manager/IFixedSizePriorityQueue.cs new file mode 100644 index 0000000000..8da88e1c6f --- /dev/null +++ b/MediaBrowser.Providers/Manager/IFixedSizePriorityQueue.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Priority_Queue +{ + /// + /// Credit: https://github.com/BlueRaja/High-Speed-Priority-Queue-for-C-Sharp + /// A helper-interface only needed to make writing unit tests a bit easier (hence the 'internal' access modifier) + /// + internal interface IFixedSizePriorityQueue : IPriorityQueue + where TPriority : IComparable + { + /// + /// Resize the queue so it can accept more nodes. All currently enqueued nodes are remain. + /// Attempting to decrease the queue size to a size too small to hold the existing nodes results in undefined behavior + /// + void Resize(int maxNodes); + + /// + /// Returns the maximum number of items that can be enqueued at once in this queue. Once you hit this number (ie. once Count == MaxSize), + /// attempting to enqueue another item will cause undefined behavior. + /// + int MaxSize { get; } + } +} \ No newline at end of file diff --git a/MediaBrowser.Providers/Manager/IPriorityQueue.cs b/MediaBrowser.Providers/Manager/IPriorityQueue.cs new file mode 100644 index 0000000000..11f2c62148 --- /dev/null +++ b/MediaBrowser.Providers/Manager/IPriorityQueue.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Priority_Queue +{ + /// + /// Credit: https://github.com/BlueRaja/High-Speed-Priority-Queue-for-C-Sharp + /// The IPriorityQueue interface. This is mainly here for purists, and in case I decide to add more implementations later. + /// For speed purposes, it is actually recommended that you *don't* access the priority queue through this interface, since the JIT can + /// (theoretically?) optimize method calls from concrete-types slightly better. + /// + public interface IPriorityQueue : IEnumerable + where TPriority : IComparable + { + /// + /// Enqueue a node to the priority queue. Lower values are placed in front. Ties are broken by first-in-first-out. + /// See implementation for how duplicates are handled. + /// + void Enqueue(TItem node, TPriority priority); + + /// + /// Removes the head of the queue (node with minimum priority; ties are broken by order of insertion), and returns it. + /// + TItem Dequeue(); + + /// + /// Removes every node from the queue. + /// + void Clear(); + + /// + /// Returns whether the given node is in the queue. + /// + bool Contains(TItem node); + + /// + /// Removes a node from the queue. The node does not need to be the head of the queue. + /// + void Remove(TItem node); + + /// + /// Call this method to change the priority of a node. + /// + void UpdatePriority(TItem node, TPriority priority); + + /// + /// Returns the head of the queue, without removing it (use Dequeue() for that). + /// + TItem First { get; } + + /// + /// Returns the number of nodes in the queue. + /// + int Count { get; } + } +} diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 0b8dca2eb0..f08a7d3c32 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -24,6 +24,7 @@ using MediaBrowser.Common.IO; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; +using Priority_Queue; namespace MediaBrowser.Providers.Manager { @@ -577,7 +578,6 @@ namespace MediaBrowser.Providers.Manager return SaveMetadata(item, updateType, _savers.Where(i => savers.Contains(i.Name, StringComparer.OrdinalIgnoreCase))); } - private readonly SemaphoreSlim _saveLock = new SemaphoreSlim(1, 1); /// /// Saves the metadata. /// @@ -607,8 +607,6 @@ namespace MediaBrowser.Providers.Manager continue; } - await _saveLock.WaitAsync().ConfigureAwait(false); - try { _libraryMonitor.ReportFileSystemChangeBeginning(path); @@ -620,7 +618,6 @@ namespace MediaBrowser.Providers.Manager } finally { - _saveLock.Release(); _libraryMonitor.ReportFileSystemChangeComplete(path, false); } } @@ -851,20 +848,20 @@ namespace MediaBrowser.Providers.Manager }); } - private readonly ConcurrentQueue> _refreshQueue = - new ConcurrentQueue>(); + private readonly SimplePriorityQueue> _refreshQueue = + new SimplePriorityQueue>(); private readonly object _refreshQueueLock = new object(); private bool _isProcessingRefreshQueue; - public void QueueRefresh(Guid id, MetadataRefreshOptions options) + public void QueueRefresh(Guid id, MetadataRefreshOptions options, RefreshPriority priority) { if (_disposed) { return; } - _refreshQueue.Enqueue(new Tuple(id, options)); + _refreshQueue.Enqueue(new Tuple(id, options), (int)priority); lock (_refreshQueueLock) { @@ -876,12 +873,19 @@ namespace MediaBrowser.Providers.Manager } } + private bool TryDequeue(out Tuple item) + { + item = _refreshQueue.Dequeue(); + + return item != null; + } + private async Task StartProcessingRefreshQueue() { Tuple refreshItem; var libraryManager = _libraryManagerFactory(); - while (_refreshQueue.TryDequeue(out refreshItem)) + while (TryDequeue(out refreshItem)) { if (_disposed) { diff --git a/MediaBrowser.Providers/Manager/SimplePriorityQueue.cs b/MediaBrowser.Providers/Manager/SimplePriorityQueue.cs new file mode 100644 index 0000000000..6435aa06b9 --- /dev/null +++ b/MediaBrowser.Providers/Manager/SimplePriorityQueue.cs @@ -0,0 +1,243 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Priority_Queue +{ + /// + /// Credit: https://github.com/BlueRaja/High-Speed-Priority-Queue-for-C-Sharp + /// A simplified priority queue implementation. Is stable, auto-resizes, and thread-safe, at the cost of being slightly slower than + /// FastPriorityQueue + /// + /// The type to enqueue + /// The priority-type to use for nodes. Must extend IComparable<TPriority> + public class SimplePriorityQueue : IPriorityQueue + where TPriority : IComparable + { + private class SimpleNode : GenericPriorityQueueNode + { + public TItem Data { get; private set; } + + public SimpleNode(TItem data) + { + Data = data; + } + } + + private const int INITIAL_QUEUE_SIZE = 10; + private readonly GenericPriorityQueue _queue; + + public SimplePriorityQueue() + { + _queue = new GenericPriorityQueue(INITIAL_QUEUE_SIZE); + } + + /// + /// Given an item of type T, returns the exist SimpleNode in the queue + /// + private SimpleNode GetExistingNode(TItem item) + { + var comparer = EqualityComparer.Default; + foreach (var node in _queue) + { + if (comparer.Equals(node.Data, item)) + { + return node; + } + } + throw new InvalidOperationException("Item cannot be found in queue: " + item); + } + + /// + /// Returns the number of nodes in the queue. + /// O(1) + /// + public int Count + { + get + { + lock (_queue) + { + return _queue.Count; + } + } + } + + + /// + /// Returns the head of the queue, without removing it (use Dequeue() for that). + /// Throws an exception when the queue is empty. + /// O(1) + /// + public TItem First + { + get + { + lock (_queue) + { + if (_queue.Count <= 0) + { + throw new InvalidOperationException("Cannot call .First on an empty queue"); + } + + SimpleNode first = _queue.First; + return (first != null ? first.Data : default(TItem)); + } + } + } + + /// + /// Removes every node from the queue. + /// O(n) + /// + public void Clear() + { + lock (_queue) + { + _queue.Clear(); + } + } + + /// + /// Returns whether the given item is in the queue. + /// O(n) + /// + public bool Contains(TItem item) + { + lock (_queue) + { + var comparer = EqualityComparer.Default; + foreach (var node in _queue) + { + if (comparer.Equals(node.Data, item)) + { + return true; + } + } + return false; + } + } + + /// + /// Removes the head of the queue (node with minimum priority; ties are broken by order of insertion), and returns it. + /// If queue is empty, throws an exception + /// O(log n) + /// + public TItem Dequeue() + { + lock (_queue) + { + if (_queue.Count <= 0) + { + throw new InvalidOperationException("Cannot call Dequeue() on an empty queue"); + } + + SimpleNode node = _queue.Dequeue(); + return node.Data; + } + } + + /// + /// Enqueue a node to the priority queue. Lower values are placed in front. Ties are broken by first-in-first-out. + /// This queue automatically resizes itself, so there's no concern of the queue becoming 'full'. + /// Duplicates are allowed. + /// O(log n) + /// + public void Enqueue(TItem item, TPriority priority) + { + lock (_queue) + { + SimpleNode node = new SimpleNode(item); + if (_queue.Count == _queue.MaxSize) + { + _queue.Resize(_queue.MaxSize * 2 + 1); + } + _queue.Enqueue(node, priority); + } + } + + /// + /// Removes an item from the queue. The item does not need to be the head of the queue. + /// If the item is not in the queue, an exception is thrown. If unsure, check Contains() first. + /// If multiple copies of the item are enqueued, only the first one is removed. + /// O(n) + /// + public void Remove(TItem item) + { + lock (_queue) + { + try + { + _queue.Remove(GetExistingNode(item)); + } + catch (InvalidOperationException ex) + { + throw new InvalidOperationException("Cannot call Remove() on a node which is not enqueued: " + item, ex); + } + } + } + + /// + /// Call this method to change the priority of an item. + /// Calling this method on a item not in the queue will throw an exception. + /// If the item is enqueued multiple times, only the first one will be updated. + /// (If your requirements are complex enough that you need to enqueue the same item multiple times and be able + /// to update all of them, please wrap your items in a wrapper class so they can be distinguished). + /// O(n) + /// + public void UpdatePriority(TItem item, TPriority priority) + { + lock (_queue) + { + try + { + SimpleNode updateMe = GetExistingNode(item); + _queue.UpdatePriority(updateMe, priority); + } + catch (InvalidOperationException ex) + { + throw new InvalidOperationException("Cannot call UpdatePriority() on a node which is not enqueued: " + item, ex); + } + } + } + + public IEnumerator GetEnumerator() + { + List queueData = new List(); + lock (_queue) + { + //Copy to a separate list because we don't want to 'yield return' inside a lock + foreach (var node in _queue) + { + queueData.Add(node.Data); + } + } + + return queueData.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public bool IsValidQueue() + { + lock (_queue) + { + return _queue.IsValidQueue(); + } + } + } + + /// + /// A simplified priority queue implementation. Is stable, auto-resizes, and thread-safe, at the cost of being slightly slower than + /// FastPriorityQueue + /// This class is kept here for backwards compatibility. It's recommended you use Simple + /// + /// The type to enqueue + public class SimplePriorityQueue : SimplePriorityQueue { } +} \ No newline at end of file diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index fe554545fa..9d20ec4239 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -65,10 +65,15 @@ + + + + + diff --git a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs index dd2cad1f94..946d6e68d6 100644 --- a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs +++ b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs @@ -284,7 +284,6 @@ namespace MediaBrowser.Providers.Movies using (var response = await _httpClient.Get(new HttpRequestOptions { Url = url, - ResourcePool = FanartArtistProvider.Current.FanArtResourcePool, CancellationToken = cancellationToken, BufferContent = true diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs index 8e4b86519b..b3cf0541e9 100644 --- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs @@ -30,8 +30,6 @@ namespace MediaBrowser.Providers.Movies /// public class MovieDbProvider : IRemoteMetadataProvider, IDisposable, IHasOrder { - internal readonly SemaphoreSlim MovieDbResourcePool = new SemaphoreSlim(1, 1); - internal static MovieDbProvider Current { get; private set; } private readonly IJsonSerializer _jsonSerializer; @@ -137,10 +135,6 @@ namespace MediaBrowser.Providers.Movies /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool dispose) { - if (dispose) - { - MovieDbResourcePool.Dispose(); - } } /// @@ -431,7 +425,6 @@ namespace MediaBrowser.Providers.Movies await Task.Delay(Convert.ToInt32(delayMs)).ConfigureAwait(false); } - options.ResourcePool = MovieDbResourcePool; _lastRequestTicks = DateTime.UtcNow.Ticks; options.BufferContent = true; diff --git a/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs b/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs index 0f0c31e6e9..bad7cf2ba9 100644 --- a/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs +++ b/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs @@ -27,7 +27,6 @@ namespace MediaBrowser.Providers.Music public static AudioDbArtistProvider Current; - public SemaphoreSlim AudioDbResourcePool = new SemaphoreSlim(2, 2); private const string ApiKey = "49jhsf8248yfahka89724011"; public const string BaseUrl = "http://www.theaudiodb.com/api/v1/json/" + ApiKey; @@ -151,7 +150,6 @@ namespace MediaBrowser.Providers.Music using (var response = await _httpClient.Get(new HttpRequestOptions { Url = url, - ResourcePool = AudioDbResourcePool, CancellationToken = cancellationToken, BufferContent = true diff --git a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs index 6fd0d82bdc..37e38e0482 100644 --- a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs +++ b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs @@ -27,7 +27,6 @@ namespace MediaBrowser.Providers.Music { public class FanartArtistProvider : IRemoteImageProvider, IHasOrder { - internal readonly SemaphoreSlim FanArtResourcePool = new SemaphoreSlim(3, 3); internal const string ApiKey = "5c6b04c68e904cfed1e6cbc9a9e683d4"; private const string FanArtBaseUrl = "https://webservice.fanart.tv/v3.1/music/{1}?api_key={0}"; @@ -255,7 +254,6 @@ namespace MediaBrowser.Providers.Music using (var response = await _httpClient.Get(new HttpRequestOptions { Url = url, - ResourcePool = FanArtResourcePool, CancellationToken = cancellationToken, BufferContent = true diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs index 4aefb62c8e..b77fcf1b28 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs @@ -548,11 +548,6 @@ namespace MediaBrowser.Providers.Music return null; } - /// - /// The _music brainz resource pool - /// - private readonly SemaphoreSlim _musicBrainzResourcePool = new SemaphoreSlim(1, 1); - private long _lastMbzUrlQueryTicks = 0; private List _mbzUrls = null; private MbzUrl _chosenUrl; @@ -656,7 +651,6 @@ namespace MediaBrowser.Providers.Music Url = url, CancellationToken = cancellationToken, UserAgent = _appHost.Name + "/" + _appHost.ApplicationVersion, - ResourcePool = _musicBrainzResourcePool, BufferContent = throttleMs > 0 }; diff --git a/MediaBrowser.Providers/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Omdb/OmdbProvider.cs index 2c368c97b2..474fdf14cd 100644 --- a/MediaBrowser.Providers/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Omdb/OmdbProvider.cs @@ -19,7 +19,6 @@ namespace MediaBrowser.Providers.Omdb { public class OmdbProvider { - internal static readonly SemaphoreSlim ResourcePool = new SemaphoreSlim(1, 1); private readonly IJsonSerializer _jsonSerializer; private readonly IFileSystem _fileSystem; private readonly IServerConfigurationManager _configurationManager; @@ -330,7 +329,6 @@ namespace MediaBrowser.Providers.Omdb return httpClient.Get(new HttpRequestOptions { Url = url, - ResourcePool = ResourcePool, CancellationToken = cancellationToken, BufferContent = true, EnableDefaultUserAgent = true diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs index cd741bed52..15f4f654f9 100644 --- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs +++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs @@ -256,12 +256,7 @@ namespace MediaBrowser.Providers.Subtitles _monitor.ReportFileSystemChangeComplete(path, false); } - return _libraryManager.GetItemById(itemId).RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)) - { - ImageRefreshMode = ImageRefreshMode.ValidationOnly, - MetadataRefreshMode = MetadataRefreshMode.ValidationOnly - - }, CancellationToken.None); + return _libraryManager.GetItemById(itemId).ChangedExternally(); } public Task GetRemoteSubtitles(string id, CancellationToken cancellationToken) diff --git a/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs b/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs index 8db3eaa79f..d50e12a279 100644 --- a/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs @@ -319,7 +319,6 @@ namespace MediaBrowser.Providers.TV using (var response = await _httpClient.Get(new HttpRequestOptions { Url = url, - ResourcePool = FanartArtistProvider.Current.FanArtResourcePool, CancellationToken = cancellationToken, BufferContent = true diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs index 38831feb6a..764b1e019d 100644 --- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs +++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs @@ -142,8 +142,7 @@ namespace MediaBrowser.Providers.TV return _httpClient.GetResponse(new HttpRequestOptions { CancellationToken = cancellationToken, - Url = url, - ResourcePool = MovieDbProvider.Current.MovieDbResourcePool + Url = url }); } diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs index 989748846c..030150e4d7 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs @@ -175,8 +175,7 @@ namespace MediaBrowser.Providers.TV return _httpClient.GetResponse(new HttpRequestOptions { CancellationToken = cancellationToken, - Url = url, - ResourcePool = TvdbSeriesProvider.Current.TvDbResourcePool + Url = url }); } } diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs index 4a52b972fc..3039968b9b 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs @@ -919,8 +919,7 @@ namespace MediaBrowser.Providers.TV return _httpClient.GetResponse(new HttpRequestOptions { CancellationToken = cancellationToken, - Url = url, - ResourcePool = TvdbSeriesProvider.Current.TvDbResourcePool + Url = url }); } diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs index 72bd62d9f3..e8ed05225e 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs @@ -143,7 +143,6 @@ namespace MediaBrowser.Providers.TV Url = ServerTimeUrl, CancellationToken = cancellationToken, EnableHttpCompression = true, - ResourcePool = TvdbSeriesProvider.Current.TvDbResourcePool, BufferContent = false }).ConfigureAwait(false)) @@ -240,7 +239,6 @@ namespace MediaBrowser.Providers.TV Url = string.Format(UpdatesUrl, lastUpdateTime), CancellationToken = cancellationToken, EnableHttpCompression = true, - ResourcePool = TvdbSeriesProvider.Current.TvDbResourcePool, BufferContent = false }).ConfigureAwait(false)) diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs index e68b7ad1d6..daa6e78f5a 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs @@ -358,8 +358,7 @@ namespace MediaBrowser.Providers.TV return _httpClient.GetResponse(new HttpRequestOptions { CancellationToken = cancellationToken, - Url = url, - ResourcePool = TvdbSeriesProvider.Current.TvDbResourcePool + Url = url }); } } diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs index cdb9ac51ed..50bc6bc74e 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs @@ -347,8 +347,7 @@ namespace MediaBrowser.Providers.TV return _httpClient.GetResponse(new HttpRequestOptions { CancellationToken = cancellationToken, - Url = url, - ResourcePool = TvdbSeriesProvider.Current.TvDbResourcePool + Url = url }); } } diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs index af37c7632e..4c5e57a949 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs @@ -27,7 +27,6 @@ namespace MediaBrowser.Providers.TV { public class TvdbSeriesProvider : IRemoteMetadataProvider, IHasOrder { - internal readonly SemaphoreSlim TvDbResourcePool = new SemaphoreSlim(2, 2); internal static TvdbSeriesProvider Current { get; private set; } private readonly IZipClient _zipClient; private readonly IHttpClient _httpClient; @@ -220,7 +219,6 @@ namespace MediaBrowser.Providers.TV using (var zipStream = await _httpClient.Get(new HttpRequestOptions { Url = url, - ResourcePool = TvDbResourcePool, CancellationToken = cancellationToken, BufferContent = false @@ -265,7 +263,6 @@ namespace MediaBrowser.Providers.TV using (var result = await _httpClient.Get(new HttpRequestOptions { Url = url, - ResourcePool = TvDbResourcePool, CancellationToken = cancellationToken, BufferContent = false @@ -520,7 +517,6 @@ namespace MediaBrowser.Providers.TV using (var stream = await _httpClient.Get(new HttpRequestOptions { Url = url, - ResourcePool = TvDbResourcePool, CancellationToken = cancellationToken, BufferContent = false @@ -1651,7 +1647,6 @@ namespace MediaBrowser.Providers.TV { CancellationToken = cancellationToken, Url = url, - ResourcePool = TvDbResourcePool, BufferContent = false }); } -- cgit v1.2.3 From 696a6b34eaaee1fc906d27a968d392b7b7193c41 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 4 May 2017 14:14:45 -0400 Subject: improve smb support --- BDInfo/BDROM.cs | 4 +- Emby.Common.Implementations/Devices/DeviceId.cs | 2 +- .../HttpClientManager/HttpClientManager.cs | 2 +- .../IO/ManagedFileSystem.cs | 56 ++++++++++++++-------- .../IO/SharpCifsFileSystem.cs | 28 +++++++++++ .../ScheduledTasks/ScheduledTaskWorker.cs | 4 +- Emby.Drawing.ImageMagick/ImageMagickEncoder.cs | 2 +- Emby.Drawing.ImageMagick/PlayedIndicatorDrawer.cs | 6 +-- Emby.Drawing.Net/GDIImageEncoder.cs | 4 +- Emby.Drawing/ImageProcessor.cs | 14 +++--- Emby.Server.Core/ApplicationHost.cs | 2 +- Emby.Server.Core/IO/LibraryMonitor.cs | 6 +-- .../Channels/ChannelManager.cs | 4 +- .../FileOrganization/EpisodeFileOrganizer.cs | 10 ++-- Emby.Server.Implementations/IO/FileRefresher.cs | 2 +- .../Images/BaseDynamicImageProvider.cs | 4 +- .../Library/CoreResolutionIgnoreRule.cs | 2 +- .../Library/LibraryManager.cs | 30 +++++++++++- .../Library/Resolvers/PhotoResolver.cs | 7 ++- Emby.Server.Implementations/Library/UserManager.cs | 4 +- .../LiveTv/EmbyTV/EmbyTV.cs | 8 ++-- .../LiveTv/EmbyTV/EncodedRecorder.cs | 4 +- .../LiveTv/EmbyTV/ItemDataProvider.cs | 2 +- .../LiveTv/Listings/XmlTvListingsProvider.cs | 2 +- .../Logging/UnhandledExceptionWriter.cs | 2 +- .../MediaEncoder/EncodingManager.cs | 2 +- .../ScheduledTasks/ChapterImagesTask.cs | 2 +- .../Security/MBLicenseFile.cs | 2 +- .../Updates/InstallationManager.cs | 4 +- MediaBrowser.Api/ApiEntryPoint.cs | 2 +- MediaBrowser.Api/EnvironmentService.cs | 2 +- MediaBrowser.Api/Images/ImageByNameService.cs | 2 +- MediaBrowser.Api/Images/RemoteImageService.cs | 4 +- MediaBrowser.Api/ItemLookupService.cs | 4 +- MediaBrowser.Api/Playback/BaseStreamingService.cs | 4 +- MediaBrowser.Api/Playback/Hls/BaseHlsService.cs | 2 +- MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs | 6 +-- MediaBrowser.Controller/Entities/BaseItem.cs | 6 +-- .../Entities/CollectionFolder.cs | 6 +-- MediaBrowser.Controller/Entities/Folder.cs | 27 ++++++++--- MediaBrowser.Controller/Entities/Game.cs | 2 +- MediaBrowser.Controller/Entities/LinkedChild.cs | 10 +++- MediaBrowser.Controller/Entities/TV/Season.cs | 2 +- MediaBrowser.Controller/Entities/Video.cs | 2 +- MediaBrowser.Controller/Library/ILibraryManager.cs | 2 + MediaBrowser.Controller/Library/ItemResolveArgs.cs | 6 +-- .../Providers/DirectoryService.cs | 6 +-- .../Images/EpisodeLocalImageProvider.cs | 2 +- .../Parsers/EpisodeXmlParser.cs | 2 +- .../Providers/EpisodeXmlProvider.cs | 2 +- .../Providers/GameXmlProvider.cs | 2 +- .../Providers/MovieXmlProvider.cs | 2 +- MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs | 2 +- MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 4 +- .../Encoder/EncodingUtils.cs | 5 ++ MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 6 +-- .../Subtitles/SubtitleEncoder.cs | 4 +- MediaBrowser.Model/IO/IFileSystem.cs | 2 + .../BoxSets/MovieDbBoxSetProvider.cs | 2 +- MediaBrowser.Providers/ImagesByName/ImageUtils.cs | 2 +- MediaBrowser.Providers/Manager/ImageSaver.cs | 10 ++-- .../MediaInfo/AudioImageProvider.cs | 2 +- .../MediaInfo/FFProbeAudioInfo.cs | 2 +- .../MediaInfo/FFProbeVideoInfo.cs | 2 +- .../Movies/FanartMovieImageProvider.cs | 2 +- .../Movies/GenericMovieDbInfo.cs | 2 +- MediaBrowser.Providers/Movies/MovieDbProvider.cs | 2 +- .../Music/AudioDbAlbumProvider.cs | 2 +- .../Music/AudioDbArtistProvider.cs | 2 +- .../Music/FanArtArtistProvider.cs | 2 +- MediaBrowser.Providers/Omdb/OmdbProvider.cs | 4 +- .../People/MovieDbPersonProvider.cs | 2 +- .../Subtitles/SubtitleManager.cs | 2 +- .../TV/FanArt/FanartSeriesProvider.cs | 2 +- .../TV/TheMovieDb/MovieDbProviderBase.cs | 2 +- .../TV/TheMovieDb/MovieDbSeasonProvider.cs | 2 +- .../TV/TheMovieDb/MovieDbSeriesProvider.cs | 4 +- .../TV/TheTVDB/TvdbEpisodeProvider.cs | 2 +- MediaBrowser.WebDashboard/Api/PackageCreator.cs | 4 +- MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs | 2 +- 80 files changed, 256 insertions(+), 151 deletions(-) (limited to 'Emby.Server.Implementations/Channels') diff --git a/BDInfo/BDROM.cs b/BDInfo/BDROM.cs index 123d1afe54..d86648364f 100644 --- a/BDInfo/BDROM.cs +++ b/BDInfo/BDROM.cs @@ -96,7 +96,7 @@ namespace BDInfo } DirectoryRoot = - _fileSystem.GetDirectoryInfo(Path.GetDirectoryName(DirectoryBDMV.FullName)); + _fileSystem.GetDirectoryInfo(_fileSystem.GetDirectoryName(DirectoryBDMV.FullName)); DirectoryBDJO = GetDirectory("BDJO", DirectoryBDMV, 0); DirectoryCLIPINF = @@ -349,7 +349,7 @@ namespace BDInfo { return dir; } - var parentFolder = Path.GetDirectoryName(dir.FullName); + var parentFolder = _fileSystem.GetDirectoryName(dir.FullName); if (string.IsNullOrEmpty(parentFolder)) { dir = null; diff --git a/Emby.Common.Implementations/Devices/DeviceId.cs b/Emby.Common.Implementations/Devices/DeviceId.cs index 3d23ab872b..1de76456cc 100644 --- a/Emby.Common.Implementations/Devices/DeviceId.cs +++ b/Emby.Common.Implementations/Devices/DeviceId.cs @@ -57,7 +57,7 @@ namespace Emby.Common.Implementations.Devices { var path = CachePath; - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); lock (_syncLock) { diff --git a/Emby.Common.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Common.Implementations/HttpClientManager/HttpClientManager.cs index 23f33f06cc..eb9bc1bd06 100644 --- a/Emby.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/Emby.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -418,7 +418,7 @@ namespace Emby.Common.Implementations.HttpClientManager private async Task CacheResponse(HttpResponseInfo response, string responseCachePath) { - _fileSystem.CreateDirectory(Path.GetDirectoryName(responseCachePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(responseCachePath)); using (var responseStream = response.Content) { diff --git a/Emby.Common.Implementations/IO/ManagedFileSystem.cs b/Emby.Common.Implementations/IO/ManagedFileSystem.cs index ba73c1ba27..3ed4f650f7 100644 --- a/Emby.Common.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Common.Implementations/IO/ManagedFileSystem.cs @@ -546,24 +546,6 @@ namespace Emby.Common.Implementations.IO return Path.DirectorySeparatorChar; } - public bool AreEqual(string path1, string path2) - { - if (path1 == null && path2 == null) - { - return true; - } - - if (path1 == null || path2 == null) - { - return false; - } - - path1 = path1.TrimEnd(GetDirectorySeparatorChar(path1)); - path2 = path2.TrimEnd(GetDirectorySeparatorChar(path2)); - - return string.Equals(path1, path2, StringComparison.OrdinalIgnoreCase); - } - public bool ContainsSubPath(string parentPath, string path) { if (string.IsNullOrEmpty(parentPath)) @@ -588,7 +570,7 @@ namespace Emby.Common.Implementations.IO throw new ArgumentNullException("path"); } - var parent = Path.GetDirectoryName(path); + var parent = GetDirectoryName(path); if (!string.IsNullOrEmpty(parent)) { @@ -598,6 +580,16 @@ namespace Emby.Common.Implementations.IO return true; } + public string GetDirectoryName(string path) + { + if (_sharpCifsFileSystem.IsEnabledForPath(path)) + { + return _sharpCifsFileSystem.GetDirectoryName(path); + } + + return Path.GetDirectoryName(path); + } + public string NormalizePath(string path) { if (string.IsNullOrEmpty(path)) @@ -605,6 +597,11 @@ namespace Emby.Common.Implementations.IO throw new ArgumentNullException("path"); } + if (_sharpCifsFileSystem.IsEnabledForPath(path)) + { + return _sharpCifsFileSystem.NormalizePath(path); + } + if (path.EndsWith(":\\", StringComparison.OrdinalIgnoreCase)) { return path; @@ -613,6 +610,21 @@ namespace Emby.Common.Implementations.IO return path.TrimEnd(GetDirectorySeparatorChar(path)); } + public bool AreEqual(string path1, string path2) + { + if (path1 == null && path2 == null) + { + return true; + } + + if (path1 == null || path2 == null) + { + return false; + } + + return string.Equals(NormalizePath(path1), NormalizePath(path2), StringComparison.OrdinalIgnoreCase); + } + public string GetFileNameWithoutExtension(FileSystemMetadata info) { if (info.IsDirectory) @@ -637,11 +649,17 @@ namespace Emby.Common.Implementations.IO // Cannot use Path.IsPathRooted because it returns false under mono when using windows-based paths, e.g. C:\\ + if (_sharpCifsFileSystem.IsEnabledForPath(path)) + { + return true; + } + if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) != -1 && !path.StartsWith("file://", StringComparison.OrdinalIgnoreCase)) { return false; } + return true; //return Path.IsPathRooted(path); diff --git a/Emby.Common.Implementations/IO/SharpCifsFileSystem.cs b/Emby.Common.Implementations/IO/SharpCifsFileSystem.cs index c1e429dc90..0a407d64f5 100644 --- a/Emby.Common.Implementations/IO/SharpCifsFileSystem.cs +++ b/Emby.Common.Implementations/IO/SharpCifsFileSystem.cs @@ -30,6 +30,34 @@ namespace Emby.Common.Implementations.IO return path.StartsWith("smb://", StringComparison.OrdinalIgnoreCase) || IsUncPath(path); } + public string NormalizePath(string path) + { + if (path.StartsWith("smb://", StringComparison.OrdinalIgnoreCase)) + { + return path; + } + + if (IsUncPath(path)) + { + return ConvertUncToSmb(path); + } + + return path; + } + + public string GetDirectoryName(string path) + { + var separator = GetDirectorySeparatorChar(path); + var result = Path.GetDirectoryName(path); + + if (separator == '/') + { + result = result.Replace('\\', '/'); + } + + return result; + } + public char GetDirectorySeparatorChar(string path) { if (path.IndexOf('/') != -1) diff --git a/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index f0518f69ed..ac1c55b6b3 100644 --- a/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -158,7 +158,7 @@ namespace Emby.Common.Implementations.ScheduledTasks _lastExecutionResult = value; var path = GetHistoryFilePath(); - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); lock (_lastExecutionResultSyncLock) { @@ -575,7 +575,7 @@ namespace Emby.Common.Implementations.ScheduledTasks { var path = GetConfigurationFilePath(); - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); JsonSerializer.SerializeToFile(triggers, path); } diff --git a/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs b/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs index 77482d56b9..500f57aade 100644 --- a/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs +++ b/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs @@ -91,7 +91,7 @@ namespace Emby.Drawing.ImageMagick try { var tmpPath = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + ".webp"); - _fileSystem.CreateDirectory(Path.GetDirectoryName(tmpPath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(tmpPath)); using (var wand = new MagickWand(1, 1, new PixelWand("none", 1))) { diff --git a/Emby.Drawing.ImageMagick/PlayedIndicatorDrawer.cs b/Emby.Drawing.ImageMagick/PlayedIndicatorDrawer.cs index 14fb0ddf15..58c6cfe82a 100644 --- a/Emby.Drawing.ImageMagick/PlayedIndicatorDrawer.cs +++ b/Emby.Drawing.ImageMagick/PlayedIndicatorDrawer.cs @@ -68,7 +68,7 @@ namespace Emby.Drawing.ImageMagick var namespacePath = typeof(PlayedIndicatorDrawer).Namespace + ".fonts." + name; var tempPath = Path.Combine(paths.TempDirectory, Guid.NewGuid().ToString("N") + ".ttf"); - fileSystem.CreateDirectory(Path.GetDirectoryName(tempPath)); + fileSystem.CreateDirectory(fileSystem.GetDirectoryName(tempPath)); using (var stream = typeof(PlayedIndicatorDrawer).Assembly.GetManifestResourceStream(namespacePath)) { @@ -78,7 +78,7 @@ namespace Emby.Drawing.ImageMagick } } - fileSystem.CreateDirectory(Path.GetDirectoryName(filePath)); + fileSystem.CreateDirectory(fileSystem.GetDirectoryName(filePath)); try { @@ -108,7 +108,7 @@ namespace Emby.Drawing.ImageMagick }).ConfigureAwait(false); - fileSystem.CreateDirectory(Path.GetDirectoryName(filePath)); + fileSystem.CreateDirectory(fileSystem.GetDirectoryName(filePath)); try { diff --git a/Emby.Drawing.Net/GDIImageEncoder.cs b/Emby.Drawing.Net/GDIImageEncoder.cs index 831a579792..638415afdc 100644 --- a/Emby.Drawing.Net/GDIImageEncoder.cs +++ b/Emby.Drawing.Net/GDIImageEncoder.cs @@ -81,7 +81,7 @@ namespace Emby.Drawing.Net { using (var croppedImage = image.CropWhitespace()) { - _fileSystem.CreateDirectory(Path.GetDirectoryName(outputPath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath)); using (var outputStream = _fileSystem.GetFileStream(outputPath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, false)) { @@ -135,7 +135,7 @@ namespace Emby.Drawing.Net var outputFormat = GetOutputFormat(originalImage, selectedOutputFormat); - _fileSystem.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(cacheFilePath)); // Save to the cache location using (var cacheFileStream = _fileSystem.GetFileStream(cacheFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, false)) diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index f19e3e037f..bee0e9b69b 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -244,9 +244,9 @@ namespace Emby.Drawing var newWidth = Convert.ToInt32(newSize.Width); var newHeight = Convert.ToInt32(newSize.Height); - _fileSystem.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(cacheFilePath)); var tmpPath = Path.ChangeExtension(Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")), Path.GetExtension(cacheFilePath)); - _fileSystem.CreateDirectory(Path.GetDirectoryName(tmpPath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(tmpPath)); _imageEncoder.EncodeImage(originalImagePath, tmpPath, AutoOrient(options.Item), newWidth, newHeight, quality, options, outputFormat); CopyFile(tmpPath, cacheFilePath); @@ -418,9 +418,9 @@ namespace Emby.Drawing try { - _fileSystem.CreateDirectory(Path.GetDirectoryName(croppedImagePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(croppedImagePath)); var tmpPath = Path.ChangeExtension(Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")), Path.GetExtension(croppedImagePath)); - _fileSystem.CreateDirectory(Path.GetDirectoryName(tmpPath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(tmpPath)); _imageEncoder.CropWhiteSpace(originalImagePath, tmpPath); CopyFile(tmpPath, croppedImagePath); @@ -592,7 +592,7 @@ namespace Emby.Drawing try { var path = ImageSizeFile; - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); _jsonSerializer.SerializeToFile(_cachedImagedSizes, path); } catch (Exception ex) @@ -765,10 +765,10 @@ namespace Emby.Drawing return enhancedImagePath; } - _fileSystem.CreateDirectory(Path.GetDirectoryName(enhancedImagePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(enhancedImagePath)); var tmpPath = Path.Combine(_appPaths.TempDirectory, Path.ChangeExtension(Guid.NewGuid().ToString(), Path.GetExtension(enhancedImagePath))); - _fileSystem.CreateDirectory(Path.GetDirectoryName(tmpPath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(tmpPath)); await ExecuteImageEnhancers(supportedEnhancers, originalImagePath, tmpPath, item, imageType, imageIndex).ConfigureAwait(false); diff --git a/Emby.Server.Core/ApplicationHost.cs b/Emby.Server.Core/ApplicationHost.cs index 994b942e92..78bdc11898 100644 --- a/Emby.Server.Core/ApplicationHost.cs +++ b/Emby.Server.Core/ApplicationHost.cs @@ -1145,7 +1145,7 @@ namespace Emby.Server.Core { if (!FileSystemManager.FileExists(certPath)) { - FileSystemManager.CreateDirectory(Path.GetDirectoryName(certPath)); + FileSystemManager.CreateDirectory(FileSystemManager.GetDirectoryName(certPath)); try { diff --git a/Emby.Server.Core/IO/LibraryMonitor.cs b/Emby.Server.Core/IO/LibraryMonitor.cs index a5b2e25558..0f6a2e9a2c 100644 --- a/Emby.Server.Core/IO/LibraryMonitor.cs +++ b/Emby.Server.Core/IO/LibraryMonitor.cs @@ -466,7 +466,7 @@ namespace Emby.Server.Core.IO } // Go up a level - var parent = Path.GetDirectoryName(i); + var parent = _fileSystem.GetDirectoryName(i); if (!string.IsNullOrEmpty(parent)) { if (_fileSystem.AreEqual(parent, path)) @@ -492,7 +492,7 @@ namespace Emby.Server.Core.IO private void CreateRefresher(string path) { - var parentPath = Path.GetDirectoryName(path); + var parentPath = _fileSystem.GetDirectoryName(path); lock (_activeRefreshers) { @@ -521,7 +521,7 @@ namespace Emby.Server.Core.IO } // They are siblings. Rebase the refresher to the parent folder. - if (string.Equals(parentPath, Path.GetDirectoryName(refresher.Path), StringComparison.Ordinal)) + if (string.Equals(parentPath, _fileSystem.GetDirectoryName(refresher.Path), StringComparison.Ordinal)) { refresher.ResetPath(parentPath, path); return; diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index de76157ba7..0cdd934b7a 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -268,7 +268,7 @@ namespace Emby.Server.Implementations.Channels return; } - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); _jsonSerializer.SerializeToFile(mediaSources, path); } @@ -1105,7 +1105,7 @@ namespace Emby.Server.Implementations.Channels { try { - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); _jsonSerializer.SerializeToFile(result, path); } diff --git a/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index 7b64c582a7..86c8c5f68e 100644 --- a/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -352,7 +352,7 @@ namespace Emby.Server.Implementations.FileOrganization _libraryMonitor.ReportFileSystemChangeBeginning(path); var renameRelatedFiles = !hasRenamedFiles && - string.Equals(Path.GetDirectoryName(path), Path.GetDirectoryName(result.TargetPath), StringComparison.OrdinalIgnoreCase); + string.Equals(_fileSystem.GetDirectoryName(path), _fileSystem.GetDirectoryName(result.TargetPath), StringComparison.OrdinalIgnoreCase); if (renameRelatedFiles) { @@ -432,7 +432,7 @@ namespace Emby.Server.Implementations.FileOrganization // Now find other files var originalFilenameWithoutExtension = Path.GetFileNameWithoutExtension(path); - var directory = Path.GetDirectoryName(path); + var directory = _fileSystem.GetDirectoryName(path); if (!string.IsNullOrWhiteSpace(originalFilenameWithoutExtension) && !string.IsNullOrWhiteSpace(directory)) { @@ -445,7 +445,7 @@ namespace Emby.Server.Implementations.FileOrganization foreach (var file in files) { - directory = Path.GetDirectoryName(file); + directory = _fileSystem.GetDirectoryName(file); var filename = Path.GetFileName(file); filename = filename.Replace(originalFilenameWithoutExtension, targetFilenameWithoutExtension, @@ -499,7 +499,7 @@ namespace Emby.Server.Implementations.FileOrganization .Select(i => i.Path) .ToList(); - var folder = Path.GetDirectoryName(targetPath); + var folder = _fileSystem.GetDirectoryName(targetPath); var targetFileNameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(targetPath); try @@ -529,7 +529,7 @@ namespace Emby.Server.Implementations.FileOrganization _libraryMonitor.ReportFileSystemChangeBeginning(result.TargetPath); - _fileSystem.CreateDirectory(Path.GetDirectoryName(result.TargetPath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(result.TargetPath)); var targetAlreadyExists = _fileSystem.FileExists(result.TargetPath); diff --git a/Emby.Server.Implementations/IO/FileRefresher.cs b/Emby.Server.Implementations/IO/FileRefresher.cs index c646726850..033cbd8b01 100644 --- a/Emby.Server.Implementations/IO/FileRefresher.cs +++ b/Emby.Server.Implementations/IO/FileRefresher.cs @@ -207,7 +207,7 @@ namespace Emby.Server.Implementations.IO { item = LibraryManager.FindByPath(path, null); - path = System.IO.Path.GetDirectoryName(path); + path = _fileSystem.GetDirectoryName(path); } if (item != null) diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs index 38908c2bd5..2677f7b2ad 100644 --- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs +++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs @@ -139,7 +139,7 @@ namespace Emby.Server.Implementations.Images CancellationToken cancellationToken) { var outputPathWithoutExtension = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid().ToString("N")); - FileSystem.CreateDirectory(Path.GetDirectoryName(outputPathWithoutExtension)); + FileSystem.CreateDirectory(FileSystem.GetDirectoryName(outputPathWithoutExtension)); string outputPath = await CreateImage(item, itemsWithImages, outputPathWithoutExtension, imageType, 0).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(outputPath)) @@ -205,7 +205,7 @@ namespace Emby.Server.Implementations.Images private async Task CreateCollage(IHasImages primaryItem, List items, string outputPath, int width, int height) { - FileSystem.CreateDirectory(Path.GetDirectoryName(outputPath)); + FileSystem.CreateDirectory(FileSystem.GetDirectoryName(outputPath)); var options = new ImageCollageOptions { diff --git a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs index d782f5b888..64f025d93f 100644 --- a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs +++ b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs @@ -79,7 +79,7 @@ namespace Emby.Server.Implementations.Library { if (parent == null) { - var parentFolderName = Path.GetFileName(Path.GetDirectoryName(path)); + var parentFolderName = Path.GetFileName(_fileSystem.GetDirectoryName(path)); if (string.Equals(parentFolderName, BaseItem.ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase)) { diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 684ad6284a..685c794b76 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1962,8 +1962,34 @@ namespace Emby.Server.Implementations.Library return new List(); } - return GetUserRootFolder().Children - .OfType() + return GetCollectionFoldersInternal(item, GetUserRootFolder().Children.OfType().ToList()); + } + + public List GetCollectionFolders(BaseItem item, List allUserRootChildren) + { + while (item != null) + { + var parent = item.GetParent(); + + if (parent == null || parent is AggregateFolder) + { + break; + } + + item = parent; + } + + if (item == null) + { + return new List(); + } + + return GetCollectionFoldersInternal(item, allUserRootChildren); + } + + private List GetCollectionFoldersInternal(BaseItem item, List allUserRootChildren) + { + return allUserRootChildren .Where(i => string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(item.Path, StringComparer.OrdinalIgnoreCase)) .ToList(); } diff --git a/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs index 0968e8ea26..8bbda3b628 100644 --- a/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs @@ -6,6 +6,7 @@ using System; using System.IO; using System.Linq; using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.IO; namespace Emby.Server.Implementations.Library.Resolvers { @@ -13,11 +14,13 @@ namespace Emby.Server.Implementations.Library.Resolvers { private readonly IImageProcessor _imageProcessor; private readonly ILibraryManager _libraryManager; + private readonly IFileSystem _fileSystem; - public PhotoResolver(IImageProcessor imageProcessor, ILibraryManager libraryManager) + public PhotoResolver(IImageProcessor imageProcessor, ILibraryManager libraryManager, IFileSystem fileSystem) { _imageProcessor = imageProcessor; _libraryManager = libraryManager; + _fileSystem = fileSystem; } /// @@ -41,7 +44,7 @@ namespace Emby.Server.Implementations.Library.Resolvers var filename = Path.GetFileNameWithoutExtension(args.Path); // Make sure the image doesn't belong to a video file - if (args.DirectoryService.GetFilePaths(Path.GetDirectoryName(args.Path)).Any(i => IsOwnedByMedia(args.GetLibraryOptions(), i, filename))) + if (args.DirectoryService.GetFilePaths(_fileSystem.GetDirectoryName(args.Path)).Any(i => IsOwnedByMedia(args.GetLibraryOptions(), i, filename))) { return null; } diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs index c2ab0427d3..0b90272915 100644 --- a/Emby.Server.Implementations/Library/UserManager.cs +++ b/Emby.Server.Implementations/Library/UserManager.cs @@ -965,7 +965,7 @@ namespace Emby.Server.Implementations.Library var path = GetPolifyFilePath(user); - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); lock (_policySyncLock) { @@ -1052,7 +1052,7 @@ namespace Emby.Server.Implementations.Library config = _jsonSerializer.DeserializeFromString(json); } - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); lock (_configSyncLock) { diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index f6bd21165f..9ce4822730 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1497,7 +1497,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _libraryManager.RegisterIgnoredPath(recordPath); _libraryMonitor.ReportFileSystemChangeBeginning(recordPath); - _fileSystem.CreateDirectory(Path.GetDirectoryName(recordPath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(recordPath)); activeRecordingInfo.Path = recordPath; var duration = recordingEndDate - DateTime.UtcNow; @@ -1725,7 +1725,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV while (FileExists(path, timerId)) { - var parent = Path.GetDirectoryName(originalPath); + var parent = _fileSystem.GetDirectoryName(originalPath); var name = Path.GetFileNameWithoutExtension(originalPath); name += "-" + index.ToString(CultureInfo.InvariantCulture); @@ -1892,7 +1892,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return; } - var imageSavePath = Path.Combine(Path.GetDirectoryName(recordingPath), imageSaveFilenameWithoutExtension); + var imageSavePath = Path.Combine(_fileSystem.GetDirectoryName(recordingPath), imageSaveFilenameWithoutExtension); // preserve original image extension imageSavePath = Path.ChangeExtension(imageSavePath, Path.GetExtension(image.Path)); @@ -2545,7 +2545,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private void SaveEpgDataForChannel(string channelId, List epgData) { var path = GetChannelEpgCachePath(channelId); - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); lock (_epgLock) { _jsonSerializer.SerializeToFile(epgData, path); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index 1673c9150d..790e6c27d1 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -108,7 +108,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private Task RecordFromFile(MediaSourceInfo mediaSource, string inputFile, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken) { _targetPath = targetFile; - _fileSystem.CreateDirectory(Path.GetDirectoryName(targetFile)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(targetFile)); var process = _processFactory.Create(new ProcessOptions { @@ -134,7 +134,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _logger.Info(commandLineLogMessage); var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "record-transcode-" + Guid.NewGuid() + ".txt"); - _fileSystem.CreateDirectory(Path.GetDirectoryName(logFilePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(logFilePath)); // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. _logFileStream = _fileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs index 16ae26d45d..953cb8e415 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs @@ -72,7 +72,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV } var file = _dataPath + ".json"; - _fileSystem.CreateDirectory(Path.GetDirectoryName(file)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(file)); lock (_fileDataLock) { diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index fc0a826b4f..b50f5ac926 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -86,7 +86,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings }).ConfigureAwait(false); - _fileSystem.CreateDirectory(Path.GetDirectoryName(cacheFile)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(cacheFile)); using (var stream = _fileSystem.OpenRead(tempFile)) { diff --git a/Emby.Server.Implementations/Logging/UnhandledExceptionWriter.cs b/Emby.Server.Implementations/Logging/UnhandledExceptionWriter.cs index 6e96d83fd3..7104935e15 100644 --- a/Emby.Server.Implementations/Logging/UnhandledExceptionWriter.cs +++ b/Emby.Server.Implementations/Logging/UnhandledExceptionWriter.cs @@ -29,7 +29,7 @@ namespace Emby.Server.Implementations.Logging _logManager.Flush(); var path = Path.Combine(_appPaths.LogDirectoryPath, "unhandled_" + Guid.NewGuid() + ".txt"); - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); var builder = LogHelper.GetLogMessage(ex); diff --git a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs index 204e04061d..884a001f0e 100644 --- a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs +++ b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs @@ -138,7 +138,7 @@ namespace Emby.Server.Implementations.MediaEncoder var inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, video.Path, protocol, null, video.PlayableStreamFileNames); - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); var container = video.Container; diff --git a/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs index 5f37025e2a..d1c70ba1dd 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs @@ -136,7 +136,7 @@ namespace Emby.Server.Implementations.ScheduledTasks { previouslyFailedImages.Add(key); - var parentPath = Path.GetDirectoryName(failHistoryPath); + var parentPath = _fileSystem.GetDirectoryName(failHistoryPath); _fileSystem.CreateDirectory(parentPath); diff --git a/Emby.Server.Implementations/Security/MBLicenseFile.cs b/Emby.Server.Implementations/Security/MBLicenseFile.cs index c791d6a52e..dc0e8b1613 100644 --- a/Emby.Server.Implementations/Security/MBLicenseFile.cs +++ b/Emby.Server.Implementations/Security/MBLicenseFile.cs @@ -193,7 +193,7 @@ namespace Emby.Server.Implementations.Security } var licenseFile = Filename; - _fileSystem.CreateDirectory(Path.GetDirectoryName(licenseFile)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(licenseFile)); lock (_fileLock) { _fileSystem.WriteAllLines(licenseFile, lines); diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index 840c7ce0d3..57019cc4e2 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -250,7 +250,7 @@ namespace Emby.Server.Implementations.Updates }).ConfigureAwait(false); - _fileSystem.CreateDirectory(Path.GetDirectoryName(PackageCachePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(PackageCachePath)); _fileSystem.CopyFile(tempFile, PackageCachePath, true); _lastPackageUpdateTime = DateTime.UtcNow; @@ -627,7 +627,7 @@ namespace Emby.Server.Implementations.Updates // Success - move it to the real target try { - _fileSystem.CreateDirectory(Path.GetDirectoryName(target)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(target)); _fileSystem.CopyFile(tempFile, target, true); //If it is an archive - write out a version file so we know what it is if (isArchive) diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index a59ab33a97..53e4749820 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -633,7 +633,7 @@ namespace MediaBrowser.Api /// The output file path. private void DeleteHlsPartialStreamFiles(string outputFilePath) { - var directory = Path.GetDirectoryName(outputFilePath); + var directory = _fileSystem.GetDirectoryName(outputFilePath); var name = Path.GetFileNameWithoutExtension(outputFilePath); var filesToDelete = _fileSystem.GetFilePaths(directory) diff --git a/MediaBrowser.Api/EnvironmentService.cs b/MediaBrowser.Api/EnvironmentService.cs index bab538c91f..c4cb0cb1d6 100644 --- a/MediaBrowser.Api/EnvironmentService.cs +++ b/MediaBrowser.Api/EnvironmentService.cs @@ -278,7 +278,7 @@ namespace MediaBrowser.Api public object Get(GetParentPath request) { - var parent = Path.GetDirectoryName(request.Path); + var parent = _fileSystem.GetDirectoryName(request.Path); if (string.IsNullOrEmpty(parent)) { diff --git a/MediaBrowser.Api/Images/ImageByNameService.cs b/MediaBrowser.Api/Images/ImageByNameService.cs index c4cfd7307a..2c8fc2d614 100644 --- a/MediaBrowser.Api/Images/ImageByNameService.cs +++ b/MediaBrowser.Api/Images/ImageByNameService.cs @@ -160,7 +160,7 @@ namespace MediaBrowser.Api.Images private string GetThemeName(string path, string rootImagePath) { - var parentName = Path.GetDirectoryName(path); + var parentName = _fileSystem.GetDirectoryName(path); if (string.Equals(parentName, rootImagePath, StringComparison.OrdinalIgnoreCase)) { diff --git a/MediaBrowser.Api/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs index d7ccf8f6d0..ebd8b89517 100644 --- a/MediaBrowser.Api/Images/RemoteImageService.cs +++ b/MediaBrowser.Api/Images/RemoteImageService.cs @@ -278,7 +278,7 @@ namespace MediaBrowser.Api.Images var fullCachePath = GetFullCachePath(urlHash + "." + ext); - _fileSystem.CreateDirectory(Path.GetDirectoryName(fullCachePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(fullCachePath)); using (var stream = result.Content) { using (var filestream = _fileSystem.GetFileStream(fullCachePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true)) @@ -287,7 +287,7 @@ namespace MediaBrowser.Api.Images } } - _fileSystem.CreateDirectory(Path.GetDirectoryName(pointerCachePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(pointerCachePath)); _fileSystem.WriteAllText(pointerCachePath, fullCachePath); } diff --git a/MediaBrowser.Api/ItemLookupService.cs b/MediaBrowser.Api/ItemLookupService.cs index b5c51bfef0..a454642a42 100644 --- a/MediaBrowser.Api/ItemLookupService.cs +++ b/MediaBrowser.Api/ItemLookupService.cs @@ -299,7 +299,7 @@ namespace MediaBrowser.Api var fullCachePath = GetFullCachePath(urlHash + "." + ext); - _fileSystem.CreateDirectory(Path.GetDirectoryName(fullCachePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(fullCachePath)); using (var stream = result.Content) { using (var filestream = _fileSystem.GetFileStream(fullCachePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true)) @@ -308,7 +308,7 @@ namespace MediaBrowser.Api } } - _fileSystem.CreateDirectory(Path.GetDirectoryName(pointerCachePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(pointerCachePath)); _fileSystem.WriteAllText(pointerCachePath, fullCachePath); } diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index f54b3bf6c1..a92cf164ac 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -198,7 +198,7 @@ namespace MediaBrowser.Api.Playback CancellationTokenSource cancellationTokenSource, string workingDirectory = null) { - FileSystem.CreateDirectory(Path.GetDirectoryName(outputPath)); + FileSystem.CreateDirectory(FileSystem.GetDirectoryName(outputPath)); await AcquireResources(state, cancellationTokenSource).ConfigureAwait(false); @@ -263,7 +263,7 @@ namespace MediaBrowser.Api.Playback } var logFilePath = Path.Combine(ServerConfigurationManager.ApplicationPaths.LogDirectoryPath, logFilePrefix + "-" + Guid.NewGuid() + ".txt"); - FileSystem.CreateDirectory(Path.GetDirectoryName(logFilePath)); + FileSystem.CreateDirectory(FileSystem.GetDirectoryName(logFilePath)); // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. state.LogFileStream = FileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true); diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index 8559bae89d..fcf57cebe2 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -268,7 +268,7 @@ namespace MediaBrowser.Api.Playback.Hls var useGenericSegmenter = true; if (useGenericSegmenter) { - var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request); + var outputTsArg = Path.Combine(FileSystem.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request); var timeDeltaParam = String.Empty; diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index b4618fb87d..0fe1e533d4 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -379,7 +379,7 @@ namespace MediaBrowser.Api.Playback.Hls private static FileSystemMetadata GetLastTranscodingFile(string playlist, string segmentExtension, IFileSystem fileSystem) { - var folder = Path.GetDirectoryName(playlist); + var folder = fileSystem.GetDirectoryName(playlist); var filePrefix = Path.GetFileNameWithoutExtension(playlist) ?? string.Empty; @@ -416,7 +416,7 @@ namespace MediaBrowser.Api.Playback.Hls private string GetSegmentPath(StreamState state, string playlist, int index) { - var folder = Path.GetDirectoryName(playlist); + var folder = FileSystem.GetDirectoryName(playlist); var filename = Path.GetFileNameWithoutExtension(playlist); @@ -926,7 +926,7 @@ namespace MediaBrowser.Api.Playback.Hls if (useGenericSegmenter) { - var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request); + var outputTsArg = Path.Combine(FileSystem.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request); var timeDeltaParam = String.Empty; diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 04ddb2729c..70512ef650 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -288,7 +288,7 @@ namespace MediaBrowser.Controller.Entities return Path; } - return System.IO.Path.GetDirectoryName(Path); + return FileSystem.GetDirectoryName(Path); } } @@ -1917,7 +1917,7 @@ namespace MediaBrowser.Controller.Entities { var allFiles = ImageInfos .Where(i => i.IsLocalFile) - .Select(i => System.IO.Path.GetDirectoryName(i.Path)) + .Select(i => FileSystem.GetDirectoryName(i.Path)) .Distinct(StringComparer.OrdinalIgnoreCase) .SelectMany(directoryService.GetFilePaths) .ToList(); @@ -2092,7 +2092,7 @@ namespace MediaBrowser.Controller.Entities var extensions = new[] { ".nfo", ".xml", ".srt" }.ToList(); extensions.AddRange(SupportedImageExtensionsList); - return FileSystem.GetFiles(System.IO.Path.GetDirectoryName(Path), extensions.ToArray(), false, false) + return FileSystem.GetFiles(FileSystem.GetDirectoryName(Path), extensions.ToArray(), false, false) .Where(i => System.IO.Path.GetFileNameWithoutExtension(i.FullName).StartsWith(filename, StringComparison.OrdinalIgnoreCase)) .ToList(); } diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index 62ea21a798..24474ba559 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -213,7 +213,7 @@ namespace MediaBrowser.Controller.Entities .SelectMany(c => c.LinkedChildren) .ToList(); - var changed = !linkedChildren.SequenceEqual(LinkedChildren, new LinkedChildComparer()); + var changed = !linkedChildren.SequenceEqual(LinkedChildren, new LinkedChildComparer(FileSystem)); LinkedChildren = linkedChildren; @@ -332,13 +332,13 @@ namespace MediaBrowser.Controller.Entities .OfType() .ToList(); - return PhysicalLocations.Where(i => !string.Equals(i, Path, StringComparison.OrdinalIgnoreCase)).SelectMany(i => GetPhysicalParents(i, rootChildren)).DistinctBy(i => i.Id); + return PhysicalLocations.Where(i => !FileSystem.AreEqual(i, Path)).SelectMany(i => GetPhysicalParents(i, rootChildren)).DistinctBy(i => i.Id); } private IEnumerable GetPhysicalParents(string path, List rootChildren) { var result = rootChildren - .Where(i => string.Equals(i.Path, path, StringComparison.OrdinalIgnoreCase)) + .Where(i => FileSystem.AreEqual(i.Path, path)) .ToList(); if (result.Count == 0) diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 268fefbd3e..edac27f99b 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -640,7 +640,7 @@ namespace MediaBrowser.Controller.Entities return true; } - path = System.IO.Path.GetDirectoryName(path); + path = FileSystem.GetDirectoryName(path); } return allLibraryPaths.Any(i => ContainsPath(i, originalPath)); @@ -1206,11 +1206,17 @@ namespace MediaBrowser.Controller.Entities return GetLinkedChildren(); } - var locations = user.RootFolder - .Children + if (LinkedChildren.Count == 0) + { + return new List(); + } + + var allUserRootChildren = user.RootFolder.Children.OfType().ToList(); + + var collectionFolderIds = allUserRootChildren .OfType() .Where(i => i.IsVisible(user)) - .SelectMany(i => i.PhysicalLocations) + .Select(i => i.Id) .ToList(); return LinkedChildren @@ -1228,9 +1234,16 @@ namespace MediaBrowser.Controller.Entities return null; } } - else if (childLocationType == LocationType.FileSystem && !locations.Any(l => FileSystem.ContainsSubPath(l, child.Path))) + else if (childLocationType == LocationType.FileSystem) { - return null; + var itemCollectionFolderIds = + LibraryManager.GetCollectionFolders(child, allUserRootChildren) + .Select(f => f.Id).ToList(); + + if (!itemCollectionFolderIds.Any(collectionFolderIds.Contains)) + { + return null; + } } } @@ -1323,7 +1336,7 @@ namespace MediaBrowser.Controller.Entities } else { newShortcutLinks = new List(); } - if (!newShortcutLinks.SequenceEqual(currentShortcutLinks, new LinkedChildComparer())) + if (!newShortcutLinks.SequenceEqual(currentShortcutLinks, new LinkedChildComparer(FileSystem))) { Logger.Info("Shortcut links have changed for {0}", Path); diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs index d19552c07f..baefc9dfa8 100644 --- a/MediaBrowser.Controller/Entities/Game.cs +++ b/MediaBrowser.Controller/Entities/Game.cs @@ -105,7 +105,7 @@ namespace MediaBrowser.Controller.Entities return new[] { new FileSystemMetadata { - FullName = System.IO.Path.GetDirectoryName(Path), + FullName = FileSystem.GetDirectoryName(Path), IsDirectory = true } }; diff --git a/MediaBrowser.Controller/Entities/LinkedChild.cs b/MediaBrowser.Controller/Entities/LinkedChild.cs index 4d3c13c6e3..6031a2448a 100644 --- a/MediaBrowser.Controller/Entities/LinkedChild.cs +++ b/MediaBrowser.Controller/Entities/LinkedChild.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; namespace MediaBrowser.Controller.Entities @@ -40,11 +41,18 @@ namespace MediaBrowser.Controller.Entities public class LinkedChildComparer : IEqualityComparer { + private readonly IFileSystem _fileSystem; + + public LinkedChildComparer(IFileSystem fileSystem) + { + _fileSystem = fileSystem; + } + public bool Equals(LinkedChild x, LinkedChild y) { if (x.Type == y.Type) { - return string.Equals(x.Path, y.Path, StringComparison.OrdinalIgnoreCase); + return _fileSystem.AreEqual(x.Path, y.Path); } return false; } diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index be268782d5..6c97a32a0e 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -125,7 +125,7 @@ namespace MediaBrowser.Controller.Entities.TV return series.Path; } - return System.IO.Path.GetDirectoryName(Path); + return FileSystem.GetDirectoryName(Path); } } diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 98f325bdc7..90aa3690a9 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -311,7 +311,7 @@ namespace MediaBrowser.Controller.Entities { if (IsStacked) { - return System.IO.Path.GetDirectoryName(Path); + return FileSystem.GetDirectoryName(Path); } if (!IsPlaceHolder) diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index ebebe71a32..dd23799407 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -456,6 +456,8 @@ namespace MediaBrowser.Controller.Library /// IEnumerable<Folder>. List GetCollectionFolders(BaseItem item); + List GetCollectionFolders(BaseItem item, List allUserRootChildren); + LibraryOptions GetLibraryOptions(BaseItem item); /// diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs index 763d27ebaf..3aa4d4ee2c 100644 --- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs +++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs @@ -114,7 +114,7 @@ namespace MediaBrowser.Controller.Library return false; } - var parentDir = System.IO.Path.GetDirectoryName(Path) ?? string.Empty; + var parentDir = BaseItem.FileSystem.GetDirectoryName(Path) ?? string.Empty; return parentDir.Length > _appPaths.RootFolderPath.Length && parentDir.StartsWith(_appPaths.RootFolderPath, StringComparison.OrdinalIgnoreCase); @@ -130,7 +130,7 @@ namespace MediaBrowser.Controller.Library { get { - return IsDirectory && string.Equals(Path, _appPaths.RootFolderPath, StringComparison.OrdinalIgnoreCase); + return IsDirectory && BaseItem.FileSystem.AreEqual(Path, _appPaths.RootFolderPath); } } @@ -300,7 +300,7 @@ namespace MediaBrowser.Controller.Library if (args != null) { if (args.Path == null && Path == null) return true; - return args.Path != null && args.Path.Equals(Path, StringComparison.OrdinalIgnoreCase); + return args.Path != null && BaseItem.FileSystem.AreEqual(args.Path, Path); } return false; } diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs index 40093df3af..62db007b90 100644 --- a/MediaBrowser.Controller/Providers/DirectoryService.cs +++ b/MediaBrowser.Controller/Providers/DirectoryService.cs @@ -63,11 +63,11 @@ namespace MediaBrowser.Controller.Providers //_logger.Debug("Getting files for " + path); entries = new Dictionary(StringComparer.OrdinalIgnoreCase); - + try { // using EnumerateFileSystemInfos doesn't handle reparse points (symlinks) - var list = _fileSystem.GetFileSystemEntries(path) + var list = _fileSystem.GetFileSystemEntries(path) .ToList(); // Seeing dupes on some users file system for some reason @@ -80,7 +80,7 @@ namespace MediaBrowser.Controller.Providers { } - //var group = entries.ToLookup(i => Path.GetDirectoryName(i.FullName)).ToList(); + //var group = entries.ToLookup(i => _fileSystem.GetDirectoryName(i.FullName)).ToList(); _cache.TryAdd(path, entries); } diff --git a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs index e005ad2247..bd33dece80 100644 --- a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs @@ -38,7 +38,7 @@ namespace MediaBrowser.LocalMetadata.Images public List GetImages(IHasImages item, IDirectoryService directoryService) { - var parentPath = Path.GetDirectoryName(item.Path); + var parentPath = _fileSystem.GetDirectoryName(item.Path); var parentPathFiles = directoryService.GetFileSystemEntries(parentPath) .ToList(); diff --git a/MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs index 9adc4e5a9e..69d799b187 100644 --- a/MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs @@ -84,7 +84,7 @@ namespace MediaBrowser.LocalMetadata.Parsers // even though it's actually using the metadata folder. filename = Path.GetFileName(filename); - var parentFolder = Path.GetDirectoryName(_xmlPath); + var parentFolder = _fileSystem.GetDirectoryName(_xmlPath); filename = Path.Combine(parentFolder, filename); var file = _fileSystem.GetFileInfo(filename); diff --git a/MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs index 7e0f1707f9..fda8ea6d0c 100644 --- a/MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs @@ -39,7 +39,7 @@ namespace MediaBrowser.LocalMetadata.Providers protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) { - var metadataPath = Path.GetDirectoryName(info.Path); + var metadataPath = FileSystem.GetDirectoryName(info.Path); metadataPath = Path.Combine(metadataPath, "metadata"); var metadataFile = Path.Combine(metadataPath, Path.ChangeExtension(Path.GetFileName(info.Path), ".xml")); diff --git a/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs index 888eff4164..8ed18df643 100644 --- a/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.LocalMetadata.Providers var specificFile = Path.ChangeExtension(info.Path, ".xml"); var file = FileSystem.GetFileInfo(specificFile); - return info.IsInMixedFolder || file.Exists ? file : FileSystem.GetFileInfo(Path.Combine(Path.GetDirectoryName(info.Path), "game.xml")); + return info.IsInMixedFolder || file.Exists ? file : FileSystem.GetFileInfo(Path.Combine(FileSystem.GetDirectoryName(info.Path), "game.xml")); } } } diff --git a/MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs index 0e59db75f6..2d4059a1a8 100644 --- a/MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs @@ -39,7 +39,7 @@ namespace MediaBrowser.LocalMetadata.Providers { var fileInfo = fileSystem.GetFileSystemInfo(info.Path); - var directoryInfo = fileInfo.IsDirectory ? fileInfo : fileSystem.GetDirectoryInfo(Path.GetDirectoryName(info.Path)); + var directoryInfo = fileInfo.IsDirectory ? fileInfo : fileSystem.GetDirectoryInfo(fileSystem.GetDirectoryName(info.Path)); var directoryPath = directoryInfo.FullName; diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs index 78e79e54a5..01918a80cc 100644 --- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs @@ -209,7 +209,7 @@ namespace MediaBrowser.LocalMetadata.Savers private void SaveToFile(Stream stream, string path) { - FileSystem.CreateDirectory(Path.GetDirectoryName(path)); + FileSystem.CreateDirectory(FileSystem.GetDirectoryName(path)); var file = FileSystem.GetFileInfo(path); diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index e402c2bac8..3672e4e845 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -70,7 +70,7 @@ namespace MediaBrowser.MediaEncoding.Encoder .CreateJob(options, EncodingHelper, IsVideoEncoder, progress, cancellationToken).ConfigureAwait(false); encodingJob.OutputFilePath = GetOutputFilePath(encodingJob); - FileSystem.CreateDirectory(Path.GetDirectoryName(encodingJob.OutputFilePath)); + FileSystem.CreateDirectory(FileSystem.GetDirectoryName(encodingJob.OutputFilePath)); encodingJob.ReadInputAtNativeFramerate = options.ReadInputAtNativeFramerate; @@ -108,7 +108,7 @@ namespace MediaBrowser.MediaEncoding.Encoder Logger.Info(commandLineLogMessage); var logFilePath = Path.Combine(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath, "transcode-" + Guid.NewGuid() + ".txt"); - FileSystem.CreateDirectory(Path.GetDirectoryName(logFilePath)); + FileSystem.CreateDirectory(FileSystem.GetDirectoryName(logFilePath)); // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. encodingJob.LogFileStream = FileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true); diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs index 498df214f9..dc3cb5f5e1 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs @@ -45,6 +45,11 @@ namespace MediaBrowser.MediaEncoding.Encoder /// System.String. private static string GetFileInputArgument(string path) { + if (path.IndexOf("://") != -1) + { + return string.Format("\"{0}\"", path); + } + // Quotes are valid path characters in linux and they need to be escaped here with a leading \ path = NormalizePath(path); diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 4819dc2898..c58a18b0fa 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -210,7 +210,7 @@ namespace MediaBrowser.MediaEncoding.Encoder if (EnableEncoderFontFile) { - var directory = Path.GetDirectoryName(FFMpegPath); + var directory = FileSystem.GetDirectoryName(FFMpegPath); if (!string.IsNullOrWhiteSpace(directory) && FileSystem.ContainsSubPath(ConfigurationManager.ApplicationPaths.ProgramDataPath, directory)) { @@ -415,7 +415,7 @@ namespace MediaBrowser.MediaEncoding.Encoder private string GetProbePathFromEncoderPath(string appPath) { - return FileSystem.GetFilePaths(Path.GetDirectoryName(appPath)) + return FileSystem.GetFilePaths(FileSystem.GetDirectoryName(appPath)) .FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffprobe", StringComparison.OrdinalIgnoreCase)); } @@ -704,7 +704,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } var tempExtractPath = Path.Combine(ConfigurationManager.ApplicationPaths.TempDirectory, Guid.NewGuid() + ".jpg"); - FileSystem.CreateDirectory(Path.GetDirectoryName(tempExtractPath)); + FileSystem.CreateDirectory(FileSystem.GetDirectoryName(tempExtractPath)); // apply some filters to thumbnail extracted below (below) crop any black lines that we made and get the correct ar then scale to width 600. // This filter chain may have adverse effects on recorded tv thumbnails if ar changes during presentation ex. commercials @ diff ar diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 3f2ecae317..1e983ca15c 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -412,7 +412,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles throw new ArgumentNullException("outputPath"); } - _fileSystem.CreateDirectory(Path.GetDirectoryName(outputPath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath)); var encodingParam = await GetSubtitleFileCharacterSet(inputPath, language, inputProtocol, cancellationToken).ConfigureAwait(false); @@ -546,7 +546,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles throw new ArgumentNullException("outputPath"); } - _fileSystem.CreateDirectory(Path.GetDirectoryName(outputPath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath)); var processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s {2} \"{3}\"", inputPath, subtitleStreamIndex, outputCodec, outputPath); diff --git a/MediaBrowser.Model/IO/IFileSystem.cs b/MediaBrowser.Model/IO/IFileSystem.cs index 6773acbfac..26de9332e3 100644 --- a/MediaBrowser.Model/IO/IFileSystem.cs +++ b/MediaBrowser.Model/IO/IFileSystem.cs @@ -146,6 +146,8 @@ namespace MediaBrowser.Model.IO /// System.String. string NormalizePath(string path); + string GetDirectoryName(string path); + /// /// Gets the file name without extension. /// diff --git a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs index 547420092d..6175c36225 100644 --- a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs +++ b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs @@ -158,7 +158,7 @@ namespace MediaBrowser.Providers.BoxSets var dataFilePath = GetDataFilePath(_config.ApplicationPaths, tmdbId, preferredMetadataLanguage); - _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(dataFilePath)); _json.SerializeToFile(mainResult, dataFilePath); } diff --git a/MediaBrowser.Providers/ImagesByName/ImageUtils.cs b/MediaBrowser.Providers/ImagesByName/ImageUtils.cs index 6c51d5bd74..566378dd02 100644 --- a/MediaBrowser.Providers/ImagesByName/ImageUtils.cs +++ b/MediaBrowser.Providers/ImagesByName/ImageUtils.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.Providers.ImagesByName }).ConfigureAwait(false); - fileSystem.CreateDirectory(Path.GetDirectoryName(file)); + fileSystem.CreateDirectory(fileSystem.GetDirectoryName(file)); try { diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 7c797133f4..1d8275c26f 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -238,7 +238,7 @@ namespace MediaBrowser.Providers.Manager { _logger.Debug("Saving image to {0}", path); - var parentFolder = Path.GetDirectoryName(path); + var parentFolder = _fileSystem.GetDirectoryName(path); await _imageSaveSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); @@ -247,7 +247,7 @@ namespace MediaBrowser.Providers.Manager _libraryMonitor.ReportFileSystemChangeBeginning(path); _libraryMonitor.ReportFileSystemChangeBeginning(parentFolder); - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); // If the file is currently hidden we'll have to remove that or the save will fail var file = _fileSystem.GetFileInfo(path); @@ -449,7 +449,7 @@ namespace MediaBrowser.Providers.Manager { if (type == ImageType.Primary && item is Episode) { - path = Path.Combine(Path.GetDirectoryName(item.Path), "metadata", filename + extension); + path = Path.Combine(_fileSystem.GetDirectoryName(item.Path), "metadata", filename + extension); } else if (item.DetectIsInMixedFolder()) @@ -581,7 +581,7 @@ namespace MediaBrowser.Providers.Manager if (item is Episode) { - var seasonFolder = Path.GetDirectoryName(item.Path); + var seasonFolder = _fileSystem.GetDirectoryName(item.Path); var imageFilename = _fileSystem.GetFileNameWithoutExtension(item.Path) + "-thumb" + extension; @@ -629,7 +629,7 @@ namespace MediaBrowser.Providers.Manager { imageFilename = "poster"; } - var folder = Path.GetDirectoryName(item.Path); + var folder = _fileSystem.GetDirectoryName(item.Path); return Path.Combine(folder, _fileSystem.GetFileNameWithoutExtension(item.Path) + "-" + imageFilename + extension); } diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs index d65084287f..cc5e7aef9b 100644 --- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs @@ -62,7 +62,7 @@ namespace MediaBrowser.Providers.MediaInfo if (!_fileSystem.FileExists(path)) { - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); var imageStream = imageStreams.FirstOrDefault(i => (i.Comment ?? string.Empty).IndexOf("front", StringComparison.OrdinalIgnoreCase) != -1) ?? imageStreams.FirstOrDefault(i => (i.Comment ?? string.Empty).IndexOf("cover", StringComparison.OrdinalIgnoreCase) != -1) ?? diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs index afcf4b2260..04e549526c 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs @@ -78,7 +78,7 @@ namespace MediaBrowser.Providers.MediaInfo }, cancellationToken).ConfigureAwait(false); - //Directory.CreateDirectory(Path.GetDirectoryName(cachePath)); + //Directory.CreateDirectory(_fileSystem.GetDirectoryName(cachePath)); //_json.SerializeToFile(result, cachePath); return result; diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 0aaa56babf..e84617fd34 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -150,7 +150,7 @@ namespace MediaBrowser.Providers.MediaInfo }, cancellationToken).ConfigureAwait(false); - //Directory.CreateDirectory(Path.GetDirectoryName(cachePath)); + //Directory.CreateDirectory(_fileSystem.GetDirectoryName(cachePath)); //_json.SerializeToFile(result, cachePath); return result; diff --git a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs index 946d6e68d6..84d8d20ad4 100644 --- a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs +++ b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs @@ -277,7 +277,7 @@ namespace MediaBrowser.Providers.Movies var path = GetFanartJsonPath(id); - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); try { diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs index 0101478b81..6702154791 100644 --- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs +++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs @@ -94,7 +94,7 @@ namespace MediaBrowser.Providers.Movies tmdbId = movieInfo.id.ToString(_usCulture); dataFilePath = MovieDbProvider.Current.GetDataFilePath(tmdbId, language); - _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(dataFilePath)); _jsonSerializer.SerializeToFile(movieInfo, dataFilePath); } } diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs index b3cf0541e9..d6aef5d1cf 100644 --- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs @@ -208,7 +208,7 @@ namespace MediaBrowser.Providers.Movies var dataFilePath = GetDataFilePath(id, preferredMetadataLanguage); - _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(dataFilePath)); _jsonSerializer.SerializeToFile(mainResult, dataFilePath); } diff --git a/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs b/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs index 96eab63cda..6d9b206891 100644 --- a/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs @@ -159,7 +159,7 @@ namespace MediaBrowser.Providers.Music var path = GetAlbumInfoPath(_config.ApplicationPaths, musicBrainzReleaseGroupId); - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); using (var response = await _httpClient.Get(new HttpRequestOptions { diff --git a/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs b/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs index bad7cf2ba9..c960e59a32 100644 --- a/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs +++ b/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs @@ -155,7 +155,7 @@ namespace MediaBrowser.Providers.Music }).ConfigureAwait(false)) { - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); using (var xmlFileStream = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true)) { diff --git a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs index 37e38e0482..977f814143 100644 --- a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs +++ b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs @@ -247,7 +247,7 @@ namespace MediaBrowser.Providers.Music var jsonPath = GetArtistJsonPath(_config.ApplicationPaths, musicBrainzId); - _fileSystem.CreateDirectory(Path.GetDirectoryName(jsonPath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(jsonPath)); try { diff --git a/MediaBrowser.Providers/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Omdb/OmdbProvider.cs index 0bafe7947f..d1c3b22142 100644 --- a/MediaBrowser.Providers/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Omdb/OmdbProvider.cs @@ -298,7 +298,7 @@ namespace MediaBrowser.Providers.Omdb using (var stream = await GetOmdbResponse(_httpClient, url, cancellationToken).ConfigureAwait(false)) { var rootObject = _jsonSerializer.DeserializeFromStream(stream); - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); _jsonSerializer.SerializeToFile(rootObject, path); } @@ -333,7 +333,7 @@ namespace MediaBrowser.Providers.Omdb using (var stream = await GetOmdbResponse(_httpClient, url, cancellationToken).ConfigureAwait(false)) { var rootObject = _jsonSerializer.DeserializeFromStream(stream); - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); _jsonSerializer.SerializeToFile(rootObject, path); } diff --git a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs index 3645a5f8df..19b8f292c9 100644 --- a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs +++ b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs @@ -250,7 +250,7 @@ namespace MediaBrowser.Providers.People }).ConfigureAwait(false)) { - _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(dataFilePath)); using (var fs = _fileSystem.GetFileStream(dataFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true)) { diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs index 15f4f654f9..1cf965e020 100644 --- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs +++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs @@ -115,7 +115,7 @@ namespace MediaBrowser.Providers.Subtitles using (var stream = response.Stream) { - var savePath = Path.Combine(Path.GetDirectoryName(video.Path), + var savePath = Path.Combine(_fileSystem.GetDirectoryName(video.Path), _fileSystem.GetFileNameWithoutExtension(video.Path) + "." + response.Language.ToLower()); if (response.IsForced) diff --git a/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs b/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs index d50e12a279..35178e1fe9 100644 --- a/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs @@ -312,7 +312,7 @@ namespace MediaBrowser.Providers.TV var path = GetFanartJsonPath(tvdbId); - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); try { diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs index 764b1e019d..b2d70918cc 100644 --- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs +++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs @@ -106,7 +106,7 @@ namespace MediaBrowser.Providers.TV var dataFilePath = GetDataFilePath(id, seasonNumber, episodeNumber, preferredMetadataLanguage); - _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(dataFilePath)); _jsonSerializer.SerializeToFile(mainResult, dataFilePath); } diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs index 1f0cc9e521..f41e254ca5 100644 --- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs +++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs @@ -190,7 +190,7 @@ namespace MediaBrowser.Providers.TV var dataFilePath = GetDataFilePath(id, seasonNumber, preferredMetadataLanguage); - _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(dataFilePath)); _jsonSerializer.SerializeToFile(mainResult, dataFilePath); } diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs index 5b4ae9745a..f290247375 100644 --- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs @@ -198,7 +198,7 @@ namespace MediaBrowser.Providers.TV tmdbId = seriesInfo.id.ToString(_usCulture); dataFilePath = GetDataFilePath(tmdbId, language); - _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(dataFilePath)); _jsonSerializer.SerializeToFile(seriesInfo, dataFilePath); await EnsureSeriesInfo(tmdbId, language, cancellationToken).ConfigureAwait(false); @@ -330,7 +330,7 @@ namespace MediaBrowser.Providers.TV var dataFilePath = GetDataFilePath(id, preferredMetadataLanguage); - _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath)); + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(dataFilePath)); _jsonSerializer.SerializeToFile(mainResult, dataFilePath); } diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs index 3039968b9b..24c2b507a2 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs @@ -226,7 +226,7 @@ namespace MediaBrowser.Providers.TV if (searchInfo.IndexNumber.HasValue) { - var files = GetEpisodeXmlFiles(searchInfo.ParentIndexNumber, searchInfo.IndexNumber, searchInfo.IndexNumberEnd, Path.GetDirectoryName(xmlFile)); + var files = GetEpisodeXmlFiles(searchInfo.ParentIndexNumber, searchInfo.IndexNumber, searchInfo.IndexNumberEnd, _fileSystem.GetDirectoryName(xmlFile)); list = files.Select(GetXmlReader).ToList(); } diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs index 8880441e29..72389044bd 100644 --- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs +++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs @@ -98,8 +98,8 @@ namespace MediaBrowser.WebDashboard.Api } path = GetDashboardResourcePath(path); - var parent = Path.GetDirectoryName(path); - + var parent = _fileSystem.GetDirectoryName(path); + return string.Equals(_basePath, parent, StringComparison.OrdinalIgnoreCase) || string.Equals(Path.Combine(_basePath, "voice"), parent, StringComparison.OrdinalIgnoreCase); } diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs index addb862ec8..ca7d8a43f7 100644 --- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs @@ -211,7 +211,7 @@ namespace MediaBrowser.XbmcMetadata.Savers private void SaveToFile(Stream stream, string path) { - FileSystem.CreateDirectory(Path.GetDirectoryName(path)); + FileSystem.CreateDirectory(FileSystem.GetDirectoryName(path)); var file = FileSystem.GetFileInfo(path); -- cgit v1.2.3