New: Readarr 0.1

This commit is contained in:
ta264
2020-05-06 21:14:11 +01:00
parent 476f2d6047
commit 08496c82af
911 changed files with 14837 additions and 24442 deletions

View File

@@ -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)
{

View File

@@ -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)

View File

@@ -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();
}

View File

@@ -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();
}
}
}

View File

@@ -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();
}

View File

@@ -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; }
}
}

View File

@@ -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();
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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

View File

@@ -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");
}
}
}

View File

@@ -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,

View File

@@ -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; }
}
}

View File

@@ -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();

View File

@@ -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; }

View File

@@ -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)
{

View File

@@ -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)

View File

@@ -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();
}

View File

@@ -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,

View File

@@ -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))
{

View File

@@ -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;
}

View File

@@ -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; }

View File

@@ -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
};
}
}

View File

@@ -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()

View File

@@ -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,

View File

@@ -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);

View File

@@ -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

View File

@@ -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
});
}

View File

@@ -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
};
}

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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
};
}

View File

@@ -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();

View File

@@ -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;
}
}
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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,

View File

@@ -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)

View File

@@ -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
};
}

View File

@@ -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)

View 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();
}
}
}

View 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();
}
}
}

View 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();
}
}
}

View File

@@ -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
};
}

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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);
}
}
}

View File

@@ -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));
}
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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));

View File

@@ -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));