/// <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(IHasMetadata 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); } } } if (!item.LockedFields.Contains(MetadataFields.Backdrops)) { minWidth = savedOptions.GetMinWidth(ImageType.Backdrop); await DownloadBackdrops(item, libraryOptions, 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, 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(IHasMetadata 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; } } }
protected virtual async Task <RefreshResult> RefreshWithProviders( MetadataResult <TItemType> metadata, TIdType id, MetadataRefreshOptions options, ICollection <IMetadataProvider> providers, ItemImageProvider imageService, CancellationToken cancellationToken) { var refreshResult = new RefreshResult { UpdateType = ItemUpdateType.None }; var item = metadata.Item; var customProviders = providers.OfType <ICustomMetadataProvider <TItemType> >().ToList(); var logName = !item.IsFileProtocol ? item.Name ?? item.Path : item.Path ?? item.Name; foreach (var provider in customProviders.Where(i => i is IPreRefreshProvider)) { await RunCustomProvider(provider, item, logName, options, refreshResult, cancellationToken).ConfigureAwait(false); } var temp = new MetadataResult <TItemType> { Item = CreateNew() }; temp.Item.Path = item.Path; var userDataList = new List <UserItemData>(); // If replacing all metadata, run internet providers first if (options.ReplaceAllMetadata) { var remoteResult = await ExecuteRemoteProviders(temp, logName, id, providers.OfType <IRemoteMetadataProvider <TItemType, TIdType> >(), cancellationToken) .ConfigureAwait(false); refreshResult.UpdateType |= remoteResult.UpdateType; refreshResult.ErrorMessage = remoteResult.ErrorMessage; refreshResult.Failures += remoteResult.Failures; } var hasLocalMetadata = false; foreach (var provider in providers.OfType <ILocalMetadataProvider <TItemType> >().ToList()) { var providerName = provider.GetType().Name; Logger.LogDebug("Running {Provider} for {Item}", providerName, logName); var itemInfo = new ItemInfo(item); try { var localItem = await provider.GetMetadata(itemInfo, options.DirectoryService, cancellationToken).ConfigureAwait(false); if (localItem.HasMetadata) { foreach (var remoteImage in localItem.RemoteImages) { try { await ProviderManager.SaveImage(item, remoteImage.Url, remoteImage.Type, null, cancellationToken).ConfigureAwait(false); refreshResult.UpdateType |= ItemUpdateType.ImageUpdate; } catch (HttpRequestException ex) { Logger.LogError(ex, "Could not save {ImageType} image: {Url}", Enum.GetName(remoteImage.Type), remoteImage.Url); } } if (imageService.MergeImages(item, localItem.Images)) { refreshResult.UpdateType |= ItemUpdateType.ImageUpdate; } if (localItem.UserDataList != null) { userDataList.AddRange(localItem.UserDataList); } MergeData(localItem, temp, Array.Empty <MetadataField>(), !options.ReplaceAllMetadata, true); refreshResult.UpdateType |= ItemUpdateType.MetadataImport; // Only one local provider allowed per item if (item.IsLocked || localItem.Item.IsLocked || IsFullLocalMetadata(localItem.Item)) { hasLocalMetadata = true; } break; } Logger.LogDebug("{Provider} returned no metadata for {Item}", providerName, logName); } catch (OperationCanceledException) { throw; } catch (Exception ex) { Logger.LogError(ex, "Error in {Provider}", provider.Name); // If a local provider fails, consider that a failure refreshResult.ErrorMessage = ex.Message; } } // Local metadata is king - if any is found don't run remote providers if (!options.ReplaceAllMetadata && (!hasLocalMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || !item.StopRefreshIfLocalMetadataFound)) { var remoteResult = await ExecuteRemoteProviders(temp, logName, id, providers.OfType <IRemoteMetadataProvider <TItemType, TIdType> >(), cancellationToken) .ConfigureAwait(false); refreshResult.UpdateType |= remoteResult.UpdateType; refreshResult.ErrorMessage = remoteResult.ErrorMessage; refreshResult.Failures += remoteResult.Failures; } if (providers.Any(i => i is not ICustomMetadataProvider)) { if (refreshResult.UpdateType > ItemUpdateType.None) { if (hasLocalMetadata) { MergeData(temp, metadata, item.LockedFields, true, true); } else { if (!options.RemoveOldMetadata) { MergeData(metadata, temp, Array.Empty <MetadataField>(), false, false); } MergeData(temp, metadata, item.LockedFields, true, false); } } } // var isUnidentified = failedProviderCount > 0 && successfulProviderCount == 0; foreach (var provider in customProviders.Where(i => i is not IPreRefreshProvider)) { await RunCustomProvider(provider, item, logName, options, refreshResult, cancellationToken).ConfigureAwait(false); } // ImportUserData(item, userDataList, cancellationToken); return(refreshResult); }
/// <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="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(IHasMetadata item, IDynamicImageProvider provider, ImageRefreshOptions refreshOptions, MetadataOptions savedOptions, ICollection <ImageType> downloadedImages, RefreshResult result, CancellationToken cancellationToken) { try { var images = provider.GetSupportedImages(item); foreach (var imageType in images) { if (!IsEnabled(savedOptions, imageType, item)) { continue; } if (!HasImage(item, imageType) || (refreshOptions.IsReplacingImage(imageType) && !downloadedImages.Contains(imageType))) { _logger.Debug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name); var response = await provider.GetImage(item, imageType, cancellationToken).ConfigureAwait(false); if (response.HasImage) { if (!string.IsNullOrEmpty(response.Path)) { if (response.Protocol == MediaProtocol.Http) { _logger.Debug("Setting image url into item {0}", item.Id); item.SetImage(new ItemImageInfo { Path = response.Path, Type = imageType }, 0); } else { var mimeType = MimeTypes.GetMimeType(response.Path); var stream = _fileSystem.GetFileStream(response.Path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read, true); await _providerManager.SaveImage(item, stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false); } } else { var mimeType = "image/" + response.Format.ToString().ToLower(); await _providerManager.SaveImage(item, response.Stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false); } downloadedImages.Add(imageType); result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; } } } } catch (OperationCanceledException) { throw; } catch (Exception ex) { result.ErrorMessage = ex.Message; _logger.ErrorException("Error in {0}", ex, provider.Name); } }
private async Task ExecuteRemoteProviders(TItemType item, TItemType temp, IEnumerable <IRemoteMetadataProvider <TItemType, TIdType> > providers, RefreshResult refreshResult, CancellationToken cancellationToken) { TIdType id = null; var unidentifiedCount = 0; var identifiedCount = 0; foreach (var provider in providers) { var providerName = provider.GetType().Name; Logger.Debug("Running {0} for {1}", providerName, item.Path ?? item.Name); if (id == null) { id = item.GetLookupInfo(); } else { MergeNewData(temp, id); } try { var result = await provider.GetMetadata(id, cancellationToken).ConfigureAwait(false); if (result.HasMetadata) { MergeData(result.Item, temp, new List <MetadataFields>(), false, false); refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataDownload; identifiedCount++; } else { unidentifiedCount++; Logger.Debug("{0} returned no metadata for {1}", providerName, item.Path ?? item.Name); } } catch (OperationCanceledException) { throw; } catch (Exception ex) { unidentifiedCount++; refreshResult.Status = ProviderRefreshStatus.CompletedWithErrors; refreshResult.ErrorMessage = ex.Message; Logger.ErrorException("Error in {0}", ex, provider.Name); } } var isUnidentified = unidentifiedCount > 0 && identifiedCount == 0; if (item.IsUnidentified != isUnidentified) { item.IsUnidentified = isUnidentified; refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport; } }
protected virtual async Task <RefreshResult> RefreshWithProviders(TItemType item, TIdType id, MetadataRefreshOptions options, List <IMetadataProvider> providers, ItemImageProvider imageService, CancellationToken cancellationToken) { var refreshResult = new RefreshResult { UpdateType = ItemUpdateType.None, Providers = providers.Select(i => i.GetType().FullName.GetMD5()).ToList() }; var customProviders = providers.OfType <ICustomMetadataProvider <TItemType> >().ToList(); foreach (var provider in customProviders.Where(i => i is IPreRefreshProvider)) { await RunCustomProvider(provider, item, options, refreshResult, cancellationToken).ConfigureAwait(false); } var temp = CreateNew(); temp.Path = item.Path; var successfulProviderCount = 0; var failedProviderCount = 0; // If replacing all metadata, run internet providers first if (options.ReplaceAllMetadata) { var remoteResult = await ExecuteRemoteProviders(item, temp, id, providers.OfType <IRemoteMetadataProvider <TItemType, TIdType> >(), cancellationToken) .ConfigureAwait(false); refreshResult.UpdateType = refreshResult.UpdateType | remoteResult.UpdateType; refreshResult.Status = remoteResult.Status; refreshResult.ErrorMessage = remoteResult.ErrorMessage; successfulProviderCount += remoteResult.Successes; failedProviderCount += remoteResult.Failures; } var hasLocalMetadata = false; foreach (var provider in providers.OfType <ILocalMetadataProvider <TItemType> >()) { var providerName = provider.GetType().Name; Logger.Debug("Running {0} for {1}", providerName, item.Path ?? item.Name); var itemInfo = new ItemInfo { Path = item.Path, IsInMixedFolder = item.IsInMixedFolder }; try { var localItem = await provider.GetMetadata(itemInfo, cancellationToken).ConfigureAwait(false); if (localItem.HasMetadata) { if (imageService.MergeImages(item, localItem.Images)) { refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.ImageUpdate; } MergeData(localItem.Item, temp, new List <MetadataFields>(), !options.ReplaceAllMetadata, true); refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport; // Only one local provider allowed per item hasLocalMetadata = true; successfulProviderCount++; break; } Logger.Debug("{0} returned no metadata for {1}", providerName, item.Path ?? item.Name); } catch (OperationCanceledException) { throw; } catch (Exception ex) { failedProviderCount++; Logger.ErrorException("Error in {0}", ex, provider.Name); // If a local provider fails, consider that a failure refreshResult.Status = ProviderRefreshStatus.Failure; refreshResult.ErrorMessage = ex.Message; if (options.MetadataRefreshMode != MetadataRefreshMode.FullRefresh) { // If the local provider fails don't continue with remote providers because the user's saved metadata could be lost return(refreshResult); } } } // Local metadata is king - if any is found don't run remote providers if (!options.ReplaceAllMetadata && (!hasLocalMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh)) { var remoteResult = await ExecuteRemoteProviders(item, temp, id, providers.OfType <IRemoteMetadataProvider <TItemType, TIdType> >(), cancellationToken) .ConfigureAwait(false); refreshResult.UpdateType = refreshResult.UpdateType | remoteResult.UpdateType; if (remoteResult.Status != ProviderRefreshStatus.Success) { refreshResult.Status = remoteResult.Status; refreshResult.ErrorMessage = remoteResult.ErrorMessage; } successfulProviderCount += remoteResult.Successes; } if (refreshResult.UpdateType > ItemUpdateType.None) { MergeData(temp, item, item.LockedFields, true, true); } var isUnidentified = failedProviderCount > 0 && successfulProviderCount == 0; if (item.IsUnidentified != isUnidentified) { item.IsUnidentified = isUnidentified; refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport; } foreach (var provider in customProviders.Where(i => !(i is IPreRefreshProvider))) { await RunCustomProvider(provider, item, options, refreshResult, cancellationToken).ConfigureAwait(false); } return(refreshResult); }
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; } } }
/// <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 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); } }
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, IDynamicImageProvider provider, ImageRefreshOptions refreshOptions, TypeOptions savedOptions, ICollection <ImageType> downloadedImages, RefreshResult result, CancellationToken cancellationToken) { try { var images = provider.GetSupportedImages(item); foreach (var imageType in images) { if (!savedOptions.IsEnabled(imageType)) { continue; } if (!item.HasImage(imageType) || (refreshOptions.IsReplacingImage(imageType) && !downloadedImages.Contains(imageType))) { _logger.LogDebug("Running {Provider} for {Item}", provider.GetType().Name, item.Path ?? item.Name); var response = await provider.GetImage(item, imageType, cancellationToken).ConfigureAwait(false); if (response.HasImage) { if (string.IsNullOrEmpty(response.Path)) { var mimeType = response.Format.GetMimeType(); await _providerManager.SaveImage(item, response.Stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false); } else { if (response.Protocol == MediaProtocol.Http) { _logger.LogDebug("Setting image url into item {Item}", item.Id); var index = item.AllowsMultipleImages(imageType) ? item.GetImages(imageType).Count() : 0; item.SetImage( new ItemImageInfo { Path = response.Path, Type = imageType }, index); } else { var mimeType = MimeTypes.GetMimeType(response.Path); var stream = AsyncFile.OpenRead(response.Path); await _providerManager.SaveImage(item, stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false); } } downloadedImages.Add(imageType); result.UpdateType |= ItemUpdateType.ImageUpdate; } } } } catch (OperationCanceledException) { throw; } catch (Exception ex) { result.ErrorMessage = ex.Message; _logger.LogError(ex, "Error in {Provider}", provider.Name); } }
private async Task <RefreshResult> ExecuteRemoteProviders(MetadataResult <TItemType> temp, string logName, TIdType id, IEnumerable <IRemoteMetadataProvider <TItemType, TIdType> > providers, CancellationToken cancellationToken) { var refreshResult = new RefreshResult(); var results = new List <MetadataResult <TItemType> >(); foreach (var provider in providers) { var providerName = provider.GetType().Name; Logger.Debug("Running {0} for {1}", providerName, logName); if (id != null) { MergeNewData(temp.Item, id); } try { var result = await provider.GetMetadata(id, cancellationToken).ConfigureAwait(false); if (result.HasMetadata) { results.Add(result); refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataDownload; } else { Logger.Debug("{0} returned no metadata for {1}", providerName, logName); } } catch (OperationCanceledException) { throw; } catch (Exception ex) { refreshResult.Failures++; refreshResult.ErrorMessage = ex.Message; Logger.ErrorException("Error in {0}", ex, provider.Name); } } var orderedResults = new List <MetadataResult <TItemType> >(); var preferredLanguage = NormalizeLanguage(id.MetadataLanguage); // prioritize results with matching ResultLanguage foreach (var result in results) { if (!result.QueriedById) { break; } if (string.Equals(NormalizeLanguage(result.ResultLanguage), preferredLanguage, StringComparison.OrdinalIgnoreCase) && result.QueriedById) { orderedResults.Add(result); } } // add all other results foreach (var result in results) { if (!orderedResults.Contains(result)) { orderedResults.Add(result); } } foreach (var result in results) { MergeData(result, temp, new List <MetadataFields>(), false, false); } return(refreshResult); }
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; } } }
protected virtual async Task <RefreshResult> RefreshWithProviders(MetadataResult <TItemType> metadata, TIdType id, MetadataRefreshOptions options, List <IMetadataProvider> providers, ItemImageProvider imageService, CancellationToken cancellationToken) { var refreshResult = new RefreshResult { UpdateType = ItemUpdateType.None, Providers = providers.Select(i => i.GetType().FullName.GetMD5()).ToList() }; var item = metadata.Item; var customProviders = providers.OfType <ICustomMetadataProvider <TItemType> >().ToList(); var logName = item.LocationType == LocationType.Remote ? item.Name ?? item.Path : item.Path ?? item.Name; foreach (var provider in customProviders.Where(i => i is IPreRefreshProvider)) { await RunCustomProvider(provider, item, logName, options, refreshResult, cancellationToken).ConfigureAwait(false); } var temp = new MetadataResult <TItemType> { Item = CreateNew() }; temp.Item.Path = item.Path; var userDataList = new List <UserItemData>(); // If replacing all metadata, run internet providers first if (options.ReplaceAllMetadata) { var remoteResult = await ExecuteRemoteProviders(temp, logName, id, providers.OfType <IRemoteMetadataProvider <TItemType, TIdType> >(), cancellationToken) .ConfigureAwait(false); refreshResult.UpdateType = refreshResult.UpdateType | remoteResult.UpdateType; refreshResult.ErrorMessage = remoteResult.ErrorMessage; refreshResult.Failures += remoteResult.Failures; } var hasLocalMetadata = false; foreach (var provider in providers.OfType <ILocalMetadataProvider <TItemType> >().ToList()) { var providerName = provider.GetType().Name; Logger.Debug("Running {0} for {1}", providerName, logName); var itemInfo = new ItemInfo(item); try { var localItem = await provider.GetMetadata(itemInfo, options.DirectoryService, cancellationToken).ConfigureAwait(false); if (localItem.HasMetadata) { if (imageService.MergeImages(item, localItem.Images)) { refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.ImageUpdate; } if (localItem.UserDataList != null) { userDataList.AddRange(localItem.UserDataList); } MergeData(localItem, temp, new List <MetadataFields>(), !options.ReplaceAllMetadata, true); refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport; // Only one local provider allowed per item if (IsFullLocalMetadata(localItem.Item)) { hasLocalMetadata = true; } break; } Logger.Debug("{0} returned no metadata for {1}", providerName, logName); } catch (OperationCanceledException) { throw; } catch (Exception ex) { refreshResult.Failures++; Logger.ErrorException("Error in {0}", ex, provider.Name); // If a local provider fails, consider that a failure refreshResult.ErrorMessage = ex.Message; if (options.MetadataRefreshMode != MetadataRefreshMode.FullRefresh) { // If the local provider fails don't continue with remote providers because the user's saved metadata could be lost return(refreshResult); } } } // Local metadata is king - if any is found don't run remote providers if (!options.ReplaceAllMetadata && (!hasLocalMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh)) { var remoteResult = await ExecuteRemoteProviders(temp, logName, id, providers.OfType <IRemoteMetadataProvider <TItemType, TIdType> >(), cancellationToken) .ConfigureAwait(false); refreshResult.UpdateType = refreshResult.UpdateType | remoteResult.UpdateType; refreshResult.ErrorMessage = remoteResult.ErrorMessage; refreshResult.Failures += remoteResult.Failures; } if (providers.Any(i => !(i is ICustomMetadataProvider))) { if (refreshResult.UpdateType > ItemUpdateType.None) { // If no local metadata, take data from item itself if (!hasLocalMetadata) { // TODO: If the new metadata from above has some blank data, this can cause old data to get filled into those empty fields MergeData(metadata, temp, new List <MetadataFields>(), false, true); } MergeData(temp, metadata, item.LockedFields, true, true); } } //var isUnidentified = failedProviderCount > 0 && successfulProviderCount == 0; foreach (var provider in customProviders.Where(i => !(i is IPreRefreshProvider))) { await RunCustomProvider(provider, item, logName, options, refreshResult, cancellationToken).ConfigureAwait(false); } await ImportUserData(item, userDataList, cancellationToken).ConfigureAwait(false); return(refreshResult); }
private async Task RunCustomProvider(ICustomMetadataProvider <TItemType> provider, TItemType item, IDirectoryService directoryService, RefreshResult refreshResult, CancellationToken cancellationToken) { Logger.Debug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name); try { refreshResult.UpdateType = refreshResult.UpdateType | await provider.FetchAsync(item, directoryService, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { throw; } catch (Exception ex) { refreshResult.Status = ProviderRefreshStatus.CompletedWithErrors; refreshResult.ErrorMessage = ex.Message; Logger.ErrorException("Error in {0}", ex, provider.Name); } }
private async Task RunCustomProvider(ICustomMetadataProvider <TItemType> provider, TItemType item, string logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) { Logger.Debug("Running {0} for {1}", provider.GetType().Name, logName); try { refreshResult.UpdateType = refreshResult.UpdateType | await provider.FetchAsync(item, options, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { throw; } catch (Exception ex) { refreshResult.ErrorMessage = ex.Message; Logger.ErrorException("Error in {0}", ex, provider.Name); } }
/// <summary> /// Refreshes from provider. /// </summary> /// <param name="item">The item.</param> /// <param name="provider">The provider.</param> /// <param name="savedOptions">The saved options.</param> /// <param name="result">The result.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> private async Task RefreshFromProvider(IHasImages item, IDynamicImageProvider provider, MetadataOptions savedOptions, RefreshResult result, CancellationToken cancellationToken) { try { var images = provider.GetSupportedImages(item); foreach (var imageType in images) { if (!item.HasImage(imageType) && savedOptions.IsEnabled(imageType)) { _logger.Debug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name); var response = await provider.GetImage(item, imageType, cancellationToken).ConfigureAwait(false); if (response.HasImage) { if (!string.IsNullOrEmpty(response.Path)) { var mimeType = "image/" + Path.GetExtension(response.Path).TrimStart('.').ToLower(); var stream = _fileSystem.GetFileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, true); await _providerManager.SaveImage(item, stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false); } else { var mimeType = "image/" + response.Format.ToString().ToLower(); await _providerManager.SaveImage(item, response.Stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false); } result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; } } } } catch (OperationCanceledException) { throw; } catch (Exception ex) { result.ErrorMessage = ex.Message; result.Status = ProviderRefreshStatus.CompletedWithErrors; _logger.ErrorException("Error in {0}", ex, provider.Name); } }