LastfmAlbumProvider.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. using MediaBrowser.Common.Net;
  2. using MediaBrowser.Controller.Configuration;
  3. using MediaBrowser.Controller.Entities.Audio;
  4. using MediaBrowser.Controller.Providers;
  5. using MediaBrowser.Model.Entities;
  6. using MediaBrowser.Model.Logging;
  7. using MediaBrowser.Model.Serialization;
  8. using MoreLinq;
  9. using System;
  10. using System.Collections.Generic;
  11. using System.IO;
  12. using System.Linq;
  13. using System.Net;
  14. using System.Threading;
  15. using System.Threading.Tasks;
  16. namespace MediaBrowser.Providers.Music
  17. {
  18. public class LastfmAlbumProvider : IRemoteMetadataProvider<MusicAlbum, AlbumInfo>, IHasOrder
  19. {
  20. private readonly IJsonSerializer _json;
  21. private readonly IHttpClient _httpClient;
  22. private readonly IServerConfigurationManager _config;
  23. private readonly ILogger _logger;
  24. public LastfmAlbumProvider(IHttpClient httpClient, IJsonSerializer json, IServerConfigurationManager config, ILogger logger)
  25. {
  26. _httpClient = httpClient;
  27. _json = json;
  28. _config = config;
  29. _logger = logger;
  30. }
  31. public async Task<MetadataResult<MusicAlbum>> GetMetadata(AlbumInfo id, CancellationToken cancellationToken)
  32. {
  33. var result = new MetadataResult<MusicAlbum>();
  34. var lastFmData = await GetAlbumResult(id, cancellationToken).ConfigureAwait(false);
  35. if (lastFmData != null && lastFmData.album != null)
  36. {
  37. result.HasMetadata = true;
  38. result.Item = new MusicAlbum();
  39. ProcessAlbumData(result.Item, lastFmData.album);
  40. }
  41. return result;
  42. }
  43. private async Task<LastfmGetAlbumResult> GetAlbumResult(AlbumInfo item, CancellationToken cancellationToken)
  44. {
  45. // Try album release Id
  46. var id = item.GetReleaseId();
  47. if (!string.IsNullOrEmpty(id))
  48. {
  49. var result = await GetAlbumResult(id, cancellationToken).ConfigureAwait(false);
  50. if (result != null && result.album != null)
  51. {
  52. return result;
  53. }
  54. }
  55. // Try album release group Id
  56. id = item.GetReleaseGroupId();
  57. if (!string.IsNullOrEmpty(id))
  58. {
  59. var result = await GetAlbumResult(id, cancellationToken).ConfigureAwait(false);
  60. if (result != null && result.album != null)
  61. {
  62. return result;
  63. }
  64. }
  65. var albumArtist = item.GetAlbumArtist();
  66. // Get each song, distinct by the combination of AlbumArtist and Album
  67. var songs = item.SongInfos.DistinctBy(i => (i.AlbumArtist ?? string.Empty) + (i.Album ?? string.Empty), StringComparer.OrdinalIgnoreCase).ToList();
  68. foreach (var song in songs.Where(song => !string.IsNullOrEmpty(song.Album) && !string.IsNullOrEmpty(song.AlbumArtist)))
  69. {
  70. var result = await GetAlbumResult(song.AlbumArtist, song.Album, cancellationToken).ConfigureAwait(false);
  71. if (result != null && result.album != null)
  72. {
  73. return result;
  74. }
  75. }
  76. if (string.IsNullOrEmpty(albumArtist))
  77. {
  78. return null;
  79. }
  80. return await GetAlbumResult(albumArtist, item.Name, cancellationToken);
  81. }
  82. private async Task<LastfmGetAlbumResult> GetAlbumResult(string artist, string album, CancellationToken cancellationToken)
  83. {
  84. // Get albu info using artist and album name
  85. var url = LastfmArtistProvider.RootUrl + string.Format("method=album.getInfo&artist={0}&album={1}&api_key={2}&format=json", UrlEncode(artist), UrlEncode(album), LastfmArtistProvider.ApiKey);
  86. using (var json = await _httpClient.Get(new HttpRequestOptions
  87. {
  88. Url = url,
  89. ResourcePool = LastfmArtistProvider.LastfmResourcePool,
  90. CancellationToken = cancellationToken,
  91. EnableHttpCompression = false
  92. }).ConfigureAwait(false))
  93. {
  94. using (var reader = new StreamReader(json))
  95. {
  96. var jsonText = await reader.ReadToEndAsync().ConfigureAwait(false);
  97. // Fix their bad json
  98. jsonText = jsonText.Replace("\"#text\"", "\"url\"");
  99. return _json.DeserializeFromString<LastfmGetAlbumResult>(jsonText);
  100. }
  101. }
  102. }
  103. private async Task<LastfmGetAlbumResult> GetAlbumResult(string musicbraizId, CancellationToken cancellationToken)
  104. {
  105. // Get albu info using artist and album name
  106. var url = LastfmArtistProvider.RootUrl + string.Format("method=album.getInfo&mbid={0}&api_key={1}&format=json", musicbraizId, LastfmArtistProvider.ApiKey);
  107. using (var json = await _httpClient.Get(new HttpRequestOptions
  108. {
  109. Url = url,
  110. ResourcePool = LastfmArtistProvider.LastfmResourcePool,
  111. CancellationToken = cancellationToken,
  112. EnableHttpCompression = false
  113. }).ConfigureAwait(false))
  114. {
  115. return _json.DeserializeFromStream<LastfmGetAlbumResult>(json);
  116. }
  117. }
  118. private void ProcessAlbumData(MusicAlbum item, LastfmAlbum data)
  119. {
  120. var overview = data.wiki != null ? data.wiki.content : null;
  121. if (!item.LockedFields.Contains(MetadataFields.Overview))
  122. {
  123. item.Overview = overview;
  124. }
  125. // Only grab the date here if the album doesn't already have one, since id3 tags are preferred
  126. DateTime release;
  127. if (DateTime.TryParse(data.releasedate, out release))
  128. {
  129. // Lastfm sends back null as sometimes 1901, other times 0
  130. if (release.Year > 1901)
  131. {
  132. if (!item.PremiereDate.HasValue)
  133. {
  134. item.PremiereDate = release;
  135. }
  136. if (!item.ProductionYear.HasValue)
  137. {
  138. item.ProductionYear = release.Year;
  139. }
  140. }
  141. }
  142. string imageSize;
  143. var url = LastfmHelper.GetImageUrl(data, out imageSize);
  144. var musicBrainzId = item.GetProviderId(MetadataProviders.MusicBrainzAlbum) ??
  145. item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup);
  146. if (!string.IsNullOrEmpty(musicBrainzId) && !string.IsNullOrEmpty(url))
  147. {
  148. LastfmHelper.SaveImageInfo(_config.ApplicationPaths, _logger, musicBrainzId, url, imageSize);
  149. }
  150. }
  151. /// <summary>
  152. /// Encodes an URL.
  153. /// </summary>
  154. /// <param name="name">The name.</param>
  155. /// <returns>System.String.</returns>
  156. private string UrlEncode(string name)
  157. {
  158. return WebUtility.UrlEncode(name);
  159. }
  160. public string Name
  161. {
  162. get { return "last.fm"; }
  163. }
  164. public int Order
  165. {
  166. get
  167. {
  168. // After fanart & audiodb
  169. return 2;
  170. }
  171. }
  172. }
  173. #region Result Objects
  174. public class LastfmStats
  175. {
  176. public string listeners { get; set; }
  177. public string playcount { get; set; }
  178. }
  179. public class LastfmTag
  180. {
  181. public string name { get; set; }
  182. public string url { get; set; }
  183. }
  184. public class LastfmTags
  185. {
  186. public List<LastfmTag> tag { get; set; }
  187. }
  188. public class LastfmFormationInfo
  189. {
  190. public string yearfrom { get; set; }
  191. public string yearto { get; set; }
  192. }
  193. public class LastFmBio
  194. {
  195. public string published { get; set; }
  196. public string summary { get; set; }
  197. public string content { get; set; }
  198. public string placeformed { get; set; }
  199. public string yearformed { get; set; }
  200. public List<LastfmFormationInfo> formationlist { get; set; }
  201. }
  202. public class LastFmImage
  203. {
  204. public string url { get; set; }
  205. public string size { get; set; }
  206. }
  207. public class LastfmArtist : IHasLastFmImages
  208. {
  209. public string name { get; set; }
  210. public string mbid { get; set; }
  211. public string url { get; set; }
  212. public string streamable { get; set; }
  213. public string ontour { get; set; }
  214. public LastfmStats stats { get; set; }
  215. public List<LastfmArtist> similar { get; set; }
  216. public LastfmTags tags { get; set; }
  217. public LastFmBio bio { get; set; }
  218. public List<LastFmImage> image { get; set; }
  219. }
  220. public class LastfmAlbum : IHasLastFmImages
  221. {
  222. public string name { get; set; }
  223. public string artist { get; set; }
  224. public string id { get; set; }
  225. public string mbid { get; set; }
  226. public string releasedate { get; set; }
  227. public int listeners { get; set; }
  228. public int playcount { get; set; }
  229. public LastfmTags toptags { get; set; }
  230. public LastFmBio wiki { get; set; }
  231. public List<LastFmImage> image { get; set; }
  232. }
  233. public interface IHasLastFmImages
  234. {
  235. List<LastFmImage> image { get; set; }
  236. }
  237. public class LastfmGetAlbumResult
  238. {
  239. public LastfmAlbum album { get; set; }
  240. }
  241. public class LastfmGetArtistResult
  242. {
  243. public LastfmArtist artist { get; set; }
  244. }
  245. public class Artistmatches
  246. {
  247. public List<LastfmArtist> artist { get; set; }
  248. }
  249. public class LastfmArtistSearchResult
  250. {
  251. public Artistmatches artistmatches { get; set; }
  252. }
  253. public class LastfmArtistSearchResults
  254. {
  255. public LastfmArtistSearchResult results { get; set; }
  256. }
  257. #endregion
  258. }