diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 4518ffad00..3074b0d5bc 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -760,145 +760,45 @@ namespace MediaBrowser.Api.Images var bytes = Convert.FromBase64String(text); // Validate first - using (var memoryStream = new MemoryStream(bytes)) + using (var validationStream = new MemoryStream(bytes)) { - using (var image = Image.FromStream(memoryStream)) + using (var image = Image.FromStream(validationStream)) { Logger.Info("New image is {0}x{1}", image.Width, image.Height); } } - string filename; + var memoryStream = new MemoryStream(bytes); - switch (imageType) - { - case ImageType.Art: - filename = "clearart"; - break; - case ImageType.Primary: - filename = entity is Episode ? Path.GetFileNameWithoutExtension(entity.Path) : "folder"; - break; - case ImageType.Backdrop: - filename = GetBackdropFilenameToSave(entity); - break; - case ImageType.Screenshot: - filename = GetScreenshotFilenameToSave(entity); - break; - default: - filename = imageType.ToString().ToLower(); - break; - } + memoryStream.Position = 0; - - var extension = mimeType.Split(';').First().Split('/').Last(); - - string oldImagePath; - switch (imageType) - { - case ImageType.Backdrop: - case ImageType.Screenshot: - oldImagePath = null; - break; - default: - oldImagePath = entity.GetImage(imageType); - break; - } - - // Don't save locally if there's no parent (special feature, trailer, etc) - var saveLocally = !(entity is Audio) && entity.Parent != null && !string.IsNullOrEmpty(entity.MetaLocation) || entity is User; - - if (imageType != ImageType.Primary) - { - if (entity is Episode) - { - saveLocally = false; - } - } - - if (entity.LocationType != LocationType.FileSystem) - { - saveLocally = false; - } - - var imagePath = _providerManager.GetSavePath(entity, filename + "." + extension, saveLocally); - - // Save to file system - using (var fs = new FileStream(imagePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true)) - { - await fs.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); - } + var imageIndex = 0; if (imageType == ImageType.Screenshot) { - entity.ScreenshotImagePaths.Add(imagePath); + imageIndex = entity.ScreenshotImagePaths.Count; } else if (imageType == ImageType.Backdrop) { - entity.BackdropImagePaths.Add(imagePath); + imageIndex = entity.BackdropImagePaths.Count; + } + + await _providerManager.SaveImage(entity, memoryStream, mimeType, imageType, imageIndex, CancellationToken.None).ConfigureAwait(false); + + var user = entity as User; + + if (user != null) + { + await _userManager.UpdateUser(user).ConfigureAwait(false); } else { - // Set the image - entity.SetImage(imageType, imagePath); + await _libraryManager.UpdateItem(entity, ItemUpdateType.ImageUpdate, CancellationToken.None) + .ConfigureAwait(false); } - // If the new and old paths are different, delete the old one - if (!string.IsNullOrEmpty(oldImagePath) && !oldImagePath.Equals(imagePath, StringComparison.OrdinalIgnoreCase)) - { - File.Delete(oldImagePath); - } - - // Directory watchers should repeat this, but do a quick refresh first - await entity.RefreshMetadata(CancellationToken.None, forceSave: true, allowSlowProviders: false).ConfigureAwait(false); + await entity.RefreshMetadata(CancellationToken.None, allowSlowProviders: false).ConfigureAwait(false); } } - - /// - /// Gets the backdrop filename to save. - /// - /// The item. - /// System.String. - private string GetBackdropFilenameToSave(BaseItem item) - { - var paths = item.BackdropImagePaths.ToList(); - - if (!paths.Any(i => string.Equals(Path.GetFileNameWithoutExtension(i), "backdrop", StringComparison.OrdinalIgnoreCase))) - { - return "screenshot"; - } - - var index = 1; - - while (paths.Any(i => string.Equals(Path.GetFileNameWithoutExtension(i), "backdrop" + index, StringComparison.OrdinalIgnoreCase))) - { - index++; - } - - return "backdrop" + index; - } - - /// - /// Gets the screenshot filename to save. - /// - /// The item. - /// System.String. - private string GetScreenshotFilenameToSave(BaseItem item) - { - var paths = item.ScreenshotImagePaths.ToList(); - - if (!paths.Any(i => string.Equals(Path.GetFileNameWithoutExtension(i), "screenshot", StringComparison.OrdinalIgnoreCase))) - { - return "screenshot"; - } - - var index = 1; - - while (paths.Any(i => string.Equals(Path.GetFileNameWithoutExtension(i), "screenshot" + index, StringComparison.OrdinalIgnoreCase))) - { - index++; - } - - return "screenshot" + index; - } } } diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index f776cf6758..d664d0bba5 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -104,6 +104,92 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager return client; } + public async Task GetResponse(HttpRequestOptions options) + { + ValidateParams(options.Url, options.CancellationToken); + + options.CancellationToken.ThrowIfCancellationRequested(); + + var client = GetHttpClient(GetHostFromUrl(options.Url), options.EnableHttpCompression); + + if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < 30) + { + throw new HttpException(string.Format("Cancelling connection to {0} due to a previous timeout.", options.Url)) { IsTimedOut = true }; + } + + using (var message = GetHttpRequestMessage(options)) + { + if (options.ResourcePool != null) + { + await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false); + } + + if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < 30) + { + if (options.ResourcePool != null) + { + options.ResourcePool.Release(); + } + + throw new HttpException(string.Format("Connection to {0} timed out", options.Url)) { IsTimedOut = true }; + } + + _logger.Info("HttpClientManager.Get url: {0}", options.Url); + + try + { + options.CancellationToken.ThrowIfCancellationRequested(); + + var response = await client.HttpClient.SendAsync(message, HttpCompletionOption.ResponseContentRead, options.CancellationToken).ConfigureAwait(false); + + EnsureSuccessStatusCode(response); + + options.CancellationToken.ThrowIfCancellationRequested(); + + return new HttpResponseInfo + { + Content = await response.Content.ReadAsStreamAsync().ConfigureAwait(false), + + StatusCode = response.StatusCode, + + ContentType = response.Content.Headers.ContentType.MediaType + }; + } + catch (OperationCanceledException ex) + { + var exception = GetCancellationException(options.Url, options.CancellationToken, ex); + + var httpException = exception as HttpException; + + if (httpException != null && httpException.IsTimedOut) + { + client.LastTimeout = DateTime.UtcNow; + } + + throw exception; + } + catch (HttpRequestException ex) + { + _logger.ErrorException("Error getting response from " + options.Url, ex); + + throw new HttpException(ex.Message, ex); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting response from " + options.Url, ex); + + throw; + } + finally + { + if (options.ResourcePool != null) + { + options.ResourcePool.Release(); + } + } + } + } + /// /// Performs a GET request and returns the resulting stream /// diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpResponseInfo.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpResponseInfo.cs deleted file mode 100644 index 4a4612ffb5..0000000000 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpResponseInfo.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; - -namespace MediaBrowser.Common.Implementations.HttpClientManager -{ - /// - /// Class HttpResponseOutput - /// - public class HttpResponseInfo - { - /// - /// Gets or sets the URL. - /// - /// The URL. - public string Url { get; set; } - - /// - /// Gets or sets the etag. - /// - /// The etag. - public string Etag { get; set; } - - /// - /// Gets or sets the last modified. - /// - /// The last modified. - public DateTime? LastModified { get; set; } - - /// - /// Gets or sets the expires. - /// - /// The expires. - public DateTime? Expires { get; set; } - - /// - /// Gets or sets a value indicating whether [must revalidate]. - /// - /// true if [must revalidate]; otherwise, false. - public bool MustRevalidate { get; set; } - - /// - /// Gets or sets the request date. - /// - /// The request date. - public DateTime RequestDate { get; set; } - } -} diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj index d804f6f1c7..e2a56e9120 100644 --- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -66,7 +66,6 @@ - diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 69439c5733..9a81537bff 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -74,6 +74,7 @@ + diff --git a/MediaBrowser.Common/Net/HttpResponseInfo.cs b/MediaBrowser.Common/Net/HttpResponseInfo.cs new file mode 100644 index 0000000000..558218ed16 --- /dev/null +++ b/MediaBrowser.Common/Net/HttpResponseInfo.cs @@ -0,0 +1,29 @@ +using System.IO; +using System.Net; + +namespace MediaBrowser.Common.Net +{ + /// + /// Class HttpResponseInfo + /// + public class HttpResponseInfo + { + /// + /// Gets or sets the type of the content. + /// + /// The type of the content. + public string ContentType { get; set; } + + /// + /// Gets or sets the content. + /// + /// The content. + public Stream Content { get; set; } + + /// + /// Gets or sets the status code. + /// + /// The status code. + public HttpStatusCode StatusCode { get; set; } + } +} diff --git a/MediaBrowser.Common/Net/IHttpClient.cs b/MediaBrowser.Common/Net/IHttpClient.cs index 2998d1af9b..6068d4e8c8 100644 --- a/MediaBrowser.Common/Net/IHttpClient.cs +++ b/MediaBrowser.Common/Net/IHttpClient.cs @@ -11,6 +11,13 @@ namespace MediaBrowser.Common.Net /// public interface IHttpClient : IDisposable { + /// + /// Gets the response. + /// + /// The options. + /// Task{HttpResponseInfo}. + Task GetResponse(HttpRequestOptions options); + /// /// Performs a GET request and returns the resulting stream /// diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index f8ecf003bf..c6d6bf2210 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -798,6 +798,9 @@ namespace MediaBrowser.Controller.Entities }); await ((Folder)child).ValidateChildren(innerProgress, cancellationToken, recursive, forceRefreshMetadata).ConfigureAwait(false); + + // Some folder providers are unable to refresh until children have been refreshed. + await child.RefreshMetadata(cancellationToken, resetResolveArgs: false).ConfigureAwait(false); } else { diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index 643dbe1c2c..6b8083b20e 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Entities; using System.Collections.Generic; using System.IO; using System.Threading; @@ -12,40 +13,8 @@ namespace MediaBrowser.Controller.Providers /// public interface IProviderManager { - /// - /// Downloads the and save image. - /// - /// The item. - /// The source. - /// Name of the target. - /// if set to true [save locally]. - /// The resource pool. - /// The cancellation token. - /// Task{System.String}. - /// item - Task DownloadAndSaveImage(BaseItem item, string source, string targetName, bool saveLocally, SemaphoreSlim resourcePool, CancellationToken cancellationToken); - - /// - /// Saves the image. - /// - /// The item. - /// The source. - /// Name of the target. - /// if set to true [save locally]. - /// The cancellation token. - /// Task{System.String}. - Task SaveImage(BaseItem item, Stream source, string targetName, bool saveLocally, CancellationToken cancellationToken); - - /// - /// Saves to library filesystem. - /// - /// The item. - /// The path. - /// The data to save. - /// The cancellation token. - /// Task. - /// - Task SaveToLibraryFilesystem(BaseItem item, string path, Stream dataToSave, CancellationToken cancellationToken); + Task DownloadAndSaveImage(BaseItem item, string source, string targetName, bool saveLocally, + SemaphoreSlim resourcePool, CancellationToken cancellationToken); /// /// Executes the metadata providers. @@ -57,19 +26,34 @@ namespace MediaBrowser.Controller.Providers /// Task{System.Boolean}. Task ExecuteMetadataProviders(BaseItem item, CancellationToken cancellationToken, bool force = false, bool allowSlowProviders = true); + /// + /// Saves the image. + /// + /// The item. + /// The URL. + /// The resource pool. + /// The type. + /// Index of the image. + /// The cancellation token. + /// Task. + Task SaveImage(BaseItem item, string url, SemaphoreSlim resourcePool, ImageType type, int? imageIndex, CancellationToken cancellationToken); + + /// + /// Saves the image. + /// + /// The item. + /// The source. + /// Type of the MIME. + /// The type. + /// Index of the image. + /// The cancellation token. + /// Task. + Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken); + /// /// Adds the metadata providers. /// /// The providers. void AddParts(IEnumerable providers); - - /// - /// Gets the save path. - /// - /// The item. - /// Name of the target file. - /// if set to true [save locally]. - /// System.String. - string GetSavePath(BaseItem item, string targetFileName, bool saveLocally); } } \ No newline at end of file diff --git a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs index 1a1c34928e..f0e696a06d 100644 --- a/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs +++ b/MediaBrowser.Providers/Movies/FanArtMovieProvider.cs @@ -303,9 +303,6 @@ namespace MediaBrowser.Providers.Movies cancellationToken.ThrowIfCancellationRequested(); - var saveLocal = ConfigurationManager.Configuration.SaveLocalMeta && - item.LocationType == LocationType.FileSystem; - string path; var hd = ConfigurationManager.Configuration.DownloadHDFanArt ? "hd" : ""; @@ -322,7 +319,7 @@ namespace MediaBrowser.Providers.Movies path = node != null ? node.Value : null; if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Logo, await _providerManager.DownloadAndSaveImage(item, path, LogoFile, saveLocal, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Logo, null, cancellationToken).ConfigureAwait(false); } } cancellationToken.ThrowIfCancellationRequested(); @@ -337,7 +334,8 @@ namespace MediaBrowser.Providers.Movies path = node != null ? node.Value : null; if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Art, await _providerManager.DownloadAndSaveImage(item, path, ArtFile, saveLocal, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Art, null, cancellationToken) + .ConfigureAwait(false); } } cancellationToken.ThrowIfCancellationRequested(); @@ -349,7 +347,8 @@ namespace MediaBrowser.Providers.Movies path = node != null ? node.Value : null; if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Disc, await _providerManager.DownloadAndSaveImage(item, path, DiscFile, saveLocal, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Disc, null, cancellationToken) + .ConfigureAwait(false); } } @@ -362,7 +361,8 @@ namespace MediaBrowser.Providers.Movies path = node != null ? node.Value : null; if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Banner, await _providerManager.DownloadAndSaveImage(item, path, BannerFile, saveLocal, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Banner, null, cancellationToken) + .ConfigureAwait(false); } } @@ -375,7 +375,8 @@ namespace MediaBrowser.Providers.Movies path = node != null ? node.Value : null; if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Thumb, await _providerManager.DownloadAndSaveImage(item, path, ThumbFile, saveLocal, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Thumb, null, cancellationToken) + .ConfigureAwait(false); } } @@ -393,7 +394,8 @@ namespace MediaBrowser.Providers.Movies if (!string.IsNullOrEmpty(path)) { - item.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(item, path, ("backdrop" + (numBackdrops > 0 ? numBackdrops.ToString(UsCulture) : "") + ".jpg"), saveLocal, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Backdrop, numBackdrops, cancellationToken) + .ConfigureAwait(false); numBackdrops++; diff --git a/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs b/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs index 2c9fbcec8a..feb14c3a01 100644 --- a/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs @@ -93,7 +93,7 @@ namespace MediaBrowser.Providers.Movies return ItemUpdateType.ImageUpdate; } } - + /// /// Gets a value indicating whether [requires internet]. /// @@ -148,7 +148,7 @@ namespace MediaBrowser.Providers.Movies { return false; } - + return base.NeedsRefreshInternal(item, providerInfo); } @@ -168,7 +168,7 @@ namespace MediaBrowser.Providers.Movies data = new BaseProviderInfo(); item.ProviderData[Id] = data; } - + var images = await FetchImages(item, item.GetProviderId(MetadataProviders.Tmdb), cancellationToken).ConfigureAwait(false); var status = await ProcessImages(item, images, cancellationToken).ConfigureAwait(false); @@ -246,7 +246,9 @@ namespace MediaBrowser.Providers.Movies }).ConfigureAwait(false); - item.PrimaryImagePath = await _providerManager.SaveImage(item, img, "folder" + Path.GetExtension(poster.file_path), ConfigurationManager.Configuration.SaveLocalMeta && item.LocationType == LocationType.FileSystem, cancellationToken).ConfigureAwait(false); + await _providerManager.SaveImage(item, img, MimeTypes.GetMimeType(poster.file_path), ImageType.Primary, null, cancellationToken) + .ConfigureAwait(false); + } } @@ -274,7 +276,8 @@ namespace MediaBrowser.Providers.Movies }).ConfigureAwait(false); - item.BackdropImagePaths.Add(await _providerManager.SaveImage(item, img, bdName + Path.GetExtension(images.backdrops[i].file_path), ConfigurationManager.Configuration.SaveLocalMeta && item.LocationType == LocationType.FileSystem, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, img, MimeTypes.GetMimeType(images.backdrops[i].file_path), ImageType.Backdrop, item.BackdropImagePaths.Count, cancellationToken) + .ConfigureAwait(false); } if (item.BackdropImagePaths.Count >= ConfigurationManager.Configuration.MaxBackdrops) diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs index 5f56ab690d..64259c4242 100644 --- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs @@ -32,7 +32,7 @@ namespace MediaBrowser.Providers.Movies /// /// The movie db /// - private readonly SemaphoreSlim _movieDbResourcePool = new SemaphoreSlim(1,1); + private readonly SemaphoreSlim _movieDbResourcePool = new SemaphoreSlim(1, 1); internal static MovieDbProvider Current { get; private set; } @@ -158,7 +158,7 @@ namespace MediaBrowser.Providers.Movies _tmdbSettingsSemaphore.Release(); return _tmdbSettings; } - + try { using (var json = await GetMovieDbResponse(new HttpRequestOptions @@ -199,7 +199,13 @@ namespace MediaBrowser.Providers.Movies protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo) { if (HasAltMeta(item)) - return false; + return false; + + // Boxsets require two passes because we need the children to be refreshed + if (item is BoxSet && string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.TmdbCollection))) + { + return true; + } return base.NeedsRefreshInternal(item, providerInfo); } @@ -291,19 +297,6 @@ namespace MediaBrowser.Providers.Movies /// Task{System.String}. public async Task FindId(BaseItem item, int? productionYear, CancellationToken cancellationToken) { - string id = null; - - if (item.LocationType == LocationType.FileSystem) - { - string justName = item.Path != null ? item.Path.Substring(item.Path.LastIndexOf(Path.DirectorySeparatorChar)) : string.Empty; - id = justName.GetAttributeValue("tmdbid"); - if (id != null) - { - Logger.Debug("Using tmdb id specified in path."); - return id; - } - } - int? year; string name = item.Name; ParseName(name, out name, out year); @@ -320,25 +313,14 @@ namespace MediaBrowser.Providers.Movies var boxset = item as BoxSet; if (boxset != null) { - var firstChild = boxset.Children.FirstOrDefault(); - - if (firstChild != null) - { - Logger.Debug("MovieDbProvider - Attempting to find boxset ID from: " + firstChild.Name); - string childName; - int? childYear; - ParseName(firstChild.Name, out childName, out childYear); - id = await GetBoxsetIdFromMovie(childName, childYear, language, cancellationToken).ConfigureAwait(false); - if (id != null) - { - Logger.Info("MovieDbProvider - Found Boxset ID: " + id); - } - } - - return id; + // See if any movies have a collection id already + return boxset.Children.OfType /// The item. /// The source. - /// Name of the target. + /// Type of the MIME. /// The cancellation token. /// Task{System.String}. - private async Task DownloadAndSaveImage(BaseItem item, string source, string targetName, CancellationToken cancellationToken) + private async Task DownloadAndSaveImage(BaseItem item, string source, string mimeType, CancellationToken cancellationToken) { - if (source == null) return null; - - //download and save locally (if not already there) - var localPath = Path.Combine(item.MetaLocation, targetName); + if (source == null) return; using (var sourceStream = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions { @@ -317,12 +309,11 @@ namespace MediaBrowser.Providers.Movies }).ConfigureAwait(false)) { - await ProviderManager.SaveToLibraryFilesystem(item, localPath, sourceStream, cancellationToken).ConfigureAwait(false); + await ProviderManager.SaveImage(item, sourceStream, mimeType, ImageType.Primary, null, cancellationToken) + .ConfigureAwait(false); Logger.Debug("TmdbPersonProvider downloaded and saved image for {0}", item.Name); } - - return localPath; } #region Result Objects diff --git a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs index d7990f4312..12539d2ba9 100644 --- a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs @@ -199,7 +199,8 @@ namespace MediaBrowser.Providers.Music if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Disc, await _providerManager.DownloadAndSaveImage(item, path, DiscFile, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Disc, null, cancellationToken) + .ConfigureAwait(false); } } @@ -217,7 +218,8 @@ namespace MediaBrowser.Providers.Music if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Primary, await _providerManager.DownloadAndSaveImage(item, path, PrimaryFile, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Primary, null, cancellationToken) + .ConfigureAwait(false); } } } diff --git a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs index f310934aff..2593b9838f 100644 --- a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs +++ b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs @@ -306,7 +306,8 @@ namespace MediaBrowser.Providers.Music path = node != null ? node.Value : null; if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Logo, await _providerManager.DownloadAndSaveImage(item, path, LogoFile, SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Logo, null, cancellationToken) + .ConfigureAwait(false); } } cancellationToken.ThrowIfCancellationRequested(); @@ -323,7 +324,8 @@ namespace MediaBrowser.Providers.Music path = node.Value; if (!string.IsNullOrEmpty(path)) { - item.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(item, path, ("Backdrop" + (numBackdrops > 0 ? numBackdrops.ToString(UsCulture) : "") + ".jpg"), SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Backdrop, numBackdrops, cancellationToken) + .ConfigureAwait(false); numBackdrops++; if (numBackdrops >= ConfigurationManager.Configuration.MaxBackdrops) break; } @@ -343,7 +345,8 @@ namespace MediaBrowser.Providers.Music path = node != null ? node.Value : null; if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Art, await _providerManager.DownloadAndSaveImage(item, path, ArtFile, SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Art, null, cancellationToken) + .ConfigureAwait(false); } } cancellationToken.ThrowIfCancellationRequested(); @@ -355,7 +358,8 @@ namespace MediaBrowser.Providers.Music path = node != null ? node.Value : null; if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Banner, await _providerManager.DownloadAndSaveImage(item, path, BannerFile, SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Banner, null, cancellationToken) + .ConfigureAwait(false); } } @@ -368,7 +372,8 @@ namespace MediaBrowser.Providers.Music path = node != null ? node.Value : null; if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Primary, await _providerManager.DownloadAndSaveImage(item, path, PrimaryFile, SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Primary, null, cancellationToken) + .ConfigureAwait(false); } } } diff --git a/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs b/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs index b16d378f7f..e8ecea38b0 100644 --- a/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs +++ b/MediaBrowser.Providers/Savers/SeriesXmlSaver.cs @@ -82,13 +82,16 @@ namespace MediaBrowser.Providers.Savers builder.Append("" + SecurityElement.Escape(series.AirTime) + ""); } - if (series.AirDays.Count == 7) + if (series.AirDays != null) { - builder.Append("" + SecurityElement.Escape("Daily") + ""); - } - else if (series.AirDays.Count > 0) - { - builder.Append("" + SecurityElement.Escape(series.AirDays[0].ToString()) + ""); + if (series.AirDays.Count == 7) + { + builder.Append("" + SecurityElement.Escape("Daily") + ""); + } + else if (series.AirDays.Count > 0) + { + builder.Append("" + SecurityElement.Escape(series.AirDays[0].ToString()) + ""); + } } XmlSaverHelpers.AddCommonNodes(item, builder); diff --git a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs index d0a0735fb9..4999a845df 100644 --- a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs +++ b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs @@ -149,7 +149,8 @@ namespace MediaBrowser.Providers.TV if (!string.IsNullOrEmpty(path)) { - season.SetImage(ImageType.Thumb, await _providerManager.DownloadAndSaveImage(season, path, ThumbFile, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(season, path, FanArtResourcePool, ImageType.Thumb, null, cancellationToken) + .ConfigureAwait(false); } } } diff --git a/MediaBrowser.Providers/TV/FanArtTVProvider.cs b/MediaBrowser.Providers/TV/FanArtTVProvider.cs index 6dc61b35d2..84ac59924c 100644 --- a/MediaBrowser.Providers/TV/FanArtTVProvider.cs +++ b/MediaBrowser.Providers/TV/FanArtTVProvider.cs @@ -234,7 +234,8 @@ namespace MediaBrowser.Providers.TV var path = node != null ? node.Value : null; if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Logo, await _providerManager.DownloadAndSaveImage(item, path, LogoFile, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Logo, null, cancellationToken) + .ConfigureAwait(false); } } @@ -250,7 +251,8 @@ namespace MediaBrowser.Providers.TV var path = node != null ? node.Value : null; if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Art, await _providerManager.DownloadAndSaveImage(item, path, ArtFile, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Art, null, cancellationToken) + .ConfigureAwait(false); } } @@ -263,7 +265,8 @@ namespace MediaBrowser.Providers.TV var path = node != null ? node.Value : null; if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Thumb, await _providerManager.DownloadAndSaveImage(item, path, ThumbFile, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Thumb, null, cancellationToken) + .ConfigureAwait(false); } } @@ -274,7 +277,8 @@ namespace MediaBrowser.Providers.TV var path = node != null ? node.Value : null; if (!string.IsNullOrEmpty(path)) { - item.SetImage(ImageType.Banner, await _providerManager.DownloadAndSaveImage(item, path, BannerFile, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Banner, null, cancellationToken) + .ConfigureAwait(false); } } @@ -292,7 +296,8 @@ namespace MediaBrowser.Providers.TV if (!string.IsNullOrEmpty(path)) { - item.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(item, path, ("backdrop" + (numBackdrops > 0 ? numBackdrops.ToString(UsCulture) : "") + ".jpg"), ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false)); + await _providerManager.SaveImage(item, path, FanArtResourcePool, ImageType.Backdrop, numBackdrops, cancellationToken) + .ConfigureAwait(false); numBackdrops++; diff --git a/MediaBrowser.Providers/TV/RemoteEpisodeProvider.cs b/MediaBrowser.Providers/TV/RemoteEpisodeProvider.cs index eb79075ffc..438d49507e 100644 --- a/MediaBrowser.Providers/TV/RemoteEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/RemoteEpisodeProvider.cs @@ -276,7 +276,10 @@ namespace MediaBrowser.Providers.TV try { - episode.PrimaryImagePath = await _providerManager.DownloadAndSaveImage(episode, TVUtils.BannerUrl + p, Path.GetFileName(p), ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken); + var url = TVUtils.BannerUrl + p; + + await _providerManager.SaveImage(episode, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Primary, null, cancellationToken) + .ConfigureAwait(false); } catch (HttpException) { diff --git a/MediaBrowser.Providers/TV/RemoteSeasonProvider.cs b/MediaBrowser.Providers/TV/RemoteSeasonProvider.cs index f8399ebdf9..1ea2c1db5f 100644 --- a/MediaBrowser.Providers/TV/RemoteSeasonProvider.cs +++ b/MediaBrowser.Providers/TV/RemoteSeasonProvider.cs @@ -188,7 +188,12 @@ namespace MediaBrowser.Providers.TV n = n.SelectSingleNode("./BannerPath"); if (n != null) - season.PrimaryImagePath = await _providerManager.DownloadAndSaveImage(season, TVUtils.BannerUrl + n.InnerText, "folder" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken).ConfigureAwait(false); + { + var url = TVUtils.BannerUrl + n.InnerText; + + await _providerManager.SaveImage(season, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Primary, null, cancellationToken) + .ConfigureAwait(false); + } } } @@ -203,15 +208,10 @@ namespace MediaBrowser.Providers.TV { try { - var bannerImagePath = - await _providerManager.DownloadAndSaveImage(season, - TVUtils.BannerUrl + n.InnerText, - "banner" + - Path.GetExtension(n.InnerText), - ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken). - ConfigureAwait(false); + var url = TVUtils.BannerUrl + n.InnerText; - season.SetImage(ImageType.Banner, bannerImagePath); + await _providerManager.SaveImage(season, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Banner, null, cancellationToken) + .ConfigureAwait(false); } catch (HttpException ex) { @@ -235,7 +235,11 @@ namespace MediaBrowser.Providers.TV n = n.SelectSingleNode("./BannerPath"); if (n != null) { - season.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(season, TVUtils.BannerUrl + n.InnerText, "backdrop" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken).ConfigureAwait(false)); + var url = TVUtils.BannerUrl + n.InnerText; + + await _providerManager.SaveImage(season, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Backdrop, 0, cancellationToken) + .ConfigureAwait(false); + } } } diff --git a/MediaBrowser.Providers/TV/RemoteSeriesProvider.cs b/MediaBrowser.Providers/TV/RemoteSeriesProvider.cs index fc37912eff..3d86ebb7e1 100644 --- a/MediaBrowser.Providers/TV/RemoteSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/RemoteSeriesProvider.cs @@ -215,13 +215,6 @@ namespace MediaBrowser.Providers.TV await FetchSeriesData(series, seriesId, seriesDataPath, force, cancellationToken).ConfigureAwait(false); } - BaseProviderInfo data; - if (!item.ProviderData.TryGetValue(Id, out data)) - { - data = new BaseProviderInfo(); - item.ProviderData[Id] = data; - } - SetLastRefreshed(item, DateTime.UtcNow); return true; } diff --git a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs index 2d8bf5ed69..776cede8ef 100644 --- a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs @@ -197,9 +197,10 @@ namespace MediaBrowser.Providers.TV n = n.SelectSingleNode("./BannerPath"); if (n != null) { - var path = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "folder" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken).ConfigureAwait(false); + var url = TVUtils.BannerUrl + n.InnerText; - series.SetImage(ImageType.Primary, path); + await _providerManager.SaveImage(series, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Primary, null, cancellationToken) + .ConfigureAwait(false); } } } @@ -212,9 +213,10 @@ namespace MediaBrowser.Providers.TV n = n.SelectSingleNode("./BannerPath"); if (n != null) { - var bannerImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "banner" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken); + var url = TVUtils.BannerUrl + n.InnerText; - series.SetImage(ImageType.Banner, bannerImagePath); + await _providerManager.SaveImage(series, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Banner, null, cancellationToken) + .ConfigureAwait(false); } } } @@ -232,8 +234,11 @@ namespace MediaBrowser.Providers.TV if (p != null) { - var bdName = "backdrop" + (bdNo > 0 ? bdNo.ToString(UsCulture) : ""); - series.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + p.InnerText, bdName + Path.GetExtension(p.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken).ConfigureAwait(false)); + var url = TVUtils.BannerUrl + p.InnerText; + + await _providerManager.SaveImage(series, url, RemoteSeriesProvider.Current.TvDbResourcePool, ImageType.Backdrop, bdNo, cancellationToken) + .ConfigureAwait(false); + bdNo++; } diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 08fbe31c00..041c9db6b8 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -148,6 +148,7 @@ + diff --git a/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs b/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs new file mode 100644 index 0000000000..3e5a2802cc --- /dev/null +++ b/MediaBrowser.Server.Implementations/Providers/ImageSaver.cs @@ -0,0 +1,255 @@ +using System.Globalization; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.Entities; +using System; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.Providers +{ + /// + /// Class ImageSaver + /// + public class ImageSaver + { + private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + + /// + /// The _config + /// + private readonly IServerConfigurationManager _config; + + /// + /// The remote image cache + /// + private readonly FileSystemRepository _remoteImageCache; + /// + /// The _directory watchers + /// + private readonly IDirectoryWatchers _directoryWatchers; + + /// + /// Initializes a new instance of the class. + /// + /// The config. + /// The directory watchers. + public ImageSaver(IServerConfigurationManager config, IDirectoryWatchers directoryWatchers) + { + _config = config; + _directoryWatchers = directoryWatchers; + _remoteImageCache = new FileSystemRepository(config.ApplicationPaths.DownloadedImagesDataPath); + } + + /// + /// Saves the image. + /// + /// The item. + /// The source. + /// Type of the MIME. + /// The type. + /// Index of the image. + /// The cancellation token. + /// Task. + public async Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken) + { + if (string.IsNullOrEmpty(mimeType)) + { + throw new ArgumentNullException("mimeType"); + } + + var saveLocally = _config.Configuration.SaveLocalMeta; + + if (item is IItemByName) + { + saveLocally = true; + } + else if (item is User) + { + saveLocally = true; + } + else if (item is Audio || item.Parent == null || string.IsNullOrEmpty(item.MetaLocation)) + { + saveLocally = false; + } + + if (type != ImageType.Primary) + { + if (item is Episode) + { + saveLocally = false; + } + } + + if (item.LocationType != LocationType.FileSystem) + { + saveLocally = false; + } + + var path = GetSavePath(item, type, imageIndex, mimeType, saveLocally); + + var currentPath = GetCurrentImagePath(item, type, imageIndex); + + try + { + _directoryWatchers.TemporarilyIgnore(path); + + using (source) + { + using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous)) + { + await source.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false); + } + } + + SetImagePath(item, type, imageIndex, path); + + if (!string.IsNullOrEmpty(currentPath) && !string.Equals(path, currentPath, StringComparison.OrdinalIgnoreCase)) + { + File.Delete(currentPath); + } + } + finally + { + _directoryWatchers.RemoveTempIgnore(path); + } + + } + + private string GetCurrentImagePath(BaseItem item, ImageType type, int? imageIndex) + { + switch (type) + { + case ImageType.Screenshot: + + if (!imageIndex.HasValue) + { + throw new ArgumentNullException("imageIndex"); + } + return item.ScreenshotImagePaths.Count > imageIndex.Value ? item.ScreenshotImagePaths[imageIndex.Value] : null; + case ImageType.Backdrop: + if (!imageIndex.HasValue) + { + throw new ArgumentNullException("imageIndex"); + } + return item.BackdropImagePaths.Count > imageIndex.Value ? item.BackdropImagePaths[imageIndex.Value] : null; + default: + return item.GetImage(type); + } + } + + private void SetImagePath(BaseItem item, ImageType type, int? imageIndex, string path) + { + switch (type) + { + case ImageType.Screenshot: + + if (!imageIndex.HasValue) + { + throw new ArgumentNullException("imageIndex"); + } + + if (item.ScreenshotImagePaths.Count > imageIndex.Value) + { + item.ScreenshotImagePaths[imageIndex.Value] = path; + } + else + { + item.ScreenshotImagePaths.Add(path); + } + break; + case ImageType.Backdrop: + if (!imageIndex.HasValue) + { + throw new ArgumentNullException("imageIndex"); + } + if (item.BackdropImagePaths.Count > imageIndex.Value) + { + item.BackdropImagePaths[imageIndex.Value] = path; + } + else + { + item.BackdropImagePaths.Add(path); + } + break; + default: + item.SetImage(type, path); + break; + } + } + + /// + /// Gets the save path. + /// + /// The item. + /// The type. + /// Index of the image. + /// Type of the MIME. + /// if set to true [save locally]. + /// System.String. + /// + /// imageIndex + /// or + /// imageIndex + /// + private string GetSavePath(BaseItem item, ImageType type, int? imageIndex, string mimeType, bool saveLocally) + { + string filename; + + switch (type) + { + case ImageType.Art: + filename = "clearart"; + break; + case ImageType.Primary: + filename = item is Episode ? Path.GetFileNameWithoutExtension(item.Path) : "folder"; + break; + case ImageType.Backdrop: + if (!imageIndex.HasValue) + { + throw new ArgumentNullException("imageIndex"); + } + filename = imageIndex.Value == 0 ? "backdrop" : "backdrop" + imageIndex.Value.ToString(UsCulture); + break; + case ImageType.Screenshot: + if (!imageIndex.HasValue) + { + throw new ArgumentNullException("imageIndex"); + } + filename = imageIndex.Value == 0 ? "screenshot" : "screenshot" + imageIndex.Value.ToString(UsCulture); + break; + default: + filename = type.ToString().ToLower(); + break; + } + + var extension = mimeType.Split('/').Last(); + + if (string.Equals(extension, "jpeg", StringComparison.OrdinalIgnoreCase)) + { + extension = "jpg"; + } + + filename += "." + extension.ToLower(); + + var path = (saveLocally && !string.IsNullOrEmpty(item.MetaLocation)) ? + Path.Combine(item.MetaLocation, filename) : + _remoteImageCache.GetResourcePath(item.GetType().FullName + item.Id, filename); + + var parentPath = Path.GetDirectoryName(path); + + if (!Directory.Exists(parentPath)) + { + Directory.CreateDirectory(parentPath); + } + + return path; + } + } +} diff --git a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs index ee8bb4c096..0af7426b10 100644 --- a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs +++ b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs @@ -2,11 +2,14 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -22,11 +25,6 @@ namespace MediaBrowser.Server.Implementations.Providers /// public class ProviderManager : IProviderManager { - /// - /// The remote image cache - /// - private readonly FileSystemRepository _remoteImageCache; - /// /// The currently running metadata providers /// @@ -74,7 +72,6 @@ namespace MediaBrowser.Server.Implementations.Providers _httpClient = httpClient; ConfigurationManager = configurationManager; _directoryWatchers = directoryWatchers; - _remoteImageCache = new FileSystemRepository(configurationManager.ApplicationPaths.DownloadedImagesDataPath); configurationManager.ConfigurationUpdated += configurationManager_ConfigurationUpdated; } @@ -206,7 +203,7 @@ namespace MediaBrowser.Server.Implementations.Providers try { var changed = await provider.FetchAsync(item, force, CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, innerCancellationTokenSource.Token).Token).ConfigureAwait(false); - + if (changed) { return provider.ItemUpdateType; @@ -315,90 +312,9 @@ namespace MediaBrowser.Server.Implementations.Providers /// The cancellation token. /// Task{System.String}. /// item - public async Task DownloadAndSaveImage(BaseItem item, string source, string targetName, bool saveLocally, SemaphoreSlim resourcePool, CancellationToken cancellationToken) + public Task DownloadAndSaveImage(BaseItem item, string source, string targetName, bool saveLocally, SemaphoreSlim resourcePool, CancellationToken cancellationToken) { - if (item == null) - { - throw new ArgumentNullException("item"); - } - if (string.IsNullOrEmpty(source)) - { - throw new ArgumentNullException("source"); - } - if (string.IsNullOrEmpty(targetName)) - { - throw new ArgumentNullException("targetName"); - } - if (resourcePool == null) - { - throw new ArgumentNullException("resourcePool"); - } - - var img = await _httpClient.Get(source, resourcePool, cancellationToken).ConfigureAwait(false); - - //download and save locally - return await SaveImage(item, img, targetName, saveLocally, cancellationToken).ConfigureAwait(false); - } - - public async Task SaveImage(BaseItem item, Stream source, string targetName, bool saveLocally, CancellationToken cancellationToken) - { - //download and save locally - var localPath = GetSavePath(item, targetName, saveLocally); - - if (saveLocally) // queue to media directories - { - await SaveToLibraryFilesystem(item, localPath, source, cancellationToken).ConfigureAwait(false); - } - else - { - // we can write directly here because it won't affect the watchers - - try - { - using (var fs = new FileStream(localPath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous)) - { - await source.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false); - } - } - catch (OperationCanceledException) - { - throw; - } - catch (Exception e) - { - _logger.ErrorException("Error downloading and saving image " + localPath, e); - throw; - } - finally - { - source.Dispose(); - } - - } - return localPath; - } - - /// - /// Gets the save path. - /// - /// The item. - /// Name of the target file. - /// if set to true [save locally]. - /// System.String. - public string GetSavePath(BaseItem item, string targetFileName, bool saveLocally) - { - var path = (saveLocally && item.MetaLocation != null) ? - Path.Combine(item.MetaLocation, targetFileName) : - _remoteImageCache.GetResourcePath(item.GetType().FullName + item.Id.ToString(), targetFileName); - - var parentPath = Path.GetDirectoryName(path); - - if (!Directory.Exists(parentPath)) - { - Directory.CreateDirectory(parentPath); - } - - return path; + throw new HttpException(string.Empty) { IsTimedOut = true }; } /// @@ -462,5 +378,45 @@ namespace MediaBrowser.Server.Implementations.Providers _directoryWatchers.RemoveTempIgnore(path); } } + + + /// + /// Saves the image. + /// + /// The item. + /// The URL. + /// The resource pool. + /// The type. + /// Index of the image. + /// The cancellation token. + /// Task. + public async Task SaveImage(BaseItem item, string url, SemaphoreSlim resourcePool, ImageType type, int? imageIndex, CancellationToken cancellationToken) + { + var response = await _httpClient.GetResponse(new HttpRequestOptions + { + CancellationToken = cancellationToken, + ResourcePool = resourcePool, + Url = url + + }).ConfigureAwait(false); + + await SaveImage(item, response.Content, response.ContentType, type, imageIndex, cancellationToken) + .ConfigureAwait(false); + } + + /// + /// Saves the image. + /// + /// The item. + /// The source. + /// Type of the MIME. + /// The type. + /// Index of the image. + /// The cancellation token. + /// Task. + public Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken) + { + return new ImageSaver(ConfigurationManager, _directoryWatchers).SaveImage(item, source, mimeType, type, imageIndex, cancellationToken); + } } }