diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 86a182fe50..98bcd8d31e 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -25,7 +23,6 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Events; using MediaBrowser.Model.IO; using MediaBrowser.Model.Providers; -using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; using Priority_Queue; using Book = MediaBrowser.Controller.Entities.Book; @@ -42,33 +39,38 @@ namespace MediaBrowser.Providers.Manager /// public class ProviderManager : IProviderManager, IDisposable { + private readonly object _refreshQueueLock = new object(); private readonly ILogger _logger; private readonly IHttpClient _httpClient; 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 _activeRefreshes = new ConcurrentDictionary(); + private readonly CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource(); + private readonly SimplePriorityQueue> _refreshQueue = + new SimplePriorityQueue>(); - private IImageProvider[] ImageProviders { get; set; } - - private IMetadataService[] _metadataServices = { }; - private IMetadataProvider[] _metadataProviders = { }; + private IMetadataService[] _metadataServices = Array.Empty(); + private IMetadataProvider[] _metadataProviders = Array.Empty(); private IEnumerable _savers; - private IExternalId[] _externalIds; - - private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource(); - - public event EventHandler> RefreshStarted; - public event EventHandler> RefreshCompleted; - public event EventHandler>> RefreshProgress; + private bool _isProcessingRefreshQueue; + private bool _disposed; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// + /// The Http client. + /// The subtitle manager. + /// The configuration manager. + /// The library monitor. + /// The logger. + /// The filesystem. + /// The server application paths. + /// The library manager. public ProviderManager( IHttpClient httpClient, ISubtitleManager subtitleManager, @@ -77,8 +79,7 @@ namespace MediaBrowser.Providers.Manager ILogger logger, IFileSystem fileSystem, IServerApplicationPaths appPaths, - ILibraryManager libraryManager, - IJsonSerializer json) + ILibraryManager libraryManager) { _logger = logger; _httpClient = httpClient; @@ -87,16 +88,27 @@ namespace MediaBrowser.Providers.Manager _fileSystem = fileSystem; _appPaths = appPaths; _libraryManager = libraryManager; - _json = json; _subtitleManager = subtitleManager; } - /// - /// Adds the metadata providers. - /// - public void AddParts(IEnumerable imageProviders, IEnumerable metadataServices, - IEnumerable metadataProviders, IEnumerable metadataSavers, - IEnumerable externalIds) + /// + public event EventHandler> RefreshStarted; + + /// + public event EventHandler> RefreshCompleted; + + /// + public event EventHandler>> RefreshProgress; + + private IImageProvider[] ImageProviders { get; set; } + + /// + public void AddParts( + IEnumerable imageProviders, + IEnumerable metadataServices, + IEnumerable metadataProviders, + IEnumerable metadataSavers, + IEnumerable externalIds) { ImageProviders = imageProviders.ToArray(); @@ -104,27 +116,17 @@ namespace MediaBrowser.Providers.Manager _metadataProviders = metadataProviders.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(); } + /// public Task 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) { @@ -147,35 +149,36 @@ namespace MediaBrowser.Providers.Manager return Task.FromResult(ItemUpdateType.None); } + /// public async Task SaveImage(BaseItem item, string url, ImageType type, int? imageIndex, CancellationToken cancellationToken) { - using (var response = await _httpClient.GetResponse(new HttpRequestOptions + using var response = await _httpClient.GetResponse(new HttpRequestOptions { CancellationToken = cancellationToken, Url = url, BufferContent = false + }).ConfigureAwait(false); - }).ConfigureAwait(false)) + // Workaround for tvheadend channel icons + // TODO: Isolate this hack into the tvh plugin + if (string.IsNullOrEmpty(response.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"; - } + response.ContentType = "image/png"; } - - await SaveImage(item, response.Content, response.ContentType, type, imageIndex, cancellationToken).ConfigureAwait(false); } + + await SaveImage(item, response.Content, response.ContentType, type, imageIndex, cancellationToken).ConfigureAwait(false); } + /// 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); } + /// public Task SaveImage(BaseItem item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(source)) @@ -188,12 +191,14 @@ namespace MediaBrowser.Providers.Manager return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, fileStream, mimeType, type, imageIndex, saveLocallyWithMedia, cancellationToken); } + /// public Task SaveImage(User user, Stream source, string mimeType, string path) { return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger) .SaveImage(user, source, path); } + /// public async Task> GetAvailableRemoteImages(BaseItem item, RemoteImageQuery query, CancellationToken cancellationToken) { var providers = GetRemoteImageProviders(item, query.IncludeDisabledProviders); @@ -213,7 +218,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); @@ -224,12 +229,17 @@ namespace MediaBrowser.Providers.Manager /// Gets the images. /// /// The item. - /// The cancellation token. /// The provider. /// The preferred languages. + /// The cancellation token. /// The type. /// Task{IEnumerable{RemoteImageInfo}}. - private async Task> GetImages(BaseItem item, CancellationToken cancellationToken, IRemoteImageProvider provider, List preferredLanguages, ImageType? type = null) + private async Task> GetImages( + BaseItem item, + IRemoteImageProvider provider, + IReadOnlyCollection preferredLanguages, + CancellationToken cancellationToken, + ImageType? type = null) { try { @@ -260,11 +270,7 @@ namespace MediaBrowser.Providers.Manager } } - /// - /// Gets the supported image providers. - /// - /// The item. - /// IEnumerable{IImageProvider}. + /// public IEnumerable GetRemoteImageProviderInfo(BaseItem item) { return GetRemoteImageProviders(item, true).Select(i => new ImageProviderInfo(i.Name, i.GetSupportedImages(item).ToArray())); @@ -283,7 +289,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 @@ -319,7 +325,7 @@ namespace MediaBrowser.Providers.Manager var currentOptions = globalMetadataOptions; return _metadataProviders.OfType>() - .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); } @@ -329,14 +335,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(); + return GetImageProviders( + item, + libraryOptions, + options, + new ImageRefreshOptions(new DirectoryService(_fileSystem)), + includeDisabled).OfType(); } - 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) { @@ -372,7 +384,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) { @@ -412,9 +429,7 @@ namespace MediaBrowser.Providers.Manager /// System.Int32. private int GetOrder(IImageProvider provider) { - var hasOrder = provider as IHasOrder; - - if (hasOrder == null) + if (!(provider is IHasOrder hasOrder)) { return 0; } @@ -441,7 +456,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; @@ -459,9 +474,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; } @@ -469,9 +482,10 @@ namespace MediaBrowser.Providers.Manager return 0; } + /// public MetadataPluginSummary[] GetAllMetadataPlugins() { - return new MetadataPluginSummary[] + return new[] { GetPluginSummary(), GetPluginSummary(), @@ -493,7 +507,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() @@ -508,11 +522,12 @@ 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(); @@ -572,7 +587,6 @@ namespace MediaBrowser.Providers.Manager private void AddImagePlugins(List list, T item, List imageProviders) where T : BaseItem { - // Locals list.AddRange(imageProviders.Where(i => (i is ILocalImageProvider)).Select(i => new MetadataPlugin { @@ -588,6 +602,7 @@ namespace MediaBrowser.Providers.Manager })); } + /// public MetadataOptions GetMetadataOptions(BaseItem item) { var type = item.GetType().Name; @@ -597,17 +612,13 @@ namespace MediaBrowser.Providers.Manager new MetadataOptions(); } - /// - /// Saves the metadata. - /// + /// public void SaveMetadata(BaseItem item, ItemUpdateType updateType) { SaveMetadata(item, updateType, _savers); } - /// - /// Saves the metadata. - /// + /// public void SaveMetadata(BaseItem item, ItemUpdateType updateType, IEnumerable savers) { SaveMetadata(item, updateType, _savers.Where(i => savers.Contains(i.Name, StringComparer.OrdinalIgnoreCase))); @@ -619,7 +630,6 @@ namespace MediaBrowser.Providers.Manager /// The item. /// Type of the update. /// The savers. - /// Task. private void SaveMetadata(BaseItem item, ItemUpdateType updateType, IEnumerable savers) { var libraryOptions = _libraryManager.GetLibraryOptions(item); @@ -628,11 +638,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 { @@ -699,11 +707,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; } @@ -734,6 +740,7 @@ namespace MediaBrowser.Providers.Manager } } + /// public Task> GetRemoteSearchResults(RemoteSearchQuery searchInfo, CancellationToken cancellationToken) where TItemType : BaseItem, new() where TLookupType : ItemLookupInfo @@ -748,7 +755,7 @@ namespace MediaBrowser.Providers.Manager return GetRemoteSearchResults(searchInfo, referenceItem, cancellationToken); } - public async Task> GetRemoteSearchResults(RemoteSearchQuery searchInfo, BaseItem referenceItem, CancellationToken cancellationToken) + private async Task> GetRemoteSearchResults(RemoteSearchQuery searchInfo, BaseItem referenceItem, CancellationToken cancellationToken) where TItemType : BaseItem, new() where TLookupType : ItemLookupInfo { @@ -837,7 +844,9 @@ namespace MediaBrowser.Providers.Manager return resultList; } - private async Task> GetSearchResults(IRemoteSearchProvider provider, TLookupType searchInfo, + private async Task> GetSearchResults( + IRemoteSearchProvider provider, + TLookupType searchInfo, CancellationToken cancellationToken) where TLookupType : ItemLookupInfo { @@ -853,6 +862,7 @@ namespace MediaBrowser.Providers.Manager return list; } + /// public Task GetSearchImage(string providerName, string url, CancellationToken cancellationToken) { var provider = _metadataProviders.OfType().FirstOrDefault(i => string.Equals(i.Name, providerName, StringComparison.OrdinalIgnoreCase)); @@ -865,6 +875,7 @@ namespace MediaBrowser.Providers.Manager return provider.GetImageResponse(url, cancellationToken); } + /// public IEnumerable GetExternalIds(IHasProviderIds item) { return _externalIds.Where(i => @@ -881,6 +892,7 @@ namespace MediaBrowser.Providers.Manager }); } + /// public IEnumerable GetExternalUrls(BaseItem item) { return GetExternalIds(item) @@ -909,6 +921,7 @@ namespace MediaBrowser.Providers.Manager }).Where(i => i != null).Concat(item.GetRelatedUrls()); } + /// public IEnumerable GetExternalIdInfos(IHasProviderIds item) { return GetExternalIds(item) @@ -921,8 +934,7 @@ namespace MediaBrowser.Providers.Manager }); } - private ConcurrentDictionary _activeRefreshes = new ConcurrentDictionary(); - + /// public Dictionary GetRefreshQueue() { lock (_refreshQueueLock) @@ -938,6 +950,7 @@ namespace MediaBrowser.Providers.Manager } } + /// public void OnRefreshStart(BaseItem item) { _logger.LogInformation("OnRefreshStart {0}", item.Id.ToString("N", CultureInfo.InvariantCulture)); @@ -945,6 +958,7 @@ namespace MediaBrowser.Providers.Manager RefreshStarted?.Invoke(this, new GenericEventArgs(item)); } + /// public void OnRefreshComplete(BaseItem item) { _logger.LogInformation("OnRefreshComplete {0}", item.Id.ToString("N", CultureInfo.InvariantCulture)); @@ -954,6 +968,7 @@ namespace MediaBrowser.Providers.Manager RefreshCompleted?.Invoke(this, new GenericEventArgs(item)); } + /// public double? GetRefreshProgress(Guid id) { if (_activeRefreshes.TryGetValue(id, out double value)) @@ -964,6 +979,7 @@ namespace MediaBrowser.Providers.Manager return null; } + /// public void OnRefreshProgress(BaseItem item, double progress) { var id = item.Id; @@ -983,12 +999,7 @@ namespace MediaBrowser.Providers.Manager RefreshProgress?.Invoke(this, new GenericEventArgs>(new Tuple(item, progress))); } - private readonly SimplePriorityQueue> _refreshQueue = - new SimplePriorityQueue>(); - - private readonly object _refreshQueueLock = new object(); - private bool _isProcessingRefreshQueue; - + /// public void QueueRefresh(Guid id, MetadataRefreshOptions options, RefreshPriority priority) { if (_disposed) @@ -1032,7 +1043,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) @@ -1062,17 +1073,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(), cancellationToken, options).ConfigureAwait(false); - } + break; } } @@ -1082,7 +1090,7 @@ namespace MediaBrowser.Providers.Manager { await child.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); - await child.ValidateChildren(new SimpleProgress(), cancellationToken, options, true).ConfigureAwait(false); + await child.ValidateChildren(new SimpleProgress(), cancellationToken, options).ConfigureAwait(false); } } @@ -1118,12 +1126,13 @@ namespace MediaBrowser.Providers.Manager } } + /// public Task RefreshFullItem(BaseItem item, MetadataRefreshOptions options, CancellationToken cancellationToken) { return RefreshItem(item, options, cancellationToken); } - private bool _disposed; + /// public void Dispose() { _disposed = true;