aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2014-03-13 23:23:58 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2014-03-13 23:23:58 -0400
commit87ebe3910782e768d6c7fc976255e49bccaf439c (patch)
tree897320dfa90e583b460aa5a87f7d49902d016cb4
parent45a1113d8ffbbc36ea450271d2974a08929352ce (diff)
implement music identification
-rw-r--r--MediaBrowser.Api/ItemLookupService.cs27
-rw-r--r--MediaBrowser.Dlna/MediaBrowser.Dlna.csproj3
-rw-r--r--MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs80
-rw-r--r--MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs130
4 files changed, 199 insertions, 41 deletions
diff --git a/MediaBrowser.Api/ItemLookupService.cs b/MediaBrowser.Api/ItemLookupService.cs
index a32a1ad03..62596287e 100644
--- a/MediaBrowser.Api/ItemLookupService.cs
+++ b/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;
diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
index 75879b3da..a7ee05cf3 100644
--- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
+++ b/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.
diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
index 43ee7bdbc..e36d8a320 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
+++ b/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;
}
diff --git a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
index 7c0233d3e..12a1bdd35 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
+++ b/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>