mirror of
https://github.com/fergalmoran/Readarr.git
synced 2025-12-22 09:29:59 +00:00
Method, Variable, Class Renames in Readarr.Api
This commit is contained in:
@@ -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]
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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); }
|
||||||
|
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 &&
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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");
|
||||||
}
|
}
|
||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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)
|
||||||
20
src/NzbDrone.Integration.Test/Client/BookClient.cs
Normal file
20
src/NzbDrone.Integration.Test/Client/BookClient.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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/";
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Readarr.Api.V1.Artist
|
namespace Readarr.Api.V1.Author
|
||||||
{
|
{
|
||||||
public class AlternateTitleResource
|
public class AlternateTitleResource
|
||||||
{
|
{
|
||||||
@@ -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; }
|
||||||
@@ -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)
|
||||||
{
|
{
|
||||||
@@ -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; }
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
@@ -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)
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
43
src/Readarr.Api.V1/Author/AuthorStatisticsResource.cs
Normal file
43
src/Readarr.Api.V1/Author/AuthorStatisticsResource.cs
Normal 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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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();
|
||||||
@@ -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)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
{
|
{
|
||||||
12
src/Readarr.Api.V1/BookShelf/BookshelfAuthorResource1.cs
Normal file
12
src/Readarr.Api.V1/BookShelf/BookshelfAuthorResource1.cs
Normal 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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
47
src/Readarr.Api.V1/BookShelf/BookshelfModule1.cs
Normal file
47
src/Readarr.Api.V1/BookShelf/BookshelfModule1.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
@@ -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)
|
||||||
133
src/Readarr.Api.V1/Books/BookModuleWithSignalR.cs
Normal file
133
src/Readarr.Api.V1/Books/BookModuleWithSignalR.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -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; }
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
{
|
{
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
@@ -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());
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user