diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs index d76c89dfb..09a0edcf0 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs @@ -25,7 +25,7 @@ namespace MediaBrowser.Providers.Music private readonly IApplicationHost _appHost; private readonly ILogger _logger; - public static string MusicBrainzBaseUrl = "http://musicbrainz.fercasas.com:5000"; + public static string MusicBrainzBaseUrl = "https://www.musicbrainz.org"; public MusicBrainzAlbumProvider(IHttpClient httpClient, IApplicationHost appHost, ILogger logger) { @@ -44,7 +44,7 @@ namespace MediaBrowser.Providers.Music if (!string.IsNullOrEmpty(releaseId)) { - url = string.Format(MusicBrainzBaseUrl + "/ws/2/release/?query=reid:{0}", releaseId); + url = string.Format("/ws/2/release/?query=reid:{0}", releaseId); } else { @@ -52,7 +52,7 @@ namespace MediaBrowser.Providers.Music if (!string.IsNullOrWhiteSpace(artistMusicBrainzId)) { - url = string.Format(MusicBrainzBaseUrl + "/ws/2/release/?query=\"{0}\" AND arid:{1}", + url = string.Format("/ws/2/release/?query=\"{0}\" AND arid:{1}", WebUtility.UrlEncode(searchInfo.Name), artistMusicBrainzId); } @@ -60,7 +60,7 @@ namespace MediaBrowser.Providers.Music { isNameSearch = true; - url = string.Format(MusicBrainzBaseUrl + "/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"", + url = string.Format("/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"", WebUtility.UrlEncode(searchInfo.Name), WebUtility.UrlEncode(searchInfo.GetAlbumArtist())); } @@ -199,57 +199,86 @@ namespace MediaBrowser.Providers.Music private async Task GetReleaseResult(string albumName, string artistId, CancellationToken cancellationToken) { - var url = string.Format(MusicBrainzBaseUrl + "/ws/2/release/?query=\"{0}\" AND arid:{1}", + var url = string.Format("/ws/2/release/?query=\"{0}\" AND arid:{1}", WebUtility.UrlEncode(albumName), artistId); var doc = await GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false); - return GetReleaseResult(doc); + return ReleaseResult.Parse(doc); } private async Task GetReleaseResultByArtistName(string albumName, string artistName, CancellationToken cancellationToken) { - var url = string.Format(MusicBrainzBaseUrl + "/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"", + var url = string.Format("/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"", WebUtility.UrlEncode(albumName), WebUtility.UrlEncode(artistName)); var doc = await GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false); - return GetReleaseResult(doc); - } - - private ReleaseResult GetReleaseResult(XmlDocument doc) - { - var ns = new XmlNamespaceManager(doc.NameTable); - ns.AddNamespace("mb", MusicBrainzBaseUrl + "/ns/mmd-2.0#"); - - var result = new ReleaseResult - { - - }; - - var releaseIdNode = doc.SelectSingleNode("//mb:release-list/mb:release/@id", ns); - - if (releaseIdNode != null) - { - result.ReleaseId = releaseIdNode.Value; - } - - var releaseGroupIdNode = doc.SelectSingleNode("//mb:release-list/mb:release/mb:release-group/@id", ns); - - if (releaseGroupIdNode != null) - { - result.ReleaseGroupId = releaseGroupIdNode.Value; - } - - return result; + return ReleaseResult.Parse(doc); } private class ReleaseResult { public string ReleaseId; public string ReleaseGroupId; + + public static ReleaseResult Parse(XmlDocument doc) + { + var docElem = doc.DocumentElement; + + if (docElem == null) + { + return new ReleaseResult(); + } + + var releaseList = docElem.FirstChild; + if (releaseList == null) + { + return new ReleaseResult(); + } + + var nodes = releaseList.ChildNodes; + string releaseId = null; + string releaseGroupId = null; + + if (nodes != null) + { + foreach (var node in nodes.Cast()) + { + if (string.Equals(node.Name, "release", StringComparison.OrdinalIgnoreCase)) + { + releaseId = node.Attributes["id"].Value; + releaseGroupId = GetReleaseGroupIdFromReleaseNode(node); + break; + } + } + } + + return new ReleaseResult + { + ReleaseId = releaseId, + ReleaseGroupId = releaseGroupId + }; + } + + private static string GetReleaseGroupIdFromReleaseNode(XmlNode node) + { + var subNodes = node.ChildNodes; + if (subNodes != null) + { + foreach (var subNode in subNodes.Cast()) + { + if (string.Equals(subNode.Name, "release-group", StringComparison.OrdinalIgnoreCase)) + { + return subNode.Attributes["id"].Value; + } + } + } + + return null; + } } /// @@ -260,7 +289,7 @@ namespace MediaBrowser.Providers.Music /// Task{System.String}. private async Task GetReleaseGroupId(string releaseEntryId, CancellationToken cancellationToken) { - var url = string.Format(MusicBrainzBaseUrl + "/ws/2/release-group/?query=reid:{0}", releaseEntryId); + var url = string.Format("/ws/2/release-group/?query=reid:{0}", releaseEntryId); var doc = await GetMusicBrainzResponse(url, false, cancellationToken).ConfigureAwait(false); @@ -276,6 +305,49 @@ namespace MediaBrowser.Providers.Music /// private readonly SemaphoreSlim _musicBrainzResourcePool = new SemaphoreSlim(1, 1); + private long _lastMbzUrlQueryTicks = 0; + private List _mbzUrls = null; + private MbzUrl _chosenUrl; + + private async Task GetMbzUrl() + { + if (_mbzUrls == null || (DateTime.UtcNow.Ticks - _lastMbzUrlQueryTicks) > TimeSpan.FromHours(12).Ticks) + { + await RefreshMzbUrls().ConfigureAwait(false); + + var urls = _mbzUrls.ToList(); + _chosenUrl = urls[new Random().Next(0, urls.Count - 1)]; + } + + return _chosenUrl; + } + + private async Task RefreshMzbUrls() + { + try + { + _mbzUrls = new List + { + new MbzUrl + { + url = MusicBrainzBaseUrl, + throttleMs = 1000 + } + }; + } + catch + { + _mbzUrls = new List + { + new MbzUrl + { + url = MusicBrainzBaseUrl, + throttleMs = 1000 + } + }; + } + } + /// /// Gets the music brainz response. /// @@ -285,9 +357,15 @@ namespace MediaBrowser.Providers.Music /// Task{XmlDocument}. internal async Task GetMusicBrainzResponse(string url, bool isSearch, CancellationToken cancellationToken) { - // MusicBrainz is extremely adamant about limiting to one request per second + var urlInfo = await GetMbzUrl().ConfigureAwait(false); - await Task.Delay(1000, cancellationToken).ConfigureAwait(false); + if (urlInfo.throttleMs > 0) + { + // MusicBrainz is extremely adamant about limiting to one request per second + await Task.Delay(urlInfo.throttleMs, cancellationToken).ConfigureAwait(false); + } + + url = urlInfo.url.TrimEnd('/') + url; var doc = new XmlDocument(); @@ -319,5 +397,11 @@ namespace MediaBrowser.Providers.Music { throw new NotImplementedException(); } + + internal class MbzUrl + { + public string url { get; set; } + public int throttleMs { get; set; } + } } } diff --git a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs index 86563b2b9..f36062ebe 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs @@ -23,7 +23,7 @@ namespace MediaBrowser.Providers.Music if (!string.IsNullOrWhiteSpace(musicBrainzId)) { - var url = string.Format(MusicBrainzAlbumProvider.MusicBrainzBaseUrl + "/ws/2/artist/?query=arid:{0}", musicBrainzId); + var url = string.Format("/ws/2/artist/?query=arid:{0}", musicBrainzId); var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, false, cancellationToken) .ConfigureAwait(false); @@ -35,7 +35,7 @@ namespace MediaBrowser.Providers.Music // They seem to throw bad request failures on any term with a slash var nameToSearch = searchInfo.Name.Replace('/', ' '); - var url = String.Format(MusicBrainzAlbumProvider.MusicBrainzBaseUrl + "/ws/2/artist/?query=artist:\"{0}\"", UrlEncode(nameToSearch)); + var url = String.Format("/ws/2/artist/?query=artist:\"{0}\"", UrlEncode(nameToSearch)); var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false); @@ -49,7 +49,7 @@ namespace MediaBrowser.Providers.Music if (HasDiacritics(searchInfo.Name)) { // Try again using the search with accent characters url - url = String.Format(MusicBrainzAlbumProvider.MusicBrainzBaseUrl + "/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch)); + url = String.Format("/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch)); doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false); @@ -62,9 +62,6 @@ namespace MediaBrowser.Providers.Music private IEnumerable GetResultsFromResponse(XmlDocument doc) { - //var ns = new XmlNamespaceManager(doc.NameTable); - //ns.AddNamespace("mb", "https://musicbrainz.org/ns/mmd-2.0#"); - var list = new List(); var docElem = doc.DocumentElement;