diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs index b1c38345e2..7a42bd52a2 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs @@ -74,36 +74,50 @@ namespace MediaBrowser.Providers.Music if (!string.IsNullOrWhiteSpace(url)) { - using (var reader = await GetMusicBrainzResponse(url, isNameSearch, cancellationToken).ConfigureAwait(false)) + using (var stream = await GetMusicBrainzResponse(url, isNameSearch, cancellationToken).ConfigureAwait(false)) { - return GetResultsFromResponse(reader); + return GetResultsFromResponse(stream); } } return new List(); } - private IEnumerable GetResultsFromResponse(XmlReader reader) + private List GetResultsFromResponse(Stream stream) { - return ReleaseResult.Parse(reader).Select(i => + using (var oReader = new StreamReader(stream, Encoding.UTF8)) { - var result = new RemoteSearchResult - { - Name = i.Title, - ProductionYear = i.Year - }; + var settings = _xmlSettings.Create(false); - if (!string.IsNullOrWhiteSpace(i.ReleaseId)) - { - result.SetProviderId(MetadataProviders.MusicBrainzAlbum, i.ReleaseId); - } - if (!string.IsNullOrWhiteSpace(i.ReleaseGroupId)) - { - result.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, i.ReleaseGroupId); - } + settings.CheckCharacters = false; + settings.IgnoreProcessingInstructions = true; + settings.IgnoreComments = true; - return result; - }); + using (var reader = XmlReader.Create(oReader, settings)) + { + var results = ReleaseResult.Parse(reader); + + return results.Select(i => + { + var result = new RemoteSearchResult + { + Name = i.Title, + ProductionYear = i.Year + }; + + if (!string.IsNullOrWhiteSpace(i.ReleaseId)) + { + result.SetProviderId(MetadataProviders.MusicBrainzAlbum, i.ReleaseId); + } + if (!string.IsNullOrWhiteSpace(i.ReleaseGroupId)) + { + result.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, i.ReleaseGroupId); + } + + return result; + }).ToList(); + } + } } public async Task> GetMetadata(AlbumInfo id, CancellationToken cancellationToken) @@ -195,9 +209,21 @@ namespace MediaBrowser.Providers.Music WebUtility.UrlEncode(albumName), artistId); - using (var reader = await GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false)) + using (var stream = await GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false)) { - return ReleaseResult.Parse(reader, 1).FirstOrDefault(); + using (var oReader = new StreamReader(stream, Encoding.UTF8)) + { + var settings = _xmlSettings.Create(false); + + settings.CheckCharacters = false; + settings.IgnoreProcessingInstructions = true; + settings.IgnoreComments = true; + + using (var reader = XmlReader.Create(oReader, settings)) + { + return ReleaseResult.Parse(reader).FirstOrDefault(); + } + } } } @@ -207,9 +233,21 @@ namespace MediaBrowser.Providers.Music WebUtility.UrlEncode(albumName), WebUtility.UrlEncode(artistName)); - using (var reader = await GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false)) + using (var stream = await GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false)) { - return ReleaseResult.Parse(reader, 1).FirstOrDefault(); + using (var oReader = new StreamReader(stream, Encoding.UTF8)) + { + var settings = _xmlSettings.Create(false); + + settings.CheckCharacters = false; + settings.IgnoreProcessingInstructions = true; + settings.IgnoreComments = true; + + using (var reader = XmlReader.Create(oReader, settings)) + { + return ReleaseResult.Parse(reader).FirstOrDefault(); + } + } } } @@ -221,31 +259,37 @@ namespace MediaBrowser.Providers.Music public string Overview; public int? Year; - public static List Parse(XmlReader reader, int? limit = null) + public static List Parse(XmlReader reader) { + var list = new List(); + reader.MoveToContent(); // Loop through each element while (reader.Read()) { - switch (reader.Name) + if (reader.NodeType == XmlNodeType.Element) { - case "release-list": - { - using (var subReader = reader.ReadSubtree()) + switch (reader.Name) + { + case "release-list": { - return ParseReleaseList(subReader); + using (var subReader = reader.ReadSubtree()) + { + list.AddRange(ParseReleaseList(subReader)); + } + break; } - } - default: - { - reader.Skip(); - break; - } + default: + { + reader.Skip(); + break; + } + } } } - return new List(); + return list; } private static List ParseReleaseList(XmlReader reader) @@ -257,24 +301,31 @@ namespace MediaBrowser.Providers.Music // Loop through each element while (reader.Read()) { - switch (reader.Name) + if (reader.NodeType == XmlNodeType.Element) { - case "release": - { - var releaseId = reader.GetAttribute("id"); - - using (var subReader = reader.ReadSubtree()) + switch (reader.Name) + { + case "release": { - var artist = ParseRelease(subReader, releaseId); - list.Add(artist); + //var releaseId = reader.GetAttribute("id"); + string releaseId = null; + + using (var subReader = reader.ReadSubtree()) + { + var release = ParseRelease(subReader, releaseId); + if (release != null) + { + list.Add(release); + } + } + break; } - break; - } - default: - { - reader.Skip(); - break; - } + default: + { + reader.Skip(); + break; + } + } } } @@ -290,41 +341,70 @@ namespace MediaBrowser.Providers.Music reader.MoveToContent(); + reader.Read(); + + // http://stackoverflow.com/questions/2299632/why-does-xmlreader-skip-every-other-element-if-there-is-no-whitespace-separator + // Loop through each element - while (reader.Read()) + while (!reader.EOF) { - switch (reader.Name) + if (reader.NodeType == XmlNodeType.Element) { - case "title": - { - result.Title = reader.ReadElementContentAsString(); - break; - } - case "date": - { - var val = reader.ReadElementContentAsString(); - DateTime date; - if (DateTime.TryParse(val, out date)) + switch (reader.Name) + { + case "title": { - result.Year = date.Year; + result.Title = reader.ReadElementContentAsString(); + break; } - break; - } - case "annotation": - { - result.Overview = reader.ReadElementContentAsString(); - break; - } - case "release-group": - { - result.ReleaseGroupId = reader.GetAttribute("id"); - break; - } - default: + case "date": + { + var val = reader.ReadElementContentAsString(); + DateTime date; + if (DateTime.TryParse(val, out date)) + { + result.Year = date.Year; + } + break; + } + case "annotation": + { + result.Overview = reader.ReadElementContentAsString(); + break; + } + case "release-group": + { + result.ReleaseGroupId = reader.GetAttribute("id"); + //explicitly consume these to avoid grabbing data from child nodes + //reader.Skip(); + using (var subtree = reader.ReadSubtree()) + { + } + break; + } + //explicitly consume these to avoid grabbing data from child nodes + //case "text-representation": + //case "artist-credit": + //case "medium-list": + //case "tag-list": + //case "label-info-list": + //case "release-event-list": + // { + // using (var subtree = reader.ReadSubtree()) + // { + // } + // break; + // } + default: { reader.Skip(); break; } + } + } + else + { + reader.Read(); } } @@ -342,30 +422,45 @@ namespace MediaBrowser.Providers.Music { var url = string.Format("/ws/2/release-group/?query=reid:{0}", releaseEntryId); - using (var reader = await GetMusicBrainzResponse(url, false, cancellationToken).ConfigureAwait(false)) + using (var stream = await GetMusicBrainzResponse(url, false, cancellationToken).ConfigureAwait(false)) { - reader.MoveToContent(); - - // Loop through each element - while (reader.Read()) + using (var oReader = new StreamReader(stream, Encoding.UTF8)) { - switch (reader.Name) + var settings = _xmlSettings.Create(false); + + settings.CheckCharacters = false; + settings.IgnoreProcessingInstructions = true; + settings.IgnoreComments = true; + + using (var reader = XmlReader.Create(oReader, settings)) { - case "release-group-list": + reader.MoveToContent(); + + // Loop through each element + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) { - using (var subReader = reader.ReadSubtree()) + switch (reader.Name) { - return GetFirstReleaseGroupId(subReader); + case "release-group-list": + { + using (var subReader = reader.ReadSubtree()) + { + return GetFirstReleaseGroupId(subReader); + } + } + default: + { + reader.Skip(); + break; + } } } - default: - { - reader.Skip(); - break; - } + } + return null; } } - return null; } } @@ -376,17 +471,20 @@ namespace MediaBrowser.Providers.Music // Loop through each element while (reader.Read()) { - switch (reader.Name) + if (reader.NodeType == XmlNodeType.Element) { - case "release-group": - { - return reader.GetAttribute("id"); - } - default: - { - reader.Skip(); - break; - } + switch (reader.Name) + { + case "release-group": + { + return reader.GetAttribute("id"); + } + default: + { + reader.Skip(); + break; + } + } } } @@ -465,7 +563,7 @@ namespace MediaBrowser.Providers.Music /// if set to true [is search]. /// The cancellation token. /// Task{XmlDocument}. - internal async Task GetMusicBrainzResponse(string url, bool isSearch, CancellationToken cancellationToken) + internal async Task GetMusicBrainzResponse(string url, bool isSearch, CancellationToken cancellationToken) { var urlInfo = await GetMbzUrl().ConfigureAwait(false); @@ -485,19 +583,7 @@ namespace MediaBrowser.Providers.Music ResourcePool = _musicBrainzResourcePool }; - using (var xml = await _httpClient.Get(options).ConfigureAwait(false)) - { - using (var oReader = new StreamReader(xml, Encoding.UTF8)) - { - var settings = _xmlSettings.Create(false); - - settings.CheckCharacters = false; - settings.IgnoreProcessingInstructions = true; - settings.IgnoreComments = true; - - return XmlReader.Create(oReader, settings); - } - } + return await _httpClient.Get(options).ConfigureAwait(false); } public int Order diff --git a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs index e0e839ef92..d670c8de18 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs @@ -6,6 +6,7 @@ using MediaBrowser.Model.Providers; using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using System.Linq; using System.Net; using System.Text; @@ -13,11 +14,19 @@ using System.Threading; using System.Threading.Tasks; using System.Xml; using MediaBrowser.Controller.Extensions; +using MediaBrowser.Model.Xml; namespace MediaBrowser.Providers.Music { public class MusicBrainzArtistProvider : IRemoteMetadataProvider { + private readonly IXmlReaderSettingsFactory _xmlSettings; + + public MusicBrainzArtistProvider(IXmlReaderSettingsFactory xmlSettings) + { + _xmlSettings = xmlSettings; + } + public async Task> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancellationToken) { var musicBrainzId = searchInfo.GetMusicBrainzArtistId(); @@ -26,10 +35,10 @@ namespace MediaBrowser.Providers.Music { var url = string.Format("/ws/2/artist/?query=arid:{0}", musicBrainzId); - using (var reader = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, false, cancellationToken) + using (var stream = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, false, cancellationToken) .ConfigureAwait(false)) { - return GetResultsFromResponse(reader); + return GetResultsFromResponse(stream); } } else @@ -39,9 +48,9 @@ namespace MediaBrowser.Providers.Music var url = String.Format("/ws/2/artist/?query=artist:\"{0}\"", UrlEncode(nameToSearch)); - using (var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false)) + using (var stream = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false)) { - var results = GetResultsFromResponse(doc).ToList(); + var results = GetResultsFromResponse(stream).ToList(); if (results.Count > 0) { @@ -54,9 +63,9 @@ namespace MediaBrowser.Providers.Music // Try again using the search with accent characters url url = String.Format("/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch)); - using (var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false)) + using (var stream = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false)) { - return GetResultsFromResponse(doc); + return GetResultsFromResponse(stream); } } } @@ -64,31 +73,46 @@ namespace MediaBrowser.Providers.Music return new List(); } - private IEnumerable GetResultsFromResponse(XmlReader reader) + private IEnumerable GetResultsFromResponse(Stream stream) { - reader.MoveToContent(); - - // Loop through each element - while (reader.Read()) + using (var oReader = new StreamReader(stream, Encoding.UTF8)) { - switch (reader.Name) + var settings = _xmlSettings.Create(false); + + settings.CheckCharacters = false; + settings.IgnoreProcessingInstructions = true; + settings.IgnoreComments = true; + + using (var reader = XmlReader.Create(oReader, settings)) { - case "artist-list": + reader.MoveToContent(); + + // Loop through each element + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) { - using (var subReader = reader.ReadSubtree()) + switch (reader.Name) { - return ParseArtistList(subReader); + case "artist-list": + { + using (var subReader = reader.ReadSubtree()) + { + return ParseArtistList(subReader); + } + } + default: + { + reader.Skip(); + break; + } } } - default: - { - reader.Skip(); - break; - } + } + + return new List(); } } - - return new List(); } private IEnumerable ParseArtistList(XmlReader reader) @@ -100,24 +124,30 @@ namespace MediaBrowser.Providers.Music // Loop through each element while (reader.Read()) { - switch (reader.Name) + if (reader.NodeType == XmlNodeType.Element) { - case "artist": - { - var mbzId = reader.GetAttribute("id"); - - using (var subReader = reader.ReadSubtree()) + switch (reader.Name) + { + case "artist": { - var artist = ParseArtist(subReader, mbzId); - list.Add(artist); + var mbzId = reader.GetAttribute("id"); + + using (var subReader = reader.ReadSubtree()) + { + var artist = ParseArtist(subReader, mbzId); + if (artist != null) + { + list.Add(artist); + } + } + break; } - break; - } - default: - { - reader.Skip(); - break; - } + default: + { + reader.Skip(); + break; + } + } } } @@ -129,35 +159,38 @@ namespace MediaBrowser.Providers.Music var result = new RemoteSearchResult(); reader.MoveToContent(); + reader.Read(); + + // http://stackoverflow.com/questions/2299632/why-does-xmlreader-skip-every-other-element-if-there-is-no-whitespace-separator // Loop through each element - while (reader.Read()) + while (!reader.EOF) { - switch (reader.Name) + if (reader.NodeType == XmlNodeType.Element) { - case "name": - { - result.Name = reader.ReadElementContentAsString(); - break; - } - //case "sort-name": - // { - // break; - // } - //case "tag-list": - // { - // break; - // } - case "annotation": - { - result.Overview = reader.ReadElementContentAsString(); - break; - } - default: - { - reader.Skip(); - break; - } + switch (reader.Name) + { + case "name": + { + result.Name = reader.ReadElementContentAsString(); + break; + } + case "annotation": + { + result.Overview = reader.ReadElementContentAsString(); + break; + } + default: + { + // there is sort-name if ever needed + reader.Skip(); + break; + } + } + } + else + { + reader.Read(); } }