/// <summary> /// Gets the images. /// </summary> /// <param name="item">The item.</param> /// <param name="provider">The provider.</param> /// <param name="preferredLanguages">The preferred languages.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="type">The type.</param> /// <returns>Task{IEnumerable{RemoteImageInfo}}.</returns> private async Task <IEnumerable <RemoteImageInfo> > GetImages( BaseItem item, IRemoteImageProvider provider, IReadOnlyCollection <string> preferredLanguages, CancellationToken cancellationToken, ImageType?type = null) { try { var result = await provider.GetImages(item, cancellationToken).ConfigureAwait(false); if (type.HasValue) { result = result.Where(i => i.Type == type.Value); } if (preferredLanguages.Count > 0) { result = result.Where(i => string.IsNullOrEmpty(i.Language) || preferredLanguages.Contains(i.Language, StringComparer.OrdinalIgnoreCase) || string.Equals(i.Language, "en", StringComparison.OrdinalIgnoreCase)); } return(result); } catch (OperationCanceledException) { return(new List <RemoteImageInfo>()); } catch (Exception ex) { _logger.LogError(ex, "{ProviderName} failed in GetImageInfos for type {ItemType} at {ItemPath}", provider.GetType().Name, item.GetType().Name, item.Path); return(new List <RemoteImageInfo>()); } }
private async Task DownloadImage(IHasImages item, IRemoteImageProvider provider, RefreshResult result, IEnumerable <RemoteImageInfo> images, int minWidth, ImageType type, CancellationToken cancellationToken) { foreach (var image in images.Where(i => i.Type == type)) { if (image.Width.HasValue && image.Width.Value < minWidth) { continue; } var url = image.Url; try { var response = await provider.GetImageResponse(url, cancellationToken).ConfigureAwait(false); await _providerManager.SaveImage(item, response.Content, response.ContentType, type, null, cancellationToken).ConfigureAwait(false); result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; break; } catch (HttpException ex) { // Sometimes providers send back bad url's. Just move to the next image if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) { continue; } break; } } }
private async Task <bool> DownloadImage( BaseItem item, LibraryOptions libraryOptions, IRemoteImageProvider provider, RefreshResult result, IEnumerable <RemoteImageInfo> images, int minWidth, ImageType type, CancellationToken cancellationToken) { var eligibleImages = images .Where(i => i.Type == type && !(i.Width.HasValue && i.Width.Value < minWidth)) .ToList(); if (EnableImageStub(item, libraryOptions) && eligibleImages.Count > 0) { SaveImageStub(item, type, eligibleImages.Select(i => i.Url)); result.UpdateType |= ItemUpdateType.ImageUpdate; return(true); } foreach (var image in eligibleImages) { var url = image.Url; try { using var response = await provider.GetImageResponse(url, cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode(); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); await _providerManager.SaveImage( item, stream, response.Content.Headers.ContentType.MediaType, type, null, cancellationToken).ConfigureAwait(false); result.UpdateType |= ItemUpdateType.ImageUpdate; return(true); } catch (HttpRequestException ex) { // Sometimes providers send back bad url's. Just move to the next image if (ex.StatusCode.HasValue && (ex.StatusCode.Value == HttpStatusCode.NotFound || ex.StatusCode.Value == HttpStatusCode.Forbidden)) { continue; } break; } } return(false); }
/// <summary> /// Refreshes from provider. /// </summary> /// <param name="item">The item.</param> /// <param name="provider">The provider.</param> /// <param name="refreshOptions">The refresh options.</param> /// <param name="savedOptions">The saved options.</param> /// <param name="backdropLimit">The backdrop limit.</param> /// <param name="screenshotLimit">The screenshot limit.</param> /// <param name="result">The result.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> private async Task RefreshFromProvider(IHasImages item, IRemoteImageProvider provider, ImageRefreshOptions refreshOptions, MetadataOptions savedOptions, int backdropLimit, int screenshotLimit, RefreshResult result, CancellationToken cancellationToken) { try { if (ContainsImages(item, provider.GetSupportedImages(item).ToList(), savedOptions, backdropLimit, screenshotLimit)) { return; } _logger.Debug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name); var images = await _providerManager.GetAvailableRemoteImages(item, new RemoteImageQuery { ProviderName = provider.Name, IncludeAllLanguages = false, IncludeDisabledProviders = false, }, cancellationToken).ConfigureAwait(false); var list = images.ToList(); int minWidth; foreach (var type in _singularImages) { if (savedOptions.IsEnabled(type) && !item.HasImage(type)) { minWidth = savedOptions.GetMinWidth(type); await DownloadImage(item, provider, result, list, minWidth, type, cancellationToken).ConfigureAwait(false); } } minWidth = savedOptions.GetMinWidth(ImageType.Backdrop); await DownloadBackdrops(item, ImageType.Backdrop, backdropLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false); var hasScreenshots = item as IHasScreenshots; if (hasScreenshots != null) { minWidth = savedOptions.GetMinWidth(ImageType.Screenshot); await DownloadBackdrops(item, ImageType.Screenshot, screenshotLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false); } } catch (OperationCanceledException) { throw; } catch (Exception ex) { result.ErrorMessage = ex.Message; result.Status = ProviderRefreshStatus.CompletedWithErrors; _logger.ErrorException("Error in {0}", ex, provider.Name); } }
private async Task <bool> DownloadImage(IHasImages item, IRemoteImageProvider provider, RefreshResult result, IEnumerable <RemoteImageInfo> images, int minWidth, ImageType type, CancellationToken cancellationToken) { var eligibleImages = images .Where(i => i.Type == type && !(i.Width.HasValue && i.Width.Value < minWidth)) .ToList(); if (EnableImageStub(item, type) && eligibleImages.Count > 0) { SaveImageStub(item, type, eligibleImages.Select(i => i.Url)); result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; return(true); } foreach (var image in eligibleImages) { var url = image.Url; try { var response = await provider.GetImageResponse(url, cancellationToken).ConfigureAwait(false); await _providerManager.SaveImage(item, response.Content, response.ContentType, type, null, cancellationToken).ConfigureAwait(false); result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; return(true); } catch (HttpException ex) { // Sometimes providers send back bad url's. Just move to the next image if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) { continue; } break; } } return(false); }
/// <summary> /// Gets the images. /// </summary> /// <param name="item">The item.</param> /// <param name="provider">The provider.</param> /// <param name="preferredLanguage">The preferred language.</param> /// <param name="includeAllLanguages">Whether to include all languages in results.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="type">The type.</param> /// <returns>Task{IEnumerable{RemoteImageInfo}}.</returns> private async Task <IEnumerable <RemoteImageInfo> > GetImages( BaseItem item, IRemoteImageProvider provider, string preferredLanguage, bool includeAllLanguages, CancellationToken cancellationToken, ImageType?type = null) { bool hasPreferredLanguage = !string.IsNullOrWhiteSpace(preferredLanguage); try { var result = await provider.GetImages(item, cancellationToken).ConfigureAwait(false); if (type.HasValue) { result = result.Where(i => i.Type == type.Value); } if (!includeAllLanguages && hasPreferredLanguage) { // Filter out languages that do not match the preferred languages. // // TODO: should exception case of "en" (English) eventually be removed? result = result.Where(i => string.IsNullOrWhiteSpace(i.Language) || string.Equals(preferredLanguage, i.Language, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Language, "en", StringComparison.OrdinalIgnoreCase)); } return(result.OrderByLanguageDescending(preferredLanguage)); } catch (OperationCanceledException) { return(new List <RemoteImageInfo>()); } catch (Exception ex) { _logger.LogError(ex, "{ProviderName} failed in GetImageInfos for type {ItemType} at {ItemPath}", provider.GetType().Name, item.GetType().Name, item.Path); return(new List <RemoteImageInfo>()); } }
/// <summary> /// Gets the images. /// </summary> /// <param name="item">The item.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="provider">The provider.</param> /// <param name="preferredLanguage">The preferred language.</param> /// <param name="type">The type.</param> /// <returns>Task{IEnumerable{RemoteImageInfo}}.</returns> private async Task <IEnumerable <RemoteImageInfo> > GetImages(IHasImages item, CancellationToken cancellationToken, IRemoteImageProvider provider, string preferredLanguage, ImageType?type = null) { try { var result = await provider.GetImages(item, cancellationToken).ConfigureAwait(false); if (type.HasValue) { result = result.Where(i => i.Type == type.Value); } if (string.Equals(preferredLanguage, "en", StringComparison.OrdinalIgnoreCase)) { result = result.Where(i => string.IsNullOrEmpty(i.Language) || string.Equals(i.Language, "en", StringComparison.OrdinalIgnoreCase)); } return(result); } catch (OperationCanceledException) { return(new List <RemoteImageInfo>()); } catch (Exception ex) { _logger.ErrorException("{0} failed in GetImageInfos for type {1}", ex, provider.GetType().Name, item.GetType().Name); return(new List <RemoteImageInfo>()); } }
private async Task DownloadBackdrops(BaseItem item, LibraryOptions libraryOptions, ImageType imageType, int limit, IRemoteImageProvider provider, RefreshResult result, IEnumerable<RemoteImageInfo> images, int minWidth, CancellationToken cancellationToken) { foreach (var image in images.Where(i => i.Type == imageType)) { if (item.GetImages(imageType).Count() >= limit) { break; } if (image.Width.HasValue && image.Width.Value < minWidth) { continue; } var url = image.Url; if (EnableImageStub(item, imageType, libraryOptions)) { SaveImageStub(item, imageType, new[] { url }); result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; continue; } try { var response = await provider.GetImageResponse(url, cancellationToken).ConfigureAwait(false); // If there's already an image of the same size, skip it if (response.ContentLength.HasValue) { try { if (item.GetImages(imageType).Any(i => _fileSystem.GetFileInfo(i.Path).Length == response.ContentLength.Value)) { response.Content.Dispose(); continue; } } catch (IOException ex) { _logger.ErrorException("Error examining images", ex); } } await _providerManager.SaveImage(item, response.Content, response.ContentType, imageType, null, cancellationToken).ConfigureAwait(false); result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; } catch (HttpException ex) { // Sometimes providers send back bad url's. Just move onto the next image if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) { continue; } break; } } }
/// <summary> /// Refreshes from provider. /// </summary> /// <param name="item">The item.</param> /// <param name="provider">The provider.</param> /// <param name="refreshOptions">The refresh options.</param> /// <param name="savedOptions">The saved options.</param> /// <param name="backdropLimit">The backdrop limit.</param> /// <param name="screenshotLimit">The screenshot limit.</param> /// <param name="downloadedImages">The downloaded images.</param> /// <param name="result">The result.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> private async Task RefreshFromProvider(BaseItem item, LibraryOptions libraryOptions, IRemoteImageProvider provider, ImageRefreshOptions refreshOptions, MetadataOptions savedOptions, int backdropLimit, int screenshotLimit, ICollection<ImageType> downloadedImages, RefreshResult result, CancellationToken cancellationToken) { try { if (!item.SupportsRemoteImageDownloading) { return; } if (!refreshOptions.ReplaceAllImages && refreshOptions.ReplaceImages.Count == 0 && ContainsImages(item, provider.GetSupportedImages(item).ToList(), savedOptions, backdropLimit, screenshotLimit)) { return; } _logger.Debug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name); var images = await _providerManager.GetAvailableRemoteImages(item, new RemoteImageQuery { ProviderName = provider.Name, IncludeAllLanguages = false, IncludeDisabledProviders = false, }, cancellationToken).ConfigureAwait(false); var list = images.ToList(); int minWidth; foreach (var imageType in _singularImages) { if (!IsEnabled(savedOptions, imageType, item)) continue; if (!HasImage(item, imageType) || (refreshOptions.IsReplacingImage(imageType) && !downloadedImages.Contains(imageType))) { minWidth = savedOptions.GetMinWidth(imageType); var downloaded = await DownloadImage(item, libraryOptions, provider, result, list, minWidth, imageType, cancellationToken).ConfigureAwait(false); if (downloaded) { downloadedImages.Add(imageType); } } } minWidth = savedOptions.GetMinWidth(ImageType.Backdrop); await DownloadBackdrops(item, libraryOptions, ImageType.Backdrop, backdropLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false); var hasScreenshots = item as IHasScreenshots; if (hasScreenshots != null) { minWidth = savedOptions.GetMinWidth(ImageType.Screenshot); await DownloadBackdrops(item, libraryOptions, ImageType.Screenshot, screenshotLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false); } } catch (OperationCanceledException) { throw; } catch (Exception ex) { result.ErrorMessage = ex.Message; _logger.ErrorException("Error in {0}", ex, provider.Name); } }
private async Task DownloadBackdrops(IHasImages item, ImageType imageType, int limit, IRemoteImageProvider provider, RefreshResult result, IEnumerable<RemoteImageInfo> images, int minWidth, CancellationToken cancellationToken) { foreach (var image in images.Where(i => i.Type == imageType)) { if (item.GetImages(imageType).Count() >= limit) { break; } if (image.Width.HasValue && image.Width.Value < minWidth) { continue; } var url = image.Url; try { var response = await provider.GetImageResponse(url, cancellationToken).ConfigureAwait(false); // If there's already an image of the same size, skip it if (response.ContentLength.HasValue) { try { if (item.GetImages(imageType).Any(i => new FileInfo(i.Path).Length == response.ContentLength.Value)) { response.Content.Dispose(); continue; } } catch (IOException ex) { _logger.ErrorException("Error examining images", ex); } } await _providerManager.SaveImage(item, response.Content, response.ContentType, imageType, null, cancellationToken).ConfigureAwait(false); result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; } catch (HttpException ex) { // Sometimes providers send back bad url's. Just move onto the next image if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) { continue; } break; } } }
private async Task<bool> DownloadImage(IHasImages item, IRemoteImageProvider provider, RefreshResult result, IEnumerable<RemoteImageInfo> images, int minWidth, ImageType type, CancellationToken cancellationToken) { foreach (var image in images.Where(i => i.Type == type)) { if (image.Width.HasValue && image.Width.Value < minWidth) { continue; } var url = image.Url; try { var response = await provider.GetImageResponse(url, cancellationToken).ConfigureAwait(false); await _providerManager.SaveImage(item, response.Content, response.ContentType, type, null, cancellationToken).ConfigureAwait(false); result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; return true; } catch (HttpException ex) { // Sometimes providers send back bad url's. Just move to the next image if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) { continue; } break; } } return false; }
/// <summary> /// Refreshes from provider. /// </summary> /// <param name="item">The item.</param> /// <param name="provider">The provider.</param> /// <param name="refreshOptions">The refresh options.</param> /// <param name="savedOptions">The saved options.</param> /// <param name="backdropLimit">The backdrop limit.</param> /// <param name="screenshotLimit">The screenshot limit.</param> /// <param name="downloadedImages">The downloaded images.</param> /// <param name="result">The result.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> private async Task RefreshFromProvider(IHasImages item, IRemoteImageProvider provider, ImageRefreshOptions refreshOptions, MetadataOptions savedOptions, int backdropLimit, int screenshotLimit, ICollection<ImageType> downloadedImages, RefreshResult result, CancellationToken cancellationToken) { try { if (!item.SupportsRemoteImageDownloading) { return; } if (!refreshOptions.ReplaceAllImages && refreshOptions.ReplaceImages.Count == 0 && ContainsImages(item, provider.GetSupportedImages(item).ToList(), savedOptions, backdropLimit, screenshotLimit)) { return; } _logger.Debug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name); var images = await _providerManager.GetAvailableRemoteImages(item, new RemoteImageQuery { ProviderName = provider.Name, IncludeAllLanguages = false, IncludeDisabledProviders = false, }, cancellationToken).ConfigureAwait(false); var list = images.ToList(); int minWidth; foreach (var imageType in _singularImages) { if (!IsEnabled(savedOptions, imageType, item)) continue; if (!item.HasImage(imageType) || (refreshOptions.IsReplacingImage(imageType) && !downloadedImages.Contains(imageType))) { minWidth = savedOptions.GetMinWidth(imageType); var downloaded = await DownloadImage(item, provider, result, list, minWidth, imageType, cancellationToken).ConfigureAwait(false); if (downloaded) { downloadedImages.Add(imageType); } } } if (!item.LockedFields.Contains(MetadataFields.Backdrops)) { minWidth = savedOptions.GetMinWidth(ImageType.Backdrop); await DownloadBackdrops(item, ImageType.Backdrop, backdropLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false); } if (!item.LockedFields.Contains(MetadataFields.Screenshots)) { var hasScreenshots = item as IHasScreenshots; if (hasScreenshots != null) { minWidth = savedOptions.GetMinWidth(ImageType.Screenshot); await DownloadBackdrops(item, ImageType.Screenshot, screenshotLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false); } } } catch (OperationCanceledException) { throw; } catch (Exception ex) { result.ErrorMessage = ex.Message; result.Status = ProviderRefreshStatus.CompletedWithErrors; _logger.ErrorException("Error in {0}", ex, provider.Name); } }
private async Task DownloadMultiImages(BaseItem item, ImageType imageType, ImageRefreshOptions refreshOptions, int limit, IRemoteImageProvider provider, RefreshResult result, IEnumerable <RemoteImageInfo> images, int minWidth, CancellationToken cancellationToken) { foreach (var image in images.Where(i => i.Type == imageType)) { if (item.GetImages(imageType).Count() >= limit) { break; } if (image.Width.HasValue && image.Width.Value < minWidth) { continue; } var url = image.Url; if (EnableImageStub(item)) { SaveImageStub(item, imageType, new[] { url }); result.UpdateType |= ItemUpdateType.ImageUpdate; continue; } try { using var response = await provider.GetImageResponse(url, cancellationToken).ConfigureAwait(false); // Sometimes providers send back bad urls. Just move to the next image if (response.StatusCode == HttpStatusCode.NotFound || response.StatusCode == HttpStatusCode.Forbidden) { _logger.LogDebug("{Url} returned {StatusCode}, ignoring", url, response.StatusCode); continue; } if (!response.IsSuccessStatusCode) { _logger.LogWarning("{Url} returned {StatusCode}, skipping all remaining requests", url, response.StatusCode); break; } // If there's already an image of the same file size, skip it unless doing a full refresh if (response.Content.Headers.ContentLength.HasValue && !refreshOptions.IsReplacingImage(imageType)) { try { if (item.GetImages(imageType).Any(i => _fileSystem.GetFileInfo(i.Path).Length == response.Content.Headers.ContentLength.Value)) { response.Content.Dispose(); continue; } } catch (IOException ex) { _logger.LogError(ex, "Error examining images"); } } await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); await _providerManager.SaveImage( item, stream, response.Content.Headers.ContentType?.MediaType, imageType, null, cancellationToken).ConfigureAwait(false); result.UpdateType |= ItemUpdateType.ImageUpdate; } catch (HttpRequestException) { break; } } }
private async Task <bool> DownloadImage( BaseItem item, IRemoteImageProvider provider, RefreshResult result, IEnumerable <RemoteImageInfo> images, int minWidth, ImageType type, CancellationToken cancellationToken) { var eligibleImages = images .Where(i => i.Type == type && (i.Width == null || i.Width >= minWidth)) .ToList(); if (EnableImageStub(item) && eligibleImages.Count > 0) { SaveImageStub(item, type, eligibleImages.Select(i => i.Url)); result.UpdateType |= ItemUpdateType.ImageUpdate; return(true); } foreach (var image in eligibleImages) { var url = image.Url; try { using var response = await provider.GetImageResponse(url, cancellationToken).ConfigureAwait(false); // Sometimes providers send back bad urls. Just move to the next image if (response.StatusCode == HttpStatusCode.NotFound || response.StatusCode == HttpStatusCode.Forbidden) { _logger.LogDebug("{Url} returned {StatusCode}, ignoring", url, response.StatusCode); continue; } if (!response.IsSuccessStatusCode) { _logger.LogWarning("{Url} returned {StatusCode}, skipping all remaining requests", url, response.StatusCode); break; } await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); await _providerManager.SaveImage( item, stream, response.Content.Headers.ContentType?.MediaType, type, null, cancellationToken).ConfigureAwait(false); result.UpdateType |= ItemUpdateType.ImageUpdate; return(true); } catch (HttpRequestException) { break; } } return(false); }
private async Task RefreshFromProvider( BaseItem item, IRemoteImageProvider provider, ImageRefreshOptions refreshOptions, TypeOptions savedOptions, int backdropLimit, ICollection <ImageType> downloadedImages, RefreshResult result, CancellationToken cancellationToken) { try { if (!item.SupportsRemoteImageDownloading) { return; } if (!refreshOptions.ReplaceAllImages && refreshOptions.ReplaceImages.Length == 0 && ContainsImages(item, provider.GetSupportedImages(item).ToList(), savedOptions, backdropLimit)) { return; } _logger.LogDebug("Running {Provider} for {Item}", provider.GetType().Name, item.Path ?? item.Name); var images = await _providerManager.GetAvailableRemoteImages( item, new RemoteImageQuery(provider.Name) { IncludeAllLanguages = true, IncludeDisabledProviders = false, }, cancellationToken).ConfigureAwait(false); var list = images.ToList(); int minWidth; foreach (var imageType in _singularImages) { if (!savedOptions.IsEnabled(imageType)) { continue; } if (!item.HasImage(imageType) || (refreshOptions.IsReplacingImage(imageType) && !downloadedImages.Contains(imageType))) { minWidth = savedOptions.GetMinWidth(imageType); var downloaded = await DownloadImage(item, provider, result, list, minWidth, imageType, cancellationToken).ConfigureAwait(false); if (downloaded) { downloadedImages.Add(imageType); } } } minWidth = savedOptions.GetMinWidth(ImageType.Backdrop); await DownloadMultiImages(item, ImageType.Backdrop, refreshOptions, backdropLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { throw; } catch (Exception ex) { result.ErrorMessage = ex.Message; _logger.LogError(ex, "Error in {Provider}", provider.Name); } }