Method, Variable, Class Renames in Readarr.Api

This commit is contained in:
Qstick
2020-05-15 17:22:44 -04:00
committed by ta264
parent 8080d375d0
commit ee4e44b81a
91 changed files with 945 additions and 948 deletions

View File

@@ -21,7 +21,7 @@ namespace NzbDrone.Automation.Test
{ {
_page.LibraryNavIcon.Click(); _page.LibraryNavIcon.Click();
_page.WaitForNoSpinner(); _page.WaitForNoSpinner();
_page.Find(By.CssSelector("div[class*='ArtistIndex']")).Should().NotBeNull(); _page.Find(By.CssSelector("div[class*='AuthorIndex']")).Should().NotBeNull();
} }
[Test] [Test]

View File

@@ -80,7 +80,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
private void GivenUnmonitorDeletedTracks(bool enabled) private void GivenUnmonitorDeletedTracks(bool enabled)
{ {
Mocker.GetMock<IConfigService>() Mocker.GetMock<IConfigService>()
.SetupGet(v => v.AutoUnmonitorPreviouslyDownloadedTracks) .SetupGet(v => v.AutoUnmonitorPreviouslyDownloadedBooks)
.Returns(enabled); .Returns(enabled);
} }

View File

@@ -26,7 +26,7 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
.Returns(_artist); .Returns(_artist);
Mocker.GetMock<ISearchForNzb>() Mocker.GetMock<ISearchForNzb>()
.Setup(s => s.ArtistSearch(_artist.Id, false, true, false)) .Setup(s => s.AuthorSearch(_artist.Id, false, true, false))
.Returns(new List<DownloadDecision>()); .Returns(new List<DownloadDecision>());
Mocker.GetMock<IProcessDownloadDecisions>() Mocker.GetMock<IProcessDownloadDecisions>()
@@ -46,7 +46,7 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
Subject.Execute(new AuthorSearchCommand { AuthorId = _artist.Id, Trigger = CommandTrigger.Manual }); Subject.Execute(new AuthorSearchCommand { AuthorId = _artist.Id, Trigger = CommandTrigger.Manual });
Mocker.GetMock<ISearchForNzb>() Mocker.GetMock<ISearchForNzb>()
.Verify(v => v.ArtistSearch(_artist.Id, false, true, false), .Verify(v => v.AuthorSearch(_artist.Id, false, true, false),
Times.Exactly(_artist.Books.Value.Count(s => s.Monitored))); Times.Exactly(_artist.Books.Value.Count(s => s.Monitored)));
} }
} }

View File

@@ -105,7 +105,7 @@ namespace NzbDrone.Core.AuthorStats
public void Handle(BookEditedEvent message) public void Handle(BookEditedEvent message)
{ {
_cache.Remove("AllAuthors"); _cache.Remove("AllAuthors");
_cache.Remove(message.Album.AuthorId.ToString()); _cache.Remove(message.Book.AuthorId.ToString());
} }
[EventHandleOrder(EventHandleOrder.First)] [EventHandleOrder(EventHandleOrder.First)]

View File

@@ -4,12 +4,12 @@ namespace NzbDrone.Core.Books.Events
{ {
public class BookEditedEvent : IEvent public class BookEditedEvent : IEvent
{ {
public Book Album { get; private set; } public Book Book { get; private set; }
public Book OldAlbum { get; private set; } public Book OldAlbum { get; private set; }
public BookEditedEvent(Book book, Book oldAlbum) public BookEditedEvent(Book book, Book oldAlbum)
{ {
Album = book; Book = book;
OldAlbum = oldAlbum; OldAlbum = oldAlbum;
} }
} }

View File

@@ -78,7 +78,7 @@ namespace NzbDrone.Core.Configuration
return _repository.Get(key.ToLower()) != null; return _repository.Get(key.ToLower()) != null;
} }
public bool AutoUnmonitorPreviouslyDownloadedTracks public bool AutoUnmonitorPreviouslyDownloadedBooks
{ {
get { return GetValueBoolean("AutoUnmonitorPreviouslyDownloadedTracks"); } get { return GetValueBoolean("AutoUnmonitorPreviouslyDownloadedTracks"); }
set { SetValue("AutoUnmonitorPreviouslyDownloadedTracks", value); } set { SetValue("AutoUnmonitorPreviouslyDownloadedTracks", value); }
@@ -158,7 +158,7 @@ namespace NzbDrone.Core.Configuration
set { SetValue("RemoveFailedDownloads", value); } set { SetValue("RemoveFailedDownloads", value); }
} }
public bool CreateEmptyArtistFolders public bool CreateEmptyAuthorFolders
{ {
get { return GetValueBoolean("CreateEmptyArtistFolders", false); } get { return GetValueBoolean("CreateEmptyArtistFolders", false); }

View File

@@ -24,11 +24,11 @@ namespace NzbDrone.Core.Configuration
bool RemoveFailedDownloads { get; set; } bool RemoveFailedDownloads { get; set; }
//Media Management //Media Management
bool AutoUnmonitorPreviouslyDownloadedTracks { get; set; } bool AutoUnmonitorPreviouslyDownloadedBooks { get; set; }
string RecycleBin { get; set; } string RecycleBin { get; set; }
int RecycleBinCleanupDays { get; set; } int RecycleBinCleanupDays { get; set; }
ProperDownloadTypes DownloadPropersAndRepacks { get; set; } ProperDownloadTypes DownloadPropersAndRepacks { get; set; }
bool CreateEmptyArtistFolders { get; set; } bool CreateEmptyAuthorFolders { get; set; }
bool DeleteEmptyFolders { get; set; } bool DeleteEmptyFolders { get; set; }
FileDateType FileDate { get; set; } FileDateType FileDate { get; set; }
bool SkipFreeSpaceCheckWhenImporting { get; set; } bool SkipFreeSpaceCheckWhenImporting { get; set; }

View File

@@ -33,7 +33,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
public virtual Decision IsSatisfiedBy(RemoteBook subject, SearchCriteriaBase searchCriteria) public virtual Decision IsSatisfiedBy(RemoteBook subject, SearchCriteriaBase searchCriteria)
{ {
if (!_configService.AutoUnmonitorPreviouslyDownloadedTracks) if (!_configService.AutoUnmonitorPreviouslyDownloadedBooks)
{ {
return Decision.Accept(); return Decision.Accept();
} }

View File

@@ -33,7 +33,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
return false; return false;
} }
return new[] { HistoryEventType.DownloadImported, HistoryEventType.TrackFileImported }.Contains(lastHistoryItem.EventType); return new[] { HistoryEventType.DownloadImported, HistoryEventType.BookFileImported }.Contains(lastHistoryItem.EventType);
}); });
return allAlbumsImportedInHistory; return allAlbumsImportedInHistory;

View File

@@ -257,7 +257,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
} }
// Since DownloadComplete is a new event type, we can't assume it exists for old downloads // Since DownloadComplete is a new event type, we can't assume it exists for old downloads
if (history.EventType == HistoryEventType.TrackFileImported) if (history.EventType == HistoryEventType.BookFileImported)
{ {
return DateTime.UtcNow.Subtract(history.Date).TotalSeconds < 60 ? TrackedDownloadState.Importing : TrackedDownloadState.Imported; return DateTime.UtcNow.Subtract(history.Date).TotalSeconds < 60 ? TrackedDownloadState.Importing : TrackedDownloadState.Imported;
} }

View File

@@ -32,14 +32,14 @@ namespace NzbDrone.Core.History
{ {
Unknown = 0, Unknown = 0,
Grabbed = 1, Grabbed = 1,
ArtistFolderImported = 2, AuthorFolderImported = 2,
TrackFileImported = 3, BookFileImported = 3,
DownloadFailed = 4, DownloadFailed = 4,
TrackFileDeleted = 5, BookFileDeleted = 5,
TrackFileRenamed = 6, BookFileRenamed = 6,
BookImportIncomplete = 7, BookImportIncomplete = 7,
DownloadImported = 8, DownloadImported = 8,
TrackFileRetagged = 9, BookFileRetagged = 9,
DownloadIgnored = 10 DownloadIgnored = 10
} }
} }

View File

@@ -90,7 +90,7 @@ namespace NzbDrone.Core.History
public List<History> FindDownloadHistory(int idAuthorId, QualityModel quality) public List<History> FindDownloadHistory(int idAuthorId, QualityModel quality)
{ {
var allowed = new[] { HistoryEventType.Grabbed, HistoryEventType.DownloadFailed, HistoryEventType.TrackFileImported }; var allowed = new[] { HistoryEventType.Grabbed, HistoryEventType.DownloadFailed, HistoryEventType.BookFileImported };
return Query(h => h.AuthorId == idAuthorId && return Query(h => h.AuthorId == idAuthorId &&
h.Quality == quality && h.Quality == quality &&

View File

@@ -215,7 +215,7 @@ namespace NzbDrone.Core.History
var history = new History var history = new History
{ {
EventType = HistoryEventType.TrackFileImported, EventType = HistoryEventType.BookFileImported,
Date = DateTime.UtcNow, Date = DateTime.UtcNow,
Quality = message.BookInfo.Quality, Quality = message.BookInfo.Quality,
SourceTitle = message.ImportedBook.SceneName ?? Path.GetFileNameWithoutExtension(message.BookInfo.Path), SourceTitle = message.ImportedBook.SceneName ?? Path.GetFileNameWithoutExtension(message.BookInfo.Path),
@@ -289,7 +289,7 @@ namespace NzbDrone.Core.History
var history = new History var history = new History
{ {
EventType = HistoryEventType.TrackFileDeleted, EventType = HistoryEventType.BookFileDeleted,
Date = DateTime.UtcNow, Date = DateTime.UtcNow,
Quality = message.BookFile.Quality, Quality = message.BookFile.Quality,
SourceTitle = message.BookFile.Path, SourceTitle = message.BookFile.Path,
@@ -309,7 +309,7 @@ namespace NzbDrone.Core.History
var history = new History var history = new History
{ {
EventType = HistoryEventType.TrackFileRenamed, EventType = HistoryEventType.BookFileRenamed,
Date = DateTime.UtcNow, Date = DateTime.UtcNow,
Quality = message.BookFile.Quality, Quality = message.BookFile.Quality,
SourceTitle = message.OriginalPath, SourceTitle = message.OriginalPath,
@@ -329,7 +329,7 @@ namespace NzbDrone.Core.History
var history = new History var history = new History
{ {
EventType = HistoryEventType.TrackFileRetagged, EventType = HistoryEventType.BookFileRetagged,
Date = DateTime.UtcNow, Date = DateTime.UtcNow,
Quality = message.BookFile.Quality, Quality = message.BookFile.Quality,
SourceTitle = path, SourceTitle = path,

View File

@@ -22,7 +22,7 @@ namespace NzbDrone.Core.IndexerSearch
public void Execute(AuthorSearchCommand message) public void Execute(AuthorSearchCommand message)
{ {
var decisions = _nzbSearchService.ArtistSearch(message.AuthorId, false, message.Trigger == CommandTrigger.Manual, false); var decisions = _nzbSearchService.AuthorSearch(message.AuthorId, false, message.Trigger == CommandTrigger.Manual, false);
var processed = _processDownloadDecisions.ProcessDecisions(decisions); var processed = _processDownloadDecisions.ProcessDecisions(decisions);
_logger.ProgressInfo("Author search completed. {0} reports downloaded.", processed.Grabbed.Count); _logger.ProgressInfo("Author search completed. {0} reports downloaded.", processed.Grabbed.Count);

View File

@@ -47,7 +47,7 @@ namespace NzbDrone.Core.IndexerSearch
foreach (var book in books) foreach (var book in books)
{ {
List<DownloadDecision> decisions; List<DownloadDecision> decisions;
decisions = _nzbSearchService.AlbumSearch(book.Id, false, userInvokedSearch, false); decisions = _nzbSearchService.BookSearch(book.Id, false, userInvokedSearch, false);
var processed = _processDownloadDecisions.ProcessDecisions(decisions); var processed = _processDownloadDecisions.ProcessDecisions(decisions);
downloadedCount += processed.Grabbed.Count; downloadedCount += processed.Grabbed.Count;
@@ -61,7 +61,7 @@ namespace NzbDrone.Core.IndexerSearch
foreach (var bookId in message.BookIds) foreach (var bookId in message.BookIds)
{ {
var decisions = var decisions =
_nzbSearchService.AlbumSearch(bookId, false, message.Trigger == CommandTrigger.Manual, false); _nzbSearchService.BookSearch(bookId, false, message.Trigger == CommandTrigger.Manual, false);
var processed = _processDownloadDecisions.ProcessDecisions(decisions); var processed = _processDownloadDecisions.ProcessDecisions(decisions);
_logger.ProgressInfo("Book search completed. {0} reports downloaded.", processed.Grabbed.Count); _logger.ProgressInfo("Book search completed. {0} reports downloaded.", processed.Grabbed.Count);

View File

@@ -16,8 +16,8 @@ namespace NzbDrone.Core.IndexerSearch
{ {
public interface ISearchForNzb public interface ISearchForNzb
{ {
List<DownloadDecision> AlbumSearch(int bookId, bool missingOnly, bool userInvokedSearch, bool interactiveSearch); List<DownloadDecision> BookSearch(int bookId, bool missingOnly, bool userInvokedSearch, bool interactiveSearch);
List<DownloadDecision> ArtistSearch(int authorId, bool missingOnly, bool userInvokedSearch, bool interactiveSearch); List<DownloadDecision> AuthorSearch(int authorId, bool missingOnly, bool userInvokedSearch, bool interactiveSearch);
} }
public class NzbSearchService : ISearchForNzb public class NzbSearchService : ISearchForNzb
@@ -41,13 +41,13 @@ namespace NzbDrone.Core.IndexerSearch
_logger = logger; _logger = logger;
} }
public List<DownloadDecision> AlbumSearch(int bookId, bool missingOnly, bool userInvokedSearch, bool interactiveSearch) public List<DownloadDecision> BookSearch(int bookId, bool missingOnly, bool userInvokedSearch, bool interactiveSearch)
{ {
var book = _bookService.GetBook(bookId); var book = _bookService.GetBook(bookId);
return AlbumSearch(book, missingOnly, userInvokedSearch, interactiveSearch); return AlbumSearch(book, missingOnly, userInvokedSearch, interactiveSearch);
} }
public List<DownloadDecision> ArtistSearch(int authorId, bool missingOnly, bool userInvokedSearch, bool interactiveSearch) public List<DownloadDecision> AuthorSearch(int authorId, bool missingOnly, bool userInvokedSearch, bool interactiveSearch)
{ {
var author = _authorService.GetAuthor(authorId); var author = _authorService.GetAuthor(authorId);
return ArtistSearch(author, missingOnly, userInvokedSearch, interactiveSearch); return ArtistSearch(author, missingOnly, userInvokedSearch, interactiveSearch);

View File

@@ -15,13 +15,13 @@ using NzbDrone.Core.Organizer;
namespace NzbDrone.Core.MediaFiles namespace NzbDrone.Core.MediaFiles
{ {
public interface IRenameTrackFileService public interface IRenameBookFileService
{ {
List<RenameBookFilePreview> GetRenamePreviews(int authorId); List<RenameBookFilePreview> GetRenamePreviews(int authorId);
List<RenameBookFilePreview> GetRenamePreviews(int authorId, int bookId); List<RenameBookFilePreview> GetRenamePreviews(int authorId, int bookId);
} }
public class RenameBookFileService : IRenameTrackFileService, IExecute<RenameFilesCommand>, IExecute<RenameAuthorCommand> public class RenameBookFileService : IRenameBookFileService, IExecute<RenameFilesCommand>, IExecute<RenameAuthorCommand>
{ {
private readonly IAuthorService _authorService; private readonly IAuthorService _authorService;
private readonly IMediaFileService _mediaFileService; private readonly IMediaFileService _mediaFileService;

View File

@@ -3,11 +3,11 @@ using NzbDrone.Core.Books;
namespace NzbDrone.Core.Validation.Paths namespace NzbDrone.Core.Validation.Paths
{ {
public class ArtistExistsValidator : PropertyValidator public class AuthorExistsValidator : PropertyValidator
{ {
private readonly IAuthorService _authorService; private readonly IAuthorService _authorService;
public ArtistExistsValidator(IAuthorService authorService) public AuthorExistsValidator(IAuthorService authorService)
: base("This author has already been added.") : base("This author has already been added.")
{ {
_authorService = authorService; _authorService = authorService;

View File

@@ -1,45 +0,0 @@
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Test.Common;
using Readarr.Api.V1.Artist;
namespace NzbDrone.Integration.Test.ApiTests
{
[TestFixture]
public class ArtistEditorFixture : IntegrationTest
{
private void GivenExistingArtist()
{
foreach (var name in new[] { "Alien Ant Farm", "Kiss" })
{
var newArtist = Artist.Lookup(name).First();
newArtist.QualityProfileId = 1;
newArtist.MetadataProfileId = 1;
newArtist.Path = string.Format(@"C:\Test\{0}", name).AsOsAgnostic();
Artist.Post(newArtist);
}
}
[Test]
public void should_be_able_to_update_multiple_artist()
{
GivenExistingArtist();
var artist = Artist.All();
var artistEditor = new ArtistEditorResource
{
QualityProfileId = 2,
AuthorIds = artist.Select(o => o.Id).ToList()
};
var result = Artist.Editor(artistEditor);
result.Should().HaveCount(2);
result.TrueForAll(s => s.QualityProfileId == 2).Should().BeTrue();
}
}
}

View File

@@ -1,28 +0,0 @@
using FluentAssertions;
using NUnit.Framework;
namespace NzbDrone.Integration.Test.ApiTests
{
[TestFixture]
public class ArtistLookupFixture : IntegrationTest
{
[TestCase("Robert Harris", "Robert Harris")]
[TestCase("J.K. Rowling", "J.K. Rowling")]
public void lookup_new_artist_by_name(string term, string name)
{
var artist = Artist.Lookup(term);
artist.Should().NotBeEmpty();
artist.Should().Contain(c => c.ArtistName == name);
}
[Test]
public void lookup_new_artist_by_goodreads_book_id()
{
var artist = Artist.Lookup("readarr:1");
artist.Should().NotBeEmpty();
artist.Should().Contain(c => c.ArtistName == "J.K. Rowling");
}
}
}

View File

@@ -0,0 +1,45 @@
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Test.Common;
using Readarr.Api.V1.Author;
namespace NzbDrone.Integration.Test.ApiTests
{
[TestFixture]
public class AuthorEditorFixture : IntegrationTest
{
private void GivenExistingAuthor()
{
foreach (var name in new[] { "Alien Ant Farm", "Kiss" })
{
var newAuthor = Author.Lookup(name).First();
newAuthor.QualityProfileId = 1;
newAuthor.MetadataProfileId = 1;
newAuthor.Path = string.Format(@"C:\Test\{0}", name).AsOsAgnostic();
Author.Post(newAuthor);
}
}
[Test]
public void should_be_able_to_update_multiple_artist()
{
GivenExistingAuthor();
var author = Author.All();
var artistEditor = new AuthorEditorResource
{
QualityProfileId = 2,
AuthorIds = author.Select(o => o.Id).ToList()
};
var result = Author.Editor(artistEditor);
result.Should().HaveCount(2);
result.TrueForAll(s => s.QualityProfileId == 2).Should().BeTrue();
}
}
}

View File

@@ -7,7 +7,7 @@ using NUnit.Framework;
namespace NzbDrone.Integration.Test.ApiTests namespace NzbDrone.Integration.Test.ApiTests
{ {
[TestFixture] [TestFixture]
public class ArtistFixture : IntegrationTest public class AuthorFixture : IntegrationTest
{ {
[Test] [Test]
[Order(0)] [Order(0)]
@@ -16,15 +16,15 @@ namespace NzbDrone.Integration.Test.ApiTests
EnsureNoArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "J.K. Rowling"); EnsureNoArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "J.K. Rowling");
var tag = EnsureTag("abc"); var tag = EnsureTag("abc");
var artist = Artist.Lookup("readarr:1").Single(); var author = Author.Lookup("readarr:1").Single();
artist.QualityProfileId = 1; author.QualityProfileId = 1;
artist.MetadataProfileId = 1; author.MetadataProfileId = 1;
artist.Path = Path.Combine(ArtistRootFolder, artist.ArtistName); author.Path = Path.Combine(AuthorRootFolder, author.AuthorName);
artist.Tags = new HashSet<int>(); author.Tags = new HashSet<int>();
artist.Tags.Add(tag.Id); author.Tags.Add(tag.Id);
var result = Artist.Post(artist); var result = Author.Post(author);
result.Should().NotBeNull(); result.Should().NotBeNull();
result.Tags.Should().Equal(tag.Id); result.Tags.Should().Equal(tag.Id);
@@ -38,11 +38,11 @@ namespace NzbDrone.Integration.Test.ApiTests
EnsureNoArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "J.K. Rowling"); EnsureNoArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "J.K. Rowling");
var artist = Artist.Lookup("readarr:1").Single(); var artist = Author.Lookup("readarr:1").Single();
artist.Path = Path.Combine(ArtistRootFolder, artist.ArtistName); artist.Path = Path.Combine(AuthorRootFolder, artist.AuthorName);
Artist.InvalidPost(artist); Author.InvalidPost(artist);
} }
[Test] [Test]
@@ -53,11 +53,11 @@ namespace NzbDrone.Integration.Test.ApiTests
EnsureNoArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "J.K. Rowling"); EnsureNoArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "J.K. Rowling");
var artist = Artist.Lookup("readarr:1").Single(); var artist = Author.Lookup("readarr:1").Single();
artist.QualityProfileId = 1; artist.QualityProfileId = 1;
Artist.InvalidPost(artist); Author.InvalidPost(artist);
} }
[Test] [Test]
@@ -66,29 +66,29 @@ namespace NzbDrone.Integration.Test.ApiTests
{ {
EnsureNoArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "J.K. Rowling"); EnsureNoArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "J.K. Rowling");
var artist = Artist.Lookup("readarr:1").Single(); var artist = Author.Lookup("readarr:1").Single();
artist.QualityProfileId = 1; artist.QualityProfileId = 1;
artist.MetadataProfileId = 1; artist.MetadataProfileId = 1;
artist.Path = Path.Combine(ArtistRootFolder, artist.ArtistName); artist.Path = Path.Combine(AuthorRootFolder, artist.AuthorName);
var result = Artist.Post(artist); var result = Author.Post(artist);
result.Should().NotBeNull(); result.Should().NotBeNull();
result.Id.Should().NotBe(0); result.Id.Should().NotBe(0);
result.QualityProfileId.Should().Be(1); result.QualityProfileId.Should().Be(1);
result.MetadataProfileId.Should().Be(1); result.MetadataProfileId.Should().Be(1);
result.Path.Should().Be(Path.Combine(ArtistRootFolder, artist.ArtistName)); result.Path.Should().Be(Path.Combine(AuthorRootFolder, artist.AuthorName));
} }
[Test] [Test]
[Order(2)] [Order(2)]
public void get_all_artist() public void get_all_artist()
{ {
EnsureArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling"); EnsureAuthor("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling");
EnsureArtist("amzn1.gr.author.v1.qTrNu9-PIaaBj5gYRDmN4Q", "34497", "Terry Pratchett"); EnsureAuthor("amzn1.gr.author.v1.qTrNu9-PIaaBj5gYRDmN4Q", "34497", "Terry Pratchett");
var artists = Artist.All(); var artists = Author.All();
artists.Should().NotBeNullOrEmpty(); artists.Should().NotBeNullOrEmpty();
artists.Should().Contain(v => v.ForeignAuthorId == "amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ"); artists.Should().Contain(v => v.ForeignAuthorId == "amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ");
@@ -99,9 +99,9 @@ namespace NzbDrone.Integration.Test.ApiTests
[Order(2)] [Order(2)]
public void get_artist_by_id() public void get_artist_by_id()
{ {
var artist = EnsureArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling"); var artist = EnsureAuthor("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling");
var result = Artist.Get(artist.Id); var result = Author.Get(artist.Id);
result.ForeignAuthorId.Should().Be("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ"); result.ForeignAuthorId.Should().Be("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ");
} }
@@ -111,14 +111,14 @@ namespace NzbDrone.Integration.Test.ApiTests
{ {
IgnoreOnMonoVersions("5.12", "5.14"); IgnoreOnMonoVersions("5.12", "5.14");
var result = Artist.InvalidGet(1000000); var result = Author.InvalidGet(1000000);
} }
[Test] [Test]
[Order(2)] [Order(2)]
public void update_artist_profile_id() public void update_artist_profile_id()
{ {
var artist = EnsureArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling"); var artist = EnsureAuthor("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling");
var profileId = 1; var profileId = 1;
if (artist.QualityProfileId == profileId) if (artist.QualityProfileId == profileId)
@@ -128,16 +128,16 @@ namespace NzbDrone.Integration.Test.ApiTests
artist.QualityProfileId = profileId; artist.QualityProfileId = profileId;
var result = Artist.Put(artist); var result = Author.Put(artist);
Artist.Get(artist.Id).QualityProfileId.Should().Be(profileId); Author.Get(artist.Id).QualityProfileId.Should().Be(profileId);
} }
[Test] [Test]
[Order(3)] [Order(3)]
public void update_artist_monitored() public void update_artist_monitored()
{ {
var artist = EnsureArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", false); var artist = EnsureAuthor("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", false);
artist.Monitored.Should().BeFalse(); artist.Monitored.Should().BeFalse();
@@ -148,7 +148,7 @@ namespace NzbDrone.Integration.Test.ApiTests
//{ //{
// season.Monitored = true; // season.Monitored = true;
//}); //});
var result = Artist.Put(artist); var result = Author.Put(artist);
result.Monitored.Should().BeTrue(); result.Monitored.Should().BeTrue();
@@ -159,22 +159,22 @@ namespace NzbDrone.Integration.Test.ApiTests
[Order(3)] [Order(3)]
public void update_artist_tags() public void update_artist_tags()
{ {
var artist = EnsureArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling"); var artist = EnsureAuthor("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling");
var tag = EnsureTag("abc"); var tag = EnsureTag("abc");
if (artist.Tags.Contains(tag.Id)) if (artist.Tags.Contains(tag.Id))
{ {
artist.Tags.Remove(tag.Id); artist.Tags.Remove(tag.Id);
var result = Artist.Put(artist); var result = Author.Put(artist);
Artist.Get(artist.Id).Tags.Should().NotContain(tag.Id); Author.Get(artist.Id).Tags.Should().NotContain(tag.Id);
} }
else else
{ {
artist.Tags.Add(tag.Id); artist.Tags.Add(tag.Id);
var result = Artist.Put(artist); var result = Author.Put(artist);
Artist.Get(artist.Id).Tags.Should().Contain(tag.Id); Author.Get(artist.Id).Tags.Should().Contain(tag.Id);
} }
} }
@@ -182,13 +182,13 @@ namespace NzbDrone.Integration.Test.ApiTests
[Order(4)] [Order(4)]
public void delete_artist() public void delete_artist()
{ {
var artist = EnsureArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling"); var artist = EnsureAuthor("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling");
Artist.Get(artist.Id).Should().NotBeNull(); Author.Get(artist.Id).Should().NotBeNull();
Artist.Delete(artist.Id); Author.Delete(artist.Id);
Artist.All().Should().NotContain(v => v.ForeignAuthorId == "amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ"); Author.All().Should().NotContain(v => v.ForeignAuthorId == "amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ");
} }
} }
} }

View File

@@ -0,0 +1,28 @@
using FluentAssertions;
using NUnit.Framework;
namespace NzbDrone.Integration.Test.ApiTests
{
[TestFixture]
public class AuthorLookupFixture : IntegrationTest
{
[TestCase("Robert Harris", "Robert Harris")]
[TestCase("J.K. Rowling", "J.K. Rowling")]
public void lookup_new_author_by_name(string term, string name)
{
var author = Author.Lookup(term);
author.Should().NotBeEmpty();
author.Should().Contain(c => c.AuthorName == name);
}
[Test]
public void lookup_new_author_by_goodreads_book_id()
{
var author = Author.Lookup("readarr:1");
author.Should().NotBeEmpty();
author.Should().Contain(c => c.AuthorName == "J.K. Rowling");
}
}
}

View File

@@ -1,6 +1,6 @@
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using Readarr.Api.V1.Artist; using Readarr.Api.V1.Author;
using Readarr.Api.V1.Blacklist; using Readarr.Api.V1.Blacklist;
namespace NzbDrone.Integration.Test.ApiTests namespace NzbDrone.Integration.Test.ApiTests
@@ -8,13 +8,13 @@ namespace NzbDrone.Integration.Test.ApiTests
[TestFixture] [TestFixture]
public class BlacklistFixture : IntegrationTest public class BlacklistFixture : IntegrationTest
{ {
private ArtistResource _artist; private AuthorResource _artist;
[Test] [Test]
[Ignore("Adding to blacklist not supported")] [Ignore("Adding to blacklist not supported")]
public void should_be_able_to_add_to_blacklist() public void should_be_able_to_add_to_blacklist()
{ {
_artist = EnsureArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling"); _artist = EnsureAuthor("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling");
Blacklist.Post(new BlacklistResource Blacklist.Post(new BlacklistResource
{ {

View File

@@ -1,12 +1,12 @@
using NUnit.Framework; using NUnit.Framework;
namespace NzbDrone.Integration.Test.ApiTests namespace NzbDrone.Integration.Test.ApiTests
{ {
[TestFixture] [TestFixture]
public class TrackFileFixture : IntegrationTest public class BookFileFixture : IntegrationTest
{ {
[Test] [Test]
public void get_all_trackfiles() public void get_all_bookfiles()
{ {
Assert.Ignore("TODO"); Assert.Ignore("TODO");
} }

View File

@@ -4,31 +4,31 @@ using System.Linq;
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Integration.Test.Client; using NzbDrone.Integration.Test.Client;
using Readarr.Api.V1.Albums; using Readarr.Api.V1.Books;
namespace NzbDrone.Integration.Test.ApiTests namespace NzbDrone.Integration.Test.ApiTests
{ {
[TestFixture] [TestFixture]
public class CalendarFixture : IntegrationTest public class CalendarFixture : IntegrationTest
{ {
public ClientBase<AlbumResource> Calendar; public ClientBase<BookResource> Calendar;
protected override void InitRestClients() protected override void InitRestClients()
{ {
base.InitRestClients(); base.InitRestClients();
Calendar = new ClientBase<AlbumResource>(RestClient, ApiKey, "calendar"); Calendar = new ClientBase<BookResource>(RestClient, ApiKey, "calendar");
} }
[Test] [Test]
public void should_be_able_to_get_albums() public void should_be_able_to_get_albums()
{ {
var artist = EnsureArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", true); var artist = EnsureAuthor("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", true);
var request = Calendar.BuildRequest(); var request = Calendar.BuildRequest();
request.AddParameter("start", new DateTime(2003, 06, 20).ToString("s") + "Z"); request.AddParameter("start", new DateTime(2003, 06, 20).ToString("s") + "Z");
request.AddParameter("end", new DateTime(2003, 06, 22).ToString("s") + "Z"); request.AddParameter("end", new DateTime(2003, 06, 22).ToString("s") + "Z");
var items = Calendar.Get<List<AlbumResource>>(request); var items = Calendar.Get<List<BookResource>>(request);
items = items.Where(v => v.AuthorId == artist.Id).ToList(); items = items.Where(v => v.AuthorId == artist.Id).ToList();
@@ -39,13 +39,13 @@ namespace NzbDrone.Integration.Test.ApiTests
[Test] [Test]
public void should_not_be_able_to_get_unmonitored_albums() public void should_not_be_able_to_get_unmonitored_albums()
{ {
var artist = EnsureArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", false); var artist = EnsureAuthor("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", false);
var request = Calendar.BuildRequest(); var request = Calendar.BuildRequest();
request.AddParameter("start", new DateTime(2003, 06, 20).ToString("s") + "Z"); request.AddParameter("start", new DateTime(2003, 06, 20).ToString("s") + "Z");
request.AddParameter("end", new DateTime(2003, 06, 22).ToString("s") + "Z"); request.AddParameter("end", new DateTime(2003, 06, 22).ToString("s") + "Z");
request.AddParameter("unmonitored", "false"); request.AddParameter("unmonitored", "false");
var items = Calendar.Get<List<AlbumResource>>(request); var items = Calendar.Get<List<BookResource>>(request);
items = items.Where(v => v.AuthorId == artist.Id).ToList(); items = items.Where(v => v.AuthorId == artist.Id).ToList();
@@ -55,13 +55,13 @@ namespace NzbDrone.Integration.Test.ApiTests
[Test] [Test]
public void should_be_able_to_get_unmonitored_albums() public void should_be_able_to_get_unmonitored_albums()
{ {
var artist = EnsureArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", false); var artist = EnsureAuthor("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", false);
var request = Calendar.BuildRequest(); var request = Calendar.BuildRequest();
request.AddParameter("start", new DateTime(2003, 06, 20).ToString("s") + "Z"); request.AddParameter("start", new DateTime(2003, 06, 20).ToString("s") + "Z");
request.AddParameter("end", new DateTime(2003, 06, 22).ToString("s") + "Z"); request.AddParameter("end", new DateTime(2003, 06, 22).ToString("s") + "Z");
request.AddParameter("unmonitored", "true"); request.AddParameter("unmonitored", "true");
var items = Calendar.Get<List<AlbumResource>>(request); var items = Calendar.Get<List<BookResource>>(request);
items = items.Where(v => v.AuthorId == artist.Id).ToList(); items = items.Where(v => v.AuthorId == artist.Id).ToList();

View File

@@ -47,7 +47,7 @@ namespace NzbDrone.Integration.Test.ApiTests
releaseResource.Age.Should().BeGreaterOrEqualTo(-1); releaseResource.Age.Should().BeGreaterOrEqualTo(-1);
releaseResource.Title.Should().NotBeNullOrWhiteSpace(); releaseResource.Title.Should().NotBeNullOrWhiteSpace();
releaseResource.DownloadUrl.Should().NotBeNullOrWhiteSpace(); releaseResource.DownloadUrl.Should().NotBeNullOrWhiteSpace();
releaseResource.ArtistName.Should().NotBeNullOrWhiteSpace(); releaseResource.AuthorName.Should().NotBeNullOrWhiteSpace();
//TODO: uncomment these after moving to restsharp for rss //TODO: uncomment these after moving to restsharp for rss
//releaseResource.NzbInfoUrl.Should().NotBeNullOrWhiteSpace(); //releaseResource.NzbInfoUrl.Should().NotBeNullOrWhiteSpace();

View File

@@ -17,7 +17,7 @@ namespace NzbDrone.Integration.Test.ApiTests
RootFolders.Post(new RootFolderResource RootFolders.Post(new RootFolderResource
{ {
Name = "TestLibrary", Name = "TestLibrary",
Path = ArtistRootFolder, Path = AuthorRootFolder,
DefaultMetadataProfileId = 1, DefaultMetadataProfileId = 1,
DefaultQualityProfileId = 1, DefaultQualityProfileId = 1,
DefaultMonitorOption = MonitorTypes.All DefaultMonitorOption = MonitorTypes.All
@@ -39,7 +39,7 @@ namespace NzbDrone.Integration.Test.ApiTests
[Order(1)] [Order(1)]
public void missing_should_have_monitored_items() public void missing_should_have_monitored_items()
{ {
EnsureArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", true); EnsureAuthor("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", true);
var result = WantedMissing.GetPaged(0, 15, "releaseDate", "desc"); var result = WantedMissing.GetPaged(0, 15, "releaseDate", "desc");
@@ -50,12 +50,12 @@ namespace NzbDrone.Integration.Test.ApiTests
[Order(1)] [Order(1)]
public void missing_should_have_artist() public void missing_should_have_artist()
{ {
EnsureArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", true); EnsureAuthor("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", true);
var result = WantedMissing.GetPaged(0, 15, "releaseDate", "desc"); var result = WantedMissing.GetPaged(0, 15, "releaseDate", "desc");
result.Records.First().Artist.Should().NotBeNull(); result.Records.First().Author.Should().NotBeNull();
result.Records.First().Artist.ArtistName.Should().Be("J.K. Rowling"); result.Records.First().Author.AuthorName.Should().Be("J.K. Rowling");
} }
[Test] [Test]
@@ -63,8 +63,8 @@ namespace NzbDrone.Integration.Test.ApiTests
public void cutoff_should_have_monitored_items() public void cutoff_should_have_monitored_items()
{ {
EnsureProfileCutoff(1, Quality.AZW3); EnsureProfileCutoff(1, Quality.AZW3);
var artist = EnsureArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", true); var artist = EnsureAuthor("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", true);
EnsureTrackFile(artist, 1, Quality.MOBI); EnsureBookFile(artist, 1, Quality.MOBI);
var result = WantedCutoffUnmet.GetPaged(0, 15, "releaseDate", "desc"); var result = WantedCutoffUnmet.GetPaged(0, 15, "releaseDate", "desc");
@@ -75,7 +75,7 @@ namespace NzbDrone.Integration.Test.ApiTests
[Order(1)] [Order(1)]
public void missing_should_not_have_unmonitored_items() public void missing_should_not_have_unmonitored_items()
{ {
EnsureArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", false); EnsureAuthor("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", false);
var result = WantedMissing.GetPaged(0, 15, "releaseDate", "desc"); var result = WantedMissing.GetPaged(0, 15, "releaseDate", "desc");
@@ -87,8 +87,8 @@ namespace NzbDrone.Integration.Test.ApiTests
public void cutoff_should_not_have_unmonitored_items() public void cutoff_should_not_have_unmonitored_items()
{ {
EnsureProfileCutoff(1, Quality.AZW3); EnsureProfileCutoff(1, Quality.AZW3);
var artist = EnsureArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", false); var artist = EnsureAuthor("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", false);
EnsureTrackFile(artist, 1, Quality.MOBI); EnsureBookFile(artist, 1, Quality.MOBI);
var result = WantedCutoffUnmet.GetPaged(0, 15, "releaseDate", "desc"); var result = WantedCutoffUnmet.GetPaged(0, 15, "releaseDate", "desc");
@@ -100,20 +100,20 @@ namespace NzbDrone.Integration.Test.ApiTests
public void cutoff_should_have_artist() public void cutoff_should_have_artist()
{ {
EnsureProfileCutoff(1, Quality.AZW3); EnsureProfileCutoff(1, Quality.AZW3);
var artist = EnsureArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", true); var artist = EnsureAuthor("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", true);
EnsureTrackFile(artist, 1, Quality.MOBI); EnsureBookFile(artist, 1, Quality.MOBI);
var result = WantedCutoffUnmet.GetPaged(0, 15, "releaseDate", "desc"); var result = WantedCutoffUnmet.GetPaged(0, 15, "releaseDate", "desc");
result.Records.First().Artist.Should().NotBeNull(); result.Records.First().Author.Should().NotBeNull();
result.Records.First().Artist.ArtistName.Should().Be("J.K. Rowling"); result.Records.First().Author.AuthorName.Should().Be("J.K. Rowling");
} }
[Test] [Test]
[Order(2)] [Order(2)]
public void missing_should_have_unmonitored_items() public void missing_should_have_unmonitored_items()
{ {
EnsureArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", false); EnsureAuthor("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", false);
var result = WantedMissing.GetPaged(0, 15, "releaseDate", "desc", "monitored", "false"); var result = WantedMissing.GetPaged(0, 15, "releaseDate", "desc", "monitored", "false");
@@ -125,8 +125,8 @@ namespace NzbDrone.Integration.Test.ApiTests
public void cutoff_should_have_unmonitored_items() public void cutoff_should_have_unmonitored_items()
{ {
EnsureProfileCutoff(1, Quality.AZW3); EnsureProfileCutoff(1, Quality.AZW3);
var artist = EnsureArtist("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", false); var artist = EnsureAuthor("amzn1.gr.author.v1.SHA8asP5mFyLIP9NlujvLQ", "1", "J.K. Rowling", false);
EnsureTrackFile(artist, 1, Quality.MOBI); EnsureBookFile(artist, 1, Quality.MOBI);
var result = WantedCutoffUnmet.GetPaged(0, 15, "releaseDate", "desc", "monitored", "false"); var result = WantedCutoffUnmet.GetPaged(0, 15, "releaseDate", "desc", "monitored", "false");

View File

@@ -1,20 +0,0 @@
using System.Collections.Generic;
using Readarr.Api.V1.Albums;
using RestSharp;
namespace NzbDrone.Integration.Test.Client
{
public class AlbumClient : ClientBase<AlbumResource>
{
public AlbumClient(IRestClient restClient, string apiKey)
: base(restClient, apiKey, "album")
{
}
public List<AlbumResource> GetAlbumsInArtist(int authorId)
{
var request = BuildRequest("?authorId=" + authorId.ToString());
return Get<List<AlbumResource>>(request);
}
}
}

View File

@@ -1,39 +1,39 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using Readarr.Api.V1.Artist; using Readarr.Api.V1.Author;
using RestSharp; using RestSharp;
namespace NzbDrone.Integration.Test.Client namespace NzbDrone.Integration.Test.Client
{ {
public class ArtistClient : ClientBase<ArtistResource> public class AuthorClient : ClientBase<AuthorResource>
{ {
public ArtistClient(IRestClient restClient, string apiKey) public AuthorClient(IRestClient restClient, string apiKey)
: base(restClient, apiKey) : base(restClient, apiKey)
{ {
} }
public List<ArtistResource> Lookup(string term) public List<AuthorResource> Lookup(string term)
{ {
var request = BuildRequest("lookup"); var request = BuildRequest("lookup");
request.AddQueryParameter("term", term); request.AddQueryParameter("term", term);
return Get<List<ArtistResource>>(request); return Get<List<AuthorResource>>(request);
} }
public List<ArtistResource> Editor(ArtistEditorResource artist) public List<AuthorResource> Editor(AuthorEditorResource artist)
{ {
var request = BuildRequest("editor"); var request = BuildRequest("editor");
request.AddJsonBody(artist); request.AddJsonBody(artist);
return Put<List<ArtistResource>>(request); return Put<List<AuthorResource>>(request);
} }
public ArtistResource Get(string slug, HttpStatusCode statusCode = HttpStatusCode.OK) public AuthorResource Get(string slug, HttpStatusCode statusCode = HttpStatusCode.OK)
{ {
var request = BuildRequest(slug); var request = BuildRequest(slug);
return Get<ArtistResource>(request, statusCode); return Get<AuthorResource>(request, statusCode);
} }
} }
public class SystemInfoClient : ClientBase<ArtistResource> public class SystemInfoClient : ClientBase<AuthorResource>
{ {
public SystemInfoClient(IRestClient restClient, string apiKey) public SystemInfoClient(IRestClient restClient, string apiKey)
: base(restClient, apiKey) : base(restClient, apiKey)

View File

@@ -0,0 +1,20 @@
using System.Collections.Generic;
using Readarr.Api.V1.Books;
using RestSharp;
namespace NzbDrone.Integration.Test.Client
{
public class BookClient : ClientBase<BookResource>
{
public BookClient(IRestClient restClient, string apiKey)
: base(restClient, apiKey, "book")
{
}
public List<BookResource> GetBooksInAuthor(int authorId)
{
var request = BuildRequest("?authorId=" + authorId.ToString());
return Get<List<BookResource>>(request);
}
}
}

View File

@@ -8,7 +8,7 @@ namespace NzbDrone.Integration.Test
[TestFixture] [TestFixture]
public class CorsFixture : IntegrationTest public class CorsFixture : IntegrationTest
{ {
private RestRequest BuildGet(string route = "artist") private RestRequest BuildGet(string route = "author")
{ {
var request = new RestRequest(route, Method.GET); var request = new RestRequest(route, Method.GET);
request.AddHeader(AccessControlHeaders.RequestMethod, "POST"); request.AddHeader(AccessControlHeaders.RequestMethod, "POST");
@@ -16,7 +16,7 @@ namespace NzbDrone.Integration.Test
return request; return request;
} }
private RestRequest BuildOptions(string route = "artist") private RestRequest BuildOptions(string route = "author")
{ {
var request = new RestRequest(route, Method.OPTIONS); var request = new RestRequest(route, Method.OPTIONS);

View File

@@ -17,20 +17,20 @@ namespace NzbDrone.Integration.Test
config.LogLevel = "Trace"; config.LogLevel = "Trace";
HostConfig.Put(config); HostConfig.Put(config);
var resultGet = Artist.All(); var resultGet = Author.All();
var logFile = "Readarr.trace.txt"; var logFile = "Readarr.trace.txt";
var logLines = Logs.GetLogFileLines(logFile); var logLines = Logs.GetLogFileLines(logFile);
var result = Artist.InvalidPost(new Readarr.Api.V1.Artist.ArtistResource()); var result = Author.InvalidPost(new Readarr.Api.V1.Author.AuthorResource());
// Skip 2 and 1 to ignore the logs endpoint // Skip 2 and 1 to ignore the logs endpoint
logLines = Logs.GetLogFileLines(logFile).Skip(logLines.Length + 2).ToArray(); logLines = Logs.GetLogFileLines(logFile).Skip(logLines.Length + 2).ToArray();
Array.Resize(ref logLines, logLines.Length - 1); Array.Resize(ref logLines, logLines.Length - 1);
logLines.Should().Contain(v => v.Contains("|Trace|Http|Req") && v.Contains("/api/v1/artist/")); logLines.Should().Contain(v => v.Contains("|Trace|Http|Req") && v.Contains("/api/v1/author/"));
logLines.Should().Contain(v => v.Contains("|Trace|Http|Res") && v.Contains("/api/v1/artist/: 400.BadRequest")); logLines.Should().Contain(v => v.Contains("|Trace|Http|Res") && v.Contains("/api/v1/author/: 400.BadRequest"));
logLines.Should().Contain(v => v.Contains("|Debug|Api|") && v.Contains("/api/v1/artist/: 400.BadRequest")); logLines.Should().Contain(v => v.Contains("|Debug|Api|") && v.Contains("/api/v1/author/: 400.BadRequest"));
} }
} }
} }

View File

@@ -9,7 +9,7 @@ namespace NzbDrone.Integration.Test
{ {
protected NzbDroneRunner _runner; protected NzbDroneRunner _runner;
public override string ArtistRootFolder => GetTempDirectory("ArtistRootFolder"); public override string AuthorRootFolder => GetTempDirectory("AuthorRootFolder");
protected override string RootUrl => "http://localhost:8787/"; protected override string RootUrl => "http://localhost:8787/";

View File

@@ -17,9 +17,9 @@ using NzbDrone.Integration.Test.Client;
using NzbDrone.SignalR; using NzbDrone.SignalR;
using NzbDrone.Test.Common; using NzbDrone.Test.Common;
using NzbDrone.Test.Common.Categories; using NzbDrone.Test.Common.Categories;
using Readarr.Api.V1.Albums; using Readarr.Api.V1.Author;
using Readarr.Api.V1.Artist;
using Readarr.Api.V1.Blacklist; using Readarr.Api.V1.Blacklist;
using Readarr.Api.V1.Books;
using Readarr.Api.V1.Config; using Readarr.Api.V1.Config;
using Readarr.Api.V1.DownloadClient; using Readarr.Api.V1.DownloadClient;
using Readarr.Api.V1.History; using Readarr.Api.V1.History;
@@ -38,7 +38,7 @@ namespace NzbDrone.Integration.Test
public ClientBase<BlacklistResource> Blacklist; public ClientBase<BlacklistResource> Blacklist;
public CommandClient Commands; public CommandClient Commands;
public DownloadClientClient DownloadClients; public DownloadClientClient DownloadClients;
public AlbumClient Albums; public BookClient Books;
public ClientBase<HistoryResource> History; public ClientBase<HistoryResource> History;
public ClientBase<HostConfigResource> HostConfig; public ClientBase<HostConfigResource> HostConfig;
public IndexerClient Indexers; public IndexerClient Indexers;
@@ -49,10 +49,10 @@ namespace NzbDrone.Integration.Test
public ReleaseClient Releases; public ReleaseClient Releases;
public ReleasePushClient ReleasePush; public ReleasePushClient ReleasePush;
public ClientBase<RootFolderResource> RootFolders; public ClientBase<RootFolderResource> RootFolders;
public ArtistClient Artist; public AuthorClient Author;
public ClientBase<TagResource> Tags; public ClientBase<TagResource> Tags;
public ClientBase<AlbumResource> WantedMissing; public ClientBase<BookResource> WantedMissing;
public ClientBase<AlbumResource> WantedCutoffUnmet; public ClientBase<BookResource> WantedCutoffUnmet;
private List<SignalRMessage> _signalRReceived; private List<SignalRMessage> _signalRReceived;
@@ -72,7 +72,7 @@ namespace NzbDrone.Integration.Test
public string TempDirectory { get; private set; } public string TempDirectory { get; private set; }
public abstract string ArtistRootFolder { get; } public abstract string AuthorRootFolder { get; }
protected abstract string RootUrl { get; } protected abstract string RootUrl { get; }
@@ -101,7 +101,7 @@ namespace NzbDrone.Integration.Test
Blacklist = new ClientBase<BlacklistResource>(RestClient, ApiKey); Blacklist = new ClientBase<BlacklistResource>(RestClient, ApiKey);
Commands = new CommandClient(RestClient, ApiKey); Commands = new CommandClient(RestClient, ApiKey);
DownloadClients = new DownloadClientClient(RestClient, ApiKey); DownloadClients = new DownloadClientClient(RestClient, ApiKey);
Albums = new AlbumClient(RestClient, ApiKey); Books = new BookClient(RestClient, ApiKey);
History = new ClientBase<HistoryResource>(RestClient, ApiKey); History = new ClientBase<HistoryResource>(RestClient, ApiKey);
HostConfig = new ClientBase<HostConfigResource>(RestClient, ApiKey, "config/host"); HostConfig = new ClientBase<HostConfigResource>(RestClient, ApiKey, "config/host");
Indexers = new IndexerClient(RestClient, ApiKey); Indexers = new IndexerClient(RestClient, ApiKey);
@@ -112,10 +112,10 @@ namespace NzbDrone.Integration.Test
Releases = new ReleaseClient(RestClient, ApiKey); Releases = new ReleaseClient(RestClient, ApiKey);
ReleasePush = new ReleasePushClient(RestClient, ApiKey); ReleasePush = new ReleasePushClient(RestClient, ApiKey);
RootFolders = new ClientBase<RootFolderResource>(RestClient, ApiKey); RootFolders = new ClientBase<RootFolderResource>(RestClient, ApiKey);
Artist = new ArtistClient(RestClient, ApiKey); Author = new AuthorClient(RestClient, ApiKey);
Tags = new ClientBase<TagResource>(RestClient, ApiKey); Tags = new ClientBase<TagResource>(RestClient, ApiKey);
WantedMissing = new ClientBase<AlbumResource>(RestClient, ApiKey, "wanted/missing"); WantedMissing = new ClientBase<BookResource>(RestClient, ApiKey, "wanted/missing");
WantedCutoffUnmet = new ClientBase<AlbumResource>(RestClient, ApiKey, "wanted/cutoff"); WantedCutoffUnmet = new ClientBase<BookResource>(RestClient, ApiKey, "wanted/cutoff");
} }
[OneTimeTearDown] [OneTimeTearDown]
@@ -249,33 +249,33 @@ namespace NzbDrone.Integration.Test
Assert.Fail("Timed on wait"); Assert.Fail("Timed on wait");
} }
public ArtistResource EnsureArtist(string authorId, string goodreadsBookId, string artistName, bool? monitored = null) public AuthorResource EnsureAuthor(string authorId, string goodreadsBookId, string authorName, bool? monitored = null)
{ {
var result = Artist.All().FirstOrDefault(v => v.ForeignAuthorId == authorId); var result = Author.All().FirstOrDefault(v => v.ForeignAuthorId == authorId);
if (result == null) if (result == null)
{ {
var lookup = Artist.Lookup("readarr:" + goodreadsBookId); var lookup = Author.Lookup("readarr:" + goodreadsBookId);
var artist = lookup.First(); var author = lookup.First();
artist.QualityProfileId = 1; author.QualityProfileId = 1;
artist.MetadataProfileId = 1; author.MetadataProfileId = 1;
artist.Path = Path.Combine(ArtistRootFolder, artist.ArtistName); author.Path = Path.Combine(AuthorRootFolder, author.AuthorName);
artist.Monitored = true; author.Monitored = true;
artist.AddOptions = new Core.Books.AddAuthorOptions(); author.AddOptions = new Core.Books.AddAuthorOptions();
Directory.CreateDirectory(artist.Path); Directory.CreateDirectory(author.Path);
result = Artist.Post(artist); result = Author.Post(author);
Commands.WaitAll(); Commands.WaitAll();
WaitForCompletion(() => Albums.GetAlbumsInArtist(result.Id).Count > 0); WaitForCompletion(() => Books.GetBooksInAuthor(result.Id).Count > 0);
} }
var changed = false; var changed = false;
if (result.RootFolderPath != ArtistRootFolder) if (result.RootFolderPath != AuthorRootFolder)
{ {
changed = true; changed = true;
result.RootFolderPath = ArtistRootFolder; result.RootFolderPath = AuthorRootFolder;
result.Path = Path.Combine(ArtistRootFolder, result.ArtistName); result.Path = Path.Combine(AuthorRootFolder, result.AuthorName);
} }
if (monitored.HasValue) if (monitored.HasValue)
@@ -289,7 +289,7 @@ namespace NzbDrone.Integration.Test
if (changed) if (changed)
{ {
Artist.Put(result); Author.Put(result);
} }
return result; return result;
@@ -297,22 +297,22 @@ namespace NzbDrone.Integration.Test
public void EnsureNoArtist(string readarrId, string artistTitle) public void EnsureNoArtist(string readarrId, string artistTitle)
{ {
var result = Artist.All().FirstOrDefault(v => v.ForeignAuthorId == readarrId); var result = Author.All().FirstOrDefault(v => v.ForeignAuthorId == readarrId);
if (result != null) if (result != null)
{ {
Artist.Delete(result.Id); Author.Delete(result.Id);
} }
} }
public void EnsureTrackFile(ArtistResource artist, int bookId, Quality quality) public void EnsureBookFile(AuthorResource artist, int bookId, Quality quality)
{ {
var result = Albums.GetAlbumsInArtist(artist.Id).Single(v => v.Id == bookId); var result = Books.GetBooksInAuthor(artist.Id).Single(v => v.Id == bookId);
// if (result.BookFile == null) // if (result.BookFile == null)
if (true) if (true)
{ {
var path = Path.Combine(ArtistRootFolder, artist.ArtistName, "Track.mp3"); var path = Path.Combine(AuthorRootFolder, artist.AuthorName, "Track.mp3");
Directory.CreateDirectory(Path.GetDirectoryName(path)); Directory.CreateDirectory(Path.GetDirectoryName(path));
File.WriteAllText(path, "Fake Track"); File.WriteAllText(path, "Fake Track");
@@ -332,7 +332,7 @@ namespace NzbDrone.Integration.Test
}); });
Commands.WaitAll(); Commands.WaitAll();
var track = Albums.GetAlbumsInArtist(artist.Id).Single(x => x.Id == bookId); var track = Books.GetBooksInAuthor(artist.Id).Single(x => x.Id == bookId);
// track.BookFileId.Should().NotBe(0); // track.BookFileId.Should().NotBe(0);
} }

View File

@@ -1,12 +0,0 @@
using System.Collections.Generic;
using Readarr.Api.V1.Albums;
namespace Readarr.Api.V1.AlbumStudio
{
public class AlbumStudioArtistResource
{
public int Id { get; set; }
public bool? Monitored { get; set; }
public List<AlbumResource> Albums { get; set; }
}
}

View File

@@ -1,47 +0,0 @@
using System.Linq;
using Nancy;
using NzbDrone.Core.Books;
using Readarr.Http.Extensions;
namespace Readarr.Api.V1.AlbumStudio
{
public class AlbumStudioModule : ReadarrV1Module
{
private readonly IAuthorService _authorService;
private readonly IBookMonitoredService _albumMonitoredService;
public AlbumStudioModule(IAuthorService authorService, IBookMonitoredService albumMonitoredService)
: base("/albumstudio")
{
_authorService = authorService;
_albumMonitoredService = albumMonitoredService;
Post("/", artist => UpdateAll());
}
private object UpdateAll()
{
//Read from request
var request = Request.Body.FromJson<AlbumStudioResource>();
var artistToUpdate = _authorService.GetAuthors(request.Artist.Select(s => s.Id));
foreach (var s in request.Artist)
{
var artist = artistToUpdate.Single(c => c.Id == s.Id);
if (s.Monitored.HasValue)
{
artist.Monitored = s.Monitored.Value;
}
if (request.MonitoringOptions != null && request.MonitoringOptions.Monitor == MonitorTypes.None)
{
artist.Monitored = false;
}
_albumMonitoredService.SetBookMonitoredStatus(artist, request.MonitoringOptions);
}
return ResponseWithCode("ok", HttpStatusCode.Accepted);
}
}
}

View File

@@ -1,133 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.AuthorStats;
using NzbDrone.Core.Books;
using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.MediaCover;
using NzbDrone.SignalR;
using Readarr.Api.V1.Artist;
using Readarr.Http;
namespace Readarr.Api.V1.Albums
{
public abstract class AlbumModuleWithSignalR : ReadarrRestModuleWithSignalR<AlbumResource, Book>
{
protected readonly IBookService _bookService;
protected readonly IAuthorStatisticsService _artistStatisticsService;
protected readonly IUpgradableSpecification _qualityUpgradableSpecification;
protected readonly IMapCoversToLocal _coverMapper;
protected AlbumModuleWithSignalR(IBookService bookService,
IAuthorStatisticsService artistStatisticsService,
IMapCoversToLocal coverMapper,
IUpgradableSpecification qualityUpgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster)
: base(signalRBroadcaster)
{
_bookService = bookService;
_artistStatisticsService = artistStatisticsService;
_coverMapper = coverMapper;
_qualityUpgradableSpecification = qualityUpgradableSpecification;
GetResourceById = GetAlbum;
}
protected AlbumModuleWithSignalR(IBookService bookService,
IAuthorStatisticsService artistStatisticsService,
IMapCoversToLocal coverMapper,
IUpgradableSpecification qualityUpgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster,
string resource)
: base(signalRBroadcaster, resource)
{
_bookService = bookService;
_artistStatisticsService = artistStatisticsService;
_coverMapper = coverMapper;
_qualityUpgradableSpecification = qualityUpgradableSpecification;
GetResourceById = GetAlbum;
}
protected AlbumResource GetAlbum(int id)
{
var album = _bookService.GetBook(id);
var resource = MapToResource(album, true);
return resource;
}
protected AlbumResource MapToResource(Book album, bool includeArtist)
{
var resource = album.ToResource();
if (includeArtist)
{
var artist = album.Author.Value;
resource.Artist = artist.ToResource();
}
FetchAndLinkAlbumStatistics(resource);
MapCoversToLocal(resource);
return resource;
}
protected List<AlbumResource> MapToResource(List<Book> albums, bool includeArtist)
{
var result = albums.ToResource();
if (includeArtist)
{
var artistDict = new Dictionary<int, NzbDrone.Core.Books.Author>();
for (var i = 0; i < albums.Count; i++)
{
var album = albums[i];
var resource = result[i];
var artist = artistDict.GetValueOrDefault(albums[i].AuthorMetadataId) ?? album.Author?.Value;
artistDict[artist.AuthorMetadataId] = artist;
resource.Artist = artist.ToResource();
}
}
var artistStats = _artistStatisticsService.AuthorStatistics();
LinkArtistStatistics(result, artistStats);
MapCoversToLocal(result.ToArray());
return result;
}
private void FetchAndLinkAlbumStatistics(AlbumResource resource)
{
LinkArtistStatistics(resource, _artistStatisticsService.AuthorStatistics(resource.AuthorId));
}
private void LinkArtistStatistics(List<AlbumResource> resources, List<AuthorStatistics> artistStatistics)
{
foreach (var album in resources)
{
var stats = artistStatistics.SingleOrDefault(ss => ss.AuthorId == album.AuthorId);
LinkArtistStatistics(album, stats);
}
}
private void LinkArtistStatistics(AlbumResource resource, AuthorStatistics artistStatistics)
{
if (artistStatistics?.BookStatistics != null)
{
var dictAlbumStats = artistStatistics.BookStatistics.ToDictionary(v => v.BookId);
resource.Statistics = dictAlbumStats.GetValueOrDefault(resource.Id).ToResource();
}
}
private void MapCoversToLocal(params AlbumResource[] albums)
{
foreach (var albumResource in albums)
{
_coverMapper.ConvertToLocalUrls(albumResource.Id, MediaCoverEntity.Book, albumResource.Images);
}
}
}
}

View File

@@ -1,43 +0,0 @@
using NzbDrone.Core.AuthorStats;
namespace Readarr.Api.V1.Albums
{
public class AlbumStatisticsResource
{
public int TrackFileCount { get; set; }
public int TrackCount { get; set; }
public int TotalTrackCount { get; set; }
public long SizeOnDisk { get; set; }
public decimal PercentOfTracks
{
get
{
if (TrackCount == 0)
{
return 0;
}
return TrackFileCount / (decimal)TrackCount * 100;
}
}
}
public static class AlbumStatisticsResourceMapper
{
public static AlbumStatisticsResource ToResource(this BookStatistics model)
{
if (model == null)
{
return null;
}
return new AlbumStatisticsResource
{
TrackFileCount = model.BookFileCount,
TrackCount = model.BookCount,
SizeOnDisk = model.SizeOnDisk
};
}
}
}

View File

@@ -1,4 +1,4 @@
namespace Readarr.Api.V1.Artist namespace Readarr.Api.V1.Author
{ {
public class AlternateTitleResource public class AlternateTitleResource
{ {

View File

@@ -1,8 +1,8 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace Readarr.Api.V1.Artist namespace Readarr.Api.V1.Author
{ {
public class ArtistEditorDeleteResource public class AuthorEditorDeleteResource
{ {
public List<int> AuthorIds { get; set; } public List<int> AuthorIds { get; set; }
public bool DeleteFiles { get; set; } public bool DeleteFiles { get; set; }

View File

@@ -7,52 +7,52 @@ using NzbDrone.Core.Books.Commands;
using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Commands;
using Readarr.Http.Extensions; using Readarr.Http.Extensions;
namespace Readarr.Api.V1.Artist namespace Readarr.Api.V1.Author
{ {
public class ArtistEditorModule : ReadarrV1Module public class AuthorEditorModule : ReadarrV1Module
{ {
private readonly IAuthorService _authorService; private readonly IAuthorService _authorService;
private readonly IManageCommandQueue _commandQueueManager; private readonly IManageCommandQueue _commandQueueManager;
public ArtistEditorModule(IAuthorService authorService, IManageCommandQueue commandQueueManager) public AuthorEditorModule(IAuthorService authorService, IManageCommandQueue commandQueueManager)
: base("/artist/editor") : base("/author/editor")
{ {
_authorService = authorService; _authorService = authorService;
_commandQueueManager = commandQueueManager; _commandQueueManager = commandQueueManager;
Put("/", artist => SaveAll()); Put("/", author => SaveAll());
Delete("/", artist => DeleteArtist()); Delete("/", author => DeleteAuthor());
} }
private object SaveAll() private object SaveAll()
{ {
var resource = Request.Body.FromJson<ArtistEditorResource>(); var resource = Request.Body.FromJson<AuthorEditorResource>();
var artistToUpdate = _authorService.GetAuthors(resource.AuthorIds); var authorsToUpdate = _authorService.GetAuthors(resource.AuthorIds);
var artistToMove = new List<BulkMoveAuthor>(); var authorsToMove = new List<BulkMoveAuthor>();
foreach (var artist in artistToUpdate) foreach (var author in authorsToUpdate)
{ {
if (resource.Monitored.HasValue) if (resource.Monitored.HasValue)
{ {
artist.Monitored = resource.Monitored.Value; author.Monitored = resource.Monitored.Value;
} }
if (resource.QualityProfileId.HasValue) if (resource.QualityProfileId.HasValue)
{ {
artist.QualityProfileId = resource.QualityProfileId.Value; author.QualityProfileId = resource.QualityProfileId.Value;
} }
if (resource.MetadataProfileId.HasValue) if (resource.MetadataProfileId.HasValue)
{ {
artist.MetadataProfileId = resource.MetadataProfileId.Value; author.MetadataProfileId = resource.MetadataProfileId.Value;
} }
if (resource.RootFolderPath.IsNotNullOrWhiteSpace()) if (resource.RootFolderPath.IsNotNullOrWhiteSpace())
{ {
artist.RootFolderPath = resource.RootFolderPath; author.RootFolderPath = resource.RootFolderPath;
artistToMove.Add(new BulkMoveAuthor authorsToMove.Add(new BulkMoveAuthor
{ {
AuthorId = artist.Id, AuthorId = author.Id,
SourcePath = artist.Path SourcePath = author.Path
}); });
} }
@@ -64,35 +64,35 @@ namespace Readarr.Api.V1.Artist
switch (applyTags) switch (applyTags)
{ {
case ApplyTags.Add: case ApplyTags.Add:
newTags.ForEach(t => artist.Tags.Add(t)); newTags.ForEach(t => author.Tags.Add(t));
break; break;
case ApplyTags.Remove: case ApplyTags.Remove:
newTags.ForEach(t => artist.Tags.Remove(t)); newTags.ForEach(t => author.Tags.Remove(t));
break; break;
case ApplyTags.Replace: case ApplyTags.Replace:
artist.Tags = new HashSet<int>(newTags); author.Tags = new HashSet<int>(newTags);
break; break;
} }
} }
} }
if (resource.MoveFiles && artistToMove.Any()) if (resource.MoveFiles && authorsToMove.Any())
{ {
_commandQueueManager.Push(new BulkMoveAuthorCommand _commandQueueManager.Push(new BulkMoveAuthorCommand
{ {
DestinationRootFolder = resource.RootFolderPath, DestinationRootFolder = resource.RootFolderPath,
Author = artistToMove Author = authorsToMove
}); });
} }
return ResponseWithCode(_authorService.UpdateAuthors(artistToUpdate, !resource.MoveFiles) return ResponseWithCode(_authorService.UpdateAuthors(authorsToUpdate, !resource.MoveFiles)
.ToResource(), .ToResource(),
HttpStatusCode.Accepted); HttpStatusCode.Accepted);
} }
private object DeleteArtist() private object DeleteAuthor()
{ {
var resource = Request.Body.FromJson<ArtistEditorResource>(); var resource = Request.Body.FromJson<AuthorEditorResource>();
foreach (var authorId in resource.AuthorIds) foreach (var authorId in resource.AuthorIds)
{ {

View File

@@ -1,14 +1,13 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace Readarr.Api.V1.Artist namespace Readarr.Api.V1.Author
{ {
public class ArtistEditorResource public class AuthorEditorResource
{ {
public List<int> AuthorIds { get; set; } public List<int> AuthorIds { get; set; }
public bool? Monitored { get; set; } public bool? Monitored { get; set; }
public int? QualityProfileId { get; set; } public int? QualityProfileId { get; set; }
public int? MetadataProfileId { get; set; } public int? MetadataProfileId { get; set; }
public bool? AlbumFolder { get; set; }
public string RootFolderPath { get; set; } public string RootFolderPath { get; set; }
public List<int> Tags { get; set; } public List<int> Tags { get; set; }
public ApplyTags ApplyTags { get; set; } public ApplyTags ApplyTags { get; set; }

View File

@@ -4,14 +4,14 @@ using NzbDrone.Core.Books;
using Readarr.Http; using Readarr.Http;
using Readarr.Http.Extensions; using Readarr.Http.Extensions;
namespace Readarr.Api.V1.Artist namespace Readarr.Api.V1.Author
{ {
public class ArtistImportModule : ReadarrRestModule<ArtistResource> public class AuthorImportModule : ReadarrRestModule<AuthorResource>
{ {
private readonly IAddAuthorService _addAuthorService; private readonly IAddAuthorService _addAuthorService;
public ArtistImportModule(IAddAuthorService addAuthorService) public AuthorImportModule(IAddAuthorService addAuthorService)
: base("/artist/import") : base("/author/import")
{ {
_addAuthorService = addAuthorService; _addAuthorService = addAuthorService;
Post("/", x => Import()); Post("/", x => Import());
@@ -19,10 +19,10 @@ namespace Readarr.Api.V1.Artist
private object Import() private object Import()
{ {
var resource = Request.Body.FromJson<List<ArtistResource>>(); var resource = Request.Body.FromJson<List<AuthorResource>>();
var newArtists = resource.ToModel(); var newAuthors = resource.ToModel();
return _addAuthorService.AddAuthors(newArtists).ToResource(); return _addAuthorService.AddAuthors(newAuthors).ToResource();
} }
} }
} }

View File

@@ -5,14 +5,14 @@ using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MetadataSource; using NzbDrone.Core.MetadataSource;
using Readarr.Http; using Readarr.Http;
namespace Readarr.Api.V1.Artist namespace Readarr.Api.V1.Author
{ {
public class ArtistLookupModule : ReadarrRestModule<ArtistResource> public class AuthorLookupModule : ReadarrRestModule<AuthorResource>
{ {
private readonly ISearchForNewAuthor _searchProxy; private readonly ISearchForNewAuthor _searchProxy;
public ArtistLookupModule(ISearchForNewAuthor searchProxy) public AuthorLookupModule(ISearchForNewAuthor searchProxy)
: base("/artist/lookup") : base("/author/lookup")
{ {
_searchProxy = searchProxy; _searchProxy = searchProxy;
Get("/", x => Search()); Get("/", x => Search());
@@ -24,12 +24,12 @@ namespace Readarr.Api.V1.Artist
return MapToResource(searchResults).ToList(); return MapToResource(searchResults).ToList();
} }
private static IEnumerable<ArtistResource> MapToResource(IEnumerable<NzbDrone.Core.Books.Author> artist) private static IEnumerable<AuthorResource> MapToResource(IEnumerable<NzbDrone.Core.Books.Author> author)
{ {
foreach (var currentArtist in artist) foreach (var currentAuthor in author)
{ {
var resource = currentArtist.ToResource(); var resource = currentAuthor.ToResource();
var poster = currentArtist.Metadata.Value.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster); var poster = currentAuthor.Metadata.Value.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster);
if (poster != null) if (poster != null)
{ {
resource.RemotePoster = poster.Url; resource.RemotePoster = poster.Url;

View File

@@ -19,9 +19,9 @@ using NzbDrone.SignalR;
using Readarr.Http; using Readarr.Http;
using Readarr.Http.Extensions; using Readarr.Http.Extensions;
namespace Readarr.Api.V1.Artist namespace Readarr.Api.V1.Author
{ {
public class ArtistModule : ReadarrRestModuleWithSignalR<ArtistResource, NzbDrone.Core.Books.Author>, public class AuthorModule : ReadarrRestModuleWithSignalR<AuthorResource, NzbDrone.Core.Books.Author>,
IHandle<BookImportedEvent>, IHandle<BookImportedEvent>,
IHandle<BookEditedEvent>, IHandle<BookEditedEvent>,
IHandle<BookFileDeletedEvent>, IHandle<BookFileDeletedEvent>,
@@ -34,24 +34,24 @@ namespace Readarr.Api.V1.Artist
private readonly IAuthorService _authorService; private readonly IAuthorService _authorService;
private readonly IBookService _bookService; private readonly IBookService _bookService;
private readonly IAddAuthorService _addAuthorService; private readonly IAddAuthorService _addAuthorService;
private readonly IAuthorStatisticsService _artistStatisticsService; private readonly IAuthorStatisticsService _authorStatisticsService;
private readonly IMapCoversToLocal _coverMapper; private readonly IMapCoversToLocal _coverMapper;
private readonly IManageCommandQueue _commandQueueManager; private readonly IManageCommandQueue _commandQueueManager;
private readonly IRootFolderService _rootFolderService; private readonly IRootFolderService _rootFolderService;
public ArtistModule(IBroadcastSignalRMessage signalRBroadcaster, public AuthorModule(IBroadcastSignalRMessage signalRBroadcaster,
IAuthorService authorService, IAuthorService authorService,
IBookService bookService, IBookService bookService,
IAddAuthorService addAuthorService, IAddAuthorService addAuthorService,
IAuthorStatisticsService artistStatisticsService, IAuthorStatisticsService authorStatisticsService,
IMapCoversToLocal coverMapper, IMapCoversToLocal coverMapper,
IManageCommandQueue commandQueueManager, IManageCommandQueue commandQueueManager,
IRootFolderService rootFolderService, IRootFolderService rootFolderService,
RootFolderValidator rootFolderValidator, RootFolderValidator rootFolderValidator,
MappedNetworkDriveValidator mappedNetworkDriveValidator, MappedNetworkDriveValidator mappedNetworkDriveValidator,
AuthorPathValidator artistPathValidator, AuthorPathValidator authorPathValidator,
ArtistExistsValidator artistExistsValidator, AuthorExistsValidator authorExistsValidator,
AuthorAncestorValidator artistAncestorValidator, AuthorAncestorValidator authorAncestorValidator,
SystemFolderValidator systemFolderValidator, SystemFolderValidator systemFolderValidator,
QualityProfileExistsValidator qualityProfileExistsValidator, QualityProfileExistsValidator qualityProfileExistsValidator,
MetadataProfileExistsValidator metadataProfileExistsValidator) MetadataProfileExistsValidator metadataProfileExistsValidator)
@@ -60,17 +60,17 @@ namespace Readarr.Api.V1.Artist
_authorService = authorService; _authorService = authorService;
_bookService = bookService; _bookService = bookService;
_addAuthorService = addAuthorService; _addAuthorService = addAuthorService;
_artistStatisticsService = artistStatisticsService; _authorStatisticsService = authorStatisticsService;
_coverMapper = coverMapper; _coverMapper = coverMapper;
_commandQueueManager = commandQueueManager; _commandQueueManager = commandQueueManager;
_rootFolderService = rootFolderService; _rootFolderService = rootFolderService;
GetResourceAll = AllArtists; GetResourceAll = AllAuthors;
GetResourceById = GetArtist; GetResourceById = GetAuthor;
CreateResource = AddArtist; CreateResource = AddAuthor;
UpdateResource = UpdateArtist; UpdateResource = UpdateAuthor;
DeleteResource = DeleteArtist; DeleteResource = DeleteAuthor;
Http.Validation.RuleBuilderExtensions.ValidId(SharedValidator.RuleFor(s => s.QualityProfileId)); Http.Validation.RuleBuilderExtensions.ValidId(SharedValidator.RuleFor(s => s.QualityProfileId));
Http.Validation.RuleBuilderExtensions.ValidId(SharedValidator.RuleFor(s => s.MetadataProfileId)); Http.Validation.RuleBuilderExtensions.ValidId(SharedValidator.RuleFor(s => s.MetadataProfileId));
@@ -80,8 +80,8 @@ namespace Readarr.Api.V1.Artist
.IsValidPath() .IsValidPath()
.SetValidator(rootFolderValidator) .SetValidator(rootFolderValidator)
.SetValidator(mappedNetworkDriveValidator) .SetValidator(mappedNetworkDriveValidator)
.SetValidator(artistPathValidator) .SetValidator(authorPathValidator)
.SetValidator(artistAncestorValidator) .SetValidator(authorAncestorValidator)
.SetValidator(systemFolderValidator) .SetValidator(systemFolderValidator)
.When(s => !s.Path.IsNullOrWhiteSpace()); .When(s => !s.Path.IsNullOrWhiteSpace());
@@ -90,26 +90,26 @@ namespace Readarr.Api.V1.Artist
PostValidator.RuleFor(s => s.Path).IsValidPath().When(s => s.RootFolderPath.IsNullOrWhiteSpace()); 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.RootFolderPath).IsValidPath().When(s => s.Path.IsNullOrWhiteSpace());
PostValidator.RuleFor(s => s.ArtistName).NotEmpty(); PostValidator.RuleFor(s => s.AuthorName).NotEmpty();
PostValidator.RuleFor(s => s.ForeignAuthorId).NotEmpty().SetValidator(artistExistsValidator); PostValidator.RuleFor(s => s.ForeignAuthorId).NotEmpty().SetValidator(authorExistsValidator);
PutValidator.RuleFor(s => s.Path).IsValidPath(); PutValidator.RuleFor(s => s.Path).IsValidPath();
} }
private ArtistResource GetArtist(int id) private AuthorResource GetAuthor(int id)
{ {
var artist = _authorService.GetAuthor(id); var author = _authorService.GetAuthor(id);
return GetArtistResource(artist); return GetArtistResource(author);
} }
private ArtistResource GetArtistResource(NzbDrone.Core.Books.Author artist) private AuthorResource GetArtistResource(NzbDrone.Core.Books.Author author)
{ {
if (artist == null) if (author == null)
{ {
return null; return null;
} }
var resource = artist.ToResource(); var resource = author.ToResource();
MapCoversToLocal(resource); MapCoversToLocal(resource);
FetchAndLinkArtistStatistics(resource); FetchAndLinkArtistStatistics(resource);
LinkNextPreviousAlbums(resource); LinkNextPreviousAlbums(resource);
@@ -120,53 +120,53 @@ namespace Readarr.Api.V1.Artist
return resource; return resource;
} }
private List<ArtistResource> AllArtists() private List<AuthorResource> AllAuthors()
{ {
var artistStats = _artistStatisticsService.AuthorStatistics(); var authorStats = _authorStatisticsService.AuthorStatistics();
var artistsResources = _authorService.GetAllAuthors().ToResource(); var authorResources = _authorService.GetAllAuthors().ToResource();
MapCoversToLocal(artistsResources.ToArray()); MapCoversToLocal(authorResources.ToArray());
LinkNextPreviousAlbums(artistsResources.ToArray()); LinkNextPreviousAlbums(authorResources.ToArray());
LinkArtistStatistics(artistsResources, artistStats); LinkArtistStatistics(authorResources, authorStats);
//PopulateAlternateTitles(seriesResources); //PopulateAlternateTitles(seriesResources);
return artistsResources; return authorResources;
} }
private int AddArtist(ArtistResource artistResource) private int AddAuthor(AuthorResource authorResource)
{ {
var artist = _addAuthorService.AddAuthor(artistResource.ToModel()); var author = _addAuthorService.AddAuthor(authorResource.ToModel());
return artist.Id; return author.Id;
} }
private void UpdateArtist(ArtistResource artistResource) private void UpdateAuthor(AuthorResource authorResource)
{ {
var moveFiles = Request.GetBooleanQueryParameter("moveFiles"); var moveFiles = Request.GetBooleanQueryParameter("moveFiles");
var artist = _authorService.GetAuthor(artistResource.Id); var author = _authorService.GetAuthor(authorResource.Id);
if (moveFiles) if (moveFiles)
{ {
var sourcePath = artist.Path; var sourcePath = author.Path;
var destinationPath = artistResource.Path; var destinationPath = authorResource.Path;
_commandQueueManager.Push(new MoveAuthorCommand _commandQueueManager.Push(new MoveAuthorCommand
{ {
AuthorId = artist.Id, AuthorId = author.Id,
SourcePath = sourcePath, SourcePath = sourcePath,
DestinationPath = destinationPath, DestinationPath = destinationPath,
Trigger = CommandTrigger.Manual Trigger = CommandTrigger.Manual
}); });
} }
var model = artistResource.ToModel(artist); var model = authorResource.ToModel(author);
_authorService.UpdateAuthor(model); _authorService.UpdateAuthor(model);
BroadcastResourceChange(ModelAction.Updated, artistResource); BroadcastResourceChange(ModelAction.Updated, authorResource);
} }
private void DeleteArtist(int id) private void DeleteAuthor(int id)
{ {
var deleteFiles = Request.GetBooleanQueryParameter("deleteFiles"); var deleteFiles = Request.GetBooleanQueryParameter("deleteFiles");
var addImportListExclusion = Request.GetBooleanQueryParameter("addImportListExclusion"); var addImportListExclusion = Request.GetBooleanQueryParameter("addImportListExclusion");
@@ -174,48 +174,48 @@ namespace Readarr.Api.V1.Artist
_authorService.DeleteAuthor(id, deleteFiles, addImportListExclusion); _authorService.DeleteAuthor(id, deleteFiles, addImportListExclusion);
} }
private void MapCoversToLocal(params ArtistResource[] artists) private void MapCoversToLocal(params AuthorResource[] authors)
{ {
foreach (var artistResource in artists) foreach (var authorResource in authors)
{ {
_coverMapper.ConvertToLocalUrls(artistResource.Id, MediaCoverEntity.Author, artistResource.Images); _coverMapper.ConvertToLocalUrls(authorResource.Id, MediaCoverEntity.Author, authorResource.Images);
} }
} }
private void LinkNextPreviousAlbums(params ArtistResource[] artists) private void LinkNextPreviousAlbums(params AuthorResource[] authors)
{ {
var nextAlbums = _bookService.GetNextBooksByAuthorMetadataId(artists.Select(x => x.ArtistMetadataId)); var nextBooks = _bookService.GetNextBooksByAuthorMetadataId(authors.Select(x => x.AuthorMetadataId));
var lastAlbums = _bookService.GetLastBooksByAuthorMetadataId(artists.Select(x => x.ArtistMetadataId)); var lastBooks = _bookService.GetLastBooksByAuthorMetadataId(authors.Select(x => x.AuthorMetadataId));
foreach (var artistResource in artists) foreach (var authorResource in authors)
{ {
artistResource.NextAlbum = nextAlbums.FirstOrDefault(x => x.AuthorMetadataId == artistResource.ArtistMetadataId); authorResource.NextBook = nextBooks.FirstOrDefault(x => x.AuthorMetadataId == authorResource.AuthorMetadataId);
artistResource.LastAlbum = lastAlbums.FirstOrDefault(x => x.AuthorMetadataId == artistResource.ArtistMetadataId); authorResource.LastBook = lastBooks.FirstOrDefault(x => x.AuthorMetadataId == authorResource.AuthorMetadataId);
} }
} }
private void FetchAndLinkArtistStatistics(ArtistResource resource) private void FetchAndLinkArtistStatistics(AuthorResource resource)
{ {
LinkArtistStatistics(resource, _artistStatisticsService.AuthorStatistics(resource.Id)); LinkArtistStatistics(resource, _authorStatisticsService.AuthorStatistics(resource.Id));
} }
private void LinkArtistStatistics(List<ArtistResource> resources, List<AuthorStatistics> artistStatistics) private void LinkArtistStatistics(List<AuthorResource> resources, List<AuthorStatistics> authorStatistics)
{ {
foreach (var artist in resources) foreach (var author in resources)
{ {
var stats = artistStatistics.SingleOrDefault(ss => ss.AuthorId == artist.Id); var stats = authorStatistics.SingleOrDefault(ss => ss.AuthorId == author.Id);
if (stats == null) if (stats == null)
{ {
continue; continue;
} }
LinkArtistStatistics(artist, stats); LinkArtistStatistics(author, stats);
} }
} }
private void LinkArtistStatistics(ArtistResource resource, AuthorStatistics artistStatistics) private void LinkArtistStatistics(AuthorResource resource, AuthorStatistics authorStatistics)
{ {
resource.Statistics = artistStatistics.ToResource(); resource.Statistics = authorStatistics.ToResource();
} }
//private void PopulateAlternateTitles(List<ArtistResource> resources) //private void PopulateAlternateTitles(List<ArtistResource> resources)
@@ -234,7 +234,7 @@ namespace Readarr.Api.V1.Artist
// resource.AlternateTitles = mappings.Select(v => new AlternateTitleResource { Title = v.Title, SeasonNumber = v.SeasonNumber, SceneSeasonNumber = v.SceneSeasonNumber }).ToList(); // resource.AlternateTitles = mappings.Select(v => new AlternateTitleResource { Title = v.Title, SeasonNumber = v.SeasonNumber, SceneSeasonNumber = v.SceneSeasonNumber }).ToList();
//} //}
private void LinkRootFolderPath(ArtistResource resource) private void LinkRootFolderPath(AuthorResource resource)
{ {
resource.RootFolderPath = _rootFolderService.GetBestRootFolderPath(resource.Path); resource.RootFolderPath = _rootFolderService.GetBestRootFolderPath(resource.Path);
} }
@@ -246,7 +246,7 @@ namespace Readarr.Api.V1.Artist
public void Handle(BookEditedEvent message) public void Handle(BookEditedEvent message)
{ {
BroadcastResourceChange(ModelAction.Updated, GetArtistResource(message.Album.Author.Value)); BroadcastResourceChange(ModelAction.Updated, GetArtistResource(message.Book.Author.Value));
} }
public void Handle(BookFileDeletedEvent message) public void Handle(BookFileDeletedEvent message)

View File

@@ -7,30 +7,30 @@ using NzbDrone.Core.Books;
using NzbDrone.Core.MediaCover; using NzbDrone.Core.MediaCover;
using Readarr.Http.REST; using Readarr.Http.REST;
namespace Readarr.Api.V1.Artist namespace Readarr.Api.V1.Author
{ {
public class ArtistResource : RestResource public class AuthorResource : RestResource
{ {
//Todo: Sorters should be done completely on the client //Todo: Sorters should be done completely on the client
//Todo: Is there an easy way to keep IgnoreArticlesWhenSorting in sync between, Series, History, Missing? //Todo: Is there an easy way to keep IgnoreArticlesWhenSorting in sync between, Series, History, Missing?
//Todo: We should get the entire Profile instead of ID and Name separately //Todo: We should get the entire Profile instead of ID and Name separately
[JsonIgnore] [JsonIgnore]
public int ArtistMetadataId { get; set; } public int AuthorMetadataId { get; set; }
public AuthorStatusType Status { get; set; } public AuthorStatusType Status { get; set; }
public bool Ended => Status == AuthorStatusType.Ended; public bool Ended => Status == AuthorStatusType.Ended;
public string ArtistName { get; set; } public string AuthorName { get; set; }
public string ForeignAuthorId { get; set; } public string ForeignAuthorId { get; set; }
public int GoodreadsId { get; set; } public int GoodreadsId { get; set; }
public string TitleSlug { get; set; } public string TitleSlug { get; set; }
public string Overview { get; set; } public string Overview { get; set; }
public string ArtistType { get; set; } public string AuthorType { get; set; }
public string Disambiguation { get; set; } public string Disambiguation { get; set; }
public List<Links> Links { get; set; } public List<Links> Links { get; set; }
public Book NextAlbum { get; set; } public Book NextBook { get; set; }
public Book LastAlbum { get; set; } public Book LastBook { get; set; }
public List<MediaCover> Images { get; set; } public List<MediaCover> Images { get; set; }
@@ -42,7 +42,6 @@ namespace Readarr.Api.V1.Artist
public int MetadataProfileId { get; set; } public int MetadataProfileId { get; set; }
//Editing Only //Editing Only
public bool AlbumFolder { get; set; }
public bool Monitored { get; set; } public bool Monitored { get; set; }
public string RootFolderPath { get; set; } public string RootFolderPath { get; set; }
@@ -54,31 +53,31 @@ namespace Readarr.Api.V1.Artist
public AddAuthorOptions AddOptions { get; set; } public AddAuthorOptions AddOptions { get; set; }
public Ratings Ratings { get; set; } public Ratings Ratings { get; set; }
public ArtistStatisticsResource Statistics { get; set; } public AuthorStatisticsResource Statistics { get; set; }
} }
public static class ArtistResourceMapper public static class AuthorResourceMapper
{ {
public static ArtistResource ToResource(this NzbDrone.Core.Books.Author model) public static AuthorResource ToResource(this NzbDrone.Core.Books.Author model)
{ {
if (model == null) if (model == null)
{ {
return null; return null;
} }
return new ArtistResource return new AuthorResource
{ {
Id = model.Id, Id = model.Id,
ArtistMetadataId = model.AuthorMetadataId, AuthorMetadataId = model.AuthorMetadataId,
ArtistName = model.Name, AuthorName = model.Name,
//AlternateTitles //AlternateTitles
SortName = model.SortName, SortName = model.SortName,
Status = model.Metadata.Value.Status, Status = model.Metadata.Value.Status,
Overview = model.Metadata.Value.Overview, Overview = model.Metadata.Value.Overview,
ArtistType = model.Metadata.Value.Type, AuthorType = model.Metadata.Value.Type,
Disambiguation = model.Metadata.Value.Disambiguation, Disambiguation = model.Metadata.Value.Disambiguation,
Images = model.Metadata.Value.Images.JsonClone(), Images = model.Metadata.Value.Images.JsonClone(),
@@ -103,11 +102,11 @@ namespace Readarr.Api.V1.Artist
AddOptions = model.AddOptions, AddOptions = model.AddOptions,
Ratings = model.Metadata.Value.Ratings, Ratings = model.Metadata.Value.Ratings,
Statistics = new ArtistStatisticsResource() Statistics = new AuthorStatisticsResource()
}; };
} }
public static NzbDrone.Core.Books.Author ToModel(this ArtistResource resource) public static NzbDrone.Core.Books.Author ToModel(this AuthorResource resource)
{ {
if (resource == null) if (resource == null)
{ {
@@ -123,14 +122,14 @@ namespace Readarr.Api.V1.Artist
ForeignAuthorId = resource.ForeignAuthorId, ForeignAuthorId = resource.ForeignAuthorId,
GoodreadsId = resource.GoodreadsId, GoodreadsId = resource.GoodreadsId,
TitleSlug = resource.TitleSlug, TitleSlug = resource.TitleSlug,
Name = resource.ArtistName, Name = resource.AuthorName,
Status = resource.Status, Status = resource.Status,
Overview = resource.Overview, Overview = resource.Overview,
Links = resource.Links, Links = resource.Links,
Images = resource.Images, Images = resource.Images,
Genres = resource.Genres, Genres = resource.Genres,
Ratings = resource.Ratings, Ratings = resource.Ratings,
Type = resource.ArtistType Type = resource.AuthorType
}, },
//AlternateTitles //AlternateTitles
@@ -150,21 +149,21 @@ namespace Readarr.Api.V1.Artist
}; };
} }
public static NzbDrone.Core.Books.Author ToModel(this ArtistResource resource, NzbDrone.Core.Books.Author artist) public static NzbDrone.Core.Books.Author ToModel(this AuthorResource resource, NzbDrone.Core.Books.Author author)
{ {
var updatedArtist = resource.ToModel(); var updatedAuthor = resource.ToModel();
artist.ApplyChanges(updatedArtist); author.ApplyChanges(updatedAuthor);
return artist; return author;
} }
public static List<ArtistResource> ToResource(this IEnumerable<NzbDrone.Core.Books.Author> artist) public static List<AuthorResource> ToResource(this IEnumerable<NzbDrone.Core.Books.Author> author)
{ {
return artist.Select(ToResource).ToList(); return author.Select(ToResource).ToList();
} }
public static List<NzbDrone.Core.Books.Author> ToModel(this IEnumerable<ArtistResource> resources) public static List<NzbDrone.Core.Books.Author> ToModel(this IEnumerable<AuthorResource> resources)
{ {
return resources.Select(ToModel).ToList(); return resources.Select(ToModel).ToList();
} }

View File

@@ -0,0 +1,43 @@
using NzbDrone.Core.AuthorStats;
namespace Readarr.Api.V1.Author
{
public class AuthorStatisticsResource
{
public int BookCount { get; set; }
public int BookFileCount { get; set; }
public int TotalBookCount { get; set; }
public long SizeOnDisk { get; set; }
public decimal PercentOfBooks
{
get
{
if (BookCount == 0)
{
return 0;
}
return BookFileCount / (decimal)BookCount * 100;
}
}
}
public static class AuthorStatisticsResourceMapper
{
public static AuthorStatisticsResource ToResource(this AuthorStatistics model)
{
if (model == null)
{
return null;
}
return new AuthorStatisticsResource
{
BookCount = model.BookCount,
BookFileCount = model.BookFileCount,
SizeOnDisk = model.SizeOnDisk
};
}
}
}

View File

@@ -2,7 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using Readarr.Api.V1.Artist; using Readarr.Api.V1.Author;
using Readarr.Http.REST; using Readarr.Http.REST;
namespace Readarr.Api.V1.Blacklist namespace Readarr.Api.V1.Blacklist
@@ -18,7 +18,7 @@ namespace Readarr.Api.V1.Blacklist
public string Indexer { get; set; } public string Indexer { get; set; }
public string Message { get; set; } public string Message { get; set; }
public ArtistResource Artist { get; set; } public AuthorResource Author { get; set; }
} }
public static class BlacklistResourceMapper public static class BlacklistResourceMapper
@@ -43,7 +43,7 @@ namespace Readarr.Api.V1.Blacklist
Indexer = model.Indexer, Indexer = model.Indexer,
Message = model.Message, Message = model.Message,
Artist = model.Author.ToResource() Author = model.Author.ToResource()
}; };
} }
} }

View File

@@ -1,11 +1,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
namespace Readarr.Api.V1.TrackFiles namespace Readarr.Api.V1.BookFiles
{ {
public class TrackFileListResource public class BookFileListResource
{ {
public List<int> TrackFileIds { get; set; } public List<int> BookFileIds { get; set; }
public QualityModel Quality { get; set; } public QualityModel Quality { get; set; }
} }
} }

View File

@@ -14,9 +14,9 @@ using Readarr.Http;
using Readarr.Http.Extensions; using Readarr.Http.Extensions;
using HttpStatusCode = System.Net.HttpStatusCode; using HttpStatusCode = System.Net.HttpStatusCode;
namespace Readarr.Api.V1.TrackFiles namespace Readarr.Api.V1.BookFiles
{ {
public class TrackFileModule : ReadarrRestModuleWithSignalR<TrackFileResource, BookFile>, public class BookFileModule : ReadarrRestModuleWithSignalR<BookFileResource, BookFile>,
IHandle<BookFileAddedEvent>, IHandle<BookFileAddedEvent>,
IHandle<BookFileDeletedEvent> IHandle<BookFileDeletedEvent>
{ {
@@ -27,7 +27,7 @@ namespace Readarr.Api.V1.TrackFiles
private readonly IBookService _bookService; private readonly IBookService _bookService;
private readonly IUpgradableSpecification _upgradableSpecification; private readonly IUpgradableSpecification _upgradableSpecification;
public TrackFileModule(IBroadcastSignalRMessage signalRBroadcaster, public BookFileModule(IBroadcastSignalRMessage signalRBroadcaster,
IMediaFileService mediaFileService, IMediaFileService mediaFileService,
IDeleteMediaFiles mediaFileDeletionService, IDeleteMediaFiles mediaFileDeletionService,
IAudioTagService audioTagService, IAudioTagService audioTagService,
@@ -43,44 +43,44 @@ namespace Readarr.Api.V1.TrackFiles
_bookService = bookService; _bookService = bookService;
_upgradableSpecification = upgradableSpecification; _upgradableSpecification = upgradableSpecification;
GetResourceById = GetTrackFile; GetResourceById = GetBookFile;
GetResourceAll = GetTrackFiles; GetResourceAll = GetBookFiles;
UpdateResource = SetQuality; UpdateResource = SetQuality;
DeleteResource = DeleteTrackFile; DeleteResource = DeleteBookFile;
Put("/editor", trackFiles => SetQuality()); Put("/editor", trackFiles => SetQuality());
Delete("/bulk", trackFiles => DeleteTrackFiles()); Delete("/bulk", trackFiles => DeleteBookFiles());
} }
private TrackFileResource MapToResource(BookFile trackFile) private BookFileResource MapToResource(BookFile bookFile)
{ {
if (trackFile.BookId > 0 && trackFile.Author != null && trackFile.Author.Value != null) if (bookFile.BookId > 0 && bookFile.Author != null && bookFile.Author.Value != null)
{ {
return trackFile.ToResource(trackFile.Author.Value, _upgradableSpecification); return bookFile.ToResource(bookFile.Author.Value, _upgradableSpecification);
} }
else else
{ {
return trackFile.ToResource(); return bookFile.ToResource();
} }
} }
private TrackFileResource GetTrackFile(int id) private BookFileResource GetBookFile(int id)
{ {
var resource = MapToResource(_mediaFileService.Get(id)); var resource = MapToResource(_mediaFileService.Get(id));
resource.AudioTags = _audioTagService.ReadTags(resource.Path); resource.AudioTags = _audioTagService.ReadTags(resource.Path);
return resource; return resource;
} }
private List<TrackFileResource> GetTrackFiles() private List<BookFileResource> GetBookFiles()
{ {
var authorIdQuery = Request.Query.AuthorId; var authorIdQuery = Request.Query.AuthorId;
var trackFileIdsQuery = Request.Query.TrackFileIds; var bookFileIdsQuery = Request.Query.TrackFileIds;
var bookIdQuery = Request.Query.BookId; var bookIdQuery = Request.Query.BookId;
var unmappedQuery = Request.Query.Unmapped; var unmappedQuery = Request.Query.Unmapped;
if (!authorIdQuery.HasValue && !trackFileIdsQuery.HasValue && !bookIdQuery.HasValue && !unmappedQuery.HasValue) if (!authorIdQuery.HasValue && !bookFileIdsQuery.HasValue && !bookIdQuery.HasValue && !unmappedQuery.HasValue)
{ {
throw new Readarr.Http.REST.BadRequestException("authorId, bookId, trackFileIds or unmapped must be provided"); throw new Readarr.Http.REST.BadRequestException("authorId, bookId, bookFileIds or unmapped must be provided");
} }
if (unmappedQuery.HasValue && Convert.ToBoolean(unmappedQuery.Value)) if (unmappedQuery.HasValue && Convert.ToBoolean(unmappedQuery.Value))
@@ -92,9 +92,9 @@ namespace Readarr.Api.V1.TrackFiles
if (authorIdQuery.HasValue && !bookIdQuery.HasValue) if (authorIdQuery.HasValue && !bookIdQuery.HasValue)
{ {
int authorId = Convert.ToInt32(authorIdQuery.Value); int authorId = Convert.ToInt32(authorIdQuery.Value);
var artist = _authorService.GetAuthor(authorId); var author = _authorService.GetAuthor(authorId);
return _mediaFileService.GetFilesByAuthor(authorId).ConvertAll(f => f.ToResource(artist, _upgradableSpecification)); return _mediaFileService.GetFilesByAuthor(authorId).ConvertAll(f => f.ToResource(author, _upgradableSpecification));
} }
if (bookIdQuery.HasValue) if (bookIdQuery.HasValue)
@@ -105,84 +105,84 @@ namespace Readarr.Api.V1.TrackFiles
.Select(e => Convert.ToInt32(e)) .Select(e => Convert.ToInt32(e))
.ToList(); .ToList();
var result = new List<TrackFileResource>(); var result = new List<BookFileResource>();
foreach (var bookId in bookIds) foreach (var bookId in bookIds)
{ {
var album = _bookService.GetBook(bookId); var book = _bookService.GetBook(bookId);
var albumArtist = _authorService.GetAuthor(album.AuthorId); var bookAuthor = _authorService.GetAuthor(book.AuthorId);
result.AddRange(_mediaFileService.GetFilesByBook(album.Id).ConvertAll(f => f.ToResource(albumArtist, _upgradableSpecification))); result.AddRange(_mediaFileService.GetFilesByBook(book.Id).ConvertAll(f => f.ToResource(bookAuthor, _upgradableSpecification)));
} }
return result; return result;
} }
else else
{ {
string trackFileIdsValue = trackFileIdsQuery.Value.ToString(); string bookFileIdsValue = bookFileIdsQuery.Value.ToString();
var trackFileIds = trackFileIdsValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) var bookFileIds = bookFileIdsValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(e => Convert.ToInt32(e)) .Select(e => Convert.ToInt32(e))
.ToList(); .ToList();
// trackfiles will come back with the artist already populated // trackfiles will come back with the artist already populated
var trackFiles = _mediaFileService.Get(trackFileIds); var bookFiles = _mediaFileService.Get(bookFileIds);
return trackFiles.ConvertAll(e => MapToResource(e)); return bookFiles.ConvertAll(e => MapToResource(e));
} }
} }
private void SetQuality(TrackFileResource trackFileResource) private void SetQuality(BookFileResource bookFileResource)
{ {
var trackFile = _mediaFileService.Get(trackFileResource.Id); var bookFile = _mediaFileService.Get(bookFileResource.Id);
trackFile.Quality = trackFileResource.Quality; bookFile.Quality = bookFileResource.Quality;
_mediaFileService.Update(trackFile); _mediaFileService.Update(bookFile);
} }
private object SetQuality() private object SetQuality()
{ {
var resource = Request.Body.FromJson<TrackFileListResource>(); var resource = Request.Body.FromJson<BookFileListResource>();
var trackFiles = _mediaFileService.Get(resource.TrackFileIds); var bookFiles = _mediaFileService.Get(resource.BookFileIds);
foreach (var trackFile in trackFiles) foreach (var bookFile in bookFiles)
{ {
if (resource.Quality != null) if (resource.Quality != null)
{ {
trackFile.Quality = resource.Quality; bookFile.Quality = resource.Quality;
} }
} }
_mediaFileService.Update(trackFiles); _mediaFileService.Update(bookFiles);
return ResponseWithCode(trackFiles.ConvertAll(f => f.ToResource(trackFiles.First().Author.Value, _upgradableSpecification)), return ResponseWithCode(bookFiles.ConvertAll(f => f.ToResource(bookFiles.First().Author.Value, _upgradableSpecification)),
Nancy.HttpStatusCode.Accepted); Nancy.HttpStatusCode.Accepted);
} }
private void DeleteTrackFile(int id) private void DeleteBookFile(int id)
{ {
var trackFile = _mediaFileService.Get(id); var bookFile = _mediaFileService.Get(id);
if (trackFile == null) if (bookFile == null)
{ {
throw new NzbDroneClientException(HttpStatusCode.NotFound, "Track file not found"); throw new NzbDroneClientException(HttpStatusCode.NotFound, "Book file not found");
} }
if (trackFile.BookId > 0 && trackFile.Author != null && trackFile.Author.Value != null) if (bookFile.BookId > 0 && bookFile.Author != null && bookFile.Author.Value != null)
{ {
_mediaFileDeletionService.DeleteTrackFile(trackFile.Author.Value, trackFile); _mediaFileDeletionService.DeleteTrackFile(bookFile.Author.Value, bookFile);
} }
else else
{ {
_mediaFileDeletionService.DeleteTrackFile(trackFile, "Unmapped_Files"); _mediaFileDeletionService.DeleteTrackFile(bookFile, "Unmapped_Files");
} }
} }
private object DeleteTrackFiles() private object DeleteBookFiles()
{ {
var resource = Request.Body.FromJson<TrackFileListResource>(); var resource = Request.Body.FromJson<BookFileListResource>();
var trackFiles = _mediaFileService.Get(resource.TrackFileIds); var bookFiles = _mediaFileService.Get(resource.BookFileIds);
var artist = trackFiles.First().Author.Value; var author = bookFiles.First().Author.Value;
foreach (var trackFile in trackFiles) foreach (var bookFile in bookFiles)
{ {
_mediaFileDeletionService.DeleteTrackFile(artist, trackFile); _mediaFileDeletionService.DeleteTrackFile(author, bookFile);
} }
return new object(); return new object();

View File

@@ -7,9 +7,9 @@ using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using Readarr.Http.REST; using Readarr.Http.REST;
namespace Readarr.Api.V1.TrackFiles namespace Readarr.Api.V1.BookFiles
{ {
public class TrackFileResource : RestResource public class BookFileResource : RestResource
{ {
public int AuthorId { get; set; } public int AuthorId { get; set; }
public int BookId { get; set; } public int BookId { get; set; }
@@ -24,7 +24,7 @@ namespace Readarr.Api.V1.TrackFiles
public ParsedTrackInfo AudioTags { get; set; } public ParsedTrackInfo AudioTags { get; set; }
} }
public static class TrackFileResourceMapper public static class BookFileResourceMapper
{ {
private static int QualityWeight(QualityModel quality) private static int QualityWeight(QualityModel quality)
{ {
@@ -39,14 +39,14 @@ namespace Readarr.Api.V1.TrackFiles
return qualityWeight; return qualityWeight;
} }
public static TrackFileResource ToResource(this BookFile model) public static BookFileResource ToResource(this BookFile model)
{ {
if (model == null) if (model == null)
{ {
return null; return null;
} }
return new TrackFileResource return new BookFileResource
{ {
Id = model.Id, Id = model.Id,
BookId = model.BookId, BookId = model.BookId,
@@ -59,18 +59,18 @@ namespace Readarr.Api.V1.TrackFiles
}; };
} }
public static TrackFileResource ToResource(this BookFile model, NzbDrone.Core.Books.Author artist, IUpgradableSpecification upgradableSpecification) public static BookFileResource ToResource(this BookFile model, NzbDrone.Core.Books.Author author, IUpgradableSpecification upgradableSpecification)
{ {
if (model == null) if (model == null)
{ {
return null; return null;
} }
return new TrackFileResource return new BookFileResource
{ {
Id = model.Id, Id = model.Id,
AuthorId = artist.Id, AuthorId = author.Id,
BookId = model.BookId, BookId = model.BookId,
Path = model.Path, Path = model.Path,
Size = model.Size, Size = model.Size,
@@ -78,7 +78,7 @@ namespace Readarr.Api.V1.TrackFiles
Quality = model.Quality, Quality = model.Quality,
QualityWeight = QualityWeight(model.Quality), QualityWeight = QualityWeight(model.Quality),
MediaInfo = model.MediaInfo.ToResource(), MediaInfo = model.MediaInfo.ToResource(),
QualityCutoffNotMet = upgradableSpecification.QualityCutoffNotMet(artist.QualityProfile.Value, model.Quality) QualityCutoffNotMet = upgradableSpecification.QualityCutoffNotMet(author.QualityProfile.Value, model.Quality)
}; };
} }
} }

View File

@@ -2,7 +2,7 @@ using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using Readarr.Http.REST; using Readarr.Http.REST;
namespace Readarr.Api.V1.TrackFiles namespace Readarr.Api.V1.BookFiles
{ {
public class MediaInfoResource : RestResource public class MediaInfoResource : RestResource
{ {

View File

@@ -0,0 +1,12 @@
using System.Collections.Generic;
using Readarr.Api.V1.Books;
namespace Readarr.Api.V1.Bookshelf
{
public class BookshelfAuthorResource
{
public int Id { get; set; }
public bool? Monitored { get; set; }
public List<BookResource> Books { get; set; }
}
}

View File

@@ -0,0 +1,47 @@
using System.Linq;
using Nancy;
using NzbDrone.Core.Books;
using Readarr.Http.Extensions;
namespace Readarr.Api.V1.Bookshelf
{
public class BookshelfModule : ReadarrV1Module
{
private readonly IAuthorService _authorService;
private readonly IBookMonitoredService _bookMonitoredService;
public BookshelfModule(IAuthorService authorService, IBookMonitoredService bookMonitoredService)
: base("/bookshelf")
{
_authorService = authorService;
_bookMonitoredService = bookMonitoredService;
Post("/", artist => UpdateAll());
}
private object UpdateAll()
{
//Read from request
var request = Request.Body.FromJson<BookshelfResource>();
var authorToUpdate = _authorService.GetAuthors(request.Authors.Select(s => s.Id));
foreach (var s in request.Authors)
{
var author = authorToUpdate.Single(c => c.Id == s.Id);
if (s.Monitored.HasValue)
{
author.Monitored = s.Monitored.Value;
}
if (request.MonitoringOptions != null && request.MonitoringOptions.Monitor == MonitorTypes.None)
{
author.Monitored = false;
}
_bookMonitoredService.SetBookMonitoredStatus(author, request.MonitoringOptions);
}
return ResponseWithCode("ok", HttpStatusCode.Accepted);
}
}
}

View File

@@ -1,11 +1,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using NzbDrone.Core.Books; using NzbDrone.Core.Books;
namespace Readarr.Api.V1.AlbumStudio namespace Readarr.Api.V1.Bookshelf
{ {
public class AlbumStudioResource public class BookshelfResource
{ {
public List<AlbumStudioArtistResource> Artist { get; set; } public List<BookshelfAuthorResource> Authors { get; set; }
public MonitoringOptions MonitoringOptions { get; set; } public MonitoringOptions MonitoringOptions { get; set; }
} }
} }

View File

@@ -5,14 +5,14 @@ using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MetadataSource; using NzbDrone.Core.MetadataSource;
using Readarr.Http; using Readarr.Http;
namespace Readarr.Api.V1.Albums namespace Readarr.Api.V1.Books
{ {
public class AlbumLookupModule : ReadarrRestModule<AlbumResource> public class BookLookupModule : ReadarrRestModule<BookResource>
{ {
private readonly ISearchForNewBook _searchProxy; private readonly ISearchForNewBook _searchProxy;
public AlbumLookupModule(ISearchForNewBook searchProxy) public BookLookupModule(ISearchForNewBook searchProxy)
: base("/album/lookup") : base("/book/lookup")
{ {
_searchProxy = searchProxy; _searchProxy = searchProxy;
Get("/", x => Search()); Get("/", x => Search());
@@ -24,12 +24,12 @@ namespace Readarr.Api.V1.Albums
return MapToResource(searchResults).ToList(); return MapToResource(searchResults).ToList();
} }
private static IEnumerable<AlbumResource> MapToResource(IEnumerable<NzbDrone.Core.Books.Book> albums) private static IEnumerable<BookResource> MapToResource(IEnumerable<NzbDrone.Core.Books.Book> books)
{ {
foreach (var currentAlbum in albums) foreach (var currentBook in books)
{ {
var resource = currentAlbum.ToResource(); var resource = currentBook.ToResource();
var cover = currentAlbum.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Cover); var cover = currentBook.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Cover);
if (cover != null) if (cover != null)
{ {
resource.RemoteCover = cover.Url; resource.RemoteCover = cover.Url;

View File

@@ -19,9 +19,9 @@ using NzbDrone.Core.Validation.Paths;
using NzbDrone.SignalR; using NzbDrone.SignalR;
using Readarr.Http.Extensions; using Readarr.Http.Extensions;
namespace Readarr.Api.V1.Albums namespace Readarr.Api.V1.Books
{ {
public class AlbumModule : AlbumModuleWithSignalR, public class BookModule : BookModuleWithSignalR,
IHandle<BookGrabbedEvent>, IHandle<BookGrabbedEvent>,
IHandle<BookEditedEvent>, IHandle<BookEditedEvent>,
IHandle<BookUpdatedEvent>, IHandle<BookUpdatedEvent>,
@@ -32,53 +32,53 @@ namespace Readarr.Api.V1.Albums
protected readonly IAuthorService _authorService; protected readonly IAuthorService _authorService;
protected readonly IAddBookService _addBookService; protected readonly IAddBookService _addBookService;
public AlbumModule(IAuthorService authorService, public BookModule(IAuthorService authorService,
IBookService bookService, IBookService bookService,
IAddBookService addBookService, IAddBookService addBookService,
IAuthorStatisticsService artistStatisticsService, IAuthorStatisticsService authorStatisticsService,
IMapCoversToLocal coverMapper, IMapCoversToLocal coverMapper,
IUpgradableSpecification upgradableSpecification, IUpgradableSpecification upgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster, IBroadcastSignalRMessage signalRBroadcaster,
QualityProfileExistsValidator qualityProfileExistsValidator, QualityProfileExistsValidator qualityProfileExistsValidator,
MetadataProfileExistsValidator metadataProfileExistsValidator) MetadataProfileExistsValidator metadataProfileExistsValidator)
: base(bookService, artistStatisticsService, coverMapper, upgradableSpecification, signalRBroadcaster) : base(bookService, authorStatisticsService, coverMapper, upgradableSpecification, signalRBroadcaster)
{ {
_authorService = authorService; _authorService = authorService;
_addBookService = addBookService; _addBookService = addBookService;
GetResourceAll = GetAlbums; GetResourceAll = GetBooks;
CreateResource = AddAlbum; CreateResource = AddBook;
UpdateResource = UpdateAlbum; UpdateResource = UpdateBook;
DeleteResource = DeleteAlbum; DeleteResource = DeleteBook;
Put("/monitor", x => SetAlbumsMonitored()); Put("/monitor", x => SetBooksMonitored());
PostValidator.RuleFor(s => s.ForeignBookId).NotEmpty(); PostValidator.RuleFor(s => s.ForeignBookId).NotEmpty();
PostValidator.RuleFor(s => s.Artist.QualityProfileId).SetValidator(qualityProfileExistsValidator); PostValidator.RuleFor(s => s.Author.QualityProfileId).SetValidator(qualityProfileExistsValidator);
PostValidator.RuleFor(s => s.Artist.MetadataProfileId).SetValidator(metadataProfileExistsValidator); PostValidator.RuleFor(s => s.Author.MetadataProfileId).SetValidator(metadataProfileExistsValidator);
PostValidator.RuleFor(s => s.Artist.RootFolderPath).IsValidPath().When(s => s.Artist.Path.IsNullOrWhiteSpace()); PostValidator.RuleFor(s => s.Author.RootFolderPath).IsValidPath().When(s => s.Author.Path.IsNullOrWhiteSpace());
PostValidator.RuleFor(s => s.Artist.ForeignAuthorId).NotEmpty(); PostValidator.RuleFor(s => s.Author.ForeignAuthorId).NotEmpty();
} }
private List<AlbumResource> GetAlbums() private List<BookResource> GetBooks()
{ {
var authorIdQuery = Request.Query.AuthorId; var authorIdQuery = Request.Query.AuthorId;
var bookIdsQuery = Request.Query.BookIds; var bookIdsQuery = Request.Query.BookIds;
var slugQuery = Request.Query.TitleSlug; var slugQuery = Request.Query.TitleSlug;
var includeAllArtistAlbumsQuery = Request.Query.IncludeAllArtistAlbums; var includeAllAuthorBooksQuery = Request.Query.IncludeAllAuthorBooks;
if (!Request.Query.AuthorId.HasValue && !bookIdsQuery.HasValue && !slugQuery.HasValue) if (!Request.Query.AuthorId.HasValue && !bookIdsQuery.HasValue && !slugQuery.HasValue)
{ {
var albums = _bookService.GetAllBooks(); var books = _bookService.GetAllBooks();
var artists = _authorService.GetAllAuthors().ToDictionary(x => x.AuthorMetadataId); var authors = _authorService.GetAllAuthors().ToDictionary(x => x.AuthorMetadataId);
foreach (var album in albums) foreach (var book in books)
{ {
album.Author = artists[album.AuthorMetadataId]; book.Author = authors[book.AuthorMetadataId];
} }
return MapToResource(albums, false); return MapToResource(books, false);
} }
if (authorIdQuery.HasValue) if (authorIdQuery.HasValue)
@@ -92,20 +92,20 @@ namespace Readarr.Api.V1.Albums
{ {
string titleSlug = slugQuery.Value.ToString(); string titleSlug = slugQuery.Value.ToString();
var album = _bookService.FindBySlug(titleSlug); var book = _bookService.FindBySlug(titleSlug);
if (album == null) if (book == null)
{ {
return MapToResource(new List<Book>(), false); return MapToResource(new List<Book>(), false);
} }
if (includeAllArtistAlbumsQuery.HasValue && Convert.ToBoolean(includeAllArtistAlbumsQuery.Value)) if (includeAllAuthorBooksQuery.HasValue && Convert.ToBoolean(includeAllAuthorBooksQuery.Value))
{ {
return MapToResource(_bookService.GetBooksByAuthor(album.AuthorId), false); return MapToResource(_bookService.GetBooksByAuthor(book.AuthorId), false);
} }
else else
{ {
return MapToResource(new List<Book> { album }, false); return MapToResource(new List<Book> { book }, false);
} }
} }
@@ -118,25 +118,25 @@ namespace Readarr.Api.V1.Albums
return MapToResource(_bookService.GetBooks(bookIds), false); return MapToResource(_bookService.GetBooks(bookIds), false);
} }
private int AddAlbum(AlbumResource albumResource) private int AddBook(BookResource bookResource)
{ {
var album = _addBookService.AddBook(albumResource.ToModel()); var book = _addBookService.AddBook(bookResource.ToModel());
return album.Id; return book.Id;
} }
private void UpdateAlbum(AlbumResource albumResource) private void UpdateBook(BookResource bookResource)
{ {
var album = _bookService.GetBook(albumResource.Id); var book = _bookService.GetBook(bookResource.Id);
var model = albumResource.ToModel(album); var model = bookResource.ToModel(book);
_bookService.UpdateBook(model); _bookService.UpdateBook(model);
BroadcastResourceChange(ModelAction.Updated, model.Id); BroadcastResourceChange(ModelAction.Updated, model.Id);
} }
private void DeleteAlbum(int id) private void DeleteBook(int id)
{ {
var deleteFiles = Request.GetBooleanQueryParameter("deleteFiles"); var deleteFiles = Request.GetBooleanQueryParameter("deleteFiles");
var addImportListExclusion = Request.GetBooleanQueryParameter("addImportListExclusion"); var addImportListExclusion = Request.GetBooleanQueryParameter("addImportListExclusion");
@@ -144,9 +144,9 @@ namespace Readarr.Api.V1.Albums
_bookService.DeleteBook(id, deleteFiles, addImportListExclusion); _bookService.DeleteBook(id, deleteFiles, addImportListExclusion);
} }
private object SetAlbumsMonitored() private object SetBooksMonitored()
{ {
var resource = Request.Body.FromJson<AlbumsMonitoredResource>(); var resource = Request.Body.FromJson<BooksMonitoredResource>();
_bookService.SetMonitored(resource.BookIds, resource.Monitored); _bookService.SetMonitored(resource.BookIds, resource.Monitored);
@@ -155,9 +155,9 @@ namespace Readarr.Api.V1.Albums
public void Handle(BookGrabbedEvent message) public void Handle(BookGrabbedEvent message)
{ {
foreach (var album in message.Book.Books) foreach (var book in message.Book.Books)
{ {
var resource = album.ToResource(); var resource = book.ToResource();
resource.Grabbed = true; resource.Grabbed = true;
BroadcastResourceChange(ModelAction.Updated, resource); BroadcastResourceChange(ModelAction.Updated, resource);
@@ -166,7 +166,7 @@ namespace Readarr.Api.V1.Albums
public void Handle(BookEditedEvent message) public void Handle(BookEditedEvent message)
{ {
BroadcastResourceChange(ModelAction.Updated, MapToResource(message.Album, true)); BroadcastResourceChange(ModelAction.Updated, MapToResource(message.Book, true));
} }
public void Handle(BookUpdatedEvent message) public void Handle(BookUpdatedEvent message)

View File

@@ -0,0 +1,133 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.AuthorStats;
using NzbDrone.Core.Books;
using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.MediaCover;
using NzbDrone.SignalR;
using Readarr.Api.V1.Author;
using Readarr.Http;
namespace Readarr.Api.V1.Books
{
public abstract class BookModuleWithSignalR : ReadarrRestModuleWithSignalR<BookResource, Book>
{
protected readonly IBookService _bookService;
protected readonly IAuthorStatisticsService _authorStatisticsService;
protected readonly IUpgradableSpecification _qualityUpgradableSpecification;
protected readonly IMapCoversToLocal _coverMapper;
protected BookModuleWithSignalR(IBookService bookService,
IAuthorStatisticsService authorStatisticsService,
IMapCoversToLocal coverMapper,
IUpgradableSpecification qualityUpgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster)
: base(signalRBroadcaster)
{
_bookService = bookService;
_authorStatisticsService = authorStatisticsService;
_coverMapper = coverMapper;
_qualityUpgradableSpecification = qualityUpgradableSpecification;
GetResourceById = GetBook;
}
protected BookModuleWithSignalR(IBookService bookService,
IAuthorStatisticsService authorStatisticsService,
IMapCoversToLocal coverMapper,
IUpgradableSpecification qualityUpgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster,
string resource)
: base(signalRBroadcaster, resource)
{
_bookService = bookService;
_authorStatisticsService = authorStatisticsService;
_coverMapper = coverMapper;
_qualityUpgradableSpecification = qualityUpgradableSpecification;
GetResourceById = GetBook;
}
protected BookResource GetBook(int id)
{
var book = _bookService.GetBook(id);
var resource = MapToResource(book, true);
return resource;
}
protected BookResource MapToResource(Book book, bool includeAuthor)
{
var resource = book.ToResource();
if (includeAuthor)
{
var artist = book.Author.Value;
resource.Author = artist.ToResource();
}
FetchAndLinkAlbumStatistics(resource);
MapCoversToLocal(resource);
return resource;
}
protected List<BookResource> MapToResource(List<Book> books, bool includeAuthor)
{
var result = books.ToResource();
if (includeAuthor)
{
var authorDict = new Dictionary<int, NzbDrone.Core.Books.Author>();
for (var i = 0; i < books.Count; i++)
{
var book = books[i];
var resource = result[i];
var author = authorDict.GetValueOrDefault(books[i].AuthorMetadataId) ?? book.Author?.Value;
authorDict[author.AuthorMetadataId] = author;
resource.Author = author.ToResource();
}
}
var authorStats = _authorStatisticsService.AuthorStatistics();
LinkAuthorStatistics(result, authorStats);
MapCoversToLocal(result.ToArray());
return result;
}
private void FetchAndLinkAlbumStatistics(BookResource resource)
{
LinkAuthorStatistics(resource, _authorStatisticsService.AuthorStatistics(resource.AuthorId));
}
private void LinkAuthorStatistics(List<BookResource> resources, List<AuthorStatistics> authorStatistics)
{
foreach (var book in resources)
{
var stats = authorStatistics.SingleOrDefault(ss => ss.AuthorId == book.AuthorId);
LinkAuthorStatistics(book, stats);
}
}
private void LinkAuthorStatistics(BookResource resource, AuthorStatistics authorStatistics)
{
if (authorStatistics?.BookStatistics != null)
{
var dictBookStats = authorStatistics.BookStatistics.ToDictionary(v => v.BookId);
resource.Statistics = dictBookStats.GetValueOrDefault(resource.Id).ToResource();
}
}
private void MapCoversToLocal(params BookResource[] books)
{
foreach (var bookResource in books)
{
_coverMapper.ConvertToLocalUrls(bookResource.Id, MediaCoverEntity.Book, bookResource.Images);
}
}
}
}

View File

@@ -4,13 +4,13 @@ using System.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;
using NzbDrone.Core.Books; using NzbDrone.Core.Books;
using NzbDrone.Core.MediaCover; using NzbDrone.Core.MediaCover;
using Readarr.Api.V1.Artist; using Readarr.Api.V1.Author;
using Readarr.Api.V1.TrackFiles; using Readarr.Api.V1.BookFiles;
using Readarr.Http.REST; using Readarr.Http.REST;
namespace Readarr.Api.V1.Albums namespace Readarr.Api.V1.Books
{ {
public class AlbumResource : RestResource public class BookResource : RestResource
{ {
public string Title { get; set; } public string Title { get; set; }
public string Disambiguation { get; set; } public string Disambiguation { get; set; }
@@ -27,10 +27,10 @@ namespace Readarr.Api.V1.Albums
public Ratings Ratings { get; set; } public Ratings Ratings { get; set; }
public DateTime? ReleaseDate { get; set; } public DateTime? ReleaseDate { get; set; }
public List<string> Genres { get; set; } public List<string> Genres { get; set; }
public ArtistResource Artist { get; set; } public AuthorResource Author { get; set; }
public List<MediaCover> Images { get; set; } public List<MediaCover> Images { get; set; }
public List<Links> Links { get; set; } public List<Links> Links { get; set; }
public AlbumStatisticsResource Statistics { get; set; } public BookStatisticsResource Statistics { get; set; }
public AddBookOptions AddOptions { get; set; } public AddBookOptions AddOptions { get; set; }
public string RemoteCover { get; set; } public string RemoteCover { get; set; }
@@ -39,16 +39,16 @@ namespace Readarr.Api.V1.Albums
public bool Grabbed { get; set; } public bool Grabbed { get; set; }
} }
public static class AlbumResourceMapper public static class BookResourceMapper
{ {
public static AlbumResource ToResource(this Book model) public static BookResource ToResource(this Book model)
{ {
if (model == null) if (model == null)
{ {
return null; return null;
} }
return new AlbumResource return new BookResource
{ {
Id = model.Id, Id = model.Id,
AuthorId = model.AuthorId, AuthorId = model.AuthorId,
@@ -68,18 +68,18 @@ namespace Readarr.Api.V1.Albums
Images = model.Images, Images = model.Images,
Links = model.Links, Links = model.Links,
Ratings = model.Ratings, Ratings = model.Ratings,
Artist = model.Author?.Value.ToResource() Author = model.Author?.Value.ToResource()
}; };
} }
public static Book ToModel(this AlbumResource resource) public static Book ToModel(this BookResource resource)
{ {
if (resource == null) if (resource == null)
{ {
return null; return null;
} }
var artist = resource.Artist?.ToModel() ?? new NzbDrone.Core.Books.Author(); var author = resource.Author?.ToModel() ?? new NzbDrone.Core.Books.Author();
return new Book return new Book
{ {
@@ -97,26 +97,26 @@ namespace Readarr.Api.V1.Albums
Images = resource.Images, Images = resource.Images,
Monitored = resource.Monitored, Monitored = resource.Monitored,
AddOptions = resource.AddOptions, AddOptions = resource.AddOptions,
Author = artist, Author = author,
AuthorMetadata = artist.Metadata.Value AuthorMetadata = author.Metadata.Value
}; };
} }
public static Book ToModel(this AlbumResource resource, Book album) public static Book ToModel(this BookResource resource, Book book)
{ {
var updatedAlbum = resource.ToModel(); var updatedBook = resource.ToModel();
album.ApplyChanges(updatedAlbum); book.ApplyChanges(updatedBook);
return album; return book;
} }
public static List<AlbumResource> ToResource(this IEnumerable<Book> models) public static List<BookResource> ToResource(this IEnumerable<Book> models)
{ {
return models?.Select(ToResource).ToList(); return models?.Select(ToResource).ToList();
} }
public static List<Book> ToModel(this IEnumerable<AlbumResource> resources) public static List<Book> ToModel(this IEnumerable<BookResource> resources)
{ {
return resources.Select(ToModel).ToList(); return resources.Select(ToModel).ToList();
} }

View File

@@ -1,12 +1,11 @@
using NzbDrone.Core.AuthorStats; using NzbDrone.Core.AuthorStats;
namespace Readarr.Api.V1.Artist namespace Readarr.Api.V1.Books
{ {
public class ArtistStatisticsResource public class BookStatisticsResource
{ {
public int BookCount { get; set; }
public int BookFileCount { get; set; } public int BookFileCount { get; set; }
public int TrackCount { get; set; } public int BookCount { get; set; }
public int TotalTrackCount { get; set; } public int TotalTrackCount { get; set; }
public long SizeOnDisk { get; set; } public long SizeOnDisk { get; set; }
@@ -14,29 +13,29 @@ namespace Readarr.Api.V1.Artist
{ {
get get
{ {
if (TrackCount == 0) if (BookCount == 0)
{ {
return 0; return 0;
} }
return BookFileCount / (decimal)TrackCount * 100; return BookFileCount / (decimal)BookCount * 100;
} }
} }
} }
public static class ArtistStatisticsResourceMapper public static class BookStatisticsResourceMapper
{ {
public static ArtistStatisticsResource ToResource(this AuthorStatistics model) public static BookStatisticsResource ToResource(this BookStatistics model)
{ {
if (model == null) if (model == null)
{ {
return null; return null;
} }
return new ArtistStatisticsResource return new BookStatisticsResource
{ {
BookCount = model.BookCount,
BookFileCount = model.BookFileCount, BookFileCount = model.BookFileCount,
BookCount = model.BookCount,
SizeOnDisk = model.SizeOnDisk SizeOnDisk = model.SizeOnDisk
}; };
} }

View File

@@ -1,8 +1,8 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace Readarr.Api.V1.Albums namespace Readarr.Api.V1.Books
{ {
public class AlbumsMonitoredResource public class BooksMonitoredResource
{ {
public List<int> BookIds { get; set; } public List<int> BookIds { get; set; }
public bool Monitored { get; set; } public bool Monitored { get; set; }

View File

@@ -3,21 +3,21 @@ using NzbDrone.Core.MediaFiles;
using Readarr.Http; using Readarr.Http;
using Readarr.Http.REST; using Readarr.Http.REST;
namespace Readarr.Api.V1.Albums namespace Readarr.Api.V1.Books
{ {
public class RenameTrackModule : ReadarrRestModule<RenameTrackResource> public class RenameBookModule : ReadarrRestModule<RenameBookResource>
{ {
private readonly IRenameTrackFileService _renameTrackFileService; private readonly IRenameBookFileService _renameBookFileService;
public RenameTrackModule(IRenameTrackFileService renameTrackFileService) public RenameBookModule(IRenameBookFileService renameBookFileService)
: base("rename") : base("rename")
{ {
_renameTrackFileService = renameTrackFileService; _renameBookFileService = renameBookFileService;
GetResourceAll = GetTracks; GetResourceAll = GetBookFiles;
} }
private List<RenameTrackResource> GetTracks() private List<RenameBookResource> GetBookFiles()
{ {
int authorId; int authorId;
@@ -33,10 +33,10 @@ namespace Readarr.Api.V1.Albums
if (Request.Query.bookId.HasValue) if (Request.Query.bookId.HasValue)
{ {
var bookId = (int)Request.Query.bookId; var bookId = (int)Request.Query.bookId;
return _renameTrackFileService.GetRenamePreviews(authorId, bookId).ToResource(); return _renameBookFileService.GetRenamePreviews(authorId, bookId).ToResource();
} }
return _renameTrackFileService.GetRenamePreviews(authorId).ToResource(); return _renameBookFileService.GetRenamePreviews(authorId).ToResource();
} }
} }
} }

View File

@@ -2,37 +2,37 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using Readarr.Http.REST; using Readarr.Http.REST;
namespace Readarr.Api.V1.Albums namespace Readarr.Api.V1.Books
{ {
public class RenameTrackResource : RestResource public class RenameBookResource : RestResource
{ {
public int AuthorId { get; set; } public int AuthorId { get; set; }
public int BookId { get; set; } public int BookId { get; set; }
public int TrackFileId { get; set; } public int BookFileId { get; set; }
public string ExistingPath { get; set; } public string ExistingPath { get; set; }
public string NewPath { get; set; } public string NewPath { get; set; }
} }
public static class RenameTrackResourceMapper public static class RenameBookResourceMapper
{ {
public static RenameTrackResource ToResource(this NzbDrone.Core.MediaFiles.RenameBookFilePreview model) public static RenameBookResource ToResource(this NzbDrone.Core.MediaFiles.RenameBookFilePreview model)
{ {
if (model == null) if (model == null)
{ {
return null; return null;
} }
return new RenameTrackResource return new RenameBookResource
{ {
AuthorId = model.AuthorId, AuthorId = model.AuthorId,
BookId = model.BookId, BookId = model.BookId,
TrackFileId = model.BookFileId, BookFileId = model.BookFileId,
ExistingPath = model.ExistingPath, ExistingPath = model.ExistingPath,
NewPath = model.NewPath NewPath = model.NewPath
}; };
} }
public static List<RenameTrackResource> ToResource(this IEnumerable<NzbDrone.Core.MediaFiles.RenameBookFilePreview> models) public static List<RenameBookResource> ToResource(this IEnumerable<NzbDrone.Core.MediaFiles.RenameBookFilePreview> models)
{ {
return models.Select(ToResource).ToList(); return models.Select(ToResource).ToList();
} }

View File

@@ -4,21 +4,21 @@ using NzbDrone.Core.MediaFiles;
using Readarr.Http; using Readarr.Http;
using Readarr.Http.REST; using Readarr.Http.REST;
namespace Readarr.Api.V1.Albums namespace Readarr.Api.V1.Books
{ {
public class RetagTrackModule : ReadarrRestModule<RetagTrackResource> public class RetagBookModule : ReadarrRestModule<RetagBookResource>
{ {
private readonly IAudioTagService _audioTagService; private readonly IAudioTagService _audioTagService;
public RetagTrackModule(IAudioTagService audioTagService) public RetagBookModule(IAudioTagService audioTagService)
: base("retag") : base("retag")
{ {
_audioTagService = audioTagService; _audioTagService = audioTagService;
GetResourceAll = GetTracks; GetResourceAll = GetBooks;
} }
private List<RetagTrackResource> GetTracks() private List<RetagBookResource> GetBooks()
{ {
if (Request.Query.bookId.HasValue) if (Request.Query.bookId.HasValue)
{ {

View File

@@ -2,7 +2,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using Readarr.Http.REST; using Readarr.Http.REST;
namespace Readarr.Api.V1.Albums namespace Readarr.Api.V1.Books
{ {
public class TagDifference public class TagDifference
{ {
@@ -11,31 +11,31 @@ namespace Readarr.Api.V1.Albums
public string NewValue { get; set; } public string NewValue { get; set; }
} }
public class RetagTrackResource : RestResource public class RetagBookResource : RestResource
{ {
public int AuthorId { get; set; } public int AuthorId { get; set; }
public int BookId { get; set; } public int BookId { get; set; }
public List<int> TrackNumbers { get; set; } public List<int> TrackNumbers { get; set; }
public int TrackFileId { get; set; } public int BookFileId { get; set; }
public string Path { get; set; } public string Path { get; set; }
public List<TagDifference> Changes { get; set; } public List<TagDifference> Changes { get; set; }
} }
public static class RetagTrackResourceMapper public static class RetagTrackResourceMapper
{ {
public static RetagTrackResource ToResource(this NzbDrone.Core.MediaFiles.RetagBookFilePreview model) public static RetagBookResource ToResource(this NzbDrone.Core.MediaFiles.RetagBookFilePreview model)
{ {
if (model == null) if (model == null)
{ {
return null; return null;
} }
return new RetagTrackResource return new RetagBookResource
{ {
AuthorId = model.AuthorId, AuthorId = model.AuthorId,
BookId = model.BookId, BookId = model.BookId,
TrackNumbers = model.TrackNumbers.ToList(), TrackNumbers = model.TrackNumbers.ToList(),
TrackFileId = model.BookFileId, BookFileId = model.BookFileId,
Path = model.Path, Path = model.Path,
Changes = model.Changes.Select(x => new TagDifference Changes = model.Changes.Select(x => new TagDifference
{ {
@@ -46,7 +46,7 @@ namespace Readarr.Api.V1.Albums
}; };
} }
public static List<RetagTrackResource> ToResource(this IEnumerable<NzbDrone.Core.MediaFiles.RetagBookFilePreview> models) public static List<RetagBookResource> ToResource(this IEnumerable<NzbDrone.Core.MediaFiles.RetagBookFilePreview> models)
{ {
return models.Select(ToResource).ToList(); return models.Select(ToResource).ToList();
} }

View File

@@ -61,35 +61,35 @@ namespace Readarr.Api.V1.Calendar
tags.AddRange(tagInput.Split(',').Select(_tagService.GetTag).Select(t => t.Id)); tags.AddRange(tagInput.Split(',').Select(_tagService.GetTag).Select(t => t.Id));
} }
var albums = _bookService.BooksBetweenDates(start, end, unmonitored); var books = _bookService.BooksBetweenDates(start, end, unmonitored);
var calendar = new Ical.Net.Calendar var calendar = new Ical.Net.Calendar
{ {
ProductId = "-//readarr.com//Readarr//EN" ProductId = "-//readarr.com//Readarr//EN"
}; };
var calendarName = "Readarr Music Schedule"; var calendarName = "Readarr Book Schedule";
calendar.AddProperty(new CalendarProperty("NAME", calendarName)); calendar.AddProperty(new CalendarProperty("NAME", calendarName));
calendar.AddProperty(new CalendarProperty("X-WR-CALNAME", calendarName)); calendar.AddProperty(new CalendarProperty("X-WR-CALNAME", calendarName));
foreach (var album in albums.OrderBy(v => v.ReleaseDate.Value)) foreach (var book in books.OrderBy(v => v.ReleaseDate.Value))
{ {
var artist = _authorService.GetAuthor(album.AuthorId); // Temp fix TODO: Figure out why Album.Artist is not populated during AlbumsBetweenDates Query var author = _authorService.GetAuthor(book.AuthorId); // Temp fix TODO: Figure out why Album.Artist is not populated during AlbumsBetweenDates Query
if (tags.Any() && tags.None(artist.Tags.Contains)) if (tags.Any() && tags.None(author.Tags.Contains))
{ {
continue; continue;
} }
var occurrence = calendar.Create<CalendarEvent>(); var occurrence = calendar.Create<CalendarEvent>();
occurrence.Uid = "Readarr_album_" + album.Id; occurrence.Uid = "Readarr_book_" + book.Id;
//occurrence.Status = album.HasFile ? EventStatus.Confirmed : EventStatus.Tentative; //occurrence.Status = album.HasFile ? EventStatus.Confirmed : EventStatus.Tentative;
occurrence.Description = album.Overview; occurrence.Description = book.Overview;
occurrence.Categories = album.Genres; occurrence.Categories = book.Genres;
occurrence.Start = new CalDateTime(album.ReleaseDate.Value.ToLocalTime()) { HasTime = false }; occurrence.Start = new CalDateTime(book.ReleaseDate.Value.ToLocalTime()) { HasTime = false };
occurrence.Summary = $"{artist.Name} - {album.Title}"; occurrence.Summary = $"{author.Name} - {book.Title}";
} }
var serializer = (IStringSerializer)new SerializerFactory().Build(calendar.GetType(), new SerializationContext()); var serializer = (IStringSerializer)new SerializerFactory().Build(calendar.GetType(), new SerializationContext());

View File

@@ -6,32 +6,32 @@ using NzbDrone.Core.Books;
using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.MediaCover; using NzbDrone.Core.MediaCover;
using NzbDrone.SignalR; using NzbDrone.SignalR;
using Readarr.Api.V1.Albums; using Readarr.Api.V1.Books;
using Readarr.Http.Extensions; using Readarr.Http.Extensions;
namespace Readarr.Api.V1.Calendar namespace Readarr.Api.V1.Calendar
{ {
public class CalendarModule : AlbumModuleWithSignalR public class CalendarModule : BookModuleWithSignalR
{ {
public CalendarModule(IBookService bookService, public CalendarModule(IBookService bookService,
IAuthorStatisticsService artistStatisticsService, IAuthorStatisticsService authorStatisticsService,
IMapCoversToLocal coverMapper, IMapCoversToLocal coverMapper,
IUpgradableSpecification upgradableSpecification, IUpgradableSpecification upgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster) IBroadcastSignalRMessage signalRBroadcaster)
: base(bookService, artistStatisticsService, coverMapper, upgradableSpecification, signalRBroadcaster, "calendar") : base(bookService, authorStatisticsService, coverMapper, upgradableSpecification, signalRBroadcaster, "calendar")
{ {
GetResourceAll = GetCalendar; GetResourceAll = GetCalendar;
} }
private List<AlbumResource> GetCalendar() private List<BookResource> GetCalendar()
{ {
var start = DateTime.Today; var start = DateTime.Today;
var end = DateTime.Today.AddDays(2); var end = DateTime.Today.AddDays(2);
var includeUnmonitored = Request.GetBooleanQueryParameter("unmonitored"); var includeUnmonitored = Request.GetBooleanQueryParameter("unmonitored");
var includeArtist = Request.GetBooleanQueryParameter("includeArtist"); var includeAuthor = Request.GetBooleanQueryParameter("includeAuthor");
//TODO: Add Album Image support to AlbumModuleWithSignalR //TODO: Add Album Image support to AlbumModuleWithSignalR
var includeAlbumImages = Request.GetBooleanQueryParameter("includeAlbumImages"); var includeBookImages = Request.GetBooleanQueryParameter("includeBookImages");
var queryStart = Request.Query.Start; var queryStart = Request.Query.Start;
var queryEnd = Request.Query.End; var queryEnd = Request.Query.End;
@@ -46,7 +46,7 @@ namespace Readarr.Api.V1.Calendar
end = DateTime.Parse(queryEnd.Value); end = DateTime.Parse(queryEnd.Value);
} }
var resources = MapToResource(_bookService.BooksBetweenDates(start, end, includeUnmonitored), includeArtist); var resources = MapToResource(_bookService.BooksBetweenDates(start, end, includeUnmonitored), includeAuthor);
return resources.OrderBy(e => e.ReleaseDate).ToList(); return resources.OrderBy(e => e.ReleaseDate).ToList();
} }

View File

@@ -7,11 +7,11 @@ namespace Readarr.Api.V1.Config
{ {
public class MediaManagementConfigResource : RestResource public class MediaManagementConfigResource : RestResource
{ {
public bool AutoUnmonitorPreviouslyDownloadedTracks { get; set; } public bool AutoUnmonitorPreviouslyDownloadedBooks { get; set; }
public string RecycleBin { get; set; } public string RecycleBin { get; set; }
public int RecycleBinCleanupDays { get; set; } public int RecycleBinCleanupDays { get; set; }
public ProperDownloadTypes DownloadPropersAndRepacks { get; set; } public ProperDownloadTypes DownloadPropersAndRepacks { get; set; }
public bool CreateEmptyArtistFolders { get; set; } public bool CreateEmptyAuthorFolders { get; set; }
public bool DeleteEmptyFolders { get; set; } public bool DeleteEmptyFolders { get; set; }
public FileDateType FileDate { get; set; } public FileDateType FileDate { get; set; }
public bool WatchLibraryForChanges { get; set; } public bool WatchLibraryForChanges { get; set; }
@@ -37,11 +37,11 @@ namespace Readarr.Api.V1.Config
{ {
return new MediaManagementConfigResource return new MediaManagementConfigResource
{ {
AutoUnmonitorPreviouslyDownloadedTracks = model.AutoUnmonitorPreviouslyDownloadedTracks, AutoUnmonitorPreviouslyDownloadedBooks = model.AutoUnmonitorPreviouslyDownloadedBooks,
RecycleBin = model.RecycleBin, RecycleBin = model.RecycleBin,
RecycleBinCleanupDays = model.RecycleBinCleanupDays, RecycleBinCleanupDays = model.RecycleBinCleanupDays,
DownloadPropersAndRepacks = model.DownloadPropersAndRepacks, DownloadPropersAndRepacks = model.DownloadPropersAndRepacks,
CreateEmptyArtistFolders = model.CreateEmptyArtistFolders, CreateEmptyAuthorFolders = model.CreateEmptyAuthorFolders,
DeleteEmptyFolders = model.DeleteEmptyFolders, DeleteEmptyFolders = model.DeleteEmptyFolders,
FileDate = model.FileDate, FileDate = model.FileDate,
WatchLibraryForChanges = model.WatchLibraryForChanges, WatchLibraryForChanges = model.WatchLibraryForChanges,

View File

@@ -75,11 +75,11 @@ namespace Readarr.Api.V1.Config
var singleTrackSampleResult = _filenameSampleService.GetStandardTrackSample(nameSpec); var singleTrackSampleResult = _filenameSampleService.GetStandardTrackSample(nameSpec);
sampleResource.SingleTrackExample = _filenameValidationService.ValidateTrackFilename(singleTrackSampleResult) != null sampleResource.SingleBookExample = _filenameValidationService.ValidateTrackFilename(singleTrackSampleResult) != null
? null ? null
: singleTrackSampleResult.FileName; : singleTrackSampleResult.FileName;
sampleResource.ArtistFolderExample = nameSpec.AuthorFolderFormat.IsNullOrWhiteSpace() sampleResource.AuthorFolderExample = nameSpec.AuthorFolderFormat.IsNullOrWhiteSpace()
? null ? null
: _filenameSampleService.GetAuthorFolderSample(nameSpec); : _filenameSampleService.GetAuthorFolderSample(nameSpec);

View File

@@ -4,8 +4,8 @@ namespace Readarr.Api.V1.Config
{ {
public class NamingExampleResource public class NamingExampleResource
{ {
public string SingleTrackExample { get; set; } public string SingleBookExample { get; set; }
public string ArtistFolderExample { get; set; } public string AuthorFolderExample { get; set; }
} }
public static class NamingConfigResourceMapper public static class NamingConfigResourceMapper

View File

@@ -6,8 +6,8 @@ using NzbDrone.Core.Datastore;
using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.History; using NzbDrone.Core.History;
using Readarr.Api.V1.Albums; using Readarr.Api.V1.Author;
using Readarr.Api.V1.Artist; using Readarr.Api.V1.Books;
using Readarr.Http; using Readarr.Http;
using Readarr.Http.Extensions; using Readarr.Http.Extensions;
using Readarr.Http.REST; using Readarr.Http.REST;
@@ -30,7 +30,7 @@ namespace Readarr.Api.V1.History
GetResourcePaged = GetHistory; GetResourcePaged = GetHistory;
Get("/since", x => GetHistorySince()); Get("/since", x => GetHistorySince());
Get("/artist", x => GetArtistHistory()); Get("/author", x => GetArtistHistory());
Post("/failed", x => MarkAsFailed()); Post("/failed", x => MarkAsFailed());
} }
@@ -40,12 +40,12 @@ namespace Readarr.Api.V1.History
if (includeArtist) if (includeArtist)
{ {
resource.Artist = model.Author.ToResource(); resource.Author = model.Author.ToResource();
} }
if (includeAlbum) if (includeAlbum)
{ {
resource.Album = model.Book.ToResource(); resource.Book = model.Book.ToResource();
} }
if (model.Author != null) if (model.Author != null)
@@ -59,8 +59,8 @@ namespace Readarr.Api.V1.History
private PagingResource<HistoryResource> GetHistory(PagingResource<HistoryResource> pagingResource) private PagingResource<HistoryResource> GetHistory(PagingResource<HistoryResource> pagingResource)
{ {
var pagingSpec = pagingResource.MapToPagingSpec<HistoryResource, NzbDrone.Core.History.History>("date", SortDirection.Descending); var pagingSpec = pagingResource.MapToPagingSpec<HistoryResource, NzbDrone.Core.History.History>("date", SortDirection.Descending);
var includeArtist = Request.GetBooleanQueryParameter("includeArtist"); var includeAuthor = Request.GetBooleanQueryParameter("includeAuthor");
var includeAlbum = Request.GetBooleanQueryParameter("includeAlbum"); var includeBook = Request.GetBooleanQueryParameter("includeBook");
var eventTypeFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "eventType"); var eventTypeFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "eventType");
var bookIdFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "bookId"); var bookIdFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "bookId");
@@ -84,7 +84,7 @@ namespace Readarr.Api.V1.History
pagingSpec.FilterExpressions.Add(h => h.DownloadId == downloadId); pagingSpec.FilterExpressions.Add(h => h.DownloadId == downloadId);
} }
return ApplyToPage(_historyService.Paged, pagingSpec, h => MapToResource(h, includeArtist, includeAlbum)); return ApplyToPage(_historyService.Paged, pagingSpec, h => MapToResource(h, includeAuthor, includeBook));
} }
private List<HistoryResource> GetHistorySince() private List<HistoryResource> GetHistorySince()
@@ -99,15 +99,15 @@ namespace Readarr.Api.V1.History
DateTime date = DateTime.Parse(queryDate.Value); DateTime date = DateTime.Parse(queryDate.Value);
HistoryEventType? eventType = null; HistoryEventType? eventType = null;
var includeArtist = Request.GetBooleanQueryParameter("includeArtist"); var includeAuthor = Request.GetBooleanQueryParameter("includeAuthor");
var includeAlbum = Request.GetBooleanQueryParameter("includeAlbum"); var includeBook = Request.GetBooleanQueryParameter("includeBook");
if (queryEventType.HasValue) if (queryEventType.HasValue)
{ {
eventType = (HistoryEventType)Convert.ToInt32(queryEventType.Value); eventType = (HistoryEventType)Convert.ToInt32(queryEventType.Value);
} }
return _historyService.Since(date, eventType).Select(h => MapToResource(h, includeArtist, includeAlbum)).ToList(); return _historyService.Since(date, eventType).Select(h => MapToResource(h, includeAuthor, includeBook)).ToList();
} }
private List<HistoryResource> GetArtistHistory() private List<HistoryResource> GetArtistHistory()
@@ -123,8 +123,8 @@ namespace Readarr.Api.V1.History
int authorId = Convert.ToInt32(queryAuthorId.Value); int authorId = Convert.ToInt32(queryAuthorId.Value);
HistoryEventType? eventType = null; HistoryEventType? eventType = null;
var includeArtist = Request.GetBooleanQueryParameter("includeArtist"); var includeAuthor = Request.GetBooleanQueryParameter("includeAuthor");
var includeAlbum = Request.GetBooleanQueryParameter("includeAlbum"); var includeBook = Request.GetBooleanQueryParameter("includeBook");
if (queryEventType.HasValue) if (queryEventType.HasValue)
{ {
@@ -135,10 +135,10 @@ namespace Readarr.Api.V1.History
{ {
int bookId = Convert.ToInt32(queryBookId.Value); int bookId = Convert.ToInt32(queryBookId.Value);
return _historyService.GetByBook(bookId, eventType).Select(h => MapToResource(h, includeArtist, includeAlbum)).ToList(); return _historyService.GetByBook(bookId, eventType).Select(h => MapToResource(h, includeAuthor, includeBook)).ToList();
} }
return _historyService.GetByAuthor(authorId, eventType).Select(h => MapToResource(h, includeArtist, includeAlbum)).ToList(); return _historyService.GetByAuthor(authorId, eventType).Select(h => MapToResource(h, includeAuthor, includeBook)).ToList();
} }
private object MarkAsFailed() private object MarkAsFailed()

View File

@@ -2,8 +2,8 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using NzbDrone.Core.History; using NzbDrone.Core.History;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using Readarr.Api.V1.Albums; using Readarr.Api.V1.Author;
using Readarr.Api.V1.Artist; using Readarr.Api.V1.Books;
using Readarr.Http.REST; using Readarr.Http.REST;
namespace Readarr.Api.V1.History namespace Readarr.Api.V1.History
@@ -22,8 +22,8 @@ namespace Readarr.Api.V1.History
public Dictionary<string, string> Data { get; set; } public Dictionary<string, string> Data { get; set; }
public AlbumResource Album { get; set; } public BookResource Book { get; set; }
public ArtistResource Artist { get; set; } public AuthorResource Author { get; set; }
} }
public static class HistoryResourceMapper public static class HistoryResourceMapper

View File

@@ -23,7 +23,7 @@ namespace Readarr.Api.V1.ImportLists
DeleteResource = DeleteImportListExclusionResource; DeleteResource = DeleteImportListExclusionResource;
SharedValidator.RuleFor(c => c.ForeignId).NotEmpty().SetValidator(guidValidator).SetValidator(importListExclusionExistsValidator); SharedValidator.RuleFor(c => c.ForeignId).NotEmpty().SetValidator(guidValidator).SetValidator(importListExclusionExistsValidator);
SharedValidator.RuleFor(c => c.ArtistName).NotEmpty(); SharedValidator.RuleFor(c => c.AuthorName).NotEmpty();
} }
private ImportListExclusionResource GetImportListExclusion(int id) private ImportListExclusionResource GetImportListExclusion(int id)

View File

@@ -8,7 +8,7 @@ namespace Readarr.Api.V1.ImportLists
public class ImportListExclusionResource : RestResource public class ImportListExclusionResource : RestResource
{ {
public string ForeignId { get; set; } public string ForeignId { get; set; }
public string ArtistName { get; set; } public string AuthorName { get; set; }
} }
public static class ImportListExclusionResourceMapper public static class ImportListExclusionResourceMapper
@@ -24,7 +24,7 @@ namespace Readarr.Api.V1.ImportLists
{ {
Id = model.Id, Id = model.Id,
ForeignId = model.ForeignId, ForeignId = model.ForeignId,
ArtistName = model.Name, AuthorName = model.Name,
}; };
} }
@@ -39,7 +39,7 @@ namespace Readarr.Api.V1.ImportLists
{ {
Id = resource.Id, Id = resource.Id,
ForeignId = resource.ForeignId, ForeignId = resource.ForeignId,
Name = resource.ArtistName Name = resource.AuthorName
}; };
} }

View File

@@ -24,7 +24,7 @@ namespace Readarr.Api.V1.Indexers
private readonly IDownloadService _downloadService; private readonly IDownloadService _downloadService;
private readonly Logger _logger; private readonly Logger _logger;
private readonly ICached<RemoteBook> _remoteAlbumCache; private readonly ICached<RemoteBook> _remoteBookCache;
public ReleaseModule(IFetchAndParseRss rssFetcherAndParser, public ReleaseModule(IFetchAndParseRss rssFetcherAndParser,
ISearchForNzb nzbSearchService, ISearchForNzb nzbSearchService,
@@ -47,12 +47,12 @@ namespace Readarr.Api.V1.Indexers
PostValidator.RuleFor(s => s.IndexerId).ValidId(); PostValidator.RuleFor(s => s.IndexerId).ValidId();
PostValidator.RuleFor(s => s.Guid).NotEmpty(); PostValidator.RuleFor(s => s.Guid).NotEmpty();
_remoteAlbumCache = cacheManager.GetCache<RemoteBook>(GetType(), "remoteAlbums"); _remoteBookCache = cacheManager.GetCache<RemoteBook>(GetType(), "remoteBooks");
} }
private object DownloadRelease(ReleaseResource release) private object DownloadRelease(ReleaseResource release)
{ {
var remoteAlbum = _remoteAlbumCache.Find(GetCacheKey(release)); var remoteAlbum = _remoteBookCache.Find(GetCacheKey(release));
if (remoteAlbum == null) if (remoteAlbum == null)
{ {
@@ -78,46 +78,46 @@ namespace Readarr.Api.V1.Indexers
{ {
if (Request.Query.bookId.HasValue) if (Request.Query.bookId.HasValue)
{ {
return GetAlbumReleases(Request.Query.bookId); return GetBookReleases(Request.Query.bookId);
} }
if (Request.Query.authorId.HasValue) if (Request.Query.authorId.HasValue)
{ {
return GetArtistReleases(Request.Query.authorId); return GetAuthorReleases(Request.Query.authorId);
} }
return GetRss(); return GetRss();
} }
private List<ReleaseResource> GetAlbumReleases(int bookId) private List<ReleaseResource> GetBookReleases(int bookId)
{ {
try try
{ {
var decisions = _nzbSearchService.AlbumSearch(bookId, true, true, true); var decisions = _nzbSearchService.BookSearch(bookId, true, true, true);
var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(decisions); var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(decisions);
return MapDecisions(prioritizedDecisions); return MapDecisions(prioritizedDecisions);
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Album search failed"); _logger.Error(ex, "Book search failed");
} }
return new List<ReleaseResource>(); return new List<ReleaseResource>();
} }
private List<ReleaseResource> GetArtistReleases(int authorId) private List<ReleaseResource> GetAuthorReleases(int authorId)
{ {
try try
{ {
var decisions = _nzbSearchService.ArtistSearch(authorId, false, true, true); var decisions = _nzbSearchService.AuthorSearch(authorId, false, true, true);
var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(decisions); var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(decisions);
return MapDecisions(prioritizedDecisions); return MapDecisions(prioritizedDecisions);
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Artist search failed"); _logger.Error(ex, "Author search failed");
} }
return new List<ReleaseResource>(); return new List<ReleaseResource>();
@@ -135,7 +135,7 @@ namespace Readarr.Api.V1.Indexers
protected override ReleaseResource MapDecision(DownloadDecision decision, int initialWeight) protected override ReleaseResource MapDecision(DownloadDecision decision, int initialWeight)
{ {
var resource = base.MapDecision(decision, initialWeight); var resource = base.MapDecision(decision, initialWeight);
_remoteAlbumCache.Set(GetCacheKey(resource), decision.RemoteBook, TimeSpan.FromMinutes(30)); _remoteBookCache.Set(GetCacheKey(resource), decision.RemoteBook, TimeSpan.FromMinutes(30));
return resource; return resource;
} }

View File

@@ -28,8 +28,8 @@ namespace Readarr.Api.V1.Indexers
public bool Discography { get; set; } public bool Discography { get; set; }
public bool SceneSource { get; set; } public bool SceneSource { get; set; }
public string AirDate { get; set; } public string AirDate { get; set; }
public string ArtistName { get; set; } public string AuthorName { get; set; }
public string AlbumTitle { get; set; } public string BookTitle { get; set; }
public bool Approved { get; set; } public bool Approved { get; set; }
public bool TemporarilyRejected { get; set; } public bool TemporarilyRejected { get; set; }
public bool Rejected { get; set; } public bool Rejected { get; set; }
@@ -65,15 +65,15 @@ namespace Readarr.Api.V1.Indexers
public static ReleaseResource ToResource(this DownloadDecision model) public static ReleaseResource ToResource(this DownloadDecision model)
{ {
var releaseInfo = model.RemoteBook.Release; var releaseInfo = model.RemoteBook.Release;
var parsedAlbumInfo = model.RemoteBook.ParsedBookInfo; var parsedBookInfo = model.RemoteBook.ParsedBookInfo;
var remoteAlbum = model.RemoteBook; var remoteBook = model.RemoteBook;
var torrentInfo = (model.RemoteBook.Release as TorrentInfo) ?? new TorrentInfo(); var torrentInfo = (model.RemoteBook.Release as TorrentInfo) ?? new TorrentInfo();
// TODO: Clean this mess up. don't mix data from multiple classes, use sub-resources instead? (Got a huge Deja Vu, didn't we talk about this already once?) // TODO: Clean this mess up. don't mix data from multiple classes, use sub-resources instead? (Got a huge Deja Vu, didn't we talk about this already once?)
return new ReleaseResource return new ReleaseResource
{ {
Guid = releaseInfo.Guid, Guid = releaseInfo.Guid,
Quality = parsedAlbumInfo.Quality, Quality = parsedBookInfo.Quality,
//QualityWeight //QualityWeight
Age = releaseInfo.Age, Age = releaseInfo.Age,
@@ -82,12 +82,12 @@ namespace Readarr.Api.V1.Indexers
Size = releaseInfo.Size, Size = releaseInfo.Size,
IndexerId = releaseInfo.IndexerId, IndexerId = releaseInfo.IndexerId,
Indexer = releaseInfo.Indexer, Indexer = releaseInfo.Indexer,
ReleaseGroup = parsedAlbumInfo.ReleaseGroup, ReleaseGroup = parsedBookInfo.ReleaseGroup,
ReleaseHash = parsedAlbumInfo.ReleaseHash, ReleaseHash = parsedBookInfo.ReleaseHash,
Title = releaseInfo.Title, Title = releaseInfo.Title,
ArtistName = parsedAlbumInfo.AuthorName, AuthorName = parsedBookInfo.AuthorName,
AlbumTitle = parsedAlbumInfo.BookTitle, BookTitle = parsedBookInfo.BookTitle,
Discography = parsedAlbumInfo.Discography, Discography = parsedBookInfo.Discography,
Approved = model.Approved, Approved = model.Approved,
TemporarilyRejected = model.TemporarilyRejected, TemporarilyRejected = model.TemporarilyRejected,
Rejected = model.Rejected, Rejected = model.Rejected,
@@ -96,10 +96,10 @@ namespace Readarr.Api.V1.Indexers
CommentUrl = releaseInfo.CommentUrl, CommentUrl = releaseInfo.CommentUrl,
DownloadUrl = releaseInfo.DownloadUrl, DownloadUrl = releaseInfo.DownloadUrl,
InfoUrl = releaseInfo.InfoUrl, InfoUrl = releaseInfo.InfoUrl,
DownloadAllowed = remoteAlbum.DownloadAllowed, DownloadAllowed = remoteBook.DownloadAllowed,
//ReleaseWeight //ReleaseWeight
PreferredWordScore = remoteAlbum.PreferredWordScore, PreferredWordScore = remoteBook.PreferredWordScore,
MagnetUrl = torrentInfo.MagnetUrl, MagnetUrl = torrentInfo.MagnetUrl,
InfoHash = torrentInfo.InfoHash, InfoHash = torrentInfo.InfoHash,

View File

@@ -70,8 +70,8 @@ namespace Readarr.Api.V1.ManualImport
Path = resource.Path, Path = resource.Path,
Name = resource.Name, Name = resource.Name,
Size = resource.Size, Size = resource.Size,
Author = resource.Artist == null ? null : _authorService.GetAuthor(resource.Artist.Id), Author = resource.Author == null ? null : _authorService.GetAuthor(resource.Author.Id),
Book = resource.Album == null ? null : _bookService.GetBook(resource.Album.Id), Book = resource.Book == null ? null : _bookService.GetBook(resource.Book.Id),
Quality = resource.Quality, Quality = resource.Quality,
DownloadId = resource.DownloadId, DownloadId = resource.DownloadId,
AdditionalFile = resource.AdditionalFile, AdditionalFile = resource.AdditionalFile,

View File

@@ -4,8 +4,8 @@ using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.MediaFiles.BookImport.Manual; using NzbDrone.Core.MediaFiles.BookImport.Manual;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using Readarr.Api.V1.Albums; using Readarr.Api.V1.Author;
using Readarr.Api.V1.Artist; using Readarr.Api.V1.Books;
using Readarr.Http.REST; using Readarr.Http.REST;
namespace Readarr.Api.V1.ManualImport namespace Readarr.Api.V1.ManualImport
@@ -15,8 +15,8 @@ namespace Readarr.Api.V1.ManualImport
public string Path { get; set; } public string Path { get; set; }
public string Name { get; set; } public string Name { get; set; }
public long Size { get; set; } public long Size { get; set; }
public ArtistResource Artist { get; set; } public AuthorResource Author { get; set; }
public AlbumResource Album { get; set; } public BookResource Book { get; set; }
public QualityModel Quality { get; set; } public QualityModel Quality { get; set; }
public int QualityWeight { get; set; } public int QualityWeight { get; set; }
public string DownloadId { get; set; } public string DownloadId { get; set; }
@@ -41,8 +41,8 @@ namespace Readarr.Api.V1.ManualImport
Path = model.Path, Path = model.Path,
Name = model.Name, Name = model.Name,
Size = model.Size, Size = model.Size,
Artist = model.Author.ToResource(), Author = model.Author.ToResource(),
Album = model.Book.ToResource(), Book = model.Book.ToResource(),
Quality = model.Quality, Quality = model.Quality,
//QualityWeight //QualityWeight

View File

@@ -10,8 +10,8 @@ namespace Readarr.Api.V1.MediaCovers
{ {
public class MediaCoverModule : ReadarrV1Module public class MediaCoverModule : ReadarrV1Module
{ {
private const string MEDIA_COVER_ARTIST_ROUTE = @"/Artist/(?<authorId>\d+)/(?<filename>(.+)\.(jpg|png|gif))"; private const string MEDIA_COVER_AUTHOR_ROUTE = @"/Author/(?<authorId>\d+)/(?<filename>(.+)\.(jpg|png|gif))";
private const string MEDIA_COVER_ALBUM_ROUTE = @"/Album/(?<authorId>\d+)/(?<filename>(.+)\.(jpg|png|gif))"; private const string MEDIA_COVER_BOOK_ROUTE = @"/Book/(?<authorId>\d+)/(?<filename>(.+)\.(jpg|png|gif))";
private static readonly Regex RegexResizedImage = new Regex(@"-\d+(?=\.(jpg|png|gif)$)", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex RegexResizedImage = new Regex(@"-\d+(?=\.(jpg|png|gif)$)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
@@ -24,8 +24,8 @@ namespace Readarr.Api.V1.MediaCovers
_appFolderInfo = appFolderInfo; _appFolderInfo = appFolderInfo;
_diskProvider = diskProvider; _diskProvider = diskProvider;
Get(MEDIA_COVER_ARTIST_ROUTE, options => GetArtistMediaCover(options.authorId, options.filename)); Get(MEDIA_COVER_AUTHOR_ROUTE, options => GetArtistMediaCover(options.authorId, options.filename));
Get(MEDIA_COVER_ALBUM_ROUTE, options => GetAlbumMediaCover(options.authorId, options.filename)); Get(MEDIA_COVER_BOOK_ROUTE, options => GetAlbumMediaCover(options.authorId, options.filename));
} }
private object GetArtistMediaCover(int authorId, string filename) private object GetArtistMediaCover(int authorId, string filename)
@@ -50,7 +50,7 @@ namespace Readarr.Api.V1.MediaCovers
private object GetAlbumMediaCover(int bookId, string filename) private object GetAlbumMediaCover(int bookId, string filename)
{ {
var filePath = Path.Combine(_appFolderInfo.GetAppDataPath(), "MediaCover", "Albums", bookId.ToString(), filename); var filePath = Path.Combine(_appFolderInfo.GetAppDataPath(), "MediaCover", "Books", bookId.ToString(), filename);
if (!_diskProvider.FileExists(filePath) || _diskProvider.GetFileSize(filePath) == 0) if (!_diskProvider.FileExists(filePath) || _diskProvider.GetFileSize(filePath) == 0)
{ {

View File

@@ -1,6 +1,6 @@
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using Readarr.Api.V1.Albums; using Readarr.Api.V1.Author;
using Readarr.Api.V1.Artist; using Readarr.Api.V1.Books;
using Readarr.Http; using Readarr.Http;
namespace Readarr.Api.V1.Parse namespace Readarr.Api.V1.Parse
@@ -33,9 +33,9 @@ namespace Readarr.Api.V1.Parse
return new ParseResource return new ParseResource
{ {
Title = title, Title = title,
ParsedAlbumInfo = remoteAlbum.ParsedBookInfo, ParsedBookInfo = remoteAlbum.ParsedBookInfo,
Artist = remoteAlbum.Author.ToResource(), Author = remoteAlbum.Author.ToResource(),
Albums = remoteAlbum.Books.ToResource() Books = remoteAlbum.Books.ToResource()
}; };
} }
else else
@@ -43,7 +43,7 @@ namespace Readarr.Api.V1.Parse
return new ParseResource return new ParseResource
{ {
Title = title, Title = title,
ParsedAlbumInfo = parsedAlbumInfo ParsedBookInfo = parsedAlbumInfo
}; };
} }
} }

View File

@@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using Readarr.Api.V1.Albums; using Readarr.Api.V1.Author;
using Readarr.Api.V1.Artist; using Readarr.Api.V1.Books;
using Readarr.Http.REST; using Readarr.Http.REST;
namespace Readarr.Api.V1.Parse namespace Readarr.Api.V1.Parse
@@ -9,8 +9,8 @@ namespace Readarr.Api.V1.Parse
public class ParseResource : RestResource public class ParseResource : RestResource
{ {
public string Title { get; set; } public string Title { get; set; }
public ParsedBookInfo ParsedAlbumInfo { get; set; } public ParsedBookInfo ParsedBookInfo { get; set; }
public ArtistResource Artist { get; set; } public AuthorResource Author { get; set; }
public List<AlbumResource> Albums { get; set; } public List<BookResource> Books { get; set; }
} }
} }

View File

@@ -27,8 +27,8 @@ namespace Readarr.Api.V1.Queue
private List<QueueResource> GetQueue() private List<QueueResource> GetQueue()
{ {
var includeArtist = Request.GetBooleanQueryParameter("includeArtist"); var includeAuthor = Request.GetBooleanQueryParameter("includeAuthor");
var includeAlbum = Request.GetBooleanQueryParameter("includeAlbum", true); var includeBook = Request.GetBooleanQueryParameter("includeBook", true);
var queue = _queueService.GetQueue(); var queue = _queueService.GetQueue();
var pending = _pendingReleaseService.GetPendingQueue(); var pending = _pendingReleaseService.GetPendingQueue();
var fullQueue = queue.Concat(pending); var fullQueue = queue.Concat(pending);
@@ -38,7 +38,7 @@ namespace Readarr.Api.V1.Queue
if (authorIdQuery.HasValue) if (authorIdQuery.HasValue)
{ {
return fullQueue.Where(q => q.Author?.Id == (int)authorIdQuery).ToResource(includeArtist, includeAlbum); return fullQueue.Where(q => q.Author?.Id == (int)authorIdQuery).ToResource(includeAuthor, includeBook);
} }
if (bookIdsQuery.HasValue) if (bookIdsQuery.HasValue)
@@ -49,10 +49,10 @@ namespace Readarr.Api.V1.Queue
.Select(e => Convert.ToInt32(e)) .Select(e => Convert.ToInt32(e))
.ToList(); .ToList();
return fullQueue.Where(q => q.Book != null && bookIds.Contains(q.Book.Id)).ToResource(includeArtist, includeAlbum); return fullQueue.Where(q => q.Book != null && bookIds.Contains(q.Book.Id)).ToResource(includeAuthor, includeBook);
} }
return fullQueue.ToResource(includeArtist, includeAlbum); return fullQueue.ToResource(includeAuthor, includeBook);
} }
public void Handle(QueueUpdatedEvent message) public void Handle(QueueUpdatedEvent message)

View File

@@ -38,20 +38,20 @@ namespace Readarr.Api.V1.Queue
private PagingResource<QueueResource> GetQueue(PagingResource<QueueResource> pagingResource) private PagingResource<QueueResource> GetQueue(PagingResource<QueueResource> pagingResource)
{ {
var pagingSpec = pagingResource.MapToPagingSpec<QueueResource, NzbDrone.Core.Queue.Queue>("timeleft", SortDirection.Ascending); var pagingSpec = pagingResource.MapToPagingSpec<QueueResource, NzbDrone.Core.Queue.Queue>("timeleft", SortDirection.Ascending);
var includeUnknownArtistItems = Request.GetBooleanQueryParameter("includeUnknownArtistItems"); var includeUnknownAuthorItems = Request.GetBooleanQueryParameter("includeUnknownAuthorItems");
var includeArtist = Request.GetBooleanQueryParameter("includeArtist"); var includeAuthor = Request.GetBooleanQueryParameter("includeAuthor");
var includeAlbum = Request.GetBooleanQueryParameter("includeAlbum"); var includeBook = Request.GetBooleanQueryParameter("includeBook");
return ApplyToPage((spec) => GetQueue(spec, includeUnknownArtistItems), pagingSpec, (q) => MapToResource(q, includeArtist, includeAlbum)); return ApplyToPage((spec) => GetQueue(spec, includeUnknownAuthorItems), pagingSpec, (q) => MapToResource(q, includeAuthor, includeBook));
} }
private PagingSpec<NzbDrone.Core.Queue.Queue> GetQueue(PagingSpec<NzbDrone.Core.Queue.Queue> pagingSpec, bool includeUnknownArtistItems) private PagingSpec<NzbDrone.Core.Queue.Queue> GetQueue(PagingSpec<NzbDrone.Core.Queue.Queue> pagingSpec, bool includeUnknownAuthorItems)
{ {
var ascending = pagingSpec.SortDirection == SortDirection.Ascending; var ascending = pagingSpec.SortDirection == SortDirection.Ascending;
var orderByFunc = GetOrderByFunc(pagingSpec); var orderByFunc = GetOrderByFunc(pagingSpec);
var queue = _queueService.GetQueue(); var queue = _queueService.GetQueue();
var filteredQueue = includeUnknownArtistItems ? queue : queue.Where(q => q.Author != null); var filteredQueue = includeUnknownAuthorItems ? queue : queue.Where(q => q.Author != null);
var pending = _pendingReleaseService.GetPendingQueue(); var pending = _pendingReleaseService.GetPendingQueue();
var fullQueue = filteredQueue.Concat(pending).ToList(); var fullQueue = filteredQueue.Concat(pending).ToList();
IOrderedEnumerable<NzbDrone.Core.Queue.Queue> ordered; IOrderedEnumerable<NzbDrone.Core.Queue.Queue> ordered;
@@ -122,11 +122,11 @@ namespace Readarr.Api.V1.Queue
return q => q.Author?.SortName; return q => q.Author?.SortName;
case "title": case "title":
return q => q.Title; return q => q.Title;
case "album": case "book":
return q => q.Book; return q => q.Book;
case "books.title": case "book.title":
return q => q.Book?.Title; return q => q.Book?.Title;
case "album.releaseDate": case "book.releaseDate":
return q => q.Book?.ReleaseDate; return q => q.Book?.ReleaseDate;
case "quality": case "quality":
return q => q.Quality; return q => q.Quality;
@@ -138,9 +138,9 @@ namespace Readarr.Api.V1.Queue
} }
} }
private QueueResource MapToResource(NzbDrone.Core.Queue.Queue queueItem, bool includeArtist, bool includeAlbum) private QueueResource MapToResource(NzbDrone.Core.Queue.Queue queueItem, bool includeAuthor, bool includeBook)
{ {
return queueItem.ToResource(includeArtist, includeAlbum); return queueItem.ToResource(includeAuthor, includeBook);
} }
public void Handle(QueueUpdatedEvent message) public void Handle(QueueUpdatedEvent message)

View File

@@ -5,8 +5,8 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Core.Download.TrackedDownloads; using NzbDrone.Core.Download.TrackedDownloads;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using Readarr.Api.V1.Albums; using Readarr.Api.V1.Author;
using Readarr.Api.V1.Artist; using Readarr.Api.V1.Books;
using Readarr.Http.REST; using Readarr.Http.REST;
namespace Readarr.Api.V1.Queue namespace Readarr.Api.V1.Queue
@@ -15,8 +15,8 @@ namespace Readarr.Api.V1.Queue
{ {
public int? AuthorId { get; set; } public int? AuthorId { get; set; }
public int? BookId { get; set; } public int? BookId { get; set; }
public ArtistResource Artist { get; set; } public AuthorResource Author { get; set; }
public AlbumResource Album { get; set; } public BookResource Book { get; set; }
public QualityModel Quality { get; set; } public QualityModel Quality { get; set; }
public decimal Size { get; set; } public decimal Size { get; set; }
public string Title { get; set; } public string Title { get; set; }
@@ -50,8 +50,8 @@ namespace Readarr.Api.V1.Queue
Id = model.Id, Id = model.Id,
AuthorId = model.Author?.Id, AuthorId = model.Author?.Id,
BookId = model.Book?.Id, BookId = model.Book?.Id,
Artist = includeArtist && model.Author != null ? model.Author.ToResource() : null, Author = includeArtist && model.Author != null ? model.Author.ToResource() : null,
Album = includeAlbum && model.Book != null ? model.Book.ToResource() : null, Book = includeAlbum && model.Book != null ? model.Book.ToResource() : null,
Quality = model.Quality, Quality = model.Quality,
Size = model.Size, Size = model.Size,
Title = model.Title, Title = model.Title,
@@ -72,9 +72,9 @@ namespace Readarr.Api.V1.Queue
}; };
} }
public static List<QueueResource> ToResource(this IEnumerable<NzbDrone.Core.Queue.Queue> models, bool includeArtist, bool includeAlbum) public static List<QueueResource> ToResource(this IEnumerable<NzbDrone.Core.Queue.Queue> models, bool includeAuthor, bool includeBook)
{ {
return models.Select((m) => ToResource(m, includeArtist, includeAlbum)).ToList(); return models.Select((m) => ToResource(m, includeAuthor, includeBook)).ToList();
} }
} }
} }

View File

@@ -4,8 +4,8 @@ using System.Linq;
using Nancy; using Nancy;
using NzbDrone.Core.MediaCover; using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MetadataSource; using NzbDrone.Core.MetadataSource;
using Readarr.Api.V1.Albums; using Readarr.Api.V1.Author;
using Readarr.Api.V1.Artist; using Readarr.Api.V1.Books;
using Readarr.Http; using Readarr.Http;
namespace Readarr.Api.V1.Search namespace Readarr.Api.V1.Search
@@ -37,26 +37,26 @@ namespace Readarr.Api.V1.Search
if (result is NzbDrone.Core.Books.Author) if (result is NzbDrone.Core.Books.Author)
{ {
var artist = (NzbDrone.Core.Books.Author)result; var author = (NzbDrone.Core.Books.Author)result;
resource.Artist = artist.ToResource(); resource.Author = author.ToResource();
resource.ForeignId = artist.ForeignAuthorId; resource.ForeignId = author.ForeignAuthorId;
var poster = artist.Metadata.Value.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster); var poster = author.Metadata.Value.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster);
if (poster != null) if (poster != null)
{ {
resource.Artist.RemotePoster = poster.Url; resource.Author.RemotePoster = poster.Url;
} }
} }
else if (result is NzbDrone.Core.Books.Book) else if (result is NzbDrone.Core.Books.Book)
{ {
var album = (NzbDrone.Core.Books.Book)result; var book = (NzbDrone.Core.Books.Book)result;
resource.Album = album.ToResource(); resource.Book = book.ToResource();
resource.ForeignId = album.ForeignBookId; resource.ForeignId = book.ForeignBookId;
var cover = album.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Cover); var cover = book.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Cover);
if (cover != null) if (cover != null)
{ {
resource.Album.RemoteCover = cover.Url; resource.Book.RemoteCover = cover.Url;
} }
} }
else else

View File

@@ -1,5 +1,5 @@
using Readarr.Api.V1.Albums; using Readarr.Api.V1.Author;
using Readarr.Api.V1.Artist; using Readarr.Api.V1.Books;
using Readarr.Http.REST; using Readarr.Http.REST;
namespace Readarr.Api.V1.Search namespace Readarr.Api.V1.Search
@@ -8,7 +8,7 @@ namespace Readarr.Api.V1.Search
SearchResource : RestResource SearchResource : RestResource
{ {
public string ForeignId { get; set; } public string ForeignId { get; set; }
public ArtistResource Artist { get; set; } public AuthorResource Author { get; set; }
public AlbumResource Album { get; set; } public BookResource Book { get; set; }
} }
} }

View File

@@ -5,29 +5,29 @@ using NzbDrone.Core.Datastore;
using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.MediaCover; using NzbDrone.Core.MediaCover;
using NzbDrone.SignalR; using NzbDrone.SignalR;
using Readarr.Api.V1.Albums; using Readarr.Api.V1.Books;
using Readarr.Http; using Readarr.Http;
using Readarr.Http.Extensions; using Readarr.Http.Extensions;
namespace Readarr.Api.V1.Wanted namespace Readarr.Api.V1.Wanted
{ {
public class CutoffModule : AlbumModuleWithSignalR public class CutoffModule : BookModuleWithSignalR
{ {
private readonly IBookCutoffService _albumCutoffService; private readonly IBookCutoffService _bookCutoffService;
public CutoffModule(IBookCutoffService albumCutoffService, public CutoffModule(IBookCutoffService bookCutoffService,
IBookService bookService, IBookService bookService,
IAuthorStatisticsService artistStatisticsService, IAuthorStatisticsService authorStatisticsService,
IMapCoversToLocal coverMapper, IMapCoversToLocal coverMapper,
IUpgradableSpecification upgradableSpecification, IUpgradableSpecification upgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster) IBroadcastSignalRMessage signalRBroadcaster)
: base(bookService, artistStatisticsService, coverMapper, upgradableSpecification, signalRBroadcaster, "wanted/cutoff") : base(bookService, authorStatisticsService, coverMapper, upgradableSpecification, signalRBroadcaster, "wanted/cutoff")
{ {
_albumCutoffService = albumCutoffService; _bookCutoffService = bookCutoffService;
GetResourcePaged = GetCutoffUnmetAlbums; GetResourcePaged = GetCutoffUnmetBooks;
} }
private PagingResource<AlbumResource> GetCutoffUnmetAlbums(PagingResource<AlbumResource> pagingResource) private PagingResource<BookResource> GetCutoffUnmetBooks(PagingResource<BookResource> pagingResource)
{ {
var pagingSpec = new PagingSpec<Book> var pagingSpec = new PagingSpec<Book>
{ {
@@ -37,7 +37,7 @@ namespace Readarr.Api.V1.Wanted
SortDirection = pagingResource.SortDirection SortDirection = pagingResource.SortDirection
}; };
var includeArtist = Request.GetBooleanQueryParameter("includeArtist"); var includeAuthor = Request.GetBooleanQueryParameter("includeAuthor");
var filter = pagingResource.Filters.FirstOrDefault(f => f.Key == "monitored"); var filter = pagingResource.Filters.FirstOrDefault(f => f.Key == "monitored");
if (filter != null && filter.Value == "false") if (filter != null && filter.Value == "false")
@@ -49,7 +49,7 @@ namespace Readarr.Api.V1.Wanted
pagingSpec.FilterExpressions.Add(v => v.Monitored == true && v.Author.Value.Monitored == true); pagingSpec.FilterExpressions.Add(v => v.Monitored == true && v.Author.Value.Monitored == true);
} }
var resource = ApplyToPage(_albumCutoffService.BooksWhereCutoffUnmet, pagingSpec, v => MapToResource(v, includeArtist)); var resource = ApplyToPage(_bookCutoffService.BooksWhereCutoffUnmet, pagingSpec, v => MapToResource(v, includeAuthor));
return resource; return resource;
} }

View File

@@ -5,25 +5,25 @@ using NzbDrone.Core.Datastore;
using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.MediaCover; using NzbDrone.Core.MediaCover;
using NzbDrone.SignalR; using NzbDrone.SignalR;
using Readarr.Api.V1.Albums; using Readarr.Api.V1.Books;
using Readarr.Http; using Readarr.Http;
using Readarr.Http.Extensions; using Readarr.Http.Extensions;
namespace Readarr.Api.V1.Wanted namespace Readarr.Api.V1.Wanted
{ {
public class MissingModule : AlbumModuleWithSignalR public class MissingModule : BookModuleWithSignalR
{ {
public MissingModule(IBookService bookService, public MissingModule(IBookService bookService,
IAuthorStatisticsService artistStatisticsService, IAuthorStatisticsService authorStatisticsService,
IMapCoversToLocal coverMapper, IMapCoversToLocal coverMapper,
IUpgradableSpecification upgradableSpecification, IUpgradableSpecification upgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster) IBroadcastSignalRMessage signalRBroadcaster)
: base(bookService, artistStatisticsService, coverMapper, upgradableSpecification, signalRBroadcaster, "wanted/missing") : base(bookService, authorStatisticsService, coverMapper, upgradableSpecification, signalRBroadcaster, "wanted/missing")
{ {
GetResourcePaged = GetMissingAlbums; GetResourcePaged = GetMissingBooks;
} }
private PagingResource<AlbumResource> GetMissingAlbums(PagingResource<AlbumResource> pagingResource) private PagingResource<BookResource> GetMissingBooks(PagingResource<BookResource> pagingResource)
{ {
var pagingSpec = new PagingSpec<Book> var pagingSpec = new PagingSpec<Book>
{ {
@@ -33,7 +33,7 @@ namespace Readarr.Api.V1.Wanted
SortDirection = pagingResource.SortDirection SortDirection = pagingResource.SortDirection
}; };
var includeArtist = Request.GetBooleanQueryParameter("includeArtist"); var includeAuthor = Request.GetBooleanQueryParameter("includeAuthor");
var monitoredFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "monitored"); var monitoredFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "monitored");
if (monitoredFilter != null && monitoredFilter.Value == "false") if (monitoredFilter != null && monitoredFilter.Value == "false")
@@ -45,7 +45,7 @@ namespace Readarr.Api.V1.Wanted
pagingSpec.FilterExpressions.Add(v => v.Monitored == true && v.Author.Value.Monitored == true); pagingSpec.FilterExpressions.Add(v => v.Monitored == true && v.Author.Value.Monitored == true);
} }
var resource = ApplyToPage(_bookService.BooksWithoutFiles, pagingSpec, v => MapToResource(v, includeArtist)); var resource = ApplyToPage(_bookService.BooksWithoutFiles, pagingSpec, v => MapToResource(v, includeAuthor));
return resource; return resource;
} }