From a09d5d0b6957e1981727a7e40461454a58d18c45 Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Sun, 7 May 2017 14:32:13 -0500 Subject: [PATCH] Switched over to using Spotify API for meta data. This will require deleting DB to start using. --- src/NzbDrone.Api/Music/AlbumResource.cs | 2 +- src/NzbDrone.Api/Music/ArtistModule.cs | 2 +- src/NzbDrone.Api/Music/ArtistResource.cs | 18 +- .../Cloud/SonarrCloudRequestBuilder.cs | 2 +- .../Datastore/Migration/111_setup_music.cs | 8 +- src/NzbDrone.Core/Datastore/TableMapping.cs | 2 +- .../Exceptions/ArtistNotFoundException.cs | 16 +- .../MetadataSource/IProvideArtistInfo.cs | 2 +- .../SkyHook/Resource/AlbumInfoResource.cs | 23 ++ .../SkyHook/Resource/ArtistInfoResource.cs | 20 ++ .../SkyHook/Resource/ArtistResource.cs | 61 +--- .../SkyHook/Resource/ImageResource.cs | 4 + .../MetadataSource/SkyHook/SkyHookProxy.cs | 293 ++++++------------ src/NzbDrone.Core/Music/AddArtistService.cs | 10 +- src/NzbDrone.Core/Music/Album.cs | 2 +- src/NzbDrone.Core/Music/Artist.cs | 6 +- src/NzbDrone.Core/Music/ArtistRepository.cs | 6 +- src/NzbDrone.Core/Music/ArtistService.cs | 8 +- .../Music/RefreshArtistService.cs | 12 +- .../Music/RefreshTrackService.cs | 4 +- src/NzbDrone.Core/Music/Track.cs | 8 +- src/NzbDrone.Core/Music/TrackService.cs | 28 +- src/NzbDrone.Core/NzbDrone.Core.csproj | 2 + src/NzbDrone.Core/Parser/Model/LocalTrack.cs | 4 +- .../Validation/Paths/ArtistExistsValidator.cs | 6 +- src/UI/AddSeries/SearchResultView.js | 4 +- 26 files changed, 229 insertions(+), 324 deletions(-) create mode 100644 src/NzbDrone.Core/MetadataSource/SkyHook/Resource/AlbumInfoResource.cs create mode 100644 src/NzbDrone.Core/MetadataSource/SkyHook/Resource/ArtistInfoResource.cs diff --git a/src/NzbDrone.Api/Music/AlbumResource.cs b/src/NzbDrone.Api/Music/AlbumResource.cs index a6d49d3bd..d3e243c66 100644 --- a/src/NzbDrone.Api/Music/AlbumResource.cs +++ b/src/NzbDrone.Api/Music/AlbumResource.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Api.Music { public class AlbumResource { - public int AlbumId { get; set; } + public string AlbumId { get; set; } public string AlbumName { get; set; } public bool Monitored { get; set; } public int Year { get; set; } diff --git a/src/NzbDrone.Api/Music/ArtistModule.cs b/src/NzbDrone.Api/Music/ArtistModule.cs index c598713d6..d7ef5fed3 100644 --- a/src/NzbDrone.Api/Music/ArtistModule.cs +++ b/src/NzbDrone.Api/Music/ArtistModule.cs @@ -71,7 +71,7 @@ namespace NzbDrone.Api.Music PostValidator.RuleFor(s => s.Path).IsValidPath().When(s => s.RootFolderPath.IsNullOrWhiteSpace()); PostValidator.RuleFor(s => s.RootFolderPath).IsValidPath().When(s => s.Path.IsNullOrWhiteSpace()); - PostValidator.RuleFor(s => s.ItunesId).GreaterThan(0).SetValidator(artistExistsValidator); + PostValidator.RuleFor(s => s.SpotifyId).NotEqual("").SetValidator(artistExistsValidator); PutValidator.RuleFor(s => s.Path).IsValidPath(); } diff --git a/src/NzbDrone.Api/Music/ArtistResource.cs b/src/NzbDrone.Api/Music/ArtistResource.cs index 89bc764a3..71cc14b85 100644 --- a/src/NzbDrone.Api/Music/ArtistResource.cs +++ b/src/NzbDrone.Api/Music/ArtistResource.cs @@ -19,9 +19,7 @@ namespace NzbDrone.Api.Music //View Only public string ArtistName { get; set; } - public int ItunesId { get; set; } - //public List AlternateTitles { get; set; } - //public string SortTitle { get; set; } + public string SpotifyId { get; set; } public string Overview { get; set; } public int AlbumCount @@ -30,7 +28,7 @@ namespace NzbDrone.Api.Music { if (Albums == null) return 0; - return Albums.Where(s => s.AlbumId > 0).Count(); // TODO: CHeck this condition + return Albums.Where(s => s.AlbumId != "").Count(); // TODO: CHeck this condition } } @@ -107,7 +105,7 @@ namespace NzbDrone.Api.Music //FirstAired = resource.FirstAired, //LastInfoSync = resource.LastInfoSync, //SeriesType = resource.SeriesType, - ItunesId = model.ItunesId, + SpotifyId = model.SpotifyId, ArtistSlug = model.ArtistSlug, RootFolderPath = model.RootFolderPath, @@ -151,16 +149,8 @@ namespace NzbDrone.Api.Music ArtistFolder = resource.ArtistFolder, Monitored = resource.Monitored, - - //UseSceneNumbering = resource.UseSceneNumbering, - //Runtime = resource.Runtime, - //TvdbId = resource.TvdbId, - //TvRageId = resource.TvRageId, - //TvMazeId = resource.TvMazeId, - //FirstAired = resource.FirstAired, //LastInfoSync = resource.LastInfoSync, - //SeriesType = resource.SeriesType, - ItunesId = resource.ItunesId, + SpotifyId = resource.SpotifyId, ArtistSlug = resource.ArtistSlug, RootFolderPath = resource.RootFolderPath, diff --git a/src/NzbDrone.Common/Cloud/SonarrCloudRequestBuilder.cs b/src/NzbDrone.Common/Cloud/SonarrCloudRequestBuilder.cs index fa734300a..0349dcf8f 100644 --- a/src/NzbDrone.Common/Cloud/SonarrCloudRequestBuilder.cs +++ b/src/NzbDrone.Common/Cloud/SonarrCloudRequestBuilder.cs @@ -17,7 +17,7 @@ namespace NzbDrone.Common.Cloud Services = new HttpRequestBuilder("http://services.lidarr.tv/v1/") .CreateFactory(); - Search = new HttpRequestBuilder("https://itunes.apple.com/{route}/") + Search = new HttpRequestBuilder("https://api.spotify.com/v1/{route}/") // TODO: maybe use {version} .CreateFactory(); InternalSearch = new HttpRequestBuilder("https://itunes.apple.com/WebObjects/MZStore.woa/wa/{route}") //viewArtist or search diff --git a/src/NzbDrone.Core/Datastore/Migration/111_setup_music.cs b/src/NzbDrone.Core/Datastore/Migration/111_setup_music.cs index 52067b23b..0e2da7d1b 100644 --- a/src/NzbDrone.Core/Datastore/Migration/111_setup_music.cs +++ b/src/NzbDrone.Core/Datastore/Migration/111_setup_music.cs @@ -13,7 +13,7 @@ namespace NzbDrone.Core.Datastore.Migration protected override void MainDbUpgrade() { Create.TableForModel("Artist") - .WithColumn("ItunesId").AsInt32().Unique() + .WithColumn("SpotifyId").AsString().Nullable().Unique() .WithColumn("ArtistName").AsString().Unique() .WithColumn("ArtistSlug").AsString().Nullable() //.Unique() .WithColumn("CleanTitle").AsString().Nullable() // Do we need this? @@ -37,8 +37,8 @@ namespace NzbDrone.Core.Datastore.Migration ; Create.TableForModel("Albums") - .WithColumn("AlbumId").AsInt32() - .WithColumn("ArtistId").AsInt32() + .WithColumn("AlbumId").AsString().Unique() + .WithColumn("ArtistId").AsInt32() // Should this be artistId (string) .WithColumn("Title").AsString() .WithColumn("Year").AsInt32() .WithColumn("Image").AsInt32() @@ -49,7 +49,7 @@ namespace NzbDrone.Core.Datastore.Migration Create.TableForModel("Tracks") .WithColumn("ItunesTrackId").AsInt32().Unique() - .WithColumn("AlbumId").AsInt32() + .WithColumn("AlbumId").AsString() .WithColumn("ArtistsId").AsString().Nullable() .WithColumn("TrackNumber").AsInt32() .WithColumn("Title").AsString().Nullable() diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs index 3d2594bef..09163a47c 100644 --- a/src/NzbDrone.Core/Datastore/TableMapping.cs +++ b/src/NzbDrone.Core/Datastore/TableMapping.cs @@ -102,7 +102,7 @@ namespace NzbDrone.Core.Datastore .Relationships.AutoMapICollectionOrComplexProperties() .For("Tracks") .LazyLoad(condition: parent => parent.Id > 0, - query: (db, parent) => db.Query().Where(c => c.ItunesTrackId == parent.Id).ToList()) + query: (db, parent) => db.Query().Where(c => c.SpotifyTrackId == parent.Id).ToList()) .HasOne(file => file.Artist, file => file.AlbumId); Mapper.Entity().RegisterModel("Tracks") diff --git a/src/NzbDrone.Core/Exceptions/ArtistNotFoundException.cs b/src/NzbDrone.Core/Exceptions/ArtistNotFoundException.cs index 60a05febd..58c7ea61f 100644 --- a/src/NzbDrone.Core/Exceptions/ArtistNotFoundException.cs +++ b/src/NzbDrone.Core/Exceptions/ArtistNotFoundException.cs @@ -8,24 +8,24 @@ namespace NzbDrone.Core.Exceptions { public class ArtistNotFoundException : NzbDroneException { - public int ItunesId { get; set; } + public string SpotifyId { get; set; } - public ArtistNotFoundException(int itunesId) - : base(string.Format("Series with iTunesId {0} was not found, it may have been removed from iTunes.", itunesId)) + public ArtistNotFoundException(string spotifyId) + : base(string.Format("Artist with SpotifyId {0} was not found, it may have been removed from Spotify.", spotifyId)) { - ItunesId = itunesId; + SpotifyId = spotifyId; } - public ArtistNotFoundException(int itunesId, string message, params object[] args) + public ArtistNotFoundException(string spotifyId, string message, params object[] args) : base(message, args) { - ItunesId = itunesId; + SpotifyId = spotifyId; } - public ArtistNotFoundException(int itunesId, string message) + public ArtistNotFoundException(string spotifyId, string message) : base(message) { - ItunesId = itunesId; + SpotifyId = spotifyId; } } } diff --git a/src/NzbDrone.Core/MetadataSource/IProvideArtistInfo.cs b/src/NzbDrone.Core/MetadataSource/IProvideArtistInfo.cs index 4ae5a3420..76810655a 100644 --- a/src/NzbDrone.Core/MetadataSource/IProvideArtistInfo.cs +++ b/src/NzbDrone.Core/MetadataSource/IProvideArtistInfo.cs @@ -6,6 +6,6 @@ namespace NzbDrone.Core.MetadataSource.SkyHook { public interface IProvideArtistInfo { - Tuple> GetArtistInfo(int itunesId); + Tuple> GetArtistInfo(string spotifyId); } } diff --git a/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/AlbumInfoResource.cs b/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/AlbumInfoResource.cs new file mode 100644 index 000000000..d442be7ec --- /dev/null +++ b/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/AlbumInfoResource.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NzbDrone.Core.MetadataSource.SkyHook.Resource +{ + public class AlbumInfoResource + { + public AlbumInfoResource() + { + + } + public string AlbumType { get; set; } // Might need to make this a separate class + public List Artists { get; set; } // Will always be length of 1 unless a compilation + public string Url { get; set; } // Link to the endpoint api to give full info for this object + public string Id { get; set; } // This is a unique Album ID. Needed for all future API calls + public List Images { get; set; } + public string Name { get; set; } // In case of a takedown, this may be empty + } + + +} diff --git a/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/ArtistInfoResource.cs b/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/ArtistInfoResource.cs new file mode 100644 index 000000000..35f969001 --- /dev/null +++ b/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/ArtistInfoResource.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NzbDrone.Core.MetadataSource.SkyHook.Resource +{ + public class ArtistInfoResource + { + public ArtistInfoResource() { } + + public List Genres { get; set; } + public string AristUrl { get; set; } + public string Id { get; set; } + public List Images { get; set; } + public string Name { get; set; } + + // We may need external_urls.spotify to external linking... + } +} diff --git a/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/ArtistResource.cs b/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/ArtistResource.cs index 5113d5394..2dd663383 100644 --- a/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/ArtistResource.cs +++ b/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/ArtistResource.cs @@ -5,61 +5,25 @@ using System.Text; namespace NzbDrone.Core.MetadataSource.SkyHook.Resource { - public class StorePlatformDataResource - { - public StorePlatformDataResource() { } - public ArtistInfoResource Artist { get; set; } - //public Lockup lockup { get; set; } - } - public class ArtistInfoResource + public class AristResultResource { - public ArtistInfoResource() { } - public Dictionary Results { get; set; } - - public bool HasArtistBio { get; set; } + public AristResultResource() + { - public string url { get; set; } - public string shortUrl { get; set; } - - public List artistContemporaries { get; set; } - public List genreNames { get; set; } - public bool hasSocialPosts { get; set; } - public string artistBio { get; set; } - public bool isGroup { get; set; } - public string id { get; set; } - public string bornOrFormed { get; set; } - public string name { get; set; } - public string latestAlbumContentId { get; set; } - public string nameRaw { get; set; } + } - //public string kind { get; set; } - //public List gallery { get; set; } - //public List genres { get; set; } - public List artistInfluencers { get; set; } - public List artistFollowers { get; set; } - //public string umcArtistImageUrl { get; set; } + public List Items { get; set; } } - public class AlbumResource - { - public AlbumResource() + public class AlbumResultResource + { + public AlbumResultResource() { } - public string ArtistName { get; set; } - public int ArtistId { get; set; } - public string CollectionName { get; set; } - public int CollectionId { get; set; } - public string PrimaryGenreName { get; set; } - public string ArtworkUrl100 { get; set; } - public string Country { get; set; } - public string CollectionExplicitness { get; set; } - public int TrackCount { get; set; } - public string Copyright { get; set; } - public DateTime ReleaseDate { get; set; } - + public List Items { get; set; } } public class ArtistResource @@ -69,10 +33,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook.Resource } - public int ResultCount { get; set; } - public List Results { get; set; } - //public string ArtistName { get; set; } - //public List Albums { get; set; } - public StorePlatformDataResource StorePlatformData { get; set; } + public AristResultResource Artists { get; set; } + public AristResultResource Albums { get; set; } } } diff --git a/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/ImageResource.cs b/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/ImageResource.cs index 81a2f578e..518705757 100644 --- a/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/ImageResource.cs +++ b/src/NzbDrone.Core/MetadataSource/SkyHook/Resource/ImageResource.cs @@ -3,6 +3,10 @@ namespace NzbDrone.Core.MetadataSource.SkyHook.Resource public class ImageResource { public string CoverType { get; set; } + + // Spotify Mapping public string Url { get; set; } + public int Height { get; set; } + public int Width { get; set; } } } \ No newline at end of file diff --git a/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs b/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs index a35e33835..0bb74c548 100644 --- a/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs +++ b/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs @@ -22,13 +22,11 @@ namespace NzbDrone.Core.MetadataSource.SkyHook private readonly Logger _logger; private readonly IHttpRequestBuilderFactory _requestBuilder; - private readonly IHttpRequestBuilderFactory _internalRequestBuilder; public SkyHookProxy(IHttpClient httpClient, ILidarrCloudRequestBuilder requestBuilder, Logger logger) { _httpClient = httpClient; _requestBuilder = requestBuilder.Search; - _internalRequestBuilder = requestBuilder.InternalSearch; _logger = logger; } @@ -67,153 +65,97 @@ namespace NzbDrone.Core.MetadataSource.SkyHook public List SearchForNewSeries(string title) { - try - { - var lowerTitle = title.ToLowerInvariant(); - Console.WriteLine("Searching for " + lowerTitle); - - //if (lowerTitle.StartsWith("tvdb:") || lowerTitle.StartsWith("tvdbid:")) - //{ - // var slug = lowerTitle.Split(':')[1].Trim(); - - // int tvdbId; - - // if (slug.IsNullOrWhiteSpace() || slug.Any(char.IsWhiteSpace) || !int.TryParse(slug, out tvdbId) || tvdbId <= 0) - // { - // return new List(); - // } - - // try - // { - // return new List { GetSeriesInfo(tvdbId).Item1 }; - // } - // catch (SeriesNotFoundException) - // { - // return new List(); - // } - //} - - // Majora: Temporarily, use iTunes to test. - var httpRequest = _requestBuilder.Create() - .AddQueryParam("entity", "album") - .AddQueryParam("term", title.ToLower().Trim()) - .Build(); - - - - Console.WriteLine("httpRequest: ", httpRequest); + // TODO: Remove this API + var tempList = new List(); + var tempSeries = new Series(); + tempSeries.Title = "AFI"; + tempList.Add(tempSeries); + return tempList; + } - var httpResponse = _httpClient.Get>(httpRequest); - //Console.WriteLine("Response: ", httpResponse.GetType()); - //_logger.Info("Response: ", httpResponse.Resource.ResultCount); + public Tuple> GetArtistInfo(string spotifyId) + { - //_logger.Info("HTTP Response: ", httpResponse.Resource.ResultCount); - var tempList = new List(); - var tempSeries = new Series(); - tempSeries.Title = "AFI"; - tempList.Add(tempSeries); - return tempList; - - return httpResponse.Resource.SelectList(MapSeries); - } - catch (HttpException) - { - throw new SkyHookException("Search for '{0}' failed. Unable to communicate with SkyHook.", title); - } - catch (Exception ex) - { - _logger.Warn(ex, ex.Message); - throw new SkyHookException("Search for '{0}' failed. Invalid response received from SkyHook.", title); - } - } + _logger.Debug("Getting Artist with SpotifyId of {0}", spotifyId); - //public Artist GetArtistInfo(int itunesId) - //{ - // Console.WriteLine("[GetArtistInfo] id:" + itunesId); - // //https://itunes.apple.com/lookup?id=909253 - // //var httpRequest = _requestBuilder.Create() - // // .SetSegment("route", "lookup") - // // .AddQueryParam("id", itunesId.ToString()) - // // .Build(); - - // // TODO: Add special header, add Overview to Artist model - // var httpRequest = _requestBuilder.Create() - // .SetSegment("route", "viewArtist") - // .AddQueryParam("id", itunesId.ToString()) - // .Build(); - // httpRequest.Headers.Add("X-Apple-Store-Front", "143459-2,32 t:music3"); - - // httpRequest.AllowAutoRedirect = true; - // httpRequest.SuppressHttpError = true; - - // var httpResponse = _httpClient.Get(httpRequest); - - // if (httpResponse.HasHttpError) - // { - // if (httpResponse.StatusCode == HttpStatusCode.NotFound) - // { - // throw new ArtistNotFoundException(itunesId); - // } - // else - // { - // throw new HttpException(httpRequest, httpResponse); - // } - // } - - // Console.WriteLine("GetArtistInfo, GetArtistInfo"); - // return MapArtists(httpResponse.Resource)[0]; - //} + ///v1/albums/{id} + // - public Tuple> GetArtistInfo(int itunesId) - { - // TODO: [GetArtistInfo]: This needs to return a set of tracks from iTunes. - // This call is expected to return information about an artist and the tracks that make up said artist. - // To do this, we need 2-3 API calls. 1st is to gather information about the artist and the albums the artist has. This is https://itunes.apple.com/search?entity=album&id=itunesId - // Next call is to populate the overview field and calls the internal API - // Finally, we need to, for each album, get all tracks, which means calling this N times: https://itunes.apple.com/search?entity=musicTrack&term=artistName (id will not work) - _logger.Debug("Getting Artist with iTunesID of {0}", itunesId); - var httpRequest1 = _requestBuilder.Create() - .SetSegment("route", "lookup") - .AddQueryParam("id", itunesId.ToString()) + // We need to perform a direct lookup of the artist + var httpRequest = _requestBuilder.Create() + .SetSegment("route", "artists/" + spotifyId) + //.SetSegment("route", "search") + //.AddQueryParam("type", "artist,album") + //.AddQueryParam("q", spotifyId.ToString()) .Build(); - var httpRequest2 = _internalRequestBuilder.Create() - .SetSegment("route", "viewArtist") - .AddQueryParam("id", itunesId.ToString()) - .Build(); - httpRequest2.Headers.Add("X-Apple-Store-Front", "143459-2,32 t:music3"); - httpRequest2.Headers.ContentType = "application/json"; + - httpRequest1.AllowAutoRedirect = true; - httpRequest1.SuppressHttpError = true; + httpRequest.AllowAutoRedirect = true; + httpRequest.SuppressHttpError = true; - var httpResponse = _httpClient.Get(httpRequest1); + var httpResponse = _httpClient.Get(httpRequest); if (httpResponse.HasHttpError) { if (httpResponse.StatusCode == HttpStatusCode.NotFound) { - throw new ArtistNotFoundException(itunesId); + throw new ArtistNotFoundException(spotifyId); } else { - throw new HttpException(httpRequest1, httpResponse); + throw new HttpException(httpRequest, httpResponse); } } - List artists = MapArtists(httpResponse.Resource); - List newArtists = new List(artists.Count); - int count = 0; - foreach (var artist in artists) + Artist artist = new Artist(); + artist.ArtistName = httpResponse.Resource.Name; + artist.SpotifyId = httpResponse.Resource.Id; + artist.Genres = httpResponse.Resource.Genres; + //Artist artist = MapArtists(httpResponse.Resource)[0]; + + + artist = MapAlbums(artist); + + + // TODO: implement tracks api call + return new Tuple>(artist, new List()); + } + + private Artist MapAlbums(Artist artist) + { + + // Find all albums for the artist and all tracks for said album + ///v1/artists/{id}/albums + var httpRequest = _requestBuilder.Create() + .SetSegment("route", "artists/" + artist.SpotifyId + "/albums") + .Build(); + httpRequest.AllowAutoRedirect = true; + httpRequest.SuppressHttpError = true; + + var httpResponse = _httpClient.Get(httpRequest); + + if (httpResponse.HasHttpError) + { + throw new HttpException(httpRequest, httpResponse); + } + + List albums = new List(); + foreach(var albumResource in httpResponse.Resource.Items) { - newArtists.Add(AddOverview(artist)); - count++; + Album album = new Album(); + album.AlbumId = albumResource.Id; + album.Title = albumResource.Name; + album.ArtworkUrl = albumResource.Images[0].Url; + albums.Add(album); } - // I don't know how we are getting tracks from iTunes yet. - return new Tuple>(newArtists[0], new List()); + // TODO: We now need to get all tracks for each album + + artist.Albums = albums; + return artist; } public List SearchForNewArtist(string title) @@ -227,16 +169,14 @@ namespace NzbDrone.Core.MetadataSource.SkyHook { var slug = lowerTitle.Split(':')[1].Trim(); - int itunesId; - - if (slug.IsNullOrWhiteSpace() || slug.Any(char.IsWhiteSpace) || !int.TryParse(slug, out itunesId) || itunesId <= 0) + if (slug.IsNullOrWhiteSpace() || slug.Any(char.IsWhiteSpace)) { return new List(); } try { - return new List { GetArtistInfo(itunesId).Item1 }; + return new List { GetArtistInfo(slug).Item1 }; } catch (ArtistNotFoundException) { @@ -246,8 +186,8 @@ namespace NzbDrone.Core.MetadataSource.SkyHook var httpRequest = _requestBuilder.Create() .SetSegment("route", "search") - .AddQueryParam("entity", "album") - .AddQueryParam("term", title.ToLower().Trim()) + .AddQueryParam("type", "artist,album") + .AddQueryParam("q", title.ToLower().Trim()) .Build(); @@ -256,16 +196,8 @@ namespace NzbDrone.Core.MetadataSource.SkyHook List artists = MapArtists(httpResponse.Resource); - List newArtists = new List(artists.Count); - int count = 0; - foreach (var artist in artists) - { - newArtists.Add(AddOverview(artist)); - count++; - } - - return newArtists; + return artists; } catch (HttpException) { @@ -278,77 +210,52 @@ namespace NzbDrone.Core.MetadataSource.SkyHook } } - private Artist AddOverview(Artist artist) - { - var httpRequest = _internalRequestBuilder.Create() - .SetSegment("route", "viewArtist") - .AddQueryParam("id", artist.ItunesId.ToString()) - .Build(); - httpRequest.Headers.Add("X-Apple-Store-Front", "143459-2,32 t:music3"); - httpRequest.Headers.ContentType = "application/json"; - var httpResponse = _httpClient.Get(httpRequest); - - if (!httpResponse.HasHttpError) - { - artist.Overview = httpResponse.Resource.StorePlatformData.Artist.Results[artist.ItunesId].artistBio; - } - - return artist; - } - private Artist MapArtistInfo(ArtistInfoResource resource) { // This expects ArtistInfoResource, thus just need to populate one artist Artist artist = new Artist(); - artist.Overview = resource.artistBio; - artist.ArtistName = resource.name; - foreach(var genre in resource.genreNames) - { - artist.Genres.Add(genre); - } + //artist.Overview = resource.artistBio; + //artist.ArtistName = resource.name; + //foreach(var genre in resource.genreNames) + //{ + // artist.Genres.Add(genre); + //} return artist; } private List MapArtists(ArtistResource resource) { - Album tempAlbum; + + List artists = new List(); - foreach (var album in resource.Results) + foreach(var artistResource in resource.Artists.Items) { - int index = artists.FindIndex(a => a.ItunesId == album.ArtistId); - tempAlbum = MapAlbum(album); + Artist artist = new Artist(); + artist.ArtistName = artistResource.Name; + artist.SpotifyId = artistResource.Id; + artist.Genres = artistResource.Genres; + //artist.ArtistSlug = a//TODO implement artistSlug mapping; + artists.Add(artist); + } - if (index >= 0) - { - artists[index].Albums.Add(tempAlbum); - } - else - { - Artist tempArtist = new Artist(); - tempArtist.ItunesId = album.ArtistId; - tempArtist.ArtistName = album.ArtistName; - tempArtist.Genres.Add(album.PrimaryGenreName); - tempArtist.Albums.Add(tempAlbum); - artists.Add(tempArtist); - } + // Maybe? Get all the albums for said artist - } return artists; } - private Album MapAlbum(AlbumResource albumQuery) - { - Album album = new Album(); - - album.AlbumId = albumQuery.CollectionId; - album.Title = albumQuery.CollectionName; - album.Year = albumQuery.ReleaseDate.Year; - album.ArtworkUrl = albumQuery.ArtworkUrl100; - album.Explicitness = albumQuery.CollectionExplicitness; - return album; - } + //private Album MapAlbum(AlbumResource albumQuery) + //{ + // Album album = new Album(); + + // album.AlbumId = albumQuery.CollectionId; + // album.Title = albumQuery.CollectionName; + // album.Year = albumQuery.ReleaseDate.Year; + // album.ArtworkUrl = albumQuery.ArtworkUrl100; + // album.Explicitness = albumQuery.CollectionExplicitness; + // return album; + //} private static Series MapSeries(ShowResource show) { diff --git a/src/NzbDrone.Core/Music/AddArtistService.cs b/src/NzbDrone.Core/Music/AddArtistService.cs index 3ca636d0b..07f995f69 100644 --- a/src/NzbDrone.Core/Music/AddArtistService.cs +++ b/src/NzbDrone.Core/Music/AddArtistService.cs @@ -48,7 +48,7 @@ namespace NzbDrone.Core.Music if (string.IsNullOrWhiteSpace(newArtist.Path)) { - var folderName = newArtist.ArtistName;// _fileNameBuilder.GetArtistFolder(newArtist); + var folderName = newArtist.ArtistName;// TODO: _fileNameBuilder.GetArtistFolder(newArtist); newArtist.Path = Path.Combine(newArtist.RootFolderPath, folderName); } @@ -63,7 +63,7 @@ namespace NzbDrone.Core.Music throw new ValidationException(validationResult.Errors); } - _logger.Info("Adding Series {0} Path: [{1}]", newArtist, newArtist.Path); + _logger.Info("Adding Artist {0} Path: [{1}]", newArtist, newArtist.Path); _artistService.AddArtist(newArtist); return newArtist; @@ -75,15 +75,15 @@ namespace NzbDrone.Core.Music try { - tuple = _artistInfo.GetArtistInfo(newArtist.ItunesId); + tuple = _artistInfo.GetArtistInfo(newArtist.SpotifyId); } catch (SeriesNotFoundException) { - _logger.Error("iTunesId {1} was not found, it may have been removed from iTunes.", newArtist.ItunesId); + _logger.Error("SpotifyId {1} was not found, it may have been removed from Spotify.", newArtist.SpotifyId); throw new ValidationException(new List { - new ValidationFailure("iTunesId", "An artist with this ID was not found", newArtist.ItunesId) + new ValidationFailure("SpotifyId", "An artist with this ID was not found", newArtist.SpotifyId) }); } diff --git a/src/NzbDrone.Core/Music/Album.cs b/src/NzbDrone.Core/Music/Album.cs index c0c7fc19e..43aaecb14 100644 --- a/src/NzbDrone.Core/Music/Album.cs +++ b/src/NzbDrone.Core/Music/Album.cs @@ -14,7 +14,7 @@ namespace NzbDrone.Core.Music Images = new List(); } - public int AlbumId { get; set; } + public string AlbumId { get; set; } public string Title { get; set; } // NOTE: This should be CollectionName in API public int Year { get; set; } public int TrackCount { get; set; } diff --git a/src/NzbDrone.Core/Music/Artist.cs b/src/NzbDrone.Core/Music/Artist.cs index ef89b2998..000aaf928 100644 --- a/src/NzbDrone.Core/Music/Artist.cs +++ b/src/NzbDrone.Core/Music/Artist.cs @@ -22,7 +22,7 @@ namespace NzbDrone.Core.Music } - public int ItunesId { get; set; } + public string SpotifyId { get; set; } public string ArtistName { get; set; } public string ArtistSlug { get; set; } public string CleanTitle { get; set; } @@ -47,13 +47,13 @@ namespace NzbDrone.Core.Music public override string ToString() { - return string.Format("[{0}][{1}]", ItunesId, ArtistName.NullSafe()); + return string.Format("[{0}][{1}]", SpotifyId, ArtistName.NullSafe()); } public void ApplyChanges(Artist otherArtist) { - ItunesId = otherArtist.ItunesId; + SpotifyId = otherArtist.SpotifyId; ArtistName = otherArtist.ArtistName; ArtistSlug = otherArtist.ArtistSlug; CleanTitle = otherArtist.CleanTitle; diff --git a/src/NzbDrone.Core/Music/ArtistRepository.cs b/src/NzbDrone.Core/Music/ArtistRepository.cs index f9e7f9da4..0da04ad0d 100644 --- a/src/NzbDrone.Core/Music/ArtistRepository.cs +++ b/src/NzbDrone.Core/Music/ArtistRepository.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Core.Music { bool ArtistPathExists(string path); Artist FindByName(string cleanTitle); - Artist FindByItunesId(int iTunesId); + Artist FindById(string spotifyId); } public class ArtistRepository : BasicRepository, IArtistRepository @@ -24,9 +24,9 @@ namespace NzbDrone.Core.Music return Query.Where(c => c.Path == path).Any(); } - public Artist FindByItunesId(int iTunesId) + public Artist FindById(string spotifyId) { - return Query.Where(s => s.ItunesId == iTunesId).SingleOrDefault(); + return Query.Where(s => s.SpotifyId == spotifyId).SingleOrDefault(); } public Artist FindByName(string cleanName) diff --git a/src/NzbDrone.Core/Music/ArtistService.cs b/src/NzbDrone.Core/Music/ArtistService.cs index 1397fad5d..bedf41f74 100644 --- a/src/NzbDrone.Core/Music/ArtistService.cs +++ b/src/NzbDrone.Core/Music/ArtistService.cs @@ -17,7 +17,7 @@ namespace NzbDrone.Core.Music Artist GetArtist(int artistId); List GetArtists(IEnumerable artistIds); Artist AddArtist(Artist newArtist); - Artist FindByItunesId(int itunesId); + Artist FindById(string spotifyId); Artist FindByName(string title); Artist FindByTitleInexact(string title); void DeleteArtist(int artistId, bool deleteFiles); @@ -69,9 +69,9 @@ namespace NzbDrone.Core.Music _eventAggregator.PublishEvent(new ArtistDeletedEvent(artist, deleteFiles)); } - public Artist FindByItunesId(int itunesId) + public Artist FindById(string spotifyId) { - return _artistRepository.FindByItunesId(itunesId); + return _artistRepository.FindById(spotifyId); } public Artist FindByName(string title) @@ -114,7 +114,7 @@ namespace NzbDrone.Core.Music if (storedAlbum != null && album.Monitored != storedAlbum.Monitored) { - _trackService.SetTrackMonitoredByAlbum(artist.Id, album.AlbumId, album.Monitored); + _trackService.SetTrackMonitoredByAlbum(artist.SpotifyId, album.AlbumId, album.Monitored); } } diff --git a/src/NzbDrone.Core/Music/RefreshArtistService.cs b/src/NzbDrone.Core/Music/RefreshArtistService.cs index 401753ef8..af0717437 100644 --- a/src/NzbDrone.Core/Music/RefreshArtistService.cs +++ b/src/NzbDrone.Core/Music/RefreshArtistService.cs @@ -52,20 +52,20 @@ namespace NzbDrone.Core.Music try { - tuple = _artistInfo.GetArtistInfo(artist.ItunesId); + tuple = _artistInfo.GetArtistInfo(artist.SpotifyId); } catch (ArtistNotFoundException) { - _logger.Error("Artist '{0}' (itunesid {1}) was not found, it may have been removed from iTunes.", artist.ArtistName, artist.ItunesId); + _logger.Error("Artist '{0}' (SpotifyId {1}) was not found, it may have been removed from Spotify.", artist.ArtistName, artist.SpotifyId); return; } var artistInfo = tuple.Item1; - if (artist.ItunesId != artistInfo.ItunesId) + if (artist.SpotifyId != artistInfo.SpotifyId) { - _logger.Warn("Artist '{0}' (itunes {1}) was replaced with '{2}' (itunes {3}), because the original was a duplicate.", artist.ArtistName, artist.ItunesId, artistInfo.ArtistName, artistInfo.ItunesId); - artist.ItunesId = artistInfo.ItunesId; + _logger.Warn("Artist '{0}' (SpotifyId {1}) was replaced with '{2}' (SpotifyId {3}), because the original was a duplicate.", artist.ArtistName, artist.SpotifyId, artistInfo.ArtistName, artistInfo.SpotifyId); + artist.SpotifyId = artistInfo.SpotifyId; } artist.ArtistName = artistInfo.ArtistName; @@ -114,7 +114,7 @@ namespace NzbDrone.Core.Music // continue; //} - _logger.Debug("New album ({0}) for artist: [{1}] {2}, setting monitored to true", album.Title, artist.ItunesId, artist.ArtistName); + _logger.Debug("New album ({0}) for artist: [{1}] {2}, setting monitored to true", album.Title, artist.SpotifyId, artist.ArtistName); album.Monitored = true; } diff --git a/src/NzbDrone.Core/Music/RefreshTrackService.cs b/src/NzbDrone.Core/Music/RefreshTrackService.cs index 76499545b..bee0e8a5d 100644 --- a/src/NzbDrone.Core/Music/RefreshTrackService.cs +++ b/src/NzbDrone.Core/Music/RefreshTrackService.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Music var successCount = 0; var failCount = 0; - var existingTracks = _trackService.GetTrackByArtist(artist.ItunesId); + var existingTracks = _trackService.GetTrackByArtist(artist.SpotifyId); var albums = artist.Albums; var updateList = new List(); @@ -57,7 +57,7 @@ namespace NzbDrone.Core.Music trackToUpdate.Monitored = GetMonitoredStatus(track, albums); newList.Add(trackToUpdate); } - trackToUpdate.ArtistId = artist.ItunesId; // TODO: Ensure LazyLoaded field gets updated. + trackToUpdate.ArtistId = artist.SpotifyId; // TODO: Ensure LazyLoaded field gets updated. trackToUpdate.TrackNumber = track.TrackNumber; trackToUpdate.Title = track.Title ?? "Unknown"; diff --git a/src/NzbDrone.Core/Music/Track.cs b/src/NzbDrone.Core/Music/Track.cs index fb437193b..f1f563306 100644 --- a/src/NzbDrone.Core/Music/Track.cs +++ b/src/NzbDrone.Core/Music/Track.cs @@ -17,10 +17,10 @@ namespace NzbDrone.Core.Music public const string RELEASE_DATE_FORMAT = "yyyy-MM-dd"; - public int ItunesTrackId { get; set; } - public int AlbumId { get; set; } + public int SpotifyTrackId { get; set; } + public string AlbumId { get; set; } public LazyLoaded Artist { get; set; } - public int ArtistId { get; set; } + public string ArtistId { get; set; } public int CompilationId { get; set; } public bool Compilation { get; set; } public int TrackNumber { get; set; } @@ -46,7 +46,7 @@ namespace NzbDrone.Core.Music public override string ToString() { - return string.Format("[{0}]{1}", ItunesTrackId, Title.NullSafe()); + return string.Format("[{0}]{1}", SpotifyTrackId, Title.NullSafe()); } } } diff --git a/src/NzbDrone.Core/Music/TrackService.cs b/src/NzbDrone.Core/Music/TrackService.cs index 91bdeb5f7..b8bbbafa7 100644 --- a/src/NzbDrone.Core/Music/TrackService.cs +++ b/src/NzbDrone.Core/Music/TrackService.cs @@ -10,12 +10,12 @@ namespace NzbDrone.Core.Music { Track GetTrack(int id); List GetTracks(IEnumerable ids); - Track FindTrack(int artistId, int albumId, int trackNumber); - Track FindTrackByTitle(int artistId, int albumId, string releaseTitle); - List GetTrackByArtist(int artistId); - List GetTracksByAblum(int artistId, int albumId); - List GetTracksByAblumTitle(int artistId, string albumTitle); - List TracksWithFiles(int artistId); + Track FindTrack(string artistId, string albumId, int trackNumber); + Track FindTrackByTitle(string artistId, string albumId, string releaseTitle); + List GetTrackByArtist(string artistId); + List GetTracksByAlbum(string artistId, string albumId); + List GetTracksByAlbumTitle(string artistId, string albumTitle); + List TracksWithFiles(string artistId); PagingSpec TracksWithoutFiles(PagingSpec pagingSpec); List GeTracksByFileId(int trackFileId); void UpdateTrack(Track track); @@ -24,7 +24,7 @@ namespace NzbDrone.Core.Music void InsertMany(List tracks); void UpdateMany(List tracks); void DeleteMany(List tracks); - void SetTrackMonitoredByAlbum(int artistId, int albumId, bool monitored); + void SetTrackMonitoredByAlbum(string artistId, string albumId, bool monitored); } public class TrackService : ITrackService @@ -34,12 +34,12 @@ namespace NzbDrone.Core.Music throw new NotImplementedException(); } - public Track FindTrack(int artistId, int albumId, int trackNumber) + public Track FindTrack(string artistId, string albumId, int trackNumber) { throw new NotImplementedException(); } - public Track FindTrackByTitle(int artistId, int albumId, string releaseTitle) + public Track FindTrackByTitle(string artistId, string albumId, string releaseTitle) { throw new NotImplementedException(); } @@ -54,7 +54,7 @@ namespace NzbDrone.Core.Music throw new NotImplementedException(); } - public List GetTrackByArtist(int artistId) + public List GetTrackByArtist(string artistId) { throw new NotImplementedException(); } @@ -64,12 +64,12 @@ namespace NzbDrone.Core.Music throw new NotImplementedException(); } - public List GetTracksByAblum(int artistId, int albumId) + public List GetTracksByAlbum(string artistId, string albumId) { throw new NotImplementedException(); } - public List GetTracksByAblumTitle(int artistId, string albumTitle) + public List GetTracksByAlbumTitle(string artistId, string albumTitle) { throw new NotImplementedException(); } @@ -84,12 +84,12 @@ namespace NzbDrone.Core.Music throw new NotImplementedException(); } - public void SetTrackMonitoredByAlbum(int artistId, int albumId, bool monitored) + public void SetTrackMonitoredByAlbum(string artistId, string albumId, bool monitored) { throw new NotImplementedException(); } - public List TracksWithFiles(int artistId) + public List TracksWithFiles(string artistId) { throw new NotImplementedException(); } diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 5dcadb8e0..7f5a97c01 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -815,6 +815,8 @@ + + diff --git a/src/NzbDrone.Core/Parser/Model/LocalTrack.cs b/src/NzbDrone.Core/Parser/Model/LocalTrack.cs index e3577527d..2f8b35588 100644 --- a/src/NzbDrone.Core/Parser/Model/LocalTrack.cs +++ b/src/NzbDrone.Core/Parser/Model/LocalTrack.cs @@ -24,7 +24,7 @@ namespace NzbDrone.Core.Parser.Model public MediaInfoModel MediaInfo { get; set; } public bool ExistingFile { get; set; } - public int Album + public string Album { get { @@ -32,7 +32,7 @@ namespace NzbDrone.Core.Parser.Model } } - public bool IsSpecial => Album == 0; + public bool IsSpecial => Album != ""; public override string ToString() { diff --git a/src/NzbDrone.Core/Validation/Paths/ArtistExistsValidator.cs b/src/NzbDrone.Core/Validation/Paths/ArtistExistsValidator.cs index 4a56bd072..3260895c5 100644 --- a/src/NzbDrone.Core/Validation/Paths/ArtistExistsValidator.cs +++ b/src/NzbDrone.Core/Validation/Paths/ArtistExistsValidator.cs @@ -12,7 +12,7 @@ namespace NzbDrone.Core.Validation.Paths private readonly IArtistService _artistService; public ArtistExistsValidator(IArtistService artistService) - : base("This artist has already been added") + : base("This artist has already been added.") { _artistService = artistService; } @@ -21,9 +21,7 @@ namespace NzbDrone.Core.Validation.Paths { if (context.PropertyValue == null) return true; - var itunesId = Convert.ToInt32(context.PropertyValue.ToString()); - - return (!_artistService.GetAllArtists().Exists(s => s.ItunesId == itunesId)); + return (!_artistService.GetAllArtists().Exists(s => s.SpotifyId == context.PropertyValue.ToString())); } } } diff --git a/src/UI/AddSeries/SearchResultView.js b/src/UI/AddSeries/SearchResultView.js index aaef92a1f..8c4c70e7e 100644 --- a/src/UI/AddSeries/SearchResultView.js +++ b/src/UI/AddSeries/SearchResultView.js @@ -223,12 +223,12 @@ var view = Marionette.ItemView.extend({ self.close(); Messenger.show({ - message : 'Added: ' + self.model.get('title'), + message : 'Added: ' + self.model.get('artistName'), actions : { goToSeries : { label : 'Go to Artist', action : function() { - Backbone.history.navigate('/artist/' + self.model.get('titleSlug'), { trigger : true }); + Backbone.history.navigate('/artist/' + self.model.get('artistSlug'), { trigger : true }); } } },