Fixed: Removed unnecessary author data from book endpoint

pull/1702/head
ta264 2 years ago
parent ce58e6ecdb
commit a59706ceb4

@ -8,6 +8,7 @@ import * as commandNames from 'Commands/commandNames';
import { toggleBooksMonitored } from 'Store/Actions/bookActions'; import { toggleBooksMonitored } from 'Store/Actions/bookActions';
import { clearBookFiles, fetchBookFiles } from 'Store/Actions/bookFileActions'; import { clearBookFiles, fetchBookFiles } from 'Store/Actions/bookFileActions';
import { executeCommand } from 'Store/Actions/commandActions'; import { executeCommand } from 'Store/Actions/commandActions';
import { clearEditions, fetchEditions } from 'Store/Actions/editionActions';
import { cancelFetchReleases, clearReleases } from 'Store/Actions/releaseActions'; import { cancelFetchReleases, clearReleases } from 'Store/Actions/releaseActions';
import createAllAuthorSelector from 'Store/Selectors/createAllAuthorsSelector'; import createAllAuthorSelector from 'Store/Selectors/createAllAuthorsSelector';
import createCommandsSelector from 'Store/Selectors/createCommandsSelector'; import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
@ -43,11 +44,12 @@ function createMapStateToProps() {
(state, { titleSlug }) => titleSlug, (state, { titleSlug }) => titleSlug,
selectBookFiles, selectBookFiles,
(state) => state.books, (state) => state.books,
(state) => state.editions,
createAllAuthorSelector(), createAllAuthorSelector(),
createCommandsSelector(), createCommandsSelector(),
createUISettingsSelector(), createUISettingsSelector(),
createDimensionsSelector(), createDimensionsSelector(),
(titleSlug, bookFiles, books, authors, commands, uiSettings, dimensions) => { (titleSlug, bookFiles, books, editions, authors, commands, uiSettings, dimensions) => {
const book = books.items.find((b) => b.titleSlug === titleSlug); const book = books.items.find((b) => b.titleSlug === titleSlug);
const author = authors.find((a) => a.id === book.authorId); const author = authors.find((a) => a.id === book.authorId);
const sortedBooks = books.items.filter((b) => b.authorId === book.authorId); const sortedBooks = books.items.filter((b) => b.authorId === book.authorId);
@ -79,8 +81,8 @@ function createMapStateToProps() {
isRefreshingCommand.body.bookId === book.id isRefreshingCommand.body.bookId === book.id
); );
const isFetching = isBookFilesFetching; const isFetching = isBookFilesFetching || editions.isFetching;
const isPopulated = isBookFilesPopulated; const isPopulated = isBookFilesPopulated && editions.isPopulated;
return { return {
...book, ...book,
@ -104,6 +106,8 @@ const mapDispatchToProps = {
executeCommand, executeCommand,
fetchBookFiles, fetchBookFiles,
clearBookFiles, clearBookFiles,
fetchEditions,
clearEditions,
clearReleases, clearReleases,
cancelFetchReleases, cancelFetchReleases,
toggleBooksMonitored toggleBooksMonitored
@ -121,7 +125,8 @@ class BookDetailsConnector extends Component {
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
if (!_.isEqual(getMonitoredEditions(prevProps), getMonitoredEditions(this.props)) || if (prevProps.id !== this.props.id ||
!_.isEqual(getMonitoredEditions(prevProps), getMonitoredEditions(this.props)) ||
(prevProps.anyReleaseOk === false && this.props.anyReleaseOk === true)) { (prevProps.anyReleaseOk === false && this.props.anyReleaseOk === true)) {
this.unpopulate(); this.unpopulate();
this.populate(); this.populate();
@ -140,12 +145,14 @@ class BookDetailsConnector extends Component {
const bookId = this.props.id; const bookId = this.props.id;
this.props.fetchBookFiles({ bookId }); this.props.fetchBookFiles({ bookId });
this.props.fetchEditions({ bookId });
} }
unpopulate = () => { unpopulate = () => {
this.props.cancelFetchReleases(); this.props.cancelFetchReleases();
this.props.clearReleases(); this.props.clearReleases();
this.props.clearBookFiles(); this.props.clearBookFiles();
this.props.clearEditions();
} }
// //
@ -195,6 +202,8 @@ BookDetailsConnector.propTypes = {
titleSlug: PropTypes.string.isRequired, titleSlug: PropTypes.string.isRequired,
fetchBookFiles: PropTypes.func.isRequired, fetchBookFiles: PropTypes.func.isRequired,
clearBookFiles: PropTypes.func.isRequired, clearBookFiles: PropTypes.func.isRequired,
fetchEditions: PropTypes.func.isRequired,
clearEditions: PropTypes.func.isRequired,
clearReleases: PropTypes.func.isRequired, clearReleases: PropTypes.func.isRequired,
cancelFetchReleases: PropTypes.func.isRequired, cancelFetchReleases: PropTypes.func.isRequired,
toggleBooksMonitored: PropTypes.func.isRequired, toggleBooksMonitored: PropTypes.func.isRequired,

@ -8,15 +8,25 @@ import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector'; import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
import BookDetailsHeader from './BookDetailsHeader'; import BookDetailsHeader from './BookDetailsHeader';
const selectOverview = createSelector(
(state) => state.editions,
(editions) => {
const monitored = editions.items.find((e) => e.monitored === true);
return monitored?.overview;
}
);
function createMapStateToProps() { function createMapStateToProps() {
return createSelector( return createSelector(
createBookSelector(), createBookSelector(),
selectOverview,
createUISettingsSelector(), createUISettingsSelector(),
createDimensionsSelector(), createDimensionsSelector(),
(book, uiSettings, dimensions) => { (book, overview, uiSettings, dimensions) => {
return { return {
...book, ...book,
overview,
shortDateFormat: uiSettings.shortDateFormat, shortDateFormat: uiSettings.shortDateFormat,
isSmallScreen: dimensions.isSmallScreen isSmallScreen: dimensions.isSmallScreen
}; };

@ -53,7 +53,7 @@ class EditBookModalContent extends Component {
editions editions
} = item; } = item;
const hasFile = statistics ? statistics.bookFileCount : 0; const hasFile = statistics ? statistics.bookFileCount > 0 : false;
const errorMessage = getErrorMessage(error, 'Unable to load editions'); const errorMessage = getErrorMessage(error, 'Unable to load editions');
return ( return (

@ -4,7 +4,7 @@ import React, { Component } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { saveBook, setBookValue } from 'Store/Actions/bookActions'; import { saveBook, setBookValue } from 'Store/Actions/bookActions';
import { clearEditions, fetchEditions } from 'Store/Actions/editionActions'; import { saveEditions } from 'Store/Actions/editionActions';
import createAuthorSelector from 'Store/Selectors/createAuthorSelector'; import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
import createBookSelector from 'Store/Selectors/createBookSelector'; import createBookSelector from 'Store/Selectors/createBookSelector';
import selectSettings from 'Store/Selectors/selectSettings'; import selectSettings from 'Store/Selectors/selectSettings';
@ -26,17 +26,14 @@ function createMapStateToProps() {
const { const {
isFetching, isFetching,
isPopulated, isPopulated,
error, error
items
} = editionState; } = editionState;
book.editions = items;
const bookSettings = _.pick(book, [ const bookSettings = _.pick(book, [
'monitored', 'monitored',
'anyEditionOk', 'anyEditionOk'
'editions'
]); ]);
bookSettings.editions = editionState.items;
const settings = selectSettings(bookSettings, pendingChanges, saveError); const settings = selectSettings(bookSettings, pendingChanges, saveError);
@ -58,10 +55,9 @@ function createMapStateToProps() {
} }
const mapDispatchToProps = { const mapDispatchToProps = {
dispatchFetchEditions: fetchEditions,
dispatchClearEditions: clearEditions,
dispatchSetBookValue: setBookValue, dispatchSetBookValue: setBookValue,
dispatchSaveBook: saveBook dispatchSaveBook: saveBook,
dispatchSaveEditions: saveEditions
}; };
class EditBookModalContentConnector extends Component { class EditBookModalContentConnector extends Component {
@ -69,20 +65,12 @@ class EditBookModalContentConnector extends Component {
// //
// Lifecycle // Lifecycle
componentDidMount() {
this.props.dispatchFetchEditions({ bookId: this.props.bookId });
}
componentDidUpdate(prevProps, prevState) { componentDidUpdate(prevProps, prevState) {
if (prevProps.isSaving && !this.props.isSaving && !this.props.saveError) { if (prevProps.isSaving && !this.props.isSaving && !this.props.saveError) {
this.props.onModalClose(); this.props.onModalClose();
} }
} }
componentWillUnmount() {
this.props.dispatchClearEditions();
}
// //
// Listeners // Listeners
@ -94,6 +82,9 @@ class EditBookModalContentConnector extends Component {
this.props.dispatchSaveBook({ this.props.dispatchSaveBook({
id: this.props.bookId id: this.props.bookId
}); });
this.props.dispatchSaveEditions({
id: this.props.bookId
});
} }
// //
@ -114,10 +105,9 @@ EditBookModalContentConnector.propTypes = {
bookId: PropTypes.number, bookId: PropTypes.number,
isSaving: PropTypes.bool.isRequired, isSaving: PropTypes.bool.isRequired,
saveError: PropTypes.object, saveError: PropTypes.object,
dispatchFetchEditions: PropTypes.func.isRequired,
dispatchClearEditions: PropTypes.func.isRequired,
dispatchSetBookValue: PropTypes.func.isRequired, dispatchSetBookValue: PropTypes.func.isRequired,
dispatchSaveBook: PropTypes.func.isRequired, dispatchSaveBook: PropTypes.func.isRequired,
dispatchSaveEditions: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired onModalClose: PropTypes.func.isRequired
}; };

@ -5,6 +5,7 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import * as commandNames from 'Commands/commandNames'; import * as commandNames from 'Commands/commandNames';
import { executeCommand } from 'Store/Actions/commandActions'; import { executeCommand } from 'Store/Actions/commandActions';
import createBookAuthorSelector from 'Store/Selectors/createBookAuthorSelector';
import createBookQualityProfileSelector from 'Store/Selectors/createBookQualityProfileSelector'; import createBookQualityProfileSelector from 'Store/Selectors/createBookQualityProfileSelector';
import createBookSelector from 'Store/Selectors/createBookSelector'; import createBookSelector from 'Store/Selectors/createBookSelector';
import createExecutingCommandsSelector from 'Store/Selectors/createExecutingCommandsSelector'; import createExecutingCommandsSelector from 'Store/Selectors/createExecutingCommandsSelector';
@ -32,11 +33,13 @@ function selectShowSearchAction() {
function createMapStateToProps() { function createMapStateToProps() {
return createSelector( return createSelector(
createBookSelector(), createBookSelector(),
createBookAuthorSelector(),
createBookQualityProfileSelector(), createBookQualityProfileSelector(),
selectShowSearchAction(), selectShowSearchAction(),
createExecutingCommandsSelector(), createExecutingCommandsSelector(),
( (
book, book,
author,
qualityProfile, qualityProfile,
showSearchAction, showSearchAction,
executingCommands executingCommands
@ -54,7 +57,7 @@ function createMapStateToProps() {
const isRefreshingBook = executingCommands.some((command) => { const isRefreshingBook = executingCommands.some((command) => {
return ( return (
(command.name === commandNames.REFRESH_AUTHOR && (command.name === commandNames.REFRESH_AUTHOR &&
command.body.authorId === book.author.id) || command.body.authorId === book.authorId) ||
(command.name === commandNames.REFRESH_BOOK && (command.name === commandNames.REFRESH_BOOK &&
command.body.bookId === book.id) command.body.bookId === book.id)
); );
@ -63,7 +66,7 @@ function createMapStateToProps() {
const isSearchingBook = executingCommands.some((command) => { const isSearchingBook = executingCommands.some((command) => {
return ( return (
(command.name === commandNames.AUTHOR_SEARCH && (command.name === commandNames.AUTHOR_SEARCH &&
command.body.authorId === book.author.id) || command.body.authorId === book.authorId) ||
(command.name === commandNames.BOOK_SEARCH && (command.name === commandNames.BOOK_SEARCH &&
command.body.bookIds.includes(book.id)) command.body.bookIds.includes(book.id))
); );
@ -71,6 +74,7 @@ function createMapStateToProps() {
return { return {
...book, ...book,
author,
qualityProfile, qualityProfile,
showSearchAction, showSearchAction,
isRefreshingBook, isRefreshingBook,

@ -12,6 +12,7 @@ import SpinnerIconButton from 'Components/Link/SpinnerIconButton';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import dimensions from 'Styles/Variables/dimensions'; import dimensions from 'Styles/Variables/dimensions';
import fonts from 'Styles/Variables/fonts'; import fonts from 'Styles/Variables/fonts';
import createAjaxRequest from 'Utilities/createAjaxRequest';
import stripHtml from 'Utilities/String/stripHtml'; import stripHtml from 'Utilities/String/stripHtml';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
import BookIndexOverviewInfo from './BookIndexOverviewInfo'; import BookIndexOverviewInfo from './BookIndexOverviewInfo';
@ -42,10 +43,26 @@ class BookIndexOverview extends Component {
this.state = { this.state = {
isEditAuthorModalOpen: false, isEditAuthorModalOpen: false,
isDeleteAuthorModalOpen: false isDeleteAuthorModalOpen: false,
overview: ''
}; };
} }
componentDidMount() {
const { id } = this.props;
// Note that this component is lazy loaded by the virtualised view.
// We want to avoid storing overviews for *all* books which is
// why it's not put into the redux store
const promise = createAjaxRequest({
url: `/book/${id}/overview`
}).request;
promise.done((data) => {
this.setState({ overview: data.overview });
});
}
// //
// Listeners // Listeners
@ -84,7 +101,6 @@ class BookIndexOverview extends Component {
const { const {
id, id,
title, title,
overview,
monitored, monitored,
titleSlug, titleSlug,
nextAiring, nextAiring,
@ -118,6 +134,7 @@ class BookIndexOverview extends Component {
} = statistics; } = statistics;
const { const {
overview,
isEditAuthorModalOpen, isEditAuthorModalOpen,
isDeleteAuthorModalOpen isDeleteAuthorModalOpen
} = this.state; } = this.state;
@ -267,7 +284,6 @@ class BookIndexOverview extends Component {
BookIndexOverview.propTypes = { BookIndexOverview.propTypes = {
id: PropTypes.number.isRequired, id: PropTypes.number.isRequired,
title: PropTypes.string.isRequired, title: PropTypes.string.isRequired,
overview: PropTypes.string.isRequired,
monitored: PropTypes.bool.isRequired, monitored: PropTypes.bool.isRequired,
titleSlug: PropTypes.string.isRequired, titleSlug: PropTypes.string.isRequired,
nextAiring: PropTypes.string, nextAiring: PropTypes.string,

@ -1,5 +1,8 @@
import { createAction } from 'redux-actions'; import { createAction } from 'redux-actions';
import { batchActions } from 'redux-batched-actions';
import { createThunk, handleThunks } from 'Store/thunks'; import { createThunk, handleThunks } from 'Store/thunks';
import getProviderState from 'Utilities/State/getProviderState';
import { updateItem } from './baseActions';
import createFetchHandler from './Creators/createFetchHandler'; import createFetchHandler from './Creators/createFetchHandler';
import createHandleActions from './Creators/createHandleActions'; import createHandleActions from './Creators/createHandleActions';
import createClearReducer from './Creators/Reducers/createClearReducer'; import createClearReducer from './Creators/Reducers/createClearReducer';
@ -25,18 +28,39 @@ export const defaultState = {
export const FETCH_EDITIONS = 'editions/fetchEditions'; export const FETCH_EDITIONS = 'editions/fetchEditions';
export const CLEAR_EDITIONS = 'editions/clearEditions'; export const CLEAR_EDITIONS = 'editions/clearEditions';
export const SAVE_EDITIONS = 'editions/saveEditions';
// //
// Action Creators // Action Creators
export const fetchEditions = createThunk(FETCH_EDITIONS); export const fetchEditions = createThunk(FETCH_EDITIONS);
export const clearEditions = createAction(CLEAR_EDITIONS); export const clearEditions = createAction(CLEAR_EDITIONS);
export const saveEditions = createThunk(SAVE_EDITIONS);
// //
// Action Handlers // Action Handlers
export const actionHandlers = handleThunks({ export const actionHandlers = handleThunks({
[FETCH_EDITIONS]: createFetchHandler(section, '/edition') [FETCH_EDITIONS]: createFetchHandler(section, '/edition'),
[SAVE_EDITIONS]: function(getState, payload, dispatch) {
const {
id,
...otherPayload
} = payload;
const saveData = getProviderState({ id, ...otherPayload }, getState, 'books');
dispatch(batchActions([
...saveData.editions.map((edition) => {
return updateItem({
id: edition.id,
section: 'editions',
...edition
});
})
]));
}
}); });
// //

@ -0,0 +1,15 @@
import { createSelector } from 'reselect';
import createBookSelector from './createBookSelector';
function createBookAuthorSelector() {
return createSelector(
createBookSelector(),
(state) => state.authors.itemMap,
(state) => state.authors.items,
(book, authorMap, allAuthors) => {
return allAuthors[authorMap[book.authorId]];
}
);
}
export default createBookAuthorSelector;

@ -1,18 +1,16 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import createBookSelector from './createBookSelector'; import createBookAuthorSelector from './createBookAuthorSelector';
function createBookQualityProfileSelector() { function createBookQualityProfileSelector() {
return createSelector( return createSelector(
(state) => state.settings.qualityProfiles.items, (state) => state.settings.qualityProfiles.items,
createBookSelector(), createBookAuthorSelector(),
(qualityProfiles, book) => { (qualityProfiles, author) => {
if (!book) { if (!author) {
return {}; return {};
} }
return qualityProfiles.find((profile) => { return qualityProfiles.find((profile) => profile.id === author.qualityProfileId);
return profile.id === book.author.qualityProfileId;
});
} }
); );
} }

@ -439,7 +439,7 @@ namespace NzbDrone.Core.MetadataSource.BookInfo
var edition = book.Editions.Value.SingleOrDefault(e => e.ForeignEditionId == id.ToString()); var edition = book.Editions.Value.SingleOrDefault(e => e.ForeignEditionId == id.ToString());
trimmed.Editions = new List<Edition> { edition }; trimmed.Editions = new List<Edition> { edition };
return trimmed; book = trimmed;
} }
var authorDict = authors.ToDictionary(x => x.ForeignAuthorId); var authorDict = authors.ToDictionary(x => x.ForeignAuthorId);

@ -52,12 +52,23 @@ namespace NzbDrone.Integration.Test.ApiTests
{ {
EnsureAuthor("14586394", "43765115", "Andrew Hunter Murray", true); EnsureAuthor("14586394", "43765115", "Andrew Hunter Murray", true);
var result = WantedMissing.GetPaged(0, 15, "releaseDate", "desc"); var result = WantedMissing.GetPagedIncludeAuthor(0, 15, "releaseDate", "desc", includeAuthor: true);
result.Records.First().Author.Should().NotBeNull(); result.Records.First().Author.Should().NotBeNull();
result.Records.First().Author.AuthorName.Should().Be("Andrew Hunter Murray"); result.Records.First().Author.AuthorName.Should().Be("Andrew Hunter Murray");
} }
[Test]
[Order(1)]
public void missing_should_not_have_author()
{
EnsureAuthor("14586394", "43765115", "Andrew Hunter Murray", true);
var result = WantedMissing.GetPagedIncludeAuthor(0, 15, "releaseDate", "desc", includeAuthor: false);
result.Records.First().Author.Should().BeNull();
}
[Test] [Test]
[Order(2)] [Order(2)]
public void cutoff_should_have_monitored_items() public void cutoff_should_have_monitored_items()
@ -103,12 +114,25 @@ namespace NzbDrone.Integration.Test.ApiTests
var author = EnsureAuthor("14586394", "43765115", "Andrew Hunter Murray", true); var author = EnsureAuthor("14586394", "43765115", "Andrew Hunter Murray", true);
EnsureBookFile(author, 1, "43765115", Quality.MOBI); EnsureBookFile(author, 1, "43765115", Quality.MOBI);
var result = WantedCutoffUnmet.GetPaged(0, 15, "releaseDate", "desc"); var result = WantedCutoffUnmet.GetPagedIncludeAuthor(0, 15, "releaseDate", "desc", includeAuthor: true);
result.Records.First().Author.Should().NotBeNull(); result.Records.First().Author.Should().NotBeNull();
result.Records.First().Author.AuthorName.Should().Be("Andrew Hunter Murray"); result.Records.First().Author.AuthorName.Should().Be("Andrew Hunter Murray");
} }
[Test]
[Order(2)]
public void cutoff_should_not_have_author()
{
EnsureProfileCutoff(1, Quality.AZW3);
var author = EnsureAuthor("14586394", "43765115", "Andrew Hunter Murray", true);
EnsureBookFile(author, 1, "43765115", Quality.MOBI);
var result = WantedCutoffUnmet.GetPagedIncludeAuthor(0, 15, "releaseDate", "desc", includeAuthor: false);
result.Records.First().Author.Should().BeNull();
}
[Test] [Test]
[Order(1)] [Order(1)]
public void missing_should_have_unmonitored_items() public void missing_should_have_unmonitored_items()

@ -0,0 +1,40 @@
using System.Collections.Generic;
using Readarr.Api.V1.Books;
using Readarr.Http;
using RestSharp;
namespace NzbDrone.Integration.Test.Client
{
public class WantedClient : ClientBase<BookResource>
{
public WantedClient(IRestClient restClient, string apiKey, string resource)
: base(restClient, apiKey, resource)
{
}
public PagingResource<BookResource> GetPagedIncludeAuthor(int pageNumber, int pageSize, string sortKey, string sortDir, string filterKey = null, string filterValue = null, bool includeAuthor = true)
{
var request = BuildRequest();
request.AddParameter("page", pageNumber);
request.AddParameter("pageSize", pageSize);
request.AddParameter("sortKey", sortKey);
request.AddParameter("sortDir", sortDir);
if (filterKey != null && filterValue != null)
{
request.AddParameter("filterKey", filterKey);
request.AddParameter("filterValue", filterValue);
}
request.AddParameter("includeAuthor", includeAuthor);
return Get<PagingResource<BookResource>>(request);
}
public List<BookResource> GetBooksInAuthor(int authorId)
{
var request = BuildRequest("?authorId=" + authorId.ToString());
return Get<List<BookResource>>(request);
}
}
}

@ -53,8 +53,8 @@ namespace NzbDrone.Integration.Test
public ClientBase<RootFolderResource> RootFolders; public ClientBase<RootFolderResource> RootFolders;
public AuthorClient Author; public AuthorClient Author;
public ClientBase<TagResource> Tags; public ClientBase<TagResource> Tags;
public ClientBase<BookResource> WantedMissing; public WantedClient WantedMissing;
public ClientBase<BookResource> WantedCutoffUnmet; public WantedClient WantedCutoffUnmet;
private List<SignalRMessage> _signalRReceived; private List<SignalRMessage> _signalRReceived;
@ -118,8 +118,8 @@ namespace NzbDrone.Integration.Test
RootFolders = new ClientBase<RootFolderResource>(RestClient, ApiKey); RootFolders = new ClientBase<RootFolderResource>(RestClient, ApiKey);
Author = new AuthorClient(RestClient, ApiKey); Author = new AuthorClient(RestClient, ApiKey);
Tags = new ClientBase<TagResource>(RestClient, ApiKey); Tags = new ClientBase<TagResource>(RestClient, ApiKey);
WantedMissing = new ClientBase<BookResource>(RestClient, ApiKey, "wanted/missing"); WantedMissing = new WantedClient(RestClient, ApiKey, "wanted/missing");
WantedCutoffUnmet = new ClientBase<BookResource>(RestClient, ApiKey, "wanted/cutoff"); WantedCutoffUnmet = new WantedClient(RestClient, ApiKey, "wanted/cutoff");
} }
[OneTimeTearDown] [OneTimeTearDown]

@ -138,6 +138,17 @@ namespace Readarr.Api.V1.Books
return MapToResource(_bookService.GetBooks(bookIds), false); return MapToResource(_bookService.GetBooks(bookIds), false);
} }
[HttpGet("{id:int}/overview")]
public object Overview(int id)
{
var overview = _editionService.GetEditionsByBook(id).Single(x => x.Monitored).Overview;
return new
{
id,
overview
};
}
[RestPostById] [RestPostById]
public ActionResult<BookResource> AddBook(BookResource bookResource) public ActionResult<BookResource> AddBook(BookResource bookResource)
{ {

@ -72,13 +72,10 @@ namespace Readarr.Api.V1.Books
AuthorTitle = authorTitle, AuthorTitle = authorTitle,
SeriesTitle = seriesTitle, SeriesTitle = seriesTitle,
Disambiguation = selectedEdition?.Disambiguation, Disambiguation = selectedEdition?.Disambiguation,
Overview = selectedEdition?.Overview,
Images = selectedEdition?.Images ?? new List<MediaCover>(), Images = selectedEdition?.Images ?? new List<MediaCover>(),
Links = model.Links.Concat(selectedEdition?.Links ?? new List<Links>()).ToList(), Links = model.Links.Concat(selectedEdition?.Links ?? new List<Links>()).ToList(),
Ratings = selectedEdition?.Ratings ?? new Ratings(), Ratings = selectedEdition?.Ratings ?? new Ratings(),
Added = model.Added, Added = model.Added,
Author = model.Author?.Value.ToResource(),
Editions = model.Editions?.Value.ToResource() ?? new List<EditionResource>()
}; };
} }

@ -51,6 +51,9 @@ namespace Readarr.Api.V1.Search
{ {
var book = (NzbDrone.Core.Books.Book)result; var book = (NzbDrone.Core.Books.Book)result;
resource.Book = book.ToResource(); resource.Book = book.ToResource();
resource.Book.Overview = book.Editions.Value.Single(x => x.Monitored).Overview;
resource.Book.Author = book.Author.Value.ToResource();
resource.Book.Editions = book.Editions.Value.ToResource();
resource.ForeignId = book.ForeignBookId; resource.ForeignId = book.ForeignBookId;
var cover = book.Editions.Value.Single(x => x.Monitored).Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Cover); var cover = book.Editions.Value.Single(x => x.Monitored).Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Cover);

Loading…
Cancel
Save