aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Providers/Manager
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Providers/Manager')
-rw-r--r--MediaBrowser.Providers/Manager/ItemImageProvider.cs123
-rw-r--r--MediaBrowser.Providers/Manager/MetadataService.cs347
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs22
-rw-r--r--MediaBrowser.Providers/Manager/ProviderUtils.cs295
4 files changed, 398 insertions, 389 deletions
diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs
index 0d1bdec58..bbbbfad54 100644
--- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs
+++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs
@@ -63,6 +63,29 @@ namespace MediaBrowser.Providers.Manager
}
/// <summary>
+ /// Removes all existing images from the provided item.
+ /// </summary>
+ /// <param name="item">The <see cref="BaseItem"/> to remove images from.</param>
+ /// <returns><c>true</c> if changes were made to the item; otherwise <c>false</c>.</returns>
+ public bool RemoveImages(BaseItem item)
+ {
+ var singular = new List<ItemImageInfo>();
+ for (var i = 0; i < _singularImages.Length; i++)
+ {
+ var currentImage = item.GetImageInfo(_singularImages[i], 0);
+ if (currentImage != null)
+ {
+ singular.Add(currentImage);
+ }
+ }
+
+ singular.AddRange(item.GetImages(ImageType.Backdrop));
+ PruneImages(item, singular);
+
+ return singular.Count > 0;
+ }
+
+ /// <summary>
/// Verifies existing images have valid paths and adds any new local images provided.
/// </summary>
/// <param name="item">The <see cref="BaseItem"/> to validate images for.</param>
@@ -100,7 +123,7 @@ namespace MediaBrowser.Providers.Manager
public async Task<RefreshResult> RefreshImages(
BaseItem item,
LibraryOptions libraryOptions,
- List<IImageProvider> providers,
+ IEnumerable<IImageProvider> providers,
ImageRefreshOptions refreshOptions,
CancellationToken cancellationToken)
{
@@ -160,14 +183,14 @@ namespace MediaBrowser.Providers.Manager
foreach (var imageType in images)
{
- if (!IsEnabled(savedOptions, imageType))
+ if (!savedOptions.IsEnabled(imageType))
{
continue;
}
- if (!HasImage(item, imageType) || (refreshOptions.IsReplacingImage(imageType) && !downloadedImages.Contains(imageType)))
+ if (!item.HasImage(imageType) || (refreshOptions.IsReplacingImage(imageType) && !downloadedImages.Contains(imageType)))
{
- _logger.LogDebug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name);
+ _logger.LogDebug("Running {Provider} for {Item}", provider.GetType().Name, item.Path ?? item.Name);
var response = await provider.GetImage(item, imageType, cancellationToken).ConfigureAwait(false);
@@ -183,7 +206,7 @@ namespace MediaBrowser.Providers.Manager
{
if (response.Protocol == MediaProtocol.Http)
{
- _logger.LogDebug("Setting image url into item {0}", item.Id);
+ _logger.LogDebug("Setting image url into item {Item}", item.Id);
var index = item.AllowsMultipleImages(imageType) ? item.GetImages(imageType).Count() : 0;
item.SetImage(
new ItemImageInfo
@@ -220,39 +243,6 @@ namespace MediaBrowser.Providers.Manager
}
}
- private bool HasImage(BaseItem item, ImageType type)
- {
- return item.HasImage(type);
- }
-
- /// <summary>
- /// Determines if an item already contains the given images.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="images">The images.</param>
- /// <param name="savedOptions">The saved options.</param>
- /// <param name="backdropLimit">The backdrop limit.</param>
- /// <returns><c>true</c> if the specified item contains images; otherwise, <c>false</c>.</returns>
- private bool ContainsImages(BaseItem item, List<ImageType> images, TypeOptions savedOptions, int backdropLimit)
- {
- // Using .Any causes the creation of a DisplayClass aka. variable capture
- for (var i = 0; i < _singularImages.Length; i++)
- {
- var type = _singularImages[i];
- if (images.Contains(type) && !HasImage(item, type) && savedOptions.GetLimit(type) > 0)
- {
- return false;
- }
- }
-
- if (images.Contains(ImageType.Backdrop) && item.GetImages(ImageType.Backdrop).Count() < backdropLimit)
- {
- return false;
- }
-
- return true;
- }
-
/// <summary>
/// Refreshes from a remote provider.
/// </summary>
@@ -289,7 +279,7 @@ namespace MediaBrowser.Providers.Manager
return;
}
- _logger.LogDebug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name);
+ _logger.LogDebug("Running {Provider} for {Item}", provider.GetType().Name, item.Path ?? item.Name);
var images = await _providerManager.GetAvailableRemoteImages(
item,
@@ -305,12 +295,12 @@ namespace MediaBrowser.Providers.Manager
foreach (var imageType in _singularImages)
{
- if (!IsEnabled(savedOptions, imageType))
+ if (!savedOptions.IsEnabled(imageType))
{
continue;
}
- if (!HasImage(item, imageType) || (refreshOptions.IsReplacingImage(imageType) && !downloadedImages.Contains(imageType)))
+ if (!item.HasImage(imageType) || (refreshOptions.IsReplacingImage(imageType) && !downloadedImages.Contains(imageType)))
{
minWidth = savedOptions.GetMinWidth(imageType);
var downloaded = await DownloadImage(item, provider, result, list, minWidth, imageType, cancellationToken).ConfigureAwait(false);
@@ -336,14 +326,37 @@ namespace MediaBrowser.Providers.Manager
}
}
- private bool IsEnabled(TypeOptions options, ImageType type)
+ /// <summary>
+ /// Determines if an item already contains the given images.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="images">The images.</param>
+ /// <param name="savedOptions">The saved options.</param>
+ /// <param name="backdropLimit">The backdrop limit.</param>
+ /// <returns><c>true</c> if the specified item contains images; otherwise, <c>false</c>.</returns>
+ private bool ContainsImages(BaseItem item, List<ImageType> images, TypeOptions savedOptions, int backdropLimit)
{
- return options.IsEnabled(type);
+ // Using .Any causes the creation of a DisplayClass aka. variable capture
+ for (var i = 0; i < _singularImages.Length; i++)
+ {
+ var type = _singularImages[i];
+ if (images.Contains(type) && !item.HasImage(type) && savedOptions.GetLimit(type) > 0)
+ {
+ return false;
+ }
+ }
+
+ if (images.Contains(ImageType.Backdrop) && item.GetImages(ImageType.Backdrop).Count() < backdropLimit)
+ {
+ return false;
+ }
+
+ return true;
}
- private void PruneImages(BaseItem item, ItemImageInfo[] images)
+ private void PruneImages(BaseItem item, IReadOnlyList<ItemImageInfo> images)
{
- for (var i = 0; i < images.Length; i++)
+ for (var i = 0; i < images.Count; i++)
{
var image = images[i];
@@ -355,6 +368,11 @@ namespace MediaBrowser.Providers.Manager
}
catch (FileNotFoundException)
{
+ // nothing to do, already gone
+ }
+ catch (UnauthorizedAccessException ex)
+ {
+ _logger.LogWarning(ex, "Unable to delete {Image}", image.Path);
}
}
}
@@ -370,7 +388,7 @@ namespace MediaBrowser.Providers.Manager
/// <returns><c>true</c> if changes were made to the item; otherwise <c>false</c>.</returns>
public bool MergeImages(BaseItem item, IReadOnlyList<LocalImageInfo> images)
{
- var changed = item.ValidateImages(new DirectoryService(_fileSystem));
+ var changed = item.ValidateImages();
for (var i = 0; i < _singularImages.Length; i++)
{
@@ -381,12 +399,7 @@ namespace MediaBrowser.Providers.Manager
{
var currentImage = item.GetImageInfo(type, 0);
- if (currentImage == null)
- {
- item.SetImagePath(type, image.FileInfo);
- changed = true;
- }
- else if (!string.Equals(currentImage.Path, image.FileInfo.FullName, StringComparison.OrdinalIgnoreCase))
+ if (currentImage == null || !string.Equals(currentImage.Path, image.FileInfo.FullName, StringComparison.OrdinalIgnoreCase))
{
item.SetImagePath(type, image.FileInfo);
changed = true;
@@ -494,7 +507,7 @@ namespace MediaBrowser.Providers.Manager
await _providerManager.SaveImage(
item,
stream,
- response.Content.Headers.ContentType.MediaType,
+ response.Content.Headers.ContentType?.MediaType,
type,
null,
cancellationToken).ConfigureAwait(false);
@@ -617,11 +630,11 @@ namespace MediaBrowser.Providers.Manager
await _providerManager.SaveImage(
item,
stream,
- response.Content.Headers.ContentType.MediaType,
+ response.Content.Headers.ContentType?.MediaType,
imageType,
null,
cancellationToken).ConfigureAwait(false);
- result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate;
+ result.UpdateType |= ItemUpdateType.ImageUpdate;
}
catch (HttpRequestException)
{
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs
index 94045b38b..0c52d2673 100644
--- a/MediaBrowser.Providers/Manager/MetadataService.cs
+++ b/MediaBrowser.Providers/Manager/MetadataService.cs
@@ -8,8 +8,10 @@ using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using Diacritics.Extensions;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
@@ -74,14 +76,10 @@ namespace MediaBrowser.Providers.Manager
var itemOfType = (TItemType)item;
var updateType = ItemUpdateType.None;
- var requiresRefresh = false;
var libraryOptions = LibraryManager.GetLibraryOptions(item);
- if (!requiresRefresh && libraryOptions.AutomaticRefreshIntervalDays > 0 && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= libraryOptions.AutomaticRefreshIntervalDays)
- {
- requiresRefresh = true;
- }
+ var requiresRefresh = libraryOptions.AutomaticRefreshIntervalDays > 0 && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= libraryOptions.AutomaticRefreshIntervalDays;
if (!requiresRefresh && refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None)
{
@@ -90,7 +88,7 @@ namespace MediaBrowser.Providers.Manager
if (requiresRefresh)
{
- Logger.LogDebug("Refreshing {0} {1} because item.RequiresRefresh() returned true", typeof(TItemType).Name, item.Path ?? item.Name);
+ Logger.LogDebug("Refreshing {Type} {Item} because item.RequiresRefresh() returned true", typeof(TItemType).Name, item.Path ?? item.Name);
}
}
@@ -98,6 +96,14 @@ namespace MediaBrowser.Providers.Manager
var allImageProviders = ((ProviderManager)ProviderManager).GetImageProviders(item, refreshOptions).ToList();
+ if (refreshOptions.RemoveOldMetadata && refreshOptions.ReplaceAllImages)
+ {
+ if (ImageProvider.RemoveImages(item))
+ {
+ updateType |= ItemUpdateType.ImageUpdate;
+ }
+ }
+
// Start by validating images
try
{
@@ -110,7 +116,7 @@ namespace MediaBrowser.Providers.Manager
catch (Exception ex)
{
localImagesFailed = true;
- Logger.LogError(ex, "Error validating images for {0}", item.Path ?? item.Name ?? "Unknown name");
+ Logger.LogError(ex, "Error validating images for {Item}", item.Path ?? item.Name ?? "Unknown name");
}
var metadataResult = new MetadataResult<TItemType>
@@ -380,8 +386,7 @@ namespace MediaBrowser.Providers.Manager
{
var updateType = ItemUpdateType.None;
- var folder = item as Folder;
- if (folder != null && folder.SupportsDateLastMediaAdded)
+ if (item is Folder folder && folder.SupportsDateLastMediaAdded)
{
var dateLastMediaAdded = DateTime.MinValue;
var any = false;
@@ -668,7 +673,7 @@ namespace MediaBrowser.Providers.Manager
foreach (var provider in providers.OfType<ILocalMetadataProvider<TItemType>>().ToList())
{
var providerName = provider.GetType().Name;
- Logger.LogDebug("Running {0} for {1}", providerName, logName);
+ Logger.LogDebug("Running {Provider} for {Item}", providerName, logName);
var itemInfo = new ItemInfo(item);
@@ -713,7 +718,7 @@ namespace MediaBrowser.Providers.Manager
break;
}
- Logger.LogDebug("{0} returned no metadata for {1}", providerName, logName);
+ Logger.LogDebug("{Provider} returned no metadata for {Item}", providerName, logName);
}
catch (OperationCanceledException)
{
@@ -749,8 +754,11 @@ 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, Array.Empty<MetadataField>(), false, false);
+ if (!options.RemoveOldMetadata)
+ {
+ MergeData(metadata, temp, Array.Empty<MetadataField>(), false, false);
+ }
+
MergeData(temp, metadata, item.LockedFields, true, false);
}
}
@@ -780,7 +788,7 @@ namespace MediaBrowser.Providers.Manager
private async Task RunCustomProvider(ICustomMetadataProvider<TItemType> provider, TItemType item, string logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken)
{
- Logger.LogDebug("Running {0} for {1}", provider.GetType().Name, logName);
+ Logger.LogDebug("Running {Provider} for {Item}", provider.GetType().Name, logName);
try
{
@@ -811,7 +819,7 @@ namespace MediaBrowser.Providers.Manager
foreach (var provider in providers)
{
var providerName = provider.GetType().Name;
- Logger.LogDebug("Running {0} for {1}", providerName, logName);
+ Logger.LogDebug("Running {Provider} for {Item}", providerName, logName);
if (id != null && !tmpDataMerged)
{
@@ -834,7 +842,7 @@ namespace MediaBrowser.Providers.Manager
}
else
{
- Logger.LogDebug("{0} returned no metadata for {1}", providerName, logName);
+ Logger.LogDebug("{Provider} returned no metadata for {Item}", providerName, logName);
}
}
catch (OperationCanceledException)
@@ -867,13 +875,6 @@ namespace MediaBrowser.Providers.Manager
}
}
- protected abstract void MergeData(
- MetadataResult<TItemType> source,
- MetadataResult<TItemType> target,
- MetadataField[] lockedFields,
- bool replaceData,
- bool mergeMetadataSettings);
-
private bool HasChanged(BaseItem item, IHasItemChangeMonitor changeMonitor, IDirectoryService directoryService)
{
try
@@ -882,16 +883,312 @@ namespace MediaBrowser.Providers.Manager
if (hasChanged)
{
- Logger.LogDebug("{0} reports change to {1}", changeMonitor.GetType().Name, item.Path ?? item.Name);
+ Logger.LogDebug("{Monitor} reports change to {Item}", changeMonitor.GetType().Name, item.Path ?? item.Name);
}
return hasChanged;
}
catch (Exception ex)
{
- Logger.LogError(ex, "Error in {0}.HasChanged", changeMonitor.GetType().Name);
+ Logger.LogError(ex, "Error in {Monitor}.HasChanged", changeMonitor.GetType().Name);
return false;
}
}
+
+ /// <summary>
+ /// Merges metadata from source into target.
+ /// </summary>
+ /// <param name="source">The source for new metadata.</param>
+ /// <param name="target">The target to insert new metadata into.</param>
+ /// <param name="lockedFields">The fields that are locked and should not be updated.</param>
+ /// <param name="replaceData"><c>true</c> if existing data should be replaced.</param>
+ /// <param name="mergeMetadataSettings"><c>true</c> if the metadata settings in target should be updated to match source.</param>
+ /// <exception cref="ArgumentException">Thrown if source or target are null.</exception>
+ protected virtual void MergeData(
+ MetadataResult<TItemType> source,
+ MetadataResult<TItemType> target,
+ MetadataField[] lockedFields,
+ bool replaceData,
+ bool mergeMetadataSettings)
+ {
+ MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
+ }
+
+ internal static void MergeBaseItemData(
+ MetadataResult<TItemType> sourceResult,
+ MetadataResult<TItemType> targetResult,
+ MetadataField[] lockedFields,
+ bool replaceData,
+ bool mergeMetadataSettings)
+ {
+ var source = sourceResult.Item;
+ var target = targetResult.Item;
+
+ if (source == null)
+ {
+ throw new ArgumentException("Item cannot be null.", nameof(sourceResult));
+ }
+
+ if (target == null)
+ {
+ throw new ArgumentException("Item cannot be null.", nameof(targetResult));
+ }
+
+ if (!lockedFields.Contains(MetadataField.Name))
+ {
+ if (replaceData || string.IsNullOrEmpty(target.Name))
+ {
+ // Safeguard against incoming data having an empty name
+ if (!string.IsNullOrWhiteSpace(source.Name))
+ {
+ target.Name = source.Name;
+ }
+ }
+ }
+
+ if (replaceData || string.IsNullOrEmpty(target.OriginalTitle))
+ {
+ // Safeguard against incoming data having an empty name
+ if (!string.IsNullOrWhiteSpace(source.OriginalTitle))
+ {
+ target.OriginalTitle = source.OriginalTitle;
+ }
+ }
+
+ if (replaceData || !target.CommunityRating.HasValue)
+ {
+ target.CommunityRating = source.CommunityRating;
+ }
+
+ if (replaceData || !target.EndDate.HasValue)
+ {
+ target.EndDate = source.EndDate;
+ }
+
+ if (!lockedFields.Contains(MetadataField.Genres))
+ {
+ if (replaceData || target.Genres.Length == 0)
+ {
+ target.Genres = source.Genres;
+ }
+ }
+
+ if (replaceData || !target.IndexNumber.HasValue)
+ {
+ target.IndexNumber = source.IndexNumber;
+ }
+
+ if (!lockedFields.Contains(MetadataField.OfficialRating))
+ {
+ if (replaceData || string.IsNullOrEmpty(target.OfficialRating))
+ {
+ target.OfficialRating = source.OfficialRating;
+ }
+ }
+
+ if (replaceData || string.IsNullOrEmpty(target.CustomRating))
+ {
+ target.CustomRating = source.CustomRating;
+ }
+
+ if (replaceData || string.IsNullOrEmpty(target.Tagline))
+ {
+ target.Tagline = source.Tagline;
+ }
+
+ if (!lockedFields.Contains(MetadataField.Overview))
+ {
+ if (replaceData || string.IsNullOrEmpty(target.Overview))
+ {
+ target.Overview = source.Overview;
+ }
+ }
+
+ if (replaceData || !target.ParentIndexNumber.HasValue)
+ {
+ target.ParentIndexNumber = source.ParentIndexNumber;
+ }
+
+ 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)
+ {
+ MergePeople(sourceResult.People, targetResult.People);
+ }
+ }
+
+ if (replaceData || !target.PremiereDate.HasValue)
+ {
+ target.PremiereDate = source.PremiereDate;
+ }
+
+ if (replaceData || !target.ProductionYear.HasValue)
+ {
+ target.ProductionYear = source.ProductionYear;
+ }
+
+ if (!lockedFields.Contains(MetadataField.Runtime))
+ {
+ if (replaceData || !target.RunTimeTicks.HasValue)
+ {
+ if (target is not Audio && target is not Video)
+ {
+ target.RunTimeTicks = source.RunTimeTicks;
+ }
+ }
+ }
+
+ if (!lockedFields.Contains(MetadataField.Studios))
+ {
+ if (replaceData || target.Studios.Length == 0)
+ {
+ target.Studios = source.Studios;
+ }
+ }
+
+ if (!lockedFields.Contains(MetadataField.Tags))
+ {
+ if (replaceData || target.Tags.Length == 0)
+ {
+ target.Tags = source.Tags;
+ }
+ }
+
+ if (!lockedFields.Contains(MetadataField.ProductionLocations))
+ {
+ if (replaceData || target.ProductionLocations.Length == 0)
+ {
+ target.ProductionLocations = source.ProductionLocations;
+ }
+ }
+
+ foreach (var id in source.ProviderIds)
+ {
+ var key = id.Key;
+
+ // Don't replace existing Id's.
+ if (replaceData)
+ {
+ target.ProviderIds[key] = id.Value;
+ }
+ else
+ {
+ target.ProviderIds.TryAdd(key, id.Value);
+ }
+ }
+
+ MergeAlbumArtist(source, target, replaceData);
+ MergeCriticRating(source, target, replaceData);
+ MergeTrailers(source, target, replaceData);
+ MergeVideoInfo(source, target, replaceData);
+ MergeDisplayOrder(source, target, replaceData);
+
+ if (replaceData || string.IsNullOrEmpty(target.ForcedSortName))
+ {
+ var forcedSortName = source.ForcedSortName;
+
+ if (!string.IsNullOrWhiteSpace(forcedSortName))
+ {
+ target.ForcedSortName = forcedSortName;
+ }
+ }
+
+ if (mergeMetadataSettings)
+ {
+ target.LockedFields = source.LockedFields;
+ target.IsLocked = source.IsLocked;
+
+ // Grab the value if it's there, but if not then don't overwrite with the default
+ if (source.DateCreated != default)
+ {
+ target.DateCreated = source.DateCreated;
+ }
+
+ target.PreferredMetadataCountryCode = source.PreferredMetadataCountryCode;
+ target.PreferredMetadataLanguage = source.PreferredMetadataLanguage;
+ }
+ }
+
+ private static void MergePeople(List<PersonInfo> source, List<PersonInfo> target)
+ {
+ foreach (var person in target)
+ {
+ var normalizedName = person.Name.RemoveDiacritics();
+ var personInSource = source.FirstOrDefault(i => string.Equals(i.Name.RemoveDiacritics(), normalizedName, StringComparison.OrdinalIgnoreCase));
+
+ if (personInSource != null)
+ {
+ foreach (var providerId in personInSource.ProviderIds)
+ {
+ person.ProviderIds.TryAdd(providerId.Key, providerId.Value);
+ }
+
+ if (string.IsNullOrWhiteSpace(person.ImageUrl))
+ {
+ person.ImageUrl = personInSource.ImageUrl;
+ }
+ }
+ }
+ }
+
+ private static void MergeDisplayOrder(BaseItem source, BaseItem target, bool replaceData)
+ {
+ if (source is IHasDisplayOrder sourceHasDisplayOrder
+ && target is IHasDisplayOrder targetHasDisplayOrder)
+ {
+ if (replaceData || string.IsNullOrEmpty(targetHasDisplayOrder.DisplayOrder))
+ {
+ var displayOrder = sourceHasDisplayOrder.DisplayOrder;
+
+ if (!string.IsNullOrWhiteSpace(displayOrder))
+ {
+ targetHasDisplayOrder.DisplayOrder = displayOrder;
+ }
+ }
+ }
+ }
+
+ private static void MergeAlbumArtist(BaseItem source, BaseItem target, bool replaceData)
+ {
+ if (source is IHasAlbumArtist sourceHasAlbumArtist
+ && target is IHasAlbumArtist targetHasAlbumArtist)
+ {
+ if (replaceData || targetHasAlbumArtist.AlbumArtists.Count == 0)
+ {
+ targetHasAlbumArtist.AlbumArtists = sourceHasAlbumArtist.AlbumArtists;
+ }
+ }
+ }
+
+ private static void MergeCriticRating(BaseItem source, BaseItem target, bool replaceData)
+ {
+ if (replaceData || !target.CriticRating.HasValue)
+ {
+ target.CriticRating = source.CriticRating;
+ }
+ }
+
+ private static void MergeTrailers(BaseItem source, BaseItem target, bool replaceData)
+ {
+ if (replaceData || target.RemoteTrailers.Count == 0)
+ {
+ target.RemoteTrailers = source.RemoteTrailers;
+ }
+ }
+
+ private static void MergeVideoInfo(BaseItem source, BaseItem target, bool replaceData)
+ {
+ if (source is Video sourceCast && target is Video targetCast)
+ {
+ if (replaceData || targetCast.Video3DFormat == null)
+ {
+ targetCast.Video3DFormat = sourceCast.Video3DFormat;
+ }
+ }
+ }
}
}
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index 0385ce6a7..5281b3721 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -128,9 +128,7 @@ namespace MediaBrowser.Providers.Manager
_metadataProviders = metadataProviders.ToArray();
_externalIds = externalIds.OrderBy(i => i.ProviderName).ToArray();
- _savers = metadataSavers
- .Where(i => i is not IConfigurableProvider configurable || configurable.IsEnabled)
- .ToArray();
+ _savers = metadataSavers.ToArray();
}
/// <inheritdoc/>
@@ -653,16 +651,12 @@ namespace MediaBrowser.Providers.Manager
}
/// <inheritdoc/>
- public void SaveMetadata(BaseItem item, ItemUpdateType updateType)
- {
- SaveMetadata(item, updateType, _savers);
- }
+ public Task SaveMetadataAsync(BaseItem item, ItemUpdateType updateType)
+ => SaveMetadataAsync(item, updateType, _savers);
/// <inheritdoc/>
- public void SaveMetadata(BaseItem item, ItemUpdateType updateType, IEnumerable<string> savers)
- {
- SaveMetadata(item, updateType, _savers.Where(i => savers.Contains(i.Name, StringComparison.OrdinalIgnoreCase)));
- }
+ public Task SaveMetadataAsync(BaseItem item, ItemUpdateType updateType, IEnumerable<string> savers)
+ => SaveMetadataAsync(item, updateType, _savers.Where(i => savers.Contains(i.Name, StringComparison.OrdinalIgnoreCase)));
/// <summary>
/// Saves the metadata.
@@ -670,7 +664,7 @@ namespace MediaBrowser.Providers.Manager
/// <param name="item">The item.</param>
/// <param name="updateType">Type of the update.</param>
/// <param name="savers">The savers.</param>
- private void SaveMetadata(BaseItem item, ItemUpdateType updateType, IEnumerable<IMetadataSaver> savers)
+ private async Task SaveMetadataAsync(BaseItem item, ItemUpdateType updateType, IEnumerable<IMetadataSaver> savers)
{
var libraryOptions = _libraryManager.GetLibraryOptions(item);
@@ -695,7 +689,7 @@ namespace MediaBrowser.Providers.Manager
try
{
_libraryMonitor.ReportFileSystemChangeBeginning(path);
- saver.Save(item, CancellationToken.None);
+ await saver.SaveAsync(item, CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -710,7 +704,7 @@ namespace MediaBrowser.Providers.Manager
{
try
{
- saver.Save(item, CancellationToken.None);
+ await saver.SaveAsync(item, CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
diff --git a/MediaBrowser.Providers/Manager/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs
deleted file mode 100644
index b90136d50..000000000
--- a/MediaBrowser.Providers/Manager/ProviderUtils.cs
+++ /dev/null
@@ -1,295 +0,0 @@
-#nullable disable
-
-#pragma warning disable CS1591
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Diacritics.Extensions;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
-
-namespace MediaBrowser.Providers.Manager
-{
- public static class ProviderUtils
- {
- public static void MergeBaseItemData<T>(
- MetadataResult<T> sourceResult,
- MetadataResult<T> targetResult,
- MetadataField[] lockedFields,
- bool replaceData,
- bool mergeMetadataSettings)
- where T : BaseItem
- {
- var source = sourceResult.Item;
- var target = targetResult.Item;
-
- if (source == null)
- {
- throw new ArgumentException("Item cannot be null.", nameof(sourceResult));
- }
-
- if (target == null)
- {
- throw new ArgumentException("Item cannot be null.", nameof(targetResult));
- }
-
- if (!lockedFields.Contains(MetadataField.Name))
- {
- if (replaceData || string.IsNullOrEmpty(target.Name))
- {
- // Safeguard against incoming data having an empty name
- if (!string.IsNullOrWhiteSpace(source.Name))
- {
- target.Name = source.Name;
- }
- }
- }
-
- if (replaceData || string.IsNullOrEmpty(target.OriginalTitle))
- {
- // Safeguard against incoming data having an empty name
- if (!string.IsNullOrWhiteSpace(source.OriginalTitle))
- {
- target.OriginalTitle = source.OriginalTitle;
- }
- }
-
- if (replaceData || !target.CommunityRating.HasValue)
- {
- target.CommunityRating = source.CommunityRating;
- }
-
- if (replaceData || !target.EndDate.HasValue)
- {
- target.EndDate = source.EndDate;
- }
-
- if (!lockedFields.Contains(MetadataField.Genres))
- {
- if (replaceData || target.Genres.Length == 0)
- {
- target.Genres = source.Genres;
- }
- }
-
- if (replaceData || !target.IndexNumber.HasValue)
- {
- target.IndexNumber = source.IndexNumber;
- }
-
- if (!lockedFields.Contains(MetadataField.OfficialRating))
- {
- if (replaceData || string.IsNullOrEmpty(target.OfficialRating))
- {
- target.OfficialRating = source.OfficialRating;
- }
- }
-
- if (replaceData || string.IsNullOrEmpty(target.CustomRating))
- {
- target.CustomRating = source.CustomRating;
- }
-
- if (replaceData || string.IsNullOrEmpty(target.Tagline))
- {
- target.Tagline = source.Tagline;
- }
-
- if (!lockedFields.Contains(MetadataField.Overview))
- {
- if (replaceData || string.IsNullOrEmpty(target.Overview))
- {
- target.Overview = source.Overview;
- }
- }
-
- if (replaceData || !target.ParentIndexNumber.HasValue)
- {
- target.ParentIndexNumber = source.ParentIndexNumber;
- }
-
- 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)
- {
- MergePeople(sourceResult.People, targetResult.People);
- }
- }
-
- if (replaceData || !target.PremiereDate.HasValue)
- {
- target.PremiereDate = source.PremiereDate;
- }
-
- if (replaceData || !target.ProductionYear.HasValue)
- {
- target.ProductionYear = source.ProductionYear;
- }
-
- if (!lockedFields.Contains(MetadataField.Runtime))
- {
- if (replaceData || !target.RunTimeTicks.HasValue)
- {
- if (target is not Audio && target is not Video)
- {
- target.RunTimeTicks = source.RunTimeTicks;
- }
- }
- }
-
- if (!lockedFields.Contains(MetadataField.Studios))
- {
- if (replaceData || target.Studios.Length == 0)
- {
- target.Studios = source.Studios;
- }
- }
-
- if (!lockedFields.Contains(MetadataField.Tags))
- {
- if (replaceData || target.Tags.Length == 0)
- {
- target.Tags = source.Tags;
- }
- }
-
- if (!lockedFields.Contains(MetadataField.ProductionLocations))
- {
- if (replaceData || target.ProductionLocations.Length == 0)
- {
- target.ProductionLocations = source.ProductionLocations;
- }
- }
-
- foreach (var id in source.ProviderIds)
- {
- var key = id.Key;
-
- // Don't replace existing Id's.
- if (replaceData || !target.ProviderIds.ContainsKey(key))
- {
- target.ProviderIds[key] = id.Value;
- }
- }
-
- MergeAlbumArtist(source, target, replaceData);
- MergeCriticRating(source, target, replaceData);
- MergeTrailers(source, target, replaceData);
- MergeVideoInfo(source, target, replaceData);
- MergeDisplayOrder(source, target, replaceData);
-
- if (replaceData || string.IsNullOrEmpty(target.ForcedSortName))
- {
- var forcedSortName = source.ForcedSortName;
-
- if (!string.IsNullOrWhiteSpace(forcedSortName))
- {
- target.ForcedSortName = forcedSortName;
- }
- }
-
- if (mergeMetadataSettings)
- {
- target.LockedFields = source.LockedFields;
- target.IsLocked = source.IsLocked;
-
- // Grab the value if it's there, but if not then don't overwrite the default
- if (source.DateCreated != default)
- {
- target.DateCreated = source.DateCreated;
- }
-
- target.PreferredMetadataCountryCode = source.PreferredMetadataCountryCode;
- target.PreferredMetadataLanguage = source.PreferredMetadataLanguage;
- }
- }
-
- private static void MergePeople(List<PersonInfo> source, List<PersonInfo> target)
- {
- foreach (var person in target)
- {
- var normalizedName = person.Name.RemoveDiacritics();
- var personInSource = source.FirstOrDefault(i => string.Equals(i.Name.RemoveDiacritics(), normalizedName, StringComparison.OrdinalIgnoreCase));
-
- if (personInSource != null)
- {
- foreach (var providerId in personInSource.ProviderIds)
- {
- if (!person.ProviderIds.ContainsKey(providerId.Key))
- {
- person.ProviderIds[providerId.Key] = providerId.Value;
- }
- }
-
- if (string.IsNullOrWhiteSpace(person.ImageUrl))
- {
- person.ImageUrl = personInSource.ImageUrl;
- }
- }
- }
- }
-
- private static void MergeDisplayOrder(BaseItem source, BaseItem target, bool replaceData)
- {
- if (source is IHasDisplayOrder sourceHasDisplayOrder
- && target is IHasDisplayOrder targetHasDisplayOrder)
- {
- if (replaceData || string.IsNullOrEmpty(targetHasDisplayOrder.DisplayOrder))
- {
- var displayOrder = sourceHasDisplayOrder.DisplayOrder;
-
- if (!string.IsNullOrWhiteSpace(displayOrder))
- {
- targetHasDisplayOrder.DisplayOrder = displayOrder;
- }
- }
- }
- }
-
- private static void MergeAlbumArtist(BaseItem source, BaseItem target, bool replaceData)
- {
- if (source is IHasAlbumArtist sourceHasAlbumArtist
- && target is IHasAlbumArtist targetHasAlbumArtist)
- {
- if (replaceData || targetHasAlbumArtist.AlbumArtists.Count == 0)
- {
- targetHasAlbumArtist.AlbumArtists = sourceHasAlbumArtist.AlbumArtists;
- }
- }
- }
-
- private static void MergeCriticRating(BaseItem source, BaseItem target, bool replaceData)
- {
- if (replaceData || !target.CriticRating.HasValue)
- {
- target.CriticRating = source.CriticRating;
- }
- }
-
- private static void MergeTrailers(BaseItem source, BaseItem target, bool replaceData)
- {
- if (replaceData || target.RemoteTrailers.Count == 0)
- {
- target.RemoteTrailers = source.RemoteTrailers;
- }
- }
-
- private static void MergeVideoInfo(BaseItem source, BaseItem target, bool replaceData)
- {
- if (source is Video sourceCast && target is Video targetCast)
- {
- if (replaceData || targetCast.Video3DFormat == null)
- {
- targetCast.Video3DFormat = sourceCast.Video3DFormat;
- }
- }
- }
- }
-}