Backport pull request #11743 from jellyfin/release-10.9.z

Fix replace logic

Original-merge: 2ddb15c7845a944d980364209c2304f03cebf025

Merged-by: joshuaboniface <joshua@boniface.me>

Backported-by: Joshua M. Boniface <joshua@boniface.me>
This commit is contained in:
Shadowghost 2024-06-01 18:40:56 -04:00 committed by Joshua M. Boniface
parent c0364fc766
commit 5d4880c497
16 changed files with 181 additions and 159 deletions

View File

@ -5222,19 +5222,20 @@ AND Type = @InternalPersonType)");
throw new ArgumentNullException(nameof(itemId)); throw new ArgumentNullException(nameof(itemId));
} }
ArgumentNullException.ThrowIfNull(people);
CheckDisposed(); CheckDisposed();
using var connection = GetConnection(); using var connection = GetConnection();
using var transaction = connection.BeginTransaction(); using var transaction = connection.BeginTransaction();
// First delete chapters // Delete all existing people first
using var command = connection.CreateCommand(); using var command = connection.CreateCommand();
command.CommandText = "delete from People where ItemId=@ItemId"; command.CommandText = "delete from People where ItemId=@ItemId";
command.TryBind("@ItemId", itemId); command.TryBind("@ItemId", itemId);
command.ExecuteNonQuery(); command.ExecuteNonQuery();
InsertPeople(itemId, people, connection); if (people is not null)
{
InsertPeople(itemId, people, connection);
}
transaction.Commit(); transaction.Commit();
} }

View File

@ -2812,8 +2812,10 @@ namespace Emby.Server.Implementations.Library
} }
_itemRepository.UpdatePeople(item.Id, people); _itemRepository.UpdatePeople(item.Id, people);
if (people is not null)
await SavePeopleMetadataAsync(people, cancellationToken).ConfigureAwait(false); {
await SavePeopleMetadataAsync(people, cancellationToken).ConfigureAwait(false);
}
} }
public async Task<ItemImageInfo> ConvertImageToLocal(BaseItem item, ItemImageInfo image, int imageIndex, bool removeOnFailure) public async Task<ItemImageInfo> ConvertImageToLocal(BaseItem item, ItemImageInfo image, int imageIndex, bool removeOnFailure)

View File

@ -290,17 +290,35 @@ public class ItemUpdateController : BaseJellyfinApiController
{ {
foreach (var season in rseries.Children.OfType<Season>()) foreach (var season in rseries.Children.OfType<Season>())
{ {
season.OfficialRating = request.OfficialRating; if (!season.LockedFields.Contains(MetadataField.OfficialRating))
{
season.OfficialRating = request.OfficialRating;
}
season.CustomRating = request.CustomRating; season.CustomRating = request.CustomRating;
season.Tags = season.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray();
if (!season.LockedFields.Contains(MetadataField.Tags))
{
season.Tags = season.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray();
}
season.OnMetadataChanged(); season.OnMetadataChanged();
await season.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); await season.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
foreach (var ep in season.Children.OfType<Episode>()) foreach (var ep in season.Children.OfType<Episode>())
{ {
ep.OfficialRating = request.OfficialRating; if (!ep.LockedFields.Contains(MetadataField.OfficialRating))
{
ep.OfficialRating = request.OfficialRating;
}
ep.CustomRating = request.CustomRating; ep.CustomRating = request.CustomRating;
ep.Tags = ep.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray();
if (!ep.LockedFields.Contains(MetadataField.Tags))
{
ep.Tags = ep.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray();
}
ep.OnMetadataChanged(); ep.OnMetadataChanged();
await ep.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); await ep.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
} }
@ -310,9 +328,18 @@ public class ItemUpdateController : BaseJellyfinApiController
{ {
foreach (var ep in season.Children.OfType<Episode>()) foreach (var ep in season.Children.OfType<Episode>())
{ {
ep.OfficialRating = request.OfficialRating; if (!ep.LockedFields.Contains(MetadataField.OfficialRating))
{
ep.OfficialRating = request.OfficialRating;
}
ep.CustomRating = request.CustomRating; ep.CustomRating = request.CustomRating;
ep.Tags = ep.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray();
if (!ep.LockedFields.Contains(MetadataField.Tags))
{
ep.Tags = ep.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray();
}
ep.OnMetadataChanged(); ep.OnMetadataChanged();
await ep.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); await ep.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
} }
@ -321,9 +348,18 @@ public class ItemUpdateController : BaseJellyfinApiController
{ {
foreach (BaseItem track in album.Children) foreach (BaseItem track in album.Children)
{ {
track.OfficialRating = request.OfficialRating; if (!track.LockedFields.Contains(MetadataField.OfficialRating))
{
track.OfficialRating = request.OfficialRating;
}
track.CustomRating = request.CustomRating; track.CustomRating = request.CustomRating;
track.Tags = track.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray();
if (!track.LockedFields.Contains(MetadataField.Tags))
{
track.Tags = track.Tags.Concat(addedTags).Except(removedTags).Distinct().ToArray();
}
track.OnMetadataChanged(); track.OnMetadataChanged();
await track.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); await track.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
} }

View File

@ -751,9 +751,6 @@ namespace MediaBrowser.Controller.Entities
[JsonIgnore] [JsonIgnore]
public virtual bool SupportsAncestors => true; public virtual bool SupportsAncestors => true;
[JsonIgnore]
public virtual bool StopRefreshIfLocalMetadataFound => true;
[JsonIgnore] [JsonIgnore]
protected virtual bool SupportsOwnedItems => !ParentId.IsEmpty() && IsFileProtocol; protected virtual bool SupportsOwnedItems => !ParentId.IsEmpty() && IsFileProtocol;

View File

@ -45,9 +45,6 @@ namespace MediaBrowser.Controller.Entities.Movies
set => TmdbCollectionName = value; set => TmdbCollectionName = value;
} }
[JsonIgnore]
public override bool StopRefreshIfLocalMetadataFound => false;
public override double GetDefaultPrimaryImageAspectRatio() public override double GetDefaultPrimaryImageAspectRatio()
{ {
// hack for tv plugins // hack for tv plugins

View File

@ -69,9 +69,6 @@ namespace MediaBrowser.Controller.Entities.TV
/// <value>The status.</value> /// <value>The status.</value>
public SeriesStatus? Status { get; set; } public SeriesStatus? Status { get; set; }
[JsonIgnore]
public override bool StopRefreshIfLocalMetadataFound => false;
public override double GetDefaultPrimaryImageAspectRatio() public override double GetDefaultPrimaryImageAspectRatio()
{ {
double value = 2; double value = 2;
@ -288,8 +285,7 @@ namespace MediaBrowser.Controller.Entities.TV
public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken) public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
{ {
// Refresh bottom up, children first, then the boxset // Refresh bottom up, seasons and episodes first, then the series
// By then hopefully the movies within will have Tmdb collection values
var items = GetRecursiveChildren(); var items = GetRecursiveChildren();
var totalItems = items.Count; var totalItems = items.Count;

View File

@ -23,9 +23,6 @@ namespace MediaBrowser.Controller.Entities
TrailerTypes = Array.Empty<TrailerType>(); TrailerTypes = Array.Empty<TrailerType>();
} }
[JsonIgnore]
public override bool StopRefreshIfLocalMetadataFound => false;
public TrailerType[] TrailerTypes { get; set; } public TrailerType[] TrailerTypes { get; set; }
public override double GetDefaultPrimaryImageAspectRatio() public override double GetDefaultPrimaryImageAspectRatio()

View File

@ -121,7 +121,8 @@ namespace MediaBrowser.Providers.Manager
var metadataResult = new MetadataResult<TItemType> var metadataResult = new MetadataResult<TItemType>
{ {
Item = itemOfType Item = itemOfType,
People = LibraryManager.GetPeople(item)
}; };
bool hasRefreshedMetadata = true; bool hasRefreshedMetadata = true;
@ -164,7 +165,7 @@ namespace MediaBrowser.Providers.Manager
} }
// Next run remote image providers, but only if local image providers didn't throw an exception // Next run remote image providers, but only if local image providers didn't throw an exception
if (!localImagesFailed && refreshOptions.ImageRefreshMode != MetadataRefreshMode.ValidationOnly) if (!localImagesFailed && refreshOptions.ImageRefreshMode > MetadataRefreshMode.ValidationOnly)
{ {
var providers = GetNonLocalImageProviders(item, allImageProviders, refreshOptions).ToList(); var providers = GetNonLocalImageProviders(item, allImageProviders, refreshOptions).ToList();
@ -242,7 +243,7 @@ namespace MediaBrowser.Providers.Manager
protected async Task SaveItemAsync(MetadataResult<TItemType> result, ItemUpdateType reason, CancellationToken cancellationToken) protected async Task SaveItemAsync(MetadataResult<TItemType> result, ItemUpdateType reason, CancellationToken cancellationToken)
{ {
if (result.Item.SupportsPeople && result.People is not null) if (result.Item.SupportsPeople)
{ {
var baseItem = result.Item; var baseItem = result.Item;
@ -655,26 +656,19 @@ 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)
{
return refreshResult;
}
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
if (options.ReplaceAllMetadata)
{
var remoteResult = await ExecuteRemoteProviders(temp, logName, 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>>())
{ {
var providerName = provider.GetType().Name; var providerName = provider.GetType().Name;
@ -720,15 +714,9 @@ 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
if (item.IsLocked || localItem.Item.IsLocked || IsFullLocalMetadata(localItem.Item))
{
hasLocalMetadata = true;
}
break; break;
} }
@ -747,10 +735,10 @@ namespace MediaBrowser.Providers.Manager
} }
} }
// Local metadata is king - if any is found don't run remote providers var isLocalLocked = temp.Item.IsLocked;
if (!options.ReplaceAllMetadata && (!hasLocalMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || !item.StopRefreshIfLocalMetadataFound)) if (!isLocalLocked && (options.ReplaceAllMetadata || options.MetadataRefreshMode > MetadataRefreshMode.ValidationOnly))
{ {
var remoteResult = await ExecuteRemoteProviders(temp, logName, 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);
refreshResult.UpdateType |= remoteResult.UpdateType; refreshResult.UpdateType |= remoteResult.UpdateType;
@ -762,19 +750,20 @@ namespace MediaBrowser.Providers.Manager
{ {
if (refreshResult.UpdateType > ItemUpdateType.None) if (refreshResult.UpdateType > ItemUpdateType.None)
{ {
if (hasLocalMetadata) if (!options.RemoveOldMetadata)
{
// Add existing metadata to provider result if it does not exist there
MergeData(metadata, temp, Array.Empty<MetadataField>(), false, false);
}
if (isLocalLocked)
{ {
MergeData(temp, metadata, item.LockedFields, true, true); MergeData(temp, metadata, item.LockedFields, true, true);
} }
else else
{ {
if (!options.RemoveOldMetadata) var shouldReplace = options.MetadataRefreshMode > MetadataRefreshMode.ValidationOnly || options.ReplaceAllMetadata;
{ MergeData(temp, metadata, item.LockedFields, shouldReplace, false);
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, false);
} }
} }
} }
@ -787,16 +776,6 @@ namespace MediaBrowser.Providers.Manager
return refreshResult; return refreshResult;
} }
protected virtual bool IsFullLocalMetadata(TItemType item)
{
if (string.IsNullOrWhiteSpace(item.Name))
{
return false;
}
return true;
}
private async Task RunCustomProvider(ICustomMetadataProvider<TItemType> provider, TItemType item, string logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) private async Task RunCustomProvider(ICustomMetadataProvider<TItemType> provider, TItemType item, string logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken)
{ {
Logger.LogDebug("Running {Provider} for {Item}", provider.GetType().Name, logName); Logger.LogDebug("Running {Provider} for {Item}", provider.GetType().Name, logName);
@ -821,7 +800,7 @@ namespace MediaBrowser.Providers.Manager
return new TItemType(); return new TItemType();
} }
private async Task<RefreshResult> ExecuteRemoteProviders(MetadataResult<TItemType> temp, string logName, TIdType id, IEnumerable<IRemoteMetadataProvider<TItemType, TIdType>> providers, CancellationToken cancellationToken) private async Task<RefreshResult> ExecuteRemoteProviders(MetadataResult<TItemType> temp, string logName, bool replaceData, TIdType id, IEnumerable<IRemoteMetadataProvider<TItemType, TIdType>> providers, CancellationToken cancellationToken)
{ {
var refreshResult = new RefreshResult(); var refreshResult = new RefreshResult();
@ -846,7 +825,7 @@ namespace MediaBrowser.Providers.Manager
{ {
result.Provider = provider.Name; result.Provider = provider.Name;
MergeData(result, temp, Array.Empty<MetadataField>(), false, false); MergeData(result, temp, Array.Empty<MetadataField>(), replaceData, false);
MergeNewData(temp.Item, id); MergeNewData(temp.Item, id);
refreshResult.UpdateType |= ItemUpdateType.MetadataDownload; refreshResult.UpdateType |= ItemUpdateType.MetadataDownload;
@ -949,11 +928,7 @@ namespace MediaBrowser.Providers.Manager
if (replaceData || string.IsNullOrEmpty(target.OriginalTitle)) if (replaceData || string.IsNullOrEmpty(target.OriginalTitle))
{ {
// Safeguard against incoming data having an empty name target.OriginalTitle = source.OriginalTitle;
if (!string.IsNullOrWhiteSpace(source.OriginalTitle))
{
target.OriginalTitle = source.OriginalTitle;
}
} }
if (replaceData || !target.CommunityRating.HasValue) if (replaceData || !target.CommunityRating.HasValue)
@ -1016,7 +991,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);
} }
@ -1049,6 +1024,10 @@ namespace MediaBrowser.Providers.Manager
{ {
target.Studios = source.Studios; target.Studios = source.Studios;
} }
else
{
target.Studios = target.Studios.Concat(source.Studios).Distinct().ToArray();
}
} }
if (!lockedFields.Contains(MetadataField.Tags)) if (!lockedFields.Contains(MetadataField.Tags))
@ -1057,6 +1036,10 @@ namespace MediaBrowser.Providers.Manager
{ {
target.Tags = source.Tags; target.Tags = source.Tags;
} }
else
{
target.Tags = target.Tags.Concat(source.Tags).Distinct().ToArray();
}
} }
if (!lockedFields.Contains(MetadataField.ProductionLocations)) if (!lockedFields.Contains(MetadataField.ProductionLocations))
@ -1065,6 +1048,10 @@ namespace MediaBrowser.Providers.Manager
{ {
target.ProductionLocations = source.ProductionLocations; target.ProductionLocations = source.ProductionLocations;
} }
else
{
target.Tags = target.ProductionLocations.Concat(source.ProductionLocations).Distinct().ToArray();
}
} }
foreach (var id in source.ProviderIds) foreach (var id in source.ProviderIds)
@ -1082,17 +1069,28 @@ namespace MediaBrowser.Providers.Manager
} }
} }
if (replaceData || !target.CriticRating.HasValue)
{
target.CriticRating = source.CriticRating;
}
if (replaceData || target.RemoteTrailers.Count == 0)
{
target.RemoteTrailers = source.RemoteTrailers;
}
else
{
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;
} }
@ -1100,22 +1098,44 @@ namespace MediaBrowser.Providers.Manager
if (mergeMetadataSettings) if (mergeMetadataSettings)
{ {
target.LockedFields = source.LockedFields; if (replaceData || !target.IsLocked)
target.IsLocked = source.IsLocked; {
target.IsLocked = target.IsLocked || source.IsLocked;
}
if (target.LockedFields.Length == 0)
{
target.LockedFields = source.LockedFields;
}
else
{
target.LockedFields = target.LockedFields.Concat(source.LockedFields).Distinct().ToArray();
}
// 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;
} }
target.PreferredMetadataCountryCode = source.PreferredMetadataCountryCode; if (replaceData || string.IsNullOrEmpty(target.PreferredMetadataCountryCode))
target.PreferredMetadataLanguage = source.PreferredMetadataLanguage; {
target.PreferredMetadataCountryCode = source.PreferredMetadataCountryCode;
}
if (replaceData || string.IsNullOrEmpty(target.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();
@ -1144,7 +1164,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;
@ -1162,22 +1181,10 @@ namespace MediaBrowser.Providers.Manager
{ {
targetHasAlbumArtist.AlbumArtists = sourceHasAlbumArtist.AlbumArtists; targetHasAlbumArtist.AlbumArtists = sourceHasAlbumArtist.AlbumArtists;
} }
} else if (sourceHasAlbumArtist.AlbumArtists.Count >= 0)
} {
targetHasAlbumArtist.AlbumArtists = targetHasAlbumArtist.AlbumArtists.Concat(sourceHasAlbumArtist.AlbumArtists).Distinct().ToArray();
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;
} }
} }
@ -1185,7 +1192,7 @@ namespace MediaBrowser.Providers.Manager
{ {
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

@ -23,22 +23,6 @@ namespace MediaBrowser.Providers.Movies
{ {
} }
/// <inheritdoc />
protected override bool IsFullLocalMetadata(Movie item)
{
if (string.IsNullOrWhiteSpace(item.Overview))
{
return false;
}
if (!item.ProductionYear.HasValue)
{
return false;
}
return base.IsFullLocalMetadata(item);
}
/// <inheritdoc /> /// <inheritdoc />
protected override void MergeData(MetadataResult<Movie> source, MetadataResult<Movie> target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) protected override void MergeData(MetadataResult<Movie> source, MetadataResult<Movie> target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{ {

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;
@ -23,22 +24,6 @@ namespace MediaBrowser.Providers.Movies
{ {
} }
/// <inheritdoc />
protected override bool IsFullLocalMetadata(Trailer item)
{
if (string.IsNullOrWhiteSpace(item.Overview))
{
return false;
}
if (!item.ProductionYear.HasValue)
{
return false;
}
return base.IsFullLocalMetadata(item);
}
/// <inheritdoc /> /// <inheritdoc />
protected override void MergeData(MetadataResult<Trailer> source, MetadataResult<Trailer> target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) protected override void MergeData(MetadataResult<Trailer> source, MetadataResult<Trailer> target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{ {
@ -48,6 +33,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,8 +50,24 @@ namespace MediaBrowser.Providers.Playlists
if (mergeMetadataSettings) if (mergeMetadataSettings)
{ {
targetItem.PlaylistMediaType = sourceItem.PlaylistMediaType; targetItem.PlaylistMediaType = sourceItem.PlaylistMediaType;
targetItem.LinkedChildren = sourceItem.LinkedChildren;
targetItem.Shares = sourceItem.Shares; if (replaceData || targetItem.LinkedChildren.Length == 0)
{
targetItem.LinkedChildren = sourceItem.LinkedChildren;
}
else
{
targetItem.LinkedChildren = sourceItem.LinkedChildren.Concat(targetItem.LinkedChildren).Distinct().ToArray();
}
if (replaceData || targetItem.Shares.Count == 0)
{
targetItem.Shares = sourceItem.Shares;
}
else
{
targetItem.Shares = sourceItem.Shares.Concat(targetItem.Shares).DistinctBy(s => s.UserId).ToArray();
}
} }
} }
} }

View File

@ -65,22 +65,6 @@ namespace MediaBrowser.Providers.TV
await CreateSeasonsAsync(item, cancellationToken).ConfigureAwait(false); await CreateSeasonsAsync(item, cancellationToken).ConfigureAwait(false);
} }
/// <inheritdoc />
protected override bool IsFullLocalMetadata(Series item)
{
if (string.IsNullOrWhiteSpace(item.Overview))
{
return false;
}
if (!item.ProductionYear.HasValue)
{
return false;
}
return base.IsFullLocalMetadata(item);
}
/// <inheritdoc /> /// <inheritdoc />
protected override void MergeData(MetadataResult<Series> source, MetadataResult<Series> target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings) protected override void MergeData(MetadataResult<Series> source, MetadataResult<Series> target, MetadataField[] lockedFields, bool replaceData, bool mergeMetadataSettings)
{ {

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.Movies;
@ -19,7 +20,7 @@ namespace Jellyfin.Providers.Tests.Manager
[InlineData(true, true)] [InlineData(true, true)]
public void MergeBaseItemData_MergeMetadataSettings_MergesWhenSet(bool mergeMetadataSettings, bool defaultDate) public void MergeBaseItemData_MergeMetadataSettings_MergesWhenSet(bool mergeMetadataSettings, bool defaultDate)
{ {
var newLocked = new[] { MetadataField.Cast }; var newLocked = new[] { MetadataField.Genres, MetadataField.Cast };
var newString = "new"; var newString = "new";
var newDate = DateTime.Now; var newDate = DateTime.Now;
@ -77,7 +78,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")]