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