Merge pull request #5 from mattman86/feature/artist-overview

Implemented artist overview
pull/4/head
Joseph Milazzo 7 years ago committed by GitHub
commit fa80bca2c9

@ -98,7 +98,6 @@ namespace NzbDrone.Api.Music
{ {
//var seriesStats = _seriesStatisticsService.SeriesStatistics(); //var seriesStats = _seriesStatisticsService.SeriesStatistics();
var artistResources = _artistService.GetAllArtists().ToResource(); var artistResources = _artistService.GetAllArtists().ToResource();
Console.WriteLine("[DEBUG] Returning {0} Artists", artistResources.Count);
MapCoversToLocal(artistResources.ToArray()); MapCoversToLocal(artistResources.ToArray());
//LinkSeriesStatistics(seriesResources, seriesStats); //LinkSeriesStatistics(seriesResources, seriesStats);
//PopulateAlternateTitles(seriesResources); //PopulateAlternateTitles(seriesResources);
@ -106,9 +105,9 @@ namespace NzbDrone.Api.Music
return artistResources; return artistResources;
} }
private int AddArtist(ArtistResource seriesResource) private int AddArtist(ArtistResource artistResource)
{ {
var model = seriesResource.ToModel(); var model = artistResource.ToModel();
return _addSeriesService.AddArtist(model).Id; return _addSeriesService.AddArtist(model).Id;
} }
@ -175,16 +174,6 @@ namespace NzbDrone.Api.Music
BroadcastResourceChange(ModelAction.Updated, message.Artist.Id); BroadcastResourceChange(ModelAction.Updated, message.Artist.Id);
} }
//public void Handle(ArtistDeletedEvent message)
//{
// BroadcastResourceChange(ModelAction.Deleted, message.Artist.ToResource());
//}
//public void Handle(ArtistRenamedEvent message)
//{
// BroadcastResourceChange(ModelAction.Updated, message.Artist.Id);
//}
//public void Handle(MediaCoversUpdatedEvent message) //public void Handle(MediaCoversUpdatedEvent message)
//{ //{
// BroadcastResourceChange(ModelAction.Updated, message.Artist.Id); // BroadcastResourceChange(ModelAction.Updated, message.Artist.Id);

@ -22,6 +22,7 @@ namespace NzbDrone.Api.Music
public int ItunesId { get; set; } public int ItunesId { get; set; }
//public List<AlternateTitleResource> AlternateTitles { get; set; } //public List<AlternateTitleResource> AlternateTitles { get; set; }
//public string SortTitle { get; set; } //public string SortTitle { get; set; }
public string Overview { get; set; }
public int AlbumCount public int AlbumCount
{ {
@ -82,7 +83,7 @@ namespace NzbDrone.Api.Music
//EpisodeFileCount //EpisodeFileCount
//SizeOnDisk //SizeOnDisk
//Status = resource.Status, //Status = resource.Status,
//Overview = resource.Overview, Overview = model.Overview,
//NextAiring //NextAiring
//PreviousAiring //PreviousAiring
//Network = resource.Network, //Network = resource.Network,
@ -135,7 +136,7 @@ namespace NzbDrone.Api.Music
//EpisodeFileCount //EpisodeFileCount
//SizeOnDisk //SizeOnDisk
//Status = resource.Status, //Status = resource.Status,
//Overview = resource.Overview, Overview = resource.Overview,
//NextAiring //NextAiring
//PreviousAiring //PreviousAiring
//Network = resource.Network, //Network = resource.Network,

@ -6,6 +6,7 @@ namespace NzbDrone.Common.Cloud
{ {
IHttpRequestBuilderFactory Services { get; } IHttpRequestBuilderFactory Services { get; }
IHttpRequestBuilderFactory Search { get; } IHttpRequestBuilderFactory Search { get; }
IHttpRequestBuilderFactory InternalSearch { get; }
IHttpRequestBuilderFactory SkyHookTvdb { get; } IHttpRequestBuilderFactory SkyHookTvdb { get; }
} }
@ -19,6 +20,9 @@ namespace NzbDrone.Common.Cloud
Search = new HttpRequestBuilder("https://itunes.apple.com/{route}/") Search = new HttpRequestBuilder("https://itunes.apple.com/{route}/")
.CreateFactory(); .CreateFactory();
InternalSearch = new HttpRequestBuilder("https://itunes.apple.com/WebObjects/MZStore.woa/wa/{route}") //viewArtist or search
.CreateFactory();
SkyHookTvdb = new HttpRequestBuilder("http://skyhook.lidarr.tv/v1/tvdb/{route}/{language}/") SkyHookTvdb = new HttpRequestBuilder("http://skyhook.lidarr.tv/v1/tvdb/{route}/{language}/")
.SetSegment("language", "en") .SetSegment("language", "en")
.CreateFactory(); .CreateFactory();
@ -28,6 +32,8 @@ namespace NzbDrone.Common.Cloud
public IHttpRequestBuilderFactory Search { get; } public IHttpRequestBuilderFactory Search { get; }
public IHttpRequestBuilderFactory InternalSearch { get; }
public IHttpRequestBuilderFactory SkyHookTvdb { get; } public IHttpRequestBuilderFactory SkyHookTvdb { get; }
} }
} }

@ -18,6 +18,7 @@ namespace NzbDrone.Core.Datastore.Migration
.WithColumn("ArtistSlug").AsString().Nullable() //.Unique() .WithColumn("ArtistSlug").AsString().Nullable() //.Unique()
.WithColumn("CleanTitle").AsString().Nullable() // Do we need this? .WithColumn("CleanTitle").AsString().Nullable() // Do we need this?
.WithColumn("Monitored").AsBoolean() .WithColumn("Monitored").AsBoolean()
.WithColumn("Overview").AsString().Nullable()
.WithColumn("AlbumFolder").AsBoolean().Nullable() .WithColumn("AlbumFolder").AsBoolean().Nullable()
.WithColumn("ArtistFolder").AsBoolean().Nullable() .WithColumn("ArtistFolder").AsBoolean().Nullable()
.WithColumn("LastInfoSync").AsDateTime().Nullable() .WithColumn("LastInfoSync").AsDateTime().Nullable()

@ -5,6 +5,42 @@ using System.Text;
namespace NzbDrone.Core.MetadataSource.SkyHook.Resource 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 ArtistInfoResource() { }
public Dictionary<int, ArtistInfoResource> Results { get; set; }
public bool HasArtistBio { get; set; }
public string url { get; set; }
public string shortUrl { get; set; }
public List<string> artistContemporaries { get; set; }
public List<string> 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> gallery { get; set; }
//public List<Genre> genres { get; set; }
public List<object> artistInfluencers { get; set; }
public List<object> artistFollowers { get; set; }
//public string umcArtistImageUrl { get; set; }
}
public class AlbumResource public class AlbumResource
{ {
public AlbumResource() public AlbumResource()
@ -37,5 +73,6 @@ namespace NzbDrone.Core.MetadataSource.SkyHook.Resource
public List<AlbumResource> Results { get; set; } public List<AlbumResource> Results { get; set; }
//public string ArtistName { get; set; } //public string ArtistName { get; set; }
//public List<AlbumResource> Albums { get; set; } //public List<AlbumResource> Albums { get; set; }
public StorePlatformDataResource StorePlatformData { get; set; }
} }
} }

@ -22,11 +22,13 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
private readonly Logger _logger; private readonly Logger _logger;
private readonly IHttpRequestBuilderFactory _requestBuilder; private readonly IHttpRequestBuilderFactory _requestBuilder;
private readonly IHttpRequestBuilderFactory _internalRequestBuilder;
public SkyHookProxy(IHttpClient httpClient, ILidarrCloudRequestBuilder requestBuilder, Logger logger) public SkyHookProxy(IHttpClient httpClient, ILidarrCloudRequestBuilder requestBuilder, Logger logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_requestBuilder = requestBuilder.Search; _requestBuilder = requestBuilder.Search;
_internalRequestBuilder = requestBuilder.InternalSearch;
_logger = logger; _logger = logger;
} }
@ -124,19 +126,63 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
} }
} }
//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<ArtistResource>(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];
//}
public Tuple<Artist, List<Track>> GetArtistInfo(int itunesId) public Tuple<Artist, List<Track>> GetArtistInfo(int itunesId)
{ {
Console.WriteLine("[GetArtistInfo] id:" + itunesId); _logger.Debug("Getting Artist with iTunesID of {0}", itunesId);
//https://itunes.apple.com/lookup?id=909253 var httpRequest1 = _requestBuilder.Create()
var httpRequest = _requestBuilder.Create()
.SetSegment("route", "lookup") .SetSegment("route", "lookup")
.AddQueryParam("id", itunesId.ToString()) .AddQueryParam("id", itunesId.ToString())
.Build(); .Build();
httpRequest.AllowAutoRedirect = true; var httpRequest2 = _internalRequestBuilder.Create()
httpRequest.SuppressHttpError = true; .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";
var httpResponse = _httpClient.Get<ArtistResource>(httpRequest); httpRequest1.AllowAutoRedirect = true;
httpRequest1.SuppressHttpError = true;
var httpResponse = _httpClient.Get<ArtistResource>(httpRequest1);
if (httpResponse.HasHttpError) if (httpResponse.HasHttpError)
{ {
@ -146,17 +192,23 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
} }
else else
{ {
throw new HttpException(httpRequest, httpResponse); throw new HttpException(httpRequest1, httpResponse);
} }
} }
Console.WriteLine("GetArtistInfo, GetArtistInfo"); List<Artist> artists = MapArtists(httpResponse.Resource);
//var tracks = httpResponse.Resource.Episodes.Select(MapEpisode); List<Artist> newArtists = new List<Artist>(artists.Count);
//var artist = MapArtist(httpResponse.Resource); int count = 0;
foreach (var artist in artists)
{
newArtists.Add(AddOverview(artist));
count++;
}
// I don't know how we are getting tracks from iTunes yet. // I don't know how we are getting tracks from iTunes yet.
return new Tuple<Artist, List<Track>>(MapArtists(httpResponse.Resource)[0], new List<Track>()); return new Tuple<Artist, List<Track>>(newArtists[0], new List<Track>());
//return new Tuple<Artist, List<Track>>(artist, tracks.ToList());
} }
public List<Artist> SearchForNewArtist(string title) public List<Artist> SearchForNewArtist(string title)
{ {
try try
@ -195,7 +247,18 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
var httpResponse = _httpClient.Get<ArtistResource>(httpRequest); var httpResponse = _httpClient.Get<ArtistResource>(httpRequest);
return MapArtists(httpResponse.Resource);
List<Artist> artists = MapArtists(httpResponse.Resource);
List<Artist> newArtists = new List<Artist>(artists.Count);
int count = 0;
foreach (var artist in artists)
{
newArtists.Add(AddOverview(artist));
count++;
}
return newArtists;
} }
catch (HttpException) catch (HttpException)
{ {
@ -208,6 +271,38 @@ 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<ArtistResource>(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);
}
return artist;
}
private List<Artist> MapArtists(ArtistResource resource) private List<Artist> MapArtists(ArtistResource resource)
{ {
Album tempAlbum; Album tempAlbum;

@ -79,18 +79,17 @@ namespace NzbDrone.Core.Music
} }
catch (SeriesNotFoundException) catch (SeriesNotFoundException)
{ {
_logger.Error("tvdbid {1} was not found, it may have been removed from TheTVDB.", newArtist.ItunesId); _logger.Error("iTunesId {1} was not found, it may have been removed from iTunes.", newArtist.ItunesId);
throw new ValidationException(new List<ValidationFailure> throw new ValidationException(new List<ValidationFailure>
{ {
new ValidationFailure("TvdbId", "A series with this ID was not found", newArtist.ItunesId) new ValidationFailure("iTunesId", "An artist with this ID was not found", newArtist.ItunesId)
}); });
} }
var artist = tuple.Item1; var artist = tuple.Item1;
// If seasons were passed in on the new series use them, otherwise use the seasons from Skyhook // If albums were passed in on the new artist use them, otherwise use the albums from Skyhook
// TODO: Refactor for albums
newArtist.Albums = newArtist.Albums != null && newArtist.Albums.Any() ? newArtist.Albums : artist.Albums; newArtist.Albums = newArtist.Albums != null && newArtist.Albums.Any() ? newArtist.Albums : artist.Albums;
artist.ApplyChanges(newArtist); artist.ApplyChanges(newArtist);

@ -26,6 +26,7 @@ namespace NzbDrone.Core.Music
public string ArtistName { get; set; } public string ArtistName { get; set; }
public string ArtistSlug { get; set; } public string ArtistSlug { get; set; }
public string CleanTitle { get; set; } public string CleanTitle { get; set; }
public string Overview { get; set; }
public bool Monitored { get; set; } public bool Monitored { get; set; }
public bool AlbumFolder { get; set; } public bool AlbumFolder { get; set; }
public bool ArtistFolder { get; set; } public bool ArtistFolder { get; set; }

@ -71,6 +71,18 @@ Handlebars.registerHelper('seasonCountHelper', function() {
return new Handlebars.SafeString('<span class="label label-info">{0} Seasons</span>'.format(seasonCount)); return new Handlebars.SafeString('<span class="label label-info">{0} Seasons</span>'.format(seasonCount));
}); });
Handlebars.registerHelper ('truncate', function (str, len) {
if (str && str.length > len && str.length > 0) {
var new_str = str + " ";
new_str = str.substr (0, len);
new_str = str.substr (0, new_str.lastIndexOf(" "));
new_str = (new_str.length > 0) ? new_str : str.substr (0, len);
return new Handlebars.SafeString ( new_str +'...' );
}
return str;
});
Handlebars.registerHelper('albumCountHelper', function() { Handlebars.registerHelper('albumCountHelper', function() {
var albumCount = this.albumCount; var albumCount = this.albumCount;

@ -20,12 +20,10 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-12 col-xs-12"> <div class="col-md-10 col-xs-12">
<a href="{{route}}"> <div>
<div> {{truncate overview 600}}
{{overview}} </div>
</div>
</a>
</div> </div>
</div> </div>
<div class="row"> <div class="row">

@ -20,6 +20,7 @@ require('../../Mixins/backbone.signalr.mixin');
module.exports = Marionette.Layout.extend({ module.exports = Marionette.Layout.extend({
template : 'Series/Index/SeriesIndexLayoutTemplate', template : 'Series/Index/SeriesIndexLayoutTemplate',
regions : { regions : {
seriesRegion : '#x-series', seriesRegion : '#x-series',
toolbar : '#x-toolbar', toolbar : '#x-toolbar',

@ -8,6 +8,12 @@
max-width: 100%; max-width: 100%;
} }
.truncate {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.edit-series-modal, .delete-series-modal { .edit-series-modal, .delete-series-modal {
overflow : visible; overflow : visible;

Loading…
Cancel
Save