diff --git a/Emby.Server.Implementations/Connect/ConnectManager.cs b/Emby.Server.Implementations/Connect/ConnectManager.cs index 7e6755f6a..8aac2a8c4 100644 --- a/Emby.Server.Implementations/Connect/ConnectManager.cs +++ b/Emby.Server.Implementations/Connect/ConnectManager.cs @@ -995,7 +995,7 @@ namespace Emby.Server.Implementations.Connect if (changed) { - await _providerManager.SaveImage(user, imageUrl, null, ImageType.Primary, null, CancellationToken.None).ConfigureAwait(false); + await _providerManager.SaveImage(user, imageUrl, ImageType.Primary, null, CancellationToken.None).ConfigureAwait(false); await user.RefreshMetadata(new MetadataRefreshOptions(_fileSystem) { diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 372a99853..de3a1664e 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -2760,7 +2760,6 @@ namespace Emby.Server.Implementations.Library return ItemRepository.UpdatePeople(item.Id, people); } - private readonly SemaphoreSlim _dynamicImageResourcePool = new SemaphoreSlim(1, 1); public async Task ConvertImageToLocal(IHasImages item, ItemImageInfo image, int imageIndex) { foreach (var url in image.Path.Split('|')) @@ -2769,7 +2768,7 @@ namespace Emby.Server.Implementations.Library { _logger.Debug("ConvertImageToLocal item {0} - image url: {1}", item.Id, url); - await _providerManagerFactory().SaveImage(item, url, _dynamicImageResourcePool, image.Type, imageIndex, CancellationToken.None).ConfigureAwait(false); + await _providerManagerFactory().SaveImage(item, url, image.Type, imageIndex, CancellationToken.None).ConfigureAwait(false); var newImage = item.GetImageInfo(image.Type, imageIndex); diff --git a/MediaBrowser.Api/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs index eb871746d..d7ccf8f6d 100644 --- a/MediaBrowser.Api/Images/RemoteImageService.cs +++ b/MediaBrowser.Api/Images/RemoteImageService.cs @@ -210,7 +210,7 @@ namespace MediaBrowser.Api.Images /// Task. private async Task DownloadRemoteImage(BaseItem item, BaseDownloadRemoteImage request) { - await _providerManager.SaveImage(item, request.ImageUrl, null, request.Type, null, CancellationToken.None).ConfigureAwait(false); + await _providerManager.SaveImage(item, request.ImageUrl, request.Type, null, CancellationToken.None).ConfigureAwait(false); await item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); } diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index a880b6d77..6e0f4ada9 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -788,7 +788,7 @@ namespace MediaBrowser.Controller.Entities query.IsVirtualUnaired, query.IsUnaired); - if (collapseBoxSetItems) + if (collapseBoxSetItems && user != null) { items = CollapseBoxSetItemsIfNeeded(items, query, queryParent, user, configurationManager); } @@ -1119,13 +1119,11 @@ namespace MediaBrowser.Controller.Entities InternalItemsQuery query, ILibraryManager libraryManager, bool enableSorting) { - var user = query.User; - items = items.DistinctBy(i => i.GetPresentationUniqueKey(), StringComparer.OrdinalIgnoreCase); if (query.SortBy.Length > 0) { - items = libraryManager.Sort(items, user, query.SortBy, query.SortOrder); + items = libraryManager.Sort(items, query.User, query.SortBy, query.SortOrder); } var itemsArray = totalRecordLimit.HasValue ? items.Take(totalRecordLimit.Value).ToArray() : items.ToArray(); diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index 428651ed5..f4d45c7e0 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -47,12 +47,11 @@ namespace MediaBrowser.Controller.Providers /// /// The item. /// The URL. - /// The resource pool. /// The type. /// Index of the image. /// The cancellation token. /// Task. - Task SaveImage(IHasImages item, string url, SemaphoreSlim resourcePool, ImageType type, int? imageIndex, CancellationToken cancellationToken); + Task SaveImage(IHasImages item, string url, ImageType type, int? imageIndex, CancellationToken cancellationToken); /// /// Saves the image. diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 5146df6e6..a65453a78 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -16,7 +16,6 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; namespace MediaBrowser.Providers.Manager @@ -234,6 +233,7 @@ namespace MediaBrowser.Providers.Manager return retryPath; } + private SemaphoreSlim _imageSaveSemaphore = new SemaphoreSlim(1, 1); /// /// Saves the image to location. /// @@ -247,11 +247,13 @@ namespace MediaBrowser.Providers.Manager var parentFolder = Path.GetDirectoryName(path); - _libraryMonitor.ReportFileSystemChangeBeginning(path); - _libraryMonitor.ReportFileSystemChangeBeginning(parentFolder); + await _imageSaveSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); try { + _libraryMonitor.ReportFileSystemChangeBeginning(path); + _libraryMonitor.ReportFileSystemChangeBeginning(parentFolder); + _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); // If the file is currently hidden we'll have to remove that or the save will fail @@ -283,6 +285,8 @@ namespace MediaBrowser.Providers.Manager } finally { + _imageSaveSemaphore.Release(); + _libraryMonitor.ReportFileSystemChangeComplete(path, false); _libraryMonitor.ReportFileSystemChangeComplete(parentFolder, false); } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 9c6d6a482..bdfe13c1d 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -253,7 +253,7 @@ namespace MediaBrowser.Providers.Manager { try { - await ProviderManager.SaveImage(personEntity, imageUrl, null, ImageType.Primary, null, cancellationToken).ConfigureAwait(false); + await ProviderManager.SaveImage(personEntity, imageUrl, ImageType.Primary, null, cancellationToken).ConfigureAwait(false); return; } catch (Exception ex) diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 003e7b9fa..0b8dca2eb 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -123,12 +123,11 @@ namespace MediaBrowser.Providers.Manager return Task.FromResult(ItemUpdateType.None); } - public async Task SaveImage(IHasImages item, string url, SemaphoreSlim resourcePool, ImageType type, int? imageIndex, CancellationToken cancellationToken) + public async Task SaveImage(IHasImages item, string url, ImageType type, int? imageIndex, CancellationToken cancellationToken) { var response = await _httpClient.GetResponse(new HttpRequestOptions { CancellationToken = cancellationToken, - ResourcePool = resourcePool, Url = url, BufferContent = false diff --git a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs index db551b763..73668b73c 100644 --- a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs +++ b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs @@ -127,14 +127,7 @@ namespace MediaBrowser.Providers.Omdb } } - using (var stream = await _httpClient.Get(new HttpRequestOptions - { - Url = url, - ResourcePool = OmdbProvider.ResourcePool, - CancellationToken = cancellationToken, - BufferContent = true - - }).ConfigureAwait(false)) + using (var stream = await OmdbProvider.GetOmdbResponse(_httpClient, url, cancellationToken).ConfigureAwait(false)) { var resultList = new List(); diff --git a/MediaBrowser.Providers/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Omdb/OmdbProvider.cs index f5086ce98..07b35c45a 100644 --- a/MediaBrowser.Providers/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Omdb/OmdbProvider.cs @@ -296,14 +296,7 @@ namespace MediaBrowser.Providers.Omdb var url = string.Format("https://www.omdbapi.com/?i={0}&plot=full&tomatoes=true&r=json", imdbParam); - using (var stream = await _httpClient.Get(new HttpRequestOptions - { - Url = url, - ResourcePool = ResourcePool, - CancellationToken = cancellationToken, - BufferContent = true - - }).ConfigureAwait(false)) + using (var stream = await GetOmdbResponse(_httpClient, url, cancellationToken).ConfigureAwait(false)) { var rootObject = _jsonSerializer.DeserializeFromStream(stream); _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); @@ -337,14 +330,7 @@ namespace MediaBrowser.Providers.Omdb var url = string.Format("https://www.omdbapi.com/?i={0}&season={1}&detail=full", imdbParam, seasonId); - using (var stream = await _httpClient.Get(new HttpRequestOptions - { - Url = url, - ResourcePool = ResourcePool, - CancellationToken = cancellationToken, - BufferContent = true - - }).ConfigureAwait(false)) + using (var stream = await GetOmdbResponse(_httpClient, url, cancellationToken).ConfigureAwait(false)) { var rootObject = _jsonSerializer.DeserializeFromStream(stream); _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); @@ -354,6 +340,17 @@ namespace MediaBrowser.Providers.Omdb return path; } + public static Task GetOmdbResponse(IHttpClient httpClient, string url, CancellationToken cancellationToken) + { + return httpClient.Get(new HttpRequestOptions + { + Url = url, + ResourcePool = ResourcePool, + CancellationToken = cancellationToken, + BufferContent = true + }); + } + internal string GetDataFilePath(string imdbId) { if (string.IsNullOrEmpty(imdbId))