diff options
| author | ferferga <ferferga.fer@gmail.com> | 2020-10-19 17:28:07 +0200 |
|---|---|---|
| committer | ferferga <ferferga.fer@gmail.com> | 2020-10-19 17:28:07 +0200 |
| commit | 9fd01fade6ac971ba72a2e7dd54e2295f23839bc (patch) | |
| tree | 20a5ff4a1621e765fc93c0e53b149edb61ff3654 /MediaBrowser.Providers/Manager | |
| parent | ba03ed65fe64b724b3e8b5b94b9cbe1075c61da2 (diff) | |
| parent | 49ac4c4044b1777dc3a25544aead7b0b15b953e8 (diff) | |
Remove "download images in advance" option
Diffstat (limited to 'MediaBrowser.Providers/Manager')
| -rw-r--r-- | MediaBrowser.Providers/Manager/ImageSaver.cs | 100 | ||||
| -rw-r--r-- | MediaBrowser.Providers/Manager/ItemImageProvider.cs | 181 | ||||
| -rw-r--r-- | MediaBrowser.Providers/Manager/MetadataService.cs | 156 | ||||
| -rw-r--r-- | MediaBrowser.Providers/Manager/ProviderManager.cs | 376 | ||||
| -rw-r--r-- | MediaBrowser.Providers/Manager/ProviderUtils.cs | 28 | ||||
| -rw-r--r-- | MediaBrowser.Providers/Manager/RefreshResult.cs | 15 |
6 files changed, 494 insertions, 362 deletions
diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 3ab621ba41..19a42d506c 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; @@ -9,30 +11,33 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; using Microsoft.Extensions.Logging; +using Episode = MediaBrowser.Controller.Entities.TV.Episode; +using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum; +using Person = MediaBrowser.Controller.Entities.Person; +using Season = MediaBrowser.Controller.Entities.TV.Season; namespace MediaBrowser.Providers.Manager { /// <summary> - /// Class ImageSaver + /// Class ImageSaver. /// </summary> public class ImageSaver { private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); /// <summary> - /// The _config + /// The _config. /// </summary> private readonly IServerConfigurationManager _config; /// <summary> - /// The _directory watchers + /// The _directory watchers. /// </summary> private readonly ILibraryMonitor _libraryMonitor; private readonly IFileSystem _fileSystem; @@ -53,6 +58,16 @@ namespace MediaBrowser.Providers.Manager _logger = logger; } + private bool EnableExtraThumbsDuplication + { + get + { + var config = _config.GetConfiguration<XbmcMetadataOptions>("xbmcmetadata"); + + return config.EnableExtraThumbsDuplication; + } + } + /// <summary> /// Saves the image. /// </summary> @@ -63,7 +78,7 @@ namespace MediaBrowser.Providers.Manager /// <param name="imageIndex">Index of the image.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - /// <exception cref="ArgumentNullException">mimeType</exception> + /// <exception cref="ArgumentNullException">mimeType.</exception> public Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken) { return SaveImage(item, source, mimeType, type, imageIndex, null, cancellationToken); @@ -78,11 +93,6 @@ namespace MediaBrowser.Providers.Manager var saveLocally = item.SupportsLocalMetadata && item.IsSaveLocalMetadataEnabled() && !item.ExtraType.HasValue && !(item is Audio); - if (item is User) - { - saveLocally = true; - } - if (type != ImageType.Primary && item is Episode) { saveLocally = false; @@ -105,6 +115,7 @@ namespace MediaBrowser.Providers.Manager } } } + if (saveLocallyWithMedia.HasValue && !saveLocallyWithMedia.Value) { saveLocally = saveLocallyWithMedia.Value; @@ -122,35 +133,40 @@ namespace MediaBrowser.Providers.Manager var retryPaths = GetSavePaths(item, type, imageIndex, mimeType, false); // If there are more than one output paths, the stream will need to be seekable - var memoryStream = new MemoryStream(); - using (source) + if (paths.Length > 1 && !source.CanSeek) { - await source.CopyToAsync(memoryStream).ConfigureAwait(false); - } + var memoryStream = new MemoryStream(); + await using (source.ConfigureAwait(false)) + { + await source.CopyToAsync(memoryStream).ConfigureAwait(false); + } - source = memoryStream; + source = memoryStream; + } var currentImage = GetCurrentImage(item, type, index); var currentImageIsLocalFile = currentImage != null && currentImage.IsLocalFile; - var currentImagePath = currentImage == null ? null : currentImage.Path; + var currentImagePath = currentImage?.Path; var savedPaths = new List<string>(); - using (source) + await using (source.ConfigureAwait(false)) { - var currentPathIndex = 0; - - foreach (var path in paths) + for (int i = 0; i < paths.Length; i++) { - source.Position = 0; + if (i != 0) + { + source.Position = 0; + } + string retryPath = null; if (paths.Length == retryPaths.Length) { - retryPath = retryPaths[currentPathIndex]; + retryPath = retryPaths[i]; } - var savedPath = await SaveImageToLocation(source, path, retryPath, cancellationToken).ConfigureAwait(false); + + var savedPath = await SaveImageToLocation(source, paths[i], retryPath, cancellationToken).ConfigureAwait(false); savedPaths.Add(savedPath); - currentPathIndex++; } } @@ -172,7 +188,6 @@ namespace MediaBrowser.Providers.Manager } catch (FileNotFoundException) { - } finally { @@ -181,6 +196,11 @@ namespace MediaBrowser.Providers.Manager } } + public async Task SaveImage(Stream source, string path) + { + await SaveImageToLocation(source, path, path, CancellationToken.None).ConfigureAwait(false); + } + private async Task<string> SaveImageToLocation(Stream source, string path, string retryPath, CancellationToken cancellationToken) { try @@ -217,7 +237,6 @@ namespace MediaBrowser.Providers.Manager } } - source.Position = 0; await SaveImageToLocation(source, retryPath, cancellationToken).ConfigureAwait(false); return retryPath; } @@ -244,9 +263,9 @@ namespace MediaBrowser.Providers.Manager _fileSystem.SetAttributes(path, false, false); - using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) + await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) { - await source.CopyToAsync(fs, IODefaults.CopyToBufferSize, cancellationToken).ConfigureAwait(false); + await source.CopyToAsync(fs, cancellationToken).ConfigureAwait(false); } if (_config.Configuration.SaveMetadataHidden) @@ -302,7 +321,7 @@ namespace MediaBrowser.Providers.Manager /// <exception cref="ArgumentNullException"> /// imageIndex /// or - /// imageIndex + /// imageIndex. /// </exception> private ItemImageInfo GetCurrentImage(BaseItem item, ImageType type, int imageIndex) { @@ -318,7 +337,8 @@ namespace MediaBrowser.Providers.Manager /// <param name="path">The path.</param> /// <exception cref="ArgumentNullException">imageIndex /// or - /// imageIndex</exception> + /// imageIndex. + /// </exception> private void SetImagePath(BaseItem item, ImageType type, int? imageIndex, string path) { item.SetImagePath(type, imageIndex ?? 0, _fileSystem.GetFileInfo(path)); @@ -336,7 +356,7 @@ namespace MediaBrowser.Providers.Manager /// <exception cref="ArgumentNullException"> /// imageIndex /// or - /// imageIndex + /// imageIndex. /// </exception> private string GetStandardSavePath(BaseItem item, ImageType type, int? imageIndex, string mimeType, bool saveLocally) { @@ -345,7 +365,7 @@ namespace MediaBrowser.Providers.Manager if (string.IsNullOrWhiteSpace(extension)) { - throw new ArgumentException(string.Format("Unable to determine image file extension from mime type {0}", mimeType)); + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Unable to determine image file extension from mime type {0}", mimeType)); } if (type == ImageType.Thumb && saveLocally) @@ -439,7 +459,6 @@ namespace MediaBrowser.Providers.Manager { path = Path.Combine(Path.GetDirectoryName(item.Path), "metadata", filename + extension); } - else if (item.IsInMixedFolder) { path = GetSavePathForItemInMixedFolder(item, type, filename, extension); @@ -458,6 +477,7 @@ namespace MediaBrowser.Providers.Manager { filename = folderName; } + path = Path.Combine(item.GetInternalMetadataPath(), filename + extension); } @@ -490,7 +510,7 @@ namespace MediaBrowser.Providers.Manager /// <param name="imageIndex">Index of the image.</param> /// <param name="mimeType">Type of the MIME.</param> /// <returns>IEnumerable{System.String}.</returns> - /// <exception cref="ArgumentNullException">imageIndex</exception> + /// <exception cref="ArgumentNullException">imageIndex.</exception> private string[] GetCompatibleSavePaths(BaseItem item, ImageType type, int? imageIndex, string mimeType) { var season = item as Season; @@ -549,6 +569,7 @@ namespace MediaBrowser.Providers.Manager { list.Add(Path.Combine(item.ContainingFolderPath, "extrathumbs", "thumb" + outputIndex.ToString(UsCulture) + extension)); } + return list.ToArray(); } @@ -593,16 +614,6 @@ namespace MediaBrowser.Providers.Manager return new[] { GetStandardSavePath(item, type, imageIndex, mimeType, true) }; } - private bool EnableExtraThumbsDuplication - { - get - { - var config = _config.GetConfiguration<XbmcMetadataOptions>("xbmcmetadata"); - - return config.EnableExtraThumbsDuplication; - } - } - /// <summary> /// Gets the save path for item in mixed folder. /// </summary> @@ -617,6 +628,7 @@ namespace MediaBrowser.Providers.Manager { imageFilename = "poster"; } + var folder = Path.GetDirectoryName(item.Path); return Path.Combine(folder, Path.GetFileNameWithoutExtension(item.Path) + "-" + imageFilename + extension); diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 60270d80cb..a57a85376e 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.IO; @@ -26,6 +28,22 @@ namespace MediaBrowser.Providers.Manager private readonly IProviderManager _providerManager; private readonly IFileSystem _fileSystem; + /// <summary> + /// Image types that are only one per item. + /// </summary> + private readonly ImageType[] _singularImages = + { + ImageType.Primary, + ImageType.Art, + ImageType.Banner, + ImageType.Box, + ImageType.BoxRear, + ImageType.Disc, + ImageType.Logo, + ImageType.Menu, + ImageType.Thumb + }; + public ItemImageProvider(ILogger logger, IProviderManager providerManager, IFileSystem fileSystem) { _logger = logger; @@ -52,12 +70,18 @@ namespace MediaBrowser.Providers.Manager return hasChanges; } - public async Task<RefreshResult> RefreshImages(BaseItem item, LibraryOptions libraryOptions, List<IImageProvider> providers, ImageRefreshOptions refreshOptions, MetadataOptions savedOptions, CancellationToken cancellationToken) + public async Task<RefreshResult> RefreshImages( + BaseItem item, + LibraryOptions libraryOptions, + List<IImageProvider> providers, + ImageRefreshOptions refreshOptions, + CancellationToken cancellationToken) { if (refreshOptions.IsReplacingImage(ImageType.Backdrop)) { ClearImages(item, ImageType.Backdrop); } + if (refreshOptions.IsReplacingImage(ImageType.Screenshot)) { ClearImages(item, ImageType.Screenshot); @@ -75,19 +99,15 @@ namespace MediaBrowser.Providers.Manager foreach (var provider in providers) { - var remoteProvider = provider as IRemoteImageProvider; - - if (remoteProvider != null) + if (provider is IRemoteImageProvider remoteProvider) { await RefreshFromProvider(item, libraryOptions, remoteProvider, refreshOptions, typeOptions, backdropLimit, screenshotLimit, downloadedImages, result, cancellationToken).ConfigureAwait(false); continue; } - var dynamicImageProvider = provider as IDynamicImageProvider; - - if (dynamicImageProvider != null) + if (provider is IDynamicImageProvider dynamicImageProvider) { - await RefreshFromProvider(item, dynamicImageProvider, refreshOptions, typeOptions, libraryOptions, downloadedImages, result, cancellationToken).ConfigureAwait(false); + await RefreshFromProvider(item, dynamicImageProvider, refreshOptions, typeOptions, downloadedImages, result, cancellationToken).ConfigureAwait(false); } } @@ -97,11 +117,11 @@ namespace MediaBrowser.Providers.Manager /// <summary> /// Refreshes from provider. /// </summary> - private async Task RefreshFromProvider(BaseItem item, + private async Task RefreshFromProvider( + BaseItem item, IDynamicImageProvider provider, ImageRefreshOptions refreshOptions, TypeOptions savedOptions, - LibraryOptions libraryOptions, ICollection<ImageType> downloadedImages, RefreshResult result, CancellationToken cancellationToken) @@ -112,7 +132,10 @@ namespace MediaBrowser.Providers.Manager foreach (var imageType in images) { - if (!IsEnabled(savedOptions, imageType, item)) continue; + if (!IsEnabled(savedOptions, imageType)) + { + continue; + } if (!HasImage(item, imageType) || (refreshOptions.IsReplacingImage(imageType) && !downloadedImages.Contains(imageType))) { @@ -127,12 +150,13 @@ namespace MediaBrowser.Providers.Manager if (response.Protocol == MediaProtocol.Http) { _logger.LogDebug("Setting image url into item {0}", item.Id); - item.SetImage(new ItemImageInfo - { - Path = response.Path, - Type = imageType - - }, 0); + item.SetImage( + new ItemImageInfo + { + Path = response.Path, + Type = imageType + }, + 0); } else { @@ -151,7 +175,7 @@ namespace MediaBrowser.Providers.Manager } downloadedImages.Add(imageType); - result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; + result.UpdateType |= ItemUpdateType.ImageUpdate; } } } @@ -167,29 +191,13 @@ namespace MediaBrowser.Providers.Manager } } - /// <summary> - /// Image types that are only one per item - /// </summary> - private readonly ImageType[] _singularImages = - { - ImageType.Primary, - ImageType.Art, - ImageType.Banner, - ImageType.Box, - ImageType.BoxRear, - ImageType.Disc, - ImageType.Logo, - ImageType.Menu, - ImageType.Thumb - }; - private bool HasImage(BaseItem item, ImageType type) { return item.HasImage(type); } /// <summary> - /// Determines if an item already contains the given images + /// Determines if an item already contains the given images. /// </summary> /// <param name="item">The item.</param> /// <param name="images">The images.</param> @@ -221,6 +229,7 @@ namespace MediaBrowser.Providers.Manager /// Refreshes from provider. /// </summary> /// <param name="item">The item.</param> + /// <param name="libraryOptions">The library options.</param> /// <param name="provider">The provider.</param> /// <param name="refreshOptions">The refresh options.</param> /// <param name="savedOptions">The saved options.</param> @@ -230,7 +239,9 @@ namespace MediaBrowser.Providers.Manager /// <param name="result">The result.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - private async Task RefreshFromProvider(BaseItem item, LibraryOptions libraryOptions, + private async Task RefreshFromProvider( + BaseItem item, + LibraryOptions libraryOptions, IRemoteImageProvider provider, ImageRefreshOptions refreshOptions, TypeOptions savedOptions, @@ -256,20 +267,24 @@ namespace MediaBrowser.Providers.Manager _logger.LogDebug("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 images = await _providerManager.GetAvailableRemoteImages( + item, + new RemoteImageQuery(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 (!IsEnabled(savedOptions, imageType)) + { + continue; + } if (!HasImage(item, imageType) || (refreshOptions.IsReplacingImage(imageType) && !downloadedImages.Contains(imageType))) { @@ -286,8 +301,7 @@ namespace MediaBrowser.Providers.Manager 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) + if (item is IHasScreenshots hasScreenshots) { minWidth = savedOptions.GetMinWidth(ImageType.Screenshot); await DownloadBackdrops(item, libraryOptions, ImageType.Screenshot, screenshotLimit, provider, result, list, minWidth, cancellationToken).ConfigureAwait(false); @@ -304,7 +318,7 @@ namespace MediaBrowser.Providers.Manager } } - private bool IsEnabled(TypeOptions options, ImageType type, BaseItem item) + private bool IsEnabled(TypeOptions options, ImageType type) { return options.IsEnabled(type); } @@ -329,7 +343,6 @@ namespace MediaBrowser.Providers.Manager } catch (FileNotFoundException) { - } } @@ -365,7 +378,6 @@ namespace MediaBrowser.Providers.Manager } else { - var newDateModified = _fileSystem.GetLastWriteTimeUtc(image.FileInfo); // If date changed then we need to reset saved image dimensions @@ -428,7 +440,9 @@ namespace MediaBrowser.Providers.Manager return changed; } - private async Task<bool> DownloadImage(BaseItem item, LibraryOptions libraryOptions, + private async Task<bool> DownloadImage( + BaseItem item, + LibraryOptions libraryOptions, IRemoteImageProvider provider, RefreshResult result, IEnumerable<RemoteImageInfo> images, @@ -440,10 +454,10 @@ namespace MediaBrowser.Providers.Manager .Where(i => i.Type == type && !(i.Width.HasValue && i.Width.Value < minWidth)) .ToList(); - if (EnableImageStub(item, type, libraryOptions) && eligibleImages.Count > 0) + if (EnableImageStub(item, libraryOptions) && eligibleImages.Count > 0) { SaveImageStub(item, type, eligibleImages.Select(i => i.Url)); - result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; + result.UpdateType |= ItemUpdateType.ImageUpdate; return true; } @@ -453,20 +467,29 @@ namespace MediaBrowser.Providers.Manager 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; + using var response = await provider.GetImageResponse(url, cancellationToken).ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + + await _providerManager.SaveImage( + item, + stream, + response.Content.Headers.ContentType.MediaType, + type, + null, + cancellationToken).ConfigureAwait(false); + + 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) + if (ex.StatusCode.HasValue + && (ex.StatusCode.Value == HttpStatusCode.NotFound || ex.StatusCode.Value == HttpStatusCode.Forbidden)) { continue; } + break; } } @@ -474,7 +497,7 @@ namespace MediaBrowser.Providers.Manager return false; } - private bool EnableImageStub(BaseItem item, ImageType type, LibraryOptions libraryOptions) + private bool EnableImageStub(BaseItem item, LibraryOptions libraryOptions) { if (item is LiveTvProgram) { @@ -494,7 +517,7 @@ namespace MediaBrowser.Providers.Manager return true; } } - + // We always want to use prefetched images return false; } @@ -507,14 +530,15 @@ namespace MediaBrowser.Providers.Manager private void SaveImageStub(BaseItem item, ImageType imageType, IEnumerable<string> urls, int newIndex) { - var path = string.Join("|", urls.Take(1).ToArray()); - - item.SetImage(new ItemImageInfo - { - Path = path, - Type = imageType + var path = string.Join('|', urls.Take(1)); - }, newIndex); + item.SetImage( + new ItemImageInfo + { + Path = path, + Type = imageType + }, + newIndex); } private async Task DownloadBackdrops(BaseItem item, LibraryOptions libraryOptions, ImageType imageType, int limit, IRemoteImageProvider provider, RefreshResult result, IEnumerable<RemoteImageInfo> images, int minWidth, CancellationToken cancellationToken) @@ -533,23 +557,23 @@ namespace MediaBrowser.Providers.Manager var url = image.Url; - if (EnableImageStub(item, imageType, libraryOptions)) + if (EnableImageStub(item, libraryOptions)) { SaveImageStub(item, imageType, new[] { url }); - result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; + result.UpdateType |= ItemUpdateType.ImageUpdate; continue; } try { - var response = await provider.GetImageResponse(url, cancellationToken).ConfigureAwait(false); + using 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) + if (response.Content.Headers.ContentLength.HasValue) { try { - if (item.GetImages(imageType).Any(i => _fileSystem.GetFileInfo(i.Path).Length == response.ContentLength.Value)) + if (item.GetImages(imageType).Any(i => _fileSystem.GetFileInfo(i.Path).Length == response.Content.Headers.ContentLength.Value)) { response.Content.Dispose(); continue; @@ -561,16 +585,25 @@ namespace MediaBrowser.Providers.Manager } } - await _providerManager.SaveImage(item, response.Content, response.ContentType, imageType, null, cancellationToken).ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await _providerManager.SaveImage( + item, + stream, + response.Content.Headers.ContentType.MediaType, + imageType, + null, + cancellationToken).ConfigureAwait(false); result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; } catch (HttpException ex) { // Sometimes providers send back bad urls. Just move onto the next image - if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) + if (ex.StatusCode.HasValue + && (ex.StatusCode.Value == HttpStatusCode.NotFound || ex.StatusCode.Value == HttpStatusCode.Forbidden)) { continue; } + break; } } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index dffdc468ad..a507bd4a6d 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Linq; @@ -19,13 +21,7 @@ namespace MediaBrowser.Providers.Manager where TItemType : BaseItem, IHasLookupInfo<TIdType>, new() where TIdType : ItemLookupInfo, new() { - protected readonly IServerConfigurationManager ServerConfigurationManager; - protected readonly ILogger Logger; - protected readonly IProviderManager ProviderManager; - protected readonly IFileSystem FileSystem; - protected readonly ILibraryManager LibraryManager; - - protected MetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, ILibraryManager libraryManager) + protected MetadataService(IServerConfigurationManager serverConfigurationManager, ILogger<MetadataService<TItemType, TIdType>> logger, IProviderManager providerManager, IFileSystem fileSystem, ILibraryManager libraryManager) { ServerConfigurationManager = serverConfigurationManager; Logger = logger; @@ -34,6 +30,26 @@ namespace MediaBrowser.Providers.Manager LibraryManager = libraryManager; } + protected IServerConfigurationManager ServerConfigurationManager { get; } + + protected ILogger<MetadataService<TItemType, TIdType>> Logger { get; } + + protected IProviderManager ProviderManager { get; } + + protected IFileSystem FileSystem { get; } + + protected ILibraryManager LibraryManager { get; } + + protected virtual bool EnableUpdatingPremiereDateFromChildren => false; + + protected virtual bool EnableUpdatingGenresFromChildren => false; + + protected virtual bool EnableUpdatingStudiosFromChildren => false; + + protected virtual bool EnableUpdatingOfficialRatingFromChildren => false; + + public virtual int Order => 0; + private FileSystemMetadata TryGetFile(string path, IDirectoryService directoryService) { try @@ -50,7 +66,6 @@ namespace MediaBrowser.Providers.Manager public async Task<ItemUpdateType> RefreshMetadata(BaseItem item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken) { var itemOfType = (TItemType)item; - var config = ProviderManager.GetMetadataOptions(item); var updateType = ItemUpdateType.None; var requiresRefresh = false; @@ -84,7 +99,7 @@ namespace MediaBrowser.Providers.Manager // Always validate images and check for new locally stored ones. if (itemImageProvider.ValidateImages(item, allImageProviders.OfType<ILocalImageProvider>(), refreshOptions.DirectoryService)) { - updateType = updateType | ItemUpdateType.ImageUpdate; + updateType |= ItemUpdateType.ImageUpdate; } } catch (Exception ex) @@ -100,7 +115,7 @@ namespace MediaBrowser.Providers.Manager bool hasRefreshedMetadata = true; bool hasRefreshedImages = true; - var isFirstRefresh = item.DateLastRefreshed == default(DateTime); + var isFirstRefresh = item.DateLastRefreshed == default; // Next run metadata providers if (refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None) @@ -112,7 +127,7 @@ namespace MediaBrowser.Providers.Manager { if (item.BeforeMetadataRefresh(refreshOptions.ReplaceAllMetadata)) { - updateType = updateType | ItemUpdateType.MetadataImport; + updateType |= ItemUpdateType.MetadataImport; } } @@ -125,12 +140,12 @@ namespace MediaBrowser.Providers.Manager ApplySearchResult(id, refreshOptions.SearchResult); } - //await FindIdentities(id, cancellationToken).ConfigureAwait(false); + // await FindIdentities(id, cancellationToken).ConfigureAwait(false); id.IsAutomated = refreshOptions.IsAutomated; var result = await RefreshWithProviders(metadataResult, id, refreshOptions, providers, itemImageProvider, cancellationToken).ConfigureAwait(false); - updateType = updateType | result.UpdateType; + updateType |= result.UpdateType; if (result.Failures > 0) { hasRefreshedMetadata = false; @@ -145,9 +160,9 @@ namespace MediaBrowser.Providers.Manager if (providers.Count > 0) { - var result = await itemImageProvider.RefreshImages(itemOfType, libraryOptions, providers, refreshOptions, config, cancellationToken).ConfigureAwait(false); + var result = await itemImageProvider.RefreshImages(itemOfType, libraryOptions, providers, refreshOptions, cancellationToken).ConfigureAwait(false); - updateType = updateType | result.UpdateType; + updateType |= result.UpdateType; if (result.Failures > 0) { hasRefreshedImages = false; @@ -156,7 +171,7 @@ namespace MediaBrowser.Providers.Manager } var beforeSaveResult = BeforeSave(itemOfType, isFirstRefresh || refreshOptions.ReplaceAllMetadata || refreshOptions.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || requiresRefresh || refreshOptions.ForceSave, updateType); - updateType = updateType | beforeSaveResult; + updateType |= beforeSaveResult; // Save if changes were made, or it's never been saved before if (refreshOptions.ForceSave || updateType > ItemUpdateType.None || isFirstRefresh || refreshOptions.ReplaceAllMetadata || requiresRefresh) @@ -173,7 +188,7 @@ namespace MediaBrowser.Providers.Manager // If any of these properties are set then make sure the updateType is not None, just to force everything to save if (refreshOptions.ForceSave || refreshOptions.ReplaceAllMetadata) { - updateType = updateType | ItemUpdateType.MetadataDownload; + updateType |= ItemUpdateType.MetadataDownload; } if (hasRefreshedMetadata && hasRefreshedImages) @@ -182,11 +197,11 @@ namespace MediaBrowser.Providers.Manager } else { - item.DateLastRefreshed = default(DateTime); + item.DateLastRefreshed = default; } // Save to database - SaveItem(metadataResult, libraryOptions, updateType, cancellationToken); + await SaveItemAsync(metadataResult, libraryOptions, updateType, cancellationToken).ConfigureAwait(false); } await AfterMetadataRefresh(itemOfType, refreshOptions, cancellationToken).ConfigureAwait(false); @@ -201,25 +216,26 @@ namespace MediaBrowser.Providers.Manager lookupInfo.Year = result.ProductionYear; } - protected void SaveItem(MetadataResult<TItemType> result, LibraryOptions libraryOptions, ItemUpdateType reason, CancellationToken cancellationToken) + protected async Task SaveItemAsync(MetadataResult<TItemType> result, LibraryOptions libraryOptions, ItemUpdateType reason, CancellationToken cancellationToken) { if (result.Item.SupportsPeople && result.People != null) { var baseItem = result.Item; LibraryManager.UpdatePeople(baseItem, result.People); - SavePeopleMetadata(result.People, libraryOptions, cancellationToken); + await SavePeopleMetadataAsync(result.People, libraryOptions, cancellationToken).ConfigureAwait(false); } - result.Item.UpdateToRepository(reason, cancellationToken); + + await result.Item.UpdateToRepositoryAsync(reason, cancellationToken).ConfigureAwait(false); } - private void SavePeopleMetadata(List<PersonInfo> people, LibraryOptions libraryOptions, CancellationToken cancellationToken) + private async Task SavePeopleMetadataAsync(List<PersonInfo> people, LibraryOptions libraryOptions, CancellationToken cancellationToken) { foreach (var person in people) { cancellationToken.ThrowIfCancellationRequested(); - if (person.ProviderIds.Any() || !string.IsNullOrWhiteSpace(person.ImageUrl)) + if (person.ProviderIds.Count > 0 || !string.IsNullOrWhiteSpace(person.ImageUrl)) { var updateType = ItemUpdateType.MetadataDownload; @@ -236,21 +252,21 @@ namespace MediaBrowser.Providers.Manager if (!string.IsNullOrWhiteSpace(person.ImageUrl) && !personEntity.HasImage(ImageType.Primary)) { - AddPersonImage(personEntity, libraryOptions, person.ImageUrl, cancellationToken); + await AddPersonImageAsync(personEntity, libraryOptions, person.ImageUrl, cancellationToken).ConfigureAwait(false); saveEntity = true; - updateType = updateType | ItemUpdateType.ImageUpdate; + updateType |= ItemUpdateType.ImageUpdate; } if (saveEntity) { - personEntity.UpdateToRepository(updateType, cancellationToken); + await personEntity.UpdateToRepositoryAsync(updateType, cancellationToken).ConfigureAwait(false); } } } } - private void AddPersonImage(Person personEntity, LibraryOptions libraryOptions, string imageUrl, CancellationToken cancellationToken) + private async Task AddPersonImageAsync(Person personEntity, LibraryOptions libraryOptions, string imageUrl, CancellationToken cancellationToken) { try { @@ -262,11 +278,13 @@ namespace MediaBrowser.Providers.Manager Logger.LogError(ex, "Error in AddPersonImage"); } - personEntity.SetImage(new ItemImageInfo - { - Path = imageUrl, - Type = ImageType.Primary - }, 0); + personEntity.SetImage( + new ItemImageInfo + { + Path = imageUrl, + Type = ImageType.Primary + }, + 0); } protected virtual Task AfterMetadataRefresh(TItemType item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken) @@ -276,7 +294,7 @@ namespace MediaBrowser.Providers.Manager } /// <summary> - /// Befores the save. + /// Before the save. /// </summary> /// <param name="item">The item.</param> /// <param name="isFullRefresh">if set to <c>true</c> [is full refresh].</param> @@ -321,6 +339,7 @@ namespace MediaBrowser.Providers.Manager { return true; } + var folder = item as Folder; if (folder != null) { @@ -333,13 +352,12 @@ namespace MediaBrowser.Providers.Manager protected virtual IList<BaseItem> GetChildrenForMetadataUpdates(TItemType item) { - var folder = item as Folder; - if (folder != null) + if (item is Folder folder) { return folder.GetRecursiveChildren(); } - return new List<BaseItem>(); + return Array.Empty<BaseItem>(); } protected virtual ItemUpdateType UpdateMetadataFromChildren(TItemType item, IList<BaseItem> children, bool isFullRefresh, ItemUpdateType currentUpdateType) @@ -386,7 +404,7 @@ namespace MediaBrowser.Providers.Manager { if (!child.IsFolder) { - ticks += (child.RunTimeTicks ?? 0); + ticks += child.RunTimeTicks ?? 0; } } @@ -419,6 +437,7 @@ namespace MediaBrowser.Providers.Manager { dateLastMediaAdded = childDateCreated; } + any = true; } } @@ -433,14 +452,6 @@ namespace MediaBrowser.Providers.Manager return updateType; } - protected virtual bool EnableUpdatingPremiereDateFromChildren => false; - - protected virtual bool EnableUpdatingGenresFromChildren => false; - - protected virtual bool EnableUpdatingStudiosFromChildren => false; - - protected virtual bool EnableUpdatingOfficialRatingFromChildren => false; - private ItemUpdateType UpdatePremiereDate(TItemType item, IList<BaseItem> children) { var updateType = ItemUpdateType.None; @@ -483,7 +494,7 @@ namespace MediaBrowser.Providers.Manager { var updateType = ItemUpdateType.None; - if (!item.LockedFields.Contains(MetadataFields.Genres)) + if (!item.LockedFields.Contains(MetadataField.Genres)) { var currentList = item.Genres; @@ -504,7 +515,7 @@ namespace MediaBrowser.Providers.Manager { var updateType = ItemUpdateType.None; - if (!item.LockedFields.Contains(MetadataFields.Studios)) + if (!item.LockedFields.Contains(MetadataField.Studios)) { var currentList = item.Studios; @@ -525,7 +536,7 @@ namespace MediaBrowser.Providers.Manager { var updateType = ItemUpdateType.None; - if (!item.LockedFields.Contains(MetadataFields.OfficialRating)) + if (!item.LockedFields.Contains(MetadataField.OfficialRating)) { if (item.UpdateRatingToItems(children)) { @@ -649,7 +660,8 @@ namespace MediaBrowser.Providers.Manager return type == typeof(TItemType); } - protected virtual async Task<RefreshResult> RefreshWithProviders(MetadataResult<TItemType> metadata, + protected virtual async Task<RefreshResult> RefreshWithProviders( + MetadataResult<TItemType> metadata, TIdType id, MetadataRefreshOptions options, List<IMetadataProvider> providers, @@ -715,7 +727,7 @@ namespace MediaBrowser.Providers.Manager userDataList.AddRange(localItem.UserDataList); } - MergeData(localItem, temp, new MetadataFields[] { }, !options.ReplaceAllMetadata, true); + MergeData(localItem, temp, Array.Empty<MetadataField>(), !options.ReplaceAllMetadata, true); refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport; // Only one local provider allowed per item @@ -723,6 +735,7 @@ namespace MediaBrowser.Providers.Manager { hasLocalMetadata = true; } + break; } @@ -763,20 +776,20 @@ namespace MediaBrowser.Providers.Manager else { // 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 MetadataFields[] { }, false, false); + MergeData(metadata, temp, Array.Empty<MetadataField>(), false, false); MergeData(temp, metadata, item.LockedFields, true, false); } } } - //var isUnidentified = failedProviderCount > 0 && successfulProviderCount == 0; + // 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); } - //ImportUserData(item, userDataList, cancellationToken); + // ImportUserData(item, userDataList, cancellationToken); return refreshResult; } @@ -797,7 +810,7 @@ namespace MediaBrowser.Providers.Manager try { - refreshResult.UpdateType = refreshResult.UpdateType | await provider.FetchAsync(item, options, cancellationToken).ConfigureAwait(false); + refreshResult.UpdateType |= await provider.FetchAsync(item, options, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -840,7 +853,7 @@ namespace MediaBrowser.Providers.Manager { result.Provider = provider.Name; - MergeData(result, temp, new MetadataFields[] { }, false, false); + MergeData(result, temp, Array.Empty<MetadataField>(), false, false); MergeNewData(temp.Item, id); refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataDownload; @@ -865,15 +878,6 @@ namespace MediaBrowser.Providers.Manager return refreshResult; } - private string NormalizeLanguage(string language) - { - if (string.IsNullOrWhiteSpace(language)) - { - return "en"; - } - return language; - } - private void MergeNewData(TItemType source, TIdType lookupInfo) { // Copy new provider id's that may have been obtained @@ -889,24 +893,23 @@ namespace MediaBrowser.Providers.Manager } } - protected abstract void MergeData(MetadataResult<TItemType> source, + protected abstract void MergeData( + MetadataResult<TItemType> source, MetadataResult<TItemType> target, - MetadataFields[] lockedFields, + MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings); - public virtual int Order => 0; - private bool HasChanged(BaseItem item, IHasItemChangeMonitor changeMonitor, IDirectoryService directoryService) { try { var hasChanged = changeMonitor.HasChanged(item, directoryService); - //if (hasChanged) - //{ - // logger.LogDebug("{0} reports change to {1}", changeMonitor.GetType().Name, item.Path ?? item.Name); - //} + if (hasChanged) + { + Logger.LogDebug("{0} reports change to {1}", changeMonitor.GetType().Name, item.Path ?? item.Name); + } return hasChanged; } @@ -917,11 +920,4 @@ namespace MediaBrowser.Providers.Manager } } } - - public class RefreshResult - { - public ItemUpdateType UpdateType { get; set; } - public string ErrorMessage { get; set; } - public int Failures { get; set; } - } } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index cfff897672..a0c7d4ad09 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -1,13 +1,15 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Mime; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Common.Net; using MediaBrowser.Common.Progress; using MediaBrowser.Controller; @@ -16,109 +18,118 @@ using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Subtitles; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Events; using MediaBrowser.Model.IO; +using MediaBrowser.Model.Net; using MediaBrowser.Model.Providers; -using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; using Priority_Queue; +using Book = MediaBrowser.Controller.Entities.Book; +using Episode = MediaBrowser.Controller.Entities.TV.Episode; +using Movie = MediaBrowser.Controller.Entities.Movies.Movie; +using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum; +using Season = MediaBrowser.Controller.Entities.TV.Season; +using Series = MediaBrowser.Controller.Entities.TV.Series; namespace MediaBrowser.Providers.Manager { /// <summary> - /// Class ProviderManager + /// Class ProviderManager. /// </summary> public class ProviderManager : IProviderManager, IDisposable { - private readonly ILogger _logger; - private readonly IHttpClient _httpClient; + private readonly object _refreshQueueLock = new object(); + private readonly ILogger<ProviderManager> _logger; + private readonly IHttpClientFactory _httpClientFactory; private readonly ILibraryMonitor _libraryMonitor; private readonly IFileSystem _fileSystem; private readonly IServerApplicationPaths _appPaths; - private readonly IJsonSerializer _json; private readonly ILibraryManager _libraryManager; private readonly ISubtitleManager _subtitleManager; private readonly IServerConfigurationManager _configurationManager; + private readonly ConcurrentDictionary<Guid, double> _activeRefreshes = new ConcurrentDictionary<Guid, double>(); + private readonly CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource(); + private readonly SimplePriorityQueue<Tuple<Guid, MetadataRefreshOptions>> _refreshQueue = + new SimplePriorityQueue<Tuple<Guid, MetadataRefreshOptions>>(); - private IImageProvider[] ImageProviders { get; set; } - - private IMetadataService[] _metadataServices = { }; - private IMetadataProvider[] _metadataProviders = { }; + private IMetadataService[] _metadataServices = Array.Empty<IMetadataService>(); + private IMetadataProvider[] _metadataProviders = Array.Empty<IMetadataProvider>(); private IEnumerable<IMetadataSaver> _savers; - private IExternalId[] _externalIds; - - private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource(); - - public event EventHandler<GenericEventArgs<BaseItem>> RefreshStarted; - public event EventHandler<GenericEventArgs<BaseItem>> RefreshCompleted; - public event EventHandler<GenericEventArgs<Tuple<BaseItem, double>>> RefreshProgress; + private bool _isProcessingRefreshQueue; + private bool _disposed; /// <summary> - /// Initializes a new instance of the <see cref="ProviderManager" /> class. + /// Initializes a new instance of the <see cref="ProviderManager"/> class. /// </summary> + /// <param name="httpClientFactory">The Http client factory.</param> + /// <param name="subtitleManager">The subtitle manager.</param> + /// <param name="configurationManager">The configuration manager.</param> + /// <param name="libraryMonitor">The library monitor.</param> + /// <param name="logger">The logger.</param> + /// <param name="fileSystem">The filesystem.</param> + /// <param name="appPaths">The server application paths.</param> + /// <param name="libraryManager">The library manager.</param> public ProviderManager( - IHttpClient httpClient, + IHttpClientFactory httpClientFactory, ISubtitleManager subtitleManager, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILogger<ProviderManager> logger, IFileSystem fileSystem, IServerApplicationPaths appPaths, - ILibraryManager libraryManager, - IJsonSerializer json) + ILibraryManager libraryManager) { _logger = logger; - _httpClient = httpClient; + _httpClientFactory = httpClientFactory; _configurationManager = configurationManager; _libraryMonitor = libraryMonitor; _fileSystem = fileSystem; _appPaths = appPaths; _libraryManager = libraryManager; - _json = json; _subtitleManager = subtitleManager; } - /// <summary> - /// Adds the metadata providers. - /// </summary> - public void AddParts(IEnumerable<IImageProvider> imageProviders, IEnumerable<IMetadataService> metadataServices, - IEnumerable<IMetadataProvider> metadataProviders, IEnumerable<IMetadataSaver> metadataSavers, - IEnumerable<IExternalId> externalIds) + /// <inheritdoc/> + public event EventHandler<GenericEventArgs<BaseItem>> RefreshStarted; + + /// <inheritdoc/> + public event EventHandler<GenericEventArgs<BaseItem>> RefreshCompleted; + + /// <inheritdoc/> + public event EventHandler<GenericEventArgs<Tuple<BaseItem, double>>> RefreshProgress; + + private IImageProvider[] ImageProviders { get; set; } + + /// <inheritdoc/> + public void AddParts( + IEnumerable<IImageProvider> imageProviders, + IEnumerable<IMetadataService> metadataServices, + IEnumerable<IMetadataProvider> metadataProviders, + IEnumerable<IMetadataSaver> metadataSavers, + IEnumerable<IExternalId> externalIds) { ImageProviders = imageProviders.ToArray(); _metadataServices = metadataServices.OrderBy(i => i.Order).ToArray(); _metadataProviders = metadataProviders.ToArray(); - _externalIds = externalIds.OrderBy(i => i.Name).ToArray(); + _externalIds = externalIds.OrderBy(i => i.ProviderName).ToArray(); - _savers = metadataSavers.Where(i => - { - var configurable = i as IConfigurableProvider; - - return configurable == null || configurable.IsEnabled; - }).ToArray(); + _savers = metadataSavers + .Where(i => !(i is IConfigurableProvider configurable) || configurable.IsEnabled) + .ToArray(); } + /// <inheritdoc/> public Task<ItemUpdateType> RefreshSingleItem(BaseItem item, MetadataRefreshOptions options, CancellationToken cancellationToken) { - IMetadataService service = null; var type = item.GetType(); - foreach (var current in _metadataServices) - { - if (current.CanRefreshPrimary(type)) - { - service = current; - break; - } - } + var service = _metadataServices.FirstOrDefault(current => current.CanRefreshPrimary(type)); if (service == null) { @@ -141,35 +152,58 @@ namespace MediaBrowser.Providers.Manager return Task.FromResult(ItemUpdateType.None); } + /// <inheritdoc/> public async Task SaveImage(BaseItem item, string url, ImageType type, int? imageIndex, CancellationToken cancellationToken) { - using (var response = await _httpClient.GetResponse(new HttpRequestOptions + var httpClient = _httpClientFactory.CreateClient(NamedClient.Default); + using var response = await httpClient.GetAsync(url, cancellationToken).ConfigureAwait(false); + + if (response.StatusCode != HttpStatusCode.OK) { - CancellationToken = cancellationToken, - Url = url, - BufferContent = false + throw new HttpException("Invalid image received.") + { + StatusCode = response.StatusCode + }; + } + + var contentType = response.Content.Headers.ContentType.MediaType; - }).ConfigureAwait(false)) + // Workaround for tvheadend channel icons + // TODO: Isolate this hack into the tvh plugin + if (string.IsNullOrEmpty(contentType)) { - // Workaround for tvheadend channel icons - // TODO: Isolate this hack into the tvh plugin - if (string.IsNullOrEmpty(response.ContentType)) + if (url.IndexOf("/imagecache/", StringComparison.OrdinalIgnoreCase) != -1) { - if (url.IndexOf("/imagecache/", StringComparison.OrdinalIgnoreCase) != -1) - { - response.ContentType = "image/png"; - } + contentType = "image/png"; } + } - await SaveImage(item, response.Content, response.ContentType, type, imageIndex, cancellationToken).ConfigureAwait(false); + // thetvdb will sometimes serve a rubbish 404 html page with a 200 OK code, because reasons... + if (contentType.Equals(MediaTypeNames.Text.Html, StringComparison.OrdinalIgnoreCase)) + { + throw new HttpException("Invalid image received.") + { + StatusCode = HttpStatusCode.NotFound + }; } + + await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await SaveImage( + item, + stream, + contentType, + type, + imageIndex, + cancellationToken).ConfigureAwait(false); } + /// <inheritdoc/> public Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken) { return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, source, mimeType, type, imageIndex, cancellationToken); } + /// <inheritdoc/> public Task SaveImage(BaseItem item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(source)) @@ -182,6 +216,14 @@ namespace MediaBrowser.Providers.Manager return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, fileStream, mimeType, type, imageIndex, saveLocallyWithMedia, cancellationToken); } + /// <inheritdoc/> + public Task SaveImage(Stream source, string mimeType, string path) + { + return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger) + .SaveImage(source, path); + } + + /// <inheritdoc/> public async Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(BaseItem item, RemoteImageQuery query, CancellationToken cancellationToken) { var providers = GetRemoteImageProviders(item, query.IncludeDisabledProviders); @@ -201,7 +243,7 @@ namespace MediaBrowser.Providers.Manager languages.Add(preferredLanguage); } - var tasks = providers.Select(i => GetImages(item, cancellationToken, i, languages, query.ImageType)); + var tasks = providers.Select(i => GetImages(item, i, languages, cancellationToken, query.ImageType)); var results = await Task.WhenAll(tasks).ConfigureAwait(false); @@ -212,12 +254,17 @@ namespace MediaBrowser.Providers.Manager /// 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="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, CancellationToken cancellationToken, IRemoteImageProvider provider, List<string> preferredLanguages, ImageType? type = null) + private async Task<IEnumerable<RemoteImageInfo>> GetImages( + BaseItem item, + IRemoteImageProvider provider, + IReadOnlyCollection<string> preferredLanguages, + CancellationToken cancellationToken, + ImageType? type = null) { try { @@ -243,25 +290,23 @@ namespace MediaBrowser.Providers.Manager } catch (Exception ex) { - _logger.LogError(ex, "{0} failed in GetImageInfos for type {1}", provider.GetType().Name, item.GetType().Name); + _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 supported image providers. - /// </summary> - /// <param name="item">The item.</param> - /// <returns>IEnumerable{IImageProvider}.</returns> + /// <inheritdoc/> public IEnumerable<ImageProviderInfo> GetRemoteImageProviderInfo(BaseItem item) { - return GetRemoteImageProviders(item, true).Select(i => new ImageProviderInfo - { - Name = i.Name, - SupportedImages = i.GetSupportedImages(item).ToArray() - }); + return GetRemoteImageProviders(item, true).Select(i => new ImageProviderInfo(i.Name, i.GetSupportedImages(item).ToArray())); } + /// <summary> + /// Gets the image providers for the provided item. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="refreshOptions">The image refresh options.</param> + /// <returns>The image providers for the item.</returns> public IEnumerable<IImageProvider> GetImageProviders(BaseItem item, ImageRefreshOptions refreshOptions) { return GetImageProviders(item, _libraryManager.GetLibraryOptions(item), GetMetadataOptions(item), refreshOptions, false); @@ -275,7 +320,7 @@ namespace MediaBrowser.Providers.Manager var typeOptions = libraryOptions.GetTypeOptions(item.GetType().Name); var typeFetcherOrder = typeOptions?.ImageFetcherOrder; - return ImageProviders.Where(i => CanRefresh(i, item, libraryOptions, options, refreshOptions, includeDisabled)) + return ImageProviders.Where(i => CanRefresh(i, item, libraryOptions, refreshOptions, includeDisabled)) .OrderBy(i => { // See if there's a user-defined order @@ -296,6 +341,13 @@ namespace MediaBrowser.Providers.Manager .ThenBy(GetOrder); } + /// <summary> + /// Gets the metadata providers for the provided item. + /// </summary> + /// <param name="item">The item.</param> + /// <param name="libraryOptions">The library options.</param> + /// <typeparam name="T">The type of metadata provider.</typeparam> + /// <returns>The metadata providers.</returns> public IEnumerable<IMetadataProvider<T>> GetMetadataProviders<T>(BaseItem item, LibraryOptions libraryOptions) where T : BaseItem { @@ -311,7 +363,7 @@ namespace MediaBrowser.Providers.Manager var currentOptions = globalMetadataOptions; return _metadataProviders.OfType<IMetadataProvider<T>>() - .Where(i => CanRefresh(i, item, libraryOptions, currentOptions, includeDisabled, forceEnableInternetMetadata)) + .Where(i => CanRefresh(i, item, libraryOptions, includeDisabled, forceEnableInternetMetadata)) .OrderBy(i => GetConfiguredOrder(item, i, libraryOptions, globalMetadataOptions)) .ThenBy(GetDefaultOrder); } @@ -321,14 +373,20 @@ namespace MediaBrowser.Providers.Manager var options = GetMetadataOptions(item); var libraryOptions = _libraryManager.GetLibraryOptions(item); - return GetImageProviders(item, libraryOptions, options, - new ImageRefreshOptions( - new DirectoryService(_fileSystem)), - includeDisabled) - .OfType<IRemoteImageProvider>(); + return GetImageProviders( + item, + libraryOptions, + options, + new ImageRefreshOptions(new DirectoryService(_fileSystem)), + includeDisabled).OfType<IRemoteImageProvider>(); } - private bool CanRefresh(IMetadataProvider provider, BaseItem item, LibraryOptions libraryOptions, MetadataOptions options, bool includeDisabled, bool forceEnableInternetMetadata) + private bool CanRefresh( + IMetadataProvider provider, + BaseItem item, + LibraryOptions libraryOptions, + bool includeDisabled, + bool forceEnableInternetMetadata) { if (!includeDisabled) { @@ -364,7 +422,12 @@ namespace MediaBrowser.Providers.Manager return true; } - private bool CanRefresh(IImageProvider provider, BaseItem item, LibraryOptions libraryOptions, MetadataOptions options, ImageRefreshOptions refreshOptions, bool includeDisabled) + private bool CanRefresh( + IImageProvider provider, + BaseItem item, + LibraryOptions libraryOptions, + ImageRefreshOptions refreshOptions, + bool includeDisabled) { if (!includeDisabled) { @@ -392,7 +455,7 @@ namespace MediaBrowser.Providers.Manager } catch (Exception ex) { - _logger.LogError(ex, "{0} failed in Supports for type {1}", provider.GetType().Name, item.GetType().Name); + _logger.LogError(ex, "{ProviderName} failed in Supports for type {ItemType} at {ItemPath}", provider.GetType().Name, item.GetType().Name, item.Path); return false; } } @@ -404,9 +467,7 @@ namespace MediaBrowser.Providers.Manager /// <returns>System.Int32.</returns> private int GetOrder(IImageProvider provider) { - var hasOrder = provider as IHasOrder; - - if (hasOrder == null) + if (!(provider is IHasOrder hasOrder)) { return 0; } @@ -433,7 +494,7 @@ namespace MediaBrowser.Providers.Manager if (provider is IRemoteMetadataProvider) { var typeOptions = libraryOptions.GetTypeOptions(item.GetType().Name); - var typeFetcherOrder = typeOptions == null ? null : typeOptions.MetadataFetcherOrder; + var typeFetcherOrder = typeOptions?.MetadataFetcherOrder; var fetcherOrder = typeFetcherOrder ?? globalMetadataOptions.MetadataFetcherOrder; @@ -451,9 +512,7 @@ namespace MediaBrowser.Providers.Manager private int GetDefaultOrder(IMetadataProvider provider) { - var hasOrder = provider as IHasOrder; - - if (hasOrder != null) + if (provider is IHasOrder hasOrder) { return hasOrder.Order; } @@ -461,9 +520,10 @@ namespace MediaBrowser.Providers.Manager return 0; } + /// <inheritdoc/> public MetadataPluginSummary[] GetAllMetadataPlugins() { - return new MetadataPluginSummary[] + return new[] { GetPluginSummary<Movie>(), GetPluginSummary<BoxSet>(), @@ -485,7 +545,7 @@ namespace MediaBrowser.Providers.Manager where T : BaseItem, new() { // Give it a dummy path just so that it looks like a file system item - var dummy = new T() + var dummy = new T { Path = Path.Combine(_appPaths.InternalMetadataPath, "dummy"), ParentId = Guid.NewGuid() @@ -500,16 +560,17 @@ namespace MediaBrowser.Providers.Manager var libraryOptions = new LibraryOptions(); - var imageProviders = GetImageProviders(dummy, libraryOptions, options, - new ImageRefreshOptions( - new DirectoryService(_fileSystem)), - true) - .ToList(); + var imageProviders = GetImageProviders( + dummy, + libraryOptions, + options, + new ImageRefreshOptions(new DirectoryService(_fileSystem)), + true).ToList(); var pluginList = summary.Plugins.ToList(); AddMetadataPlugins(pluginList, dummy, libraryOptions, options); - AddImagePlugins(pluginList, dummy, imageProviders); + AddImagePlugins(pluginList, imageProviders); var subtitleProviders = _subtitleManager.GetSupportedProviders(dummy); @@ -540,14 +601,14 @@ namespace MediaBrowser.Providers.Manager var providers = GetMetadataProvidersInternal<T>(item, libraryOptions, options, true, true).ToList(); // Locals - list.AddRange(providers.Where(i => (i is ILocalMetadataProvider)).Select(i => new MetadataPlugin + list.AddRange(providers.Where(i => i is ILocalMetadataProvider).Select(i => new MetadataPlugin { Name = i.Name, Type = MetadataPluginType.LocalMetadataProvider })); // Fetchers - list.AddRange(providers.Where(i => (i is IRemoteMetadataProvider)).Select(i => new MetadataPlugin + list.AddRange(providers.Where(i => i is IRemoteMetadataProvider).Select(i => new MetadataPlugin { Name = i.Name, Type = MetadataPluginType.MetadataFetcher @@ -561,12 +622,10 @@ namespace MediaBrowser.Providers.Manager })); } - private void AddImagePlugins<T>(List<MetadataPlugin> list, T item, List<IImageProvider> imageProviders) - where T : BaseItem + private void AddImagePlugins(List<MetadataPlugin> list, List<IImageProvider> imageProviders) { - // Locals - list.AddRange(imageProviders.Where(i => (i is ILocalImageProvider)).Select(i => new MetadataPlugin + list.AddRange(imageProviders.Where(i => i is ILocalImageProvider).Select(i => new MetadataPlugin { Name = i.Name, Type = MetadataPluginType.LocalImageProvider @@ -580,6 +639,7 @@ namespace MediaBrowser.Providers.Manager })); } + /// <inheritdoc/> public MetadataOptions GetMetadataOptions(BaseItem item) { var type = item.GetType().Name; @@ -589,17 +649,13 @@ namespace MediaBrowser.Providers.Manager new MetadataOptions(); } - /// <summary> - /// Saves the metadata. - /// </summary> + /// <inheritdoc/> public void SaveMetadata(BaseItem item, ItemUpdateType updateType) { SaveMetadata(item, updateType, _savers); } - /// <summary> - /// Saves the metadata. - /// </summary> + /// <inheritdoc/> public void SaveMetadata(BaseItem item, ItemUpdateType updateType, IEnumerable<string> savers) { SaveMetadata(item, updateType, _savers.Where(i => savers.Contains(i.Name, StringComparer.OrdinalIgnoreCase))); @@ -611,7 +667,6 @@ namespace MediaBrowser.Providers.Manager /// <param name="item">The item.</param> /// <param name="updateType">Type of the update.</param> /// <param name="savers">The savers.</param> - /// <returns>Task.</returns> private void SaveMetadata(BaseItem item, ItemUpdateType updateType, IEnumerable<IMetadataSaver> savers) { var libraryOptions = _libraryManager.GetLibraryOptions(item); @@ -620,11 +675,9 @@ namespace MediaBrowser.Providers.Manager { _logger.LogDebug("Saving {0} to {1}.", item.Path ?? item.Name, saver.Name); - var fileSaver = saver as IMetadataFileSaver; - - if (fileSaver != null) + if (saver is IMetadataFileSaver fileSaver) { - string path = null; + string path; try { @@ -691,11 +744,9 @@ namespace MediaBrowser.Providers.Manager { if (updateType >= ItemUpdateType.MetadataEdit) { - var fileSaver = saver as IMetadataFileSaver; - // Manual edit occurred // Even if save local is off, save locally anyway if the metadata file already exists - if (fileSaver == null || !File.Exists(fileSaver.GetSavePath(item))) + if (!(saver is IMetadataFileSaver fileSaver) || !File.Exists(fileSaver.GetSavePath(item))) { return false; } @@ -726,6 +777,7 @@ namespace MediaBrowser.Providers.Manager } } + /// <inheritdoc/> public Task<IEnumerable<RemoteSearchResult>> GetRemoteSearchResults<TItemType, TLookupType>(RemoteSearchQuery<TLookupType> searchInfo, CancellationToken cancellationToken) where TItemType : BaseItem, new() where TLookupType : ItemLookupInfo @@ -740,7 +792,7 @@ namespace MediaBrowser.Providers.Manager return GetRemoteSearchResults<TItemType, TLookupType>(searchInfo, referenceItem, cancellationToken); } - public async Task<IEnumerable<RemoteSearchResult>> GetRemoteSearchResults<TItemType, TLookupType>(RemoteSearchQuery<TLookupType> searchInfo, BaseItem referenceItem, CancellationToken cancellationToken) + private async Task<IEnumerable<RemoteSearchResult>> GetRemoteSearchResults<TItemType, TLookupType>(RemoteSearchQuery<TLookupType> searchInfo, BaseItem referenceItem, CancellationToken cancellationToken) where TItemType : BaseItem, new() where TLookupType : ItemLookupInfo { @@ -779,6 +831,7 @@ namespace MediaBrowser.Providers.Manager { searchInfo.SearchInfo.MetadataLanguage = _configurationManager.Configuration.PreferredMetadataLanguage; } + if (string.IsNullOrWhiteSpace(searchInfo.SearchInfo.MetadataCountryCode)) { searchInfo.SearchInfo.MetadataCountryCode = _configurationManager.Configuration.MetadataCountryCode; @@ -823,12 +876,14 @@ namespace MediaBrowser.Providers.Manager } } - //_logger.LogDebug("Returning search results {0}", _json.SerializeToString(resultList)); + // _logger.LogDebug("Returning search results {0}", _json.SerializeToString(resultList)); return resultList; } - private async Task<IEnumerable<RemoteSearchResult>> GetSearchResults<TLookupType>(IRemoteSearchProvider<TLookupType> provider, TLookupType searchInfo, + private async Task<IEnumerable<RemoteSearchResult>> GetSearchResults<TLookupType>( + IRemoteSearchProvider<TLookupType> provider, + TLookupType searchInfo, CancellationToken cancellationToken) where TLookupType : ItemLookupInfo { @@ -844,7 +899,8 @@ namespace MediaBrowser.Providers.Manager return list; } - public Task<HttpResponseInfo> GetSearchImage(string providerName, string url, CancellationToken cancellationToken) + /// <inheritdoc/> + public Task<HttpResponseMessage> GetSearchImage(string providerName, string url, CancellationToken cancellationToken) { var provider = _metadataProviders.OfType<IRemoteSearchProvider>().FirstOrDefault(i => string.Equals(i.Name, providerName, StringComparison.OrdinalIgnoreCase)); @@ -856,7 +912,7 @@ namespace MediaBrowser.Providers.Manager return provider.GetImageResponse(url, cancellationToken); } - public IEnumerable<IExternalId> GetExternalIds(IHasProviderIds item) + private IEnumerable<IExternalId> GetExternalIds(IHasProviderIds item) { return _externalIds.Where(i => { @@ -872,6 +928,7 @@ namespace MediaBrowser.Providers.Manager }); } + /// <inheritdoc/> public IEnumerable<ExternalUrl> GetExternalUrls(BaseItem item) { return GetExternalIds(item) @@ -891,29 +948,29 @@ namespace MediaBrowser.Providers.Manager return new ExternalUrl { - Name = i.Name, + Name = i.ProviderName, Url = string.Format( CultureInfo.InvariantCulture, i.UrlFormatString, value) }; - }).Where(i => i != null).Concat(item.GetRelatedUrls()); } + /// <inheritdoc/> public IEnumerable<ExternalIdInfo> GetExternalIdInfos(IHasProviderIds item) { return GetExternalIds(item) .Select(i => new ExternalIdInfo { - Name = i.Name, + Name = i.ProviderName, Key = i.Key, + Type = i.Type, UrlFormatString = i.UrlFormatString }); } - private ConcurrentDictionary<Guid, double> _activeRefreshes = new ConcurrentDictionary<Guid, double>(); - + /// <inheritdoc/> public Dictionary<Guid, Guid> GetRefreshQueue() { lock (_refreshQueueLock) @@ -929,22 +986,25 @@ namespace MediaBrowser.Providers.Manager } } + /// <inheritdoc/> public void OnRefreshStart(BaseItem item) { - _logger.LogInformation("OnRefreshStart {0}", item.Id.ToString("N", CultureInfo.InvariantCulture)); + _logger.LogDebug("OnRefreshStart {0}", item.Id.ToString("N", CultureInfo.InvariantCulture)); _activeRefreshes[item.Id] = 0; RefreshStarted?.Invoke(this, new GenericEventArgs<BaseItem>(item)); } + /// <inheritdoc/> public void OnRefreshComplete(BaseItem item) { - _logger.LogInformation("OnRefreshComplete {0}", item.Id.ToString("N", CultureInfo.InvariantCulture)); + _logger.LogDebug("OnRefreshComplete {0}", item.Id.ToString("N", CultureInfo.InvariantCulture)); _activeRefreshes.Remove(item.Id, out _); RefreshCompleted?.Invoke(this, new GenericEventArgs<BaseItem>(item)); } + /// <inheritdoc/> public double? GetRefreshProgress(Guid id) { if (_activeRefreshes.TryGetValue(id, out double value)) @@ -955,6 +1015,7 @@ namespace MediaBrowser.Providers.Manager return null; } + /// <inheritdoc/> public void OnRefreshProgress(BaseItem item, double progress) { var id = item.Id; @@ -974,12 +1035,7 @@ namespace MediaBrowser.Providers.Manager RefreshProgress?.Invoke(this, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(item, progress))); } - private readonly SimplePriorityQueue<Tuple<Guid, MetadataRefreshOptions>> _refreshQueue = - new SimplePriorityQueue<Tuple<Guid, MetadataRefreshOptions>>(); - - private readonly object _refreshQueueLock = new object(); - private bool _isProcessingRefreshQueue; - + /// <inheritdoc/> public void QueueRefresh(Guid id, MetadataRefreshOptions options, RefreshPriority priority) { if (_disposed) @@ -1023,7 +1079,7 @@ namespace MediaBrowser.Providers.Manager if (item != null) { // Try to throttle this a little bit. - await Task.Delay(100).ConfigureAwait(false); + await Task.Delay(100, cancellationToken).ConfigureAwait(false); var task = item is MusicArtist artist ? RefreshArtist(artist, refreshItem.Item2, cancellationToken) @@ -1053,17 +1109,14 @@ namespace MediaBrowser.Providers.Manager await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); // Collection folders don't validate their children so we'll have to simulate that here - - if (item is CollectionFolder collectionFolder) + switch (item) { - await RefreshCollectionFolderChildren(options, collectionFolder, cancellationToken).ConfigureAwait(false); - } - else - { - if (item is Folder folder) - { + case CollectionFolder collectionFolder: + await RefreshCollectionFolderChildren(options, collectionFolder, cancellationToken).ConfigureAwait(false); + break; + case Folder folder: await folder.ValidateChildren(new SimpleProgress<double>(), cancellationToken, options).ConfigureAwait(false); - } + break; } } @@ -1073,7 +1126,7 @@ namespace MediaBrowser.Providers.Manager { await child.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); - await child.ValidateChildren(new SimpleProgress<double>(), cancellationToken, options, true).ConfigureAwait(false); + await child.ValidateChildren(new SimpleProgress<double>(), cancellationToken, options).ConfigureAwait(false); } } @@ -1109,20 +1162,41 @@ namespace MediaBrowser.Providers.Manager } } + /// <inheritdoc/> public Task RefreshFullItem(BaseItem item, MetadataRefreshOptions options, CancellationToken cancellationToken) { return RefreshItem(item, options, cancellationToken); } - private bool _disposed; + /// <inheritdoc/> public void Dispose() { - _disposed = true; + Dispose(true); + GC.SuppressFinalize(this); + } + + /// <summary> + /// Releases unmanaged and optionally managed resources. + /// </summary> + /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } if (!_disposeCancellationTokenSource.IsCancellationRequested) { _disposeCancellationTokenSource.Cancel(); } + + if (disposing) + { + _disposeCancellationTokenSource.Dispose(); + } + + _disposed = true; } } } diff --git a/MediaBrowser.Providers/Manager/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs index 8d1588c4eb..70a5a6ac13 100644 --- a/MediaBrowser.Providers/Manager/ProviderUtils.cs +++ b/MediaBrowser.Providers/Manager/ProviderUtils.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Linq; @@ -14,7 +16,7 @@ namespace MediaBrowser.Providers.Manager public static void MergeBaseItemData<T>( MetadataResult<T> sourceResult, MetadataResult<T> targetResult, - MetadataFields[] lockedFields, + MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) where T : BaseItem @@ -24,14 +26,15 @@ namespace MediaBrowser.Providers.Manager if (source == null) { - throw new ArgumentNullException(nameof(source)); + throw new ArgumentException("Item cannot be null.", nameof(sourceResult)); } + if (target == null) { - throw new ArgumentNullException(nameof(target)); + throw new ArgumentException("Item cannot be null.", nameof(targetResult)); } - if (!lockedFields.Contains(MetadataFields.Name)) + if (!lockedFields.Contains(MetadataField.Name)) { if (replaceData || string.IsNullOrEmpty(target.Name)) { @@ -62,7 +65,7 @@ namespace MediaBrowser.Providers.Manager target.EndDate = source.EndDate; } - if (!lockedFields.Contains(MetadataFields.Genres)) + if (!lockedFields.Contains(MetadataField.Genres)) { if (replaceData || target.Genres.Length == 0) { @@ -75,7 +78,7 @@ namespace MediaBrowser.Providers.Manager target.IndexNumber = source.IndexNumber; } - if (!lockedFields.Contains(MetadataFields.OfficialRating)) + if (!lockedFields.Contains(MetadataField.OfficialRating)) { if (replaceData || string.IsNullOrEmpty(target.OfficialRating)) { @@ -93,7 +96,7 @@ namespace MediaBrowser.Providers.Manager target.Tagline = source.Tagline; } - if (!lockedFields.Contains(MetadataFields.Overview)) + if (!lockedFields.Contains(MetadataField.Overview)) { if (replaceData || string.IsNullOrEmpty(target.Overview)) { @@ -106,12 +109,11 @@ namespace MediaBrowser.Providers.Manager target.ParentIndexNumber = source.ParentIndexNumber; } - if (!lockedFields.Contains(MetadataFields.Cast)) + if (!lockedFields.Contains(MetadataField.Cast)) { if (replaceData || targetResult.People == null || targetResult.People.Count == 0) { targetResult.People = sourceResult.People; - } else if (targetResult.People != null && sourceResult.People != null) { @@ -129,7 +131,7 @@ namespace MediaBrowser.Providers.Manager target.ProductionYear = source.ProductionYear; } - if (!lockedFields.Contains(MetadataFields.Runtime)) + if (!lockedFields.Contains(MetadataField.Runtime)) { if (replaceData || !target.RunTimeTicks.HasValue) { @@ -140,7 +142,7 @@ namespace MediaBrowser.Providers.Manager } } - if (!lockedFields.Contains(MetadataFields.Studios)) + if (!lockedFields.Contains(MetadataField.Studios)) { if (replaceData || target.Studios.Length == 0) { @@ -148,7 +150,7 @@ namespace MediaBrowser.Providers.Manager } } - if (!lockedFields.Contains(MetadataFields.Tags)) + if (!lockedFields.Contains(MetadataField.Tags)) { if (replaceData || target.Tags.Length == 0) { @@ -156,7 +158,7 @@ namespace MediaBrowser.Providers.Manager } } - if (!lockedFields.Contains(MetadataFields.ProductionLocations)) + if (!lockedFields.Contains(MetadataField.ProductionLocations)) { if (replaceData || target.ProductionLocations.Length == 0) { diff --git a/MediaBrowser.Providers/Manager/RefreshResult.cs b/MediaBrowser.Providers/Manager/RefreshResult.cs new file mode 100644 index 0000000000..72fc61e424 --- /dev/null +++ b/MediaBrowser.Providers/Manager/RefreshResult.cs @@ -0,0 +1,15 @@ +#pragma warning disable CS1591 + +using MediaBrowser.Controller.Library; + +namespace MediaBrowser.Providers.Manager +{ + public class RefreshResult + { + public ItemUpdateType UpdateType { get; set; } + + public string ErrorMessage { get; set; } + + public int Failures { get; set; } + } +} |
