Fix replacement logic

This commit is contained in:
Shadowghost 2024-05-20 12:24:57 +02:00
parent 52cfd9f261
commit 37d7e8f5bf
9 changed files with 202 additions and 149 deletions

View File

@ -654,24 +654,16 @@ namespace MediaBrowser.Providers.Manager
await RunCustomProvider(provider, item, logName, options, refreshResult, cancellationToken).ConfigureAwait(false); await RunCustomProvider(provider, item, logName, options, refreshResult, cancellationToken).ConfigureAwait(false);
} }
if (!item.IsLocked)
{
var temp = new MetadataResult<TItemType> var temp = new MetadataResult<TItemType>
{ {
Item = CreateNew() Item = CreateNew()
}; };
temp.Item.Path = item.Path; temp.Item.Path = item.Path;
temp.Item.Id = item.Id;
// If replacing all metadata, run internet providers first var hasLocalBaseMetadataOrLocked = false;
if (options.ReplaceAllMetadata)
{
var remoteResult = await ExecuteRemoteProviders(temp, logName, true, id, providers.OfType<IRemoteMetadataProvider<TItemType, TIdType>>(), cancellationToken)
.ConfigureAwait(false);
refreshResult.UpdateType |= remoteResult.UpdateType;
refreshResult.ErrorMessage = remoteResult.ErrorMessage;
refreshResult.Failures += remoteResult.Failures;
}
var hasLocalMetadata = false;
var foundImageTypes = new List<ImageType>(); var foundImageTypes = new List<ImageType>();
foreach (var provider in providers.OfType<ILocalMetadataProvider<TItemType>>()) foreach (var provider in providers.OfType<ILocalMetadataProvider<TItemType>>())
@ -719,13 +711,13 @@ namespace MediaBrowser.Providers.Manager
refreshResult.UpdateType |= ItemUpdateType.ImageUpdate; refreshResult.UpdateType |= ItemUpdateType.ImageUpdate;
} }
MergeData(localItem, temp, Array.Empty<MetadataField>(), options.ReplaceAllMetadata, true); MergeData(localItem, temp, Array.Empty<MetadataField>(), false, true);
refreshResult.UpdateType |= ItemUpdateType.MetadataImport; refreshResult.UpdateType |= ItemUpdateType.MetadataImport;
// Only one local provider allowed per item // Only one local provider allowed per item
if (item.IsLocked || localItem.Item.IsLocked || IsFullLocalMetadata(localItem.Item)) if (item.IsLocked || localItem.Item.IsLocked || HasBaseMetadata(localItem.Item))
{ {
hasLocalMetadata = true; hasLocalBaseMetadataOrLocked = true;
} }
break; break;
@ -746,8 +738,7 @@ namespace MediaBrowser.Providers.Manager
} }
} }
// Local metadata is king - if any is found don't run remote providers if (options.ReplaceAllMetadata || !(hasLocalBaseMetadataOrLocked && item.StopRefreshIfLocalMetadataFound) || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh)
if (!options.ReplaceAllMetadata && (!hasLocalMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || !item.StopRefreshIfLocalMetadataFound))
{ {
var remoteResult = await ExecuteRemoteProviders(temp, logName, false, id, providers.OfType<IRemoteMetadataProvider<TItemType, TIdType>>(), cancellationToken) var remoteResult = await ExecuteRemoteProviders(temp, logName, false, id, providers.OfType<IRemoteMetadataProvider<TItemType, TIdType>>(), cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
@ -761,20 +752,12 @@ namespace MediaBrowser.Providers.Manager
{ {
if (refreshResult.UpdateType > ItemUpdateType.None) if (refreshResult.UpdateType > ItemUpdateType.None)
{ {
if (hasLocalMetadata) if (options.RemoveOldMetadata)
{ {
MergeData(temp, metadata, item.LockedFields, true, true); MergeData(metadata, temp, Array.Empty<MetadataField>(), true, true);
}
else
{
if (!options.RemoveOldMetadata)
{
MergeData(metadata, temp, Array.Empty<MetadataField>(), false, false);
} }
// Will always replace all metadata when Scan for new and updated files is used. Else, follow the options. MergeData(temp, metadata, item.LockedFields, options.MetadataRefreshMode >= MetadataRefreshMode.Default || options.ReplaceAllMetadata, true);
MergeData(temp, metadata, item.LockedFields, options.MetadataRefreshMode == MetadataRefreshMode.Default || options.ReplaceAllMetadata, false);
}
} }
} }
@ -782,11 +765,12 @@ namespace MediaBrowser.Providers.Manager
{ {
await RunCustomProvider(provider, item, logName, options, refreshResult, cancellationToken).ConfigureAwait(false); await RunCustomProvider(provider, item, logName, options, refreshResult, cancellationToken).ConfigureAwait(false);
} }
}
return refreshResult; return refreshResult;
} }
protected virtual bool IsFullLocalMetadata(TItemType item) protected virtual bool HasBaseMetadata(TItemType item)
{ {
if (string.IsNullOrWhiteSpace(item.Name)) if (string.IsNullOrWhiteSpace(item.Name))
{ {
@ -947,13 +931,9 @@ namespace MediaBrowser.Providers.Manager
} }
if (replaceData || string.IsNullOrEmpty(target.OriginalTitle)) if (replaceData || string.IsNullOrEmpty(target.OriginalTitle))
{
// Safeguard against incoming data having an empty name
if (!string.IsNullOrWhiteSpace(source.OriginalTitle))
{ {
target.OriginalTitle = source.OriginalTitle; target.OriginalTitle = source.OriginalTitle;
} }
}
if (replaceData || !target.CommunityRating.HasValue) if (replaceData || !target.CommunityRating.HasValue)
{ {
@ -1015,7 +995,7 @@ namespace MediaBrowser.Providers.Manager
{ {
targetResult.People = sourceResult.People; targetResult.People = sourceResult.People;
} }
else if (targetResult.People is not null && sourceResult.People is not null) else if (sourceResult.People is not null && sourceResult.People.Count >= 0)
{ {
MergePeople(sourceResult.People, targetResult.People); MergePeople(sourceResult.People, targetResult.People);
} }
@ -1048,6 +1028,10 @@ namespace MediaBrowser.Providers.Manager
{ {
target.Studios = source.Studios; target.Studios = source.Studios;
} }
else if (source.Studios.Length >= 0)
{
target.Studios = target.Studios.Concat(source.Studios).Distinct().ToArray();
}
} }
if (!lockedFields.Contains(MetadataField.Tags)) if (!lockedFields.Contains(MetadataField.Tags))
@ -1056,6 +1040,10 @@ namespace MediaBrowser.Providers.Manager
{ {
target.Tags = source.Tags; target.Tags = source.Tags;
} }
else if (source.Tags.Length >= 0)
{
target.Tags = target.Tags.Concat(source.Tags).Distinct().ToArray();
}
} }
if (!lockedFields.Contains(MetadataField.ProductionLocations)) if (!lockedFields.Contains(MetadataField.ProductionLocations))
@ -1064,6 +1052,10 @@ namespace MediaBrowser.Providers.Manager
{ {
target.ProductionLocations = source.ProductionLocations; target.ProductionLocations = source.ProductionLocations;
} }
else if (source.ProductionLocations.Length >= 0)
{
target.Tags = target.ProductionLocations.Concat(source.ProductionLocations).Distinct().ToArray();
}
} }
foreach (var id in source.ProviderIds) foreach (var id in source.ProviderIds)
@ -1081,40 +1073,78 @@ namespace MediaBrowser.Providers.Manager
} }
} }
if (replaceData || !target.CriticRating.HasValue)
{
target.CriticRating = source.CriticRating;
}
if (replaceData || target.RemoteTrailers.Count == 0)
{
target.RemoteTrailers = source.RemoteTrailers;
}
else if (source.CriticRating.HasValue)
{
target.RemoteTrailers = target.RemoteTrailers.Concat(source.RemoteTrailers).Distinct().ToArray();
}
MergeAlbumArtist(source, target, replaceData); MergeAlbumArtist(source, target, replaceData);
MergeCriticRating(source, target, replaceData);
MergeTrailers(source, target, replaceData);
MergeVideoInfo(source, target, replaceData); MergeVideoInfo(source, target, replaceData);
MergeDisplayOrder(source, target, replaceData); MergeDisplayOrder(source, target, replaceData);
if (replaceData || string.IsNullOrEmpty(target.ForcedSortName)) if (replaceData || string.IsNullOrEmpty(target.ForcedSortName))
{ {
var forcedSortName = source.ForcedSortName; var forcedSortName = source.ForcedSortName;
if (!string.IsNullOrEmpty(forcedSortName))
if (!string.IsNullOrWhiteSpace(forcedSortName))
{ {
target.ForcedSortName = forcedSortName; target.ForcedSortName = forcedSortName;
} }
} }
if (mergeMetadataSettings) if (mergeMetadataSettings)
{
if (replaceData || target.LockedFields.Length == 0)
{ {
target.LockedFields = source.LockedFields; target.LockedFields = source.LockedFields;
target.IsLocked = source.IsLocked; }
else
{
target.LockedFields = target.LockedFields.Concat(source.LockedFields).Distinct().ToArray();
}
if (replaceData)
{
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) if (source.DateCreated != default)
{ {
target.DateCreated = source.DateCreated; target.DateCreated = source.DateCreated;
} }
if (replaceData)
{
target.IsLocked = source.IsLocked;
}
if (replaceData || string.IsNullOrEmpty(target.PreferredMetadataCountryCode))
{
target.PreferredMetadataCountryCode = source.PreferredMetadataCountryCode; target.PreferredMetadataCountryCode = source.PreferredMetadataCountryCode;
}
if (replaceData || string.IsNullOrEmpty(target.PreferredMetadataLanguage))
{
target.PreferredMetadataLanguage = source.PreferredMetadataLanguage; target.PreferredMetadataLanguage = source.PreferredMetadataLanguage;
} }
} }
}
private static void MergePeople(List<PersonInfo> source, List<PersonInfo> target) private static void MergePeople(List<PersonInfo> source, List<PersonInfo> target)
{ {
if (target is null)
{
target = new List<PersonInfo>();
}
foreach (var person in target) foreach (var person in target)
{ {
var normalizedName = person.Name.RemoveDiacritics(); var normalizedName = person.Name.RemoveDiacritics();
@ -1143,7 +1173,6 @@ namespace MediaBrowser.Providers.Manager
if (replaceData || string.IsNullOrEmpty(targetHasDisplayOrder.DisplayOrder)) if (replaceData || string.IsNullOrEmpty(targetHasDisplayOrder.DisplayOrder))
{ {
var displayOrder = sourceHasDisplayOrder.DisplayOrder; var displayOrder = sourceHasDisplayOrder.DisplayOrder;
if (!string.IsNullOrWhiteSpace(displayOrder)) if (!string.IsNullOrWhiteSpace(displayOrder))
{ {
targetHasDisplayOrder.DisplayOrder = displayOrder; targetHasDisplayOrder.DisplayOrder = displayOrder;
@ -1161,30 +1190,18 @@ namespace MediaBrowser.Providers.Manager
{ {
targetHasAlbumArtist.AlbumArtists = sourceHasAlbumArtist.AlbumArtists; targetHasAlbumArtist.AlbumArtists = sourceHasAlbumArtist.AlbumArtists;
} }
} else if (sourceHasAlbumArtist.AlbumArtists.Count >= 0)
}
private static void MergeCriticRating(BaseItem source, BaseItem target, bool replaceData)
{ {
if (replaceData || !target.CriticRating.HasValue) targetHasAlbumArtist.AlbumArtists = targetHasAlbumArtist.AlbumArtists.Concat(sourceHasAlbumArtist.AlbumArtists).Distinct().ToArray();
{
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) private static void MergeVideoInfo(BaseItem source, BaseItem target, bool replaceData)
{ {
if (source is Video sourceCast && target is Video targetCast) if (source is Video sourceCast && target is Video targetCast)
{ {
if (replaceData || targetCast.Video3DFormat is null) if (replaceData || !targetCast.Video3DFormat.HasValue)
{ {
targetCast.Video3DFormat = sourceCast.Video3DFormat; targetCast.Video3DFormat = sourceCast.Video3DFormat;
} }

View File

@ -24,7 +24,7 @@ namespace MediaBrowser.Providers.Movies
} }
/// <inheritdoc /> /// <inheritdoc />
protected override bool IsFullLocalMetadata(Movie item) protected override bool HasBaseMetadata(Movie item)
{ {
if (string.IsNullOrWhiteSpace(item.Overview)) if (string.IsNullOrWhiteSpace(item.Overview))
{ {
@ -36,7 +36,7 @@ namespace MediaBrowser.Providers.Movies
return false; return false;
} }
return base.IsFullLocalMetadata(item); return base.HasBaseMetadata(item);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -1,5 +1,6 @@
#pragma warning disable CS1591 #pragma warning disable CS1591
using System.Linq;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
@ -24,7 +25,7 @@ namespace MediaBrowser.Providers.Movies
} }
/// <inheritdoc /> /// <inheritdoc />
protected override bool IsFullLocalMetadata(Trailer item) protected override bool HasBaseMetadata(Trailer item)
{ {
if (string.IsNullOrWhiteSpace(item.Overview)) if (string.IsNullOrWhiteSpace(item.Overview))
{ {
@ -36,7 +37,7 @@ namespace MediaBrowser.Providers.Movies
return false; return false;
} }
return base.IsFullLocalMetadata(item); return base.HasBaseMetadata(item);
} }
/// <inheritdoc /> /// <inheritdoc />
@ -48,6 +49,10 @@ namespace MediaBrowser.Providers.Movies
{ {
target.Item.TrailerTypes = source.Item.TrailerTypes; target.Item.TrailerTypes = source.Item.TrailerTypes;
} }
else
{
target.Item.TrailerTypes = target.Item.TrailerTypes.Concat(source.Item.TrailerTypes).Distinct().ToArray();
}
} }
} }
} }

View File

@ -225,6 +225,10 @@ namespace MediaBrowser.Providers.Music
{ {
targetItem.Artists = sourceItem.Artists; targetItem.Artists = sourceItem.Artists;
} }
else
{
targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct().ToArray();
}
if (replaceData || string.IsNullOrEmpty(targetItem.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist))) if (replaceData || string.IsNullOrEmpty(targetItem.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist)))
{ {

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Linq;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
@ -60,6 +61,10 @@ namespace MediaBrowser.Providers.Music
{ {
targetItem.Artists = sourceItem.Artists; targetItem.Artists = sourceItem.Artists;
} }
else
{
targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct().ToArray();
}
if (replaceData || string.IsNullOrEmpty(targetItem.Album)) if (replaceData || string.IsNullOrEmpty(targetItem.Album))
{ {

View File

@ -1,5 +1,6 @@
#pragma warning disable CS1591 #pragma warning disable CS1591
using System.Linq;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
@ -45,6 +46,10 @@ namespace MediaBrowser.Providers.Music
{ {
targetItem.Artists = sourceItem.Artists; targetItem.Artists = sourceItem.Artists;
} }
else
{
targetItem.Artists = targetItem.Artists.Concat(sourceItem.Artists).Distinct().ToArray();
}
} }
} }
} }

View File

@ -1,6 +1,7 @@
#pragma warning disable CS1591 #pragma warning disable CS1591
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
@ -49,9 +50,25 @@ namespace MediaBrowser.Providers.Playlists
if (mergeMetadataSettings) if (mergeMetadataSettings)
{ {
targetItem.PlaylistMediaType = sourceItem.PlaylistMediaType; targetItem.PlaylistMediaType = sourceItem.PlaylistMediaType;
if (replaceData || targetItem.LinkedChildren.Length == 0)
{
targetItem.LinkedChildren = sourceItem.LinkedChildren; targetItem.LinkedChildren = sourceItem.LinkedChildren;
}
else
{
targetItem.LinkedChildren = sourceItem.LinkedChildren.Concat(targetItem.LinkedChildren).Distinct().ToArray();
}
if (replaceData || targetItem.Shares.Count == 0)
{
targetItem.Shares = sourceItem.Shares; targetItem.Shares = sourceItem.Shares;
} }
else
{
targetItem.Shares = sourceItem.Shares.Concat(targetItem.Shares).DistinctBy(s => s.UserId).ToArray();
}
}
} }
} }
} }

View File

@ -66,7 +66,7 @@ namespace MediaBrowser.Providers.TV
} }
/// <inheritdoc /> /// <inheritdoc />
protected override bool IsFullLocalMetadata(Series item) protected override bool HasBaseMetadata(Series item)
{ {
if (string.IsNullOrWhiteSpace(item.Overview)) if (string.IsNullOrWhiteSpace(item.Overview))
{ {
@ -78,7 +78,7 @@ namespace MediaBrowser.Providers.TV
return false; return false;
} }
return base.IsFullLocalMetadata(item); return base.HasBaseMetadata(item);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -77,7 +77,7 @@ namespace Jellyfin.Providers.Tests.Manager
[Theory] [Theory]
[InlineData("Name", MetadataField.Name, false)] [InlineData("Name", MetadataField.Name, false)]
[InlineData("OriginalTitle", null, false)] [InlineData("OriginalTitle", null)]
[InlineData("OfficialRating", MetadataField.OfficialRating)] [InlineData("OfficialRating", MetadataField.OfficialRating)]
[InlineData("CustomRating")] [InlineData("CustomRating")]
[InlineData("Tagline")] [InlineData("Tagline")]