mirror of
https://github.com/lidarr/lidarr.git
synced 2025-07-16 10:03:51 -07:00
Updated the code to allow a search to be made from UI to iTunes and return a mock result.
This commit is contained in:
parent
684e4f4c80
commit
2813fccc78
32 changed files with 1401 additions and 65 deletions
55
src/NzbDrone.Api/Music/AlbumResource.cs
Normal file
55
src/NzbDrone.Api/Music/AlbumResource.cs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
using NzbDrone.Core.Music;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Music
|
||||||
|
{
|
||||||
|
public class AlbumResource
|
||||||
|
{
|
||||||
|
public int AlbumId { get; set; }
|
||||||
|
public bool Monitored { get; set; }
|
||||||
|
//public string Overview { get; set; }
|
||||||
|
public int Year { get; set; }
|
||||||
|
//public SeasonStatisticsResource Statistics { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AlbumResourceMapper
|
||||||
|
{
|
||||||
|
public static AlbumResource ToResource(this Album model)
|
||||||
|
{
|
||||||
|
if (model == null) return null;
|
||||||
|
|
||||||
|
return new AlbumResource
|
||||||
|
{
|
||||||
|
AlbumId = model.AlbumId,
|
||||||
|
Monitored = model.Monitored,
|
||||||
|
//Overview = model.Overview; //TODO: Inspect if Album needs an overview
|
||||||
|
Year = model.Year
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Album ToModel(this AlbumResource resource)
|
||||||
|
{
|
||||||
|
if (resource == null) return null;
|
||||||
|
|
||||||
|
return new Album
|
||||||
|
{
|
||||||
|
AlbumId = resource.AlbumId,
|
||||||
|
Monitored = resource.Monitored,
|
||||||
|
Year = resource.Year
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<AlbumResource> ToResource(this IEnumerable<Album> models)
|
||||||
|
{
|
||||||
|
return models.Select(ToResource).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Album> ToModel(this IEnumerable<AlbumResource> resources)
|
||||||
|
{
|
||||||
|
return resources?.Select(ToModel).ToList() ?? new List<Album>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
46
src/NzbDrone.Api/Music/ArtistLookupModule.cs
Normal file
46
src/NzbDrone.Api/Music/ArtistLookupModule.cs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
using Nancy;
|
||||||
|
using NzbDrone.Api.Extensions;
|
||||||
|
using NzbDrone.Core.MediaCover;
|
||||||
|
using NzbDrone.Core.MetadataSource;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Music
|
||||||
|
{
|
||||||
|
public class ArtistLookupModule : NzbDroneRestModule<ArtistResource>
|
||||||
|
{
|
||||||
|
private readonly ISearchForNewSeries _searchProxy; //TODO: Switch out for Music varriant
|
||||||
|
|
||||||
|
public ArtistLookupModule(ISearchForNewSeries searchProxy)
|
||||||
|
: base("/artist/lookup")
|
||||||
|
{
|
||||||
|
_searchProxy = searchProxy;
|
||||||
|
Get["/"] = x => Search();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Response Search()
|
||||||
|
{
|
||||||
|
var iTunesResults = _searchProxy.SearchForNewArtist((string)Request.Query.term);
|
||||||
|
return MapToResource(iTunesResults).AsResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static IEnumerable<ArtistResource> MapToResource(IEnumerable<Core.Music.Artist> artists)
|
||||||
|
{
|
||||||
|
foreach (var currentArtist in artists)
|
||||||
|
{
|
||||||
|
var resource = currentArtist.ToResource();
|
||||||
|
var poster = currentArtist.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster);
|
||||||
|
if (poster != null)
|
||||||
|
{
|
||||||
|
resource.RemotePoster = poster.Url;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return resource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
205
src/NzbDrone.Api/Music/ArtistResource.cs
Normal file
205
src/NzbDrone.Api/Music/ArtistResource.cs
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
using NzbDrone.Api.REST;
|
||||||
|
using NzbDrone.Api.Series;
|
||||||
|
using NzbDrone.Core.MediaCover;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Music
|
||||||
|
{
|
||||||
|
public class ArtistResource : RestResource
|
||||||
|
{
|
||||||
|
public ArtistResource()
|
||||||
|
{
|
||||||
|
Monitored = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Todo: Sorters should be done completely on the client
|
||||||
|
//Todo: Is there an easy way to keep IgnoreArticlesWhenSorting in sync between, Series, History, Missing?
|
||||||
|
//Todo: We should get the entire Profile instead of ID and Name separately
|
||||||
|
|
||||||
|
//View Only
|
||||||
|
public string ArtistName { get; set; }
|
||||||
|
//public List<AlternateTitleResource> AlternateTitles { get; set; }
|
||||||
|
//public string SortTitle { get; set; }
|
||||||
|
|
||||||
|
public int AlbumCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Albums == null) return 0;
|
||||||
|
|
||||||
|
return Albums.Where(s => s.AlbumId > 0).Count(); // TODO: CHeck this condition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int? TotalTrackCount { get; set; }
|
||||||
|
public int? TrackCount { get; set; }
|
||||||
|
public int? TrackFileCount { get; set; }
|
||||||
|
public long? SizeOnDisk { get; set; }
|
||||||
|
//public SeriesStatusType Status { get; set; }
|
||||||
|
|
||||||
|
public List<MediaCover> Images { get; set; }
|
||||||
|
|
||||||
|
public string RemotePoster { get; set; }
|
||||||
|
public List<AlbumResource> Albums { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
//View & Edit
|
||||||
|
public string Path { get; set; }
|
||||||
|
public int ProfileId { get; set; }
|
||||||
|
|
||||||
|
//Editing Only
|
||||||
|
public bool ArtistFolder { get; set; }
|
||||||
|
public bool Monitored { get; set; }
|
||||||
|
|
||||||
|
//public bool UseSceneNumbering { get; set; }
|
||||||
|
//public int Runtime { get; set; }
|
||||||
|
//public int TvdbId { get; set; }
|
||||||
|
//public int TvRageId { get; set; }
|
||||||
|
//public int TvMazeId { get; set; }
|
||||||
|
//public DateTime? FirstAired { get; set; }
|
||||||
|
//public DateTime? LastInfoSync { get; set; }
|
||||||
|
//public SeriesTypes SeriesType { get; set; }
|
||||||
|
public string CleanTitle { get; set; }
|
||||||
|
public int ItunesId { get; set; }
|
||||||
|
//public string TitleSlug { get; set; }
|
||||||
|
public string RootFolderPath { get; set; }
|
||||||
|
public string Certification { get; set; }
|
||||||
|
public List<string> Genres { get; set; }
|
||||||
|
public HashSet<int> Tags { get; set; }
|
||||||
|
public DateTime Added { get; set; }
|
||||||
|
public AddSeriesOptions AddOptions { get; set; }
|
||||||
|
public Ratings Ratings { get; set; }
|
||||||
|
public string ArtistSlug { get; internal set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ArtistResourceMapper
|
||||||
|
{
|
||||||
|
public static ArtistResource ToResource(this Core.Music.Artist model)
|
||||||
|
{
|
||||||
|
if (model == null) return null;
|
||||||
|
|
||||||
|
return new ArtistResource
|
||||||
|
{
|
||||||
|
Id = model.Id,
|
||||||
|
|
||||||
|
ArtistName = model.ArtistName,
|
||||||
|
//AlternateTitles
|
||||||
|
//SortTitle = resource.SortTitle,
|
||||||
|
|
||||||
|
//TotalEpisodeCount
|
||||||
|
//EpisodeCount
|
||||||
|
//EpisodeFileCount
|
||||||
|
//SizeOnDisk
|
||||||
|
//Status = resource.Status,
|
||||||
|
//Overview = resource.Overview,
|
||||||
|
//NextAiring
|
||||||
|
//PreviousAiring
|
||||||
|
//Network = resource.Network,
|
||||||
|
//AirTime = resource.AirTime,
|
||||||
|
Images = model.Images,
|
||||||
|
|
||||||
|
Albums = model.Albums.ToResource(),
|
||||||
|
//Year = resource.Year,
|
||||||
|
|
||||||
|
Path = model.Path,
|
||||||
|
ProfileId = model.ProfileId,
|
||||||
|
|
||||||
|
ArtistFolder = model.ArtistFolder,
|
||||||
|
Monitored = model.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,
|
||||||
|
CleanTitle = model.CleanTitle,
|
||||||
|
ItunesId = model.ItunesId,
|
||||||
|
ArtistSlug = model.ArtistSlug,
|
||||||
|
|
||||||
|
RootFolderPath = model.RootFolderPath,
|
||||||
|
Certification = model.Certification,
|
||||||
|
Genres = model.Genres,
|
||||||
|
Tags = model.Tags,
|
||||||
|
Added = model.Added,
|
||||||
|
//AddOptions = resource.AddOptions,
|
||||||
|
//Ratings = resource.Ratings
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Core.Music.Artist ToModel(this ArtistResource resource)
|
||||||
|
{
|
||||||
|
if (resource == null) return null;
|
||||||
|
|
||||||
|
return new Core.Music.Artist
|
||||||
|
{
|
||||||
|
Id = resource.Id,
|
||||||
|
|
||||||
|
ArtistName = resource.ArtistName,
|
||||||
|
//AlternateTitles
|
||||||
|
//SortTitle = resource.SortTitle,
|
||||||
|
|
||||||
|
//TotalEpisodeCount
|
||||||
|
//EpisodeCount
|
||||||
|
//EpisodeFileCount
|
||||||
|
//SizeOnDisk
|
||||||
|
//Status = resource.Status,
|
||||||
|
//Overview = resource.Overview,
|
||||||
|
//NextAiring
|
||||||
|
//PreviousAiring
|
||||||
|
//Network = resource.Network,
|
||||||
|
//AirTime = resource.AirTime,
|
||||||
|
Images = resource.Images,
|
||||||
|
|
||||||
|
Albums = resource.Albums.ToModel(),
|
||||||
|
//Year = resource.Year,
|
||||||
|
|
||||||
|
Path = resource.Path,
|
||||||
|
ProfileId = resource.ProfileId,
|
||||||
|
|
||||||
|
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,
|
||||||
|
CleanTitle = resource.CleanTitle,
|
||||||
|
ItunesId = resource.ItunesId,
|
||||||
|
ArtistSlug = resource.ArtistSlug,
|
||||||
|
|
||||||
|
RootFolderPath = resource.RootFolderPath,
|
||||||
|
Certification = resource.Certification,
|
||||||
|
Genres = resource.Genres,
|
||||||
|
Tags = resource.Tags,
|
||||||
|
Added = resource.Added,
|
||||||
|
//AddOptions = resource.AddOptions,
|
||||||
|
//Ratings = resource.Ratings
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Core.Music.Artist ToModel(this ArtistResource resource, Core.Music.Artist artist)
|
||||||
|
{
|
||||||
|
var updatedArtist = resource.ToModel();
|
||||||
|
|
||||||
|
artist.ApplyChanges(updatedArtist);
|
||||||
|
|
||||||
|
return artist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<ArtistResource> ToResource(this IEnumerable<Core.Music.Artist> artist)
|
||||||
|
{
|
||||||
|
return artist.Select(ToResource).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -111,6 +111,9 @@
|
||||||
<Compile Include="Frontend\Mappers\RobotsTxtMapper.cs" />
|
<Compile Include="Frontend\Mappers\RobotsTxtMapper.cs" />
|
||||||
<Compile Include="Indexers\ReleaseModuleBase.cs" />
|
<Compile Include="Indexers\ReleaseModuleBase.cs" />
|
||||||
<Compile Include="Indexers\ReleasePushModule.cs" />
|
<Compile Include="Indexers\ReleasePushModule.cs" />
|
||||||
|
<Compile Include="Music\AlbumResource.cs" />
|
||||||
|
<Compile Include="Music\ArtistLookupModule.cs" />
|
||||||
|
<Compile Include="Music\ArtistResource.cs" />
|
||||||
<Compile Include="Parse\ParseModule.cs" />
|
<Compile Include="Parse\ParseModule.cs" />
|
||||||
<Compile Include="Parse\ParseResource.cs" />
|
<Compile Include="Parse\ParseResource.cs" />
|
||||||
<Compile Include="ManualImport\ManualImportModule.cs" />
|
<Compile Include="ManualImport\ManualImportModule.cs" />
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace NzbDrone.Common.Cloud
|
||||||
public interface ILidarrCloudRequestBuilder
|
public interface ILidarrCloudRequestBuilder
|
||||||
{
|
{
|
||||||
IHttpRequestBuilderFactory Services { get; }
|
IHttpRequestBuilderFactory Services { get; }
|
||||||
|
IHttpRequestBuilderFactory Search { get; }
|
||||||
IHttpRequestBuilderFactory SkyHookTvdb { get; }
|
IHttpRequestBuilderFactory SkyHookTvdb { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,16 +13,22 @@ namespace NzbDrone.Common.Cloud
|
||||||
{
|
{
|
||||||
public LidarrCloudRequestBuilder()
|
public LidarrCloudRequestBuilder()
|
||||||
{
|
{
|
||||||
Services = new HttpRequestBuilder("http://services.Lidarr.tv/v1/")
|
|
||||||
|
Services = new HttpRequestBuilder("http://services.lidarr.tv/v1/")
|
||||||
.CreateFactory();
|
.CreateFactory();
|
||||||
|
|
||||||
SkyHookTvdb = new HttpRequestBuilder("http://skyhook.Lidarr.tv/v1/tvdb/{route}/{language}/")
|
Search = new HttpRequestBuilder("https://itunes.apple.com/search/")
|
||||||
|
.CreateFactory();
|
||||||
|
|
||||||
|
SkyHookTvdb = new HttpRequestBuilder("http://skyhook.lidarr.tv/v1/tvdb/{route}/{language}/")
|
||||||
.SetSegment("language", "en")
|
.SetSegment("language", "en")
|
||||||
.CreateFactory();
|
.CreateFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IHttpRequestBuilderFactory Services { get; }
|
public IHttpRequestBuilderFactory Services { get; }
|
||||||
|
|
||||||
|
public IHttpRequestBuilderFactory Search { get; }
|
||||||
|
|
||||||
public IHttpRequestBuilderFactory SkyHookTvdb { get; }
|
public IHttpRequestBuilderFactory SkyHookTvdb { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
|
using NzbDrone.Core.Music;
|
||||||
|
|
||||||
namespace NzbDrone.Core.MetadataSource
|
namespace NzbDrone.Core.MetadataSource
|
||||||
{
|
{
|
||||||
public interface ISearchForNewSeries
|
public interface ISearchForNewSeries
|
||||||
{
|
{
|
||||||
List<Series> SearchForNewSeries(string title);
|
List<Series> SearchForNewSeries(string title);
|
||||||
|
List<Artist> SearchForNewArtist(string title);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MetadataSource.SkyHook.Resource
|
||||||
|
{
|
||||||
|
public class AlbumResource
|
||||||
|
{
|
||||||
|
public AlbumResource()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ArtistName { get; set; }
|
||||||
|
public int ArtistId { get; set; }
|
||||||
|
public string CollectionName { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ArtistResource
|
||||||
|
{
|
||||||
|
public ArtistResource()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ResultCount { get; set; }
|
||||||
|
public List<AlbumResource> Results { get; set; }
|
||||||
|
//public string ArtistName { get; set; }
|
||||||
|
//public List<AlbumResource> Albums { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,9 @@ using NzbDrone.Core.Exceptions;
|
||||||
using NzbDrone.Core.MediaCover;
|
using NzbDrone.Core.MediaCover;
|
||||||
using NzbDrone.Core.MetadataSource.SkyHook.Resource;
|
using NzbDrone.Core.MetadataSource.SkyHook.Resource;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using NzbDrone.Core.Music;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace NzbDrone.Core.MetadataSource.SkyHook
|
namespace NzbDrone.Core.MetadataSource.SkyHook
|
||||||
{
|
{
|
||||||
|
@ -23,12 +26,13 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
||||||
public SkyHookProxy(IHttpClient httpClient, ILidarrCloudRequestBuilder requestBuilder, Logger logger)
|
public SkyHookProxy(IHttpClient httpClient, ILidarrCloudRequestBuilder requestBuilder, Logger logger)
|
||||||
{
|
{
|
||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
_requestBuilder = requestBuilder.SkyHookTvdb;
|
_requestBuilder = requestBuilder.Search;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tuple<Series, List<Episode>> GetSeriesInfo(int tvdbSeriesId)
|
public Tuple<Series, List<Episode>> GetSeriesInfo(int tvdbSeriesId)
|
||||||
{
|
{
|
||||||
|
Console.WriteLine("[GetSeriesInfo] id:" + tvdbSeriesId);
|
||||||
var httpRequest = _requestBuilder.Create()
|
var httpRequest = _requestBuilder.Create()
|
||||||
.SetSegment("route", "shows")
|
.SetSegment("route", "shows")
|
||||||
.Resource(tvdbSeriesId.ToString())
|
.Resource(tvdbSeriesId.ToString())
|
||||||
|
@ -62,36 +66,52 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var lowerTitle = title.ToLowerInvariant();
|
var lowerTitle = title.ToLowerInvariant();
|
||||||
|
Console.WriteLine("Searching for " + lowerTitle);
|
||||||
|
|
||||||
if (lowerTitle.StartsWith("tvdb:") || lowerTitle.StartsWith("tvdbid:"))
|
//if (lowerTitle.StartsWith("tvdb:") || lowerTitle.StartsWith("tvdbid:"))
|
||||||
{
|
//{
|
||||||
var slug = lowerTitle.Split(':')[1].Trim();
|
// var slug = lowerTitle.Split(':')[1].Trim();
|
||||||
|
|
||||||
int tvdbId;
|
// int tvdbId;
|
||||||
|
|
||||||
if (slug.IsNullOrWhiteSpace() || slug.Any(char.IsWhiteSpace) || !int.TryParse(slug, out tvdbId) || tvdbId <= 0)
|
// if (slug.IsNullOrWhiteSpace() || slug.Any(char.IsWhiteSpace) || !int.TryParse(slug, out tvdbId) || tvdbId <= 0)
|
||||||
{
|
// {
|
||||||
return new List<Series>();
|
// return new List<Series>();
|
||||||
}
|
// }
|
||||||
|
|
||||||
try
|
// try
|
||||||
{
|
// {
|
||||||
return new List<Series> { GetSeriesInfo(tvdbId).Item1 };
|
// return new List<Series> { GetSeriesInfo(tvdbId).Item1 };
|
||||||
}
|
// }
|
||||||
catch (SeriesNotFoundException)
|
// catch (SeriesNotFoundException)
|
||||||
{
|
// {
|
||||||
return new List<Series>();
|
// return new List<Series>();
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
|
// Majora: Temporarily, use iTunes to test.
|
||||||
var httpRequest = _requestBuilder.Create()
|
var httpRequest = _requestBuilder.Create()
|
||||||
.SetSegment("route", "search")
|
.AddQueryParam("entity", "album")
|
||||||
.AddQueryParam("term", title.ToLower().Trim())
|
.AddQueryParam("term", title.ToLower().Trim())
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var httpResponse = _httpClient.Get<List<ShowResource>>(httpRequest);
|
|
||||||
|
|
||||||
return httpResponse.Resource.SelectList(MapSeries);
|
|
||||||
|
Console.WriteLine("httpRequest: ", httpRequest);
|
||||||
|
|
||||||
|
var httpResponse = _httpClient.Get<ArtistResource>(httpRequest);
|
||||||
|
|
||||||
|
//Console.WriteLine("Response: ", httpResponse.GetType());
|
||||||
|
//_logger.Info("Response: ", httpResponse.Resource.ResultCount);
|
||||||
|
|
||||||
|
//_logger.Info("HTTP Response: ", httpResponse.Resource.ResultCount);
|
||||||
|
var tempList = new List<Series>();
|
||||||
|
var tempSeries = new Series();
|
||||||
|
tempSeries.Title = "AFI";
|
||||||
|
tempList.Add(tempSeries);
|
||||||
|
return tempList;
|
||||||
|
|
||||||
|
//return httpResponse.Resource.Results.SelectList(MapArtist);
|
||||||
}
|
}
|
||||||
catch (HttpException)
|
catch (HttpException)
|
||||||
{
|
{
|
||||||
|
@ -104,6 +124,79 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Artist> SearchForNewArtist(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<Series>();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// return new List<Series> { GetSeriesInfo(tvdbId).Item1 };
|
||||||
|
// }
|
||||||
|
// catch (SeriesNotFoundException)
|
||||||
|
// {
|
||||||
|
// return new List<Series>();
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
var httpRequest = _requestBuilder.Create()
|
||||||
|
.AddQueryParam("entity", "album")
|
||||||
|
.AddQueryParam("term", title.ToLower().Trim())
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Console.WriteLine("httpRequest: ", httpRequest);
|
||||||
|
|
||||||
|
var httpResponse = _httpClient.Get<ArtistResource>(httpRequest);
|
||||||
|
|
||||||
|
//Console.WriteLine("Response: ", httpResponse.GetType());
|
||||||
|
//_logger.Info("Response: ", httpResponse.Resource.ResultCount);
|
||||||
|
|
||||||
|
//_logger.Info("HTTP Response: ", httpResponse.Resource.ResultCount);
|
||||||
|
var tempList = new List<Artist>();
|
||||||
|
var tempSeries = new Artist();
|
||||||
|
tempSeries.ArtistName = "AFI";
|
||||||
|
tempList.Add(tempSeries);
|
||||||
|
return tempList;
|
||||||
|
|
||||||
|
//return httpResponse.Resource.Results.SelectList(MapArtist);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Artist MapArtist(ArtistResource artistQuery)
|
||||||
|
{
|
||||||
|
var artist = new Artist();
|
||||||
|
//artist.ItunesId = artistQuery.artistId;
|
||||||
|
|
||||||
|
// artist.ArtistName = artistQuery.ArtistName;
|
||||||
|
|
||||||
|
|
||||||
|
return artist;
|
||||||
|
}
|
||||||
|
|
||||||
private static Series MapSeries(ShowResource show)
|
private static Series MapSeries(ShowResource show)
|
||||||
{
|
{
|
||||||
var series = new Series();
|
var series = new Series();
|
||||||
|
|
|
@ -55,6 +55,8 @@ namespace NzbDrone.Core.Music
|
||||||
|
|
||||||
public List<Album> Albums { get; set; }
|
public List<Album> Albums { get; set; }
|
||||||
public HashSet<int> Tags { get; set; }
|
public HashSet<int> Tags { get; set; }
|
||||||
|
public bool ArtistFolder { get; set; }
|
||||||
|
|
||||||
//public AddSeriesOptions AddOptions { get; set; } // TODO: Learn what this does
|
//public AddSeriesOptions AddOptions { get; set; } // TODO: Learn what this does
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
|
129
src/NzbDrone.Core/Music/ArtistRepository.cs
Normal file
129
src/NzbDrone.Core/Music/ArtistRepository.cs
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Music
|
||||||
|
{
|
||||||
|
public interface IArtistRepository : IBasicRepository<Artist>
|
||||||
|
{
|
||||||
|
bool ArtistPathExists(string path);
|
||||||
|
Artist FindByTitle(string cleanTitle);
|
||||||
|
Artist FindByItunesId(int iTunesId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ArtistRepository : IArtistRepository
|
||||||
|
{
|
||||||
|
public IEnumerable<Artist> All()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ArtistPathExists(string path)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(Artist model)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(int id)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteMany(IEnumerable<int> ids)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteMany(List<Artist> model)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Artist FindByItunesId(int iTunesId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Artist FindByTitle(string cleanTitle)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Artist> Get(IEnumerable<int> ids)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Artist Get(int id)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PagingSpec<Artist> GetPaged(PagingSpec<Artist> pagingSpec)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasItems()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Artist Insert(Artist model)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InsertMany(IList<Artist> model)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Purge(bool vacuum = false)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetFields(Artist model, params Expression<Func<Artist, object>>[] properties)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Artist Single()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Artist SingleOrDefault()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Artist Update(Artist model)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateMany(IList<Artist> model)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Artist Upsert(Artist model)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
95
src/NzbDrone.Core/Music/ArtistService.cs
Normal file
95
src/NzbDrone.Core/Music/ArtistService.cs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.Organizer;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Music
|
||||||
|
{
|
||||||
|
public interface IArtistService
|
||||||
|
{
|
||||||
|
Artist GetArtist(int artistId);
|
||||||
|
List<Artist> GetArtists(IEnumerable<int> artistIds);
|
||||||
|
Artist AddArtist(Artist newArtist);
|
||||||
|
Artist FindByItunesId(int itunesId);
|
||||||
|
Artist FindByTitle(string title);
|
||||||
|
Artist FindByTitleInexact(string title);
|
||||||
|
void DeleteArtist(int artistId, bool deleteFiles);
|
||||||
|
List<Artist> GetAllArtists();
|
||||||
|
Artist UpdateArtist(Artist artist);
|
||||||
|
List<Artist> UpdateArtists(List<Artist> artist);
|
||||||
|
bool ArtistPathExists(string folder);
|
||||||
|
void RemoveAddOptions(Artist artist);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ArtistService : IArtistService
|
||||||
|
{
|
||||||
|
private readonly IArtistRepository _artistRepository;
|
||||||
|
private readonly IEventAggregator _eventAggregator;
|
||||||
|
private readonly ITrackService _trackService;
|
||||||
|
private readonly IBuildFileNames _fileNameBuilder;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public Artist AddArtist(Artist newArtist)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ArtistPathExists(string folder)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteArtist(int artistId, bool deleteFiles)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Artist FindByItunesId(int itunesId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Artist FindByTitle(string title)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Artist FindByTitleInexact(string title)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Artist> GetAllArtists()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Artist GetArtist(int artistId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Artist> GetArtists(IEnumerable<int> artistIds)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAddOptions(Artist artist)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Artist UpdateArtist(Artist artist)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Artist> UpdateArtists(List<Artist> artist)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
using NzbDrone.Core.Datastore;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Music
|
|
||||||
{
|
|
||||||
public class Compilation : ModelBase
|
|
||||||
{
|
|
||||||
public Compilation()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public int CompilationId { get; set; }
|
|
||||||
public LazyList<Artist> Artists { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
117
src/NzbDrone.Core/Music/TrackService.cs
Normal file
117
src/NzbDrone.Core/Music/TrackService.cs
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Music
|
||||||
|
{
|
||||||
|
public interface ITrackService
|
||||||
|
{
|
||||||
|
Track GetTrack(int id);
|
||||||
|
List<Track> GetTracks(IEnumerable<int> ids);
|
||||||
|
Track FindTrack(int artistId, int albumId, int trackNumber);
|
||||||
|
Track FindTrackByTitle(int artistId, int albumId, string releaseTitle);
|
||||||
|
List<Track> GetTrackByArtist(int artistId);
|
||||||
|
List<Track> GetTracksByAblum(int artistId, int albumId);
|
||||||
|
List<Track> GetTracksByAblumTitle(int artistId, string albumTitle);
|
||||||
|
List<Track> TracksWithFiles(int artistId);
|
||||||
|
PagingSpec<Track> TracksWithoutFiles(PagingSpec<Track> pagingSpec);
|
||||||
|
List<Track> GeTracksByFileId(int trackFileId);
|
||||||
|
void UpdateTrack(Track track);
|
||||||
|
void SetTrackMonitored(int trackId, bool monitored);
|
||||||
|
void UpdateTracks(List<Track> tracks);
|
||||||
|
void InsertMany(List<Track> tracks);
|
||||||
|
void UpdateMany(List<Track> tracks);
|
||||||
|
void DeleteMany(List<Track> tracks);
|
||||||
|
void SetTrackMonitoredByAlbum(int artistId, int albumId, bool monitored);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TrackService : ITrackService
|
||||||
|
{
|
||||||
|
public void DeleteMany(List<Track> tracks)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Track FindTrack(int artistId, int albumId, int trackNumber)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Track FindTrackByTitle(int artistId, int albumId, string releaseTitle)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Track> GeTracksByFileId(int trackFileId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Track GetTrack(int id)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Track> GetTrackByArtist(int artistId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Track> GetTracks(IEnumerable<int> ids)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Track> GetTracksByAblum(int artistId, int albumId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Track> GetTracksByAblumTitle(int artistId, string albumTitle)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InsertMany(List<Track> tracks)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTrackMonitored(int trackId, bool monitored)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTrackMonitoredByAlbum(int artistId, int albumId, bool monitored)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Track> TracksWithFiles(int artistId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PagingSpec<Track> TracksWithoutFiles(PagingSpec<Track> pagingSpec)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateMany(List<Track> tracks)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateTrack(Track track)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateTracks(List<Track> tracks)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -809,6 +809,7 @@
|
||||||
<Compile Include="Messaging\Events\IHandle.cs" />
|
<Compile Include="Messaging\Events\IHandle.cs" />
|
||||||
<Compile Include="Messaging\IProcessMessage.cs" />
|
<Compile Include="Messaging\IProcessMessage.cs" />
|
||||||
<Compile Include="MetadataSource\SkyHook\Resource\ActorResource.cs" />
|
<Compile Include="MetadataSource\SkyHook\Resource\ActorResource.cs" />
|
||||||
|
<Compile Include="MetadataSource\SkyHook\Resource\ArtistResource.cs" />
|
||||||
<Compile Include="MetadataSource\SkyHook\Resource\EpisodeResource.cs" />
|
<Compile Include="MetadataSource\SkyHook\Resource\EpisodeResource.cs" />
|
||||||
<Compile Include="MetadataSource\SkyHook\Resource\ImageResource.cs" />
|
<Compile Include="MetadataSource\SkyHook\Resource\ImageResource.cs" />
|
||||||
<Compile Include="MetadataSource\SkyHook\Resource\RatingResource.cs" />
|
<Compile Include="MetadataSource\SkyHook\Resource\RatingResource.cs" />
|
||||||
|
@ -841,7 +842,10 @@
|
||||||
<Compile Include="MetadataSource\ISearchForNewSeries.cs" />
|
<Compile Include="MetadataSource\ISearchForNewSeries.cs" />
|
||||||
<Compile Include="Music\Album.cs" />
|
<Compile Include="Music\Album.cs" />
|
||||||
<Compile Include="Music\Artist.cs" />
|
<Compile Include="Music\Artist.cs" />
|
||||||
|
<Compile Include="Music\ArtistRepository.cs" />
|
||||||
|
<Compile Include="Music\ArtistService.cs" />
|
||||||
<Compile Include="Music\Track.cs" />
|
<Compile Include="Music\Track.cs" />
|
||||||
|
<Compile Include="Music\TrackService.cs" />
|
||||||
<Compile Include="Notifications\Join\JoinAuthException.cs" />
|
<Compile Include="Notifications\Join\JoinAuthException.cs" />
|
||||||
<Compile Include="Notifications\Join\JoinInvalidDeviceException.cs" />
|
<Compile Include="Notifications\Join\JoinInvalidDeviceException.cs" />
|
||||||
<Compile Include="Notifications\Join\JoinResponseModel.cs" />
|
<Compile Include="Notifications\Join\JoinResponseModel.cs" />
|
||||||
|
@ -897,6 +901,8 @@
|
||||||
<Compile Include="Parser\IsoLanguage.cs" />
|
<Compile Include="Parser\IsoLanguage.cs" />
|
||||||
<Compile Include="Parser\IsoLanguages.cs" />
|
<Compile Include="Parser\IsoLanguages.cs" />
|
||||||
<Compile Include="Parser\LanguageParser.cs" />
|
<Compile Include="Parser\LanguageParser.cs" />
|
||||||
|
<Compile Include="Parser\Model\LocalTrack.cs" />
|
||||||
|
<Compile Include="Parser\Model\ParsedTrackInfo.cs" />
|
||||||
<Compile Include="Profiles\Delay\DelayProfile.cs" />
|
<Compile Include="Profiles\Delay\DelayProfile.cs" />
|
||||||
<Compile Include="Profiles\Delay\DelayProfileService.cs" />
|
<Compile Include="Profiles\Delay\DelayProfileService.cs" />
|
||||||
<Compile Include="Profiles\Delay\DelayProfileTagInUseValidator.cs" />
|
<Compile Include="Profiles\Delay\DelayProfileTagInUseValidator.cs" />
|
||||||
|
|
42
src/NzbDrone.Core/Parser/Model/LocalTrack.cs
Normal file
42
src/NzbDrone.Core/Parser/Model/LocalTrack.cs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||||
|
using NzbDrone.Core.Music;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Parser.Model
|
||||||
|
{
|
||||||
|
public class LocalTrack
|
||||||
|
{
|
||||||
|
public LocalTrack()
|
||||||
|
{
|
||||||
|
Tracks = new List<Track>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Path { get; set; }
|
||||||
|
public long Size { get; set; }
|
||||||
|
public ParsedTrackInfo ParsedTrackInfo { get; set; }
|
||||||
|
public Artist Artist { get; set; }
|
||||||
|
public List<Track> Tracks { get; set; }
|
||||||
|
public QualityModel Quality { get; set; }
|
||||||
|
public MediaInfoModel MediaInfo { get; set; }
|
||||||
|
public bool ExistingFile { get; set; }
|
||||||
|
|
||||||
|
public int Album
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Tracks.Select(c => c.AlbumId).Distinct().Single();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSpecial => Album == 0;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
97
src/NzbDrone.Core/Parser/Model/ParsedTrackInfo.cs
Normal file
97
src/NzbDrone.Core/Parser/Model/ParsedTrackInfo.cs
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Parser.Model
|
||||||
|
{
|
||||||
|
public class ParsedTrackInfo
|
||||||
|
{
|
||||||
|
// [TODO]: Properly fill this out
|
||||||
|
public string ArtistTitle { get; set; }
|
||||||
|
public string AlbumTitle { get; set; }
|
||||||
|
public SeriesTitleInfo SeriesTitleInfo { get; set; }
|
||||||
|
public QualityModel Quality { get; set; }
|
||||||
|
public int SeasonNumber { get; set; }
|
||||||
|
public int[] EpisodeNumbers { get; set; }
|
||||||
|
public int[] AbsoluteEpisodeNumbers { get; set; }
|
||||||
|
public string AirDate { get; set; }
|
||||||
|
public Language Language { get; set; }
|
||||||
|
public bool FullSeason { get; set; }
|
||||||
|
public bool Special { get; set; }
|
||||||
|
public string ReleaseGroup { get; set; }
|
||||||
|
public string ReleaseHash { get; set; }
|
||||||
|
|
||||||
|
public ParsedTrackInfo()
|
||||||
|
{
|
||||||
|
EpisodeNumbers = new int[0];
|
||||||
|
AbsoluteEpisodeNumbers = new int[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsDaily
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return !string.IsNullOrWhiteSpace(AirDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
//This prevents manually downloading a release from blowing up in mono
|
||||||
|
//TODO: Is there a better way?
|
||||||
|
private set { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsAbsoluteNumbering
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return AbsoluteEpisodeNumbers.Any();
|
||||||
|
}
|
||||||
|
|
||||||
|
//This prevents manually downloading a release from blowing up in mono
|
||||||
|
//TODO: Is there a better way?
|
||||||
|
private set { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsPossibleSpecialEpisode
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
// if we don't have eny episode numbers we are likely a special episode and need to do a search by episode title
|
||||||
|
return (AirDate.IsNullOrWhiteSpace() &&
|
||||||
|
ArtistTitle.IsNullOrWhiteSpace() &&
|
||||||
|
(EpisodeNumbers.Length == 0 || SeasonNumber == 0) ||
|
||||||
|
!ArtistTitle.IsNullOrWhiteSpace() && Special);
|
||||||
|
}
|
||||||
|
|
||||||
|
//This prevents manually downloading a release from blowing up in mono
|
||||||
|
//TODO: Is there a better way?
|
||||||
|
private set { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
string episodeString = "[Unknown Episode]";
|
||||||
|
|
||||||
|
if (IsDaily && EpisodeNumbers.Empty())
|
||||||
|
{
|
||||||
|
episodeString = string.Format("{0}", AirDate);
|
||||||
|
}
|
||||||
|
else if (FullSeason)
|
||||||
|
{
|
||||||
|
episodeString = string.Format("Season {0:00}", SeasonNumber);
|
||||||
|
}
|
||||||
|
else if (EpisodeNumbers != null && EpisodeNumbers.Any())
|
||||||
|
{
|
||||||
|
episodeString = string.Format("S{0:00}E{1}", SeasonNumber, string.Join("-", EpisodeNumbers.Select(c => c.ToString("00"))));
|
||||||
|
}
|
||||||
|
else if (AbsoluteEpisodeNumbers != null && AbsoluteEpisodeNumbers.Any())
|
||||||
|
{
|
||||||
|
episodeString = string.Format("{0}", string.Join("-", AbsoluteEpisodeNumbers.Select(c => c.ToString("000"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Format("{0} - {1} {2}", ArtistTitle, episodeString, Quality);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -277,6 +277,27 @@ namespace NzbDrone.Core.Parser
|
||||||
|
|
||||||
private static readonly string[] Numbers = new[] { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
|
private static readonly string[] Numbers = new[] { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
|
||||||
|
|
||||||
|
public static ParsedTrackInfo ParseMusicPath(string path)
|
||||||
|
{
|
||||||
|
var fileInfo = new FileInfo(path);
|
||||||
|
|
||||||
|
var result = ParseMusicTitle(fileInfo.Name);
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
Logger.Debug("Attempting to parse track info using directory and file names. {0}", fileInfo.Directory.Name);
|
||||||
|
result = ParseMusicTitle(fileInfo.Directory.Name + " " + fileInfo.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
Logger.Debug("Attempting to parse track info using directory name. {0}", fileInfo.Directory.Name);
|
||||||
|
result = ParseMusicTitle(fileInfo.Directory.Name + fileInfo.Extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static ParsedEpisodeInfo ParsePath(string path)
|
public static ParsedEpisodeInfo ParsePath(string path)
|
||||||
{
|
{
|
||||||
var fileInfo = new FileInfo(path);
|
var fileInfo = new FileInfo(path);
|
||||||
|
@ -298,6 +319,116 @@ namespace NzbDrone.Core.Parser
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ParsedTrackInfo ParseMusicTitle(string title)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!ValidateBeforeParsing(title)) return null;
|
||||||
|
|
||||||
|
Logger.Debug("Parsing string '{0}'", title);
|
||||||
|
|
||||||
|
if (ReversedTitleRegex.IsMatch(title))
|
||||||
|
{
|
||||||
|
var titleWithoutExtension = RemoveFileExtension(title).ToCharArray();
|
||||||
|
Array.Reverse(titleWithoutExtension);
|
||||||
|
|
||||||
|
title = new string(titleWithoutExtension) + title.Substring(titleWithoutExtension.Length);
|
||||||
|
|
||||||
|
Logger.Debug("Reversed name detected. Converted to '{0}'", title);
|
||||||
|
}
|
||||||
|
|
||||||
|
var simpleTitle = SimpleTitleRegex.Replace(title, string.Empty);
|
||||||
|
|
||||||
|
simpleTitle = RemoveFileExtension(simpleTitle);
|
||||||
|
|
||||||
|
// TODO: Quick fix stripping [url] - prefixes.
|
||||||
|
simpleTitle = WebsitePrefixRegex.Replace(simpleTitle, string.Empty);
|
||||||
|
|
||||||
|
simpleTitle = CleanTorrentSuffixRegex.Replace(simpleTitle, string.Empty);
|
||||||
|
|
||||||
|
var airDateMatch = AirDateRegex.Match(simpleTitle);
|
||||||
|
if (airDateMatch.Success)
|
||||||
|
{
|
||||||
|
simpleTitle = airDateMatch.Groups[1].Value + airDateMatch.Groups["airyear"].Value + "." + airDateMatch.Groups["airmonth"].Value + "." + airDateMatch.Groups["airday"].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sixDigitAirDateMatch = SixDigitAirDateRegex.Match(simpleTitle);
|
||||||
|
if (sixDigitAirDateMatch.Success)
|
||||||
|
{
|
||||||
|
var airYear = sixDigitAirDateMatch.Groups["airyear"].Value;
|
||||||
|
var airMonth = sixDigitAirDateMatch.Groups["airmonth"].Value;
|
||||||
|
var airDay = sixDigitAirDateMatch.Groups["airday"].Value;
|
||||||
|
|
||||||
|
if (airMonth != "00" || airDay != "00")
|
||||||
|
{
|
||||||
|
var fixedDate = string.Format("20{0}.{1}.{2}", airYear, airMonth, airDay);
|
||||||
|
|
||||||
|
simpleTitle = simpleTitle.Replace(sixDigitAirDateMatch.Groups["airdate"].Value, fixedDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var regex in ReportTitleRegex)
|
||||||
|
{
|
||||||
|
var match = regex.Matches(simpleTitle);
|
||||||
|
|
||||||
|
if (match.Count != 0)
|
||||||
|
{
|
||||||
|
Logger.Trace(regex);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = ParseMatchMusicCollection(match);
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
if (result.FullSeason && title.ContainsIgnoreCase("Special"))
|
||||||
|
{
|
||||||
|
result.FullSeason = false;
|
||||||
|
result.Special = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Language = LanguageParser.ParseLanguage(title);
|
||||||
|
Logger.Debug("Language parsed: {0}", result.Language);
|
||||||
|
|
||||||
|
result.Quality = QualityParser.ParseQuality(title);
|
||||||
|
Logger.Debug("Quality parsed: {0}", result.Quality);
|
||||||
|
|
||||||
|
result.ReleaseGroup = ParseReleaseGroup(title);
|
||||||
|
|
||||||
|
var subGroup = GetSubGroup(match);
|
||||||
|
if (!subGroup.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
result.ReleaseGroup = subGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Debug("Release Group parsed: {0}", result.ReleaseGroup);
|
||||||
|
|
||||||
|
result.ReleaseHash = GetReleaseHash(match);
|
||||||
|
if (!result.ReleaseHash.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
Logger.Debug("Release Hash parsed: {0}", result.ReleaseHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (InvalidDateException ex)
|
||||||
|
{
|
||||||
|
Logger.Debug(ex, ex.Message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if (!title.ToLower().Contains("password") && !title.ToLower().Contains("yenc"))
|
||||||
|
Logger.Error(e, "An error has occurred while trying to parse {0}", title);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Debug("Unable to parse {0}", title);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public static ParsedEpisodeInfo ParseTitle(string title)
|
public static ParsedEpisodeInfo ParseTitle(string title)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -522,6 +653,10 @@ namespace NzbDrone.Core.Parser
|
||||||
return seriesTitleInfo;
|
return seriesTitleInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ParsedTrackInfo ParseMatchMusicCollection(MatchCollection matchCollection)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchCollection)
|
private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchCollection)
|
||||||
{
|
{
|
||||||
var seriesName = matchCollection[0].Groups["title"].Value.Replace('.', ' ').Replace('_', ' ');
|
var seriesName = matchCollection[0].Groups["title"].Value.Replace('.', ' ').Replace('_', ' ');
|
||||||
|
|
|
@ -8,6 +8,8 @@ using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
|
using NzbDrone.Core.Music;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Parser
|
namespace NzbDrone.Core.Parser
|
||||||
{
|
{
|
||||||
|
@ -20,13 +22,20 @@ namespace NzbDrone.Core.Parser
|
||||||
RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int seriesId, IEnumerable<int> episodeIds);
|
RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, int seriesId, IEnumerable<int> episodeIds);
|
||||||
List<Episode> GetEpisodes(ParsedEpisodeInfo parsedEpisodeInfo, Series series, bool sceneSource, SearchCriteriaBase searchCriteria = null);
|
List<Episode> GetEpisodes(ParsedEpisodeInfo parsedEpisodeInfo, Series series, bool sceneSource, SearchCriteriaBase searchCriteria = null);
|
||||||
ParsedEpisodeInfo ParseSpecialEpisodeTitle(string title, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null);
|
ParsedEpisodeInfo ParseSpecialEpisodeTitle(string title, int tvdbId, int tvRageId, SearchCriteriaBase searchCriteria = null);
|
||||||
|
|
||||||
|
// Music stuff here
|
||||||
|
LocalTrack GetLocalTrack(string filename, Artist artist);
|
||||||
|
LocalTrack GetLocalTrack(string filename, Artist artist, ParsedTrackInfo folderInfo, bool sceneSource);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ParsingService : IParsingService
|
public class ParsingService : IParsingService
|
||||||
{
|
{
|
||||||
private readonly IEpisodeService _episodeService;
|
private readonly IEpisodeService _episodeService;
|
||||||
private readonly ISeriesService _seriesService;
|
private readonly ISeriesService _seriesService;
|
||||||
// private readonly ISceneMappingService _sceneMappingService;
|
|
||||||
|
private readonly IArtistService _artistService;
|
||||||
|
private readonly ITrackService _trackService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public ParsingService(IEpisodeService episodeService,
|
public ParsingService(IEpisodeService episodeService,
|
||||||
|
@ -474,5 +483,89 @@ namespace NzbDrone.Core.Parser
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LocalTrack GetLocalTrack(string filename, Artist artist)
|
||||||
|
{
|
||||||
|
return GetLocalTrack(filename, artist, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalTrack GetLocalTrack(string filename, Artist artist, ParsedTrackInfo folderInfo, bool sceneSource)
|
||||||
|
{
|
||||||
|
ParsedTrackInfo parsedTrackInfo;
|
||||||
|
|
||||||
|
if (folderInfo != null)
|
||||||
|
{
|
||||||
|
parsedTrackInfo = folderInfo.JsonClone();
|
||||||
|
parsedTrackInfo.Quality = QualityParser.ParseQuality(Path.GetFileName(filename));
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parsedTrackInfo = Parser.ParseMusicPath(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsedTrackInfo == null || parsedTrackInfo.IsPossibleSpecialEpisode)
|
||||||
|
{
|
||||||
|
var title = Path.GetFileNameWithoutExtension(filename);
|
||||||
|
//var specialEpisodeInfo = ParseSpecialEpisodeTitle(title, series);
|
||||||
|
|
||||||
|
//if (specialEpisodeInfo != null)
|
||||||
|
//{
|
||||||
|
// parsedTrackInfo = specialEpisodeInfo;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsedTrackInfo == null)
|
||||||
|
{
|
||||||
|
if (MediaFileExtensions.Extensions.Contains(Path.GetExtension(filename)))
|
||||||
|
{
|
||||||
|
_logger.Warn("Unable to parse track info from path {0}", filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tracks = GetTracks(parsedTrackInfo, artist, sceneSource);
|
||||||
|
|
||||||
|
return new LocalTrack
|
||||||
|
{
|
||||||
|
Artist = artist,
|
||||||
|
Quality = parsedTrackInfo.Quality,
|
||||||
|
Tracks = tracks,
|
||||||
|
Path = filename,
|
||||||
|
ParsedTrackInfo = parsedTrackInfo,
|
||||||
|
ExistingFile = artist.Path.IsParentPath(filename)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Track> GetTracks(ParsedTrackInfo parsedTrackInfo, Artist artist, bool sceneSource)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
|
||||||
|
/*if (parsedTrackInfo.FullSeason) // IF Album
|
||||||
|
{
|
||||||
|
return _trackService.GetTracksByAlbumTitle(artist.Id, parsedTrackInfo.AlbumTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsedTrackInfo.IsDaily)
|
||||||
|
{
|
||||||
|
if (artist.SeriesType == SeriesTypes.Standard)
|
||||||
|
{
|
||||||
|
_logger.Warn("Found daily-style episode for non-daily series: {0}.", series);
|
||||||
|
return new List<Episode>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var episodeInfo = GetDailyEpisode(artist, parsedTrackInfo.AirDate, searchCriteria);
|
||||||
|
|
||||||
|
if (episodeInfo != null)
|
||||||
|
{
|
||||||
|
return new List<Episode> { episodeInfo };
|
||||||
|
}
|
||||||
|
|
||||||
|
return new List<Track>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetStandardEpisodes(artist, parsedTrackInfo, sceneSource, searchCriteria);*/
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
var Backbone = require('backbone');
|
var Backbone = require('backbone');
|
||||||
var SeriesModel = require('../Series/SeriesModel');
|
var ArtistModel = require('../Artist/ArtistModel');
|
||||||
var _ = require('underscore');
|
var _ = require('underscore');
|
||||||
|
|
||||||
module.exports = Backbone.Collection.extend({
|
module.exports = Backbone.Collection.extend({
|
||||||
url : window.NzbDrone.ApiRoot + '/series/lookup',
|
url : window.NzbDrone.ApiRoot + '/artist/lookup',
|
||||||
model : SeriesModel,
|
model : ArtistModel,
|
||||||
|
|
||||||
parse : function(response) {
|
parse : function(response) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -15,7 +15,9 @@ module.exports = Backbone.Collection.extend({
|
||||||
if (self.unmappedFolderModel) {
|
if (self.unmappedFolderModel) {
|
||||||
model.path = self.unmappedFolderModel.get('folder').path;
|
model.path = self.unmappedFolderModel.get('folder').path;
|
||||||
}
|
}
|
||||||
|
console.log('model: ', model);
|
||||||
});
|
});
|
||||||
|
console.log('response: ', response); // Note: this gets called after api responds with artist model
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
<div class="btn-group add-series-btn-group btn-group-lg btn-block">
|
<div class="btn-group add-series-btn-group btn-group-lg btn-block">
|
||||||
<button type="button" class="btn btn-default col-md-10 col-xs-8 add-series-import-btn x-import">
|
<button type="button" class="btn btn-default col-md-10 col-xs-8 add-series-import-btn x-import">
|
||||||
<i class="icon-sonarr-hdd"/>
|
<i class="icon-sonarr-hdd"/>
|
||||||
Import existing series on disk
|
Import existing artists on disk
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-default col-md-2 col-xs-4 x-add-new"><i class="icon-sonarr-active hidden-xs"></i> Add New Series</button>
|
<button class="btn btn-default col-md-2 col-xs-4 x-add-new"><i class="icon-sonarr-active hidden-xs"></i> Add New Artist</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -28,6 +28,7 @@ module.exports = Marionette.Layout.extend({
|
||||||
initialize : function(options) {
|
initialize : function(options) {
|
||||||
this.isExisting = options.isExisting;
|
this.isExisting = options.isExisting;
|
||||||
this.collection = new AddSeriesCollection();
|
this.collection = new AddSeriesCollection();
|
||||||
|
console.log('this.collection:', this.collection);
|
||||||
|
|
||||||
if (this.isExisting) {
|
if (this.isExisting) {
|
||||||
this.collection.unmappedFolderModel = this.model;
|
this.collection.unmappedFolderModel = this.model;
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
{{#if folder}}
|
{{#if folder}}
|
||||||
<input type="text" class="form-control x-series-search" value="{{folder.name}}">
|
<input type="text" class="form-control x-series-search" value="{{folder.name}}">
|
||||||
{{else}}
|
{{else}}
|
||||||
<input type="text" class="form-control x-series-search" placeholder="Start typing the name of series you want to add ...">
|
<input type="text" class="form-control x-series-search" placeholder="Start typing the name of music you want to add ...">
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
<div class="text-center hint col-md-12">
|
<div class="text-center hint col-md-12">
|
||||||
<span>You can also search by tvdbid using the tvdb: prefixes.</span>
|
<span>You can also search by iTunes using the itunes: prefixes.</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,5 +3,5 @@
|
||||||
There was an error searching for '{{term}}'.
|
There was an error searching for '{{term}}'.
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
If the series title contains non-alphanumeric characters try removing them, otherwise try your search again later.
|
If the artist name contains non-alphanumeric characters try removing them, otherwise try your search again later.
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div class="x-existing-folders">
|
<div class="x-existing-folders">
|
||||||
<div class="loading-folders x-loading-folders">
|
<div class="loading-folders x-loading-folders">
|
||||||
Loading search results from TheTVDB for your series, this may take a few minutes.
|
Loading search results from iTunes for your artists, this may take a few minutes.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -6,7 +6,8 @@ var Marionette = require('marionette');
|
||||||
var Profiles = require('../Profile/ProfileCollection');
|
var Profiles = require('../Profile/ProfileCollection');
|
||||||
var RootFolders = require('./RootFolders/RootFolderCollection');
|
var RootFolders = require('./RootFolders/RootFolderCollection');
|
||||||
var RootFolderLayout = require('./RootFolders/RootFolderLayout');
|
var RootFolderLayout = require('./RootFolders/RootFolderLayout');
|
||||||
var SeriesCollection = require('../Series/SeriesCollection');
|
//var SeriesCollection = require('../Series/SeriesCollection');
|
||||||
|
var SeriesCollection = require('../Artist/ArtistCollection');
|
||||||
var Config = require('../Config');
|
var Config = require('../Config');
|
||||||
var Messenger = require('../Shared/Messenger');
|
var Messenger = require('../Shared/Messenger');
|
||||||
var AsValidatedView = require('../Mixins/AsValidatedView');
|
var AsValidatedView = require('../Mixins/AsValidatedView');
|
||||||
|
@ -210,6 +211,7 @@ var view = Marionette.ItemView.extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
promise.done(function() {
|
promise.done(function() {
|
||||||
|
console.log('[SearchResultView] _addSeries promise resolve:', self.model);
|
||||||
SeriesCollection.add(self.model);
|
SeriesCollection.add(self.model);
|
||||||
|
|
||||||
self.close();
|
self.close();
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<h2 class="series-title">
|
<h2 class="series-title">
|
||||||
{{titleWithYear}}
|
{{titleWithYear}}
|
||||||
|
{{artistName}}
|
||||||
|
|
||||||
<span class="labels">
|
<span class="labels">
|
||||||
<span class="label label-default">{{network}}</span>
|
<span class="label label-default">{{network}}</span>
|
||||||
|
@ -41,8 +42,6 @@
|
||||||
<option value="future">Future</option>
|
<option value="future">Future</option>
|
||||||
<option value="missing">Missing</option>
|
<option value="missing">Missing</option>
|
||||||
<option value="existing">Existing</option>
|
<option value="existing">Existing</option>
|
||||||
<option value="first">First Season</option>
|
|
||||||
<option value="latest">Latest Season</option>
|
|
||||||
<option value="none">None</option>
|
<option value="none">None</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
@ -52,10 +51,9 @@
|
||||||
{{> ProfileSelectionPartial profiles}}
|
{{> ProfileSelectionPartial profiles}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group col-md-2">
|
<!--<div class="form-group col-md-2">
|
||||||
<label>Series Type</label>
|
|
||||||
{{> SeriesTypeSelectionPartial}}
|
</div>-->
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group col-md-2">
|
<div class="form-group col-md-2">
|
||||||
<label>Season Folders</label>
|
<label>Season Folders</label>
|
||||||
|
|
124
src/UI/Artist/ArtistCollection.js
Normal file
124
src/UI/Artist/ArtistCollection.js
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
var _ = require('underscore');
|
||||||
|
var Backbone = require('backbone');
|
||||||
|
var PageableCollection = require('backbone.pageable');
|
||||||
|
var ArtistModel = require('./ArtistModel');
|
||||||
|
var ApiData = require('../Shared/ApiData');
|
||||||
|
var AsFilteredCollection = require('../Mixins/AsFilteredCollection');
|
||||||
|
var AsSortedCollection = require('../Mixins/AsSortedCollection');
|
||||||
|
var AsPersistedStateCollection = require('../Mixins/AsPersistedStateCollection');
|
||||||
|
var moment = require('moment');
|
||||||
|
require('../Mixins/backbone.signalr.mixin');
|
||||||
|
|
||||||
|
var Collection = PageableCollection.extend({
|
||||||
|
url : window.NzbDrone.ApiRoot + '/artist',
|
||||||
|
model : ArtistModel,
|
||||||
|
tableName : 'artist',
|
||||||
|
|
||||||
|
state : {
|
||||||
|
sortKey : 'sortTitle',
|
||||||
|
order : -1,
|
||||||
|
pageSize : 100000,
|
||||||
|
secondarySortKey : 'sortTitle',
|
||||||
|
secondarySortOrder : -1
|
||||||
|
},
|
||||||
|
|
||||||
|
mode : 'client',
|
||||||
|
|
||||||
|
save : function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var proxy = _.extend(new Backbone.Model(), {
|
||||||
|
id : '',
|
||||||
|
|
||||||
|
url : self.url + '/editor',
|
||||||
|
|
||||||
|
toJSON : function() {
|
||||||
|
return self.filter(function(model) {
|
||||||
|
return model.edited;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.listenTo(proxy, 'sync', function(proxyModel, models) {
|
||||||
|
this.add(models, { merge : true });
|
||||||
|
this.trigger('save', this);
|
||||||
|
});
|
||||||
|
|
||||||
|
return proxy.save();
|
||||||
|
},
|
||||||
|
|
||||||
|
filterModes : {
|
||||||
|
'all' : [
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
],
|
||||||
|
'continuing' : [
|
||||||
|
'status',
|
||||||
|
'continuing'
|
||||||
|
],
|
||||||
|
'ended' : [
|
||||||
|
'status',
|
||||||
|
'ended'
|
||||||
|
],
|
||||||
|
'monitored' : [
|
||||||
|
'monitored',
|
||||||
|
true
|
||||||
|
],
|
||||||
|
'missing' : [
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
function(model) { return model.get('episodeCount') !== model.get('episodeFileCount'); }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
sortMappings : {
|
||||||
|
title : {
|
||||||
|
sortKey : 'sortTitle'
|
||||||
|
},
|
||||||
|
|
||||||
|
artistName: {
|
||||||
|
sortKey : 'artistName'
|
||||||
|
},
|
||||||
|
|
||||||
|
nextAiring : {
|
||||||
|
sortValue : function(model, attr, order) {
|
||||||
|
var nextAiring = model.get(attr);
|
||||||
|
|
||||||
|
if (nextAiring) {
|
||||||
|
return moment(nextAiring).unix();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (order === 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Number.MAX_VALUE;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
percentOfEpisodes : {
|
||||||
|
sortValue : function(model, attr) {
|
||||||
|
var percentOfEpisodes = model.get(attr);
|
||||||
|
var episodeCount = model.get('episodeCount');
|
||||||
|
|
||||||
|
return percentOfEpisodes + episodeCount / 1000000;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
path : {
|
||||||
|
sortValue : function(model) {
|
||||||
|
var path = model.get('path');
|
||||||
|
|
||||||
|
return path.toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Collection = AsFilteredCollection.call(Collection);
|
||||||
|
Collection = AsSortedCollection.call(Collection);
|
||||||
|
Collection = AsPersistedStateCollection.call(Collection);
|
||||||
|
|
||||||
|
var data = ApiData.get('series'); // TOOD: Build backend for artist
|
||||||
|
|
||||||
|
module.exports = new Collection(data, { full : true }).bindSignalR();
|
37
src/UI/Artist/ArtistController.js
Normal file
37
src/UI/Artist/ArtistController.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
var NzbDroneController = require('../Shared/NzbDroneController');
|
||||||
|
var AppLayout = require('../AppLayout');
|
||||||
|
var ArtistCollection = require('./ArtistCollection');
|
||||||
|
var SeriesIndexLayout = require('./Index/SeriesIndexLayout');
|
||||||
|
var SeriesDetailsLayout = require('../Series/Details/SeriesDetailsLayout');
|
||||||
|
|
||||||
|
module.exports = NzbDroneController.extend({
|
||||||
|
_originalInit : NzbDroneController.prototype.initialize,
|
||||||
|
|
||||||
|
initialize : function() {
|
||||||
|
this.route('', this.series);
|
||||||
|
this.route('artist', this.series);
|
||||||
|
this.route('artist/:query', this.seriesDetails);
|
||||||
|
|
||||||
|
this._originalInit.apply(this, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
artist : function() {
|
||||||
|
this.setTitle('Lidarr');
|
||||||
|
this.setArtistName('Lidarr');
|
||||||
|
this.showMainRegion(new SeriesIndexLayout());
|
||||||
|
},
|
||||||
|
|
||||||
|
seriesDetails : function(query) {
|
||||||
|
var artists = ArtistCollection.where({ artistNameSlug : query });
|
||||||
|
console.log('seriesDetails, artists: ', artists);
|
||||||
|
if (artists.length !== 0) {
|
||||||
|
var targetSeries = artists[0];
|
||||||
|
console.log("[ArtistController] targetSeries: ", targetSeries);
|
||||||
|
this.setTitle(targetSeries.get('title'));
|
||||||
|
this.setArtistName(targetSeries.get('artistName'));
|
||||||
|
this.showMainRegion(new SeriesDetailsLayout({ model : targetSeries }));
|
||||||
|
} else {
|
||||||
|
this.showNotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
31
src/UI/Artist/ArtistModel.js
Normal file
31
src/UI/Artist/ArtistModel.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
var Backbone = require('backbone');
|
||||||
|
var _ = require('underscore');
|
||||||
|
|
||||||
|
module.exports = Backbone.Model.extend({
|
||||||
|
urlRoot : window.NzbDrone.ApiRoot + '/artist',
|
||||||
|
|
||||||
|
defaults : {
|
||||||
|
episodeFileCount : 0,
|
||||||
|
episodeCount : 0,
|
||||||
|
isExisting : false,
|
||||||
|
status : 0
|
||||||
|
},
|
||||||
|
|
||||||
|
setAlbumsMonitored : function(seasonNumber) {
|
||||||
|
_.each(this.get('albums'), function(album) {
|
||||||
|
if (season.seasonNumber === seasonNumber) {
|
||||||
|
album.monitored = !album.monitored;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setAlbumPass : function(seasonNumber) {
|
||||||
|
_.each(this.get('albums'), function(album) {
|
||||||
|
if (album.seasonNumber >= seasonNumber) {
|
||||||
|
album.monitored = true;
|
||||||
|
} else {
|
||||||
|
album.monitored = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
|
@ -71,7 +71,7 @@ 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('titleWithYear', function() {
|
/*Handlebars.registerHelper('titleWithYear', function() {
|
||||||
if (this.title.endsWith(' ({0})'.format(this.year))) {
|
if (this.title.endsWith(' ({0})'.format(this.year))) {
|
||||||
return this.title;
|
return this.title;
|
||||||
}
|
}
|
||||||
|
@ -81,4 +81,4 @@ Handlebars.registerHelper('titleWithYear', function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Handlebars.SafeString('{0} <span class="year">({1})</span>'.format(this.title, this.year));
|
return new Handlebars.SafeString('{0} <span class="year">({1})</span>'.format(this.title, this.year));
|
||||||
});
|
});*/
|
||||||
|
|
|
@ -4,7 +4,7 @@ var vent = require('vent');
|
||||||
var reqres = require('../../reqres');
|
var reqres = require('../../reqres');
|
||||||
var Marionette = require('marionette');
|
var Marionette = require('marionette');
|
||||||
var Backbone = require('backbone');
|
var Backbone = require('backbone');
|
||||||
var SeriesCollection = require('../SeriesCollection');
|
var ArtistCollection = require('../../Artist/ArtistCollection');
|
||||||
var EpisodeCollection = require('../EpisodeCollection');
|
var EpisodeCollection = require('../EpisodeCollection');
|
||||||
var EpisodeFileCollection = require('../EpisodeFileCollection');
|
var EpisodeFileCollection = require('../EpisodeFileCollection');
|
||||||
var SeasonCollection = require('../SeasonCollection');
|
var SeasonCollection = require('../SeasonCollection');
|
||||||
|
@ -45,7 +45,7 @@ module.exports = Marionette.Layout.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize : function() {
|
initialize : function() {
|
||||||
this.seriesCollection = SeriesCollection.clone();
|
this.seriesCollection = ArtistCollection.clone();
|
||||||
this.seriesCollection.shadowCollection.bindSignalR();
|
this.seriesCollection.shadowCollection.bindSignalR();
|
||||||
|
|
||||||
this.listenTo(this.model, 'change:monitored', this._setMonitoredState);
|
this.listenTo(this.model, 'change:monitored', this._setMonitoredState);
|
||||||
|
@ -155,6 +155,7 @@ module.exports = Marionette.Layout.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
_seriesSearch : function() {
|
_seriesSearch : function() {
|
||||||
|
console.log('_seriesSearch:', this.model);
|
||||||
CommandController.Execute('seriesSearch', {
|
CommandController.Execute('seriesSearch', {
|
||||||
name : 'seriesSearch',
|
name : 'seriesSearch',
|
||||||
seriesId : this.model.id
|
seriesId : this.model.id
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue