mirror of
https://github.com/Readarr/Readarr.git
synced 2026-04-17 21:25:39 -04:00
New: Readarr 0.1
This commit is contained in:
@@ -9,9 +9,9 @@ namespace Readarr.Api.V1.Albums
|
||||
{
|
||||
public class AlbumLookupModule : ReadarrRestModule<AlbumResource>
|
||||
{
|
||||
private readonly ISearchForNewAlbum _searchProxy;
|
||||
private readonly ISearchForNewBook _searchProxy;
|
||||
|
||||
public AlbumLookupModule(ISearchForNewAlbum searchProxy)
|
||||
public AlbumLookupModule(ISearchForNewBook searchProxy)
|
||||
: base("/album/lookup")
|
||||
{
|
||||
_searchProxy = searchProxy;
|
||||
@@ -20,11 +20,11 @@ namespace Readarr.Api.V1.Albums
|
||||
|
||||
private object Search()
|
||||
{
|
||||
var searchResults = _searchProxy.SearchForNewAlbum((string)Request.Query.term, null);
|
||||
var searchResults = _searchProxy.SearchForNewBook((string)Request.Query.term, null);
|
||||
return MapToResource(searchResults).ToList();
|
||||
}
|
||||
|
||||
private static IEnumerable<AlbumResource> MapToResource(IEnumerable<NzbDrone.Core.Music.Album> albums)
|
||||
private static IEnumerable<AlbumResource> MapToResource(IEnumerable<NzbDrone.Core.Music.Book> albums)
|
||||
{
|
||||
foreach (var currentAlbum in albums)
|
||||
{
|
||||
|
||||
@@ -30,13 +30,11 @@ namespace Readarr.Api.V1.Albums
|
||||
IHandle<TrackFileDeletedEvent>
|
||||
{
|
||||
protected readonly IArtistService _artistService;
|
||||
protected readonly IReleaseService _releaseService;
|
||||
protected readonly IAddAlbumService _addAlbumService;
|
||||
|
||||
public AlbumModule(IArtistService artistService,
|
||||
IAlbumService albumService,
|
||||
IAddAlbumService addAlbumService,
|
||||
IReleaseService releaseService,
|
||||
IArtistStatisticsService artistStatisticsService,
|
||||
IMapCoversToLocal coverMapper,
|
||||
IUpgradableSpecification upgradableSpecification,
|
||||
@@ -47,7 +45,6 @@ namespace Readarr.Api.V1.Albums
|
||||
: base(albumService, artistStatisticsService, coverMapper, upgradableSpecification, signalRBroadcaster)
|
||||
{
|
||||
_artistService = artistService;
|
||||
_releaseService = releaseService;
|
||||
_addAlbumService = addAlbumService;
|
||||
|
||||
GetResourceAll = GetAlbums;
|
||||
@@ -56,78 +53,69 @@ namespace Readarr.Api.V1.Albums
|
||||
DeleteResource = DeleteAlbum;
|
||||
Put("/monitor", x => SetAlbumsMonitored());
|
||||
|
||||
PostValidator.RuleFor(s => s.ForeignAlbumId).NotEmpty();
|
||||
PostValidator.RuleFor(s => s.ForeignBookId).NotEmpty();
|
||||
PostValidator.RuleFor(s => s.Artist.QualityProfileId).SetValidator(qualityProfileExistsValidator);
|
||||
PostValidator.RuleFor(s => s.Artist.MetadataProfileId).SetValidator(metadataProfileExistsValidator);
|
||||
PostValidator.RuleFor(s => s.Artist.RootFolderPath).IsValidPath().When(s => s.Artist.Path.IsNullOrWhiteSpace());
|
||||
PostValidator.RuleFor(s => s.Artist.ForeignArtistId).NotEmpty();
|
||||
PostValidator.RuleFor(s => s.Artist.ForeignAuthorId).NotEmpty();
|
||||
}
|
||||
|
||||
private List<AlbumResource> GetAlbums()
|
||||
{
|
||||
var artistIdQuery = Request.Query.ArtistId;
|
||||
var albumIdsQuery = Request.Query.AlbumIds;
|
||||
var foreignIdQuery = Request.Query.ForeignAlbumId;
|
||||
var authorIdQuery = Request.Query.AuthorId;
|
||||
var bookIdsQuery = Request.Query.BookIds;
|
||||
var slugQuery = Request.Query.TitleSlug;
|
||||
var includeAllArtistAlbumsQuery = Request.Query.IncludeAllArtistAlbums;
|
||||
|
||||
if (!Request.Query.ArtistId.HasValue && !albumIdsQuery.HasValue && !foreignIdQuery.HasValue)
|
||||
if (!Request.Query.AuthorId.HasValue && !bookIdsQuery.HasValue && !slugQuery.HasValue)
|
||||
{
|
||||
var albums = _albumService.GetAllAlbums();
|
||||
|
||||
var artists = _artistService.GetAllArtists().ToDictionary(x => x.ArtistMetadataId);
|
||||
var releases = _releaseService.GetAllReleases().GroupBy(x => x.AlbumId).ToDictionary(x => x.Key, y => y.ToList());
|
||||
var artists = _artistService.GetAllArtists().ToDictionary(x => x.AuthorMetadataId);
|
||||
|
||||
foreach (var album in albums)
|
||||
{
|
||||
album.Artist = artists[album.ArtistMetadataId];
|
||||
if (releases.TryGetValue(album.Id, out var albumReleases))
|
||||
{
|
||||
album.AlbumReleases = albumReleases;
|
||||
}
|
||||
else
|
||||
{
|
||||
album.AlbumReleases = new List<AlbumRelease>();
|
||||
}
|
||||
album.Author = artists[album.AuthorMetadataId];
|
||||
}
|
||||
|
||||
return MapToResource(albums, false);
|
||||
}
|
||||
|
||||
if (artistIdQuery.HasValue)
|
||||
if (authorIdQuery.HasValue)
|
||||
{
|
||||
int artistId = Convert.ToInt32(artistIdQuery.Value);
|
||||
int authorId = Convert.ToInt32(authorIdQuery.Value);
|
||||
|
||||
return MapToResource(_albumService.GetAlbumsByArtist(artistId), false);
|
||||
return MapToResource(_albumService.GetAlbumsByArtist(authorId), false);
|
||||
}
|
||||
|
||||
if (foreignIdQuery.HasValue)
|
||||
if (slugQuery.HasValue)
|
||||
{
|
||||
string foreignAlbumId = foreignIdQuery.Value.ToString();
|
||||
string titleSlug = slugQuery.Value.ToString();
|
||||
|
||||
var album = _albumService.FindById(foreignAlbumId);
|
||||
var album = _albumService.FindBySlug(titleSlug);
|
||||
|
||||
if (album == null)
|
||||
{
|
||||
return MapToResource(new List<Album>(), false);
|
||||
return MapToResource(new List<Book>(), false);
|
||||
}
|
||||
|
||||
if (includeAllArtistAlbumsQuery.HasValue && Convert.ToBoolean(includeAllArtistAlbumsQuery.Value))
|
||||
{
|
||||
return MapToResource(_albumService.GetAlbumsByArtist(album.ArtistId), false);
|
||||
return MapToResource(_albumService.GetAlbumsByArtist(album.AuthorId), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
return MapToResource(new List<Album> { album }, false);
|
||||
return MapToResource(new List<Book> { album }, false);
|
||||
}
|
||||
}
|
||||
|
||||
string albumIdsValue = albumIdsQuery.Value.ToString();
|
||||
string bookIdsValue = bookIdsQuery.Value.ToString();
|
||||
|
||||
var albumIds = albumIdsValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
var bookIds = bookIdsValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(e => Convert.ToInt32(e))
|
||||
.ToList();
|
||||
|
||||
return MapToResource(_albumService.GetAlbums(albumIds), false);
|
||||
return MapToResource(_albumService.GetAlbums(bookIds), false);
|
||||
}
|
||||
|
||||
private int AddAlbum(AlbumResource albumResource)
|
||||
@@ -144,7 +132,6 @@ namespace Readarr.Api.V1.Albums
|
||||
var model = albumResource.ToModel(album);
|
||||
|
||||
_albumService.UpdateAlbum(model);
|
||||
_releaseService.UpdateMany(model.AlbumReleases.Value);
|
||||
|
||||
BroadcastResourceChange(ModelAction.Updated, model.Id);
|
||||
}
|
||||
@@ -161,9 +148,9 @@ namespace Readarr.Api.V1.Albums
|
||||
{
|
||||
var resource = Request.Body.FromJson<AlbumsMonitoredResource>();
|
||||
|
||||
_albumService.SetMonitored(resource.AlbumIds, resource.Monitored);
|
||||
_albumService.SetMonitored(resource.BookIds, resource.Monitored);
|
||||
|
||||
return ResponseWithCode(MapToResource(_albumService.GetAlbums(resource.AlbumIds), false), HttpStatusCode.Accepted);
|
||||
return ResponseWithCode(MapToResource(_albumService.GetAlbums(resource.BookIds), false), HttpStatusCode.Accepted);
|
||||
}
|
||||
|
||||
public void Handle(AlbumGrabbedEvent message)
|
||||
|
||||
@@ -11,7 +11,7 @@ using Readarr.Http;
|
||||
|
||||
namespace Readarr.Api.V1.Albums
|
||||
{
|
||||
public abstract class AlbumModuleWithSignalR : ReadarrRestModuleWithSignalR<AlbumResource, Album>
|
||||
public abstract class AlbumModuleWithSignalR : ReadarrRestModuleWithSignalR<AlbumResource, Book>
|
||||
{
|
||||
protected readonly IAlbumService _albumService;
|
||||
protected readonly IArtistStatisticsService _artistStatisticsService;
|
||||
@@ -56,13 +56,13 @@ namespace Readarr.Api.V1.Albums
|
||||
return resource;
|
||||
}
|
||||
|
||||
protected AlbumResource MapToResource(Album album, bool includeArtist)
|
||||
protected AlbumResource MapToResource(Book album, bool includeArtist)
|
||||
{
|
||||
var resource = album.ToResource();
|
||||
|
||||
if (includeArtist)
|
||||
{
|
||||
var artist = album.Artist.Value;
|
||||
var artist = album.Author.Value;
|
||||
|
||||
resource.Artist = artist.ToResource();
|
||||
}
|
||||
@@ -73,19 +73,19 @@ namespace Readarr.Api.V1.Albums
|
||||
return resource;
|
||||
}
|
||||
|
||||
protected List<AlbumResource> MapToResource(List<Album> albums, bool includeArtist)
|
||||
protected List<AlbumResource> MapToResource(List<Book> albums, bool includeArtist)
|
||||
{
|
||||
var result = albums.ToResource();
|
||||
|
||||
if (includeArtist)
|
||||
{
|
||||
var artistDict = new Dictionary<int, NzbDrone.Core.Music.Artist>();
|
||||
var artistDict = new Dictionary<int, NzbDrone.Core.Music.Author>();
|
||||
for (var i = 0; i < albums.Count; i++)
|
||||
{
|
||||
var album = albums[i];
|
||||
var resource = result[i];
|
||||
var artist = artistDict.GetValueOrDefault(albums[i].ArtistMetadataId) ?? album.Artist?.Value;
|
||||
artistDict[artist.ArtistMetadataId] = artist;
|
||||
var artist = artistDict.GetValueOrDefault(albums[i].AuthorMetadataId) ?? album.Author?.Value;
|
||||
artistDict[artist.AuthorMetadataId] = artist;
|
||||
|
||||
resource.Artist = artist.ToResource();
|
||||
}
|
||||
@@ -100,14 +100,14 @@ namespace Readarr.Api.V1.Albums
|
||||
|
||||
private void FetchAndLinkAlbumStatistics(AlbumResource resource)
|
||||
{
|
||||
LinkArtistStatistics(resource, _artistStatisticsService.ArtistStatistics(resource.ArtistId));
|
||||
LinkArtistStatistics(resource, _artistStatisticsService.ArtistStatistics(resource.AuthorId));
|
||||
}
|
||||
|
||||
private void LinkArtistStatistics(List<AlbumResource> resources, List<ArtistStatistics> artistStatistics)
|
||||
{
|
||||
foreach (var album in resources)
|
||||
{
|
||||
var stats = artistStatistics.SingleOrDefault(ss => ss.ArtistId == album.ArtistId);
|
||||
var stats = artistStatistics.SingleOrDefault(ss => ss.AuthorId == album.AuthorId);
|
||||
LinkArtistStatistics(album, stats);
|
||||
}
|
||||
}
|
||||
@@ -116,7 +116,7 @@ namespace Readarr.Api.V1.Albums
|
||||
{
|
||||
if (artistStatistics?.AlbumStatistics != null)
|
||||
{
|
||||
var dictAlbumStats = artistStatistics.AlbumStatistics.ToDictionary(v => v.AlbumId);
|
||||
var dictAlbumStats = artistStatistics.AlbumStatistics.ToDictionary(v => v.BookId);
|
||||
|
||||
resource.Statistics = dictAlbumStats.GetValueOrDefault(resource.Id).ToResource();
|
||||
}
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace Readarr.Api.V1.Albums
|
||||
{
|
||||
public class AlbumReleaseResource
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int AlbumId { get; set; }
|
||||
public string ForeignReleaseId { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Status { get; set; }
|
||||
public int Duration { get; set; }
|
||||
public int TrackCount { get; set; }
|
||||
public List<MediumResource> Media { get; set; }
|
||||
public int MediumCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Media == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Media.Where(s => s.MediumNumber > 0).Count();
|
||||
}
|
||||
}
|
||||
|
||||
public string Disambiguation { get; set; }
|
||||
public List<string> Country { get; set; }
|
||||
public List<string> Label { get; set; }
|
||||
public string Format { get; set; }
|
||||
public bool Monitored { get; set; }
|
||||
}
|
||||
|
||||
public static class AlbumReleaseResourceMapper
|
||||
{
|
||||
public static AlbumReleaseResource ToResource(this AlbumRelease model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new AlbumReleaseResource
|
||||
{
|
||||
Id = model.Id,
|
||||
AlbumId = model.AlbumId,
|
||||
ForeignReleaseId = model.ForeignReleaseId,
|
||||
Title = model.Title,
|
||||
Status = model.Status,
|
||||
Duration = model.Duration,
|
||||
TrackCount = model.TrackCount,
|
||||
Media = model.Media.ToResource(),
|
||||
Disambiguation = model.Disambiguation,
|
||||
Country = model.Country,
|
||||
Label = model.Label,
|
||||
Monitored = model.Monitored,
|
||||
Format = string.Join(", ",
|
||||
model.Media.OrderBy(x => x.Number)
|
||||
.GroupBy(x => x.Format)
|
||||
.Select(g => MediaFormatHelper(g.Key, g.Count()))
|
||||
.ToList())
|
||||
};
|
||||
}
|
||||
|
||||
public static AlbumRelease ToModel(this AlbumReleaseResource resource)
|
||||
{
|
||||
if (resource == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new AlbumRelease
|
||||
{
|
||||
Id = resource.Id,
|
||||
AlbumId = resource.AlbumId,
|
||||
ForeignReleaseId = resource.ForeignReleaseId,
|
||||
Title = resource.Title,
|
||||
Status = resource.Status,
|
||||
Duration = resource.Duration,
|
||||
Label = resource.Label,
|
||||
Disambiguation = resource.Disambiguation,
|
||||
Country = resource.Country,
|
||||
Media = resource.Media.ToModel(),
|
||||
TrackCount = resource.TrackCount,
|
||||
Monitored = resource.Monitored
|
||||
};
|
||||
}
|
||||
|
||||
private static string MediaFormatHelper(string name, int count)
|
||||
{
|
||||
return count == 1 ? name : string.Join("x", new List<string> { count.ToString(), name });
|
||||
}
|
||||
|
||||
public static List<AlbumReleaseResource> ToResource(this IEnumerable<AlbumRelease> models)
|
||||
{
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
|
||||
public static List<AlbumRelease> ToModel(this IEnumerable<AlbumReleaseResource> resources)
|
||||
{
|
||||
return resources.Select(ToModel).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using Newtonsoft.Json;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.Music;
|
||||
using Readarr.Api.V1.Artist;
|
||||
using Readarr.Api.V1.TrackFiles;
|
||||
using Readarr.Http.REST;
|
||||
|
||||
namespace Readarr.Api.V1.Albums
|
||||
@@ -14,32 +15,18 @@ namespace Readarr.Api.V1.Albums
|
||||
public string Title { get; set; }
|
||||
public string Disambiguation { get; set; }
|
||||
public string Overview { get; set; }
|
||||
public int ArtistId { get; set; }
|
||||
public string ForeignAlbumId { get; set; }
|
||||
public string Publisher { get; set; }
|
||||
public string Language { get; set; }
|
||||
public int AuthorId { get; set; }
|
||||
public string ForeignBookId { get; set; }
|
||||
public int GoodreadsId { get; set; }
|
||||
public string TitleSlug { get; set; }
|
||||
public string Isbn { get; set; }
|
||||
public string Asin { get; set; }
|
||||
public bool Monitored { get; set; }
|
||||
public bool AnyReleaseOk { get; set; }
|
||||
public int ProfileId { get; set; }
|
||||
public int Duration { get; set; }
|
||||
public string AlbumType { get; set; }
|
||||
public List<string> SecondaryTypes { get; set; }
|
||||
public int MediumCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Media == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Media.Where(s => s.MediumNumber > 0).Count();
|
||||
}
|
||||
}
|
||||
|
||||
public Ratings Ratings { get; set; }
|
||||
public DateTime? ReleaseDate { get; set; }
|
||||
public List<AlbumReleaseResource> Releases { get; set; }
|
||||
public List<string> Genres { get; set; }
|
||||
public List<MediumResource> Media { get; set; }
|
||||
public ArtistResource Artist { get; set; }
|
||||
public List<MediaCover> Images { get; set; }
|
||||
public List<Links> Links { get; set; }
|
||||
@@ -54,83 +41,82 @@ namespace Readarr.Api.V1.Albums
|
||||
|
||||
public static class AlbumResourceMapper
|
||||
{
|
||||
public static AlbumResource ToResource(this Album model)
|
||||
public static AlbumResource ToResource(this Book model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var selectedRelease = model.AlbumReleases?.Value.Where(x => x.Monitored).SingleOrDefault();
|
||||
|
||||
return new AlbumResource
|
||||
{
|
||||
Id = model.Id,
|
||||
ArtistId = model.ArtistId,
|
||||
ForeignAlbumId = model.ForeignAlbumId,
|
||||
ProfileId = model.ProfileId,
|
||||
AuthorId = model.AuthorId,
|
||||
ForeignBookId = model.ForeignBookId,
|
||||
GoodreadsId = model.GoodreadsId,
|
||||
TitleSlug = model.TitleSlug,
|
||||
Asin = model.Asin,
|
||||
Isbn = model.Isbn13,
|
||||
Monitored = model.Monitored,
|
||||
AnyReleaseOk = model.AnyReleaseOk,
|
||||
ReleaseDate = model.ReleaseDate,
|
||||
Genres = model.Genres,
|
||||
Title = model.Title,
|
||||
Disambiguation = model.Disambiguation,
|
||||
Overview = model.Overview,
|
||||
Publisher = model.Publisher,
|
||||
Language = model.Language,
|
||||
Images = model.Images,
|
||||
Links = model.Links,
|
||||
Ratings = model.Ratings,
|
||||
Duration = selectedRelease?.Duration ?? 0,
|
||||
AlbumType = model.AlbumType,
|
||||
SecondaryTypes = model.SecondaryTypes.Select(s => s.Name).ToList(),
|
||||
Releases = model.AlbumReleases?.Value.ToResource() ?? new List<AlbumReleaseResource>(),
|
||||
Media = selectedRelease?.Media.ToResource() ?? new List<MediumResource>(),
|
||||
Artist = model.Artist?.Value.ToResource()
|
||||
Artist = model.Author?.Value.ToResource()
|
||||
};
|
||||
}
|
||||
|
||||
public static Album ToModel(this AlbumResource resource)
|
||||
public static Book ToModel(this AlbumResource resource)
|
||||
{
|
||||
if (resource == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var artist = resource.Artist?.ToModel() ?? new NzbDrone.Core.Music.Artist();
|
||||
var artist = resource.Artist?.ToModel() ?? new NzbDrone.Core.Music.Author();
|
||||
|
||||
return new Album
|
||||
return new Book
|
||||
{
|
||||
Id = resource.Id,
|
||||
ForeignAlbumId = resource.ForeignAlbumId,
|
||||
ForeignBookId = resource.ForeignBookId,
|
||||
GoodreadsId = resource.GoodreadsId,
|
||||
TitleSlug = resource.TitleSlug,
|
||||
Asin = resource.Asin,
|
||||
Isbn13 = resource.Isbn,
|
||||
Title = resource.Title,
|
||||
Disambiguation = resource.Disambiguation,
|
||||
Overview = resource.Overview,
|
||||
Publisher = resource.Publisher,
|
||||
Language = resource.Language,
|
||||
Images = resource.Images,
|
||||
AlbumType = resource.AlbumType,
|
||||
Monitored = resource.Monitored,
|
||||
AnyReleaseOk = resource.AnyReleaseOk,
|
||||
AlbumReleases = resource.Releases.ToModel(),
|
||||
AddOptions = resource.AddOptions,
|
||||
Artist = artist,
|
||||
ArtistMetadata = artist.Metadata.Value
|
||||
Author = artist,
|
||||
AuthorMetadata = artist.Metadata.Value
|
||||
};
|
||||
}
|
||||
|
||||
public static Album ToModel(this AlbumResource resource, Album album)
|
||||
public static Book ToModel(this AlbumResource resource, Book album)
|
||||
{
|
||||
var updatedAlbum = resource.ToModel();
|
||||
|
||||
album.ApplyChanges(updatedAlbum);
|
||||
album.AlbumReleases = updatedAlbum.AlbumReleases;
|
||||
|
||||
return album;
|
||||
}
|
||||
|
||||
public static List<AlbumResource> ToResource(this IEnumerable<Album> models)
|
||||
public static List<AlbumResource> ToResource(this IEnumerable<Book> models)
|
||||
{
|
||||
return models?.Select(ToResource).ToList();
|
||||
}
|
||||
|
||||
public static List<Album> ToModel(this IEnumerable<AlbumResource> resources)
|
||||
public static List<Book> ToModel(this IEnumerable<AlbumResource> resources)
|
||||
{
|
||||
return resources.Select(ToModel).ToList();
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Readarr.Api.V1.Albums
|
||||
{
|
||||
public class AlbumsMonitoredResource
|
||||
{
|
||||
public List<int> AlbumIds { get; set; }
|
||||
public List<int> BookIds { get; set; }
|
||||
public bool Monitored { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace Readarr.Api.V1.Albums
|
||||
{
|
||||
public class MediumResource
|
||||
{
|
||||
public int MediumNumber { get; set; }
|
||||
public string MediumName { get; set; }
|
||||
public string MediumFormat { get; set; }
|
||||
}
|
||||
|
||||
public static class MediumResourceMapper
|
||||
{
|
||||
public static MediumResource ToResource(this Medium model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new MediumResource
|
||||
{
|
||||
MediumNumber = model.Number,
|
||||
MediumName = model.Name,
|
||||
MediumFormat = model.Format
|
||||
};
|
||||
}
|
||||
|
||||
public static Medium ToModel(this MediumResource resource)
|
||||
{
|
||||
if (resource == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Medium
|
||||
{
|
||||
Number = resource.MediumNumber,
|
||||
Name = resource.MediumName,
|
||||
Format = resource.MediumFormat
|
||||
};
|
||||
}
|
||||
|
||||
public static List<MediumResource> ToResource(this IEnumerable<Medium> models)
|
||||
{
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
|
||||
public static List<Medium> ToModel(this IEnumerable<MediumResource> resources)
|
||||
{
|
||||
return resources.Select(ToModel).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using NzbDrone.Core.MediaFiles;
|
||||
using Readarr.Http;
|
||||
using Readarr.Http.REST;
|
||||
|
||||
namespace Readarr.Api.V1.Tracks
|
||||
namespace Readarr.Api.V1.Albums
|
||||
{
|
||||
public class RenameTrackModule : ReadarrRestModule<RenameTrackResource>
|
||||
{
|
||||
@@ -19,24 +19,24 @@ namespace Readarr.Api.V1.Tracks
|
||||
|
||||
private List<RenameTrackResource> GetTracks()
|
||||
{
|
||||
int artistId;
|
||||
int authorId;
|
||||
|
||||
if (Request.Query.ArtistId.HasValue)
|
||||
if (Request.Query.AuthorId.HasValue)
|
||||
{
|
||||
artistId = (int)Request.Query.ArtistId;
|
||||
authorId = (int)Request.Query.AuthorId;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BadRequestException("artistId is missing");
|
||||
throw new BadRequestException("authorId is missing");
|
||||
}
|
||||
|
||||
if (Request.Query.albumId.HasValue)
|
||||
if (Request.Query.bookId.HasValue)
|
||||
{
|
||||
var albumId = (int)Request.Query.albumId;
|
||||
return _renameTrackFileService.GetRenamePreviews(artistId, albumId).ToResource();
|
||||
var bookId = (int)Request.Query.bookId;
|
||||
return _renameTrackFileService.GetRenamePreviews(authorId, bookId).ToResource();
|
||||
}
|
||||
|
||||
return _renameTrackFileService.GetRenamePreviews(artistId).ToResource();
|
||||
return _renameTrackFileService.GetRenamePreviews(authorId).ToResource();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,12 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Readarr.Http.REST;
|
||||
|
||||
namespace Readarr.Api.V1.Tracks
|
||||
namespace Readarr.Api.V1.Albums
|
||||
{
|
||||
public class RenameTrackResource : RestResource
|
||||
{
|
||||
public int ArtistId { get; set; }
|
||||
public int AlbumId { get; set; }
|
||||
public List<int> TrackNumbers { get; set; }
|
||||
public int AuthorId { get; set; }
|
||||
public int BookId { get; set; }
|
||||
public int TrackFileId { get; set; }
|
||||
public string ExistingPath { get; set; }
|
||||
public string NewPath { get; set; }
|
||||
@@ -25,9 +24,8 @@ namespace Readarr.Api.V1.Tracks
|
||||
|
||||
return new RenameTrackResource
|
||||
{
|
||||
ArtistId = model.ArtistId,
|
||||
AlbumId = model.AlbumId,
|
||||
TrackNumbers = model.TrackNumbers.ToList(),
|
||||
AuthorId = model.AuthorId,
|
||||
BookId = model.BookId,
|
||||
TrackFileId = model.TrackFileId,
|
||||
ExistingPath = model.ExistingPath,
|
||||
NewPath = model.NewPath
|
||||
@@ -4,7 +4,7 @@ using NzbDrone.Core.MediaFiles;
|
||||
using Readarr.Http;
|
||||
using Readarr.Http.REST;
|
||||
|
||||
namespace Readarr.Api.V1.Tracks
|
||||
namespace Readarr.Api.V1.Albums
|
||||
{
|
||||
public class RetagTrackModule : ReadarrRestModule<RetagTrackResource>
|
||||
{
|
||||
@@ -20,19 +20,19 @@ namespace Readarr.Api.V1.Tracks
|
||||
|
||||
private List<RetagTrackResource> GetTracks()
|
||||
{
|
||||
if (Request.Query.albumId.HasValue)
|
||||
if (Request.Query.bookId.HasValue)
|
||||
{
|
||||
var albumId = (int)Request.Query.albumId;
|
||||
return _audioTagService.GetRetagPreviewsByAlbum(albumId).Where(x => x.Changes.Any()).ToResource();
|
||||
var bookId = (int)Request.Query.bookId;
|
||||
return _audioTagService.GetRetagPreviewsByAlbum(bookId).Where(x => x.Changes.Any()).ToResource();
|
||||
}
|
||||
else if (Request.Query.ArtistId.HasValue)
|
||||
else if (Request.Query.AuthorId.HasValue)
|
||||
{
|
||||
var artistId = (int)Request.Query.ArtistId;
|
||||
return _audioTagService.GetRetagPreviewsByArtist(artistId).Where(x => x.Changes.Any()).ToResource();
|
||||
var authorId = (int)Request.Query.AuthorId;
|
||||
return _audioTagService.GetRetagPreviewsByArtist(authorId).Where(x => x.Changes.Any()).ToResource();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BadRequestException("One of artistId or albumId must be specified");
|
||||
throw new BadRequestException("One of authorId or bookId must be specified");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Readarr.Http.REST;
|
||||
|
||||
namespace Readarr.Api.V1.Tracks
|
||||
namespace Readarr.Api.V1.Albums
|
||||
{
|
||||
public class TagDifference
|
||||
{
|
||||
@@ -13,8 +13,8 @@ namespace Readarr.Api.V1.Tracks
|
||||
|
||||
public class RetagTrackResource : RestResource
|
||||
{
|
||||
public int ArtistId { get; set; }
|
||||
public int AlbumId { get; set; }
|
||||
public int AuthorId { get; set; }
|
||||
public int BookId { get; set; }
|
||||
public List<int> TrackNumbers { get; set; }
|
||||
public int TrackFileId { get; set; }
|
||||
public string Path { get; set; }
|
||||
@@ -32,8 +32,8 @@ namespace Readarr.Api.V1.Tracks
|
||||
|
||||
return new RetagTrackResource
|
||||
{
|
||||
ArtistId = model.ArtistId,
|
||||
AlbumId = model.AlbumId,
|
||||
AuthorId = model.AuthorId,
|
||||
BookId = model.BookId,
|
||||
TrackNumbers = model.TrackNumbers.ToList(),
|
||||
TrackFileId = model.TrackFileId,
|
||||
Path = model.Path,
|
||||
@@ -4,7 +4,7 @@ namespace Readarr.Api.V1.Artist
|
||||
{
|
||||
public class ArtistEditorDeleteResource
|
||||
{
|
||||
public List<int> ArtistIds { get; set; }
|
||||
public List<int> AuthorIds { get; set; }
|
||||
public bool DeleteFiles { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Readarr.Api.V1.Artist
|
||||
private object SaveAll()
|
||||
{
|
||||
var resource = Request.Body.FromJson<ArtistEditorResource>();
|
||||
var artistToUpdate = _artistService.GetArtists(resource.ArtistIds);
|
||||
var artistToUpdate = _artistService.GetArtists(resource.AuthorIds);
|
||||
var artistToMove = new List<BulkMoveArtist>();
|
||||
|
||||
foreach (var artist in artistToUpdate)
|
||||
@@ -46,17 +46,12 @@ namespace Readarr.Api.V1.Artist
|
||||
artist.MetadataProfileId = resource.MetadataProfileId.Value;
|
||||
}
|
||||
|
||||
if (resource.AlbumFolder.HasValue)
|
||||
{
|
||||
artist.AlbumFolder = resource.AlbumFolder.Value;
|
||||
}
|
||||
|
||||
if (resource.RootFolderPath.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
artist.RootFolderPath = resource.RootFolderPath;
|
||||
artistToMove.Add(new BulkMoveArtist
|
||||
{
|
||||
ArtistId = artist.Id,
|
||||
AuthorId = artist.Id,
|
||||
SourcePath = artist.Path
|
||||
});
|
||||
}
|
||||
@@ -99,9 +94,9 @@ namespace Readarr.Api.V1.Artist
|
||||
{
|
||||
var resource = Request.Body.FromJson<ArtistEditorResource>();
|
||||
|
||||
foreach (var artistId in resource.ArtistIds)
|
||||
foreach (var authorId in resource.AuthorIds)
|
||||
{
|
||||
_artistService.DeleteArtist(artistId, false);
|
||||
_artistService.DeleteArtist(authorId, false);
|
||||
}
|
||||
|
||||
return new object();
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Readarr.Api.V1.Artist
|
||||
{
|
||||
public class ArtistEditorResource
|
||||
{
|
||||
public List<int> ArtistIds { get; set; }
|
||||
public List<int> AuthorIds { get; set; }
|
||||
public bool? Monitored { get; set; }
|
||||
public int? QualityProfileId { get; set; }
|
||||
public int? MetadataProfileId { get; set; }
|
||||
|
||||
@@ -9,9 +9,9 @@ namespace Readarr.Api.V1.Artist
|
||||
{
|
||||
public class ArtistLookupModule : ReadarrRestModule<ArtistResource>
|
||||
{
|
||||
private readonly ISearchForNewArtist _searchProxy;
|
||||
private readonly ISearchForNewAuthor _searchProxy;
|
||||
|
||||
public ArtistLookupModule(ISearchForNewArtist searchProxy)
|
||||
public ArtistLookupModule(ISearchForNewAuthor searchProxy)
|
||||
: base("/artist/lookup")
|
||||
{
|
||||
_searchProxy = searchProxy;
|
||||
@@ -20,11 +20,11 @@ namespace Readarr.Api.V1.Artist
|
||||
|
||||
private object Search()
|
||||
{
|
||||
var searchResults = _searchProxy.SearchForNewArtist((string)Request.Query.term);
|
||||
var searchResults = _searchProxy.SearchForNewAuthor((string)Request.Query.term);
|
||||
return MapToResource(searchResults).ToList();
|
||||
}
|
||||
|
||||
private static IEnumerable<ArtistResource> MapToResource(IEnumerable<NzbDrone.Core.Music.Artist> artist)
|
||||
private static IEnumerable<ArtistResource> MapToResource(IEnumerable<NzbDrone.Core.Music.Author> artist)
|
||||
{
|
||||
foreach (var currentArtist in artist)
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@ using Readarr.Http.Extensions;
|
||||
|
||||
namespace Readarr.Api.V1.Artist
|
||||
{
|
||||
public class ArtistModule : ReadarrRestModuleWithSignalR<ArtistResource, NzbDrone.Core.Music.Artist>,
|
||||
public class ArtistModule : ReadarrRestModuleWithSignalR<ArtistResource, NzbDrone.Core.Music.Author>,
|
||||
IHandle<AlbumImportedEvent>,
|
||||
IHandle<AlbumEditedEvent>,
|
||||
IHandle<TrackFileDeletedEvent>,
|
||||
@@ -91,7 +91,7 @@ namespace Readarr.Api.V1.Artist
|
||||
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.ArtistName).NotEmpty();
|
||||
PostValidator.RuleFor(s => s.ForeignArtistId).NotEmpty().SetValidator(artistExistsValidator);
|
||||
PostValidator.RuleFor(s => s.ForeignAuthorId).NotEmpty().SetValidator(artistExistsValidator);
|
||||
|
||||
PutValidator.RuleFor(s => s.Path).IsValidPath();
|
||||
}
|
||||
@@ -102,7 +102,7 @@ namespace Readarr.Api.V1.Artist
|
||||
return GetArtistResource(artist);
|
||||
}
|
||||
|
||||
private ArtistResource GetArtistResource(NzbDrone.Core.Music.Artist artist)
|
||||
private ArtistResource GetArtistResource(NzbDrone.Core.Music.Author artist)
|
||||
{
|
||||
if (artist == null)
|
||||
{
|
||||
@@ -152,7 +152,7 @@ namespace Readarr.Api.V1.Artist
|
||||
|
||||
_commandQueueManager.Push(new MoveArtistCommand
|
||||
{
|
||||
ArtistId = artist.Id,
|
||||
AuthorId = artist.Id,
|
||||
SourcePath = sourcePath,
|
||||
DestinationPath = destinationPath,
|
||||
Trigger = CommandTrigger.Manual
|
||||
@@ -189,8 +189,8 @@ namespace Readarr.Api.V1.Artist
|
||||
|
||||
foreach (var artistResource in artists)
|
||||
{
|
||||
artistResource.NextAlbum = nextAlbums.FirstOrDefault(x => x.ArtistMetadataId == artistResource.ArtistMetadataId);
|
||||
artistResource.LastAlbum = lastAlbums.FirstOrDefault(x => x.ArtistMetadataId == artistResource.ArtistMetadataId);
|
||||
artistResource.NextAlbum = nextAlbums.FirstOrDefault(x => x.AuthorMetadataId == artistResource.ArtistMetadataId);
|
||||
artistResource.LastAlbum = lastAlbums.FirstOrDefault(x => x.AuthorMetadataId == artistResource.ArtistMetadataId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ namespace Readarr.Api.V1.Artist
|
||||
{
|
||||
foreach (var artist in resources)
|
||||
{
|
||||
var stats = artistStatistics.SingleOrDefault(ss => ss.ArtistId == artist.Id);
|
||||
var stats = artistStatistics.SingleOrDefault(ss => ss.AuthorId == artist.Id);
|
||||
if (stats == null)
|
||||
{
|
||||
continue;
|
||||
@@ -246,7 +246,7 @@ namespace Readarr.Api.V1.Artist
|
||||
|
||||
public void Handle(AlbumEditedEvent message)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Updated, GetArtistResource(message.Album.Artist.Value));
|
||||
BroadcastResourceChange(ModelAction.Updated, GetArtistResource(message.Album.Author.Value));
|
||||
}
|
||||
|
||||
public void Handle(TrackFileDeletedEvent message)
|
||||
|
||||
@@ -21,21 +21,18 @@ namespace Readarr.Api.V1.Artist
|
||||
public bool Ended => Status == ArtistStatusType.Ended;
|
||||
|
||||
public string ArtistName { get; set; }
|
||||
public string ForeignArtistId { get; set; }
|
||||
public string MBId { get; set; }
|
||||
public int TADBId { get; set; }
|
||||
public int DiscogsId { get; set; }
|
||||
public string AllMusicId { get; set; }
|
||||
public string ForeignAuthorId { get; set; }
|
||||
public int GoodreadsId { get; set; }
|
||||
public string TitleSlug { get; set; }
|
||||
public string Overview { get; set; }
|
||||
public string ArtistType { get; set; }
|
||||
public string Disambiguation { get; set; }
|
||||
public List<Links> Links { get; set; }
|
||||
|
||||
public Album NextAlbum { get; set; }
|
||||
public Album LastAlbum { get; set; }
|
||||
public Book NextAlbum { get; set; }
|
||||
public Book LastAlbum { get; set; }
|
||||
|
||||
public List<MediaCover> Images { get; set; }
|
||||
public List<Member> Members { get; set; }
|
||||
|
||||
public string RemotePoster { get; set; }
|
||||
|
||||
@@ -62,7 +59,7 @@ namespace Readarr.Api.V1.Artist
|
||||
|
||||
public static class ArtistResourceMapper
|
||||
{
|
||||
public static ArtistResource ToResource(this NzbDrone.Core.Music.Artist model)
|
||||
public static ArtistResource ToResource(this NzbDrone.Core.Music.Author model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
@@ -72,7 +69,7 @@ namespace Readarr.Api.V1.Artist
|
||||
return new ArtistResource
|
||||
{
|
||||
Id = model.Id,
|
||||
ArtistMetadataId = model.ArtistMetadataId,
|
||||
ArtistMetadataId = model.AuthorMetadataId,
|
||||
|
||||
ArtistName = model.Name,
|
||||
|
||||
@@ -91,11 +88,12 @@ namespace Readarr.Api.V1.Artist
|
||||
MetadataProfileId = model.MetadataProfileId,
|
||||
Links = model.Metadata.Value.Links,
|
||||
|
||||
AlbumFolder = model.AlbumFolder,
|
||||
Monitored = model.Monitored,
|
||||
|
||||
CleanName = model.CleanName,
|
||||
ForeignArtistId = model.Metadata.Value.ForeignArtistId,
|
||||
ForeignAuthorId = model.Metadata.Value.ForeignAuthorId,
|
||||
GoodreadsId = model.Metadata.Value.GoodreadsId,
|
||||
TitleSlug = model.Metadata.Value.TitleSlug,
|
||||
|
||||
// Root folder path is now calculated from the artist path
|
||||
// RootFolderPath = model.RootFolderPath,
|
||||
@@ -109,20 +107,22 @@ namespace Readarr.Api.V1.Artist
|
||||
};
|
||||
}
|
||||
|
||||
public static NzbDrone.Core.Music.Artist ToModel(this ArtistResource resource)
|
||||
public static NzbDrone.Core.Music.Author ToModel(this ArtistResource resource)
|
||||
{
|
||||
if (resource == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new NzbDrone.Core.Music.Artist
|
||||
return new NzbDrone.Core.Music.Author
|
||||
{
|
||||
Id = resource.Id,
|
||||
|
||||
Metadata = new NzbDrone.Core.Music.ArtistMetadata
|
||||
Metadata = new NzbDrone.Core.Music.AuthorMetadata
|
||||
{
|
||||
ForeignArtistId = resource.ForeignArtistId,
|
||||
ForeignAuthorId = resource.ForeignAuthorId,
|
||||
GoodreadsId = resource.GoodreadsId,
|
||||
TitleSlug = resource.TitleSlug,
|
||||
Name = resource.ArtistName,
|
||||
Status = resource.Status,
|
||||
Overview = resource.Overview,
|
||||
@@ -139,7 +139,6 @@ namespace Readarr.Api.V1.Artist
|
||||
QualityProfileId = resource.QualityProfileId,
|
||||
MetadataProfileId = resource.MetadataProfileId,
|
||||
|
||||
AlbumFolder = resource.AlbumFolder,
|
||||
Monitored = resource.Monitored,
|
||||
|
||||
CleanName = resource.CleanName,
|
||||
@@ -151,7 +150,7 @@ namespace Readarr.Api.V1.Artist
|
||||
};
|
||||
}
|
||||
|
||||
public static NzbDrone.Core.Music.Artist ToModel(this ArtistResource resource, NzbDrone.Core.Music.Artist artist)
|
||||
public static NzbDrone.Core.Music.Author ToModel(this ArtistResource resource, NzbDrone.Core.Music.Author artist)
|
||||
{
|
||||
var updatedArtist = resource.ToModel();
|
||||
|
||||
@@ -160,12 +159,12 @@ namespace Readarr.Api.V1.Artist
|
||||
return artist;
|
||||
}
|
||||
|
||||
public static List<ArtistResource> ToResource(this IEnumerable<NzbDrone.Core.Music.Artist> artist)
|
||||
public static List<ArtistResource> ToResource(this IEnumerable<NzbDrone.Core.Music.Author> artist)
|
||||
{
|
||||
return artist.Select(ToResource).ToList();
|
||||
}
|
||||
|
||||
public static List<NzbDrone.Core.Music.Artist> ToModel(this IEnumerable<ArtistResource> resources)
|
||||
public static List<NzbDrone.Core.Music.Author> ToModel(this IEnumerable<ArtistResource> resources)
|
||||
{
|
||||
return resources.Select(ToModel).ToList();
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ namespace Readarr.Api.V1.Blacklist
|
||||
{
|
||||
public class BlacklistResource : RestResource
|
||||
{
|
||||
public int ArtistId { get; set; }
|
||||
public List<int> AlbumIds { get; set; }
|
||||
public int AuthorId { get; set; }
|
||||
public List<int> BookIds { get; set; }
|
||||
public string SourceTitle { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
@@ -34,8 +34,8 @@ namespace Readarr.Api.V1.Blacklist
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
ArtistId = model.ArtistId,
|
||||
AlbumIds = model.AlbumIds,
|
||||
AuthorId = model.AuthorId,
|
||||
BookIds = model.BookIds,
|
||||
SourceTitle = model.SourceTitle,
|
||||
Quality = model.Quality,
|
||||
Date = model.Date,
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace Readarr.Api.V1.Calendar
|
||||
var albums = _albumService.AlbumsBetweenDates(start, end, unmonitored);
|
||||
var calendar = new Ical.Net.Calendar
|
||||
{
|
||||
ProductId = "-//readarr.audio//Readarr//EN"
|
||||
ProductId = "-//readarr.com//Readarr//EN"
|
||||
};
|
||||
|
||||
var calendarName = "Readarr Music Schedule";
|
||||
@@ -73,7 +73,7 @@ namespace Readarr.Api.V1.Calendar
|
||||
|
||||
foreach (var album in albums.OrderBy(v => v.ReleaseDate.Value))
|
||||
{
|
||||
var artist = _artistService.GetArtist(album.ArtistId); // Temp fix TODO: Figure out why Album.Artist is not populated during AlbumsBetweenDates Query
|
||||
var artist = _artistService.GetArtist(album.AuthorId); // Temp fix TODO: Figure out why Album.Artist is not populated during AlbumsBetweenDates Query
|
||||
|
||||
if (tags.Any() && tags.None(artist.Tags.Contains))
|
||||
{
|
||||
|
||||
@@ -17,9 +17,9 @@ namespace Readarr.Api.V1.Config
|
||||
private readonly IBuildFileNames _filenameBuilder;
|
||||
|
||||
public NamingConfigModule(INamingConfigService namingConfigService,
|
||||
IFilenameSampleService filenameSampleService,
|
||||
IFilenameValidationService filenameValidationService,
|
||||
IBuildFileNames filenameBuilder)
|
||||
IFilenameSampleService filenameSampleService,
|
||||
IFilenameValidationService filenameValidationService,
|
||||
IBuildFileNames filenameBuilder)
|
||||
: base("config/naming")
|
||||
{
|
||||
_namingConfigService = namingConfigService;
|
||||
@@ -33,9 +33,7 @@ namespace Readarr.Api.V1.Config
|
||||
Get("/examples", x => GetExamples(this.Bind<NamingConfigResource>()));
|
||||
|
||||
SharedValidator.RuleFor(c => c.StandardTrackFormat).ValidTrackFormat();
|
||||
SharedValidator.RuleFor(c => c.MultiDiscTrackFormat).ValidTrackFormat();
|
||||
SharedValidator.RuleFor(c => c.ArtistFolderFormat).ValidArtistFolderFormat();
|
||||
SharedValidator.RuleFor(c => c.AlbumFolderFormat).ValidAlbumFolderFormat();
|
||||
}
|
||||
|
||||
private void UpdateNamingConfig(NamingConfigResource resource)
|
||||
@@ -57,12 +55,6 @@ namespace Readarr.Api.V1.Config
|
||||
basicConfig.AddToResource(resource);
|
||||
}
|
||||
|
||||
if (resource.MultiDiscTrackFormat.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
var basicConfig = _filenameBuilder.GetBasicNamingConfig(nameSpec);
|
||||
basicConfig.AddToResource(resource);
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
@@ -82,24 +74,15 @@ namespace Readarr.Api.V1.Config
|
||||
var sampleResource = new NamingExampleResource();
|
||||
|
||||
var singleTrackSampleResult = _filenameSampleService.GetStandardTrackSample(nameSpec);
|
||||
var multiDiscTrackSampleResult = _filenameSampleService.GetMultiDiscTrackSample(nameSpec);
|
||||
|
||||
sampleResource.SingleTrackExample = _filenameValidationService.ValidateTrackFilename(singleTrackSampleResult) != null
|
||||
? null
|
||||
: singleTrackSampleResult.FileName;
|
||||
|
||||
sampleResource.MultiDiscTrackExample = _filenameValidationService.ValidateTrackFilename(multiDiscTrackSampleResult) != null
|
||||
? null
|
||||
: multiDiscTrackSampleResult.FileName;
|
||||
|
||||
sampleResource.ArtistFolderExample = nameSpec.ArtistFolderFormat.IsNullOrWhiteSpace()
|
||||
? null
|
||||
: _filenameSampleService.GetArtistFolderSample(nameSpec);
|
||||
|
||||
sampleResource.AlbumFolderExample = nameSpec.AlbumFolderFormat.IsNullOrWhiteSpace()
|
||||
? null
|
||||
: _filenameSampleService.GetAlbumFolderSample(nameSpec);
|
||||
|
||||
return sampleResource;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,9 +7,7 @@ namespace Readarr.Api.V1.Config
|
||||
public bool RenameTracks { get; set; }
|
||||
public bool ReplaceIllegalCharacters { get; set; }
|
||||
public string StandardTrackFormat { get; set; }
|
||||
public string MultiDiscTrackFormat { get; set; }
|
||||
public string ArtistFolderFormat { get; set; }
|
||||
public string AlbumFolderFormat { get; set; }
|
||||
public bool IncludeArtistName { get; set; }
|
||||
public bool IncludeAlbumTitle { get; set; }
|
||||
public bool IncludeQuality { get; set; }
|
||||
|
||||
@@ -5,9 +5,7 @@ namespace Readarr.Api.V1.Config
|
||||
public class NamingExampleResource
|
||||
{
|
||||
public string SingleTrackExample { get; set; }
|
||||
public string MultiDiscTrackExample { get; set; }
|
||||
public string ArtistFolderExample { get; set; }
|
||||
public string AlbumFolderExample { get; set; }
|
||||
}
|
||||
|
||||
public static class NamingConfigResourceMapper
|
||||
@@ -21,9 +19,7 @@ namespace Readarr.Api.V1.Config
|
||||
RenameTracks = model.RenameTracks,
|
||||
ReplaceIllegalCharacters = model.ReplaceIllegalCharacters,
|
||||
StandardTrackFormat = model.StandardTrackFormat,
|
||||
MultiDiscTrackFormat = model.MultiDiscTrackFormat,
|
||||
ArtistFolderFormat = model.ArtistFolderFormat,
|
||||
AlbumFolderFormat = model.AlbumFolderFormat
|
||||
ArtistFolderFormat = model.ArtistFolderFormat
|
||||
};
|
||||
}
|
||||
|
||||
@@ -46,10 +42,7 @@ namespace Readarr.Api.V1.Config
|
||||
RenameTracks = resource.RenameTracks,
|
||||
ReplaceIllegalCharacters = resource.ReplaceIllegalCharacters,
|
||||
StandardTrackFormat = resource.StandardTrackFormat,
|
||||
MultiDiscTrackFormat = resource.MultiDiscTrackFormat,
|
||||
|
||||
ArtistFolderFormat = resource.ArtistFolderFormat,
|
||||
AlbumFolderFormat = resource.AlbumFolderFormat
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.History;
|
||||
using Readarr.Api.V1.Albums;
|
||||
using Readarr.Api.V1.Artist;
|
||||
using Readarr.Api.V1.Tracks;
|
||||
using Readarr.Http;
|
||||
using Readarr.Http.Extensions;
|
||||
using Readarr.Http.REST;
|
||||
@@ -35,7 +34,7 @@ namespace Readarr.Api.V1.History
|
||||
Post("/failed", x => MarkAsFailed());
|
||||
}
|
||||
|
||||
protected HistoryResource MapToResource(NzbDrone.Core.History.History model, bool includeArtist, bool includeAlbum, bool includeTrack)
|
||||
protected HistoryResource MapToResource(NzbDrone.Core.History.History model, bool includeArtist, bool includeAlbum)
|
||||
{
|
||||
var resource = model.ToResource();
|
||||
|
||||
@@ -49,11 +48,6 @@ namespace Readarr.Api.V1.History
|
||||
resource.Album = model.Album.ToResource();
|
||||
}
|
||||
|
||||
if (includeTrack)
|
||||
{
|
||||
resource.Track = model.Track.ToResource();
|
||||
}
|
||||
|
||||
if (model.Artist != null)
|
||||
{
|
||||
resource.QualityCutoffNotMet = _upgradableSpecification.QualityCutoffNotMet(model.Artist.QualityProfile.Value, model.Quality);
|
||||
@@ -67,10 +61,9 @@ namespace Readarr.Api.V1.History
|
||||
var pagingSpec = pagingResource.MapToPagingSpec<HistoryResource, NzbDrone.Core.History.History>("date", SortDirection.Descending);
|
||||
var includeArtist = Request.GetBooleanQueryParameter("includeArtist");
|
||||
var includeAlbum = Request.GetBooleanQueryParameter("includeAlbum");
|
||||
var includeTrack = Request.GetBooleanQueryParameter("includeTrack");
|
||||
|
||||
var eventTypeFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "eventType");
|
||||
var albumIdFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "albumId");
|
||||
var bookIdFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "bookId");
|
||||
var downloadIdFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "downloadId");
|
||||
|
||||
if (eventTypeFilter != null)
|
||||
@@ -79,10 +72,10 @@ namespace Readarr.Api.V1.History
|
||||
pagingSpec.FilterExpressions.Add(v => v.EventType == filterValue);
|
||||
}
|
||||
|
||||
if (albumIdFilter != null)
|
||||
if (bookIdFilter != null)
|
||||
{
|
||||
var albumId = Convert.ToInt32(albumIdFilter.Value);
|
||||
pagingSpec.FilterExpressions.Add(h => h.AlbumId == albumId);
|
||||
var bookId = Convert.ToInt32(bookIdFilter.Value);
|
||||
pagingSpec.FilterExpressions.Add(h => h.BookId == bookId);
|
||||
}
|
||||
|
||||
if (downloadIdFilter != null)
|
||||
@@ -91,7 +84,7 @@ namespace Readarr.Api.V1.History
|
||||
pagingSpec.FilterExpressions.Add(h => h.DownloadId == downloadId);
|
||||
}
|
||||
|
||||
return ApplyToPage(_historyService.Paged, pagingSpec, h => MapToResource(h, includeArtist, includeAlbum, includeTrack));
|
||||
return ApplyToPage(_historyService.Paged, pagingSpec, h => MapToResource(h, includeArtist, includeAlbum));
|
||||
}
|
||||
|
||||
private List<HistoryResource> GetHistorySince()
|
||||
@@ -108,46 +101,44 @@ namespace Readarr.Api.V1.History
|
||||
HistoryEventType? eventType = null;
|
||||
var includeArtist = Request.GetBooleanQueryParameter("includeArtist");
|
||||
var includeAlbum = Request.GetBooleanQueryParameter("includeAlbum");
|
||||
var includeTrack = Request.GetBooleanQueryParameter("includeTrack");
|
||||
|
||||
if (queryEventType.HasValue)
|
||||
{
|
||||
eventType = (HistoryEventType)Convert.ToInt32(queryEventType.Value);
|
||||
}
|
||||
|
||||
return _historyService.Since(date, eventType).Select(h => MapToResource(h, includeArtist, includeAlbum, includeTrack)).ToList();
|
||||
return _historyService.Since(date, eventType).Select(h => MapToResource(h, includeArtist, includeAlbum)).ToList();
|
||||
}
|
||||
|
||||
private List<HistoryResource> GetArtistHistory()
|
||||
{
|
||||
var queryArtistId = Request.Query.ArtistId;
|
||||
var queryAlbumId = Request.Query.AlbumId;
|
||||
var queryAuthorId = Request.Query.AuthorId;
|
||||
var queryBookId = Request.Query.BookId;
|
||||
var queryEventType = Request.Query.EventType;
|
||||
|
||||
if (!queryArtistId.HasValue)
|
||||
if (!queryAuthorId.HasValue)
|
||||
{
|
||||
throw new BadRequestException("artistId is missing");
|
||||
throw new BadRequestException("authorId is missing");
|
||||
}
|
||||
|
||||
int artistId = Convert.ToInt32(queryArtistId.Value);
|
||||
int authorId = Convert.ToInt32(queryAuthorId.Value);
|
||||
HistoryEventType? eventType = null;
|
||||
var includeArtist = Request.GetBooleanQueryParameter("includeArtist");
|
||||
var includeAlbum = Request.GetBooleanQueryParameter("includeAlbum");
|
||||
var includeTrack = Request.GetBooleanQueryParameter("includeTrack");
|
||||
|
||||
if (queryEventType.HasValue)
|
||||
{
|
||||
eventType = (HistoryEventType)Convert.ToInt32(queryEventType.Value);
|
||||
}
|
||||
|
||||
if (queryAlbumId.HasValue)
|
||||
if (queryBookId.HasValue)
|
||||
{
|
||||
int albumId = Convert.ToInt32(queryAlbumId.Value);
|
||||
int bookId = Convert.ToInt32(queryBookId.Value);
|
||||
|
||||
return _historyService.GetByAlbum(albumId, eventType).Select(h => MapToResource(h, includeArtist, includeAlbum, includeTrack)).ToList();
|
||||
return _historyService.GetByAlbum(bookId, eventType).Select(h => MapToResource(h, includeArtist, includeAlbum)).ToList();
|
||||
}
|
||||
|
||||
return _historyService.GetByArtist(artistId, eventType).Select(h => MapToResource(h, includeArtist, includeAlbum, includeTrack)).ToList();
|
||||
return _historyService.GetByArtist(authorId, eventType).Select(h => MapToResource(h, includeArtist, includeAlbum)).ToList();
|
||||
}
|
||||
|
||||
private object MarkAsFailed()
|
||||
|
||||
@@ -4,16 +4,14 @@ using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using Readarr.Api.V1.Albums;
|
||||
using Readarr.Api.V1.Artist;
|
||||
using Readarr.Api.V1.Tracks;
|
||||
using Readarr.Http.REST;
|
||||
|
||||
namespace Readarr.Api.V1.History
|
||||
{
|
||||
public class HistoryResource : RestResource
|
||||
{
|
||||
public int AlbumId { get; set; }
|
||||
public int ArtistId { get; set; }
|
||||
public int TrackId { get; set; }
|
||||
public int BookId { get; set; }
|
||||
public int AuthorId { get; set; }
|
||||
public string SourceTitle { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public bool QualityCutoffNotMet { get; set; }
|
||||
@@ -26,7 +24,6 @@ namespace Readarr.Api.V1.History
|
||||
|
||||
public AlbumResource Album { get; set; }
|
||||
public ArtistResource Artist { get; set; }
|
||||
public TrackResource Track { get; set; }
|
||||
}
|
||||
|
||||
public static class HistoryResourceMapper
|
||||
@@ -42,9 +39,8 @@ namespace Readarr.Api.V1.History
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
AlbumId = model.AlbumId,
|
||||
ArtistId = model.ArtistId,
|
||||
TrackId = model.TrackId,
|
||||
BookId = model.BookId,
|
||||
AuthorId = model.AuthorId,
|
||||
SourceTitle = model.SourceTitle,
|
||||
Quality = model.Quality,
|
||||
|
||||
|
||||
@@ -76,24 +76,24 @@ namespace Readarr.Api.V1.Indexers
|
||||
|
||||
private List<ReleaseResource> GetReleases()
|
||||
{
|
||||
if (Request.Query.albumId.HasValue)
|
||||
if (Request.Query.bookId.HasValue)
|
||||
{
|
||||
return GetAlbumReleases(Request.Query.albumId);
|
||||
return GetAlbumReleases(Request.Query.bookId);
|
||||
}
|
||||
|
||||
if (Request.Query.artistId.HasValue)
|
||||
if (Request.Query.authorId.HasValue)
|
||||
{
|
||||
return GetArtistReleases(Request.Query.artistId);
|
||||
return GetArtistReleases(Request.Query.authorId);
|
||||
}
|
||||
|
||||
return GetRss();
|
||||
}
|
||||
|
||||
private List<ReleaseResource> GetAlbumReleases(int albumId)
|
||||
private List<ReleaseResource> GetAlbumReleases(int bookId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var decisions = _nzbSearchService.AlbumSearch(albumId, true, true, true);
|
||||
var decisions = _nzbSearchService.AlbumSearch(bookId, true, true, true);
|
||||
var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(decisions);
|
||||
|
||||
return MapDecisions(prioritizedDecisions);
|
||||
@@ -106,11 +106,11 @@ namespace Readarr.Api.V1.Indexers
|
||||
return new List<ReleaseResource>();
|
||||
}
|
||||
|
||||
private List<ReleaseResource> GetArtistReleases(int artistId)
|
||||
private List<ReleaseResource> GetArtistReleases(int authorId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var decisions = _nzbSearchService.ArtistSearch(artistId, false, true, true);
|
||||
var decisions = _nzbSearchService.ArtistSearch(authorId, false, true, true);
|
||||
var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(decisions);
|
||||
|
||||
return MapDecisions(prioritizedDecisions);
|
||||
|
||||
@@ -52,12 +52,12 @@ namespace Readarr.Api.V1.Indexers
|
||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
|
||||
// [JsonIgnore]
|
||||
public int? ArtistId { get; set; }
|
||||
public int? AuthorId { get; set; }
|
||||
|
||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
|
||||
// [JsonIgnore]
|
||||
public int? AlbumId { get; set; }
|
||||
public int? BookId { get; set; }
|
||||
}
|
||||
|
||||
public static class ReleaseResourceMapper
|
||||
|
||||
@@ -15,19 +15,16 @@ namespace Readarr.Api.V1.ManualImport
|
||||
{
|
||||
private readonly IArtistService _artistService;
|
||||
private readonly IAlbumService _albumService;
|
||||
private readonly IReleaseService _releaseService;
|
||||
private readonly IManualImportService _manualImportService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public ManualImportModule(IManualImportService manualImportService,
|
||||
IArtistService artistService,
|
||||
IAlbumService albumService,
|
||||
IReleaseService releaseService,
|
||||
Logger logger)
|
||||
{
|
||||
_artistService = artistService;
|
||||
_albumService = albumService;
|
||||
_releaseService = releaseService;
|
||||
_manualImportService = manualImportService;
|
||||
_logger = logger;
|
||||
|
||||
@@ -75,12 +72,10 @@ namespace Readarr.Api.V1.ManualImport
|
||||
Size = resource.Size,
|
||||
Artist = resource.Artist == null ? null : _artistService.GetArtist(resource.Artist.Id),
|
||||
Album = resource.Album == null ? null : _albumService.GetAlbum(resource.Album.Id),
|
||||
Release = resource.AlbumReleaseId == 0 ? null : _releaseService.GetRelease(resource.AlbumReleaseId),
|
||||
Quality = resource.Quality,
|
||||
DownloadId = resource.DownloadId,
|
||||
AdditionalFile = resource.AdditionalFile,
|
||||
ReplaceExistingFiles = resource.ReplaceExistingFiles,
|
||||
DisableReleaseSwitching = resource.DisableReleaseSwitching
|
||||
ReplaceExistingFiles = resource.ReplaceExistingFiles
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using Readarr.Api.V1.Albums;
|
||||
using Readarr.Api.V1.Artist;
|
||||
using Readarr.Api.V1.Tracks;
|
||||
using Readarr.Http.REST;
|
||||
|
||||
namespace Readarr.Api.V1.ManualImport
|
||||
@@ -18,8 +17,6 @@ namespace Readarr.Api.V1.ManualImport
|
||||
public long Size { get; set; }
|
||||
public ArtistResource Artist { get; set; }
|
||||
public AlbumResource Album { get; set; }
|
||||
public int AlbumReleaseId { get; set; }
|
||||
public List<TrackResource> Tracks { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public int QualityWeight { get; set; }
|
||||
public string DownloadId { get; set; }
|
||||
@@ -27,7 +24,6 @@ namespace Readarr.Api.V1.ManualImport
|
||||
public ParsedTrackInfo AudioTags { get; set; }
|
||||
public bool AdditionalFile { get; set; }
|
||||
public bool ReplaceExistingFiles { get; set; }
|
||||
public bool DisableReleaseSwitching { get; set; }
|
||||
}
|
||||
|
||||
public static class ManualImportResourceMapper
|
||||
@@ -47,8 +43,6 @@ namespace Readarr.Api.V1.ManualImport
|
||||
Size = model.Size,
|
||||
Artist = model.Artist.ToResource(),
|
||||
Album = model.Album.ToResource(),
|
||||
AlbumReleaseId = model.Release?.Id ?? 0,
|
||||
Tracks = model.Tracks.ToResource(),
|
||||
Quality = model.Quality,
|
||||
|
||||
//QualityWeight
|
||||
@@ -56,8 +50,7 @@ namespace Readarr.Api.V1.ManualImport
|
||||
Rejections = model.Rejections,
|
||||
AudioTags = model.Tags,
|
||||
AdditionalFile = model.AdditionalFile,
|
||||
ReplaceExistingFiles = model.ReplaceExistingFiles,
|
||||
DisableReleaseSwitching = model.DisableReleaseSwitching
|
||||
ReplaceExistingFiles = model.ReplaceExistingFiles
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ namespace Readarr.Api.V1.MediaCovers
|
||||
{
|
||||
public class MediaCoverModule : ReadarrV1Module
|
||||
{
|
||||
private const string MEDIA_COVER_ARTIST_ROUTE = @"/Artist/(?<artistId>\d+)/(?<filename>(.+)\.(jpg|png|gif))";
|
||||
private const string MEDIA_COVER_ALBUM_ROUTE = @"/Album/(?<artistId>\d+)/(?<filename>(.+)\.(jpg|png|gif))";
|
||||
private const string MEDIA_COVER_ARTIST_ROUTE = @"/Artist/(?<authorId>\d+)/(?<filename>(.+)\.(jpg|png|gif))";
|
||||
private const string MEDIA_COVER_ALBUM_ROUTE = @"/Album/(?<authorId>\d+)/(?<filename>(.+)\.(jpg|png|gif))";
|
||||
|
||||
private static readonly Regex RegexResizedImage = new Regex(@"-\d+(?=\.(jpg|png|gif)$)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
@@ -24,13 +24,13 @@ namespace Readarr.Api.V1.MediaCovers
|
||||
_appFolderInfo = appFolderInfo;
|
||||
_diskProvider = diskProvider;
|
||||
|
||||
Get(MEDIA_COVER_ARTIST_ROUTE, options => GetArtistMediaCover(options.artistId, options.filename));
|
||||
Get(MEDIA_COVER_ALBUM_ROUTE, options => GetAlbumMediaCover(options.artistId, options.filename));
|
||||
Get(MEDIA_COVER_ARTIST_ROUTE, options => GetArtistMediaCover(options.authorId, options.filename));
|
||||
Get(MEDIA_COVER_ALBUM_ROUTE, options => GetAlbumMediaCover(options.authorId, options.filename));
|
||||
}
|
||||
|
||||
private object GetArtistMediaCover(int artistId, string filename)
|
||||
private object GetArtistMediaCover(int authorId, string filename)
|
||||
{
|
||||
var filePath = Path.Combine(_appFolderInfo.GetAppDataPath(), "MediaCover", artistId.ToString(), filename);
|
||||
var filePath = Path.Combine(_appFolderInfo.GetAppDataPath(), "MediaCover", authorId.ToString(), filename);
|
||||
|
||||
if (!_diskProvider.FileExists(filePath) || _diskProvider.GetFileSize(filePath) == 0)
|
||||
{
|
||||
@@ -48,9 +48,9 @@ namespace Readarr.Api.V1.MediaCovers
|
||||
return new StreamResponse(() => File.OpenRead(filePath), MimeTypes.GetMimeType(filePath));
|
||||
}
|
||||
|
||||
private object GetAlbumMediaCover(int albumId, string filename)
|
||||
private object GetAlbumMediaCover(int bookId, string filename)
|
||||
{
|
||||
var filePath = Path.Combine(_appFolderInfo.GetAppDataPath(), "MediaCover", "Albums", albumId.ToString(), filename);
|
||||
var filePath = Path.Combine(_appFolderInfo.GetAppDataPath(), "MediaCover", "Albums", bookId.ToString(), filename);
|
||||
|
||||
if (!_diskProvider.FileExists(filePath) || _diskProvider.GetFileSize(filePath) == 0)
|
||||
{
|
||||
|
||||
@@ -13,9 +13,6 @@ namespace Readarr.Api.V1.Profiles.Metadata
|
||||
{
|
||||
_profileService = profileService;
|
||||
SharedValidator.RuleFor(c => c.Name).NotEqual("None").WithMessage("'None' is a reserved profile name").NotEmpty();
|
||||
SharedValidator.RuleFor(c => c.PrimaryAlbumTypes).MustHaveAllowedPrimaryType();
|
||||
SharedValidator.RuleFor(c => c.SecondaryAlbumTypes).MustHaveAllowedSecondaryType();
|
||||
SharedValidator.RuleFor(c => c.ReleaseStatuses).MustHaveAllowedReleaseStatus();
|
||||
|
||||
GetResourceAll = GetAll;
|
||||
GetResourceById = GetById;
|
||||
|
||||
@@ -8,27 +8,13 @@ namespace Readarr.Api.V1.Profiles.Metadata
|
||||
public class MetadataProfileResource : RestResource
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public List<ProfilePrimaryAlbumTypeItemResource> PrimaryAlbumTypes { get; set; }
|
||||
public List<ProfileSecondaryAlbumTypeItemResource> SecondaryAlbumTypes { get; set; }
|
||||
public List<ProfileReleaseStatusItemResource> ReleaseStatuses { get; set; }
|
||||
}
|
||||
|
||||
public class ProfilePrimaryAlbumTypeItemResource : RestResource
|
||||
{
|
||||
public NzbDrone.Core.Music.PrimaryAlbumType AlbumType { get; set; }
|
||||
public bool Allowed { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileSecondaryAlbumTypeItemResource : RestResource
|
||||
{
|
||||
public NzbDrone.Core.Music.SecondaryAlbumType AlbumType { get; set; }
|
||||
public bool Allowed { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileReleaseStatusItemResource : RestResource
|
||||
{
|
||||
public NzbDrone.Core.Music.ReleaseStatus ReleaseStatus { get; set; }
|
||||
public bool Allowed { get; set; }
|
||||
public double MinRating { get; set; }
|
||||
public int MinRatingCount { get; set; }
|
||||
public bool SkipMissingDate { get; set; }
|
||||
public bool SkipMissingIsbn { get; set; }
|
||||
public bool SkipPartsAndSets { get; set; }
|
||||
public bool SkipSeriesSecondary { get; set; }
|
||||
public string AllowedLanguages { get; set; }
|
||||
}
|
||||
|
||||
public static class MetadataProfileResourceMapper
|
||||
@@ -44,51 +30,13 @@ namespace Readarr.Api.V1.Profiles.Metadata
|
||||
{
|
||||
Id = model.Id,
|
||||
Name = model.Name,
|
||||
PrimaryAlbumTypes = model.PrimaryAlbumTypes.ConvertAll(ToResource),
|
||||
SecondaryAlbumTypes = model.SecondaryAlbumTypes.ConvertAll(ToResource),
|
||||
ReleaseStatuses = model.ReleaseStatuses.ConvertAll(ToResource)
|
||||
};
|
||||
}
|
||||
|
||||
public static ProfilePrimaryAlbumTypeItemResource ToResource(this ProfilePrimaryAlbumTypeItem model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ProfilePrimaryAlbumTypeItemResource
|
||||
{
|
||||
AlbumType = model.PrimaryAlbumType,
|
||||
Allowed = model.Allowed
|
||||
};
|
||||
}
|
||||
|
||||
public static ProfileSecondaryAlbumTypeItemResource ToResource(this ProfileSecondaryAlbumTypeItem model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ProfileSecondaryAlbumTypeItemResource
|
||||
{
|
||||
AlbumType = model.SecondaryAlbumType,
|
||||
Allowed = model.Allowed
|
||||
};
|
||||
}
|
||||
|
||||
public static ProfileReleaseStatusItemResource ToResource(this ProfileReleaseStatusItem model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ProfileReleaseStatusItemResource
|
||||
{
|
||||
ReleaseStatus = model.ReleaseStatus,
|
||||
Allowed = model.Allowed
|
||||
MinRating = model.MinRating,
|
||||
MinRatingCount = model.MinRatingCount,
|
||||
SkipMissingDate = model.SkipMissingDate,
|
||||
SkipMissingIsbn = model.SkipMissingIsbn,
|
||||
SkipPartsAndSets = model.SkipPartsAndSets,
|
||||
SkipSeriesSecondary = model.SkipSeriesSecondary,
|
||||
AllowedLanguages = model.AllowedLanguages
|
||||
};
|
||||
}
|
||||
|
||||
@@ -103,51 +51,13 @@ namespace Readarr.Api.V1.Profiles.Metadata
|
||||
{
|
||||
Id = resource.Id,
|
||||
Name = resource.Name,
|
||||
PrimaryAlbumTypes = resource.PrimaryAlbumTypes.ConvertAll(ToModel),
|
||||
SecondaryAlbumTypes = resource.SecondaryAlbumTypes.ConvertAll(ToModel),
|
||||
ReleaseStatuses = resource.ReleaseStatuses.ConvertAll(ToModel)
|
||||
};
|
||||
}
|
||||
|
||||
public static ProfilePrimaryAlbumTypeItem ToModel(this ProfilePrimaryAlbumTypeItemResource resource)
|
||||
{
|
||||
if (resource == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ProfilePrimaryAlbumTypeItem
|
||||
{
|
||||
PrimaryAlbumType = (NzbDrone.Core.Music.PrimaryAlbumType)resource.AlbumType.Id,
|
||||
Allowed = resource.Allowed
|
||||
};
|
||||
}
|
||||
|
||||
public static ProfileSecondaryAlbumTypeItem ToModel(this ProfileSecondaryAlbumTypeItemResource resource)
|
||||
{
|
||||
if (resource == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ProfileSecondaryAlbumTypeItem
|
||||
{
|
||||
SecondaryAlbumType = (NzbDrone.Core.Music.SecondaryAlbumType)resource.AlbumType.Id,
|
||||
Allowed = resource.Allowed
|
||||
};
|
||||
}
|
||||
|
||||
public static ProfileReleaseStatusItem ToModel(this ProfileReleaseStatusItemResource resource)
|
||||
{
|
||||
if (resource == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ProfileReleaseStatusItem
|
||||
{
|
||||
ReleaseStatus = (NzbDrone.Core.Music.ReleaseStatus)resource.ReleaseStatus.Id,
|
||||
Allowed = resource.Allowed
|
||||
MinRating = resource.MinRating,
|
||||
MinRatingCount = resource.MinRatingCount,
|
||||
SkipMissingDate = resource.SkipMissingDate,
|
||||
SkipMissingIsbn = resource.SkipMissingIsbn,
|
||||
SkipPartsAndSets = resource.SkipPartsAndSets,
|
||||
SkipSeriesSecondary = resource.SkipSeriesSecondary,
|
||||
AllowedLanguages = resource.AllowedLanguages
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Profiles.Metadata;
|
||||
using Readarr.Http;
|
||||
|
||||
@@ -14,35 +13,9 @@ namespace Readarr.Api.V1.Profiles.Metadata
|
||||
|
||||
private MetadataProfileResource GetAll()
|
||||
{
|
||||
var orderedPrimTypes = NzbDrone.Core.Music.PrimaryAlbumType.All
|
||||
.OrderByDescending(l => l.Id)
|
||||
.ToList();
|
||||
|
||||
var orderedSecTypes = NzbDrone.Core.Music.SecondaryAlbumType.All
|
||||
.OrderByDescending(l => l.Id)
|
||||
.ToList();
|
||||
|
||||
var orderedRelStatuses = NzbDrone.Core.Music.ReleaseStatus.All
|
||||
.OrderByDescending(l => l.Id)
|
||||
.ToList();
|
||||
|
||||
var primTypes = orderedPrimTypes
|
||||
.Select(v => new ProfilePrimaryAlbumTypeItem { PrimaryAlbumType = v, Allowed = false })
|
||||
.ToList();
|
||||
|
||||
var secTypes = orderedSecTypes
|
||||
.Select(v => new ProfileSecondaryAlbumTypeItem { SecondaryAlbumType = v, Allowed = false })
|
||||
.ToList();
|
||||
|
||||
var relStatuses = orderedRelStatuses
|
||||
.Select(v => new ProfileReleaseStatusItem { ReleaseStatus = v, Allowed = false })
|
||||
.ToList();
|
||||
|
||||
var profile = new MetadataProfile
|
||||
{
|
||||
PrimaryAlbumTypes = primTypes,
|
||||
SecondaryAlbumTypes = secTypes,
|
||||
ReleaseStatuses = relStatuses
|
||||
AllowedLanguages = "eng, en-US, en-GB"
|
||||
};
|
||||
|
||||
return profile.ToResource();
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentValidation;
|
||||
using FluentValidation.Validators;
|
||||
|
||||
namespace Readarr.Api.V1.Profiles.Metadata
|
||||
{
|
||||
public static class MetadataValidation
|
||||
{
|
||||
public static IRuleBuilderOptions<T, IList<ProfilePrimaryAlbumTypeItemResource>> MustHaveAllowedPrimaryType<T>(this IRuleBuilder<T, IList<ProfilePrimaryAlbumTypeItemResource>> ruleBuilder)
|
||||
{
|
||||
ruleBuilder.SetValidator(new NotEmptyValidator(null));
|
||||
|
||||
return ruleBuilder.SetValidator(new PrimaryTypeValidator<T>());
|
||||
}
|
||||
|
||||
public static IRuleBuilderOptions<T, IList<ProfileSecondaryAlbumTypeItemResource>> MustHaveAllowedSecondaryType<T>(this IRuleBuilder<T, IList<ProfileSecondaryAlbumTypeItemResource>> ruleBuilder)
|
||||
{
|
||||
ruleBuilder.SetValidator(new NotEmptyValidator(null));
|
||||
|
||||
return ruleBuilder.SetValidator(new SecondaryTypeValidator<T>());
|
||||
}
|
||||
|
||||
public static IRuleBuilderOptions<T, IList<ProfileReleaseStatusItemResource>> MustHaveAllowedReleaseStatus<T>(this IRuleBuilder<T, IList<ProfileReleaseStatusItemResource>> ruleBuilder)
|
||||
{
|
||||
ruleBuilder.SetValidator(new NotEmptyValidator(null));
|
||||
|
||||
return ruleBuilder.SetValidator(new ReleaseStatusValidator<T>());
|
||||
}
|
||||
}
|
||||
|
||||
public class PrimaryTypeValidator<T> : PropertyValidator
|
||||
{
|
||||
public PrimaryTypeValidator()
|
||||
: base("Must have at least one allowed primary type")
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool IsValid(PropertyValidatorContext context)
|
||||
{
|
||||
var list = context.PropertyValue as IList<ProfilePrimaryAlbumTypeItemResource>;
|
||||
|
||||
if (list == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!list.Any(c => c.Allowed))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class SecondaryTypeValidator<T> : PropertyValidator
|
||||
{
|
||||
public SecondaryTypeValidator()
|
||||
: base("Must have at least one allowed secondary type")
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool IsValid(PropertyValidatorContext context)
|
||||
{
|
||||
var list = context.PropertyValue as IList<ProfileSecondaryAlbumTypeItemResource>;
|
||||
|
||||
if (list == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!list.Any(c => c.Allowed))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class ReleaseStatusValidator<T> : PropertyValidator
|
||||
{
|
||||
public ReleaseStatusValidator()
|
||||
: base("Must have at least one allowed release status")
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool IsValid(PropertyValidatorContext context)
|
||||
{
|
||||
var list = context.PropertyValue as IList<ProfileReleaseStatusItemResource>;
|
||||
|
||||
if (list == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!list.Any(c => c.Allowed))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,23 +33,23 @@ namespace Readarr.Api.V1.Queue
|
||||
var pending = _pendingReleaseService.GetPendingQueue();
|
||||
var fullQueue = queue.Concat(pending);
|
||||
|
||||
var artistIdQuery = Request.Query.ArtistId;
|
||||
var albumIdsQuery = Request.Query.AlbumIds;
|
||||
var authorIdQuery = Request.Query.AuthorId;
|
||||
var bookIdsQuery = Request.Query.BookIds;
|
||||
|
||||
if (artistIdQuery.HasValue)
|
||||
if (authorIdQuery.HasValue)
|
||||
{
|
||||
return fullQueue.Where(q => q.Artist?.Id == (int)artistIdQuery).ToResource(includeArtist, includeAlbum);
|
||||
return fullQueue.Where(q => q.Artist?.Id == (int)authorIdQuery).ToResource(includeArtist, includeAlbum);
|
||||
}
|
||||
|
||||
if (albumIdsQuery.HasValue)
|
||||
if (bookIdsQuery.HasValue)
|
||||
{
|
||||
string albumIdsValue = albumIdsQuery.Value.ToString();
|
||||
string bookIdsValue = bookIdsQuery.Value.ToString();
|
||||
|
||||
var albumIds = albumIdsValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
var bookIds = bookIdsValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(e => Convert.ToInt32(e))
|
||||
.ToList();
|
||||
|
||||
return fullQueue.Where(q => q.Album != null && albumIds.Contains(q.Album.Id)).ToResource(includeArtist, includeAlbum);
|
||||
return fullQueue.Where(q => q.Album != null && bookIds.Contains(q.Album.Id)).ToResource(includeArtist, includeAlbum);
|
||||
}
|
||||
|
||||
return fullQueue.ToResource(includeArtist, includeAlbum);
|
||||
|
||||
@@ -118,13 +118,13 @@ namespace Readarr.Api.V1.Queue
|
||||
{
|
||||
case "status":
|
||||
return q => q.Status;
|
||||
case "artist.sortName":
|
||||
case "authors.sortName":
|
||||
return q => q.Artist?.SortName;
|
||||
case "title":
|
||||
return q => q.Title;
|
||||
case "album":
|
||||
return q => q.Album;
|
||||
case "album.title":
|
||||
case "books.title":
|
||||
return q => q.Album?.Title;
|
||||
case "album.releaseDate":
|
||||
return q => q.Album?.ReleaseDate;
|
||||
|
||||
@@ -13,8 +13,8 @@ namespace Readarr.Api.V1.Queue
|
||||
{
|
||||
public class QueueResource : RestResource
|
||||
{
|
||||
public int? ArtistId { get; set; }
|
||||
public int? AlbumId { get; set; }
|
||||
public int? AuthorId { get; set; }
|
||||
public int? BookId { get; set; }
|
||||
public ArtistResource Artist { get; set; }
|
||||
public AlbumResource Album { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
@@ -48,8 +48,8 @@ namespace Readarr.Api.V1.Queue
|
||||
return new QueueResource
|
||||
{
|
||||
Id = model.Id,
|
||||
ArtistId = model.Artist?.Id,
|
||||
AlbumId = model.Album?.Id,
|
||||
AuthorId = model.Artist?.Id,
|
||||
BookId = model.Album?.Id,
|
||||
Artist = includeArtist && model.Artist != null ? model.Artist.ToResource() : null,
|
||||
Album = includeAlbum && model.Album != null ? model.Album.ToResource() : null,
|
||||
Quality = model.Quality,
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Books.Calibre;
|
||||
using NzbDrone.Core.RootFolders;
|
||||
using NzbDrone.Core.Validation;
|
||||
using NzbDrone.Core.Validation.Paths;
|
||||
@@ -53,6 +57,14 @@ namespace Readarr.Api.V1.RootFolders
|
||||
|
||||
SharedValidator.RuleFor(c => c.DefaultQualityProfileId)
|
||||
.SetValidator(qualityProfileExistsValidator);
|
||||
|
||||
SharedValidator.RuleFor(c => c.Host).ValidHost().When(x => x.IsCalibreLibrary);
|
||||
SharedValidator.RuleFor(c => c.Port).InclusiveBetween(1, 65535).When(x => x.IsCalibreLibrary);
|
||||
SharedValidator.RuleFor(c => c.UrlBase).ValidUrlBase().When(c => c.UrlBase.IsNotNullOrWhiteSpace());
|
||||
SharedValidator.RuleFor(c => c.Username).NotEmpty().When(c => !string.IsNullOrWhiteSpace(c.Password));
|
||||
SharedValidator.RuleFor(c => c.Password).NotEmpty().When(c => !string.IsNullOrWhiteSpace(c.Username));
|
||||
|
||||
SharedValidator.RuleFor(c => c.OutputFormat).Must(x => x.Split(',').All(y => Enum.TryParse<CalibreFormat>(y, true, out _))).When(x => x.OutputFormat.IsNotNullOrWhiteSpace()).WithMessage("Invalid output formats");
|
||||
}
|
||||
|
||||
private RootFolderResource GetRootFolder(int id)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Books.Calibre;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Core.RootFolders;
|
||||
using Readarr.Http.REST;
|
||||
@@ -14,6 +15,15 @@ namespace Readarr.Api.V1.RootFolders
|
||||
public int DefaultQualityProfileId { get; set; }
|
||||
public MonitorTypes DefaultMonitorOption { get; set; }
|
||||
public HashSet<int> DefaultTags { get; set; }
|
||||
public bool IsCalibreLibrary { get; set; }
|
||||
public string Host { get; set; }
|
||||
public int Port { get; set; }
|
||||
public string UrlBase { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
public string OutputFormat { get; set; }
|
||||
public int OutputProfile { get; set; }
|
||||
public bool UseSsl { get; set; }
|
||||
|
||||
public bool Accessible { get; set; }
|
||||
public long? FreeSpace { get; set; }
|
||||
@@ -39,6 +49,15 @@ namespace Readarr.Api.V1.RootFolders
|
||||
DefaultQualityProfileId = model.DefaultQualityProfileId,
|
||||
DefaultMonitorOption = model.DefaultMonitorOption,
|
||||
DefaultTags = model.DefaultTags,
|
||||
IsCalibreLibrary = model.IsCalibreLibrary,
|
||||
Host = model.CalibreSettings?.Host,
|
||||
Port = model.CalibreSettings?.Port ?? 0,
|
||||
UrlBase = model.CalibreSettings?.UrlBase,
|
||||
Username = model.CalibreSettings?.Username,
|
||||
Password = model.CalibreSettings?.Password,
|
||||
OutputFormat = model.CalibreSettings?.OutputFormat,
|
||||
OutputProfile = model.CalibreSettings?.OutputProfile ?? 0,
|
||||
UseSsl = model.CalibreSettings?.UseSsl ?? false,
|
||||
|
||||
Accessible = model.Accessible,
|
||||
FreeSpace = model.FreeSpace,
|
||||
@@ -53,6 +72,26 @@ namespace Readarr.Api.V1.RootFolders
|
||||
return null;
|
||||
}
|
||||
|
||||
CalibreSettings cs;
|
||||
if (resource.IsCalibreLibrary)
|
||||
{
|
||||
cs = new CalibreSettings
|
||||
{
|
||||
Host = resource.Host,
|
||||
Port = resource.Port,
|
||||
UrlBase = resource.UrlBase,
|
||||
Username = resource.Username,
|
||||
Password = resource.Password,
|
||||
OutputFormat = resource.OutputFormat,
|
||||
OutputProfile = resource.OutputProfile,
|
||||
UseSsl = resource.UseSsl
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
cs = null;
|
||||
}
|
||||
|
||||
return new RootFolder
|
||||
{
|
||||
Id = resource.Id,
|
||||
@@ -62,7 +101,9 @@ namespace Readarr.Api.V1.RootFolders
|
||||
DefaultMetadataProfileId = resource.DefaultMetadataProfileId,
|
||||
DefaultQualityProfileId = resource.DefaultQualityProfileId,
|
||||
DefaultMonitorOption = resource.DefaultMonitorOption,
|
||||
DefaultTags = resource.DefaultTags
|
||||
DefaultTags = resource.DefaultTags,
|
||||
IsCalibreLibrary = resource.IsCalibreLibrary,
|
||||
CalibreSettings = cs
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -35,11 +35,11 @@ namespace Readarr.Api.V1.Search
|
||||
var resource = new SearchResource();
|
||||
resource.Id = id++;
|
||||
|
||||
if (result is NzbDrone.Core.Music.Artist)
|
||||
if (result is NzbDrone.Core.Music.Author)
|
||||
{
|
||||
var artist = (NzbDrone.Core.Music.Artist)result;
|
||||
var artist = (NzbDrone.Core.Music.Author)result;
|
||||
resource.Artist = artist.ToResource();
|
||||
resource.ForeignId = artist.ForeignArtistId;
|
||||
resource.ForeignId = artist.ForeignAuthorId;
|
||||
|
||||
var poster = artist.Metadata.Value.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster);
|
||||
if (poster != null)
|
||||
@@ -47,11 +47,11 @@ namespace Readarr.Api.V1.Search
|
||||
resource.Artist.RemotePoster = poster.Url;
|
||||
}
|
||||
}
|
||||
else if (result is NzbDrone.Core.Music.Album)
|
||||
else if (result is NzbDrone.Core.Music.Book)
|
||||
{
|
||||
var album = (NzbDrone.Core.Music.Album)result;
|
||||
var album = (NzbDrone.Core.Music.Book)result;
|
||||
resource.Album = album.ToResource();
|
||||
resource.ForeignId = album.ForeignAlbumId;
|
||||
resource.ForeignId = album.ForeignBookId;
|
||||
|
||||
var cover = album.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Cover);
|
||||
if (cover != null)
|
||||
|
||||
33
src/Readarr.Api.V1/Series/SeriesBookLinkResource.cs
Normal file
33
src/Readarr.Api.V1/Series/SeriesBookLinkResource.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Music;
|
||||
using Readarr.Http.REST;
|
||||
|
||||
namespace Readarr.Api.V1.Series
|
||||
{
|
||||
public class SeriesBookLinkResource : RestResource
|
||||
{
|
||||
public string Position { get; set; }
|
||||
public int SeriesId { get; set; }
|
||||
public int BookId { get; set; }
|
||||
}
|
||||
|
||||
public static class SeriesBookLinkResourceMapper
|
||||
{
|
||||
public static SeriesBookLinkResource ToResource(this SeriesBookLink model)
|
||||
{
|
||||
return new SeriesBookLinkResource
|
||||
{
|
||||
Id = model.Id,
|
||||
Position = model.Position,
|
||||
SeriesId = model.SeriesId,
|
||||
BookId = model.BookId
|
||||
};
|
||||
}
|
||||
|
||||
public static List<SeriesBookLinkResource> ToResource(this IEnumerable<SeriesBookLink> models)
|
||||
{
|
||||
return models?.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
35
src/Readarr.Api.V1/Series/SeriesModule.cs
Normal file
35
src/Readarr.Api.V1/Series/SeriesModule.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Nancy;
|
||||
using NzbDrone.Core.Music;
|
||||
using Readarr.Http;
|
||||
using Readarr.Http.REST;
|
||||
|
||||
namespace Readarr.Api.V1.Series
|
||||
{
|
||||
public class SeriesModule : ReadarrRestModule<SeriesResource>
|
||||
{
|
||||
protected readonly ISeriesService _seriesService;
|
||||
|
||||
public SeriesModule(ISeriesService seriesService)
|
||||
{
|
||||
_seriesService = seriesService;
|
||||
|
||||
GetResourceAll = GetSeries;
|
||||
}
|
||||
|
||||
private List<SeriesResource> GetSeries()
|
||||
{
|
||||
var authorIdQuery = Request.Query.AuthorId;
|
||||
|
||||
if (!authorIdQuery.HasValue)
|
||||
{
|
||||
throw new BadRequestException("authorId must be provided");
|
||||
}
|
||||
|
||||
int authorId = Convert.ToInt32(authorIdQuery.Value);
|
||||
|
||||
return _seriesService.GetByAuthorId(authorId).ToResource();
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/Readarr.Api.V1/Series/SeriesResource.cs
Normal file
37
src/Readarr.Api.V1/Series/SeriesResource.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Readarr.Http.REST;
|
||||
|
||||
namespace Readarr.Api.V1.Series
|
||||
{
|
||||
public class SeriesResource : RestResource
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public string Description { get; set; }
|
||||
public List<SeriesBookLinkResource> Links { get; set; }
|
||||
}
|
||||
|
||||
public static class SeriesResourceMapper
|
||||
{
|
||||
public static SeriesResource ToResource(this NzbDrone.Core.Music.Series model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SeriesResource
|
||||
{
|
||||
Id = model.Id,
|
||||
Title = model.Title,
|
||||
Description = model.Description,
|
||||
Links = model.LinkItems.Value.ToResource()
|
||||
};
|
||||
}
|
||||
|
||||
public static List<SeriesResource> ToResource(this IEnumerable<NzbDrone.Core.Music.Series> models)
|
||||
{
|
||||
return models?.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace Readarr.Api.V1.Tags
|
||||
public List<int> ImportListIds { get; set; }
|
||||
public List<int> NotificationIds { get; set; }
|
||||
public List<int> RestrictionIds { get; set; }
|
||||
public List<int> ArtistIds { get; set; }
|
||||
public List<int> AuthorIds { get; set; }
|
||||
}
|
||||
|
||||
public static class TagDetailsResourceMapper
|
||||
@@ -32,7 +32,7 @@ namespace Readarr.Api.V1.Tags
|
||||
ImportListIds = model.ImportListIds,
|
||||
NotificationIds = model.NotificationIds,
|
||||
RestrictionIds = model.RestrictionIds,
|
||||
ArtistIds = model.ArtistIds
|
||||
AuthorIds = model.AuthorIds
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ using HttpStatusCode = System.Net.HttpStatusCode;
|
||||
|
||||
namespace Readarr.Api.V1.TrackFiles
|
||||
{
|
||||
public class TrackFileModule : ReadarrRestModuleWithSignalR<TrackFileResource, TrackFile>,
|
||||
public class TrackFileModule : ReadarrRestModuleWithSignalR<TrackFileResource, BookFile>,
|
||||
IHandle<TrackFileAddedEvent>,
|
||||
IHandle<TrackFileDeletedEvent>
|
||||
{
|
||||
@@ -52,9 +52,9 @@ namespace Readarr.Api.V1.TrackFiles
|
||||
Delete("/bulk", trackFiles => DeleteTrackFiles());
|
||||
}
|
||||
|
||||
private TrackFileResource MapToResource(TrackFile trackFile)
|
||||
private TrackFileResource MapToResource(BookFile trackFile)
|
||||
{
|
||||
if (trackFile.AlbumId > 0 && trackFile.Artist != null && trackFile.Artist.Value != null)
|
||||
if (trackFile.BookId > 0 && trackFile.Artist != null && trackFile.Artist.Value != null)
|
||||
{
|
||||
return trackFile.ToResource(trackFile.Artist.Value, _upgradableSpecification);
|
||||
}
|
||||
@@ -73,14 +73,14 @@ namespace Readarr.Api.V1.TrackFiles
|
||||
|
||||
private List<TrackFileResource> GetTrackFiles()
|
||||
{
|
||||
var artistIdQuery = Request.Query.ArtistId;
|
||||
var authorIdQuery = Request.Query.AuthorId;
|
||||
var trackFileIdsQuery = Request.Query.TrackFileIds;
|
||||
var albumIdQuery = Request.Query.AlbumId;
|
||||
var bookIdQuery = Request.Query.BookId;
|
||||
var unmappedQuery = Request.Query.Unmapped;
|
||||
|
||||
if (!artistIdQuery.HasValue && !trackFileIdsQuery.HasValue && !albumIdQuery.HasValue && !unmappedQuery.HasValue)
|
||||
if (!authorIdQuery.HasValue && !trackFileIdsQuery.HasValue && !bookIdQuery.HasValue && !unmappedQuery.HasValue)
|
||||
{
|
||||
throw new Readarr.Http.REST.BadRequestException("artistId, albumId, trackFileIds or unmapped must be provided");
|
||||
throw new Readarr.Http.REST.BadRequestException("authorId, bookId, trackFileIds or unmapped must be provided");
|
||||
}
|
||||
|
||||
if (unmappedQuery.HasValue && Convert.ToBoolean(unmappedQuery.Value))
|
||||
@@ -89,27 +89,27 @@ namespace Readarr.Api.V1.TrackFiles
|
||||
return files.ConvertAll(f => MapToResource(f));
|
||||
}
|
||||
|
||||
if (artistIdQuery.HasValue && !albumIdQuery.HasValue)
|
||||
if (authorIdQuery.HasValue && !bookIdQuery.HasValue)
|
||||
{
|
||||
int artistId = Convert.ToInt32(artistIdQuery.Value);
|
||||
var artist = _artistService.GetArtist(artistId);
|
||||
int authorId = Convert.ToInt32(authorIdQuery.Value);
|
||||
var artist = _artistService.GetArtist(authorId);
|
||||
|
||||
return _mediaFileService.GetFilesByArtist(artistId).ConvertAll(f => f.ToResource(artist, _upgradableSpecification));
|
||||
return _mediaFileService.GetFilesByArtist(authorId).ConvertAll(f => f.ToResource(artist, _upgradableSpecification));
|
||||
}
|
||||
|
||||
if (albumIdQuery.HasValue)
|
||||
if (bookIdQuery.HasValue)
|
||||
{
|
||||
string albumIdValue = albumIdQuery.Value.ToString();
|
||||
string bookIdValue = bookIdQuery.Value.ToString();
|
||||
|
||||
var albumIds = albumIdValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
var bookIds = bookIdValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(e => Convert.ToInt32(e))
|
||||
.ToList();
|
||||
|
||||
var result = new List<TrackFileResource>();
|
||||
foreach (var albumId in albumIds)
|
||||
foreach (var bookId in bookIds)
|
||||
{
|
||||
var album = _albumService.GetAlbum(albumId);
|
||||
var albumArtist = _artistService.GetArtist(album.ArtistId);
|
||||
var album = _albumService.GetAlbum(bookId);
|
||||
var albumArtist = _artistService.GetArtist(album.AuthorId);
|
||||
result.AddRange(_mediaFileService.GetFilesByAlbum(album.Id).ConvertAll(f => f.ToResource(albumArtist, _upgradableSpecification)));
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ namespace Readarr.Api.V1.TrackFiles
|
||||
throw new NzbDroneClientException(HttpStatusCode.NotFound, "Track file not found");
|
||||
}
|
||||
|
||||
if (trackFile.AlbumId > 0 && trackFile.Artist != null && trackFile.Artist.Value != null)
|
||||
if (trackFile.BookId > 0 && trackFile.Artist != null && trackFile.Artist.Value != null)
|
||||
{
|
||||
_mediaFileDeletionService.DeleteTrackFile(trackFile.Artist.Value, trackFile);
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ namespace Readarr.Api.V1.TrackFiles
|
||||
{
|
||||
public class TrackFileResource : RestResource
|
||||
{
|
||||
public int ArtistId { get; set; }
|
||||
public int AlbumId { get; set; }
|
||||
public int AuthorId { get; set; }
|
||||
public int BookId { get; set; }
|
||||
public string Path { get; set; }
|
||||
public long Size { get; set; }
|
||||
public DateTime DateAdded { get; set; }
|
||||
@@ -39,7 +39,7 @@ namespace Readarr.Api.V1.TrackFiles
|
||||
return qualityWeight;
|
||||
}
|
||||
|
||||
public static TrackFileResource ToResource(this TrackFile model)
|
||||
public static TrackFileResource ToResource(this BookFile model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
@@ -49,7 +49,7 @@ namespace Readarr.Api.V1.TrackFiles
|
||||
return new TrackFileResource
|
||||
{
|
||||
Id = model.Id,
|
||||
AlbumId = model.AlbumId,
|
||||
BookId = model.BookId,
|
||||
Path = model.Path,
|
||||
Size = model.Size,
|
||||
DateAdded = model.DateAdded,
|
||||
@@ -59,7 +59,7 @@ namespace Readarr.Api.V1.TrackFiles
|
||||
};
|
||||
}
|
||||
|
||||
public static TrackFileResource ToResource(this TrackFile model, NzbDrone.Core.Music.Artist artist, IUpgradableSpecification upgradableSpecification)
|
||||
public static TrackFileResource ToResource(this BookFile model, NzbDrone.Core.Music.Author artist, IUpgradableSpecification upgradableSpecification)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
@@ -70,8 +70,8 @@ namespace Readarr.Api.V1.TrackFiles
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
ArtistId = artist.Id,
|
||||
AlbumId = model.AlbumId,
|
||||
AuthorId = artist.Id,
|
||||
BookId = model.BookId,
|
||||
Path = model.Path,
|
||||
Size = model.Size,
|
||||
DateAdded = model.DateAdded,
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Nancy;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.SignalR;
|
||||
using Readarr.Http.REST;
|
||||
|
||||
namespace Readarr.Api.V1.Tracks
|
||||
{
|
||||
public class TrackModule : TrackModuleWithSignalR
|
||||
{
|
||||
public TrackModule(IArtistService artistService,
|
||||
ITrackService trackService,
|
||||
IUpgradableSpecification upgradableSpecification,
|
||||
IBroadcastSignalRMessage signalRBroadcaster)
|
||||
: base(trackService, artistService, upgradableSpecification, signalRBroadcaster)
|
||||
{
|
||||
GetResourceAll = GetTracks;
|
||||
}
|
||||
|
||||
private List<TrackResource> GetTracks()
|
||||
{
|
||||
var artistIdQuery = Request.Query.ArtistId;
|
||||
var albumIdQuery = Request.Query.AlbumId;
|
||||
var albumReleaseIdQuery = Request.Query.AlbumReleaseId;
|
||||
var trackIdsQuery = Request.Query.TrackIds;
|
||||
|
||||
if (!artistIdQuery.HasValue && !trackIdsQuery.HasValue && !albumIdQuery.HasValue && !albumReleaseIdQuery.HasValue)
|
||||
{
|
||||
throw new BadRequestException("One of artistId, albumId, albumReleaseId or trackIds must be provided");
|
||||
}
|
||||
|
||||
if (artistIdQuery.HasValue && !albumIdQuery.HasValue)
|
||||
{
|
||||
int artistId = Convert.ToInt32(artistIdQuery.Value);
|
||||
|
||||
return MapToResource(_trackService.GetTracksByArtist(artistId), false, false);
|
||||
}
|
||||
|
||||
if (albumReleaseIdQuery.HasValue)
|
||||
{
|
||||
int releaseId = Convert.ToInt32(albumReleaseIdQuery.Value);
|
||||
|
||||
return MapToResource(_trackService.GetTracksByRelease(releaseId), false, false);
|
||||
}
|
||||
|
||||
if (albumIdQuery.HasValue)
|
||||
{
|
||||
int albumId = Convert.ToInt32(albumIdQuery.Value);
|
||||
|
||||
return MapToResource(_trackService.GetTracksByAlbum(albumId), false, false);
|
||||
}
|
||||
|
||||
string trackIdsValue = trackIdsQuery.Value.ToString();
|
||||
|
||||
var trackIds = trackIdsValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(e => Convert.ToInt32(e))
|
||||
.ToList();
|
||||
|
||||
return MapToResource(_trackService.GetTracks(trackIds), false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Datastore.Events;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.SignalR;
|
||||
using Readarr.Api.V1.Artist;
|
||||
using Readarr.Api.V1.TrackFiles;
|
||||
using Readarr.Http;
|
||||
|
||||
namespace Readarr.Api.V1.Tracks
|
||||
{
|
||||
public abstract class TrackModuleWithSignalR : ReadarrRestModuleWithSignalR<TrackResource, Track>,
|
||||
IHandle<TrackImportedEvent>,
|
||||
IHandle<TrackFileDeletedEvent>
|
||||
{
|
||||
protected readonly ITrackService _trackService;
|
||||
protected readonly IArtistService _artistService;
|
||||
protected readonly IUpgradableSpecification _upgradableSpecification;
|
||||
|
||||
protected TrackModuleWithSignalR(ITrackService trackService,
|
||||
IArtistService artistService,
|
||||
IUpgradableSpecification upgradableSpecification,
|
||||
IBroadcastSignalRMessage signalRBroadcaster)
|
||||
: base(signalRBroadcaster)
|
||||
{
|
||||
_trackService = trackService;
|
||||
_artistService = artistService;
|
||||
_upgradableSpecification = upgradableSpecification;
|
||||
|
||||
GetResourceById = GetTrack;
|
||||
}
|
||||
|
||||
protected TrackModuleWithSignalR(ITrackService trackService,
|
||||
IArtistService artistService,
|
||||
IUpgradableSpecification upgradableSpecification,
|
||||
IBroadcastSignalRMessage signalRBroadcaster,
|
||||
string resource)
|
||||
: base(signalRBroadcaster, resource)
|
||||
{
|
||||
_trackService = trackService;
|
||||
_artistService = artistService;
|
||||
_upgradableSpecification = upgradableSpecification;
|
||||
|
||||
GetResourceById = GetTrack;
|
||||
}
|
||||
|
||||
protected TrackResource GetTrack(int id)
|
||||
{
|
||||
var track = _trackService.GetTrack(id);
|
||||
var resource = MapToResource(track, true, true);
|
||||
return resource;
|
||||
}
|
||||
|
||||
protected TrackResource MapToResource(Track track, bool includeArtist, bool includeTrackFile)
|
||||
{
|
||||
var resource = track.ToResource();
|
||||
|
||||
if (includeArtist || includeTrackFile)
|
||||
{
|
||||
var artist = track.Artist.Value;
|
||||
|
||||
if (includeArtist)
|
||||
{
|
||||
resource.Artist = artist.ToResource();
|
||||
}
|
||||
|
||||
if (includeTrackFile && track.TrackFileId != 0)
|
||||
{
|
||||
resource.TrackFile = track.TrackFile.Value.ToResource(artist, _upgradableSpecification);
|
||||
}
|
||||
}
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
protected List<TrackResource> MapToResource(List<Track> tracks, bool includeArtist, bool includeTrackFile)
|
||||
{
|
||||
var result = tracks.ToResource();
|
||||
|
||||
if (includeArtist || includeTrackFile)
|
||||
{
|
||||
var artistDict = new Dictionary<int, NzbDrone.Core.Music.Artist>();
|
||||
for (var i = 0; i < tracks.Count; i++)
|
||||
{
|
||||
var track = tracks[i];
|
||||
var resource = result[i];
|
||||
var artist = track.Artist.Value;
|
||||
|
||||
if (includeArtist)
|
||||
{
|
||||
resource.Artist = artist.ToResource();
|
||||
}
|
||||
|
||||
if (includeTrackFile && tracks[i].TrackFileId != 0)
|
||||
{
|
||||
resource.TrackFile = tracks[i].TrackFile.Value.ToResource(artist, _upgradableSpecification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Handle(TrackImportedEvent message)
|
||||
{
|
||||
foreach (var track in message.TrackInfo.Tracks)
|
||||
{
|
||||
track.TrackFile = message.ImportedTrack;
|
||||
BroadcastResourceChange(ModelAction.Updated, MapToResource(track, true, true));
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(TrackFileDeletedEvent message)
|
||||
{
|
||||
foreach (var track in message.TrackFile.Tracks.Value)
|
||||
{
|
||||
track.TrackFile = message.TrackFile;
|
||||
BroadcastResourceChange(ModelAction.Updated, MapToResource(track, true, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using NzbDrone.Core.Music;
|
||||
using Readarr.Api.V1.Artist;
|
||||
using Readarr.Api.V1.TrackFiles;
|
||||
using Readarr.Http.REST;
|
||||
|
||||
namespace Readarr.Api.V1.Tracks
|
||||
{
|
||||
public class TrackResource : RestResource
|
||||
{
|
||||
public int ArtistId { get; set; }
|
||||
public int TrackFileId { get; set; }
|
||||
public int AlbumId { get; set; }
|
||||
public bool Explicit { get; set; }
|
||||
public int AbsoluteTrackNumber { get; set; }
|
||||
public string TrackNumber { get; set; }
|
||||
public string Title { get; set; }
|
||||
public int Duration { get; set; }
|
||||
public TrackFileResource TrackFile { get; set; }
|
||||
public int MediumNumber { get; set; }
|
||||
public bool HasFile { get; set; }
|
||||
|
||||
public ArtistResource Artist { get; set; }
|
||||
public Ratings Ratings { get; set; }
|
||||
|
||||
//Hiding this so people don't think its usable (only used to set the initial state)
|
||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public bool Grabbed { get; set; }
|
||||
}
|
||||
|
||||
public static class TrackResourceMapper
|
||||
{
|
||||
public static TrackResource ToResource(this Track model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TrackResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
ArtistId = model.Artist.Value.Id,
|
||||
TrackFileId = model.TrackFileId,
|
||||
AlbumId = model.AlbumId,
|
||||
Explicit = model.Explicit,
|
||||
AbsoluteTrackNumber = model.AbsoluteTrackNumber,
|
||||
TrackNumber = model.TrackNumber,
|
||||
Title = model.Title,
|
||||
Duration = model.Duration,
|
||||
MediumNumber = model.MediumNumber,
|
||||
HasFile = model.HasFile,
|
||||
Ratings = model.Ratings,
|
||||
};
|
||||
}
|
||||
|
||||
public static List<TrackResource> ToResource(this IEnumerable<Track> models)
|
||||
{
|
||||
if (models == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ namespace Readarr.Api.V1.Wanted
|
||||
|
||||
private PagingResource<AlbumResource> GetCutoffUnmetAlbums(PagingResource<AlbumResource> pagingResource)
|
||||
{
|
||||
var pagingSpec = new PagingSpec<Album>
|
||||
var pagingSpec = new PagingSpec<Book>
|
||||
{
|
||||
Page = pagingResource.Page,
|
||||
PageSize = pagingResource.PageSize,
|
||||
@@ -42,11 +42,11 @@ namespace Readarr.Api.V1.Wanted
|
||||
|
||||
if (filter != null && filter.Value == "false")
|
||||
{
|
||||
pagingSpec.FilterExpressions.Add(v => v.Monitored == false || v.Artist.Value.Monitored == false);
|
||||
pagingSpec.FilterExpressions.Add(v => v.Monitored == false || v.Author.Value.Monitored == false);
|
||||
}
|
||||
else
|
||||
{
|
||||
pagingSpec.FilterExpressions.Add(v => v.Monitored == true && v.Artist.Value.Monitored == true);
|
||||
pagingSpec.FilterExpressions.Add(v => v.Monitored == true && v.Author.Value.Monitored == true);
|
||||
}
|
||||
|
||||
var resource = ApplyToPage(_albumCutoffService.AlbumsWhereCutoffUnmet, pagingSpec, v => MapToResource(v, includeArtist));
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Readarr.Api.V1.Wanted
|
||||
|
||||
private PagingResource<AlbumResource> GetMissingAlbums(PagingResource<AlbumResource> pagingResource)
|
||||
{
|
||||
var pagingSpec = new PagingSpec<Album>
|
||||
var pagingSpec = new PagingSpec<Book>
|
||||
{
|
||||
Page = pagingResource.Page,
|
||||
PageSize = pagingResource.PageSize,
|
||||
@@ -38,11 +38,11 @@ namespace Readarr.Api.V1.Wanted
|
||||
|
||||
if (monitoredFilter != null && monitoredFilter.Value == "false")
|
||||
{
|
||||
pagingSpec.FilterExpressions.Add(v => v.Monitored == false || v.Artist.Value.Monitored == false);
|
||||
pagingSpec.FilterExpressions.Add(v => v.Monitored == false || v.Author.Value.Monitored == false);
|
||||
}
|
||||
else
|
||||
{
|
||||
pagingSpec.FilterExpressions.Add(v => v.Monitored == true && v.Artist.Value.Monitored == true);
|
||||
pagingSpec.FilterExpressions.Add(v => v.Monitored == true && v.Author.Value.Monitored == true);
|
||||
}
|
||||
|
||||
var resource = ApplyToPage(_albumService.AlbumsWithoutFiles, pagingSpec, v => MapToResource(v, includeArtist));
|
||||
|
||||
Reference in New Issue
Block a user