aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Providers/Manager/MetadataService.cs
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Providers/Manager/MetadataService.cs')
-rw-r--r--MediaBrowser.Providers/Manager/MetadataService.cs178
1 files changed, 102 insertions, 76 deletions
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs
index e0272bc7b..beece997d 100644
--- a/MediaBrowser.Providers/Manager/MetadataService.cs
+++ b/MediaBrowser.Providers/Manager/MetadataService.cs
@@ -4,11 +4,11 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -16,8 +16,8 @@ using System.Threading.Tasks;
namespace MediaBrowser.Providers.Manager
{
public abstract class MetadataService<TItemType, TIdType> : IMetadataService
- where TItemType : IHasMetadata, new()
- where TIdType : ItemId, new()
+ where TItemType : IHasMetadata, IHasLookupInfo<TIdType>, new()
+ where TIdType : ItemLookupInfo, new()
{
protected readonly IServerConfigurationManager ServerConfigurationManager;
protected readonly ILogger Logger;
@@ -37,10 +37,19 @@ namespace MediaBrowser.Providers.Manager
/// <summary>
/// Saves the provider result.
/// </summary>
+ /// <param name="item">The item.</param>
/// <param name="result">The result.</param>
/// <returns>Task.</returns>
- protected Task SaveProviderResult(MetadataStatus result)
+ protected Task SaveProviderResult(TItemType item, MetadataStatus result)
{
+ result.ItemId = item.Id;
+ result.ItemName = item.Name;
+ result.ItemType = item.GetType().Name;
+
+ var series = item as IHasSeries;
+
+ result.SeriesName = series == null ? null : series.SeriesName;
+
return ProviderRepo.SaveMetadataStatus(result, CancellationToken.None);
}
@@ -56,10 +65,15 @@ namespace MediaBrowser.Providers.Manager
public async Task RefreshMetadata(IHasMetadata item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken)
{
+ if (refreshOptions.DirectoryService == null)
+ {
+ refreshOptions.DirectoryService = new DirectoryService(Logger);
+ }
+
var itemOfType = (TItemType)item;
- var config = GetMetadataOptions(itemOfType);
+ var config = ProviderManager.GetMetadataOptions(item);
- var updateType = ItemUpdateType.Unspecified;
+ var updateType = ItemUpdateType.None;
var refreshResult = GetLastResult(item.Id);
refreshResult.LastErrorMessage = string.Empty;
refreshResult.LastStatus = ProviderRefreshStatus.Success;
@@ -73,7 +87,7 @@ namespace MediaBrowser.Providers.Manager
try
{
// Always validate images and check for new locally stored ones.
- if (itemImageProvider.ValidateImages(item, allImageProviders.OfType<ILocalImageProvider>()))
+ if (itemImageProvider.ValidateImages(item, allImageProviders.OfType<ILocalImageProvider>(), refreshOptions.DirectoryService))
{
updateType = updateType | ItemUpdateType.ImageUpdate;
}
@@ -92,13 +106,12 @@ namespace MediaBrowser.Providers.Manager
if (providers.Count > 0 || !refreshResult.DateLastMetadataRefresh.HasValue)
{
- updateType = updateType | BeforeMetadataRefresh(itemOfType);
+ updateType = updateType | item.BeforeMetadataRefresh();
}
if (providers.Count > 0)
{
-
- var result = await RefreshWithProviders(itemOfType, refreshOptions, providers, cancellationToken).ConfigureAwait(false);
+ var result = await RefreshWithProviders(itemOfType, refreshOptions, providers, itemImageProvider, cancellationToken).ConfigureAwait(false);
updateType = updateType | result.UpdateType;
refreshResult.AddStatus(result.Status, result.ErrorMessage);
@@ -125,44 +138,21 @@ namespace MediaBrowser.Providers.Manager
updateType = updateType | BeforeSave(itemOfType);
- var providersHadChanges = updateType > ItemUpdateType.Unspecified;
+ var providersHadChanges = updateType > ItemUpdateType.None;
- if (refreshOptions.ForceSave || providersHadChanges)
+ // Save if changes were made, or it's never been saved before
+ if (refreshOptions.ForceSave || providersHadChanges || item.DateLastSaved == default(DateTime))
{
- if (string.IsNullOrEmpty(item.Name))
- {
- throw new InvalidOperationException(item.GetType().Name + " has no name: " + item.Path);
- }
-
// Save to database
await SaveItem(itemOfType, updateType, cancellationToken);
}
if (providersHadChanges || refreshResult.IsDirty)
{
- await SaveProviderResult(refreshResult).ConfigureAwait(false);
+ await SaveProviderResult(itemOfType, refreshResult).ConfigureAwait(false);
}
}
- private readonly MetadataOptions _defaultOptions = new MetadataOptions();
- protected MetadataOptions GetMetadataOptions(TItemType item)
- {
- var type = item.GetType().Name;
- return ServerConfigurationManager.Configuration.MetadataOptions
- .FirstOrDefault(i => string.Equals(i.ItemType, type, StringComparison.OrdinalIgnoreCase)) ??
- _defaultOptions;
- }
-
- /// <summary>
- /// Befores the metadata refresh.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>ItemUpdateType.</returns>
- protected virtual ItemUpdateType BeforeMetadataRefresh(TItemType item)
- {
- return ItemUpdateType.Unspecified;
- }
-
/// <summary>
/// Befores the save.
/// </summary>
@@ -170,7 +160,15 @@ namespace MediaBrowser.Providers.Manager
/// <returns>ItemUpdateType.</returns>
protected virtual ItemUpdateType BeforeSave(TItemType item)
{
- return ItemUpdateType.Unspecified;
+ var updateType = ItemUpdateType.None;
+
+ if (string.IsNullOrEmpty(item.Name) && !string.IsNullOrEmpty(item.Path))
+ {
+ item.Name = Path.GetFileNameWithoutExtension(item.Path);
+ updateType = updateType | ItemUpdateType.MetadataEdit;
+ }
+
+ return updateType;
}
/// <summary>
@@ -194,15 +192,37 @@ namespace MediaBrowser.Providers.Manager
var currentItem = item;
var providersWithChanges = providers.OfType<IHasChangeMonitor>()
- .Where(i => i.HasChanged(currentItem, currentItem.DateLastSaved))
+ .Where(i => i.HasChanged(currentItem, options.DirectoryService, currentItem.DateLastSaved))
+ .Cast<IMetadataProvider<TItemType>>()
.ToList();
- // If local providers are the only ones with changes, then just run those
- if (providersWithChanges.All(i => i is ILocalMetadataProvider))
+ if (providersWithChanges.Count == 0)
{
- providers = providersWithChanges.Count == 0 ?
- new List<IMetadataProvider<TItemType>>() :
- providers.Where(i => i is ILocalMetadataProvider).ToList();
+ providers = new List<IMetadataProvider<TItemType>>();
+ }
+ else
+ {
+ providers = providers.Where(i =>
+ {
+ // If any provider reports a change, always run local ones as well
+ if (i is ILocalMetadataProvider)
+ {
+ return true;
+ }
+
+ var anyRemoteProvidersChanged = providersWithChanges.OfType<IRemoteMetadataProvider>()
+ .Any();
+
+ // If any remote providers changed, run them all so that priorities can be honored
+ if (i is IRemoteMetadataProvider)
+ {
+ return anyRemoteProvidersChanged;
+ }
+
+ // Run custom providers if they report a change or any remote providers change
+ return anyRemoteProvidersChanged || providersWithChanges.Contains(i);
+
+ }).ToList();
}
}
@@ -223,7 +243,7 @@ namespace MediaBrowser.Providers.Manager
var currentItem = item;
providers = providers.OfType<IHasChangeMonitor>()
- .Where(i => i.HasChanged(currentItem, dateLastImageRefresh.Value))
+ .Where(i => i.HasChanged(currentItem, options.DirectoryService, dateLastImageRefresh.Value))
.Cast<IImageProvider>()
.ToList();
}
@@ -231,27 +251,9 @@ namespace MediaBrowser.Providers.Manager
return providers;
}
- protected abstract Task SaveItem(TItemType item, ItemUpdateType reason, CancellationToken cancellationToken);
-
- protected virtual TIdType GetId(TItemType item)
+ protected Task SaveItem(TItemType item, ItemUpdateType reason, CancellationToken cancellationToken)
{
- var id = new TIdType
- {
- MetadataCountryCode = item.GetPreferredMetadataCountryCode(),
- MetadataLanguage = item.GetPreferredMetadataLanguage(),
- Name = item.Name,
- ProviderIds = item.ProviderIds
- };
-
- var baseItem = item as BaseItem;
-
- if (baseItem != null)
- {
- id.IndexNumber = baseItem.IndexNumber;
- id.ParentIndexNumber = baseItem.ParentIndexNumber;
- }
-
- return id;
+ return item.UpdateToRepository(reason, cancellationToken);
}
public bool CanRefresh(IHasMetadata item)
@@ -259,11 +261,11 @@ namespace MediaBrowser.Providers.Manager
return item is TItemType;
}
- protected virtual async Task<RefreshResult> RefreshWithProviders(TItemType item, MetadataRefreshOptions options, List<IMetadataProvider> providers, CancellationToken cancellationToken)
+ protected virtual async Task<RefreshResult> RefreshWithProviders(TItemType item, MetadataRefreshOptions options, List<IMetadataProvider> providers, ItemImageProvider imageService, CancellationToken cancellationToken)
{
var refreshResult = new RefreshResult
{
- UpdateType = ItemUpdateType.Unspecified,
+ UpdateType = ItemUpdateType.None,
Providers = providers.Select(i => i.GetType().FullName.GetMD5()).ToList()
};
@@ -273,7 +275,7 @@ namespace MediaBrowser.Providers.Manager
// If replacing all metadata, run internet providers first
if (options.ReplaceAllMetadata)
{
- await ExecuteRemoteProviders(item, temp, providers.OfType<IRemoteMetadataProvider<TItemType>>(), refreshResult, cancellationToken).ConfigureAwait(false);
+ await ExecuteRemoteProviders(item, temp, providers.OfType<IRemoteMetadataProvider<TItemType, TIdType>>(), refreshResult, cancellationToken).ConfigureAwait(false);
}
var hasLocalMetadata = false;
@@ -290,6 +292,11 @@ namespace MediaBrowser.Providers.Manager
if (localItem.HasMetadata)
{
+ if (imageService.MergeImages(item, localItem.Images))
+ {
+ refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport;
+ }
+
if (!string.IsNullOrEmpty(localItem.Item.Name))
{
MergeData(localItem.Item, temp, new List<MetadataFields>(), !options.ReplaceAllMetadata, true);
@@ -319,31 +326,32 @@ namespace MediaBrowser.Providers.Manager
}
}
- if (!options.ReplaceAllMetadata && !hasLocalMetadata)
+ // Local metadata is king - if any is found don't run remote providers
+ if ((!options.ReplaceAllMetadata && !hasLocalMetadata) || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh)
{
- await ExecuteRemoteProviders(item, temp, providers.OfType<IRemoteMetadataProvider<TItemType>>(), refreshResult, cancellationToken).ConfigureAwait(false);
+ await ExecuteRemoteProviders(item, temp, providers.OfType<IRemoteMetadataProvider<TItemType, TIdType>>(), refreshResult, cancellationToken).ConfigureAwait(false);
}
- if (refreshResult.UpdateType > ItemUpdateType.Unspecified)
+ if (refreshResult.UpdateType > ItemUpdateType.None)
{
MergeData(temp, item, item.LockedFields, true, true);
}
foreach (var provider in providers.OfType<ICustomMetadataProvider<TItemType>>())
{
- await RunCustomProvider(provider, item, refreshResult, cancellationToken).ConfigureAwait(false);
+ await RunCustomProvider(provider, item, options.DirectoryService, refreshResult, cancellationToken).ConfigureAwait(false);
}
return refreshResult;
}
- private async Task RunCustomProvider(ICustomMetadataProvider<TItemType> provider, TItemType item, RefreshResult refreshResult, CancellationToken cancellationToken)
+ private async Task RunCustomProvider(ICustomMetadataProvider<TItemType> provider, TItemType item, IDirectoryService directoryService, RefreshResult refreshResult, CancellationToken cancellationToken)
{
Logger.Debug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name);
try
{
- refreshResult.UpdateType = refreshResult.UpdateType | await provider.FetchAsync(item, cancellationToken).ConfigureAwait(false);
+ refreshResult.UpdateType = refreshResult.UpdateType | await provider.FetchAsync(item, directoryService, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
@@ -362,14 +370,23 @@ namespace MediaBrowser.Providers.Manager
return new TItemType();
}
- private async Task ExecuteRemoteProviders(TItemType item, TItemType temp, IEnumerable<IRemoteMetadataProvider<TItemType>> providers, RefreshResult refreshResult, CancellationToken cancellationToken)
+ private async Task ExecuteRemoteProviders(TItemType item, TItemType temp, IEnumerable<IRemoteMetadataProvider<TItemType, TIdType>> providers, RefreshResult refreshResult, CancellationToken cancellationToken)
{
- var id = GetId(item);
+ TIdType id = null;
foreach (var provider in providers)
{
Logger.Debug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name);
+ if (id == null)
+ {
+ id = item.GetLookupInfo();
+ }
+ else
+ {
+ MergeNewData(temp, id);
+ }
+
try
{
var result = await provider.GetMetadata(id, cancellationToken).ConfigureAwait(false);
@@ -394,6 +411,15 @@ namespace MediaBrowser.Providers.Manager
}
}
+ private void MergeNewData(TItemType source, TIdType lookupInfo)
+ {
+ // Copy new provider id's that may have been obtained
+ foreach (var providerId in source.ProviderIds)
+ {
+ lookupInfo.ProviderIds[providerId.Key] = providerId.Value;
+ }
+ }
+
protected abstract void MergeData(TItemType source, TItemType target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings);
public virtual int Order