mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-04-24 22:17:25 -04:00
separate musicbrainz from lastfm artist providers
This commit is contained in:
parent
5ea002771a
commit
68bb977a74
17 changed files with 196 additions and 108 deletions
|
@ -22,13 +22,6 @@ namespace MediaBrowser.Controller.Library
|
|||
/// <returns><c>true</c> if [is enabled for] [the specified item]; otherwise, <c>false</c>.</returns>
|
||||
bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the save path.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
string GetSavePath(IHasMetadata item);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the specified item.
|
||||
/// </summary>
|
||||
|
@ -37,4 +30,14 @@ namespace MediaBrowser.Controller.Library
|
|||
/// <returns>Task.</returns>
|
||||
void Save(IHasMetadata item, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public interface IMetadataFileSaver : IMetadataSaver
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the save path.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
string GetSavePath(IHasMetadata item);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ using MediaBrowser.Controller.Entities.Audio;
|
|||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
@ -582,7 +583,15 @@ namespace MediaBrowser.Providers.Manager
|
|||
list.Add(GetPluginSummary<Studio>());
|
||||
list.Add(GetPluginSummary<GameGenre>());
|
||||
list.Add(GetPluginSummary<MusicGenre>());
|
||||
|
||||
|
||||
list.Add(GetPluginSummary<AdultVideo>());
|
||||
list.Add(GetPluginSummary<MusicVideo>());
|
||||
|
||||
list.Add(GetPluginSummary<LiveTvChannel>());
|
||||
list.Add(GetPluginSummary<LiveTvProgram>());
|
||||
list.Add(GetPluginSummary<LiveTvVideoRecording>());
|
||||
list.Add(GetPluginSummary<LiveTvAudioRecording>());
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
@ -672,33 +681,49 @@ namespace MediaBrowser.Providers.Manager
|
|||
/// <returns>Task.</returns>
|
||||
public async Task SaveMetadata(IHasMetadata item, ItemUpdateType updateType)
|
||||
{
|
||||
var locationType = item.LocationType;
|
||||
if (locationType == LocationType.Remote || locationType == LocationType.Virtual)
|
||||
{
|
||||
throw new ArgumentException("Only file-system based items can save metadata.");
|
||||
}
|
||||
|
||||
foreach (var saver in _savers.Where(i => i.IsEnabledFor(item, updateType)))
|
||||
{
|
||||
var path = saver.GetSavePath(item);
|
||||
var fileSaver = saver as IMetadataFileSaver;
|
||||
|
||||
var semaphore = _fileLocks.GetOrAdd(path, key => new SemaphoreSlim(1, 1));
|
||||
|
||||
await semaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
try
|
||||
if (fileSaver != null)
|
||||
{
|
||||
_libraryMonitor.ReportFileSystemChangeBeginning(path);
|
||||
saver.Save(item, CancellationToken.None);
|
||||
var locationType = item.LocationType;
|
||||
if (locationType == LocationType.Remote || locationType == LocationType.Virtual)
|
||||
{
|
||||
throw new ArgumentException("Only file-system based items can save metadata.");
|
||||
}
|
||||
|
||||
var path = fileSaver.GetSavePath(item);
|
||||
|
||||
var semaphore = _fileLocks.GetOrAdd(path, key => new SemaphoreSlim(1, 1));
|
||||
|
||||
await semaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
_libraryMonitor.ReportFileSystemChangeBeginning(path);
|
||||
saver.Save(item, CancellationToken.None);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error in metadata saver", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_libraryMonitor.ReportFileSystemChangeComplete(path, false);
|
||||
semaphore.Release();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
else
|
||||
{
|
||||
_logger.ErrorException("Error in metadata saver", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_libraryMonitor.ReportFileSystemChangeComplete(path, false);
|
||||
semaphore.Release();
|
||||
try
|
||||
{
|
||||
saver.Save(item, CancellationToken.None);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error in metadata saver", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,6 +105,7 @@
|
|||
<Compile Include="Music\AlbumMetadataService.cs" />
|
||||
<Compile Include="Music\ArtistMetadataService.cs" />
|
||||
<Compile Include="Music\LastfmArtistProvider.cs" />
|
||||
<Compile Include="Music\MusicBrainzArtistProvider.cs" />
|
||||
<Compile Include="People\MovieDbPersonImageProvider.cs" />
|
||||
<Compile Include="Movies\MovieUpdatesPrescanTask.cs" />
|
||||
<Compile Include="Movies\MovieXmlParser.cs" />
|
||||
|
|
|
@ -5,7 +5,6 @@ using MediaBrowser.Controller.Entities.Audio;
|
|||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
@ -15,11 +14,10 @@ using System.Net;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
public class LastfmArtistProvider : IRemoteMetadataProvider<MusicArtist>
|
||||
public class LastfmArtistProvider : IRemoteMetadataProvider<MusicArtist>, IHasOrder
|
||||
{
|
||||
private readonly IJsonSerializer _json;
|
||||
private readonly IHttpClient _httpClient;
|
||||
|
@ -44,7 +42,7 @@ namespace MediaBrowser.Providers.Music
|
|||
{
|
||||
var result = new MetadataResult<MusicArtist>();
|
||||
|
||||
var musicBrainzId = id.GetProviderId(MetadataProviders.Musicbrainz) ?? await FindId(id, cancellationToken).ConfigureAwait(false);
|
||||
var musicBrainzId = id.GetProviderId(MetadataProviders.Musicbrainz);
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(musicBrainzId))
|
||||
{
|
||||
|
@ -123,69 +121,6 @@ namespace MediaBrowser.Providers.Music
|
|||
|
||||
LastfmHelper.SaveImageInfo(_config.ApplicationPaths, _logger, musicBrainzId, url, imageSize);
|
||||
}
|
||||
|
||||
private async Task<string> FindId(ItemId item, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
// If we don't get anything, go directly to music brainz
|
||||
return await FindIdFromMusicBrainz(item, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException e)
|
||||
{
|
||||
if (e.StatusCode.HasValue && e.StatusCode.Value == HttpStatusCode.BadRequest)
|
||||
{
|
||||
// They didn't like a character in the name. Handle the exception so that the provider doesn't keep retrying over and over
|
||||
return null;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the id from music brainz.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{System.String}.</returns>
|
||||
private async Task<string> FindIdFromMusicBrainz(ItemId item, CancellationToken cancellationToken)
|
||||
{
|
||||
// They seem to throw bad request failures on any term with a slash
|
||||
var nameToSearch = item.Name.Replace('/', ' ');
|
||||
|
||||
var url = String.Format("http://www.musicbrainz.org/ws/2/artist/?query=artist:\"{0}\"", UrlEncode(nameToSearch));
|
||||
|
||||
var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var ns = new XmlNamespaceManager(doc.NameTable);
|
||||
ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
|
||||
var node = doc.SelectSingleNode("//mb:artist-list/mb:artist/@id", ns);
|
||||
|
||||
if (node != null && node.Value != null)
|
||||
{
|
||||
return node.Value;
|
||||
}
|
||||
|
||||
if (HasDiacritics(item.Name))
|
||||
{
|
||||
// Try again using the search with accent characters url
|
||||
url = String.Format("http://www.musicbrainz.org/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch));
|
||||
|
||||
doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
ns = new XmlNamespaceManager(doc.NameTable);
|
||||
ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
|
||||
node = doc.SelectSingleNode("//mb:artist-list/mb:artist/@id", ns);
|
||||
|
||||
if (node != null && node.Value != null)
|
||||
{
|
||||
return node.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified text has diacritics.
|
||||
|
@ -225,5 +160,10 @@ namespace MediaBrowser.Providers.Music
|
|||
{
|
||||
get { return "last.fm"; }
|
||||
}
|
||||
|
||||
public int Order
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
119
MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
Normal file
119
MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
Normal file
|
@ -0,0 +1,119 @@
|
|||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
public class MusicBrainzArtistProvider : IRemoteMetadataProvider<MusicArtist>
|
||||
{
|
||||
public async Task<MetadataResult<MusicArtist>> GetMetadata(ItemId id, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = new MetadataResult<MusicArtist>();
|
||||
|
||||
var musicBrainzId = id.GetProviderId(MetadataProviders.Musicbrainz) ?? await FindId(id, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(musicBrainzId))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
result.Item = new MusicArtist();
|
||||
result.HasMetadata = true;
|
||||
|
||||
result.Item.SetProviderId(MetadataProviders.Musicbrainz, musicBrainzId);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the id from music brainz.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{System.String}.</returns>
|
||||
private async Task<string> FindId(ItemId item, CancellationToken cancellationToken)
|
||||
{
|
||||
// They seem to throw bad request failures on any term with a slash
|
||||
var nameToSearch = item.Name.Replace('/', ' ');
|
||||
|
||||
var url = String.Format("http://www.musicbrainz.org/ws/2/artist/?query=artist:\"{0}\"", UrlEncode(nameToSearch));
|
||||
|
||||
var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var ns = new XmlNamespaceManager(doc.NameTable);
|
||||
ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
|
||||
var node = doc.SelectSingleNode("//mb:artist-list/mb:artist/@id", ns);
|
||||
|
||||
if (node != null && node.Value != null)
|
||||
{
|
||||
return node.Value;
|
||||
}
|
||||
|
||||
if (HasDiacritics(item.Name))
|
||||
{
|
||||
// Try again using the search with accent characters url
|
||||
url = String.Format("http://www.musicbrainz.org/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch));
|
||||
|
||||
doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
ns = new XmlNamespaceManager(doc.NameTable);
|
||||
ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
|
||||
node = doc.SelectSingleNode("//mb:artist-list/mb:artist/@id", ns);
|
||||
|
||||
if (node != null && node.Value != null)
|
||||
{
|
||||
return node.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified text has diacritics.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <returns><c>true</c> if the specified text has diacritics; otherwise, <c>false</c>.</returns>
|
||||
private bool HasDiacritics(string text)
|
||||
{
|
||||
return !String.Equals(text, RemoveDiacritics(text), StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the diacritics.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private string RemoveDiacritics(string text)
|
||||
{
|
||||
return String.Concat(
|
||||
text.Normalize(NormalizationForm.FormD)
|
||||
.Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) !=
|
||||
UnicodeCategory.NonSpacingMark)
|
||||
).Normalize(NormalizationForm.FormC);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encodes an URL.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private string UrlEncode(string name)
|
||||
{
|
||||
return WebUtility.UrlEncode(name);
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return "MusicBrainz"; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ using System.Threading;
|
|||
|
||||
namespace MediaBrowser.Providers.Savers
|
||||
{
|
||||
class AlbumXmlSaver : IMetadataSaver
|
||||
class AlbumXmlSaver : IMetadataFileSaver
|
||||
{
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ using System.Threading;
|
|||
|
||||
namespace MediaBrowser.Providers.Savers
|
||||
{
|
||||
class ArtistXmlSaver : IMetadataSaver
|
||||
class ArtistXmlSaver : IMetadataFileSaver
|
||||
{
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ using MediaBrowser.Controller.Providers;
|
|||
|
||||
namespace MediaBrowser.Providers.Savers
|
||||
{
|
||||
public class BoxSetXmlSaver : IMetadataSaver
|
||||
public class BoxSetXmlSaver : IMetadataFileSaver
|
||||
{
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace MediaBrowser.Providers.Savers
|
|||
/// <summary>
|
||||
/// Class PersonXmlSaver
|
||||
/// </summary>
|
||||
public class ChannelXmlSaver : IMetadataSaver
|
||||
public class ChannelXmlSaver : IMetadataFileSaver
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether [is enabled for] [the specified item].
|
||||
|
|
|
@ -12,7 +12,7 @@ using System.Threading;
|
|||
|
||||
namespace MediaBrowser.Providers.Savers
|
||||
{
|
||||
public class EpisodeXmlSaver : IMetadataSaver
|
||||
public class EpisodeXmlSaver : IMetadataFileSaver
|
||||
{
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IItemRepository _itemRepository;
|
||||
|
|
|
@ -12,7 +12,7 @@ using System.Threading;
|
|||
|
||||
namespace MediaBrowser.Providers.Savers
|
||||
{
|
||||
public class FolderXmlSaver : IMetadataSaver
|
||||
public class FolderXmlSaver : IMetadataFileSaver
|
||||
{
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ using System.Threading;
|
|||
|
||||
namespace MediaBrowser.Providers.Savers
|
||||
{
|
||||
public class GameSystemXmlSaver : IMetadataSaver
|
||||
public class GameSystemXmlSaver : IMetadataFileSaver
|
||||
{
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace MediaBrowser.Providers.Savers
|
|||
/// <summary>
|
||||
/// Saves game.xml for games
|
||||
/// </summary>
|
||||
public class GameXmlSaver : IMetadataSaver
|
||||
public class GameXmlSaver : IMetadataFileSaver
|
||||
{
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace MediaBrowser.Providers.Savers
|
|||
/// <summary>
|
||||
/// Saves movie.xml for movies, trailers and music videos
|
||||
/// </summary>
|
||||
public class MovieXmlSaver : IMetadataSaver
|
||||
public class MovieXmlSaver : IMetadataFileSaver
|
||||
{
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IItemRepository _itemRepository;
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace MediaBrowser.Providers.Savers
|
|||
/// <summary>
|
||||
/// Class PersonXmlSaver
|
||||
/// </summary>
|
||||
public class PersonXmlSaver : IMetadataSaver
|
||||
public class PersonXmlSaver : IMetadataFileSaver
|
||||
{
|
||||
public string Name
|
||||
{
|
||||
|
|
|
@ -9,7 +9,7 @@ using System.Threading;
|
|||
|
||||
namespace MediaBrowser.Providers.Savers
|
||||
{
|
||||
public class SeasonXmlSaver : IMetadataSaver
|
||||
public class SeasonXmlSaver : IMetadataFileSaver
|
||||
{
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ using System.Threading;
|
|||
|
||||
namespace MediaBrowser.Providers.Savers
|
||||
{
|
||||
public class SeriesXmlSaver : IMetadataSaver
|
||||
public class SeriesXmlSaver : IMetadataFileSaver
|
||||
{
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue