Extend music parsing
This commit is contained in:
parent
0246ba1fb4
commit
61fa325ef0
|
@ -181,6 +181,24 @@ namespace Emby.Naming.Common
|
|||
"volume"
|
||||
};
|
||||
|
||||
ArtistSubfolders = new[]
|
||||
{
|
||||
"albums",
|
||||
"broadcasts",
|
||||
"bootlegs",
|
||||
"compilations",
|
||||
"dj-mixes",
|
||||
"eps",
|
||||
"live",
|
||||
"mixtapes",
|
||||
"others",
|
||||
"remixes",
|
||||
"singles",
|
||||
"soundtracks",
|
||||
"spokenwords",
|
||||
"streets"
|
||||
};
|
||||
|
||||
AudioFileExtensions = new[]
|
||||
{
|
||||
".669",
|
||||
|
@ -732,6 +750,11 @@ namespace Emby.Naming.Common
|
|||
/// </summary>
|
||||
public string[] AlbumStackingPrefixes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets list of artist subfolders.
|
||||
/// </summary>
|
||||
public string[] ArtistSubfolders { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets list of subtitle file extensions.
|
||||
/// </summary>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -98,7 +99,15 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
|||
// Args points to an album if parent is an Artist folder or it directly contains music
|
||||
if (args.IsDirectory)
|
||||
{
|
||||
// if (args.Parent is MusicArtist) return true; // saves us from testing children twice
|
||||
foreach (var subfolder in _namingOptions.ArtistSubfolders)
|
||||
{
|
||||
if (Path.GetDirectoryName(args.Path.AsSpan()).Equals(subfolder, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
_logger.LogDebug("Found release folder: {Path}", args.Path);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService))
|
||||
{
|
||||
return true;
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
public string AlbumArtist => AlbumArtists.FirstOrDefault();
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
public override bool SupportsPeople => true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tracks.
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="OptimizedPriorityQueue" Version="5.1.0" />
|
||||
<PackageReference Include="PlaylistsNET" Version="1.2.1" />
|
||||
<PackageReference Include="TagLibSharp" Version="2.2.0" />
|
||||
<PackageReference Include="TMDbLib" Version="1.9.2" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -17,6 +18,7 @@ using MediaBrowser.Model.Dlna;
|
|||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using TagLib;
|
||||
|
||||
namespace MediaBrowser.Providers.MediaInfo
|
||||
{
|
||||
|
@ -93,7 +95,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||
// var extension = (Path.GetExtension(audio.Path) ?? string.Empty).TrimStart('.');
|
||||
// audio.Container = extension;
|
||||
|
||||
FetchDataFromTags(audio, mediaInfo);
|
||||
FetchDataFromTags(audio);
|
||||
|
||||
_itemRepo.SaveMediaStreams(audio.Id, mediaInfo.MediaStreams, cancellationToken);
|
||||
}
|
||||
|
@ -102,71 +104,90 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||
/// Fetches data from the tags dictionary.
|
||||
/// </summary>
|
||||
/// <param name="audio">The audio.</param>
|
||||
/// <param name="data">The data.</param>
|
||||
private void FetchDataFromTags(Audio audio, Model.MediaInfo.MediaInfo data)
|
||||
private void FetchDataFromTags(Audio audio)
|
||||
{
|
||||
// Only set Name if title was found in the dictionary
|
||||
if (!string.IsNullOrEmpty(data.Name))
|
||||
var file = TagLib.File.Create(audio.Path);
|
||||
var tagTypes = file.TagTypesOnDisk;
|
||||
Tag tags = null;
|
||||
|
||||
if (tagTypes.HasFlag(TagTypes.Id3v2))
|
||||
{
|
||||
audio.Name = data.Name;
|
||||
tags = file.GetTag(TagTypes.Id3v2);
|
||||
}
|
||||
else if (tagTypes.HasFlag(TagTypes.Ape))
|
||||
{
|
||||
tags = file.GetTag(TagTypes.Ape);
|
||||
}
|
||||
else if (tagTypes.HasFlag(TagTypes.FlacMetadata))
|
||||
{
|
||||
tags = file.GetTag(TagTypes.FlacMetadata);
|
||||
}
|
||||
else if (tagTypes.HasFlag(TagTypes.Id3v1))
|
||||
{
|
||||
tags = file.GetTag(TagTypes.Id3v1);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(data.ForcedSortName))
|
||||
if (tags != null)
|
||||
{
|
||||
audio.ForcedSortName = data.ForcedSortName;
|
||||
}
|
||||
|
||||
if (audio.SupportsPeople && !audio.LockedFields.Contains(MetadataField.Cast))
|
||||
{
|
||||
var people = new List<PersonInfo>();
|
||||
|
||||
foreach (var person in data.People)
|
||||
if (audio.SupportsPeople && !audio.LockedFields.Contains(MetadataField.Cast))
|
||||
{
|
||||
PeopleHelper.AddPerson(people, new PersonInfo
|
||||
var people = new List<PersonInfo>();
|
||||
var albumArtists = tags.AlbumArtists;
|
||||
foreach (var albumArtist in albumArtists)
|
||||
{
|
||||
Name = person.Name,
|
||||
Type = person.Type,
|
||||
Role = person.Role
|
||||
});
|
||||
PeopleHelper.AddPerson(people, new PersonInfo
|
||||
{
|
||||
Name = albumArtist,
|
||||
Type = "AlbumArtist"
|
||||
});
|
||||
}
|
||||
|
||||
var performers = tags.Performers;
|
||||
foreach (var performer in performers)
|
||||
{
|
||||
PeopleHelper.AddPerson(people, new PersonInfo
|
||||
{
|
||||
Name = performer,
|
||||
Type = "Artist"
|
||||
});
|
||||
}
|
||||
|
||||
foreach (var composer in tags.Composers)
|
||||
{
|
||||
PeopleHelper.AddPerson(people, new PersonInfo
|
||||
{
|
||||
Name = composer,
|
||||
Type = "Composer"
|
||||
});
|
||||
}
|
||||
|
||||
_libraryManager.UpdatePeople(audio, people);
|
||||
audio.Artists = performers;
|
||||
audio.AlbumArtists = albumArtists;
|
||||
}
|
||||
|
||||
_libraryManager.UpdatePeople(audio, people);
|
||||
}
|
||||
|
||||
audio.Album = data.Album;
|
||||
audio.Artists = data.Artists;
|
||||
audio.AlbumArtists = data.AlbumArtists;
|
||||
audio.IndexNumber = data.IndexNumber;
|
||||
audio.ParentIndexNumber = data.ParentIndexNumber;
|
||||
audio.ProductionYear = data.ProductionYear;
|
||||
audio.PremiereDate = data.PremiereDate;
|
||||
|
||||
// If we don't have a ProductionYear try and get it from PremiereDate
|
||||
if (audio.PremiereDate.HasValue && !audio.ProductionYear.HasValue)
|
||||
{
|
||||
audio.ProductionYear = audio.PremiereDate.Value.ToLocalTime().Year;
|
||||
}
|
||||
|
||||
if (!audio.LockedFields.Contains(MetadataField.Genres))
|
||||
{
|
||||
audio.Genres = Array.Empty<string>();
|
||||
|
||||
foreach (var genre in data.Genres)
|
||||
audio.Name = tags.Title;
|
||||
audio.Album = tags.Album;
|
||||
audio.IndexNumber = Convert.ToInt32(tags.Track);
|
||||
audio.ParentIndexNumber = Convert.ToInt32(tags.Disc);
|
||||
if(tags.Year != 0)
|
||||
{
|
||||
audio.AddGenre(genre);
|
||||
var year = Convert.ToInt32(tags.Year);
|
||||
audio.ProductionYear = year;
|
||||
audio.PremiereDate = new DateTime(year, 01, 01);
|
||||
}
|
||||
}
|
||||
|
||||
if (!audio.LockedFields.Contains(MetadataField.Studios))
|
||||
{
|
||||
audio.SetStudios(data.Studios);
|
||||
}
|
||||
if (!audio.LockedFields.Contains(MetadataField.Genres))
|
||||
{
|
||||
audio.Genres = tags.Genres.Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
|
||||
}
|
||||
|
||||
audio.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, data.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist));
|
||||
audio.SetProviderId(MetadataProvider.MusicBrainzArtist, data.GetProviderId(MetadataProvider.MusicBrainzArtist));
|
||||
audio.SetProviderId(MetadataProvider.MusicBrainzAlbum, data.GetProviderId(MetadataProvider.MusicBrainzAlbum));
|
||||
audio.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, data.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup));
|
||||
audio.SetProviderId(MetadataProvider.MusicBrainzTrack, data.GetProviderId(MetadataProvider.MusicBrainzTrack));
|
||||
audio.SetProviderId(MetadataProvider.MusicBrainzArtist, tags.MusicBrainzArtistId);
|
||||
audio.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, tags.MusicBrainzReleaseArtistId);
|
||||
audio.SetProviderId(MetadataProvider.MusicBrainzAlbum, tags.MusicBrainzReleaseId);
|
||||
audio.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, tags.MusicBrainzReleaseGroupId);
|
||||
audio.SetProviderId(MetadataProvider.MusicBrainzTrack, tags.MusicBrainzTrackId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,40 +61,61 @@ namespace MediaBrowser.Providers.Music
|
|||
|
||||
var songs = children.Cast<Audio>().ToArray();
|
||||
|
||||
updateType |= SetAlbumArtistFromSongs(item, songs);
|
||||
updateType |= SetArtistsFromSongs(item, songs);
|
||||
updateType |= SetAlbumArtistFromSongs(item, songs);
|
||||
updateType |= SetAlbumFromSongs(item, songs);
|
||||
updateType |= SetPeople(item);
|
||||
}
|
||||
|
||||
return updateType;
|
||||
}
|
||||
|
||||
private ItemUpdateType SetAlbumArtistFromSongs(MusicAlbum item, IEnumerable<Audio> songs)
|
||||
private ItemUpdateType SetAlbumArtistFromSongs(MusicAlbum item, IReadOnlyList<Audio> songs)
|
||||
{
|
||||
var updateType = ItemUpdateType.None;
|
||||
|
||||
var artists = songs
|
||||
var albumArtists = songs
|
||||
.SelectMany(i => i.AlbumArtists)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.OrderBy(i => i)
|
||||
.GroupBy(i => i)
|
||||
.OrderByDescending(g => g.Count())
|
||||
.Select(g => g.Key)
|
||||
.ToArray();
|
||||
|
||||
if (!item.AlbumArtists.SequenceEqual(artists, StringComparer.OrdinalIgnoreCase))
|
||||
var musicbrainzAlbumArtistIds = songs
|
||||
.Select(i => i.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist))
|
||||
.GroupBy(i => i)
|
||||
.OrderByDescending(g => g.Count())
|
||||
.Select(g => g.Key)
|
||||
.ToArray();
|
||||
|
||||
var musicbrainzAlbumArtistId = item.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist);
|
||||
var firstMusicbrainzAlbumArtistId = musicbrainzAlbumArtistIds[0];
|
||||
if (!string.IsNullOrEmpty(firstMusicbrainzAlbumArtistId) &&
|
||||
(string.IsNullOrEmpty(musicbrainzAlbumArtistId)
|
||||
|| !musicbrainzAlbumArtistId.Equals(firstMusicbrainzAlbumArtistId, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
item.AlbumArtists = artists;
|
||||
item.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, firstMusicbrainzAlbumArtistId);
|
||||
updateType |= ItemUpdateType.MetadataEdit;
|
||||
}
|
||||
|
||||
if (!item.AlbumArtists.SequenceEqual(albumArtists, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
item.AlbumArtists = albumArtists;
|
||||
updateType |= ItemUpdateType.MetadataEdit;
|
||||
}
|
||||
|
||||
return updateType;
|
||||
}
|
||||
|
||||
private ItemUpdateType SetArtistsFromSongs(MusicAlbum item, IEnumerable<Audio> songs)
|
||||
private ItemUpdateType SetArtistsFromSongs(MusicAlbum item, IReadOnlyList<Audio> songs)
|
||||
{
|
||||
var updateType = ItemUpdateType.None;
|
||||
|
||||
var artists = songs
|
||||
.SelectMany(i => i.Artists)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.OrderBy(i => i)
|
||||
.GroupBy(i => i)
|
||||
.OrderByDescending(g => g.Count())
|
||||
.Select(g => g.Key)
|
||||
.ToArray();
|
||||
|
||||
if (!item.Artists.SequenceEqual(artists, StringComparer.OrdinalIgnoreCase))
|
||||
|
@ -106,6 +127,78 @@ namespace MediaBrowser.Providers.Music
|
|||
return updateType;
|
||||
}
|
||||
|
||||
private ItemUpdateType SetAlbumFromSongs(MusicAlbum item, IReadOnlyList<Audio> songs)
|
||||
{
|
||||
var updateType = ItemUpdateType.None;
|
||||
|
||||
var musicbrainzAlbumIds = songs
|
||||
.Select(i => i.GetProviderId(MetadataProvider.MusicBrainzAlbum))
|
||||
.GroupBy(i => i)
|
||||
.OrderByDescending(g => g.Count())
|
||||
.Select(g => g.Key)
|
||||
.ToArray();
|
||||
|
||||
var musicbrainzAlbumId = item.GetProviderId(MetadataProvider.MusicBrainzAlbum);
|
||||
if (!String.IsNullOrEmpty(musicbrainzAlbumIds[0])
|
||||
&& (String.IsNullOrEmpty(musicbrainzAlbumId)
|
||||
|| !musicbrainzAlbumId.Equals(musicbrainzAlbumIds[0], StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
item.SetProviderId(MetadataProvider.MusicBrainzAlbum, musicbrainzAlbumIds[0]!);
|
||||
updateType |= ItemUpdateType.MetadataEdit;
|
||||
}
|
||||
|
||||
var musicbrainzReleaseGroupIds = songs
|
||||
.Select(i => i.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup))
|
||||
.GroupBy(i => i)
|
||||
.OrderByDescending(g => g.Count())
|
||||
.Select(g => g.Key)
|
||||
.ToArray();
|
||||
|
||||
var musicbrainzReleaseGroupId = item.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup);
|
||||
if (!String.IsNullOrEmpty(musicbrainzReleaseGroupIds[0])
|
||||
&& (String.IsNullOrEmpty(musicbrainzReleaseGroupId)
|
||||
|| !musicbrainzReleaseGroupId.Equals(musicbrainzReleaseGroupIds[0], StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
item.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, musicbrainzReleaseGroupIds[0]!);
|
||||
updateType |= ItemUpdateType.MetadataEdit;
|
||||
}
|
||||
|
||||
return updateType;
|
||||
}
|
||||
|
||||
private ItemUpdateType SetPeople(MusicAlbum item)
|
||||
{
|
||||
var updateType = ItemUpdateType.None;
|
||||
|
||||
if (item.AlbumArtists.Any() || item.Artists.Any())
|
||||
{
|
||||
var people = new List<PersonInfo>();
|
||||
|
||||
foreach (var albumArtist in item.AlbumArtists)
|
||||
{
|
||||
PeopleHelper.AddPerson(people, new PersonInfo
|
||||
{
|
||||
Name = albumArtist,
|
||||
Type = "AlbumArtist"
|
||||
});
|
||||
}
|
||||
|
||||
foreach (var artist in item.Artists)
|
||||
{
|
||||
PeopleHelper.AddPerson(people, new PersonInfo
|
||||
{
|
||||
Name = artist,
|
||||
Type = "Artist"
|
||||
});
|
||||
}
|
||||
|
||||
LibraryManager.UpdatePeople(item, people);
|
||||
updateType |= ItemUpdateType.MetadataEdit;
|
||||
}
|
||||
|
||||
return updateType;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void MergeData(
|
||||
MetadataResult<MusicAlbum> source,
|
||||
|
@ -123,6 +216,45 @@ namespace MediaBrowser.Providers.Music
|
|||
{
|
||||
targetItem.Artists = sourceItem.Artists;
|
||||
}
|
||||
|
||||
if (replaceData || string.IsNullOrEmpty(targetItem.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist)))
|
||||
{
|
||||
var targetAlbumArtistId = targetItem.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist);
|
||||
var sourceAlbumArtistId = sourceItem.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist);
|
||||
|
||||
if (!string.IsNullOrEmpty(sourceAlbumArtistId)
|
||||
&& (string.IsNullOrEmpty(targetAlbumArtistId)
|
||||
|| !targetAlbumArtistId.Equals(sourceAlbumArtistId, StringComparison.Ordinal)))
|
||||
{
|
||||
targetItem.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, sourceAlbumArtistId);
|
||||
}
|
||||
}
|
||||
|
||||
if (replaceData || string.IsNullOrEmpty(targetItem.GetProviderId(MetadataProvider.MusicBrainzAlbum)))
|
||||
{
|
||||
var targetAlbumId = targetItem.GetProviderId(MetadataProvider.MusicBrainzAlbum);
|
||||
var sourceAlbumId = sourceItem.GetProviderId(MetadataProvider.MusicBrainzAlbum);
|
||||
|
||||
if (!string.IsNullOrEmpty(sourceAlbumId)
|
||||
&& (string.IsNullOrEmpty(targetAlbumId)
|
||||
|| !targetAlbumId.Equals(sourceAlbumId, StringComparison.Ordinal)))
|
||||
{
|
||||
targetItem.SetProviderId(MetadataProvider.MusicBrainzAlbum, sourceAlbumId);
|
||||
}
|
||||
}
|
||||
|
||||
if (replaceData || string.IsNullOrEmpty(targetItem.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup)))
|
||||
{
|
||||
var targetReleaseGroupId = targetItem.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup);
|
||||
var sourceReleaseGroupId = sourceItem.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup);
|
||||
|
||||
if (!string.IsNullOrEmpty(sourceReleaseGroupId)
|
||||
&& (string.IsNullOrEmpty(targetReleaseGroupId)
|
||||
|| !targetReleaseGroupId.Equals(sourceItem)))
|
||||
{
|
||||
targetItem.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, sourceReleaseGroupId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
|
@ -40,6 +41,45 @@ namespace MediaBrowser.Providers.Music
|
|||
{
|
||||
targetItem.Album = sourceItem.Album;
|
||||
}
|
||||
|
||||
var targetAlbumArtistId = targetItem.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist);
|
||||
if (replaceData || string.IsNullOrEmpty(targetAlbumArtistId))
|
||||
{
|
||||
var sourceAlbumArtistId = sourceItem.GetProviderId(MetadataProvider.MusicBrainzAlbumArtist);
|
||||
|
||||
if (!string.IsNullOrEmpty(sourceAlbumArtistId)
|
||||
&& (string.IsNullOrEmpty(targetAlbumArtistId)
|
||||
|| !targetAlbumArtistId.Equals(sourceAlbumArtistId, StringComparison.Ordinal)))
|
||||
{
|
||||
targetItem.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, sourceAlbumArtistId);
|
||||
}
|
||||
}
|
||||
|
||||
var targetAlbumId = targetItem.GetProviderId(MetadataProvider.MusicBrainzAlbum);
|
||||
if (replaceData || string.IsNullOrEmpty(targetAlbumId))
|
||||
{
|
||||
var sourceAlbumId = sourceItem.GetProviderId(MetadataProvider.MusicBrainzAlbum);
|
||||
|
||||
if (!string.IsNullOrEmpty(sourceAlbumId)
|
||||
&& (string.IsNullOrEmpty(targetAlbumId)
|
||||
|| !targetAlbumId.Equals(sourceAlbumId, StringComparison.Ordinal)))
|
||||
{
|
||||
targetItem.SetProviderId(MetadataProvider.MusicBrainzAlbum, sourceAlbumId);
|
||||
}
|
||||
}
|
||||
|
||||
var targetReleaseGroupId = targetItem.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup);
|
||||
if (replaceData || string.IsNullOrEmpty(targetReleaseGroupId))
|
||||
{
|
||||
var sourceReleaseGroupId = sourceItem.GetProviderId(MetadataProvider.MusicBrainzReleaseGroup);
|
||||
|
||||
if (!string.IsNullOrEmpty(sourceReleaseGroupId)
|
||||
&& (string.IsNullOrEmpty(targetReleaseGroupId)
|
||||
|| !targetReleaseGroupId.Equals(sourceReleaseGroupId, StringComparison.Ordinal)))
|
||||
{
|
||||
targetItem.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, sourceReleaseGroupId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user