Browse Source

implement music identification

Luke Pulverenti 11 years ago
parent
commit
87ebe39107

+ 27 - 0
MediaBrowser.Api/ItemLookupService.cs

@@ -3,6 +3,7 @@ using MediaBrowser.Common.IO;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
@@ -67,6 +68,18 @@ namespace MediaBrowser.Api
     {
     }
 
+    [Route("/Items/RemoteSearch/MusicArtist", "POST")]
+    [Api(Description = "Gets external id infos for an item")]
+    public class GetMusicArtistRemoteSearchResults : RemoteSearchQuery<ArtistInfo>, IReturn<List<RemoteSearchResult>>
+    {
+    }
+
+    [Route("/Items/RemoteSearch/MusicAlbum", "POST")]
+    [Api(Description = "Gets external id infos for an item")]
+    public class GetMusicAlbumRemoteSearchResults : RemoteSearchQuery<AlbumInfo>, IReturn<List<RemoteSearchResult>>
+    {
+    }
+
     [Route("/Items/RemoteSearch/Person", "POST")]
     [Api(Description = "Gets external id infos for an item")]
     public class GetPersonRemoteSearchResults : RemoteSearchQuery<PersonLookupInfo>, IReturn<List<RemoteSearchResult>>
@@ -167,6 +180,20 @@ namespace MediaBrowser.Api
             return ToOptimizedResult(result);
         }
 
+        public object Post(GetMusicAlbumRemoteSearchResults request)
+        {
+            var result = _providerManager.GetRemoteSearchResults<MusicAlbum, AlbumInfo>(request, CancellationToken.None).Result;
+
+            return ToOptimizedResult(result);
+        }
+
+        public object Post(GetMusicArtistRemoteSearchResults request)
+        {
+            var result = _providerManager.GetRemoteSearchResults<MusicArtist, ArtistInfo>(request, CancellationToken.None).Result;
+
+            return ToOptimizedResult(result);
+        }
+
         public object Get(GetRemoteSearchImage request)
         {
             var result = GetRemoteImage(request).Result;

+ 3 - 0
MediaBrowser.Dlna/MediaBrowser.Dlna.csproj

@@ -96,6 +96,9 @@
       <Name>MediaBrowser.Model</Name>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Server\" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.

+ 79 - 1
MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs

@@ -7,6 +7,7 @@ using MediaBrowser.Model.Providers;
 using System;
 using System.Collections.Generic;
 using System.IO;
+using System.Linq;
 using System.Net;
 using System.Text;
 using System.Threading;
@@ -31,9 +32,86 @@ namespace MediaBrowser.Providers.Music
 
         public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(AlbumInfo searchInfo, CancellationToken cancellationToken)
         {
+            var releaseId = searchInfo.GetReleaseId();
+
+            string url = null;
+
+            if (!string.IsNullOrEmpty(releaseId))
+            {
+                url = string.Format("http://www.musicbrainz.org/ws/2/release/?query=reid:{0}", releaseId);
+            }
+            else
+            {
+                var artistMusicBrainzId = searchInfo.GetMusicBrainzArtistId();
+
+                if (!string.IsNullOrWhiteSpace(artistMusicBrainzId))
+                {
+                    url = string.Format("http://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND arid:{1}",
+                        WebUtility.UrlEncode(searchInfo.Name),
+                        artistMusicBrainzId);
+                }
+                else
+                {
+                    url = string.Format("http://www.musicbrainz.org/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"",
+                       WebUtility.UrlEncode(searchInfo.Name),
+                       WebUtility.UrlEncode(searchInfo.GetAlbumArtist()));
+                }
+            }
+
+            if (!string.IsNullOrWhiteSpace(url))
+            {
+                var doc = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false);
+
+                return GetResultsFromResponse(doc);
+            }
+
             return new List<RemoteSearchResult>();
         }
 
+        private IEnumerable<RemoteSearchResult> GetResultsFromResponse(XmlDocument doc)
+        {
+            var ns = new XmlNamespaceManager(doc.NameTable);
+            ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
+
+            var list = new List<RemoteSearchResult>();
+
+            var nodes = doc.SelectNodes("//mb:release-list/mb:release", ns);
+
+            if (nodes != null)
+            {
+                foreach (var node in nodes.Cast<XmlNode>())
+                {
+                    if (node.Attributes != null)
+                    {
+                        string name = null;
+
+                        string mbzId = node.Attributes["id"].Value;
+
+                        var nameNode = node.SelectSingleNode("//mb:title", ns);
+
+                        if (nameNode != null)
+                        {
+                            name = nameNode.InnerText;
+                        }
+
+                        if (!string.IsNullOrWhiteSpace(mbzId) && !string.IsNullOrWhiteSpace(name))
+                        {
+                            var result = new RemoteSearchResult
+                            {
+                                Name = name
+                            };
+
+                            result.SetProviderId(MetadataProviders.MusicBrainzAlbum, mbzId);
+
+                            list.Add(result);
+                        }
+                    }
+                }
+            }
+
+            return list;
+        }
+
         public async Task<MetadataResult<MusicAlbum>> GetMetadata(AlbumInfo id, CancellationToken cancellationToken)
         {
             var releaseId = id.GetReleaseId();
@@ -146,7 +224,7 @@ namespace MediaBrowser.Providers.Music
             {
                 result.ReleaseGroupId = releaseGroupIdNode.Value;
             }
-            
+
             return result;
         }
 

+ 90 - 40
MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs

@@ -19,70 +19,120 @@ namespace MediaBrowser.Providers.Music
     {
         public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancellationToken)
         {
-            return new List<RemoteSearchResult>();
-        }
-
-        public async Task<MetadataResult<MusicArtist>> GetMetadata(ArtistInfo id, CancellationToken cancellationToken)
-        {
-            var result = new MetadataResult<MusicArtist>();
-
-            var musicBrainzId = id.GetMusicBrainzArtistId() ?? await FindId(id, cancellationToken).ConfigureAwait(false);
+            var musicBrainzId = searchInfo.GetMusicBrainzArtistId();
 
             if (!string.IsNullOrWhiteSpace(musicBrainzId))
             {
-                cancellationToken.ThrowIfCancellationRequested();
+                var url = string.Format("http://www.musicbrainz.org/ws/2/artist/?query=arid:{0}", musicBrainzId);
 
-                result.Item = new MusicArtist();
-                result.HasMetadata = true;
+                var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken)
+                            .ConfigureAwait(false);
 
-                result.Item.SetProviderId(MetadataProviders.MusicBrainzArtist, musicBrainzId);
+                return GetResultsFromResponse(doc);
             }
+            else
+            {
+                // They seem to throw bad request failures on any term with a slash
+                var nameToSearch = searchInfo.Name.Replace('/', ' ');
 
-            return result;
-        }
-        
-        /// <summary>
-        /// Finds the id from music brainz.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task{System.String}.</returns>
-        private async Task<string> FindId(ItemLookupInfo item, CancellationToken cancellationToken)
-        {
-            // They seem to throw bad request failures on any term with a slash
-            var nameToSearch = item.Name.Replace('/', ' ');
+                var url = String.Format("http://www.musicbrainz.org/ws/2/artist/?query=artist:\"{0}\"", UrlEncode(nameToSearch));
+
+                var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false);
+
+                var results = GetResultsFromResponse(doc).ToList();
+
+                if (results.Count > 0)
+                {
+                    return results;
+                }
 
-            var url = String.Format("http://www.musicbrainz.org/ws/2/artist/?query=artist:\"{0}\"", UrlEncode(nameToSearch));
+                if (HasDiacritics(searchInfo.Name))
+                {
+                    // Try again using the search with accent characters url
+                    url = String.Format("http://www.musicbrainz.org/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch));
+
+                    doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false);
+
+                    return GetResultsFromResponse(doc);
+                }
+            }
 
-            var doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false);
+            return new List<RemoteSearchResult>();
+        }
 
+        private IEnumerable<RemoteSearchResult> GetResultsFromResponse(XmlDocument doc)
+        {
             var ns = new XmlNamespaceManager(doc.NameTable);
             ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
-            var node = doc.SelectSingleNode("//mb:artist-list/mb:artist/@id", ns);
 
-            if (node != null && node.Value != null)
+            var list = new List<RemoteSearchResult>();
+
+            var nodes = doc.SelectNodes("//mb:artist-list/mb:artist", ns);
+
+            if (nodes != null)
             {
-                return node.Value;
+                foreach (var node in nodes.Cast<XmlNode>())
+                {
+                    if (node.Attributes != null)
+                    {
+                        string name = null;
+
+                        string mbzId = node.Attributes["id"].Value;
+
+                        var nameNode = node.SelectSingleNode("//mb:name", ns);
+
+                        if (nameNode != null)
+                        {
+                            name = nameNode.InnerText;
+                        }
+
+                        if (!string.IsNullOrWhiteSpace(mbzId) && !string.IsNullOrWhiteSpace(name))
+                        {
+                            var result = new RemoteSearchResult
+                            {
+                                Name = name
+                            };
+
+                            result.SetProviderId(MetadataProviders.MusicBrainzArtist, mbzId);
+
+                            list.Add(result);
+                        }
+                    }
+                }
             }
 
-            if (HasDiacritics(item.Name))
+            return list;
+        }
+
+        public async Task<MetadataResult<MusicArtist>> GetMetadata(ArtistInfo id, CancellationToken cancellationToken)
+        {
+            var result = new MetadataResult<MusicArtist>
             {
-                // Try again using the search with accent characters url
-                url = String.Format("http://www.musicbrainz.org/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch));
+                Item = new MusicArtist()
+            };
 
-                doc = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false);
+            var musicBrainzId = id.GetMusicBrainzArtistId();
 
-                ns = new XmlNamespaceManager(doc.NameTable);
-                ns.AddNamespace("mb", "http://musicbrainz.org/ns/mmd-2.0#");
-                node = doc.SelectSingleNode("//mb:artist-list/mb:artist/@id", ns);
+            if (string.IsNullOrWhiteSpace(musicBrainzId))
+            {
+                var searchResults = await GetSearchResults(id, cancellationToken).ConfigureAwait(false);
+
+                var singleResult = searchResults.FirstOrDefault();
 
-                if (node != null && node.Value != null)
+                if (singleResult != null)
                 {
-                    return node.Value;
+                    musicBrainzId = singleResult.GetProviderId(MetadataProviders.MusicBrainzArtist);
+                    result.Item.Name = singleResult.Name;
                 }
             }
 
-            return null;
+            if (!string.IsNullOrWhiteSpace(musicBrainzId))
+            {
+                result.HasMetadata = true;
+                result.Item.SetProviderId(MetadataProviders.MusicBrainzArtist, musicBrainzId);
+            }
+
+            return result;
         }
 
         /// <summary>