aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Providers/Manager/ProviderManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Providers/Manager/ProviderManager.cs')
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs171
1 files changed, 163 insertions, 8 deletions
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index 823c34a75..c9ae47ad0 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -26,7 +26,7 @@ namespace MediaBrowser.Providers.Manager
/// <summary>
/// Class ProviderManager
/// </summary>
- public class ProviderManager : IProviderManager
+ public class ProviderManager : IProviderManager, IDisposable
{
/// <summary>
/// The _logger
@@ -63,6 +63,8 @@ namespace MediaBrowser.Providers.Manager
private IExternalId[] _externalIds;
+ private readonly Func<ILibraryManager> _libraryManagerFactory;
+
/// <summary>
/// Initializes a new instance of the <see cref="ProviderManager" /> class.
/// </summary>
@@ -71,7 +73,7 @@ namespace MediaBrowser.Providers.Manager
/// <param name="libraryMonitor">The directory watchers.</param>
/// <param name="logManager">The log manager.</param>
/// <param name="fileSystem">The file system.</param>
- public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILogManager logManager, IFileSystem fileSystem, IServerApplicationPaths appPaths)
+ public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILogManager logManager, IFileSystem fileSystem, IServerApplicationPaths appPaths, Func<ILibraryManager> libraryManagerFactory)
{
_logger = logManager.GetLogger("ProviderManager");
_httpClient = httpClient;
@@ -79,6 +81,7 @@ namespace MediaBrowser.Providers.Manager
_libraryMonitor = libraryMonitor;
_fileSystem = fileSystem;
_appPaths = appPaths;
+ _libraryManagerFactory = libraryManagerFactory;
}
/// <summary>
@@ -108,7 +111,7 @@ namespace MediaBrowser.Providers.Manager
_externalIds = externalIds.OrderBy(i => i.Name).ToArray();
}
- public Task RefreshMetadata(IHasMetadata item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ public Task<ItemUpdateType> RefreshSingleItem(IHasMetadata item, MetadataRefreshOptions options, CancellationToken cancellationToken)
{
var service = _metadataServices.FirstOrDefault(i => i.CanRefresh(item));
@@ -118,7 +121,7 @@ namespace MediaBrowser.Providers.Manager
}
_logger.Error("Unable to find a metadata service for item of type " + item.GetType().Name);
- return Task.FromResult(true);
+ return Task.FromResult(ItemUpdateType.None);
}
public async Task SaveImage(IHasImages item, string url, SemaphoreSlim resourcePool, ImageType type, int? imageIndex, CancellationToken cancellationToken)
@@ -309,7 +312,7 @@ namespace MediaBrowser.Providers.Manager
if (provider is IRemoteMetadataProvider)
{
- if (!ConfigurationManager.Configuration.EnableInternetProviders)
+ if (!item.IsInternetMetadataEnabled())
{
return false;
}
@@ -357,7 +360,7 @@ namespace MediaBrowser.Providers.Manager
if (provider is IRemoteImageProvider)
{
- if (!ConfigurationManager.Configuration.EnableInternetProviders)
+ if (!item.IsInternetMetadataEnabled())
{
return false;
}
@@ -512,7 +515,7 @@ namespace MediaBrowser.Providers.Manager
Type = MetadataPluginType.LocalMetadataProvider
}));
- if (ConfigurationManager.Configuration.EnableInternetProviders)
+ if (item.IsInternetMetadataEnabled())
{
// Fetchers
list.AddRange(providers.Where(i => (i is IRemoteMetadataProvider)).Select(i => new MetadataPlugin
@@ -544,7 +547,7 @@ namespace MediaBrowser.Providers.Manager
Type = MetadataPluginType.LocalImageProvider
}));
- var enableInternet = ConfigurationManager.Configuration.EnableInternetProviders;
+ var enableInternet = item.IsInternetMetadataEnabled();
// Fetchers
list.AddRange(imageProviders.Where(i => i is IDynamicImageProvider || (enableInternet && i is IRemoteImageProvider)).Select(i => new MetadataPlugin
@@ -841,5 +844,157 @@ namespace MediaBrowser.Providers.Manager
});
}
+
+ private readonly ConcurrentQueue<Tuple<Guid, MetadataRefreshOptions>> _refreshQueue =
+ new ConcurrentQueue<Tuple<Guid, MetadataRefreshOptions>>();
+
+ private readonly object _refreshTimerLock = new object();
+ private Timer _refreshTimer;
+
+ public void QueueRefresh(Guid id, MetadataRefreshOptions options)
+ {
+ if (_disposed)
+ {
+ return;
+ }
+
+ _refreshQueue.Enqueue(new Tuple<Guid, MetadataRefreshOptions>(id, options));
+ StartRefreshTimer();
+ }
+
+ private void StartRefreshTimer()
+ {
+ lock (_refreshTimerLock)
+ {
+ if (_refreshTimer == null)
+ {
+ _refreshTimer = new Timer(RefreshTimerCallback, null, 100, Timeout.Infinite);
+ }
+ }
+ }
+
+ private void StopRefreshTimer()
+ {
+ lock (_refreshTimerLock)
+ {
+ if (_refreshTimer != null)
+ {
+ _refreshTimer.Dispose();
+ _refreshTimer = null;
+ }
+ }
+ }
+
+ private async void RefreshTimerCallback(object state)
+ {
+ Tuple<Guid, MetadataRefreshOptions> refreshItem;
+ var libraryManager = _libraryManagerFactory();
+
+ while (_refreshQueue.TryDequeue(out refreshItem))
+ {
+ if (_disposed)
+ {
+ return;
+ }
+
+ var item = libraryManager.GetItemById(refreshItem.Item1);
+ if (item != null)
+ {
+ try
+ {
+ var artist = item as MusicArtist;
+ var task = artist == null
+ ? RefreshItem(item, refreshItem.Item2, CancellationToken.None)
+ : RefreshArtist(artist, refreshItem.Item2);
+
+ await task.ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error refreshing item", ex);
+ }
+ }
+ }
+
+ StopRefreshTimer();
+ }
+
+ private async Task RefreshItem(BaseItem item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ {
+ await item.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
+
+ if (item.IsFolder)
+ {
+ // Collection folders don't validate their children so we'll have to simulate that here
+ var collectionFolder = item as CollectionFolder;
+
+ if (collectionFolder != null)
+ {
+ await RefreshCollectionFolderChildren(options, collectionFolder).ConfigureAwait(false);
+ }
+ else
+ {
+ var folder = (Folder)item;
+
+ await folder.ValidateChildren(new Progress<double>(), cancellationToken, options).ConfigureAwait(false);
+ }
+ }
+ }
+
+ private async Task RefreshCollectionFolderChildren(MetadataRefreshOptions options, CollectionFolder collectionFolder)
+ {
+ foreach (var child in collectionFolder.Children.ToList())
+ {
+ await child.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
+
+ if (child.IsFolder)
+ {
+ var folder = (Folder)child;
+
+ await folder.ValidateChildren(new Progress<double>(), CancellationToken.None).ConfigureAwait(false);
+ }
+ }
+ }
+
+ private async Task RefreshArtist(MusicArtist item, MetadataRefreshOptions options)
+ {
+ var cancellationToken = CancellationToken.None;
+
+ var albums = _libraryManagerFactory().RootFolder
+ .GetRecursiveChildren()
+ .OfType<MusicAlbum>()
+ .Where(i => i.HasAnyArtist(item.Name))
+ .ToList();
+
+ var musicArtists = albums
+ .Select(i => i.Parent)
+ .OfType<MusicArtist>()
+ .ToList();
+
+ var musicArtistRefreshTasks = musicArtists.Select(i => i.ValidateChildren(new Progress<double>(), cancellationToken, options, true));
+
+ await Task.WhenAll(musicArtistRefreshTasks).ConfigureAwait(false);
+
+ try
+ {
+ await item.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error refreshing library", ex);
+ }
+ }
+
+ public Task RefreshFullItem(IHasMetadata item, MetadataRefreshOptions options,
+ CancellationToken cancellationToken)
+ {
+ return RefreshItem((BaseItem)item, options, cancellationToken);
+ }
+
+ private bool _disposed;
+ public void Dispose()
+ {
+ _disposed = true;
+ }
}
} \ No newline at end of file