fixes #520 - Support multiple artists per audio track

pull/702/head
Luke Pulverenti 11 years ago
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>();
if (!string.IsNullOrEmpty(i.AlbumArtist))
{
list.Add(i.AlbumArtist);
}
if (!string.IsNullOrEmpty(i.Artist))
{
list.Add(i.Artist);
}
return list;
})
list.Add(i.AlbumArtist);
}
list.AddRange(i.Artists);
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…
Cancel
Save