Clean up ProviderManager.cs

This commit is contained in:
Patrick Barron 2020-07-03 14:02:04 -04:00
parent c8539709ac
commit 3fdbdf4078

View file

@ -1,5 +1,3 @@
#pragma warning disable CS1591
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
@ -25,7 +23,6 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Events; using MediaBrowser.Model.Events;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.Providers; using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Serialization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Priority_Queue; using Priority_Queue;
using Book = MediaBrowser.Controller.Entities.Book; using Book = MediaBrowser.Controller.Entities.Book;
@ -42,33 +39,38 @@ namespace MediaBrowser.Providers.Manager
/// </summary> /// </summary>
public class ProviderManager : IProviderManager, IDisposable public class ProviderManager : IProviderManager, IDisposable
{ {
private readonly object _refreshQueueLock = new object();
private readonly ILogger<ProviderManager> _logger; private readonly ILogger<ProviderManager> _logger;
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly ILibraryMonitor _libraryMonitor; private readonly ILibraryMonitor _libraryMonitor;
private readonly IFileSystem _fileSystem; private readonly IFileSystem _fileSystem;
private readonly IServerApplicationPaths _appPaths; private readonly IServerApplicationPaths _appPaths;
private readonly IJsonSerializer _json;
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
private readonly ISubtitleManager _subtitleManager; private readonly ISubtitleManager _subtitleManager;
private readonly IServerConfigurationManager _configurationManager; 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 = Array.Empty<IMetadataService>();
private IMetadataProvider[] _metadataProviders = Array.Empty<IMetadataProvider>();
private IMetadataService[] _metadataServices = { };
private IMetadataProvider[] _metadataProviders = { };
private IEnumerable<IMetadataSaver> _savers; private IEnumerable<IMetadataSaver> _savers;
private IExternalId[] _externalIds; private IExternalId[] _externalIds;
private bool _isProcessingRefreshQueue;
private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource(); private bool _disposed;
public event EventHandler<GenericEventArgs<BaseItem>> RefreshStarted;
public event EventHandler<GenericEventArgs<BaseItem>> RefreshCompleted;
public event EventHandler<GenericEventArgs<Tuple<BaseItem, double>>> RefreshProgress;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ProviderManager" /> class. /// Initializes a new instance of the <see cref="ProviderManager"/> class.
/// </summary> /// </summary>
/// <param name="httpClient">The Http client.</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( public ProviderManager(
IHttpClient httpClient, IHttpClient httpClient,
ISubtitleManager subtitleManager, ISubtitleManager subtitleManager,
@ -77,8 +79,7 @@ namespace MediaBrowser.Providers.Manager
ILogger<ProviderManager> logger, ILogger<ProviderManager> logger,
IFileSystem fileSystem, IFileSystem fileSystem,
IServerApplicationPaths appPaths, IServerApplicationPaths appPaths,
ILibraryManager libraryManager, ILibraryManager libraryManager)
IJsonSerializer json)
{ {
_logger = logger; _logger = logger;
_httpClient = httpClient; _httpClient = httpClient;
@ -87,16 +88,27 @@ namespace MediaBrowser.Providers.Manager
_fileSystem = fileSystem; _fileSystem = fileSystem;
_appPaths = appPaths; _appPaths = appPaths;
_libraryManager = libraryManager; _libraryManager = libraryManager;
_json = json;
_subtitleManager = subtitleManager; _subtitleManager = subtitleManager;
} }
/// <summary> /// <inheritdoc/>
/// Adds the metadata providers. public event EventHandler<GenericEventArgs<BaseItem>> RefreshStarted;
/// </summary>
public void AddParts(IEnumerable<IImageProvider> imageProviders, IEnumerable<IMetadataService> metadataServices, /// <inheritdoc/>
IEnumerable<IMetadataProvider> metadataProviders, IEnumerable<IMetadataSaver> metadataSavers, public event EventHandler<GenericEventArgs<BaseItem>> RefreshCompleted;
IEnumerable<IExternalId> externalIds)
/// <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(); ImageProviders = imageProviders.ToArray();
@ -104,27 +116,17 @@ namespace MediaBrowser.Providers.Manager
_metadataProviders = metadataProviders.ToArray(); _metadataProviders = metadataProviders.ToArray();
_externalIds = externalIds.OrderBy(i => i.ProviderName).ToArray(); _externalIds = externalIds.OrderBy(i => i.ProviderName).ToArray();
_savers = metadataSavers.Where(i => _savers = metadataSavers
{ .Where(i => !(i is IConfigurableProvider configurable) || configurable.IsEnabled)
var configurable = i as IConfigurableProvider; .ToArray();
return configurable == null || configurable.IsEnabled;
}).ToArray();
} }
/// <inheritdoc/>
public Task<ItemUpdateType> RefreshSingleItem(BaseItem item, MetadataRefreshOptions options, CancellationToken cancellationToken) public Task<ItemUpdateType> RefreshSingleItem(BaseItem item, MetadataRefreshOptions options, CancellationToken cancellationToken)
{ {
IMetadataService service = null;
var type = item.GetType(); var type = item.GetType();
foreach (var current in _metadataServices) var service = _metadataServices.FirstOrDefault(current => current.CanRefreshPrimary(type));
{
if (current.CanRefreshPrimary(type))
{
service = current;
break;
}
}
if (service == null) if (service == null)
{ {
@ -147,35 +149,36 @@ namespace MediaBrowser.Providers.Manager
return Task.FromResult(ItemUpdateType.None); return Task.FromResult(ItemUpdateType.None);
} }
/// <inheritdoc/>
public async Task SaveImage(BaseItem item, string url, ImageType type, int? imageIndex, CancellationToken cancellationToken) 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, CancellationToken = cancellationToken,
Url = url, Url = url,
BufferContent = false 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 if (url.IndexOf("/imagecache/", StringComparison.OrdinalIgnoreCase) != -1)
// TODO: Isolate this hack into the tvh plugin
if (string.IsNullOrEmpty(response.ContentType))
{ {
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);
} }
/// <inheritdoc/>
public Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken) 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); 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) public Task SaveImage(BaseItem item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken)
{ {
if (string.IsNullOrWhiteSpace(source)) 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); return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, fileStream, mimeType, type, imageIndex, saveLocallyWithMedia, cancellationToken);
} }
/// <inheritdoc/>
public Task SaveImage(User user, Stream source, string mimeType, string path) public Task SaveImage(User user, Stream source, string mimeType, string path)
{ {
return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger) return new ImageSaver(_configurationManager, _libraryMonitor, _fileSystem, _logger)
.SaveImage(user, source, path); .SaveImage(user, source, path);
} }
/// <inheritdoc/>
public async Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(BaseItem item, RemoteImageQuery query, CancellationToken cancellationToken) public async Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(BaseItem item, RemoteImageQuery query, CancellationToken cancellationToken)
{ {
var providers = GetRemoteImageProviders(item, query.IncludeDisabledProviders); var providers = GetRemoteImageProviders(item, query.IncludeDisabledProviders);
@ -213,7 +218,7 @@ namespace MediaBrowser.Providers.Manager
languages.Add(preferredLanguage); 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); var results = await Task.WhenAll(tasks).ConfigureAwait(false);
@ -224,12 +229,17 @@ namespace MediaBrowser.Providers.Manager
/// Gets the images. /// Gets the images.
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="provider">The provider.</param> /// <param name="provider">The provider.</param>
/// <param name="preferredLanguages">The preferred languages.</param> /// <param name="preferredLanguages">The preferred languages.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="type">The type.</param> /// <param name="type">The type.</param>
/// <returns>Task{IEnumerable{RemoteImageInfo}}.</returns> /// <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 try
{ {
@ -260,11 +270,7 @@ namespace MediaBrowser.Providers.Manager
} }
} }
/// <summary> /// <inheritdoc/>
/// Gets the supported image providers.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>IEnumerable{IImageProvider}.</returns>
public IEnumerable<ImageProviderInfo> GetRemoteImageProviderInfo(BaseItem item) public IEnumerable<ImageProviderInfo> GetRemoteImageProviderInfo(BaseItem item)
{ {
return GetRemoteImageProviders(item, true).Select(i => new ImageProviderInfo(i.Name, i.GetSupportedImages(item).ToArray())); 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 typeOptions = libraryOptions.GetTypeOptions(item.GetType().Name);
var typeFetcherOrder = typeOptions?.ImageFetcherOrder; 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 => .OrderBy(i =>
{ {
// See if there's a user-defined order // See if there's a user-defined order
@ -319,7 +325,7 @@ namespace MediaBrowser.Providers.Manager
var currentOptions = globalMetadataOptions; var currentOptions = globalMetadataOptions;
return _metadataProviders.OfType<IMetadataProvider<T>>() 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)) .OrderBy(i => GetConfiguredOrder(item, i, libraryOptions, globalMetadataOptions))
.ThenBy(GetDefaultOrder); .ThenBy(GetDefaultOrder);
} }
@ -329,14 +335,20 @@ namespace MediaBrowser.Providers.Manager
var options = GetMetadataOptions(item); var options = GetMetadataOptions(item);
var libraryOptions = _libraryManager.GetLibraryOptions(item); var libraryOptions = _libraryManager.GetLibraryOptions(item);
return GetImageProviders(item, libraryOptions, options, return GetImageProviders(
new ImageRefreshOptions( item,
new DirectoryService(_fileSystem)), libraryOptions,
includeDisabled) options,
.OfType<IRemoteImageProvider>(); 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) if (!includeDisabled)
{ {
@ -372,7 +384,12 @@ namespace MediaBrowser.Providers.Manager
return true; 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) if (!includeDisabled)
{ {
@ -412,9 +429,7 @@ namespace MediaBrowser.Providers.Manager
/// <returns>System.Int32.</returns> /// <returns>System.Int32.</returns>
private int GetOrder(IImageProvider provider) private int GetOrder(IImageProvider provider)
{ {
var hasOrder = provider as IHasOrder; if (!(provider is IHasOrder hasOrder))
if (hasOrder == null)
{ {
return 0; return 0;
} }
@ -441,7 +456,7 @@ namespace MediaBrowser.Providers.Manager
if (provider is IRemoteMetadataProvider) if (provider is IRemoteMetadataProvider)
{ {
var typeOptions = libraryOptions.GetTypeOptions(item.GetType().Name); var typeOptions = libraryOptions.GetTypeOptions(item.GetType().Name);
var typeFetcherOrder = typeOptions == null ? null : typeOptions.MetadataFetcherOrder; var typeFetcherOrder = typeOptions?.MetadataFetcherOrder;
var fetcherOrder = typeFetcherOrder ?? globalMetadataOptions.MetadataFetcherOrder; var fetcherOrder = typeFetcherOrder ?? globalMetadataOptions.MetadataFetcherOrder;
@ -459,9 +474,7 @@ namespace MediaBrowser.Providers.Manager
private int GetDefaultOrder(IMetadataProvider provider) private int GetDefaultOrder(IMetadataProvider provider)
{ {
var hasOrder = provider as IHasOrder; if (provider is IHasOrder hasOrder)
if (hasOrder != null)
{ {
return hasOrder.Order; return hasOrder.Order;
} }
@ -469,9 +482,10 @@ namespace MediaBrowser.Providers.Manager
return 0; return 0;
} }
/// <inheritdoc/>
public MetadataPluginSummary[] GetAllMetadataPlugins() public MetadataPluginSummary[] GetAllMetadataPlugins()
{ {
return new MetadataPluginSummary[] return new[]
{ {
GetPluginSummary<Movie>(), GetPluginSummary<Movie>(),
GetPluginSummary<BoxSet>(), GetPluginSummary<BoxSet>(),
@ -493,7 +507,7 @@ namespace MediaBrowser.Providers.Manager
where T : BaseItem, new() where T : BaseItem, new()
{ {
// Give it a dummy path just so that it looks like a file system item // 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"), Path = Path.Combine(_appPaths.InternalMetadataPath, "dummy"),
ParentId = Guid.NewGuid() ParentId = Guid.NewGuid()
@ -508,11 +522,12 @@ namespace MediaBrowser.Providers.Manager
var libraryOptions = new LibraryOptions(); var libraryOptions = new LibraryOptions();
var imageProviders = GetImageProviders(dummy, libraryOptions, options, var imageProviders = GetImageProviders(
new ImageRefreshOptions( dummy,
new DirectoryService(_fileSystem)), libraryOptions,
true) options,
.ToList(); new ImageRefreshOptions(new DirectoryService(_fileSystem)),
true).ToList();
var pluginList = summary.Plugins.ToList(); var pluginList = summary.Plugins.ToList();
@ -572,7 +587,6 @@ namespace MediaBrowser.Providers.Manager
private void AddImagePlugins<T>(List<MetadataPlugin> list, T item, List<IImageProvider> imageProviders) private void AddImagePlugins<T>(List<MetadataPlugin> list, T item, List<IImageProvider> imageProviders)
where T : BaseItem where T : BaseItem
{ {
// Locals // 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
{ {
@ -588,6 +602,7 @@ namespace MediaBrowser.Providers.Manager
})); }));
} }
/// <inheritdoc/>
public MetadataOptions GetMetadataOptions(BaseItem item) public MetadataOptions GetMetadataOptions(BaseItem item)
{ {
var type = item.GetType().Name; var type = item.GetType().Name;
@ -597,17 +612,13 @@ namespace MediaBrowser.Providers.Manager
new MetadataOptions(); new MetadataOptions();
} }
/// <summary> /// <inheritdoc/>
/// Saves the metadata.
/// </summary>
public void SaveMetadata(BaseItem item, ItemUpdateType updateType) public void SaveMetadata(BaseItem item, ItemUpdateType updateType)
{ {
SaveMetadata(item, updateType, _savers); SaveMetadata(item, updateType, _savers);
} }
/// <summary> /// <inheritdoc/>
/// Saves the metadata.
/// </summary>
public void SaveMetadata(BaseItem item, ItemUpdateType updateType, IEnumerable<string> savers) public void SaveMetadata(BaseItem item, ItemUpdateType updateType, IEnumerable<string> savers)
{ {
SaveMetadata(item, updateType, _savers.Where(i => savers.Contains(i.Name, StringComparer.OrdinalIgnoreCase))); SaveMetadata(item, updateType, _savers.Where(i => savers.Contains(i.Name, StringComparer.OrdinalIgnoreCase)));
@ -619,7 +630,6 @@ namespace MediaBrowser.Providers.Manager
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="updateType">Type of the update.</param> /// <param name="updateType">Type of the update.</param>
/// <param name="savers">The savers.</param> /// <param name="savers">The savers.</param>
/// <returns>Task.</returns>
private void SaveMetadata(BaseItem item, ItemUpdateType updateType, IEnumerable<IMetadataSaver> savers) private void SaveMetadata(BaseItem item, ItemUpdateType updateType, IEnumerable<IMetadataSaver> savers)
{ {
var libraryOptions = _libraryManager.GetLibraryOptions(item); 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); _logger.LogDebug("Saving {0} to {1}.", item.Path ?? item.Name, saver.Name);
var fileSaver = saver as IMetadataFileSaver; if (saver is IMetadataFileSaver fileSaver)
if (fileSaver != null)
{ {
string path = null; string path;
try try
{ {
@ -699,11 +707,9 @@ namespace MediaBrowser.Providers.Manager
{ {
if (updateType >= ItemUpdateType.MetadataEdit) if (updateType >= ItemUpdateType.MetadataEdit)
{ {
var fileSaver = saver as IMetadataFileSaver;
// Manual edit occurred // Manual edit occurred
// Even if save local is off, save locally anyway if the metadata file already exists // 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; return false;
} }
@ -734,6 +740,7 @@ namespace MediaBrowser.Providers.Manager
} }
} }
/// <inheritdoc/>
public Task<IEnumerable<RemoteSearchResult>> GetRemoteSearchResults<TItemType, TLookupType>(RemoteSearchQuery<TLookupType> searchInfo, CancellationToken cancellationToken) public Task<IEnumerable<RemoteSearchResult>> GetRemoteSearchResults<TItemType, TLookupType>(RemoteSearchQuery<TLookupType> searchInfo, CancellationToken cancellationToken)
where TItemType : BaseItem, new() where TItemType : BaseItem, new()
where TLookupType : ItemLookupInfo where TLookupType : ItemLookupInfo
@ -748,7 +755,7 @@ namespace MediaBrowser.Providers.Manager
return GetRemoteSearchResults<TItemType, TLookupType>(searchInfo, referenceItem, cancellationToken); 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 TItemType : BaseItem, new()
where TLookupType : ItemLookupInfo where TLookupType : ItemLookupInfo
{ {
@ -837,7 +844,9 @@ namespace MediaBrowser.Providers.Manager
return 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) CancellationToken cancellationToken)
where TLookupType : ItemLookupInfo where TLookupType : ItemLookupInfo
{ {
@ -853,6 +862,7 @@ namespace MediaBrowser.Providers.Manager
return list; return list;
} }
/// <inheritdoc/>
public Task<HttpResponseInfo> GetSearchImage(string providerName, string url, CancellationToken cancellationToken) public Task<HttpResponseInfo> GetSearchImage(string providerName, string url, CancellationToken cancellationToken)
{ {
var provider = _metadataProviders.OfType<IRemoteSearchProvider>().FirstOrDefault(i => string.Equals(i.Name, providerName, StringComparison.OrdinalIgnoreCase)); var provider = _metadataProviders.OfType<IRemoteSearchProvider>().FirstOrDefault(i => string.Equals(i.Name, providerName, StringComparison.OrdinalIgnoreCase));
@ -865,6 +875,7 @@ namespace MediaBrowser.Providers.Manager
return provider.GetImageResponse(url, cancellationToken); return provider.GetImageResponse(url, cancellationToken);
} }
/// <inheritdoc/>
public IEnumerable<IExternalId> GetExternalIds(IHasProviderIds item) public IEnumerable<IExternalId> GetExternalIds(IHasProviderIds item)
{ {
return _externalIds.Where(i => return _externalIds.Where(i =>
@ -881,6 +892,7 @@ namespace MediaBrowser.Providers.Manager
}); });
} }
/// <inheritdoc/>
public IEnumerable<ExternalUrl> GetExternalUrls(BaseItem item) public IEnumerable<ExternalUrl> GetExternalUrls(BaseItem item)
{ {
return GetExternalIds(item) return GetExternalIds(item)
@ -909,6 +921,7 @@ namespace MediaBrowser.Providers.Manager
}).Where(i => i != null).Concat(item.GetRelatedUrls()); }).Where(i => i != null).Concat(item.GetRelatedUrls());
} }
/// <inheritdoc/>
public IEnumerable<ExternalIdInfo> GetExternalIdInfos(IHasProviderIds item) public IEnumerable<ExternalIdInfo> GetExternalIdInfos(IHasProviderIds item)
{ {
return GetExternalIds(item) return GetExternalIds(item)
@ -921,8 +934,7 @@ namespace MediaBrowser.Providers.Manager
}); });
} }
private ConcurrentDictionary<Guid, double> _activeRefreshes = new ConcurrentDictionary<Guid, double>(); /// <inheritdoc/>
public Dictionary<Guid, Guid> GetRefreshQueue() public Dictionary<Guid, Guid> GetRefreshQueue()
{ {
lock (_refreshQueueLock) lock (_refreshQueueLock)
@ -938,6 +950,7 @@ namespace MediaBrowser.Providers.Manager
} }
} }
/// <inheritdoc/>
public void OnRefreshStart(BaseItem item) public void OnRefreshStart(BaseItem item)
{ {
_logger.LogInformation("OnRefreshStart {0}", item.Id.ToString("N", CultureInfo.InvariantCulture)); _logger.LogInformation("OnRefreshStart {0}", item.Id.ToString("N", CultureInfo.InvariantCulture));
@ -945,6 +958,7 @@ namespace MediaBrowser.Providers.Manager
RefreshStarted?.Invoke(this, new GenericEventArgs<BaseItem>(item)); RefreshStarted?.Invoke(this, new GenericEventArgs<BaseItem>(item));
} }
/// <inheritdoc/>
public void OnRefreshComplete(BaseItem item) public void OnRefreshComplete(BaseItem item)
{ {
_logger.LogInformation("OnRefreshComplete {0}", item.Id.ToString("N", CultureInfo.InvariantCulture)); _logger.LogInformation("OnRefreshComplete {0}", item.Id.ToString("N", CultureInfo.InvariantCulture));
@ -954,6 +968,7 @@ namespace MediaBrowser.Providers.Manager
RefreshCompleted?.Invoke(this, new GenericEventArgs<BaseItem>(item)); RefreshCompleted?.Invoke(this, new GenericEventArgs<BaseItem>(item));
} }
/// <inheritdoc/>
public double? GetRefreshProgress(Guid id) public double? GetRefreshProgress(Guid id)
{ {
if (_activeRefreshes.TryGetValue(id, out double value)) if (_activeRefreshes.TryGetValue(id, out double value))
@ -964,6 +979,7 @@ namespace MediaBrowser.Providers.Manager
return null; return null;
} }
/// <inheritdoc/>
public void OnRefreshProgress(BaseItem item, double progress) public void OnRefreshProgress(BaseItem item, double progress)
{ {
var id = item.Id; var id = item.Id;
@ -983,12 +999,7 @@ namespace MediaBrowser.Providers.Manager
RefreshProgress?.Invoke(this, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(item, progress))); RefreshProgress?.Invoke(this, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(item, progress)));
} }
private readonly SimplePriorityQueue<Tuple<Guid, MetadataRefreshOptions>> _refreshQueue = /// <inheritdoc/>
new SimplePriorityQueue<Tuple<Guid, MetadataRefreshOptions>>();
private readonly object _refreshQueueLock = new object();
private bool _isProcessingRefreshQueue;
public void QueueRefresh(Guid id, MetadataRefreshOptions options, RefreshPriority priority) public void QueueRefresh(Guid id, MetadataRefreshOptions options, RefreshPriority priority)
{ {
if (_disposed) if (_disposed)
@ -1032,7 +1043,7 @@ namespace MediaBrowser.Providers.Manager
if (item != null) if (item != null)
{ {
// Try to throttle this a little bit. // 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 var task = item is MusicArtist artist
? RefreshArtist(artist, refreshItem.Item2, cancellationToken) ? RefreshArtist(artist, refreshItem.Item2, cancellationToken)
@ -1062,17 +1073,14 @@ namespace MediaBrowser.Providers.Manager
await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false);
// Collection folders don't validate their children so we'll have to simulate that here // Collection folders don't validate their children so we'll have to simulate that here
switch (item)
if (item is CollectionFolder collectionFolder)
{ {
await RefreshCollectionFolderChildren(options, collectionFolder, cancellationToken).ConfigureAwait(false); case CollectionFolder collectionFolder:
} await RefreshCollectionFolderChildren(options, collectionFolder, cancellationToken).ConfigureAwait(false);
else break;
{ case Folder folder:
if (item is Folder folder)
{
await folder.ValidateChildren(new SimpleProgress<double>(), cancellationToken, options).ConfigureAwait(false); await folder.ValidateChildren(new SimpleProgress<double>(), cancellationToken, options).ConfigureAwait(false);
} break;
} }
} }
@ -1082,7 +1090,7 @@ namespace MediaBrowser.Providers.Manager
{ {
await child.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); 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);
} }
} }
@ -1118,12 +1126,13 @@ namespace MediaBrowser.Providers.Manager
} }
} }
/// <inheritdoc/>
public Task RefreshFullItem(BaseItem item, MetadataRefreshOptions options, CancellationToken cancellationToken) public Task RefreshFullItem(BaseItem item, MetadataRefreshOptions options, CancellationToken cancellationToken)
{ {
return RefreshItem(item, options, cancellationToken); return RefreshItem(item, options, cancellationToken);
} }
private bool _disposed; /// <inheritdoc/>
public void Dispose() public void Dispose()
{ {
_disposed = true; _disposed = true;