mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
fixes #520 - Support multiple artists per audio track
This commit is contained in:
parent
cbf061d5f6
commit
44b12c0f9f
@ -5,6 +5,7 @@ using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using ServiceStack.ServiceHost;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Api
|
||||
@ -76,15 +77,35 @@ namespace MediaBrowser.Api
|
||||
|
||||
var artists1 = album1.RecursiveChildren
|
||||
.OfType<Audio>()
|
||||
.SelectMany(i => new[] { i.AlbumArtist, i.Artist })
|
||||
.Where(i => !string.IsNullOrEmpty(i))
|
||||
.SelectMany(i =>
|
||||
{
|
||||
var list = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(i.AlbumArtist))
|
||||
{
|
||||
list.Add(i.AlbumArtist);
|
||||
}
|
||||
list.AddRange(i.Artists);
|
||||
|
||||
return list;
|
||||
})
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
var artists2 = album2.RecursiveChildren
|
||||
.OfType<Audio>()
|
||||
.SelectMany(i => new[] { i.AlbumArtist, i.Artist })
|
||||
.Where(i => !string.IsNullOrEmpty(i))
|
||||
.SelectMany(i =>
|
||||
{
|
||||
var list = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(i.AlbumArtist))
|
||||
{
|
||||
list.Add(i.AlbumArtist);
|
||||
}
|
||||
list.AddRange(i.Artists);
|
||||
|
||||
return list;
|
||||
})
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
|
@ -140,8 +140,18 @@ namespace MediaBrowser.Api
|
||||
|
||||
return libraryManager.RootFolder.RecursiveChildren
|
||||
.OfType<Audio>()
|
||||
.SelectMany(i => new[] { i.Artist, i.AlbumArtist })
|
||||
.Where(i => !string.IsNullOrEmpty(i))
|
||||
.SelectMany(i =>
|
||||
{
|
||||
var list = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(i.AlbumArtist))
|
||||
{
|
||||
list.Add(i.AlbumArtist);
|
||||
}
|
||||
list.AddRange(i.Artists);
|
||||
|
||||
return list;
|
||||
})
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.FirstOrDefault(i =>
|
||||
{
|
||||
|
@ -1,5 +1,6 @@
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using ServiceStack.ServiceHost;
|
||||
using System;
|
||||
@ -111,14 +112,25 @@ namespace MediaBrowser.Api
|
||||
{
|
||||
var item = await GetArtist(request.Name, _libraryManager).ConfigureAwait(false);
|
||||
|
||||
var cancellationToken = CancellationToken.None;
|
||||
|
||||
try
|
||||
{
|
||||
await item.RefreshMetadata(CancellationToken.None, forceRefresh: request.Forced).ConfigureAwait(false);
|
||||
await item.RefreshMetadata(cancellationToken, forceRefresh: request.Forced).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error refreshing library", ex);
|
||||
}
|
||||
|
||||
// Refresh albums
|
||||
var refreshTasks = _libraryManager.RootFolder
|
||||
.RecursiveChildren
|
||||
.OfType<MusicAlbum>()
|
||||
.Where(i => i.HasArtist(item.Name))
|
||||
.Select(i => i.ValidateChildren(new Progress<double>(), cancellationToken, true, request.Forced));
|
||||
|
||||
await Task.WhenAll(refreshTasks).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public void Post(RefreshGenre request)
|
||||
|
@ -275,7 +275,7 @@ namespace MediaBrowser.Api
|
||||
{
|
||||
song.Album = request.Album;
|
||||
song.AlbumArtist = request.AlbumArtist;
|
||||
song.Artist = request.Artists[0];
|
||||
song.Artists = request.Artists.ToList();
|
||||
}
|
||||
|
||||
var musicVideo = item as MusicVideo;
|
||||
|
@ -196,8 +196,7 @@ namespace MediaBrowser.Api
|
||||
result.SongCount = songs.Count;
|
||||
|
||||
result.Artists = songs
|
||||
.Select(i => i.Artist)
|
||||
.Where(i => !string.IsNullOrEmpty(i))
|
||||
.SelectMany(i => i.Artists)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
|
||||
@ -210,7 +209,7 @@ namespace MediaBrowser.Api
|
||||
{
|
||||
result.Album = song.Album;
|
||||
result.AlbumArtist = song.AlbumArtist;
|
||||
result.Artists = !string.IsNullOrEmpty(song.Artist) ? new[] { song.Artist } : new string[] { };
|
||||
result.Artists = song.Artists.ToArray();
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -181,20 +181,17 @@ namespace MediaBrowser.Api.UserLibrary
|
||||
|
||||
return itemsList
|
||||
.SelectMany(i =>
|
||||
{
|
||||
var list = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(i.AlbumArtist))
|
||||
{
|
||||
var list = new List<string>();
|
||||
list.Add(i.AlbumArtist);
|
||||
}
|
||||
list.AddRange(i.Artists);
|
||||
|
||||
if (!string.IsNullOrEmpty(i.AlbumArtist))
|
||||
{
|
||||
list.Add(i.AlbumArtist);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(i.Artist))
|
||||
{
|
||||
list.Add(i.Artist);
|
||||
}
|
||||
|
||||
return list;
|
||||
})
|
||||
return list;
|
||||
})
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.Select(name => new IbnStub<Artist>(name, () => itemsList.Where(i => i.HasArtist(name)), GetEntity));
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Audio
|
||||
@ -13,6 +14,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
public Audio()
|
||||
{
|
||||
MediaStreams = new List<MediaStream>();
|
||||
Artists = new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -57,7 +59,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
/// Gets or sets the artist.
|
||||
/// </summary>
|
||||
/// <value>The artist.</value>
|
||||
public string Artist { get; set; }
|
||||
public List<string> Artists { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the album.
|
||||
@ -99,7 +101,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
/// <returns><c>true</c> if the specified name has artist; otherwise, <c>false</c>.</returns>
|
||||
public bool HasArtist(string name)
|
||||
{
|
||||
return string.Equals(Artist, name, StringComparison.OrdinalIgnoreCase) || string.Equals(AlbumArtist, name, StringComparison.OrdinalIgnoreCase);
|
||||
return Artists.Contains(name, StringComparer.OrdinalIgnoreCase) || string.Equals(AlbumArtist, name, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -257,7 +257,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
var songs = recursiveChildren.OfType<Audio.Audio>().ToList();
|
||||
|
||||
indexFolders = songs.Select(i => i.Artist ?? string.Empty)
|
||||
indexFolders = songs.SelectMany(i => i.Artists)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.Select(i =>
|
||||
{
|
||||
@ -278,7 +278,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
})
|
||||
.Where(i => i != null)
|
||||
.Select(a => new IndexFolder(us, a,
|
||||
songs.Where(i => string.Equals(i.Artist, a.Name, StringComparison.OrdinalIgnoreCase)
|
||||
songs.Where(i => i.Artists.Contains(a.Name, StringComparer.OrdinalIgnoreCase)
|
||||
), currentIndexName)).Concat(indexFolders);
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
var album = item.Parent as MusicAlbum;
|
||||
|
||||
var filename = item.Album ?? string.Empty;
|
||||
filename += item.Artist ?? string.Empty;
|
||||
filename += item.Artists.FirstOrDefault() ?? string.Empty;
|
||||
filename += album == null ? item.Id.ToString("N") + item.DateModified.Ticks : album.Id.ToString("N") + album.DateModified.Ticks;
|
||||
|
||||
var path = ImageCache.GetResourcePath(filename + "_primary", ".jpg");
|
||||
|
@ -128,7 +128,19 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
|
||||
audio.Album = GetDictionaryValue(tags, "album");
|
||||
|
||||
audio.Artist = GetDictionaryValue(tags, "artist");
|
||||
var artist = GetDictionaryValue(tags, "artist");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(artist))
|
||||
{
|
||||
audio.Artists.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
audio.Artists = Split(artist)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
}
|
||||
|
||||
// Several different forms of albumartist
|
||||
audio.AlbumArtist = GetDictionaryValue(tags, "albumartist") ?? GetDictionaryValue(tags, "album artist") ?? GetDictionaryValue(tags, "album_artist");
|
||||
@ -159,6 +171,8 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
|
||||
if (!audio.LockedFields.Contains(MetadataFields.Studios))
|
||||
{
|
||||
audio.Studios.Clear();
|
||||
|
||||
// There's several values in tags may or may not be present
|
||||
FetchStudios(audio, tags, "organization");
|
||||
FetchStudios(audio, tags, "ensemble");
|
||||
@ -166,6 +180,8 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
}
|
||||
}
|
||||
|
||||
private readonly char[] _nameDelimiters = new[] { '/', '|', ';', '\\' };
|
||||
|
||||
/// <summary>
|
||||
/// Splits the specified val.
|
||||
/// </summary>
|
||||
@ -175,9 +191,10 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
{
|
||||
// Only use the comma as a delimeter if there are no slashes or pipes.
|
||||
// We want to be careful not to split names that have commas in them
|
||||
var delimeter = val.IndexOf('/') == -1 && val.IndexOf('|') == -1 ? new[] { ',' } : new[] { '/', '|' };
|
||||
var delimeter = _nameDelimiters.Any(i => val.IndexOf(i) != -1) ? _nameDelimiters : new[] { ',' };
|
||||
|
||||
return val.Split(delimeter, StringSplitOptions.RemoveEmptyEntries);
|
||||
return val.Split(delimeter, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Where(i => !string.IsNullOrWhiteSpace(i));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -194,11 +211,8 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
{
|
||||
// Sometimes the artist name is listed here, account for that
|
||||
var studios =
|
||||
val.Split(new[] { '/', '|' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Where(i => !string.IsNullOrWhiteSpace(i))
|
||||
.Where(i => !string.Equals(i, audio.Artist, StringComparison.OrdinalIgnoreCase) && !string.Equals(i, audio.AlbumArtist, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
audio.Studios.Clear();
|
||||
Split(val)
|
||||
.Where(i => !audio.HasArtist(i));
|
||||
|
||||
foreach (var studio in studios)
|
||||
{
|
||||
@ -221,8 +235,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
{
|
||||
audio.Genres.Clear();
|
||||
|
||||
foreach (var genre in val
|
||||
.Split(new[] { '/', '|' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
foreach (var genre in Split(val)
|
||||
.Where(i => !string.IsNullOrWhiteSpace(i)))
|
||||
{
|
||||
// Account for sloppy tags by trimming
|
||||
|
@ -135,10 +135,7 @@ namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
list.Add(i.AlbumArtist);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(i.Artist))
|
||||
{
|
||||
list.Add(i.Artist);
|
||||
}
|
||||
list.AddRange(i.Artists);
|
||||
|
||||
return list;
|
||||
})
|
||||
|
@ -893,7 +893,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||
{
|
||||
dto.Album = audio.Album;
|
||||
dto.AlbumArtist = audio.AlbumArtist;
|
||||
dto.Artists = new[] { audio.Artist };
|
||||
dto.Artists = audio.Artists.ToArray();
|
||||
|
||||
var albumParent = audio.FindParent<MusicAlbum>();
|
||||
|
||||
@ -919,8 +919,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||
dto.AlbumArtist = songs.Select(i => i.AlbumArtist).FirstOrDefault(i => !string.IsNullOrEmpty(i));
|
||||
|
||||
dto.Artists =
|
||||
songs.Select(i => i.Artist ?? string.Empty)
|
||||
.Where(i => !string.IsNullOrEmpty(i))
|
||||
songs.SelectMany(i => i.Artists)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
}
|
||||
|
@ -900,10 +900,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
{
|
||||
list.Add(c.AlbumArtist);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(c.Artist))
|
||||
{
|
||||
list.Add(c.Artist);
|
||||
}
|
||||
list.AddRange(c.Artists);
|
||||
|
||||
return list;
|
||||
})
|
||||
|
@ -120,8 +120,18 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
|
||||
// Find artists
|
||||
var artists = items.OfType<Audio>()
|
||||
.SelectMany(i => new[] { i.Artist, i.AlbumArtist })
|
||||
.Where(i => !string.IsNullOrEmpty(i))
|
||||
.SelectMany(i =>
|
||||
{
|
||||
var list = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(i.AlbumArtist))
|
||||
{
|
||||
list.Add(i.AlbumArtist);
|
||||
}
|
||||
list.AddRange(i.Artists);
|
||||
|
||||
return list;
|
||||
})
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
|
@ -37,7 +37,7 @@ namespace MediaBrowser.Server.Implementations.Sorting
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return audio.Artist ?? string.Empty;
|
||||
return audio.Artists.FirstOrDefault() ?? string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
Loading…
x
Reference in New Issue
Block a user