convert album providers
This commit is contained in:
parent
9685b81db5
commit
67fde8c16d
|
@ -21,9 +21,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
Tags = new List<string>();
|
||||
}
|
||||
|
||||
public string LastFmImageUrl { get; set; }
|
||||
public string LastFmImageSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the tags.
|
||||
/// </summary>
|
||||
|
|
|
@ -146,11 +146,13 @@
|
|||
<Compile Include="Providers\IDynamicInfoProvider.cs" />
|
||||
<Compile Include="Providers\IHasMetadata.cs" />
|
||||
<Compile Include="Providers\IImageProvider.cs" />
|
||||
<Compile Include="Providers\ILocalMetadataProvider.cs" />
|
||||
<Compile Include="Providers\IProviderRepository.cs" />
|
||||
<Compile Include="Providers\IRemoteImageProvider.cs" />
|
||||
<Compile Include="Providers\ILocalImageProvider.cs" />
|
||||
<Compile Include="Providers\IMetadataProvider.cs" />
|
||||
<Compile Include="Providers\IMetadataService.cs" />
|
||||
<Compile Include="Providers\IRemoteMetadataProvider.cs" />
|
||||
<Compile Include="Providers\ItemId.cs" />
|
||||
<Compile Include="Providers\MetadataRefreshOptions.cs" />
|
||||
<Compile Include="Providers\NameParser.cs" />
|
||||
|
|
|
@ -19,11 +19,5 @@ namespace MediaBrowser.Controller.Providers
|
|||
/// <param name="item">The item.</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||
bool Supports(IHasImages item);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the order.
|
||||
/// </summary>
|
||||
/// <value>The order.</value>
|
||||
int Order { get; }
|
||||
}
|
||||
}
|
||||
|
|
27
MediaBrowser.Controller/Providers/ILocalMetadataProvider.cs
Normal file
27
MediaBrowser.Controller/Providers/ILocalMetadataProvider.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.Providers
|
||||
{
|
||||
public interface ILocalMetadataProvider : IMetadataProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether [has local metadata] [the specified item].
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns><c>true</c> if [has local metadata] [the specified item]; otherwise, <c>false</c>.</returns>
|
||||
bool HasLocalMetadata(IHasMetadata item);
|
||||
}
|
||||
|
||||
public interface ILocalMetadataProvider<TItemType> : IMetadataProvider<TItemType>, ILocalMetadataProvider
|
||||
where TItemType : IHasMetadata
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the metadata.
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{MetadataResult{`0}}.</returns>
|
||||
Task<MetadataResult<TItemType>> GetMetadata(string path, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,4 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.Providers
|
||||
{
|
||||
|
@ -20,32 +18,6 @@ namespace MediaBrowser.Controller.Providers
|
|||
where TItemType : IHasMetadata
|
||||
{
|
||||
}
|
||||
|
||||
public interface ILocalMetadataProvider : IMetadataProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether [has local metadata] [the specified item].
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns><c>true</c> if [has local metadata] [the specified item]; otherwise, <c>false</c>.</returns>
|
||||
bool HasLocalMetadata(IHasMetadata item);
|
||||
}
|
||||
|
||||
public interface IRemoteMetadataProvider : IMetadataProvider
|
||||
{
|
||||
}
|
||||
|
||||
public interface IRemoteMetadataProvider<TItemType> : IMetadataProvider<TItemType>, IRemoteMetadataProvider
|
||||
where TItemType : IHasMetadata
|
||||
{
|
||||
Task<MetadataResult<TItemType>> GetMetadata(ItemId id, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public interface ILocalMetadataProvider<TItemType> : IMetadataProvider<TItemType>, ILocalMetadataProvider
|
||||
where TItemType : IHasMetadata
|
||||
{
|
||||
Task<MetadataResult<TItemType>> GetMetadata(string path, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public interface IHasChangeMonitor
|
||||
{
|
||||
|
@ -58,6 +30,11 @@ namespace MediaBrowser.Controller.Providers
|
|||
bool HasChanged(IHasMetadata item, DateTime date);
|
||||
}
|
||||
|
||||
public interface IHasOrder
|
||||
{
|
||||
int Order { get; }
|
||||
}
|
||||
|
||||
public class MetadataResult<T>
|
||||
where T : IHasMetadata
|
||||
{
|
||||
|
|
|
@ -10,8 +10,7 @@ namespace MediaBrowser.Controller.Providers
|
|||
/// Adds the parts.
|
||||
/// </summary>
|
||||
/// <param name="providers">The providers.</param>
|
||||
/// <param name="imageProviders">The image providers.</param>
|
||||
void AddParts(IEnumerable<IMetadataProvider> providers, IEnumerable<IImageProvider> imageProviders);
|
||||
void AddParts(IEnumerable<IMetadataProvider> providers);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can refresh the specified item.
|
||||
|
|
|
@ -74,13 +74,13 @@ namespace MediaBrowser.Controller.Providers
|
|||
/// <param name="providerName">Name of the provider.</param>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <returns>Task{IEnumerable{RemoteImageInfo}}.</returns>
|
||||
Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(BaseItem item, CancellationToken cancellationToken, string providerName = null, ImageType? type = null);
|
||||
Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(IHasImages item, CancellationToken cancellationToken, string providerName = null, ImageType? type = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the image providers.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns>IEnumerable{ImageProviderInfo}.</returns>
|
||||
IEnumerable<ImageProviderInfo> GetImageProviderInfo(BaseItem item);
|
||||
IEnumerable<ImageProviderInfo> GetImageProviderInfo(IHasImages item);
|
||||
}
|
||||
}
|
21
MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs
Normal file
21
MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.Providers
|
||||
{
|
||||
public interface IRemoteMetadataProvider : IMetadataProvider
|
||||
{
|
||||
}
|
||||
|
||||
public interface IRemoteMetadataProvider<TItemType> : IMetadataProvider<TItemType>, IRemoteMetadataProvider
|
||||
where TItemType : IHasMetadata
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the metadata.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{MetadataResult{`0}}.</returns>
|
||||
Task<MetadataResult<TItemType>> GetMetadata(ItemId id, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
|
@ -37,4 +37,18 @@ namespace MediaBrowser.Controller.Providers
|
|||
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
public class AlbumId : ItemId
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the album artist.
|
||||
/// </summary>
|
||||
/// <value>The album artist.</value>
|
||||
public string AlbumArtist { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the artist music brainz identifier.
|
||||
/// </summary>
|
||||
/// <value>The artist music brainz identifier.</value>
|
||||
public string ArtistMusicBrainzId { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
|
@ -38,13 +39,14 @@ namespace MediaBrowser.Providers.All
|
|||
if (locationType == LocationType.FileSystem)
|
||||
{
|
||||
// Episode has it's own provider
|
||||
if (item is Episode)
|
||||
if (item is Episode || item is Audio)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (locationType == LocationType.Virtual)
|
||||
{
|
||||
var season = item as Season;
|
||||
|
|
|
@ -15,7 +15,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Providers.BoxSets
|
||||
{
|
||||
public class BoxSetMetadataService : ConcreteMetadataService<BoxSet>
|
||||
public class BoxSetMetadataService : ConcreteMetadataService<BoxSet, ItemId>
|
||||
{
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly ILocalizationManager _iLocalizationManager;
|
||||
|
|
|
@ -14,7 +14,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Providers.BoxSets
|
||||
{
|
||||
class MovieDbBoxSetImageProvider : IRemoteImageProvider
|
||||
class MovieDbBoxSetImageProvider : IRemoteImageProvider, IHasOrder
|
||||
{
|
||||
private readonly IHttpClient _httpClient;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Providers.GameGenres
|
||||
{
|
||||
public class GameGenreMetadataService : ConcreteMetadataService<GameGenre>
|
||||
public class GameGenreMetadataService : ConcreteMetadataService<GameGenre, ItemId>
|
||||
{
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Providers.Genres
|
||||
{
|
||||
public class GenreMetadataService : ConcreteMetadataService<Genre>
|
||||
public class GenreMetadataService : ConcreteMetadataService<Genre, ItemId>
|
||||
{
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Providers.LiveTv
|
||||
{
|
||||
public class ChannelMetadataService : ConcreteMetadataService<LiveTvChannel>
|
||||
public class ChannelMetadataService : ConcreteMetadataService<LiveTvChannel, ItemId>
|
||||
{
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Providers.LiveTv
|
||||
{
|
||||
public class ProgramMetadataService : ConcreteMetadataService<LiveTvProgram>
|
||||
public class ProgramMetadataService : ConcreteMetadataService<LiveTvProgram, ItemId>
|
||||
{
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
|
|
|
@ -4,8 +4,9 @@ using MediaBrowser.Model.Logging;
|
|||
|
||||
namespace MediaBrowser.Providers.Manager
|
||||
{
|
||||
public abstract class ConcreteMetadataService<TItemType> : MetadataService<TItemType>
|
||||
where TItemType : IHasMetadata, new()
|
||||
public abstract class ConcreteMetadataService<TItemType, TIdType> : MetadataService<TItemType, TIdType>
|
||||
where TItemType : IHasMetadata, new()
|
||||
where TIdType : ItemId, new()
|
||||
{
|
||||
protected ConcreteMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo)
|
||||
: base(serverConfigurationManager, logger, providerManager, providerRepo)
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using MediaBrowser.Common.Extensions;
|
||||
using System.IO;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
|
@ -21,6 +23,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
private readonly ILogger _logger;
|
||||
private readonly IProviderManager _providerManager;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
public ItemImageProvider(ILogger logger, IProviderManager providerManager, IServerConfigurationManager config)
|
||||
{
|
||||
|
@ -97,9 +100,21 @@ namespace MediaBrowser.Providers.Manager
|
|||
|
||||
if (response.HasImage)
|
||||
{
|
||||
var mimeType = "image/" + response.Format.ToString().ToLower();
|
||||
if (!string.IsNullOrEmpty(response.Path))
|
||||
{
|
||||
var mimeType = "image/" + Path.GetExtension(response.Path).TrimStart('.').ToLower();
|
||||
|
||||
await _providerManager.SaveImage((BaseItem)item, response.Stream, mimeType, imageType, null, Guid.NewGuid().ToString(), cancellationToken).ConfigureAwait(false);
|
||||
var stream = _fileSystem.GetFileStream(response.Path, FileMode.Open, FileAccess.Read,
|
||||
FileShare.Read, true);
|
||||
|
||||
await _providerManager.SaveImage((BaseItem)item, stream, mimeType, imageType, null, Guid.NewGuid().ToString(), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var mimeType = "image/" + response.Format.ToString().ToLower();
|
||||
|
||||
await _providerManager.SaveImage((BaseItem)item, response.Stream, mimeType, imageType, null, Guid.NewGuid().ToString(), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate;
|
||||
}
|
||||
|
@ -227,26 +242,14 @@ namespace MediaBrowser.Providers.Manager
|
|||
/// <returns>IEnumerable{IImageProvider}.</returns>
|
||||
private IEnumerable<IImageProvider> GetImageProviders(IHasImages item, IEnumerable<IImageProvider> imageProviders)
|
||||
{
|
||||
var providers = imageProviders.Where(i =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return i.Supports(item);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error in ImageProvider.Supports", ex, i.Name);
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
var providers = imageProviders;
|
||||
|
||||
if (!_config.Configuration.EnableInternetProviders)
|
||||
{
|
||||
providers = providers.Where(i => !(i is IRemoteImageProvider));
|
||||
}
|
||||
|
||||
return providers.OrderBy(i => i.Order);
|
||||
return providers;
|
||||
}
|
||||
|
||||
private bool MergeImages(IHasImages item, List<LocalImageInfo> images)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
@ -13,8 +12,9 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Providers.Manager
|
||||
{
|
||||
public abstract class MetadataService<TItemType> : IMetadataService
|
||||
public abstract class MetadataService<TItemType, TIdType> : IMetadataService
|
||||
where TItemType : IHasMetadata
|
||||
where TIdType : ItemId, new()
|
||||
{
|
||||
protected readonly IServerConfigurationManager ServerConfigurationManager;
|
||||
protected readonly ILogger Logger;
|
||||
|
@ -23,8 +23,6 @@ namespace MediaBrowser.Providers.Manager
|
|||
|
||||
private IMetadataProvider<TItemType>[] _providers = { };
|
||||
|
||||
private IImageProvider[] _imageProviders = { };
|
||||
|
||||
protected MetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo)
|
||||
{
|
||||
ServerConfigurationManager = serverConfigurationManager;
|
||||
|
@ -37,13 +35,10 @@ namespace MediaBrowser.Providers.Manager
|
|||
/// Adds the parts.
|
||||
/// </summary>
|
||||
/// <param name="providers">The providers.</param>
|
||||
/// <param name="imageProviders">The image providers.</param>
|
||||
public void AddParts(IEnumerable<IMetadataProvider> providers, IEnumerable<IImageProvider> imageProviders)
|
||||
public void AddParts(IEnumerable<IMetadataProvider> providers)
|
||||
{
|
||||
_providers = providers.OfType<IMetadataProvider<TItemType>>()
|
||||
.ToArray();
|
||||
|
||||
_imageProviders = imageProviders.OrderBy(i => i.Order).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -79,11 +74,13 @@ namespace MediaBrowser.Providers.Manager
|
|||
var itemImageProvider = new ItemImageProvider(Logger, ProviderManager, ServerConfigurationManager);
|
||||
var localImagesFailed = false;
|
||||
|
||||
var allImageProviders = ((ProviderManager)ProviderManager).GetImageProviders(item).ToList();
|
||||
|
||||
// Start by validating images
|
||||
try
|
||||
{
|
||||
// Always validate images and check for new locally stored ones.
|
||||
if (itemImageProvider.ValidateImages(item, GetLocalImageProviders(item)))
|
||||
if (itemImageProvider.ValidateImages(item, allImageProviders.OfType<ILocalImageProvider>()))
|
||||
{
|
||||
updateType = updateType | ItemUpdateType.ImageUpdate;
|
||||
}
|
||||
|
@ -114,7 +111,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
// Next run remote image providers, but only if local image providers didn't throw an exception
|
||||
if (!localImagesFailed && options.ImageRefreshMode != ImageRefreshMode.ValidationOnly)
|
||||
{
|
||||
var providers = GetNonLocalImageProviders(item, lastResult.DateLastImagesRefresh.HasValue, options).ToList();
|
||||
var providers = GetNonLocalImageProviders(item, allImageProviders, lastResult.DateLastImagesRefresh.HasValue, options).ToList();
|
||||
|
||||
if (providers.Count > 0)
|
||||
{
|
||||
|
@ -135,7 +132,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
{
|
||||
if (string.IsNullOrEmpty(item.Name))
|
||||
{
|
||||
throw new InvalidOperationException("Item has no name");
|
||||
throw new InvalidOperationException(item.GetType().Name + " has no name: " + item.Path);
|
||||
}
|
||||
|
||||
// Save to database
|
||||
|
@ -167,7 +164,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
protected virtual IEnumerable<IMetadataProvider> GetProviders(IHasMetadata item, bool hasRefreshedMetadata, MetadataRefreshOptions options)
|
||||
{
|
||||
// Get providers to refresh
|
||||
var providers = _providers.Where(i => CanRefresh(i, item)).ToList();
|
||||
var providers = ((ProviderManager) ProviderManager).GetMetadataProviders<TItemType>(item).ToList();
|
||||
|
||||
// Run all if either of these flags are true
|
||||
var runAllProviders = options.ReplaceAllMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || !hasRefreshedMetadata;
|
||||
|
@ -193,22 +190,10 @@ namespace MediaBrowser.Providers.Manager
|
|||
return providers;
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<IImageProvider> GetNonLocalImageProviders(IHasMetadata item, bool hasRefreshedImages, ImageRefreshOptions options)
|
||||
protected virtual IEnumerable<IImageProvider> GetNonLocalImageProviders(IHasMetadata item, IEnumerable<IImageProvider> allImageProviders, bool hasRefreshedImages, ImageRefreshOptions options)
|
||||
{
|
||||
// Get providers to refresh
|
||||
var providers = _imageProviders.Where(i =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return !(i is ILocalImageProvider) && i.Supports(item);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error in ImageProvider.Supports", ex, i.Name);
|
||||
|
||||
return false;
|
||||
}
|
||||
}).ToList();
|
||||
var providers = allImageProviders.Where(i => !(i is ILocalImageProvider)).ToList();
|
||||
|
||||
// Run all if either of these flags are true
|
||||
var runAllProviders = options.ImageRefreshMode == ImageRefreshMode.FullRefresh || !hasRefreshedImages;
|
||||
|
@ -226,33 +211,12 @@ namespace MediaBrowser.Providers.Manager
|
|||
|
||||
return providers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can refresh the specified provider.
|
||||
/// </summary>
|
||||
/// <param name="provider">The provider.</param>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns><c>true</c> if this instance can refresh the specified provider; otherwise, <c>false</c>.</returns>
|
||||
protected bool CanRefresh(IMetadataProvider provider, IHasMetadata item)
|
||||
{
|
||||
if (!ServerConfigurationManager.Configuration.EnableInternetProviders && provider is IRemoteMetadataProvider)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.LocationType != LocationType.FileSystem && provider is ILocalMetadataProvider)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract Task SaveItem(TItemType item, ItemUpdateType reason, CancellationToken cancellationToken);
|
||||
|
||||
protected virtual ItemId GetId(IHasMetadata item)
|
||||
protected virtual TIdType GetId(TItemType item)
|
||||
{
|
||||
return new ItemId
|
||||
return new TIdType
|
||||
{
|
||||
MetadataCountryCode = item.GetPreferredMetadataCountryCode(),
|
||||
MetadataLanguage = item.GetPreferredMetadataLanguage(),
|
||||
|
@ -371,23 +335,6 @@ namespace MediaBrowser.Providers.Manager
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<ILocalImageProvider> GetLocalImageProviders(IHasImages item)
|
||||
{
|
||||
return _imageProviders.OfType<ILocalImageProvider>().Where(i =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return i.Supports(item);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error in ImageProvider.Supports", ex, i.Name);
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class RefreshResult
|
||||
|
|
|
@ -50,7 +50,6 @@ namespace MediaBrowser.Providers.Manager
|
|||
/// <value>The metadata providers enumerable.</value>
|
||||
private BaseMetadataProvider[] MetadataProviders { get; set; }
|
||||
|
||||
private IRemoteImageProvider[] RemoteImageProviders { get; set; }
|
||||
private IImageProvider[] ImageProviders { get; set; }
|
||||
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
@ -58,6 +57,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
private readonly IProviderRepository _providerRepo;
|
||||
|
||||
private IMetadataService[] _metadataServices = { };
|
||||
private IMetadataProvider[] _metadataProviders = { };
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProviderManager" /> class.
|
||||
|
@ -89,16 +89,10 @@ namespace MediaBrowser.Providers.Manager
|
|||
{
|
||||
MetadataProviders = providers.OrderBy(e => e.Priority).ToArray();
|
||||
|
||||
ImageProviders = imageProviders.OrderBy(i => i.Order).ToArray();
|
||||
RemoteImageProviders = ImageProviders.OfType<IRemoteImageProvider>().ToArray();
|
||||
ImageProviders = imageProviders.ToArray();
|
||||
|
||||
_metadataServices = metadataServices.OrderBy(i => i.Order).ToArray();
|
||||
|
||||
var providerList = metadataProviders.ToList();
|
||||
foreach (var service in _metadataServices)
|
||||
{
|
||||
service.AddParts(providerList, ImageProviders);
|
||||
}
|
||||
_metadataProviders = metadataProviders.ToArray();
|
||||
}
|
||||
|
||||
public Task RefreshMetadata(IHasMetadata item, MetadataRefreshOptions options, CancellationToken cancellationToken)
|
||||
|
@ -391,7 +385,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
/// <param name="providerName">Name of the provider.</param>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <returns>Task{IEnumerable{RemoteImageInfo}}.</returns>
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(BaseItem item, CancellationToken cancellationToken, string providerName = null, ImageType? type = null)
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(IHasImages item, CancellationToken cancellationToken, string providerName = null, ImageType? type = null)
|
||||
{
|
||||
var providers = GetRemoteImageProviders(item);
|
||||
|
||||
|
@ -418,7 +412,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
/// <param name="preferredLanguage">The preferred language.</param>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <returns>Task{IEnumerable{RemoteImageInfo}}.</returns>
|
||||
private async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken, IRemoteImageProvider i, string preferredLanguage, ImageType? type = null)
|
||||
private async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken, IRemoteImageProvider i, string preferredLanguage, ImageType? type = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -452,9 +446,23 @@ namespace MediaBrowser.Providers.Manager
|
|||
return images;
|
||||
}
|
||||
|
||||
private IEnumerable<IRemoteImageProvider> GetRemoteImageProviders(BaseItem item)
|
||||
/// <summary>
|
||||
/// Gets the supported image providers.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns>IEnumerable{IImageProvider}.</returns>
|
||||
public IEnumerable<ImageProviderInfo> GetImageProviderInfo(IHasImages item)
|
||||
{
|
||||
return RemoteImageProviders.Where(i =>
|
||||
return GetRemoteImageProviders(item).Select(i => new ImageProviderInfo
|
||||
{
|
||||
Name = i.Name,
|
||||
Order = GetOrder(item, i)
|
||||
});
|
||||
}
|
||||
|
||||
public IEnumerable<IImageProvider> GetImageProviders(IHasImages item)
|
||||
{
|
||||
return ImageProviders.Where(i =>
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -466,22 +474,77 @@ namespace MediaBrowser.Providers.Manager
|
|||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
}).OrderBy(i => GetOrder(item, i));
|
||||
}
|
||||
|
||||
public IEnumerable<IMetadataProvider<T>> GetMetadataProviders<T>(IHasMetadata item)
|
||||
where T : IHasMetadata
|
||||
{
|
||||
return _metadataProviders.OfType<IMetadataProvider<T>>()
|
||||
.Where(i => CanRefresh(i, item))
|
||||
.OrderBy(i => GetOrder(item, i));
|
||||
}
|
||||
|
||||
private IEnumerable<IRemoteImageProvider> GetRemoteImageProviders(IHasImages item)
|
||||
{
|
||||
return GetImageProviders(item).OfType<IRemoteImageProvider>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the supported image providers.
|
||||
/// Determines whether this instance can refresh the specified provider.
|
||||
/// </summary>
|
||||
/// <param name="provider">The provider.</param>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns><c>true</c> if this instance can refresh the specified provider; otherwise, <c>false</c>.</returns>
|
||||
protected bool CanRefresh(IMetadataProvider provider, IHasMetadata item)
|
||||
{
|
||||
if (!ConfigurationManager.Configuration.EnableInternetProviders && provider is IRemoteMetadataProvider)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.LocationType != LocationType.FileSystem && provider is ILocalMetadataProvider)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the order.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns>IEnumerable{IImageProvider}.</returns>
|
||||
public IEnumerable<ImageProviderInfo> GetImageProviderInfo(BaseItem item)
|
||||
/// <param name="provider">The provider.</param>
|
||||
/// <returns>System.Int32.</returns>
|
||||
private int GetOrder(IHasImages item, IImageProvider provider)
|
||||
{
|
||||
return GetRemoteImageProviders(item).Select(i => new ImageProviderInfo
|
||||
{
|
||||
Name = i.Name,
|
||||
Order = i.Order
|
||||
var hasOrder = provider as IHasOrder;
|
||||
|
||||
});
|
||||
if (hasOrder == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return hasOrder.Order;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the order.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="provider">The provider.</param>
|
||||
/// <returns>System.Int32.</returns>
|
||||
private int GetOrder(IHasMetadata item, IMetadataProvider provider)
|
||||
{
|
||||
var hasOrder = provider as IHasOrder;
|
||||
|
||||
if (hasOrder == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return hasOrder.Order;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,29 +100,26 @@
|
|||
<Compile Include="Movies\ManualMovieDbImageProvider.cs" />
|
||||
<Compile Include="Movies\ManualFanartMovieImageProvider.cs" />
|
||||
<Compile Include="MusicGenres\MusicGenreMetadataService.cs" />
|
||||
<Compile Include="Music\AlbumMetadataService.cs" />
|
||||
<Compile Include="Music\ArtistMetadataService.cs" />
|
||||
<Compile Include="Music\LastFmArtistProvider.cs" />
|
||||
<Compile Include="Music\LastfmArtistProvider.cs" />
|
||||
<Compile Include="People\MovieDbPersonImageProvider.cs" />
|
||||
<Compile Include="Movies\MovieUpdatesPrescanTask.cs" />
|
||||
<Compile Include="Movies\MovieXmlParser.cs" />
|
||||
<Compile Include="Movies\FanArtMovieProvider.cs" />
|
||||
<Compile Include="Movies\FanArtMovieUpdatesPrescanTask.cs" />
|
||||
<Compile Include="Movies\FanartMovieProvider.cs" />
|
||||
<Compile Include="Movies\FanartMovieUpdatesPrescanTask.cs" />
|
||||
<Compile Include="Movies\MovieDbImagesProvider.cs" />
|
||||
<Compile Include="Movies\MovieDbProvider.cs" />
|
||||
<Compile Include="Movies\MovieProviderFromXml.cs" />
|
||||
<Compile Include="Movies\OpenMovieDatabaseProvider.cs" />
|
||||
<Compile Include="Music\AlbumInfoFromSongProvider.cs" />
|
||||
<Compile Include="Music\AlbumProviderFromXml.cs" />
|
||||
<Compile Include="Music\AlbumXmlProvider.cs" />
|
||||
<Compile Include="Music\ArtistXmlProvider.cs" />
|
||||
<Compile Include="Music\FanArtAlbumProvider.cs" />
|
||||
<Compile Include="Music\FanArtUpdatesPrescanTask.cs" />
|
||||
<Compile Include="Music\FanartUpdatesPrescanTask.cs" />
|
||||
<Compile Include="Music\LastfmAlbumProvider.cs" />
|
||||
<Compile Include="Music\LastFmImageProvider.cs" />
|
||||
<Compile Include="Music\LastfmBaseProvider.cs" />
|
||||
<Compile Include="Music\LastfmHelper.cs" />
|
||||
<Compile Include="Music\ManualFanartAlbumProvider.cs" />
|
||||
<Compile Include="Music\FanartAlbumProvider.cs" />
|
||||
<Compile Include="Music\FanartArtistProvider.cs" />
|
||||
<Compile Include="Music\ManualLastFmImageProvider.cs" />
|
||||
<Compile Include="Music\LastfmImageProvider.cs" />
|
||||
<Compile Include="Music\MusicBrainzAlbumProvider.cs" />
|
||||
<Compile Include="Music\MusicVideoXmlParser.cs" />
|
||||
<Compile Include="Music\SoundtrackPostScanTask.cs" />
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace MediaBrowser.Providers.Movies
|
|||
/// <summary>
|
||||
/// Class FanArtMovieProvider
|
||||
/// </summary>
|
||||
class FanArtMovieProvider : BaseMetadataProvider
|
||||
class FanartMovieProvider : BaseMetadataProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the HTTP client.
|
||||
|
@ -37,18 +37,18 @@ namespace MediaBrowser.Providers.Movies
|
|||
/// </summary>
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
||||
internal static FanArtMovieProvider Current { get; private set; }
|
||||
internal static FanartMovieProvider Current { get; private set; }
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FanArtMovieProvider" /> class.
|
||||
/// Initializes a new instance of the <see cref="FanartMovieProvider" /> class.
|
||||
/// </summary>
|
||||
/// <param name="httpClient">The HTTP client.</param>
|
||||
/// <param name="logManager">The log manager.</param>
|
||||
/// <param name="configurationManager">The configuration manager.</param>
|
||||
/// <param name="providerManager">The provider manager.</param>
|
||||
/// <exception cref="System.ArgumentNullException">httpClient</exception>
|
||||
public FanArtMovieProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
|
||||
public FanartMovieProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
|
||||
: base(logManager, configurationManager)
|
||||
{
|
||||
if (httpClient == null)
|
||||
|
|
|
@ -16,7 +16,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Providers.Movies
|
||||
{
|
||||
class FanArtMovieUpdatesPrescanTask : ILibraryPostScanTask
|
||||
class FanartMovieUpdatesPrescanTask : ILibraryPostScanTask
|
||||
{
|
||||
private const string UpdatesUrl = "http://api.fanart.tv/webservice/newmovies/{0}/{1}/";
|
||||
|
||||
|
@ -37,7 +37,7 @@ namespace MediaBrowser.Providers.Movies
|
|||
|
||||
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
||||
|
||||
public FanArtMovieUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem)
|
||||
public FanartMovieUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem)
|
||||
{
|
||||
_jsonSerializer = jsonSerializer;
|
||||
_config = config;
|
||||
|
@ -60,7 +60,7 @@ namespace MediaBrowser.Providers.Movies
|
|||
return;
|
||||
}
|
||||
|
||||
var path = FanArtMovieProvider.GetMoviesDataPath(_config.CommonApplicationPaths);
|
||||
var path = FanartMovieProvider.GetMoviesDataPath(_config.CommonApplicationPaths);
|
||||
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
|
@ -118,7 +118,7 @@ namespace MediaBrowser.Providers.Movies
|
|||
return new List<string>();
|
||||
}
|
||||
|
||||
var updates = _jsonSerializer.DeserializeFromString<List<FanArtUpdatesPrescanTask.FanArtUpdate>>(json);
|
||||
var updates = _jsonSerializer.DeserializeFromString<List<FanartUpdatesPrescanTask.FanArtUpdate>>(json);
|
||||
|
||||
var existingDictionary = existingIds.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
|
@ -136,7 +136,7 @@ namespace MediaBrowser.Providers.Movies
|
|||
{
|
||||
_logger.Info("Updating movie " + id);
|
||||
|
||||
await FanArtMovieProvider.Current.DownloadMovieXml(id, cancellationToken).ConfigureAwait(false);
|
||||
await FanartMovieProvider.Current.DownloadMovieXml(id, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
|
|
|
@ -20,7 +20,7 @@ using MediaBrowser.Providers.Music;
|
|||
|
||||
namespace MediaBrowser.Providers.Movies
|
||||
{
|
||||
public class ManualFanartMovieImageProvider : IRemoteImageProvider, IHasChangeMonitor
|
||||
public class ManualFanartMovieImageProvider : IRemoteImageProvider, IHasChangeMonitor, IHasOrder
|
||||
{
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
@ -86,9 +86,9 @@ namespace MediaBrowser.Providers.Movies
|
|||
|
||||
if (!string.IsNullOrEmpty(movieId))
|
||||
{
|
||||
await FanArtMovieProvider.Current.EnsureMovieXml(movieId, cancellationToken).ConfigureAwait(false);
|
||||
await FanartMovieProvider.Current.EnsureMovieXml(movieId, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var xmlPath = FanArtMovieProvider.Current.GetFanartXmlPath(movieId);
|
||||
var xmlPath = FanartMovieProvider.Current.GetFanartXmlPath(movieId);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -344,7 +344,7 @@ namespace MediaBrowser.Providers.Movies
|
|||
if (!string.IsNullOrEmpty(id))
|
||||
{
|
||||
// Process images
|
||||
var xmlPath = FanArtMovieProvider.Current.GetFanartXmlPath(id);
|
||||
var xmlPath = FanartMovieProvider.Current.GetFanartXmlPath(id);
|
||||
|
||||
var fileInfo = new FileInfo(xmlPath);
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Providers.Movies
|
||||
{
|
||||
class ManualMovieDbImageProvider : IRemoteImageProvider
|
||||
class ManualMovieDbImageProvider : IRemoteImageProvider, IHasOrder
|
||||
{
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
private readonly IHttpClient _httpClient;
|
||||
|
|
|
@ -1,154 +0,0 @@
|
|||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
public class AlbumInfoFromSongProvider : BaseMetadataProvider
|
||||
{
|
||||
public AlbumInfoFromSongProvider(ILogManager logManager, IServerConfigurationManager configurationManager)
|
||||
: base(logManager, configurationManager)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Supports(BaseItem item)
|
||||
{
|
||||
return item is MusicAlbum;
|
||||
}
|
||||
|
||||
protected override bool RefreshOnVersionChange
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override string ProviderVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
return "2";
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
|
||||
{
|
||||
// If song metadata has changed
|
||||
if (GetComparisonData((MusicAlbum)item) != providerInfo.FileStamp)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.NeedsRefreshInternal(item, providerInfo);
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the data.
|
||||
/// </summary>
|
||||
/// <param name="album">The album.</param>
|
||||
/// <returns>Guid.</returns>
|
||||
private Guid GetComparisonData(MusicAlbum album)
|
||||
{
|
||||
var songs = album.RecursiveChildren.OfType<Audio>().ToList();
|
||||
|
||||
return GetComparisonData(songs);
|
||||
}
|
||||
|
||||
private Guid GetComparisonData(List<Audio> songs)
|
||||
{
|
||||
var albumArtistNames = songs.Select(i => i.AlbumArtist)
|
||||
.Where(i => !string.IsNullOrEmpty(i))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
var studios = songs.SelectMany(i => i.Studios)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
var genres = songs.SelectMany(i => i.Genres)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
albumArtistNames.AddRange(studios);
|
||||
albumArtistNames.AddRange(genres);
|
||||
|
||||
return string.Join(string.Empty, albumArtistNames.OrderBy(i => i).ToArray()).GetMD5();
|
||||
}
|
||||
|
||||
public override Task<bool> FetchAsync(BaseItem item, bool force, BaseProviderInfo providerInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
var album = (MusicAlbum)item;
|
||||
|
||||
var songs = album.RecursiveChildren.OfType<Audio>().ToList();
|
||||
|
||||
if (!item.LockedFields.Contains(MetadataFields.Name))
|
||||
{
|
||||
var name = songs.Select(i => i.Album).FirstOrDefault(i => !string.IsNullOrEmpty(i));
|
||||
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
album.Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
if (!item.LockedFields.Contains(MetadataFields.Studios))
|
||||
{
|
||||
album.Studios = songs.SelectMany(i => i.Studios)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
if (!item.LockedFields.Contains(MetadataFields.Genres))
|
||||
{
|
||||
album.Genres = songs.SelectMany(i => i.Genres)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
album.AlbumArtist = songs
|
||||
.Select(i => i.AlbumArtist)
|
||||
.FirstOrDefault(i => !string.IsNullOrEmpty(i));
|
||||
|
||||
album.Artists = songs.SelectMany(i => i.Artists)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
var date = songs.Select(i => i.PremiereDate)
|
||||
.FirstOrDefault(i => i.HasValue);
|
||||
|
||||
if (date.HasValue)
|
||||
{
|
||||
album.PremiereDate = date.Value;
|
||||
album.ProductionYear = date.Value.Year;
|
||||
}
|
||||
else
|
||||
{
|
||||
var year = songs.Select(i => i.ProductionYear ?? 1800).FirstOrDefault(i => i != 1800);
|
||||
|
||||
if (year != 1800)
|
||||
{
|
||||
album.ProductionYear = year;
|
||||
}
|
||||
}
|
||||
|
||||
providerInfo.FileStamp = GetComparisonData(songs);
|
||||
|
||||
SetLastRefreshed(item, DateTime.UtcNow, providerInfo);
|
||||
return TrueTaskResult;
|
||||
}
|
||||
|
||||
public override MetadataProviderPriority Priority
|
||||
{
|
||||
get { return MetadataProviderPriority.Second; }
|
||||
}
|
||||
}
|
||||
}
|
188
MediaBrowser.Providers/Music/AlbumMetadataService.cs
Normal file
188
MediaBrowser.Providers/Music/AlbumMetadataService.cs
Normal file
|
@ -0,0 +1,188 @@
|
|||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Providers.Manager;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
public class AlbumMetadataService : ConcreteMetadataService<MusicAlbum, AlbumId>
|
||||
{
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
public AlbumMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, ILibraryManager libraryManager)
|
||||
: base(serverConfigurationManager, logger, providerManager, providerRepo)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merges the specified source.
|
||||
/// </summary>
|
||||
/// <param name="source">The source.</param>
|
||||
/// <param name="target">The target.</param>
|
||||
/// <param name="lockedFields">The locked fields.</param>
|
||||
/// <param name="replaceData">if set to <c>true</c> [replace data].</param>
|
||||
/// <param name="mergeMetadataSettings">if set to <c>true</c> [merge metadata settings].</param>
|
||||
protected override void MergeData(MusicAlbum source, MusicAlbum target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
|
||||
{
|
||||
ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
|
||||
}
|
||||
|
||||
protected override Task SaveItem(MusicAlbum item, ItemUpdateType reason, CancellationToken cancellationToken)
|
||||
{
|
||||
return _libraryManager.UpdateItem(item, reason, cancellationToken);
|
||||
}
|
||||
|
||||
protected override ItemUpdateType AfterMetadataRefresh(MusicAlbum item)
|
||||
{
|
||||
var updateType = base.AfterMetadataRefresh(item);
|
||||
|
||||
var songs = item.RecursiveChildren.OfType<Audio>().ToList();
|
||||
|
||||
if (!item.LockedFields.Contains(MetadataFields.Genres))
|
||||
{
|
||||
var currentList = item.Genres.ToList();
|
||||
|
||||
item.Genres = songs.SelectMany(i => i.Genres)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
if (currentList.Count != item.Genres.Count || !currentList.OrderBy(i => i).SequenceEqual(item.Genres.OrderBy(i => i), StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
updateType = updateType | ItemUpdateType.MetadataDownload;
|
||||
}
|
||||
}
|
||||
|
||||
if (!item.LockedFields.Contains(MetadataFields.Studios))
|
||||
{
|
||||
var currentList = item.Studios.ToList();
|
||||
|
||||
item.Studios = songs.SelectMany(i => i.Studios)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
if (currentList.Count != item.Studios.Count || !currentList.OrderBy(i => i).SequenceEqual(item.Studios.OrderBy(i => i), StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
updateType = updateType | ItemUpdateType.MetadataDownload;
|
||||
}
|
||||
}
|
||||
|
||||
if (!item.LockedFields.Contains(MetadataFields.Name))
|
||||
{
|
||||
var name = songs.Select(i => i.Album).FirstOrDefault(i => !string.IsNullOrEmpty(i));
|
||||
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
if (!string.Equals(item.Name, name, StringComparison.Ordinal))
|
||||
{
|
||||
item.Name = name;
|
||||
updateType = updateType | ItemUpdateType.MetadataDownload;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateType = updateType | SetAlbumArtistFromSongs(item, songs);
|
||||
updateType = updateType | SetArtistsFromSongs(item, songs);
|
||||
updateType = updateType | SetDateFromSongs(item, songs);
|
||||
|
||||
return updateType;
|
||||
}
|
||||
|
||||
protected override AlbumId GetId(MusicAlbum item)
|
||||
{
|
||||
var id = base.GetId(item);
|
||||
|
||||
id.AlbumArtist = item.AlbumArtist;
|
||||
|
||||
var artist = item.Parents.OfType<MusicArtist>().FirstOrDefault();
|
||||
|
||||
if (artist != null)
|
||||
{
|
||||
id.ArtistMusicBrainzId = artist.GetProviderId(MetadataProviders.Musicbrainz);
|
||||
id.AlbumArtist = id.AlbumArtist ?? artist.Name;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
private ItemUpdateType SetAlbumArtistFromSongs(MusicAlbum item, IEnumerable<Audio> songs)
|
||||
{
|
||||
var updateType = ItemUpdateType.Unspecified;
|
||||
|
||||
var albumArtist = songs
|
||||
.Select(i => i.AlbumArtist)
|
||||
.FirstOrDefault(i => !string.IsNullOrEmpty(i));
|
||||
|
||||
if (!string.IsNullOrEmpty(albumArtist))
|
||||
{
|
||||
if (!string.Equals(item.AlbumArtist, albumArtist, StringComparison.Ordinal))
|
||||
{
|
||||
item.AlbumArtist = albumArtist;
|
||||
updateType = updateType | ItemUpdateType.MetadataDownload;
|
||||
}
|
||||
}
|
||||
|
||||
return updateType;
|
||||
}
|
||||
|
||||
private ItemUpdateType SetArtistsFromSongs(MusicAlbum item, IEnumerable<Audio> songs)
|
||||
{
|
||||
var updateType = ItemUpdateType.Unspecified;
|
||||
|
||||
var currentList = item.Artists.ToList();
|
||||
|
||||
item.Artists = songs.SelectMany(i => i.Artists)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
if (currentList.Count != item.Artists.Count || !currentList.OrderBy(i => i).SequenceEqual(item.Artists.OrderBy(i => i), StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
updateType = updateType | ItemUpdateType.MetadataDownload;
|
||||
}
|
||||
|
||||
return updateType;
|
||||
}
|
||||
|
||||
private ItemUpdateType SetDateFromSongs(MusicAlbum item, List<Audio> songs)
|
||||
{
|
||||
var updateType = ItemUpdateType.Unspecified;
|
||||
|
||||
var date = songs.Select(i => i.PremiereDate)
|
||||
.FirstOrDefault(i => i.HasValue);
|
||||
|
||||
var originalPremiereDate = item.PremiereDate;
|
||||
var originalProductionYear = item.ProductionYear;
|
||||
|
||||
if (date.HasValue)
|
||||
{
|
||||
item.PremiereDate = date.Value;
|
||||
item.ProductionYear = date.Value.Year;
|
||||
}
|
||||
else
|
||||
{
|
||||
var year = songs.Select(i => i.ProductionYear ?? 1800).FirstOrDefault(i => i != 1800);
|
||||
|
||||
if (year != 1800)
|
||||
{
|
||||
item.ProductionYear = year;
|
||||
}
|
||||
}
|
||||
|
||||
if ((originalPremiereDate ?? DateTime.MinValue) != (item.PremiereDate ?? DateTime.MinValue) ||
|
||||
(originalProductionYear ?? -1) != (item.ProductionYear ?? -1))
|
||||
{
|
||||
updateType = updateType | ItemUpdateType.MetadataDownload;
|
||||
}
|
||||
|
||||
return updateType;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
class AlbumProviderFromXml : BaseMetadataProvider
|
||||
{
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
public AlbumProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
|
||||
: base(logManager, configurationManager)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supportses the specified item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||
public override bool Supports(BaseItem item)
|
||||
{
|
||||
return item is MusicAlbum && item.LocationType == LocationType.FileSystem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the priority.
|
||||
/// </summary>
|
||||
/// <value>The priority.</value>
|
||||
public override MetadataProviderPriority Priority
|
||||
{
|
||||
get { return MetadataProviderPriority.First; }
|
||||
}
|
||||
|
||||
private const string XmlFileName = "album.xml";
|
||||
protected override bool NeedsRefreshBasedOnCompareDate(BaseItem item, BaseProviderInfo providerInfo)
|
||||
{
|
||||
var xml = item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, XmlFileName));
|
||||
|
||||
if (xml == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _fileSystem.GetLastWriteTimeUtc(xml) > item.DateLastSaved;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches metadata and returns true or false indicating if any work that requires persistence was done
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="force">if set to <c>true</c> [force].</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{System.Boolean}.</returns>
|
||||
public override async Task<bool> FetchAsync(BaseItem item, bool force, BaseProviderInfo providerInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var metadataFile = item.ResolveArgs.GetMetaFileByPath(Path.Combine(item.MetaLocation, XmlFileName));
|
||||
|
||||
if (metadataFile != null)
|
||||
{
|
||||
var path = metadataFile.FullName;
|
||||
|
||||
await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
new BaseItemXmlParser<MusicAlbum>(Logger).Fetch((MusicAlbum)item, path, cancellationToken);
|
||||
}
|
||||
finally
|
||||
{
|
||||
XmlParsingResourcePool.Release();
|
||||
}
|
||||
|
||||
SetLastRefreshed(item, DateTime.UtcNow, providerInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
59
MediaBrowser.Providers/Music/AlbumXmlProvider.cs
Normal file
59
MediaBrowser.Providers/Music/AlbumXmlProvider.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
class AlbumXmlProvider : BaseXmlProvider, ILocalMetadataProvider<MusicAlbum>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public AlbumXmlProvider(IFileSystem fileSystem, ILogger logger)
|
||||
: base(fileSystem)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<MetadataResult<MusicAlbum>> GetMetadata(string path, CancellationToken cancellationToken)
|
||||
{
|
||||
path = GetXmlPath(path);
|
||||
|
||||
var result = new MetadataResult<MusicAlbum>();
|
||||
|
||||
await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
var item = new MusicAlbum();
|
||||
|
||||
new BaseItemXmlParser<MusicAlbum>(_logger).Fetch(item, path, cancellationToken);
|
||||
result.HasMetadata = true;
|
||||
result.Item = item;
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
result.HasMetadata = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
XmlParsingResourcePool.Release();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return "Media Browser Xml"; }
|
||||
}
|
||||
|
||||
protected override string GetXmlPath(string path)
|
||||
{
|
||||
return Path.Combine(path, "album.xml");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
public class ArtistMetadataService : ConcreteMetadataService<MusicArtist>
|
||||
public class ArtistMetadataService : ConcreteMetadataService<MusicArtist, ItemId>
|
||||
{
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
|
@ -49,13 +49,13 @@ namespace MediaBrowser.Providers.Music
|
|||
{
|
||||
var songs = item.RecursiveChildren.OfType<Audio>().ToList();
|
||||
|
||||
var currentGenres = item.Genres.ToList();
|
||||
var currentList = item.Genres.ToList();
|
||||
|
||||
item.Genres = songs.SelectMany(i => i.Genres)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
if (currentGenres.Count != item.Genres.Count || !currentGenres.OrderBy(i => i).SequenceEqual(item.Genres.OrderBy(i => i), StringComparer.OrdinalIgnoreCase))
|
||||
if (currentList.Count != item.Genres.Count || !currentList.OrderBy(i => i).SequenceEqual(item.Genres.OrderBy(i => i), StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
updateType = updateType | ItemUpdateType.MetadataDownload;
|
||||
}
|
||||
|
|
|
@ -3,210 +3,373 @@ using MediaBrowser.Common.Net;
|
|||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Net;
|
||||
using System.Net;
|
||||
using System.Xml;
|
||||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
/// <summary>
|
||||
/// Class FanArtAlbumProvider
|
||||
/// </summary>
|
||||
public class FanArtAlbumProvider : BaseMetadataProvider
|
||||
public class FanartAlbumProvider : IRemoteImageProvider, IHasChangeMonitor, IHasOrder
|
||||
{
|
||||
/// <summary>
|
||||
/// The _provider manager
|
||||
/// </summary>
|
||||
private readonly IProviderManager _providerManager;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the HTTP client.
|
||||
/// </summary>
|
||||
/// <value>The HTTP client.</value>
|
||||
protected IHttpClient HttpClient { get; private set; }
|
||||
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FanArtAlbumProvider"/> class.
|
||||
/// </summary>
|
||||
/// <param name="httpClient">The HTTP client.</param>
|
||||
/// <param name="logManager">The log manager.</param>
|
||||
/// <param name="configurationManager">The configuration manager.</param>
|
||||
/// <param name="providerManager">The provider manager.</param>
|
||||
public FanArtAlbumProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
|
||||
: base(logManager, configurationManager)
|
||||
public FanartAlbumProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem)
|
||||
{
|
||||
_providerManager = providerManager;
|
||||
_config = config;
|
||||
_httpClient = httpClient;
|
||||
_fileSystem = fileSystem;
|
||||
HttpClient = httpClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the priority.
|
||||
/// </summary>
|
||||
/// <value>The priority.</value>
|
||||
public override MetadataProviderPriority Priority
|
||||
public string Name
|
||||
{
|
||||
get { return MetadataProviderPriority.Fifth; }
|
||||
get { return ProviderName; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supportses the specified item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||
public override bool Supports(BaseItem item)
|
||||
public static string ProviderName
|
||||
{
|
||||
get { return "FanArt"; }
|
||||
}
|
||||
|
||||
public bool Supports(IHasImages item)
|
||||
{
|
||||
return item is MusicAlbum;
|
||||
}
|
||||
|
||||
public override ItemUpdateType ItemUpdateType
|
||||
public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
|
||||
{
|
||||
get
|
||||
return new List<ImageType>
|
||||
{
|
||||
return ItemUpdateType.ImageUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether [refresh on version change].
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [refresh on version change]; otherwise, <c>false</c>.</value>
|
||||
protected override bool RefreshOnVersionChange
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
ImageType.Primary,
|
||||
ImageType.Disc
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the provider version.
|
||||
/// </summary>
|
||||
/// <value>The provider version.</value>
|
||||
protected override string ProviderVersion
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, ImageType imageType, CancellationToken cancellationToken)
|
||||
{
|
||||
get
|
||||
{
|
||||
return "18";
|
||||
}
|
||||
var images = await GetAllImages(item, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return images.Where(i => i.Type == imageType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Needses the refresh internal.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="providerInfo">The provider info.</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||
protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetAllImages(IHasImages item, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!ConfigurationManager.Configuration.DownloadMusicAlbumImages.Disc &&
|
||||
!ConfigurationManager.Configuration.DownloadMusicAlbumImages.Primary)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var album = (MusicAlbum)item;
|
||||
|
||||
if (item.HasImage(ImageType.Primary) && item.HasImage(ImageType.Disc))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var list = new List<RemoteImageInfo>();
|
||||
|
||||
return base.NeedsRefreshInternal(item, providerInfo);
|
||||
}
|
||||
|
||||
protected override DateTime CompareDate(BaseItem item)
|
||||
{
|
||||
var artistMusicBrainzId = item.Parent.GetProviderId(MetadataProviders.Musicbrainz);
|
||||
var artistMusicBrainzId = album.Parent.GetProviderId(MetadataProviders.Musicbrainz);
|
||||
|
||||
if (!string.IsNullOrEmpty(artistMusicBrainzId))
|
||||
{
|
||||
var artistXmlPath = FanartArtistProvider.GetArtistXmlPath(ConfigurationManager.CommonApplicationPaths, artistMusicBrainzId);
|
||||
await FanartArtistProvider.Current.EnsureMovieXml(artistMusicBrainzId, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var file = new FileInfo(artistXmlPath);
|
||||
var artistXmlPath = FanartArtistProvider.GetArtistXmlPath(_config.CommonApplicationPaths, artistMusicBrainzId);
|
||||
|
||||
if (file.Exists)
|
||||
{
|
||||
return _fileSystem.GetLastWriteTimeUtc(file);
|
||||
}
|
||||
}
|
||||
|
||||
return base.CompareDate(item);
|
||||
}
|
||||
var musicBrainzReleaseGroupId = album.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
|
||||
|
||||
/// <summary>
|
||||
/// Fetches metadata and returns true or false indicating if any work that requires persistence was done
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="force">if set to <c>true</c> [force].</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{System.Boolean}.</returns>
|
||||
public override async Task<bool> FetchAsync(BaseItem item, bool force, BaseProviderInfo providerInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!item.LockedFields.Contains(MetadataFields.Images))
|
||||
{
|
||||
var images = await _providerManager.GetAvailableRemoteImages(item, cancellationToken, ManualFanartAlbumProvider.ProviderName).ConfigureAwait(false);
|
||||
await FetchFromXml(item, images.ToList(), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
var musicBrainzId = album.GetProviderId(MetadataProviders.Musicbrainz);
|
||||
|
||||
SetLastRefreshed(item, DateTime.UtcNow, providerInfo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches from XML.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="images">The images.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
private async Task FetchFromXml(BaseItem item, List<RemoteImageInfo> images, CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (ConfigurationManager.Configuration.DownloadMusicAlbumImages.Primary && !item.HasImage(ImageType.Primary))
|
||||
{
|
||||
await SaveImage(item, images, ImageType.Primary, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (ConfigurationManager.Configuration.DownloadMusicAlbumImages.Disc && !item.HasImage(ImageType.Disc))
|
||||
{
|
||||
await SaveImage(item, images, ImageType.Disc, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveImage(BaseItem item, List<RemoteImageInfo> images, ImageType type, CancellationToken cancellationToken)
|
||||
{
|
||||
foreach (var image in images.Where(i => i.Type == type))
|
||||
{
|
||||
try
|
||||
{
|
||||
await _providerManager.SaveImage(item, image.Url, FanartArtistProvider.FanArtResourcePool, type, null, cancellationToken).ConfigureAwait(false);
|
||||
break;
|
||||
AddImages(list, artistXmlPath, musicBrainzId, musicBrainzReleaseGroupId, cancellationToken);
|
||||
}
|
||||
catch (HttpException ex)
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
// Sometimes fanart has bad url's in their xml
|
||||
if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var language = item.GetPreferredMetadataLanguage();
|
||||
|
||||
var isLanguageEn = string.Equals(language, "en", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
// Sort first by width to prioritize HD versions
|
||||
return list.OrderByDescending(i => i.Width ?? 0)
|
||||
.ThenByDescending(i =>
|
||||
{
|
||||
if (string.Equals(language, i.Language, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
if (!isLanguageEn)
|
||||
{
|
||||
if (string.Equals("en", i.Language, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(i.Language))
|
||||
{
|
||||
return isLanguageEn ? 3 : 2;
|
||||
}
|
||||
return 0;
|
||||
})
|
||||
.ThenByDescending(i => i.CommunityRating ?? 0)
|
||||
.ThenByDescending(i => i.VoteCount ?? 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the images.
|
||||
/// </summary>
|
||||
/// <param name="list">The list.</param>
|
||||
/// <param name="xmlPath">The XML path.</param>
|
||||
/// <param name="releaseId">The release identifier.</param>
|
||||
/// <param name="releaseGroupId">The release group identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
private void AddImages(List<RemoteImageInfo> list, string xmlPath, string releaseId, string releaseGroupId, CancellationToken cancellationToken)
|
||||
{
|
||||
using (var streamReader = new StreamReader(xmlPath, Encoding.UTF8))
|
||||
{
|
||||
// Use XmlReader for best performance
|
||||
using (var reader = XmlReader.Create(streamReader, new XmlReaderSettings
|
||||
{
|
||||
CheckCharacters = false,
|
||||
IgnoreProcessingInstructions = true,
|
||||
IgnoreComments = true,
|
||||
ValidationType = ValidationType.None
|
||||
}))
|
||||
{
|
||||
reader.MoveToContent();
|
||||
|
||||
// Loop through each element
|
||||
while (reader.Read())
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
switch (reader.Name)
|
||||
{
|
||||
case "music":
|
||||
{
|
||||
using (var subReader = reader.ReadSubtree())
|
||||
{
|
||||
AddImagesFromMusicNode(list, releaseId, releaseGroupId, subReader, cancellationToken);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
reader.Skip();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the images from music node.
|
||||
/// </summary>
|
||||
/// <param name="list">The list.</param>
|
||||
/// <param name="releaseId">The release identifier.</param>
|
||||
/// <param name="releaseGroupId">The release group identifier.</param>
|
||||
/// <param name="reader">The reader.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
private void AddImagesFromMusicNode(List<RemoteImageInfo> list, string releaseId, string releaseGroupId, XmlReader reader, CancellationToken cancellationToken)
|
||||
{
|
||||
reader.MoveToContent();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
switch (reader.Name)
|
||||
{
|
||||
case "albums":
|
||||
{
|
||||
using (var subReader = reader.ReadSubtree())
|
||||
{
|
||||
AddImagesFromAlbumsNode(list, releaseId, releaseGroupId, subReader, cancellationToken);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
using (reader.ReadSubtree())
|
||||
{
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the images from albums node.
|
||||
/// </summary>
|
||||
/// <param name="list">The list.</param>
|
||||
/// <param name="releaseId">The release identifier.</param>
|
||||
/// <param name="releaseGroupId">The release group identifier.</param>
|
||||
/// <param name="reader">The reader.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
private void AddImagesFromAlbumsNode(List<RemoteImageInfo> list, string releaseId, string releaseGroupId, XmlReader reader, CancellationToken cancellationToken)
|
||||
{
|
||||
reader.MoveToContent();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
switch (reader.Name)
|
||||
{
|
||||
case "album":
|
||||
{
|
||||
var id = reader.GetAttribute("id");
|
||||
|
||||
using (var subReader = reader.ReadSubtree())
|
||||
{
|
||||
if (string.Equals(id, releaseId, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(id, releaseGroupId, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
AddImages(list, subReader, cancellationToken);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
using (reader.ReadSubtree())
|
||||
{
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the images.
|
||||
/// </summary>
|
||||
/// <param name="list">The list.</param>
|
||||
/// <param name="reader">The reader.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
private void AddImages(List<RemoteImageInfo> list, XmlReader reader, CancellationToken cancellationToken)
|
||||
{
|
||||
reader.MoveToContent();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
switch (reader.Name)
|
||||
{
|
||||
case "cdart":
|
||||
{
|
||||
AddImage(list, reader, ImageType.Disc, 1000, 1000);
|
||||
break;
|
||||
}
|
||||
case "albumcover":
|
||||
{
|
||||
AddImage(list, reader, ImageType.Primary, 1000, 1000);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
using (reader.ReadSubtree())
|
||||
{
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the image.
|
||||
/// </summary>
|
||||
/// <param name="list">The list.</param>
|
||||
/// <param name="reader">The reader.</param>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="height">The height.</param>
|
||||
private void AddImage(List<RemoteImageInfo> list, XmlReader reader, ImageType type, int width, int height)
|
||||
{
|
||||
var url = reader.GetAttribute("url");
|
||||
|
||||
var size = reader.GetAttribute("size");
|
||||
|
||||
if (!string.IsNullOrEmpty(size))
|
||||
{
|
||||
int sizeNum;
|
||||
if (int.TryParse(size, NumberStyles.Any, _usCulture, out sizeNum))
|
||||
{
|
||||
width = sizeNum;
|
||||
height = sizeNum;
|
||||
}
|
||||
}
|
||||
|
||||
var likesString = reader.GetAttribute("likes");
|
||||
int likes;
|
||||
|
||||
var info = new RemoteImageInfo
|
||||
{
|
||||
RatingType = RatingType.Likes,
|
||||
Type = type,
|
||||
Width = width,
|
||||
Height = height,
|
||||
ProviderName = Name,
|
||||
Url = url,
|
||||
Language = reader.GetAttribute("lang")
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Any, _usCulture, out likes))
|
||||
{
|
||||
info.CommunityRating = likes;
|
||||
}
|
||||
|
||||
list.Add(info);
|
||||
}
|
||||
|
||||
public int Order
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
return _httpClient.GetResponse(new HttpRequestOptions
|
||||
{
|
||||
CancellationToken = cancellationToken,
|
||||
Url = url,
|
||||
ResourcePool = FanartArtistProvider.FanArtResourcePool
|
||||
});
|
||||
}
|
||||
|
||||
public bool HasChanged(IHasMetadata item, DateTime date)
|
||||
{
|
||||
var album = (MusicAlbum)item;
|
||||
|
||||
var artistMusicBrainzId = album.Parent.GetProviderId(MetadataProviders.Musicbrainz);
|
||||
|
||||
if (!String.IsNullOrEmpty(artistMusicBrainzId))
|
||||
{
|
||||
// Process images
|
||||
var artistXmlPath = FanartArtistProvider.GetArtistXmlPath(_config.CommonApplicationPaths, artistMusicBrainzId);
|
||||
|
||||
var fileInfo = new FileInfo(artistXmlPath);
|
||||
|
||||
return fileInfo.Exists && _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ using System.Xml;
|
|||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
public class FanartArtistProvider : IRemoteImageProvider, IHasChangeMonitor
|
||||
public class FanartArtistProvider : IRemoteImageProvider, IHasChangeMonitor, IHasOrder
|
||||
{
|
||||
internal static readonly SemaphoreSlim FanArtResourcePool = new SemaphoreSlim(3, 3);
|
||||
internal const string ApiKey = "5c6b04c68e904cfed1e6cbc9a9e683d4";
|
||||
|
|
|
@ -15,7 +15,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
class FanArtUpdatesPrescanTask : ILibraryPostScanTask
|
||||
class FanartUpdatesPrescanTask : ILibraryPostScanTask
|
||||
{
|
||||
private const string UpdatesUrl = "http://api.fanart.tv/webservice/newmusic/{0}/{1}/";
|
||||
|
||||
|
@ -36,7 +36,7 @@ namespace MediaBrowser.Providers.Music
|
|||
|
||||
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
||||
|
||||
public FanArtUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem)
|
||||
public FanartUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem)
|
||||
{
|
||||
_jsonSerializer = jsonSerializer;
|
||||
_config = config;
|
||||
|
|
|
@ -1,113 +1,165 @@
|
|||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
/// <summary>
|
||||
/// Class LastFmArtistImageProvider
|
||||
/// </summary>
|
||||
public class LastFmImageProvider : BaseMetadataProvider
|
||||
public class LastfmImageProvider : IRemoteImageProvider, IHasOrder
|
||||
{
|
||||
/// <summary>
|
||||
/// The _provider manager
|
||||
/// </summary>
|
||||
private readonly IProviderManager _providerManager;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LastFmImageProvider"/> class.
|
||||
/// </summary>
|
||||
/// <param name="logManager">The log manager.</param>
|
||||
/// <param name="configurationManager">The configuration manager.</param>
|
||||
/// <param name="providerManager">The provider manager.</param>
|
||||
public LastFmImageProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager) :
|
||||
base(logManager, configurationManager)
|
||||
public LastfmImageProvider(IHttpClient httpClient, IServerConfigurationManager config)
|
||||
{
|
||||
_providerManager = providerManager;
|
||||
_httpClient = httpClient;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supportses the specified item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||
public override bool Supports(BaseItem item)
|
||||
public string Name
|
||||
{
|
||||
return item is MusicAlbum;
|
||||
get { return ProviderName; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Needses the refresh internal.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="providerInfo">The provider info.</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||
protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
|
||||
public static string ProviderName
|
||||
{
|
||||
if (item.HasImage(ImageType.Primary))
|
||||
get { return "last.fm"; }
|
||||
}
|
||||
|
||||
public bool Supports(IHasImages item)
|
||||
{
|
||||
return item is MusicAlbum || item is MusicArtist;
|
||||
}
|
||||
|
||||
public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
|
||||
{
|
||||
return new List<ImageType>
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.NeedsRefreshInternal(item, providerInfo);
|
||||
ImageType.Primary
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches metadata and returns true or false indicating if any work that requires persistence was done
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="force">if set to <c>true</c> [force].</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{System.Boolean}.</returns>
|
||||
public override async Task<bool> FetchAsync(BaseItem item, bool force, BaseProviderInfo providerInfo, CancellationToken cancellationToken)
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, ImageType imageType, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!item.HasImage(ImageType.Primary))
|
||||
{
|
||||
var images = await _providerManager.GetAvailableRemoteImages(item, cancellationToken, ManualLastFmImageProvider.ProviderName).ConfigureAwait(false);
|
||||
var images = await GetAllImages(item, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
await DownloadImages(item, images.ToList(), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
SetLastRefreshed(item, DateTime.UtcNow, providerInfo);
|
||||
|
||||
return true;
|
||||
return images.Where(i => i.Type == imageType);
|
||||
}
|
||||
|
||||
private async Task DownloadImages(BaseItem item, List<RemoteImageInfo> images, CancellationToken cancellationToken)
|
||||
public Task<IEnumerable<RemoteImageInfo>> GetAllImages(IHasImages item, CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
var list = new List<RemoteImageInfo>();
|
||||
|
||||
var configSetting = item is MusicAlbum
|
||||
? ConfigurationManager.Configuration.DownloadMusicAlbumImages
|
||||
: ConfigurationManager.Configuration.DownloadMusicArtistImages;
|
||||
RemoteImageInfo info = null;
|
||||
|
||||
if (configSetting.Primary && !item.HasImage(ImageType.Primary) && !item.LockedFields.Contains(MetadataFields.Images))
|
||||
var musicBrainzId = item.GetProviderId(MetadataProviders.Musicbrainz);
|
||||
|
||||
if (!string.IsNullOrEmpty(musicBrainzId))
|
||||
{
|
||||
var image = images.FirstOrDefault(i => i.Type == ImageType.Primary);
|
||||
var cachePath = Path.Combine(_config.ApplicationPaths.CachePath, "lastfm", musicBrainzId, "image.txt");
|
||||
|
||||
if (image != null)
|
||||
try
|
||||
{
|
||||
var parts = File.ReadAllText(cachePath).Split('|');
|
||||
|
||||
info = GetInfo(parts.FirstOrDefault(), parts.LastOrDefault());
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
await _providerManager.SaveImage(item, image.Url, LastFmArtistProvider.LastfmResourcePool, ImageType.Primary, null, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (info == null)
|
||||
{
|
||||
var musicBrainzReleaseGroupId = item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
|
||||
|
||||
if (!string.IsNullOrEmpty(musicBrainzReleaseGroupId))
|
||||
{
|
||||
var cachePath = Path.Combine(_config.ApplicationPaths.CachePath, "lastfm", musicBrainzReleaseGroupId, "image.txt");
|
||||
|
||||
try
|
||||
{
|
||||
var parts = File.ReadAllText(cachePath).Split('|');
|
||||
|
||||
info = GetInfo(parts.FirstOrDefault(), parts.LastOrDefault());
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (info != null)
|
||||
{
|
||||
list.Add(info);
|
||||
}
|
||||
|
||||
// The only info we have is size
|
||||
return Task.FromResult<IEnumerable<RemoteImageInfo>>(list.OrderByDescending(i => i.Width ?? 0));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the priority.
|
||||
/// </summary>
|
||||
/// <value>The priority.</value>
|
||||
public override MetadataProviderPriority Priority
|
||||
private RemoteImageInfo GetInfo(string url, string size)
|
||||
{
|
||||
get { return MetadataProviderPriority.Fifth; }
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var info = new RemoteImageInfo
|
||||
{
|
||||
ProviderName = Name,
|
||||
Url = url,
|
||||
Type = ImageType.Primary
|
||||
};
|
||||
|
||||
if (string.Equals(size, "mega", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
||||
}
|
||||
else if (string.Equals(size, "extralarge", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
||||
}
|
||||
else if (string.Equals(size, "large", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
||||
}
|
||||
else if (string.Equals(size, "medium", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public int Order
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
return _httpClient.GetResponse(new HttpRequestOptions
|
||||
{
|
||||
CancellationToken = cancellationToken,
|
||||
Url = url,
|
||||
ResourcePool = LastfmArtistProvider.LastfmResourcePool
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,106 +1,51 @@
|
|||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MoreLinq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
public class LastfmAlbumProvider : LastfmBaseProvider
|
||||
public class LastfmAlbumProvider : IRemoteMetadataProvider<MusicAlbum>, IHasOrder
|
||||
{
|
||||
internal static LastfmAlbumProvider Current;
|
||||
private readonly IJsonSerializer _json;
|
||||
private readonly IHttpClient _httpClient;
|
||||
|
||||
public LastfmAlbumProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager)
|
||||
: base(jsonSerializer, httpClient, logManager, configurationManager)
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public LastfmAlbumProvider(IHttpClient httpClient, IJsonSerializer json, IServerConfigurationManager config, ILogger logger)
|
||||
{
|
||||
Current = this;
|
||||
_httpClient = httpClient;
|
||||
_json = json;
|
||||
_config = config;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the priority.
|
||||
/// </summary>
|
||||
/// <value>The priority.</value>
|
||||
public override MetadataProviderPriority Priority
|
||||
public async Task<MetadataResult<MusicAlbum>> GetMetadata(ItemId id, CancellationToken cancellationToken)
|
||||
{
|
||||
get { return MetadataProviderPriority.Fourth; }
|
||||
}
|
||||
var result = new MetadataResult<MusicAlbum>();
|
||||
|
||||
protected override string ProviderVersion
|
||||
{
|
||||
get
|
||||
var lastFmData = await GetAlbumResult((AlbumId)id, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (lastFmData != null && lastFmData.album != null)
|
||||
{
|
||||
return "9";
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasAltMeta(BaseItem item)
|
||||
{
|
||||
return item.LocationType == LocationType.FileSystem && item.ResolveArgs.ContainsMetaFileByName("album.xml");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Needses the refresh internal.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="providerInfo">The provider info.</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||
protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
|
||||
{
|
||||
var hasId = !string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Musicbrainz)) &&
|
||||
!string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup));
|
||||
|
||||
if (hasId && HasAltMeta(item))
|
||||
{
|
||||
return false;
|
||||
result.HasMetadata = true;
|
||||
ProcessAlbumData(result.Item, lastFmData.album);
|
||||
}
|
||||
|
||||
// If song metadata has changed and we don't have an mbid, refresh
|
||||
if (!hasId && GetComparisonData(item as MusicAlbum) != providerInfo.FileStamp)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.NeedsRefreshInternal(item, providerInfo);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches metadata and returns true or false indicating if any work that requires persistence was done
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="force">if set to <c>true</c> [force].</param>
|
||||
/// <param name="cancellationToken">The cancellation token</param>
|
||||
/// <returns>Task{System.Boolean}.</returns>
|
||||
public override async Task<bool> FetchAsync(BaseItem item, bool force, BaseProviderInfo providerInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var album = (MusicAlbum)item;
|
||||
|
||||
var result = await GetAlbumResult(album, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (result != null && result.album != null)
|
||||
{
|
||||
LastfmHelper.ProcessAlbumData(item, result.album);
|
||||
}
|
||||
|
||||
providerInfo.FileStamp = GetComparisonData(album);
|
||||
|
||||
SetLastRefreshed(item, DateTime.UtcNow, providerInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private async Task<LastfmGetAlbumResult> GetAlbumResult(MusicAlbum item, CancellationToken cancellationToken)
|
||||
private async Task<LastfmGetAlbumResult> GetAlbumResult(AlbumId item, CancellationToken cancellationToken)
|
||||
{
|
||||
// Try album release Id
|
||||
if (!string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Musicbrainz)))
|
||||
|
@ -123,33 +68,37 @@ namespace MediaBrowser.Providers.Music
|
|||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Get each song, distinct by the combination of AlbumArtist and Album
|
||||
var songs = item.RecursiveChildren.OfType<Audio>().DistinctBy(i => (i.AlbumArtist ?? string.Empty) + (i.Album ?? string.Empty), StringComparer.OrdinalIgnoreCase).ToList();
|
||||
|
||||
foreach (var song in songs.Where(song => !string.IsNullOrEmpty(song.Album) && !string.IsNullOrEmpty(song.AlbumArtist)))
|
||||
//// Get each song, distinct by the combination of AlbumArtist and Album
|
||||
//var songs = item.RecursiveChildren.OfType<Audio>().DistinctBy(i => (i.AlbumArtist ?? string.Empty) + (i.Album ?? string.Empty), StringComparer.OrdinalIgnoreCase).ToList();
|
||||
|
||||
//foreach (var song in songs.Where(song => !string.IsNullOrEmpty(song.Album) && !string.IsNullOrEmpty(song.AlbumArtist)))
|
||||
//{
|
||||
// var result = await GetAlbumResult(song.AlbumArtist, song.Album, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// if (result != null && result.album != null)
|
||||
// {
|
||||
// return result;
|
||||
// }
|
||||
//}
|
||||
|
||||
if (string.IsNullOrEmpty(item.AlbumArtist))
|
||||
{
|
||||
var result = await GetAlbumResult(song.AlbumArtist, song.Album, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (result != null && result.album != null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Try the folder name
|
||||
return await GetAlbumResult(item.Parent.Name, item.Name, cancellationToken);
|
||||
return await GetAlbumResult(item.AlbumArtist, item.Name, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task<LastfmGetAlbumResult> GetAlbumResult(string artist, string album, CancellationToken cancellationToken)
|
||||
{
|
||||
// Get albu info using artist and album name
|
||||
var url = LastFmArtistProvider.RootUrl + string.Format("method=album.getInfo&artist={0}&album={1}&api_key={2}&format=json", UrlEncode(artist), UrlEncode(album), LastFmArtistProvider.ApiKey);
|
||||
var url = LastfmArtistProvider.RootUrl + string.Format("method=album.getInfo&artist={0}&album={1}&api_key={2}&format=json", UrlEncode(artist), UrlEncode(album), LastfmArtistProvider.ApiKey);
|
||||
|
||||
using (var json = await HttpClient.Get(new HttpRequestOptions
|
||||
using (var json = await _httpClient.Get(new HttpRequestOptions
|
||||
{
|
||||
Url = url,
|
||||
ResourcePool = LastFmArtistProvider.LastfmResourcePool,
|
||||
ResourcePool = LastfmArtistProvider.LastfmResourcePool,
|
||||
CancellationToken = cancellationToken,
|
||||
EnableHttpCompression = false
|
||||
|
||||
|
@ -162,7 +111,7 @@ namespace MediaBrowser.Providers.Music
|
|||
// Fix their bad json
|
||||
jsonText = jsonText.Replace("\"#text\"", "\"url\"");
|
||||
|
||||
return JsonSerializer.DeserializeFromString<LastfmGetAlbumResult>(jsonText);
|
||||
return _json.DeserializeFromString<LastfmGetAlbumResult>(jsonText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -170,48 +119,180 @@ namespace MediaBrowser.Providers.Music
|
|||
private async Task<LastfmGetAlbumResult> GetAlbumResult(string musicbraizId, CancellationToken cancellationToken)
|
||||
{
|
||||
// Get albu info using artist and album name
|
||||
var url = LastFmArtistProvider.RootUrl + string.Format("method=album.getInfo&mbid={0}&api_key={1}&format=json", musicbraizId, LastFmArtistProvider.ApiKey);
|
||||
var url = LastfmArtistProvider.RootUrl + string.Format("method=album.getInfo&mbid={0}&api_key={1}&format=json", musicbraizId, LastfmArtistProvider.ApiKey);
|
||||
|
||||
using (var json = await HttpClient.Get(new HttpRequestOptions
|
||||
using (var json = await _httpClient.Get(new HttpRequestOptions
|
||||
{
|
||||
Url = url,
|
||||
ResourcePool = LastFmArtistProvider.LastfmResourcePool,
|
||||
ResourcePool = LastfmArtistProvider.LastfmResourcePool,
|
||||
CancellationToken = cancellationToken,
|
||||
EnableHttpCompression = false
|
||||
|
||||
}).ConfigureAwait(false))
|
||||
{
|
||||
return JsonSerializer.DeserializeFromStream<LastfmGetAlbumResult>(json);
|
||||
return _json.DeserializeFromStream<LastfmGetAlbumResult>(json);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Supports(BaseItem item)
|
||||
private void ProcessAlbumData(MusicAlbum item, LastfmAlbum data)
|
||||
{
|
||||
return item is MusicAlbum;
|
||||
var overview = data.wiki != null ? data.wiki.content : null;
|
||||
|
||||
if (!item.LockedFields.Contains(MetadataFields.Overview))
|
||||
{
|
||||
item.Overview = overview;
|
||||
}
|
||||
|
||||
// Only grab the date here if the album doesn't already have one, since id3 tags are preferred
|
||||
DateTime release;
|
||||
|
||||
if (DateTime.TryParse(data.releasedate, out release))
|
||||
{
|
||||
// Lastfm sends back null as sometimes 1901, other times 0
|
||||
if (release.Year > 1901)
|
||||
{
|
||||
if (!item.PremiereDate.HasValue)
|
||||
{
|
||||
item.PremiereDate = release;
|
||||
}
|
||||
|
||||
if (!item.ProductionYear.HasValue)
|
||||
{
|
||||
item.ProductionYear = release.Year;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string imageSize;
|
||||
var url = LastfmHelper.GetImageUrl(data, out imageSize);
|
||||
|
||||
var musicBrainzId = item.GetProviderId(MetadataProviders.Musicbrainz) ??
|
||||
item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
|
||||
|
||||
LastfmHelper.SaveImageInfo(_config.ApplicationPaths, _logger, musicBrainzId, url, imageSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data.
|
||||
/// Encodes an URL.
|
||||
/// </summary>
|
||||
/// <param name="album">The album.</param>
|
||||
/// <returns>Guid.</returns>
|
||||
private Guid GetComparisonData(MusicAlbum album)
|
||||
/// <param name="name">The name.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private string UrlEncode(string name)
|
||||
{
|
||||
var songs = album.RecursiveChildren.OfType<Audio>().ToList();
|
||||
return WebUtility.UrlEncode(name);
|
||||
}
|
||||
|
||||
var albumArtists = songs.Select(i => i.AlbumArtist)
|
||||
.Where(i => !string.IsNullOrEmpty(i))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
public string Name
|
||||
{
|
||||
get { return "last.fm"; }
|
||||
}
|
||||
|
||||
var albumNames = songs.Select(i => i.AlbumArtist)
|
||||
.Where(i => !string.IsNullOrEmpty(i))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
albumArtists.AddRange(albumNames);
|
||||
|
||||
return string.Join(string.Empty, albumArtists.OrderBy(i => i).ToArray()).GetMD5();
|
||||
public int Order
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
}
|
||||
|
||||
#region Result Objects
|
||||
|
||||
public class LastfmStats
|
||||
{
|
||||
public string listeners { get; set; }
|
||||
public string playcount { get; set; }
|
||||
}
|
||||
|
||||
public class LastfmTag
|
||||
{
|
||||
public string name { get; set; }
|
||||
public string url { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class LastfmTags
|
||||
{
|
||||
public List<LastfmTag> tag { get; set; }
|
||||
}
|
||||
|
||||
public class LastfmFormationInfo
|
||||
{
|
||||
public string yearfrom { get; set; }
|
||||
public string yearto { get; set; }
|
||||
}
|
||||
|
||||
public class LastFmBio
|
||||
{
|
||||
public string published { get; set; }
|
||||
public string summary { get; set; }
|
||||
public string content { get; set; }
|
||||
public string placeformed { get; set; }
|
||||
public string yearformed { get; set; }
|
||||
public List<LastfmFormationInfo> formationlist { get; set; }
|
||||
}
|
||||
|
||||
public class LastFmImage
|
||||
{
|
||||
public string url { get; set; }
|
||||
public string size { get; set; }
|
||||
}
|
||||
|
||||
public class LastfmArtist : IHasLastFmImages
|
||||
{
|
||||
public string name { get; set; }
|
||||
public string mbid { get; set; }
|
||||
public string url { get; set; }
|
||||
public string streamable { get; set; }
|
||||
public string ontour { get; set; }
|
||||
public LastfmStats stats { get; set; }
|
||||
public List<LastfmArtist> similar { get; set; }
|
||||
public LastfmTags tags { get; set; }
|
||||
public LastFmBio bio { get; set; }
|
||||
public List<LastFmImage> image { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class LastfmAlbum : IHasLastFmImages
|
||||
{
|
||||
public string name { get; set; }
|
||||
public string artist { get; set; }
|
||||
public string id { get; set; }
|
||||
public string mbid { get; set; }
|
||||
public string releasedate { get; set; }
|
||||
public int listeners { get; set; }
|
||||
public int playcount { get; set; }
|
||||
public LastfmTags toptags { get; set; }
|
||||
public LastFmBio wiki { get; set; }
|
||||
public List<LastFmImage> image { get; set; }
|
||||
}
|
||||
|
||||
public interface IHasLastFmImages
|
||||
{
|
||||
List<LastFmImage> image { get; set; }
|
||||
}
|
||||
|
||||
public class LastfmGetAlbumResult
|
||||
{
|
||||
public LastfmAlbum album { get; set; }
|
||||
}
|
||||
|
||||
public class LastfmGetArtistResult
|
||||
{
|
||||
public LastfmArtist artist { get; set; }
|
||||
}
|
||||
|
||||
public class Artistmatches
|
||||
{
|
||||
public List<LastfmArtist> artist { get; set; }
|
||||
}
|
||||
|
||||
public class LastfmArtistSearchResult
|
||||
{
|
||||
public Artistmatches artistmatches { get; set; }
|
||||
}
|
||||
|
||||
public class LastfmArtistSearchResults
|
||||
{
|
||||
public LastfmArtistSearchResult results { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ using System.Xml;
|
|||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
public class LastFmArtistProvider : IRemoteMetadataProvider<MusicArtist>
|
||||
public class LastfmArtistProvider : IRemoteMetadataProvider<MusicArtist>
|
||||
{
|
||||
private readonly IJsonSerializer _json;
|
||||
private readonly IHttpClient _httpClient;
|
||||
|
@ -30,12 +30,14 @@ namespace MediaBrowser.Providers.Music
|
|||
internal static string ApiKey = "7b76553c3eb1d341d642755aecc40a33";
|
||||
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private ILogger _logger;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public LastFmArtistProvider(IHttpClient httpClient, IJsonSerializer json)
|
||||
public LastfmArtistProvider(IHttpClient httpClient, IJsonSerializer json, IServerConfigurationManager config, ILogger logger)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_json = json;
|
||||
_config = config;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<MetadataResult<MusicArtist>> GetMetadata(ItemId id, CancellationToken cancellationToken)
|
||||
|
@ -119,25 +121,7 @@ namespace MediaBrowser.Providers.Music
|
|||
string imageSize;
|
||||
var url = LastfmHelper.GetImageUrl(data, out imageSize);
|
||||
|
||||
var cachePath = Path.Combine(_config.ApplicationPaths.CachePath, "lastfm", musicBrainzId, "image.txt");
|
||||
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
File.Delete(cachePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
|
||||
File.WriteAllText(cachePath, url + "|" + imageSize);
|
||||
}
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
// Don't fail if this is unable to write
|
||||
_logger.ErrorException("Error saving to {0}", ex, cachePath);
|
||||
}
|
||||
LastfmHelper.SaveImageInfo(_config.ApplicationPaths, _logger, musicBrainzId, url, imageSize);
|
||||
}
|
||||
|
||||
private async Task<string> FindId(ItemId item, CancellationToken cancellationToken)
|
||||
|
|
|
@ -1,194 +0,0 @@
|
|||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
/// <summary>
|
||||
/// Class MovieDbProvider
|
||||
/// </summary>
|
||||
public abstract class LastfmBaseProvider : BaseMetadataProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LastfmBaseProvider" /> class.
|
||||
/// </summary>
|
||||
/// <param name="jsonSerializer">The json serializer.</param>
|
||||
/// <param name="httpClient">The HTTP client.</param>
|
||||
/// <param name="logManager">The log manager.</param>
|
||||
/// <param name="configurationManager">The configuration manager.</param>
|
||||
/// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
|
||||
protected LastfmBaseProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager)
|
||||
: base(logManager, configurationManager)
|
||||
{
|
||||
if (jsonSerializer == null)
|
||||
{
|
||||
throw new ArgumentNullException("jsonSerializer");
|
||||
}
|
||||
if (httpClient == null)
|
||||
{
|
||||
throw new ArgumentNullException("httpClient");
|
||||
}
|
||||
JsonSerializer = jsonSerializer;
|
||||
HttpClient = httpClient;
|
||||
}
|
||||
|
||||
protected override string ProviderVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
return "8";
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool RefreshOnVersionChange
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the json serializer.
|
||||
/// </summary>
|
||||
/// <value>The json serializer.</value>
|
||||
protected IJsonSerializer JsonSerializer { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the HTTP client.
|
||||
/// </summary>
|
||||
/// <value>The HTTP client.</value>
|
||||
protected IHttpClient HttpClient { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether [requires internet].
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [requires internet]; otherwise, <c>false</c>.</value>
|
||||
public override bool RequiresInternet
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encodes an URL.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
protected static string UrlEncode(string name)
|
||||
{
|
||||
return WebUtility.UrlEncode(name);
|
||||
}
|
||||
}
|
||||
|
||||
#region Result Objects
|
||||
|
||||
public class LastfmStats
|
||||
{
|
||||
public string listeners { get; set; }
|
||||
public string playcount { get; set; }
|
||||
}
|
||||
|
||||
public class LastfmTag
|
||||
{
|
||||
public string name { get; set; }
|
||||
public string url { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class LastfmTags
|
||||
{
|
||||
public List<LastfmTag> tag { get; set; }
|
||||
}
|
||||
|
||||
public class LastfmFormationInfo
|
||||
{
|
||||
public string yearfrom { get; set; }
|
||||
public string yearto { get; set; }
|
||||
}
|
||||
|
||||
public class LastFmBio
|
||||
{
|
||||
public string published { get; set; }
|
||||
public string summary { get; set; }
|
||||
public string content { get; set; }
|
||||
public string placeformed { get; set; }
|
||||
public string yearformed { get; set; }
|
||||
public List<LastfmFormationInfo> formationlist { get; set; }
|
||||
}
|
||||
|
||||
public class LastFmImage
|
||||
{
|
||||
public string url { get; set; }
|
||||
public string size { get; set; }
|
||||
}
|
||||
|
||||
public class LastfmArtist : IHasLastFmImages
|
||||
{
|
||||
public string name { get; set; }
|
||||
public string mbid { get; set; }
|
||||
public string url { get; set; }
|
||||
public string streamable { get; set; }
|
||||
public string ontour { get; set; }
|
||||
public LastfmStats stats { get; set; }
|
||||
public List<LastfmArtist> similar { get; set; }
|
||||
public LastfmTags tags { get; set; }
|
||||
public LastFmBio bio { get; set; }
|
||||
public List<LastFmImage> image { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class LastfmAlbum : IHasLastFmImages
|
||||
{
|
||||
public string name { get; set; }
|
||||
public string artist { get; set; }
|
||||
public string id { get; set; }
|
||||
public string mbid { get; set; }
|
||||
public string releasedate { get; set; }
|
||||
public int listeners { get; set; }
|
||||
public int playcount { get; set; }
|
||||
public LastfmTags toptags { get; set; }
|
||||
public LastFmBio wiki { get; set; }
|
||||
public List<LastFmImage> image { get; set; }
|
||||
}
|
||||
|
||||
public interface IHasLastFmImages
|
||||
{
|
||||
List<LastFmImage> image { get; set; }
|
||||
}
|
||||
|
||||
public class LastfmGetAlbumResult
|
||||
{
|
||||
public LastfmAlbum album { get; set; }
|
||||
}
|
||||
|
||||
public class LastfmGetArtistResult
|
||||
{
|
||||
public LastfmArtist artist { get; set; }
|
||||
}
|
||||
|
||||
public class Artistmatches
|
||||
{
|
||||
public List<LastfmArtist> artist { get; set; }
|
||||
}
|
||||
|
||||
public class LastfmArtistSearchResult
|
||||
{
|
||||
public Artistmatches artistmatches { get; set; }
|
||||
}
|
||||
|
||||
public class LastfmArtistSearchResults
|
||||
{
|
||||
public LastfmArtistSearchResult results { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
|
@ -37,41 +37,27 @@ namespace MediaBrowser.Providers.Music
|
|||
return null;
|
||||
}
|
||||
|
||||
public static void ProcessAlbumData(BaseItem item, LastfmAlbum data)
|
||||
public static void SaveImageInfo(IApplicationPaths appPaths, ILogger logger, string musicBrainzId, string url, string size)
|
||||
{
|
||||
var overview = data.wiki != null ? data.wiki.content : null;
|
||||
var cachePath = Path.Combine(appPaths.CachePath, "lastfm", musicBrainzId, "image.txt");
|
||||
|
||||
if (!item.LockedFields.Contains(MetadataFields.Overview))
|
||||
try
|
||||
{
|
||||
item.Overview = overview;
|
||||
}
|
||||
|
||||
// Only grab the date here if the album doesn't already have one, since id3 tags are preferred
|
||||
DateTime release;
|
||||
|
||||
if (DateTime.TryParse(data.releasedate, out release))
|
||||
{
|
||||
// Lastfm sends back null as sometimes 1901, other times 0
|
||||
if (release.Year > 1901)
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
if (!item.PremiereDate.HasValue)
|
||||
{
|
||||
item.PremiereDate = release;
|
||||
}
|
||||
|
||||
if (!item.ProductionYear.HasValue)
|
||||
{
|
||||
item.ProductionYear = release.Year;
|
||||
}
|
||||
File.Delete(cachePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
|
||||
File.WriteAllText(cachePath, url + "|" + size);
|
||||
}
|
||||
}
|
||||
|
||||
var album = (MusicAlbum)item;
|
||||
|
||||
string imageSize;
|
||||
|
||||
album.LastFmImageUrl = GetImageUrl(data, out imageSize);
|
||||
album.LastFmImageSize = imageSize;
|
||||
catch (IOException ex)
|
||||
{
|
||||
// Don't fail if this is unable to write
|
||||
logger.ErrorException("Error saving to {0}", ex, cachePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,354 +0,0 @@
|
|||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
public class ManualFanartAlbumProvider : IRemoteImageProvider
|
||||
{
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IHttpClient _httpClient;
|
||||
|
||||
public ManualFanartAlbumProvider(IServerConfigurationManager config, IHttpClient httpClient)
|
||||
{
|
||||
_config = config;
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return ProviderName; }
|
||||
}
|
||||
|
||||
public static string ProviderName
|
||||
{
|
||||
get { return "FanArt"; }
|
||||
}
|
||||
|
||||
public bool Supports(IHasImages item)
|
||||
{
|
||||
return item is MusicAlbum;
|
||||
}
|
||||
|
||||
public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
|
||||
{
|
||||
return new List<ImageType>
|
||||
{
|
||||
ImageType.Primary,
|
||||
ImageType.Disc
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, ImageType imageType, CancellationToken cancellationToken)
|
||||
{
|
||||
var images = await GetAllImages(item, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return images.Where(i => i.Type == imageType);
|
||||
}
|
||||
|
||||
public Task<IEnumerable<RemoteImageInfo>> GetAllImages(IHasImages item, CancellationToken cancellationToken)
|
||||
{
|
||||
var album = (MusicAlbum)item;
|
||||
|
||||
var list = new List<RemoteImageInfo>();
|
||||
|
||||
var artistMusicBrainzId = album.Parent.GetProviderId(MetadataProviders.Musicbrainz);
|
||||
|
||||
if (!string.IsNullOrEmpty(artistMusicBrainzId))
|
||||
{
|
||||
var artistXmlPath = FanartArtistProvider.GetArtistXmlPath(_config.CommonApplicationPaths, artistMusicBrainzId);
|
||||
|
||||
var musicBrainzReleaseGroupId = album.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
|
||||
|
||||
var musicBrainzId = album.GetProviderId(MetadataProviders.Musicbrainz);
|
||||
|
||||
try
|
||||
{
|
||||
AddImages(list, artistXmlPath, musicBrainzId, musicBrainzReleaseGroupId, cancellationToken);
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var language = item.GetPreferredMetadataLanguage();
|
||||
|
||||
var isLanguageEn = string.Equals(language, "en", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
// Sort first by width to prioritize HD versions
|
||||
list = list.OrderByDescending(i => i.Width ?? 0)
|
||||
.ThenByDescending(i =>
|
||||
{
|
||||
if (string.Equals(language, i.Language, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
if (!isLanguageEn)
|
||||
{
|
||||
if (string.Equals("en", i.Language, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(i.Language))
|
||||
{
|
||||
return isLanguageEn ? 3 : 2;
|
||||
}
|
||||
return 0;
|
||||
})
|
||||
.ThenByDescending(i => i.CommunityRating ?? 0)
|
||||
.ThenByDescending(i => i.VoteCount ?? 0)
|
||||
.ToList();
|
||||
|
||||
return Task.FromResult<IEnumerable<RemoteImageInfo>>(list);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the images.
|
||||
/// </summary>
|
||||
/// <param name="list">The list.</param>
|
||||
/// <param name="xmlPath">The XML path.</param>
|
||||
/// <param name="releaseId">The release identifier.</param>
|
||||
/// <param name="releaseGroupId">The release group identifier.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
private void AddImages(List<RemoteImageInfo> list, string xmlPath, string releaseId, string releaseGroupId, CancellationToken cancellationToken)
|
||||
{
|
||||
using (var streamReader = new StreamReader(xmlPath, Encoding.UTF8))
|
||||
{
|
||||
// Use XmlReader for best performance
|
||||
using (var reader = XmlReader.Create(streamReader, new XmlReaderSettings
|
||||
{
|
||||
CheckCharacters = false,
|
||||
IgnoreProcessingInstructions = true,
|
||||
IgnoreComments = true,
|
||||
ValidationType = ValidationType.None
|
||||
}))
|
||||
{
|
||||
reader.MoveToContent();
|
||||
|
||||
// Loop through each element
|
||||
while (reader.Read())
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
switch (reader.Name)
|
||||
{
|
||||
case "music":
|
||||
{
|
||||
using (var subReader = reader.ReadSubtree())
|
||||
{
|
||||
AddImagesFromMusicNode(list, releaseId, releaseGroupId, subReader, cancellationToken);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
reader.Skip();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the images from music node.
|
||||
/// </summary>
|
||||
/// <param name="list">The list.</param>
|
||||
/// <param name="releaseId">The release identifier.</param>
|
||||
/// <param name="releaseGroupId">The release group identifier.</param>
|
||||
/// <param name="reader">The reader.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
private void AddImagesFromMusicNode(List<RemoteImageInfo> list, string releaseId, string releaseGroupId, XmlReader reader, CancellationToken cancellationToken)
|
||||
{
|
||||
reader.MoveToContent();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
switch (reader.Name)
|
||||
{
|
||||
case "albums":
|
||||
{
|
||||
using (var subReader = reader.ReadSubtree())
|
||||
{
|
||||
AddImagesFromAlbumsNode(list, releaseId, releaseGroupId, subReader, cancellationToken);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
using (reader.ReadSubtree())
|
||||
{
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the images from albums node.
|
||||
/// </summary>
|
||||
/// <param name="list">The list.</param>
|
||||
/// <param name="releaseId">The release identifier.</param>
|
||||
/// <param name="releaseGroupId">The release group identifier.</param>
|
||||
/// <param name="reader">The reader.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
private void AddImagesFromAlbumsNode(List<RemoteImageInfo> list, string releaseId, string releaseGroupId, XmlReader reader, CancellationToken cancellationToken)
|
||||
{
|
||||
reader.MoveToContent();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
switch (reader.Name)
|
||||
{
|
||||
case "album":
|
||||
{
|
||||
var id = reader.GetAttribute("id");
|
||||
|
||||
using (var subReader = reader.ReadSubtree())
|
||||
{
|
||||
if (string.Equals(id, releaseId, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(id, releaseGroupId, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
AddImages(list, subReader, cancellationToken);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
using (reader.ReadSubtree())
|
||||
{
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the images.
|
||||
/// </summary>
|
||||
/// <param name="list">The list.</param>
|
||||
/// <param name="reader">The reader.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
private void AddImages(List<RemoteImageInfo> list, XmlReader reader, CancellationToken cancellationToken)
|
||||
{
|
||||
reader.MoveToContent();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
switch (reader.Name)
|
||||
{
|
||||
case "cdart":
|
||||
{
|
||||
AddImage(list, reader, ImageType.Disc, 1000, 1000);
|
||||
break;
|
||||
}
|
||||
case "albumcover":
|
||||
{
|
||||
AddImage(list, reader, ImageType.Primary, 1000, 1000);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
using (reader.ReadSubtree())
|
||||
{
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the image.
|
||||
/// </summary>
|
||||
/// <param name="list">The list.</param>
|
||||
/// <param name="reader">The reader.</param>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="height">The height.</param>
|
||||
private void AddImage(List<RemoteImageInfo> list, XmlReader reader, ImageType type, int width, int height)
|
||||
{
|
||||
var url = reader.GetAttribute("url");
|
||||
|
||||
var size = reader.GetAttribute("size");
|
||||
|
||||
if (!string.IsNullOrEmpty(size))
|
||||
{
|
||||
int sizeNum;
|
||||
if (int.TryParse(size, NumberStyles.Any, _usCulture, out sizeNum))
|
||||
{
|
||||
width = sizeNum;
|
||||
height = sizeNum;
|
||||
}
|
||||
}
|
||||
|
||||
var likesString = reader.GetAttribute("likes");
|
||||
int likes;
|
||||
|
||||
var info = new RemoteImageInfo
|
||||
{
|
||||
RatingType = RatingType.Likes,
|
||||
Type = type,
|
||||
Width = width,
|
||||
Height = height,
|
||||
ProviderName = Name,
|
||||
Url = url,
|
||||
Language = reader.GetAttribute("lang")
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Any, _usCulture, out likes))
|
||||
{
|
||||
info.CommunityRating = likes;
|
||||
}
|
||||
|
||||
list.Add(info);
|
||||
}
|
||||
|
||||
public int Order
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
return _httpClient.GetResponse(new HttpRequestOptions
|
||||
{
|
||||
CancellationToken = cancellationToken,
|
||||
Url = url,
|
||||
ResourcePool = FanartArtistProvider.FanArtResourcePool
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,150 +0,0 @@
|
|||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
public class ManualLastFmImageProvider : IRemoteImageProvider
|
||||
{
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
public ManualLastFmImageProvider(IHttpClient httpClient, IServerConfigurationManager config)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return ProviderName; }
|
||||
}
|
||||
|
||||
public static string ProviderName
|
||||
{
|
||||
get { return "last.fm"; }
|
||||
}
|
||||
|
||||
public bool Supports(IHasImages item)
|
||||
{
|
||||
return item is MusicAlbum || item is MusicArtist;
|
||||
}
|
||||
|
||||
public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
|
||||
{
|
||||
return new List<ImageType>
|
||||
{
|
||||
ImageType.Primary
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, ImageType imageType, CancellationToken cancellationToken)
|
||||
{
|
||||
var images = await GetAllImages(item, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return images.Where(i => i.Type == imageType);
|
||||
}
|
||||
|
||||
public Task<IEnumerable<RemoteImageInfo>> GetAllImages(IHasImages item, CancellationToken cancellationToken)
|
||||
{
|
||||
var list = new List<RemoteImageInfo>();
|
||||
|
||||
RemoteImageInfo info = null;
|
||||
|
||||
var musicBrainzId = item.GetProviderId(MetadataProviders.Musicbrainz);
|
||||
|
||||
var album = item as MusicAlbum;
|
||||
if (album != null)
|
||||
{
|
||||
info = GetInfo(album.LastFmImageUrl, album.LastFmImageSize);
|
||||
}
|
||||
|
||||
var musicArtist = item as MusicArtist;
|
||||
if (musicArtist != null && !string.IsNullOrEmpty(musicBrainzId))
|
||||
{
|
||||
var cachePath = Path.Combine(_config.ApplicationPaths.CachePath, "lastfm", musicBrainzId, "image.txt");
|
||||
|
||||
try
|
||||
{
|
||||
var parts = File.ReadAllText(cachePath).Split('|');
|
||||
|
||||
info = GetInfo(parts.FirstOrDefault(), parts.LastOrDefault());
|
||||
}
|
||||
catch (DirectoryNotFoundException ex)
|
||||
{
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (info != null)
|
||||
{
|
||||
list.Add(info);
|
||||
}
|
||||
|
||||
// The only info we have is size
|
||||
return Task.FromResult<IEnumerable<RemoteImageInfo>>(list.OrderByDescending(i => i.Width ?? 0));
|
||||
}
|
||||
|
||||
private RemoteImageInfo GetInfo(string url, string size)
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var info = new RemoteImageInfo
|
||||
{
|
||||
ProviderName = Name,
|
||||
Url = url,
|
||||
Type = ImageType.Primary
|
||||
};
|
||||
|
||||
if (string.Equals(size, "mega", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
||||
}
|
||||
else if (string.Equals(size, "extralarge", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
||||
}
|
||||
else if (string.Equals(size, "large", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
||||
}
|
||||
else if (string.Equals(size, "medium", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public int Order
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
|
||||
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
return _httpClient.GetResponse(new HttpRequestOptions
|
||||
{
|
||||
CancellationToken = cancellationToken,
|
||||
Url = url,
|
||||
ResourcePool = LastFmArtistProvider.LastfmResourcePool
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,8 @@
|
|||
using MediaBrowser.Common;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
@ -16,46 +13,46 @@ using System.Xml;
|
|||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
public class MusicBrainzAlbumProvider : BaseMetadataProvider
|
||||
public class MusicBrainzAlbumProvider : IRemoteMetadataProvider<MusicAlbum>, IHasOrder
|
||||
{
|
||||
internal static MusicBrainzAlbumProvider Current;
|
||||
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IApplicationHost _appHost;
|
||||
|
||||
public MusicBrainzAlbumProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IHttpClient httpClient, IApplicationHost appHost)
|
||||
: base(logManager, configurationManager)
|
||||
public MusicBrainzAlbumProvider(IHttpClient httpClient, IApplicationHost appHost)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_appHost = appHost;
|
||||
|
||||
Current = this;
|
||||
}
|
||||
|
||||
public override bool Supports(BaseItem item)
|
||||
public async Task<MetadataResult<MusicAlbum>> GetMetadata(ItemId id, CancellationToken cancellationToken)
|
||||
{
|
||||
return item is MusicAlbum;
|
||||
}
|
||||
var albumId = (AlbumId)id;
|
||||
var releaseId = albumId.GetProviderId(MetadataProviders.Musicbrainz);
|
||||
var releaseGroupId = albumId.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
|
||||
|
||||
public override async Task<bool> FetchAsync(BaseItem item, bool force, BaseProviderInfo providerInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
var releaseId = item.GetProviderId(MetadataProviders.Musicbrainz);
|
||||
var releaseGroupId = item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
|
||||
var result = new MetadataResult<MusicAlbum>();
|
||||
|
||||
if (string.IsNullOrEmpty(releaseId))
|
||||
{
|
||||
var result = await GetReleaseResult((MusicAlbum)item, cancellationToken).ConfigureAwait(false);
|
||||
var releaseResult = await GetReleaseResult(albumId.ArtistMusicBrainzId, albumId.AlbumArtist, albumId.Name, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (!string.IsNullOrEmpty(result.ReleaseId))
|
||||
result.Item = new MusicAlbum();
|
||||
|
||||
if (!string.IsNullOrEmpty(releaseResult.ReleaseId))
|
||||
{
|
||||
releaseId = result.ReleaseId;
|
||||
item.SetProviderId(MetadataProviders.Musicbrainz, releaseId);
|
||||
releaseId = releaseResult.ReleaseId;
|
||||
result.HasMetadata = true;
|
||||
result.Item.SetProviderId(MetadataProviders.Musicbrainz, releaseId);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(result.ReleaseGroupId))
|
||||
if (!string.IsNullOrEmpty(releaseResult.ReleaseGroupId))
|
||||
{
|
||||
releaseGroupId = result.ReleaseGroupId;
|
||||
item.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, releaseGroupId);
|
||||
releaseGroupId = releaseResult.ReleaseGroupId;
|
||||
result.HasMetadata = true;
|
||||
result.Item.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, releaseGroupId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,25 +60,26 @@ namespace MediaBrowser.Providers.Music
|
|||
if (!string.IsNullOrEmpty(releaseId) && string.IsNullOrEmpty(releaseGroupId))
|
||||
{
|
||||
releaseGroupId = await GetReleaseGroupId(releaseId, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
item.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, releaseGroupId);
|
||||
result.HasMetadata = true;
|
||||
result.Item.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, releaseGroupId);
|
||||
}
|
||||
|
||||
SetLastRefreshed(item, DateTime.UtcNow, providerInfo);
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
private Task<ReleaseResult> GetReleaseResult(MusicAlbum album, CancellationToken cancellationToken)
|
||||
public string Name
|
||||
{
|
||||
var artist = album.Parent;
|
||||
var artistId = artist.GetProviderId(MetadataProviders.Musicbrainz);
|
||||
get { return "MusicBrainz"; }
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(artistId))
|
||||
private Task<ReleaseResult> GetReleaseResult(string artistMusicBrainId, string artistName, string albumName, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(artistMusicBrainId))
|
||||
{
|
||||
return GetReleaseResult(album.Name, artistId, cancellationToken);
|
||||
return GetReleaseResult(albumName, artistMusicBrainId, cancellationToken);
|
||||
}
|
||||
|
||||
return GetReleaseResultByArtistName(album.Name, artist.Name, cancellationToken);
|
||||
return GetReleaseResultByArtistName(albumName, artistName, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task<ReleaseResult> GetReleaseResult(string albumName, string artistId, CancellationToken cancellationToken)
|
||||
|
@ -218,10 +216,9 @@ namespace MediaBrowser.Providers.Music
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public override MetadataProviderPriority Priority
|
||||
public int Order
|
||||
{
|
||||
get { return MetadataProviderPriority.Third; }
|
||||
get { return 0; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Providers.MusicGenres
|
||||
{
|
||||
public class MusicGenreMetadataService : ConcreteMetadataService<MusicGenre>
|
||||
public class MusicGenreMetadataService : ConcreteMetadataService<MusicGenre, ItemId>
|
||||
{
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Providers.People
|
||||
{
|
||||
public class MovieDbPersonImageProvider : IRemoteImageProvider
|
||||
public class MovieDbPersonImageProvider : IRemoteImageProvider, IHasOrder
|
||||
{
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
|
|
|
@ -11,7 +11,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Providers.People
|
||||
{
|
||||
public class PersonMetadataService : ConcreteMetadataService<Person>
|
||||
public class PersonMetadataService : ConcreteMetadataService<Person, ItemId>
|
||||
{
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ using System.Xml;
|
|||
|
||||
namespace MediaBrowser.Providers.People
|
||||
{
|
||||
public class TvdbPersonImageProvider : IRemoteImageProvider
|
||||
public class TvdbPersonImageProvider : IRemoteImageProvider, IHasOrder
|
||||
{
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly ILibraryManager _library;
|
||||
|
|
|
@ -11,7 +11,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Providers.Studios
|
||||
{
|
||||
public class StudioMetadataService : ConcreteMetadataService<Studio>
|
||||
public class StudioMetadataService : ConcreteMetadataService<Studio, ItemId>
|
||||
{
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ namespace MediaBrowser.Providers.TV
|
|||
|
||||
var existingDictionary = existingSeriesIds.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var updates = _jsonSerializer.DeserializeFromString<List<FanArtUpdatesPrescanTask.FanArtUpdate>>(json);
|
||||
var updates = _jsonSerializer.DeserializeFromString<List<FanartUpdatesPrescanTask.FanArtUpdate>>(json);
|
||||
|
||||
return updates.Select(i => i.id).Where(existingDictionary.ContainsKey);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ using MediaBrowser.Providers.Music;
|
|||
|
||||
namespace MediaBrowser.Providers.TV
|
||||
{
|
||||
public class ManualFanartSeasonImageProvider : IRemoteImageProvider
|
||||
public class ManualFanartSeasonImageProvider : IRemoteImageProvider, IHasOrder
|
||||
{
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
|
|
@ -19,7 +19,7 @@ using MediaBrowser.Providers.Music;
|
|||
|
||||
namespace MediaBrowser.Providers.TV
|
||||
{
|
||||
public class ManualFanartSeriesImageProvider : IRemoteImageProvider
|
||||
public class ManualFanartSeriesImageProvider : IRemoteImageProvider, IHasOrder
|
||||
{
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
|
|
@ -19,7 +19,7 @@ using System.Xml;
|
|||
|
||||
namespace MediaBrowser.Providers.TV
|
||||
{
|
||||
public class ManualTvdbSeasonImageProvider : IRemoteImageProvider
|
||||
public class ManualTvdbSeasonImageProvider : IRemoteImageProvider, IHasOrder
|
||||
{
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
|
|
|
@ -19,7 +19,7 @@ using System.Xml;
|
|||
|
||||
namespace MediaBrowser.Providers.TV
|
||||
{
|
||||
public class ManualTvdbSeriesImageProvider : IRemoteImageProvider
|
||||
public class ManualTvdbSeriesImageProvider : IRemoteImageProvider, IHasOrder
|
||||
{
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IHttpClient _httpClient;
|
||||
|
|
|
@ -11,7 +11,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Providers.Users
|
||||
{
|
||||
public class UserMetadataService : ConcreteMetadataService<User>
|
||||
public class UserMetadataService : ConcreteMetadataService<User, ItemId>
|
||||
{
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user