Extend music parsing

This commit is contained in:
Shadowghost 2022-03-28 23:11:21 +02:00
parent 0246ba1fb4
commit 61fa325ef0
7 changed files with 291 additions and 65 deletions

View File

@ -181,6 +181,24 @@ namespace Emby.Naming.Common
"volume" "volume"
}; };
ArtistSubfolders = new[]
{
"albums",
"broadcasts",
"bootlegs",
"compilations",
"dj-mixes",
"eps",
"live",
"mixtapes",
"others",
"remixes",
"singles",
"soundtracks",
"spokenwords",
"streets"
};
AudioFileExtensions = new[] AudioFileExtensions = new[]
{ {
".669", ".669",
@ -732,6 +750,11 @@ namespace Emby.Naming.Common
/// </summary> /// </summary>
public string[] AlbumStackingPrefixes { get; set; } public string[] AlbumStackingPrefixes { get; set; }
/// <summary>
/// Gets or sets list of artist subfolders.
/// </summary>
public string[] ArtistSubfolders { get; set; }
/// <summary> /// <summary>
/// Gets or sets list of subtitle file extensions. /// Gets or sets list of subtitle file extensions.
/// </summary> /// </summary>

View File

@ -2,6 +2,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; 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 // Args points to an album if parent is an Artist folder or it directly contains music
if (args.IsDirectory) 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)) if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService))
{ {
return true; return true;

View File

@ -54,7 +54,7 @@ namespace MediaBrowser.Controller.Entities.Audio
public string AlbumArtist => AlbumArtists.FirstOrDefault(); public string AlbumArtist => AlbumArtists.FirstOrDefault();
[JsonIgnore] [JsonIgnore]
public override bool SupportsPeople => false; public override bool SupportsPeople => true;
/// <summary> /// <summary>
/// Gets the tracks. /// Gets the tracks.

View File

@ -22,6 +22,7 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="OptimizedPriorityQueue" Version="5.1.0" /> <PackageReference Include="OptimizedPriorityQueue" Version="5.1.0" />
<PackageReference Include="PlaylistsNET" Version="1.2.1" /> <PackageReference Include="PlaylistsNET" Version="1.2.1" />
<PackageReference Include="TagLibSharp" Version="2.2.0" />
<PackageReference Include="TMDbLib" Version="1.9.2" /> <PackageReference Include="TMDbLib" Version="1.9.2" />
</ItemGroup> </ItemGroup>

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -17,6 +18,7 @@ using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
using TagLib;
namespace MediaBrowser.Providers.MediaInfo namespace MediaBrowser.Providers.MediaInfo
{ {
@ -93,7 +95,7 @@ namespace MediaBrowser.Providers.MediaInfo
// var extension = (Path.GetExtension(audio.Path) ?? string.Empty).TrimStart('.'); // var extension = (Path.GetExtension(audio.Path) ?? string.Empty).TrimStart('.');
// audio.Container = extension; // audio.Container = extension;
FetchDataFromTags(audio, mediaInfo); FetchDataFromTags(audio);
_itemRepo.SaveMediaStreams(audio.Id, mediaInfo.MediaStreams, cancellationToken); _itemRepo.SaveMediaStreams(audio.Id, mediaInfo.MediaStreams, cancellationToken);
} }
@ -102,71 +104,90 @@ namespace MediaBrowser.Providers.MediaInfo
/// Fetches data from the tags dictionary. /// Fetches data from the tags dictionary.
/// </summary> /// </summary>
/// <param name="audio">The audio.</param> /// <param name="audio">The audio.</param>
/// <param name="data">The data.</param> private void FetchDataFromTags(Audio audio)
private void FetchDataFromTags(Audio audio, Model.MediaInfo.MediaInfo data)
{ {
// Only set Name if title was found in the dictionary var file = TagLib.File.Create(audio.Path);
if (!string.IsNullOrEmpty(data.Name)) 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)) if (audio.SupportsPeople && !audio.LockedFields.Contains(MetadataField.Cast))
{ {
var people = new List<PersonInfo>(); var people = new List<PersonInfo>();
var albumArtists = tags.AlbumArtists;
foreach (var person in data.People) foreach (var albumArtist in albumArtists)
{ {
PeopleHelper.AddPerson(people, new PersonInfo PeopleHelper.AddPerson(people, new PersonInfo
{ {
Name = person.Name, Name = albumArtist,
Type = person.Type, Type = "AlbumArtist"
Role = person.Role });
}
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); _libraryManager.UpdatePeople(audio, people);
audio.Artists = performers;
audio.AlbumArtists = albumArtists;
} }
audio.Album = data.Album; audio.Name = tags.Title;
audio.Artists = data.Artists; audio.Album = tags.Album;
audio.AlbumArtists = data.AlbumArtists; audio.IndexNumber = Convert.ToInt32(tags.Track);
audio.IndexNumber = data.IndexNumber; audio.ParentIndexNumber = Convert.ToInt32(tags.Disc);
audio.ParentIndexNumber = data.ParentIndexNumber; if(tags.Year != 0)
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; var year = Convert.ToInt32(tags.Year);
audio.ProductionYear = year;
audio.PremiereDate = new DateTime(year, 01, 01);
} }
if (!audio.LockedFields.Contains(MetadataField.Genres)) if (!audio.LockedFields.Contains(MetadataField.Genres))
{ {
audio.Genres = Array.Empty<string>(); audio.Genres = tags.Genres.Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
foreach (var genre in data.Genres)
{
audio.AddGenre(genre);
}
} }
if (!audio.LockedFields.Contains(MetadataField.Studios)) audio.SetProviderId(MetadataProvider.MusicBrainzArtist, tags.MusicBrainzArtistId);
{ audio.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, tags.MusicBrainzReleaseArtistId);
audio.SetStudios(data.Studios); audio.SetProviderId(MetadataProvider.MusicBrainzAlbum, tags.MusicBrainzReleaseId);
} audio.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, tags.MusicBrainzReleaseGroupId);
audio.SetProviderId(MetadataProvider.MusicBrainzTrack, tags.MusicBrainzTrackId);
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));
} }
} }
} }

View File

@ -61,40 +61,61 @@ namespace MediaBrowser.Providers.Music
var songs = children.Cast<Audio>().ToArray(); var songs = children.Cast<Audio>().ToArray();
updateType |= SetAlbumArtistFromSongs(item, songs);
updateType |= SetArtistsFromSongs(item, songs); updateType |= SetArtistsFromSongs(item, songs);
updateType |= SetAlbumArtistFromSongs(item, songs);
updateType |= SetAlbumFromSongs(item, songs);
updateType |= SetPeople(item);
} }
return updateType; return updateType;
} }
private ItemUpdateType SetAlbumArtistFromSongs(MusicAlbum item, IEnumerable<Audio> songs) private ItemUpdateType SetAlbumArtistFromSongs(MusicAlbum item, IReadOnlyList<Audio> songs)
{ {
var updateType = ItemUpdateType.None; var updateType = ItemUpdateType.None;
var artists = songs var albumArtists = songs
.SelectMany(i => i.AlbumArtists) .SelectMany(i => i.AlbumArtists)
.Distinct(StringComparer.OrdinalIgnoreCase) .GroupBy(i => i)
.OrderBy(i => i) .OrderByDescending(g => g.Count())
.Select(g => g.Key)
.ToArray(); .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; updateType |= ItemUpdateType.MetadataEdit;
} }
return updateType; return updateType;
} }
private ItemUpdateType SetArtistsFromSongs(MusicAlbum item, IEnumerable<Audio> songs) private ItemUpdateType SetArtistsFromSongs(MusicAlbum item, IReadOnlyList<Audio> songs)
{ {
var updateType = ItemUpdateType.None; var updateType = ItemUpdateType.None;
var artists = songs var artists = songs
.SelectMany(i => i.Artists) .SelectMany(i => i.Artists)
.Distinct(StringComparer.OrdinalIgnoreCase) .GroupBy(i => i)
.OrderBy(i => i) .OrderByDescending(g => g.Count())
.Select(g => g.Key)
.ToArray(); .ToArray();
if (!item.Artists.SequenceEqual(artists, StringComparer.OrdinalIgnoreCase)) if (!item.Artists.SequenceEqual(artists, StringComparer.OrdinalIgnoreCase))
@ -106,6 +127,78 @@ namespace MediaBrowser.Providers.Music
return updateType; 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 /> /// <inheritdoc />
protected override void MergeData( protected override void MergeData(
MetadataResult<MusicAlbum> source, MetadataResult<MusicAlbum> source,
@ -123,6 +216,45 @@ namespace MediaBrowser.Providers.Music
{ {
targetItem.Artists = sourceItem.Artists; 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);
}
}
} }
} }
} }

View File

@ -1,5 +1,6 @@
#pragma warning disable CS1591 #pragma warning disable CS1591
using System;
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;
@ -40,6 +41,45 @@ namespace MediaBrowser.Providers.Music
{ {
targetItem.Album = sourceItem.Album; 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);
}
}
} }
} }
} }