浏览代码

added audio db id's to web client

Luke Pulverenti 11 年之前
父节点
当前提交
a29cd06883

+ 1 - 1
MediaBrowser.Api/BaseApiService.cs

@@ -75,7 +75,7 @@ namespace MediaBrowser.Api
         protected object ToOptimizedSerializedResultUsingCache<T>(T result)
            where T : class
         {
-            return ResultFactory.GetOptimizedSerializedResultUsingCache(Request, result);
+            return ToOptimizedResult(result);
         }
         
         /// <summary>

+ 2 - 2
MediaBrowser.Api/Images/RemoteImageService.cs

@@ -193,7 +193,7 @@ namespace MediaBrowser.Api.Images
 
         private List<ImageProviderInfo> GetImageProviders(BaseItem item)
         {
-            return _providerManager.GetImageProviderInfo(item).ToList();
+            return _providerManager.GetRemoteImageProviderInfo(item).ToList();
         }
 
         public object Get(GetRemoteImages request)
@@ -224,7 +224,7 @@ namespace MediaBrowser.Api.Images
             var result = new RemoteImageResult
             {
                 TotalRecordCount = imagesList.Count,
-                Providers = images.Select(i => i.ProviderName)
+                Providers = imagesList.Select(i => i.ProviderName)
                 .Distinct(StringComparer.OrdinalIgnoreCase)
                 .ToList()
             };

+ 2 - 2
MediaBrowser.Api/ItemRefreshService.cs

@@ -308,8 +308,8 @@ namespace MediaBrowser.Api
         {
             return new MetadataRefreshOptions
             {
-                MetadataRefreshMode = request.Forced ? MetadataRefreshMode.FullRefresh : MetadataRefreshMode.EnsureMetadata,
-                ImageRefreshMode = request.Forced ? ImageRefreshMode.FullRefresh : ImageRefreshMode.Default,
+                MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
+                ImageRefreshMode = ImageRefreshMode.FullRefresh,
                 ReplaceAllMetadata = request.Forced
             };
         }

+ 1 - 1
MediaBrowser.Api/UserService.cs

@@ -68,7 +68,7 @@ namespace MediaBrowser.Api
     /// </summary>
     [Route("/Users/{Id}/Authenticate", "POST")]
     [Api(Description = "Authenticates a user")]
-    public class AuthenticateUser : IReturnVoid
+    public class AuthenticateUser : IReturn<AuthenticationResult>
     {
         /// <summary>
         /// Gets or sets the id.

+ 18 - 0
MediaBrowser.Controller/Providers/BaseItemXmlParser.cs

@@ -719,6 +719,24 @@ namespace MediaBrowser.Controller.Providers
                         }
                         break;
                     }
+                case "TvRageId":
+                    {
+                        var id = reader.ReadElementContentAsString();
+                        if (!string.IsNullOrWhiteSpace(id))
+                        {
+                            item.SetProviderId(MetadataProviders.TvRage, id);
+                        }
+                        break;
+                    }
+                case "AudioDbArtistId":
+                    {
+                        var id = reader.ReadElementContentAsString();
+                        if (!string.IsNullOrWhiteSpace(id))
+                        {
+                            item.SetProviderId(MetadataProviders.AudioDbArtist, id);
+                        }
+                        break;
+                    }
                 case "RottenTomatoesId":
                     var rtId = reader.ReadElementContentAsString();
                     if (!string.IsNullOrWhiteSpace(rtId))

+ 1 - 1
MediaBrowser.Controller/Providers/IProviderManager.cs

@@ -73,7 +73,7 @@ namespace MediaBrowser.Controller.Providers
         /// </summary>
         /// <param name="item">The item.</param>
         /// <returns>IEnumerable{ImageProviderInfo}.</returns>
-        IEnumerable<ImageProviderInfo> GetImageProviderInfo(IHasImages item);
+        IEnumerable<ImageProviderInfo> GetRemoteImageProviderInfo(IHasImages item);
 
         /// <summary>
         /// Gets all metadata plugins.

+ 2 - 3
MediaBrowser.Model/Entities/MetadataProviders.cs

@@ -39,8 +39,7 @@ namespace MediaBrowser.Model.Entities
         NesBox,
         NesBoxRom,
         TvRage,
-        Freebase,
-        FreebaseMachine,
-        AudioDbArtist
+        AudioDbArtist,
+        AudioDbAlbum
     }
 }

+ 1 - 1
MediaBrowser.Providers/Manager/ProviderManager.cs

@@ -275,7 +275,7 @@ namespace MediaBrowser.Providers.Manager
         /// </summary>
         /// <param name="item">The item.</param>
         /// <returns>IEnumerable{IImageProvider}.</returns>
-        public IEnumerable<ImageProviderInfo> GetImageProviderInfo(IHasImages item)
+        public IEnumerable<ImageProviderInfo> GetRemoteImageProviderInfo(IHasImages item)
         {
             return GetRemoteImageProviders(item).Select(i => new ImageProviderInfo
             {

+ 2 - 0
MediaBrowser.Providers/MediaBrowser.Providers.csproj

@@ -119,6 +119,8 @@
     <Compile Include="Music\AlbumImageFromSongProvider.cs" />
     <Compile Include="Music\AlbumMetadataService.cs" />
     <Compile Include="Music\ArtistMetadataService.cs" />
+    <Compile Include="Music\AudioDbAlbumImageProvider.cs" />
+    <Compile Include="Music\AudioDbAlbumProvider.cs" />
     <Compile Include="Music\AudioDbArtistImageProvider.cs" />
     <Compile Include="Music\AudioDbArtistProvider.cs" />
     <Compile Include="Music\AudioMetadataService.cs" />

+ 29 - 3
MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
@@ -6,9 +6,11 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaInfo;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Serialization;
 using System;
 using System.Collections.Generic;
 using System.Globalization;
+using System.IO;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
@@ -19,13 +21,17 @@ namespace MediaBrowser.Providers.MediaInfo
     {
         private readonly IMediaEncoder _mediaEncoder;
         private readonly IItemRepository _itemRepo;
+        private readonly IApplicationPaths _appPaths;
+        private readonly IJsonSerializer _json;
 
         private readonly CultureInfo _usCulture = new CultureInfo("en-US");
 
-        public FFProbeAudioInfo(IMediaEncoder mediaEncoder, IItemRepository itemRepo)
+        public FFProbeAudioInfo(IMediaEncoder mediaEncoder, IItemRepository itemRepo, IApplicationPaths appPaths, IJsonSerializer json)
         {
             _mediaEncoder = mediaEncoder;
             _itemRepo = itemRepo;
+            _appPaths = appPaths;
+            _json = json;
         }
 
         public async Task<ItemUpdateType> Probe<T>(T item, CancellationToken cancellationToken)
@@ -48,10 +54,30 @@ namespace MediaBrowser.Providers.MediaInfo
         {
             cancellationToken.ThrowIfCancellationRequested();
 
+            var idString = item.Id.ToString("N");
+            var cachePath = Path.Combine(_appPaths.CachePath, "ffprobe-audio", idString.Substring(0, 2), idString, "v" + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json");
+
+            try
+            {
+                return _json.DeserializeFromFile<InternalMediaInfoResult>(cachePath);
+            }
+            catch (FileNotFoundException)
+            {
+
+            }
+            catch (DirectoryNotFoundException)
+            {
+            }
+
             const InputType type = InputType.File;
             var inputPath = new[] { item.Path };
 
-            return await _mediaEncoder.GetMediaInfo(inputPath, type, false, cancellationToken).ConfigureAwait(false);
+            var result = await _mediaEncoder.GetMediaInfo(inputPath, type, false, cancellationToken).ConfigureAwait(false);
+
+            Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
+            _json.SerializeToFile(result, cachePath);
+
+            return result;
         }
 
         /// <summary>

+ 10 - 4
MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.TV;
@@ -15,6 +16,7 @@ using MediaBrowser.Model.MediaInfo;
 using System;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Model.Serialization;
 
 namespace MediaBrowser.Providers.MediaInfo
 {
@@ -36,6 +38,8 @@ namespace MediaBrowser.Providers.MediaInfo
         private readonly IItemRepository _itemRepo;
         private readonly IBlurayExaminer _blurayExaminer;
         private readonly ILocalizationManager _localization;
+        private readonly IApplicationPaths _appPaths;
+        private readonly IJsonSerializer _json;
 
         public string Name
         {
@@ -87,7 +91,7 @@ namespace MediaBrowser.Providers.MediaInfo
             return FetchAudioInfo(item, cancellationToken);
         }
 
-        public FFProbeProvider(ILogger logger, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization)
+        public FFProbeProvider(ILogger logger, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization, IApplicationPaths appPaths, IJsonSerializer json)
         {
             _logger = logger;
             _isoManager = isoManager;
@@ -95,6 +99,8 @@ namespace MediaBrowser.Providers.MediaInfo
             _itemRepo = itemRepo;
             _blurayExaminer = blurayExaminer;
             _localization = localization;
+            _appPaths = appPaths;
+            _json = json;
         }
 
         private readonly Task<ItemUpdateType> _cachedTask = Task.FromResult(ItemUpdateType.Unspecified);
@@ -116,7 +122,7 @@ namespace MediaBrowser.Providers.MediaInfo
                 return _cachedTask;
             }
 
-            var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization);
+            var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization, _appPaths, _json);
 
             return prober.ProbeVideo(item, cancellationToken);
         }
@@ -129,7 +135,7 @@ namespace MediaBrowser.Providers.MediaInfo
                 return _cachedTask;
             }
 
-            var prober = new FFProbeAudioInfo(_mediaEncoder, _itemRepo);
+            var prober = new FFProbeAudioInfo(_mediaEncoder, _itemRepo, _appPaths, _json);
 
             return prober.Probe(item, cancellationToken);
         }

+ 30 - 2
MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs

@@ -1,4 +1,5 @@
 using DvdLib.Ifo;
+using MediaBrowser.Common.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Localization;
@@ -8,6 +9,7 @@ using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.Serialization;
 using System;
 using System.Collections.Generic;
 using System.Globalization;
@@ -26,10 +28,12 @@ namespace MediaBrowser.Providers.MediaInfo
         private readonly IItemRepository _itemRepo;
         private readonly IBlurayExaminer _blurayExaminer;
         private readonly ILocalizationManager _localization;
+        private readonly IApplicationPaths _appPaths;
+        private readonly IJsonSerializer _json;
 
         private readonly CultureInfo _usCulture = new CultureInfo("en-US");
 
-        public FFProbeVideoInfo(ILogger logger, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization)
+        public FFProbeVideoInfo(ILogger logger, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization, IApplicationPaths appPaths, IJsonSerializer json)
         {
             _logger = logger;
             _isoManager = isoManager;
@@ -37,6 +41,8 @@ namespace MediaBrowser.Providers.MediaInfo
             _itemRepo = itemRepo;
             _blurayExaminer = blurayExaminer;
             _localization = localization;
+            _appPaths = appPaths;
+            _json = json;
         }
 
         public async Task<ItemUpdateType> ProbeVideo<T>(T item, CancellationToken cancellationToken)
@@ -84,6 +90,23 @@ namespace MediaBrowser.Providers.MediaInfo
         {
             cancellationToken.ThrowIfCancellationRequested();
 
+            cancellationToken.ThrowIfCancellationRequested();
+
+            var idString = item.Id.ToString("N");
+            var cachePath = Path.Combine(_appPaths.CachePath, "ffprobe-video", idString.Substring(0, 2), idString, "v" + _mediaEncoder.Version + item.DateModified.Ticks.ToString(_usCulture) + ".json");
+
+            try
+            {
+                return _json.DeserializeFromFile<InternalMediaInfoResult>(cachePath);
+            }
+            catch (FileNotFoundException)
+            {
+
+            }
+            catch (DirectoryNotFoundException)
+            {
+            }
+
             var type = InputType.File;
             var inputPath = isoMount == null ? new[] { item.Path } : new[] { isoMount.MountedPath };
 
@@ -94,7 +117,12 @@ namespace MediaBrowser.Providers.MediaInfo
                 inputPath = MediaEncoderHelpers.GetInputArgument(video.Path, video.LocationType == LocationType.Remote, video.VideoType, video.IsoType, isoMount, video.PlayableStreamFileNames, out type);
             }
 
-            return await _mediaEncoder.GetMediaInfo(inputPath, type, false, cancellationToken).ConfigureAwait(false);
+            var result = await _mediaEncoder.GetMediaInfo(inputPath, type, false, cancellationToken).ConfigureAwait(false);
+
+            Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
+            _json.SerializeToFile(result, cachePath);
+
+            return result;
         }
 
         protected async Task Fetch(Video video, CancellationToken cancellationToken, InternalMediaInfoResult data, IIsoMount isoMount)

+ 122 - 0
MediaBrowser.Providers/Music/AudioDbAlbumImageProvider.cs

@@ -0,0 +1,122 @@
+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 MediaBrowser.Model.Serialization;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Providers.Music
+{
+    public class AudioDbAlbumImageProvider : IRemoteImageProvider, IHasOrder
+    {
+        private readonly IServerConfigurationManager _config;
+        private readonly IHttpClient _httpClient;
+        private readonly IJsonSerializer _json;
+
+        public AudioDbAlbumImageProvider(IServerConfigurationManager config, IHttpClient httpClient, IJsonSerializer json)
+        {
+            _config = config;
+            _httpClient = httpClient;
+            _json = json;
+        }
+
+        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 async Task<IEnumerable<RemoteImageInfo>> GetAllImages(IHasImages item, CancellationToken cancellationToken)
+        {
+            var id = item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
+
+            if (!string.IsNullOrWhiteSpace(id))
+            {
+                await AudioDbAlbumProvider.Current.EnsureInfo(id, cancellationToken).ConfigureAwait(false);
+
+                var path = AudioDbAlbumProvider.GetAlbumInfoPath(_config.ApplicationPaths, id);
+
+                var obj = _json.DeserializeFromFile<AudioDbAlbumProvider.RootObject>(path);
+
+                if (obj != null && obj.album != null && obj.album.Count > 0)
+                {
+                    return GetImages(obj.album[0]);
+                }
+            }
+
+            return new List<RemoteImageInfo>();
+        }
+
+        private IEnumerable<RemoteImageInfo> GetImages(AudioDbAlbumProvider.Album item)
+        {
+            var list = new List<RemoteImageInfo>();
+
+            if (!string.IsNullOrWhiteSpace(item.strAlbumThumb))
+            {
+                list.Add(new RemoteImageInfo
+                {
+                    ProviderName = Name,
+                    Url = item.strAlbumThumb,
+                    Type = ImageType.Primary
+                });
+            }
+
+            if (!string.IsNullOrWhiteSpace(item.strAlbumCDart))
+            {
+                list.Add(new RemoteImageInfo
+                {
+                    ProviderName = Name,
+                    Url = item.strAlbumCDart,
+                    Type = ImageType.Disc
+                });
+            }
+
+            return list;
+        }
+        
+        public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
+        {
+            return _httpClient.GetResponse(new HttpRequestOptions
+            {
+                CancellationToken = cancellationToken,
+                Url = url,
+                ResourcePool = AudioDbArtistProvider.Current.AudioDbResourcePool
+            });
+        }
+
+        public string Name
+        {
+            get { return "TheAudioDB"; }
+        }
+
+        public int Order
+        {
+            get
+            {
+                // After embedded and fanart
+                return 2;
+            }
+        }
+
+        public bool Supports(IHasImages item)
+        {
+            return item is MusicAlbum;
+        }
+    }
+}

+ 210 - 0
MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs

@@ -0,0 +1,210 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Serialization;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Providers.Music
+{
+    public class AudioDbAlbumProvider : IRemoteMetadataProvider<MusicAlbum,AlbumInfo>, IHasOrder
+    {
+        private readonly IServerConfigurationManager _config;
+        private readonly IFileSystem _fileSystem;
+        private readonly IHttpClient _httpClient;
+        private readonly IJsonSerializer _json;
+
+        public static AudioDbAlbumProvider Current;
+
+        private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+
+        public AudioDbAlbumProvider(IServerConfigurationManager config, IFileSystem fileSystem, IHttpClient httpClient, IJsonSerializer json)
+        {
+            _config = config;
+            _fileSystem = fileSystem;
+            _httpClient = httpClient;
+            _json = json;
+
+            Current = this;
+        }
+
+        public async Task<MetadataResult<MusicAlbum>> GetMetadata(AlbumInfo info, CancellationToken cancellationToken)
+        {
+            var result = new MetadataResult<MusicAlbum>();
+
+            var id = info.GetReleaseGroupId();
+
+            if (!string.IsNullOrWhiteSpace(id))
+            {
+                await EnsureInfo(id, cancellationToken).ConfigureAwait(false);
+
+                var path = GetAlbumInfoPath(_config.ApplicationPaths, id);
+
+                var obj = _json.DeserializeFromFile<RootObject>(path);
+
+                if (obj != null && obj.album != null && obj.album.Count > 0)
+                {
+                    result.Item = new MusicAlbum();
+                    result.HasMetadata = true;
+                    ProcessResult(result.Item, obj.album[0]);
+                }
+            }
+
+            return result;
+        }
+
+        private void ProcessResult(MusicAlbum item, Album result)
+        {
+            item.AlbumArtist = result.strArtist;
+
+            if (!string.IsNullOrEmpty(result.intYearReleased))
+            {
+                item.ProductionYear = int.Parse(result.intYearReleased, _usCulture);
+            }
+
+            if (!string.IsNullOrEmpty(result.strGenre))
+            {
+                item.Genres = new List<string> { result.strGenre };
+            }
+
+            item.SetProviderId(MetadataProviders.AudioDbArtist, result.idArtist);
+            item.SetProviderId(MetadataProviders.AudioDbAlbum, result.idAlbum);
+
+            item.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, result.strMusicBrainzArtistID);
+            item.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, result.strMusicBrainzID);
+        }
+        
+        public string Name
+        {
+            get { return "TheAudioDB"; }
+        }
+
+        private readonly Task _cachedTask = Task.FromResult(true);
+        internal Task EnsureInfo(string musicBrainzReleaseGroupId, CancellationToken cancellationToken)
+        {
+            var xmlPath = GetAlbumInfoPath(_config.ApplicationPaths, musicBrainzReleaseGroupId);
+
+            var fileInfo = _fileSystem.GetFileSystemInfo(xmlPath);
+
+            if (fileInfo.Exists)
+            {
+                if ((DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 7)
+                {
+                    return _cachedTask;
+                }
+            }
+
+            return DownloadInfo(musicBrainzReleaseGroupId, cancellationToken);
+        }
+
+        internal async Task DownloadInfo(string musicBrainzReleaseGroupId, CancellationToken cancellationToken)
+        {
+            cancellationToken.ThrowIfCancellationRequested();
+
+            var url = AudioDbArtistProvider.BaseUrl + "/album-mb.php?i=" + musicBrainzReleaseGroupId;
+
+            var path = GetAlbumInfoPath(_config.ApplicationPaths, musicBrainzReleaseGroupId);
+            
+            Directory.CreateDirectory(Path.GetDirectoryName(path));
+
+            using (var response = await _httpClient.Get(new HttpRequestOptions
+            {
+                Url = url,
+                ResourcePool = AudioDbArtistProvider.Current.AudioDbResourcePool,
+                CancellationToken = cancellationToken
+
+            }).ConfigureAwait(false))
+            {
+                using (var xmlFileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true))
+                {
+                    await response.CopyToAsync(xmlFileStream).ConfigureAwait(false);
+                }
+            }
+        }
+
+        private static string GetAlbumDataPath(IApplicationPaths appPaths, string musicBrainzReleaseGroupId)
+        {
+            var dataPath = Path.Combine(GetAlbumDataPath(appPaths), musicBrainzReleaseGroupId);
+
+            return dataPath;
+        }
+
+        private static string GetAlbumDataPath(IApplicationPaths appPaths)
+        {
+            var dataPath = Path.Combine(appPaths.CachePath, "audiodb-album");
+
+            return dataPath;
+        }
+
+        internal static string GetAlbumInfoPath(IApplicationPaths appPaths, string musicBrainzReleaseGroupId)
+        {
+            var dataPath = GetAlbumDataPath(appPaths, musicBrainzReleaseGroupId);
+
+            return Path.Combine(dataPath, "album.json");
+        }
+
+        public int Order
+        {
+            get
+            {
+                // After music brainz
+                return 1;
+            }
+        }
+
+        public class Album
+        {
+            public string idAlbum { get; set; }
+            public string idArtist { get; set; }
+            public string strAlbum { get; set; }
+            public string strArtist { get; set; }
+            public string intYearReleased { get; set; }
+            public string strGenre { get; set; }
+            public string strSubGenre { get; set; }
+            public string strReleaseFormat { get; set; }
+            public string intSales { get; set; }
+            public string strAlbumThumb { get; set; }
+            public string strAlbumCDart { get; set; }
+            public string strDescriptionEN { get; set; }
+            public object strDescriptionDE { get; set; }
+            public object strDescriptionFR { get; set; }
+            public object strDescriptionCN { get; set; }
+            public object strDescriptionIT { get; set; }
+            public object strDescriptionJP { get; set; }
+            public object strDescriptionRU { get; set; }
+            public object strDescriptionES { get; set; }
+            public object strDescriptionPT { get; set; }
+            public object strDescriptionSE { get; set; }
+            public object strDescriptionNL { get; set; }
+            public object strDescriptionHU { get; set; }
+            public object strDescriptionNO { get; set; }
+            public object strDescriptionIL { get; set; }
+            public object strDescriptionPL { get; set; }
+            public object intLoved { get; set; }
+            public object intScore { get; set; }
+            public string strReview { get; set; }
+            public object strMood { get; set; }
+            public object strTheme { get; set; }
+            public object strSpeed { get; set; }
+            public object strLocation { get; set; }
+            public string strMusicBrainzID { get; set; }
+            public string strMusicBrainzArtistID { get; set; }
+            public object strItunesID { get; set; }
+            public object strAmazonID { get; set; }
+            public string strLocked { get; set; }
+        }
+
+        public class RootObject
+        {
+            public List<Album> album { get; set; }
+        }
+    }
+}

+ 8 - 3
MediaBrowser.Providers/Music/AudioDbArtistProvider.cs

@@ -66,6 +66,11 @@ namespace MediaBrowser.Providers.Music
             item.HomePageUrl = result.strWebsite;
             item.Overview = result.strBiographyEN;
 
+            if (!string.IsNullOrEmpty(result.strGenre))
+            {
+                item.Genres = new List<string> { result.strGenre };
+            }
+
             item.SetProviderId(MetadataProviders.AudioDbArtist, result.idArtist);
             item.SetProviderId(MetadataProviders.MusicBrainzArtist, result.strMusicBrainzID);
         }
@@ -84,7 +89,7 @@ namespace MediaBrowser.Providers.Music
 
             if (fileInfo.Exists)
             {
-                if (_config.Configuration.EnableFanArtUpdates || (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 7)
+                if ((DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 7)
                 {
                     return _cachedTask;
                 }
@@ -136,9 +141,9 @@ namespace MediaBrowser.Providers.Music
         /// </summary>
         /// <param name="appPaths">The application paths.</param>
         /// <returns>System.String.</returns>
-        internal static string GetArtistDataPath(IApplicationPaths appPaths)
+        private static string GetArtistDataPath(IApplicationPaths appPaths)
         {
-            var dataPath = Path.Combine(appPaths.DataPath, "audiodb");
+            var dataPath = Path.Combine(appPaths.CachePath, "audiodb-artist");
 
             return dataPath;
         }

+ 5 - 2
MediaBrowser.Providers/Music/LastfmAlbumProvider.cs

@@ -175,7 +175,10 @@ namespace MediaBrowser.Providers.Music
             var musicBrainzId = item.GetProviderId(MetadataProviders.MusicBrainzAlbum) ??
                 item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
 
-            LastfmHelper.SaveImageInfo(_config.ApplicationPaths, _logger, musicBrainzId, url, imageSize);
+            if (!string.IsNullOrEmpty(musicBrainzId) && !string.IsNullOrEmpty(url))
+            {
+                LastfmHelper.SaveImageInfo(_config.ApplicationPaths, _logger, musicBrainzId, url, imageSize);
+            }
         }
 
         /// <summary>
@@ -197,7 +200,7 @@ namespace MediaBrowser.Providers.Music
         {
             get
             {
-                // After embedded provider and fanart
+                // After fanart & audiodb
                 return 2;
             }
         }

+ 4 - 1
MediaBrowser.Providers/Music/LastfmArtistProvider.cs

@@ -117,7 +117,10 @@ namespace MediaBrowser.Providers.Music
             string imageSize;
             var url = LastfmHelper.GetImageUrl(data, out imageSize);
 
-            LastfmHelper.SaveImageInfo(_config.ApplicationPaths, _logger, musicBrainzId, url, imageSize);
+            if (!string.IsNullOrEmpty(musicBrainzId) && !string.IsNullOrEmpty(url))
+            {
+                LastfmHelper.SaveImageInfo(_config.ApplicationPaths, _logger, musicBrainzId, url, imageSize);
+            }
         }
 
         /// <summary>

+ 42 - 28
MediaBrowser.Providers/Savers/XmlSaverHelpers.cs

@@ -307,7 +307,7 @@ namespace MediaBrowser.Providers.Savers
             {
                 builder.Append("<AwardSummary>" + SecurityElement.Escape(hasAwards.AwardSummary) + "</AwardSummary>");
             }
-            
+
             var hasBudget = item as IHasBudget;
             if (hasBudget != null)
             {
@@ -396,67 +396,81 @@ namespace MediaBrowser.Providers.Savers
                 }
             }
 
-            var tvcom = item.GetProviderId(MetadataProviders.Tvcom);
+            var externalId = item.GetProviderId(MetadataProviders.Tvcom);
+
+            if (!string.IsNullOrEmpty(externalId))
+            {
+                builder.Append("<TVcomId>" + SecurityElement.Escape(externalId) + "</TVcomId>");
+            }
+
+            externalId = item.GetProviderId(MetadataProviders.RottenTomatoes);
+
+            if (!string.IsNullOrEmpty(externalId))
+            {
+                builder.Append("<RottenTomatoesId>" + SecurityElement.Escape(externalId) + "</RottenTomatoesId>");
+            }
+
+            externalId = item.GetProviderId(MetadataProviders.Zap2It);
 
-            if (!string.IsNullOrEmpty(tvcom))
+            if (!string.IsNullOrEmpty(externalId))
             {
-                builder.Append("<TVcomId>" + SecurityElement.Escape(tvcom) + "</TVcomId>");
+                builder.Append("<Zap2ItId>" + SecurityElement.Escape(externalId) + "</Zap2ItId>");
             }
 
-            var rt = item.GetProviderId(MetadataProviders.RottenTomatoes);
+            externalId = item.GetProviderId(MetadataProviders.MusicBrainzAlbum);
 
-            if (!string.IsNullOrEmpty(rt))
+            if (!string.IsNullOrEmpty(externalId))
             {
-                builder.Append("<RottenTomatoesId>" + SecurityElement.Escape(rt) + "</RottenTomatoesId>");
+                builder.Append("<MusicBrainzAlbumId>" + SecurityElement.Escape(externalId) + "</MusicBrainzAlbumId>");
             }
 
-            var zap2It = item.GetProviderId(MetadataProviders.Zap2It);
+            externalId = item.GetProviderId(MetadataProviders.MusicBrainzAlbumArtist);
 
-            if (!string.IsNullOrEmpty(zap2It))
+            if (!string.IsNullOrEmpty(externalId))
             {
-                builder.Append("<Zap2ItId>" + SecurityElement.Escape(zap2It) + "</Zap2ItId>");
+                builder.Append("<MusicBrainzAlbumArtistId>" + SecurityElement.Escape(externalId) + "</MusicBrainzAlbumArtistId>");
             }
 
-            var mbz = item.GetProviderId(MetadataProviders.MusicBrainzAlbum);
+            externalId = item.GetProviderId(MetadataProviders.MusicBrainzArtist);
 
-            if (!string.IsNullOrEmpty(mbz))
+            if (!string.IsNullOrEmpty(externalId))
             {
-                builder.Append("<MusicBrainzAlbumId>" + SecurityElement.Escape(mbz) + "</MusicBrainzAlbumId>");
+                builder.Append("<MusicBrainzArtistId>" + SecurityElement.Escape(externalId) + "</MusicBrainzArtistId>");
             }
 
-            mbz = item.GetProviderId(MetadataProviders.MusicBrainzAlbumArtist);
+            externalId = item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
 
-            if (!string.IsNullOrEmpty(mbz))
+            if (!string.IsNullOrEmpty(externalId))
             {
-                builder.Append("<MusicBrainzAlbumArtistId>" + SecurityElement.Escape(mbz) + "</MusicBrainzAlbumArtistId>");
+                builder.Append("<MusicBrainzReleaseGroupId>" + SecurityElement.Escape(externalId) + "</MusicBrainzReleaseGroupId>");
             }
 
-            mbz = item.GetProviderId(MetadataProviders.MusicBrainzArtist);
+            externalId = item.GetProviderId(MetadataProviders.Gamesdb);
 
-            if (!string.IsNullOrEmpty(mbz))
+            if (!string.IsNullOrEmpty(externalId))
             {
-                builder.Append("<MusicBrainzArtistId>" + SecurityElement.Escape(mbz) + "</MusicBrainzArtistId>");
+                builder.Append("<GamesDbId>" + SecurityElement.Escape(externalId) + "</GamesDbId>");
             }
 
-            mbz = item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
+            externalId = item.GetProviderId(MetadataProviders.TmdbCollection);
 
-            if (!string.IsNullOrEmpty(mbz))
+            if (!string.IsNullOrEmpty(externalId))
             {
-                builder.Append("<MusicBrainzReleaseGroupId>" + SecurityElement.Escape(mbz) + "</MusicBrainzReleaseGroupId>");
+                builder.Append("<TMDbCollectionId>" + SecurityElement.Escape(externalId) + "</TMDbCollectionId>");
             }
 
-            var gamesdb = item.GetProviderId(MetadataProviders.Gamesdb);
+            externalId = item.GetProviderId(MetadataProviders.AudioDbArtist);
 
-            if (!string.IsNullOrEmpty(gamesdb))
+            if (!string.IsNullOrEmpty(externalId))
             {
-                builder.Append("<GamesDbId>" + SecurityElement.Escape(gamesdb) + "</GamesDbId>");
+                builder.Append("<AudioDbArtistId>" + SecurityElement.Escape(externalId) + "</AudioDbArtistId>");
             }
 
-            var tmdbCollection = item.GetProviderId(MetadataProviders.TmdbCollection);
+            externalId = item.GetProviderId(MetadataProviders.TvRage);
 
-            if (!string.IsNullOrEmpty(tmdbCollection))
+            if (!string.IsNullOrEmpty(externalId))
             {
-                builder.Append("<TMDbCollectionId>" + SecurityElement.Escape(tmdbCollection) + "</TMDbCollectionId>");
+                builder.Append("<TvRageId>" + SecurityElement.Escape(externalId) + "</TvRageId>");
             }
 
             var hasTagline = item as IHasTaglines;

+ 0 - 8
MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs

@@ -175,14 +175,6 @@ namespace MediaBrowser.Providers.TV
                 {
                     series.SetProviderId(MetadataProviders.Tvdb, ids.tvdb_id.ToString(_usCulture));
                 }
-                if (!string.IsNullOrWhiteSpace(ids.freebase_id))
-                {
-                    series.SetProviderId(MetadataProviders.Freebase, ids.freebase_id);
-                }
-                if (!string.IsNullOrWhiteSpace(ids.freebase_mid))
-                {
-                    series.SetProviderId(MetadataProviders.FreebaseMachine, ids.freebase_mid);
-                }
             }
         }
 

+ 6 - 1
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -701,7 +701,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                     }
                 }
             }
-
         }
 
         internal async Task RefreshChannels(IProgress<double> progress, CancellationToken cancellationToken)
@@ -726,6 +725,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
             foreach (var channelInfo in allChannelsList)
             {
+                cancellationToken.ThrowIfCancellationRequested();
+                
                 try
                 {
                     var item = await GetChannel(channelInfo.Item2, channelInfo.Item1, cancellationToken).ConfigureAwait(false);
@@ -758,8 +759,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
             var guideDays = GetGuideDays(list.Count);
 
+            cancellationToken.ThrowIfCancellationRequested();
+
             foreach (var item in list)
             {
+                cancellationToken.ThrowIfCancellationRequested();
+                
                 // Avoid implicitly captured closure
                 var currentChannel = item;