diff --git a/frontend/src/AddAuthor/AuthorMonitorNewItemsOptionsPopoverContent.js b/frontend/src/AddAuthor/AuthorMonitorNewItemsOptionsPopoverContent.js new file mode 100644 index 000000000..3d632d87a --- /dev/null +++ b/frontend/src/AddAuthor/AuthorMonitorNewItemsOptionsPopoverContent.js @@ -0,0 +1,27 @@ +import React from 'react'; +import DescriptionList from 'Components/DescriptionList/DescriptionList'; +import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem'; +import translate from 'Utilities/String/translate'; + +function AuthorMonitorNewItemsOptionsPopoverContent() { + return ( + + + + + + + + ); +} + +export default AuthorMonitorNewItemsOptionsPopoverContent; diff --git a/frontend/src/AddAuthor/AuthorMonitoringOptionsPopoverContent.js b/frontend/src/AddAuthor/AuthorMonitoringOptionsPopoverContent.js index 4f27c7fc4..b3c9ae5b8 100644 --- a/frontend/src/AddAuthor/AuthorMonitoringOptionsPopoverContent.js +++ b/frontend/src/AddAuthor/AuthorMonitoringOptionsPopoverContent.js @@ -1,46 +1,52 @@ import React from 'react'; +import Alert from 'Components/Alert'; import DescriptionList from 'Components/DescriptionList/DescriptionList'; import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem'; import translate from 'Utilities/String/translate'; function AuthorMonitoringOptionsPopoverContent() { return ( - - - - - - - - - - - - - - - + <> + + This is a one time adjustment to set which books are monitored + + + + + + + + + + + + + + + + + ); } diff --git a/frontend/src/Author/Edit/EditAuthorModalContent.js b/frontend/src/Author/Edit/EditAuthorModalContent.js index 595838f63..f4141382e 100644 --- a/frontend/src/Author/Edit/EditAuthorModalContent.js +++ b/frontend/src/Author/Edit/EditAuthorModalContent.js @@ -1,6 +1,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import AuthorMetadataProfilePopoverContent from 'AddAuthor/AuthorMetadataProfilePopoverContent'; +import AuthorMonitorNewItemsOptionsPopoverContent from 'AddAuthor/AuthorMonitorNewItemsOptionsPopoverContent'; import MoveAuthorModal from 'Author/MoveAuthor/MoveAuthorModal'; import Form from 'Components/Form/Form'; import FormGroup from 'Components/Form/FormGroup'; @@ -73,6 +74,7 @@ class EditAuthorModalContent extends Component { const { monitored, + monitorNewItems, qualityProfileId, metadataProfileId, path, @@ -101,6 +103,31 @@ class EditAuthorModalContent extends Component { /> + + + {translate('MonitorNewItems')} + + } + title={translate('MonitorNewItems')} + body={} + position={tooltipPositions.RIGHT} + /> + + + + + {translate('QualityProfile')} diff --git a/frontend/src/Author/Edit/EditAuthorModalContentConnector.js b/frontend/src/Author/Edit/EditAuthorModalContentConnector.js index efa268d50..103ff8185 100644 --- a/frontend/src/Author/Edit/EditAuthorModalContentConnector.js +++ b/frontend/src/Author/Edit/EditAuthorModalContentConnector.js @@ -39,6 +39,7 @@ function createMapStateToProps() { const authorSettings = _.pick(author, [ 'monitored', + 'monitorNewItems', 'qualityProfileId', 'metadataProfileId', 'path', diff --git a/frontend/src/Author/Editor/AuthorEditorFooter.css b/frontend/src/Author/Editor/AuthorEditorFooter.css index 0d065135c..645d3d9ab 100644 --- a/frontend/src/Author/Editor/AuthorEditorFooter.css +++ b/frontend/src/Author/Editor/AuthorEditorFooter.css @@ -1,11 +1,23 @@ +.footer { + display: flex; + flex-direction: column; + flex-grow: 1; +} + +.dropdownContainer { + display: flex; + flex-wrap: wrap; + margin-bottom: 10px; +} + .inputContainer { + flex: 1; margin-right: 20px; min-width: 150px; } .buttonContainer { display: flex; - justify-content: flex-end; flex-grow: 1; } @@ -24,12 +36,14 @@ composes: button from '~Components/Link/SpinnerButton.css'; margin-right: 10px; + margin-bottom: 10px; height: 35px; } .deleteSelectedButton { composes: button from '~Components/Link/SpinnerButton.css'; + margin-bottom: 10px; margin-left: 50px; height: 35px; } @@ -48,6 +62,10 @@ } @media only screen and (max-width: $breakpointSmall) { + .dropdownContainer { + display: block; + } + .inputContainer { margin-right: 0; } @@ -61,6 +79,7 @@ } .buttons { + display: block; justify-content: space-between; } diff --git a/frontend/src/Author/Editor/AuthorEditorFooter.js b/frontend/src/Author/Editor/AuthorEditorFooter.js index d55730e8e..dd3cf7e53 100644 --- a/frontend/src/Author/Editor/AuthorEditorFooter.js +++ b/frontend/src/Author/Editor/AuthorEditorFooter.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import MoveAuthorModal from 'Author/MoveAuthor/MoveAuthorModal'; import MetadataProfileSelectInputConnector from 'Components/Form/MetadataProfileSelectInputConnector'; +import MonitorNewItemsSelectInput from 'Components/Form/MonitorNewItemsSelectInput'; import QualityProfileSelectInputConnector from 'Components/Form/QualityProfileSelectInputConnector'; import RootFolderSelectInputConnector from 'Components/Form/RootFolderSelectInputConnector'; import SelectInput from 'Components/Form/SelectInput'; @@ -26,6 +27,7 @@ class AuthorEditorFooter extends Component { this.state = { monitored: NO_CHANGE, + monitorNewItems: NO_CHANGE, qualityProfileId: NO_CHANGE, metadataProfileId: NO_CHANGE, rootFolderPath: NO_CHANGE, @@ -46,6 +48,7 @@ class AuthorEditorFooter extends Component { if (prevProps.isSaving && !isSaving && !saveError) { this.setState({ monitored: NO_CHANGE, + monitorNewItems: NO_CHANGE, qualityProfileId: NO_CHANGE, metadataProfileId: NO_CHANGE, rootFolderPath: NO_CHANGE, @@ -145,6 +148,7 @@ class AuthorEditorFooter extends Component { const { monitored, + monitorNewItems, qualityProfileId, metadataProfileId, rootFolderPath, @@ -163,83 +167,99 @@ class AuthorEditorFooter extends Component { return ( -
- - - -
+
+
+
+ + + +
-
- - - -
+
+ + + +
-
- - - -
+
+ + + +
-
- - - -
+
+ + + +
+ +
+ + + +
+
+ +
+
+ -
-
- +
-
-
Set Readarr Tags -
- - Delete - + + Delete + + +
diff --git a/frontend/src/Author/MonitoringOptions/MonitoringOptionsModalContent.js b/frontend/src/Author/MonitoringOptions/MonitoringOptionsModalContent.js index 248ac8347..25dbce0ec 100644 --- a/frontend/src/Author/MonitoringOptions/MonitoringOptionsModalContent.js +++ b/frontend/src/Author/MonitoringOptions/MonitoringOptionsModalContent.js @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; +import Alert from 'Components/Alert'; import Form from 'Components/Form/Form'; import FormGroup from 'Components/Form/FormGroup'; import FormInputGroup from 'Components/Form/FormInputGroup'; @@ -10,7 +11,7 @@ import ModalBody from 'Components/Modal/ModalBody'; import ModalContent from 'Components/Modal/ModalContent'; import ModalFooter from 'Components/Modal/ModalFooter'; import ModalHeader from 'Components/Modal/ModalHeader'; -import { inputTypes } from 'Helpers/Props'; +import { inputTypes, kinds } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; const NO_CHANGE = 'noChange'; @@ -92,6 +93,12 @@ class MonitoringOptionsModalContent extends Component { + +
+ {translate('MonitorBookExistingOnlyWarning')} +
+
+
{translate('Monitoring')} diff --git a/frontend/src/Bookshelf/BookshelfFooter.js b/frontend/src/Bookshelf/BookshelfFooter.js index 7e84dcba5..6a9a046eb 100644 --- a/frontend/src/Bookshelf/BookshelfFooter.js +++ b/frontend/src/Bookshelf/BookshelfFooter.js @@ -1,6 +1,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import MonitorBooksSelectInput from 'Components/Form/MonitorBooksSelectInput'; +import MonitorNewItemsSelectInput from 'Components/Form/MonitorNewItemsSelectInput'; import SelectInput from 'Components/Form/SelectInput'; import SpinnerButton from 'Components/Link/SpinnerButton'; import PageContentFooter from 'Components/Page/PageContentFooter'; @@ -19,7 +20,8 @@ class BookshelfFooter extends Component { this.state = { monitored: NO_CHANGE, - monitor: NO_CHANGE + monitor: NO_CHANGE, + monitorNewItems: NO_CHANGE }; } @@ -32,7 +34,8 @@ class BookshelfFooter extends Component { if (prevProps.isSaving && !isSaving && !saveError) { this.setState({ monitored: NO_CHANGE, - monitor: NO_CHANGE + monitor: NO_CHANGE, + monitorNewItems: NO_CHANGE }); } } @@ -47,7 +50,8 @@ class BookshelfFooter extends Component { onUpdateSelectedPress = () => { const { monitor, - monitored + monitored, + monitorNewItems } = this.state; const changes = {}; @@ -60,6 +64,10 @@ class BookshelfFooter extends Component { changes.monitor = monitor; } + if (monitorNewItems !== NO_CHANGE) { + changes.monitorNewItems = monitorNewItems; + } + this.props.onUpdateSelectedPress(changes); } @@ -74,7 +82,8 @@ class BookshelfFooter extends Component { const { monitored, - monitor + monitor, + monitorNewItems } = this.state; const monitoredOptions = [ @@ -83,7 +92,9 @@ class BookshelfFooter extends Component { { key: 'unmonitored', value: 'Unmonitored' } ]; - const noChanges = monitored === NO_CHANGE && monitor === NO_CHANGE; + const noChanges = monitored === NO_CHANGE && + monitor === NO_CHANGE && + monitorNewItems === NO_CHANGE; return ( @@ -103,7 +114,7 @@ class BookshelfFooter extends Component {
- Monitor Books + Monitor Existing Books
+
+
+ Monitor New Books +
+ + +
+
{selectedCount} Author(s) Selected diff --git a/frontend/src/Components/Form/FormInputGroup.js b/frontend/src/Components/Form/FormInputGroup.js index ef2729bc0..01b004b45 100644 --- a/frontend/src/Components/Form/FormInputGroup.js +++ b/frontend/src/Components/Form/FormInputGroup.js @@ -16,6 +16,7 @@ import IndexerSelectInputConnector from './IndexerSelectInputConnector'; import KeyValueListInput from './KeyValueListInput'; import MetadataProfileSelectInputConnector from './MetadataProfileSelectInputConnector'; import MonitorBooksSelectInput from './MonitorBooksSelectInput'; +import MonitorNewItemsSelectInput from './MonitorNewItemsSelectInput'; import NumberInput from './NumberInput'; import OAuthInputConnector from './OAuthInputConnector'; import PasswordInput from './PasswordInput'; @@ -51,6 +52,9 @@ function getComponent(type) { case inputTypes.MONITOR_BOOKS_SELECT: return MonitorBooksSelectInput; + case inputTypes.MONITOR_NEW_ITEMS_SELECT: + return MonitorNewItemsSelectInput; + case inputTypes.NUMBER: return NumberInput; diff --git a/frontend/src/Components/Form/MonitorNewItemsSelectInput.js b/frontend/src/Components/Form/MonitorNewItemsSelectInput.js new file mode 100644 index 000000000..6069b5511 --- /dev/null +++ b/frontend/src/Components/Form/MonitorNewItemsSelectInput.js @@ -0,0 +1,50 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import monitorNewItemsOptions from 'Utilities/Author/monitorNewItemsOptions'; +import SelectInput from './SelectInput'; + +function MonitorNewItemsSelectInput(props) { + const { + includeNoChange, + includeMixed, + ...otherProps + } = props; + + const values = [...monitorNewItemsOptions]; + + if (includeNoChange) { + values.unshift({ + key: 'noChange', + value: 'No Change', + disabled: true + }); + } + + if (includeMixed) { + values.unshift({ + key: 'mixed', + value: '(Mixed)', + disabled: true + }); + } + + return ( + + ); +} + +MonitorNewItemsSelectInput.propTypes = { + includeNoChange: PropTypes.bool.isRequired, + includeMixed: PropTypes.bool.isRequired, + onChange: PropTypes.func.isRequired +}; + +MonitorNewItemsSelectInput.defaultProps = { + includeNoChange: false, + includeMixed: false +}; + +export default MonitorNewItemsSelectInput; diff --git a/frontend/src/Helpers/Props/inputTypes.js b/frontend/src/Helpers/Props/inputTypes.js index 6fe18d0b8..887535664 100644 --- a/frontend/src/Helpers/Props/inputTypes.js +++ b/frontend/src/Helpers/Props/inputTypes.js @@ -5,6 +5,7 @@ export const DEVICE = 'device'; export const BOOKSHELF = 'bookshelf'; export const KEY_VALUE_LIST = 'keyValueList'; export const MONITOR_BOOKS_SELECT = 'monitorBooksSelect'; +export const MONITOR_NEW_ITEMS_SELECT = 'monitorNewItemsSelect'; export const NUMBER = 'number'; export const OAUTH = 'oauth'; export const PASSWORD = 'password'; @@ -29,6 +30,7 @@ export const all = [ BOOKSHELF, KEY_VALUE_LIST, MONITOR_BOOKS_SELECT, + MONITOR_NEW_ITEMS_SELECT, NUMBER, OAUTH, PASSWORD, diff --git a/frontend/src/Search/Author/AddNewAuthorModalContentConnector.js b/frontend/src/Search/Author/AddNewAuthorModalContentConnector.js index 51ce83bd0..60886520b 100644 --- a/frontend/src/Search/Author/AddNewAuthorModalContentConnector.js +++ b/frontend/src/Search/Author/AddNewAuthorModalContentConnector.js @@ -57,6 +57,7 @@ class AddNewAuthorModalContentConnector extends Component { foreignAuthorId, rootFolderPath, monitor, + monitorNewItems, qualityProfileId, metadataProfileId, tags @@ -66,6 +67,7 @@ class AddNewAuthorModalContentConnector extends Component { foreignAuthorId, rootFolderPath: rootFolderPath.value, monitor: monitor.value, + monitorNewItems: monitorNewItems.value, qualityProfileId: qualityProfileId.value, metadataProfileId: metadataProfileId.value, tags: tags.value, @@ -91,6 +93,7 @@ AddNewAuthorModalContentConnector.propTypes = { foreignAuthorId: PropTypes.string.isRequired, rootFolderPath: PropTypes.object, monitor: PropTypes.object.isRequired, + monitorNewItems: PropTypes.object.isRequired, qualityProfileId: PropTypes.object, metadataProfileId: PropTypes.object, tags: PropTypes.object.isRequired, diff --git a/frontend/src/Search/Book/AddNewBookModalContentConnector.js b/frontend/src/Search/Book/AddNewBookModalContentConnector.js index a095eed0e..c39f55ce0 100644 --- a/frontend/src/Search/Book/AddNewBookModalContentConnector.js +++ b/frontend/src/Search/Book/AddNewBookModalContentConnector.js @@ -58,6 +58,7 @@ class AddNewBookModalContentConnector extends Component { foreignBookId, rootFolderPath, monitor, + monitorNewItems, qualityProfileId, metadataProfileId, tags @@ -67,6 +68,7 @@ class AddNewBookModalContentConnector extends Component { foreignBookId, rootFolderPath: rootFolderPath.value, monitor: monitor.value, + monitorNewItems: monitorNewItems.value, qualityProfileId: qualityProfileId.value, metadataProfileId: metadataProfileId.value, tags: tags.value, @@ -93,6 +95,7 @@ AddNewBookModalContentConnector.propTypes = { foreignBookId: PropTypes.string.isRequired, rootFolderPath: PropTypes.object, monitor: PropTypes.object.isRequired, + monitorNewItems: PropTypes.object.isRequired, qualityProfileId: PropTypes.object, metadataProfileId: PropTypes.object, tags: PropTypes.object.isRequired, diff --git a/frontend/src/Search/Common/AddAuthorOptionsForm.js b/frontend/src/Search/Common/AddAuthorOptionsForm.js index 7b2ab4c17..e97b2fa0d 100644 --- a/frontend/src/Search/Common/AddAuthorOptionsForm.js +++ b/frontend/src/Search/Common/AddAuthorOptionsForm.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import AuthorMetadataProfilePopoverContent from 'AddAuthor/AuthorMetadataProfilePopoverContent'; import AuthorMonitoringOptionsPopoverContent from 'AddAuthor/AuthorMonitoringOptionsPopoverContent'; +import AuthorMonitorNewItemsOptionsPopoverContent from 'AddAuthor/AuthorMonitorNewItemsOptionsPopoverContent'; import Form from 'Components/Form/Form'; import FormGroup from 'Components/Form/FormGroup'; import FormInputGroup from 'Components/Form/FormInputGroup'; @@ -32,6 +33,7 @@ class AddAuthorOptionsForm extends Component { const { rootFolderPath, monitor, + monitorNewItems, qualityProfileId, metadataProfileId, includeNoneMetadataProfile, @@ -77,12 +79,38 @@ class AddAuthorOptionsForm extends Component { + + + {translate('MonitorNewItems')} + + } + title={translate('MonitorNewItems')} + body={} + position={tooltipPositions.RIGHT} + /> + + + + + {translate('QualityProfile')} @@ -145,6 +173,7 @@ class AddAuthorOptionsForm extends Component { AddAuthorOptionsForm.propTypes = { rootFolderPath: PropTypes.object, monitor: PropTypes.object.isRequired, + monitorNewItems: PropTypes.string.isRequired, qualityProfileId: PropTypes.object, metadataProfileId: PropTypes.object, showMetadataProfile: PropTypes.bool.isRequired, diff --git a/frontend/src/Settings/ImportLists/ImportLists/EditImportListModalContent.js b/frontend/src/Settings/ImportLists/ImportLists/EditImportListModalContent.js index 916999bda..9ff064e25 100644 --- a/frontend/src/Settings/ImportLists/ImportLists/EditImportListModalContent.js +++ b/frontend/src/Settings/ImportLists/ImportLists/EditImportListModalContent.js @@ -1,8 +1,10 @@ import PropTypes from 'prop-types'; import React from 'react'; +import AuthorMonitorNewItemsOptionsPopoverContent from 'AddAuthor/AuthorMonitorNewItemsOptionsPopoverContent'; import Alert from 'Components/Alert'; import DescriptionList from 'Components/DescriptionList/DescriptionList'; import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem'; +import FieldSet from 'Components/FieldSet'; import Form from 'Components/Form/Form'; import FormGroup from 'Components/Form/FormGroup'; import FormInputGroup from 'Components/Form/FormInputGroup'; @@ -76,6 +78,7 @@ function EditImportListModalContent(props) { shouldMonitorExisting, shouldSearch, rootFolderPath, + monitorNewItems, qualityProfileId, metadataProfileId, tags, @@ -114,148 +117,178 @@ function EditImportListModalContent(props) { {message.value.message} } - - - {translate('Name')} - - - - - - - - {translate('EnableAutomaticAdd')} - - - - - - - - Monitor - - - } - title={translate('MonitoringOptions')} - body={} - position={tooltipPositions.RIGHT} + +
+ + + {translate('Name')} + + + + + + + + {translate('EnableAutomaticAdd')} + + + + + + + + Monitor + + + } + title={translate('MonitoringOptions')} + body={} + position={tooltipPositions.RIGHT} + /> + + + + + + + + {translate('ShouldMonitorExisting')} + + + + + + + + {translate('SearchForNewItems')} + + + + +
+ +
+ + + {translate('RootFolder')} + + + + + + + + {translate('MonitorNewItems')} + + } + title={translate('MonitorNewItems')} + body={} + position={tooltipPositions.RIGHT} + /> + + + + + + + + {translate('QualityProfile')} + + + + + + + + {translate('MetadataProfile')} + + + + + + + + {translate('ReadarrTags')} + + + - - - - - - - - {translate('ShouldMonitorExisting')} - - - - - - - - {translate('SearchForNewItems')} - - - - - - - - {translate('RootFolder')} - - - - - - - - {translate('QualityProfile')} - - - - - - - - {translate('MetadataProfile')} - - - - - - - - {translate('ReadarrTags')} - - - - + +
{ !!fields && !!fields.length && -
+
{ fields.map((field) => { return ( @@ -271,7 +304,7 @@ function EditImportListModalContent(props) { ); }) } -
+ } diff --git a/frontend/src/Settings/MediaManagement/RootFolder/EditRootFolderModalContent.js b/frontend/src/Settings/MediaManagement/RootFolder/EditRootFolderModalContent.js index a1e13c534..4d57b9d99 100644 --- a/frontend/src/Settings/MediaManagement/RootFolder/EditRootFolderModalContent.js +++ b/frontend/src/Settings/MediaManagement/RootFolder/EditRootFolderModalContent.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import AuthorMetadataProfilePopoverContent from 'AddAuthor/AuthorMetadataProfilePopoverContent'; import AuthorMonitoringOptionsPopoverContent from 'AddAuthor/AuthorMonitoringOptionsPopoverContent'; +import AuthorMonitorNewItemsOptionsPopoverContent from 'AddAuthor/AuthorMonitorNewItemsOptionsPopoverContent'; import Form from 'Components/Form/Form'; import FormGroup from 'Components/Form/FormGroup'; import FormInputGroup from 'Components/Form/FormInputGroup'; @@ -43,6 +44,7 @@ function EditRootFolderModalContent(props) { defaultQualityProfileId, defaultMetadataProfileId, defaultMonitorOption, + defaultNewItemMonitorOption, defaultTags, isCalibreLibrary, host, @@ -295,7 +297,7 @@ function EditRootFolderModalContent(props) { - Monitor + {translate('Monitor')} + + + {translate('MonitorNewItems')} + + } + title={translate('MonitorNewItems')} + body={} + position={tooltipPositions.RIGHT} + /> + + + + + {translate('QualityProfile')} diff --git a/frontend/src/Store/Actions/bookshelfActions.js b/frontend/src/Store/Actions/bookshelfActions.js index 5e5f4cd08..d62b61c2d 100644 --- a/frontend/src/Store/Actions/bookshelfActions.js +++ b/frontend/src/Store/Actions/bookshelfActions.js @@ -4,7 +4,6 @@ import { createThunk, handleThunks } from 'Store/thunks'; import createAjaxRequest from 'Utilities/createAjaxRequest'; import { filterPredicates, filters } from './authorActions'; import { set } from './baseActions'; -import { fetchBooks } from './bookActions'; import createHandleActions from './Creators/createHandleActions'; import createSetClientSideCollectionFilterReducer from './Creators/Reducers/createSetClientSideCollectionFilterReducer'; import createSetClientSideCollectionSortReducer from './Creators/Reducers/createSetClientSideCollectionSortReducer'; @@ -97,7 +96,8 @@ export const actionHandlers = handleThunks({ const { authorIds, monitored, - monitor + monitor, + monitorNewItems } = payload; const authors = []; @@ -122,14 +122,13 @@ export const actionHandlers = handleThunks({ method: 'POST', data: JSON.stringify({ authors, - monitoringOptions: { monitor } + monitoringOptions: { monitor }, + monitorNewItems }), dataType: 'json' }).request; promise.done((data) => { - dispatch(fetchBooks()); - dispatch(set({ section, isSaving: false, diff --git a/frontend/src/Utilities/Author/getNewAuthor.js b/frontend/src/Utilities/Author/getNewAuthor.js index bea2ca0af..de774474e 100644 --- a/frontend/src/Utilities/Author/getNewAuthor.js +++ b/frontend/src/Utilities/Author/getNewAuthor.js @@ -3,6 +3,7 @@ function getNewAuthor(author, payload) { const { rootFolderPath, monitor, + monitorNewItems, qualityProfileId, metadataProfileId, tags, @@ -16,6 +17,7 @@ function getNewAuthor(author, payload) { author.addOptions = addOptions; author.monitored = true; + author.monitorNewItems = monitorNewItems; author.qualityProfileId = qualityProfileId; author.metadataProfileId = metadataProfileId; author.rootFolderPath = rootFolderPath; diff --git a/frontend/src/Utilities/Author/monitorNewItemsOptions.js b/frontend/src/Utilities/Author/monitorNewItemsOptions.js new file mode 100644 index 000000000..839cd8563 --- /dev/null +++ b/frontend/src/Utilities/Author/monitorNewItemsOptions.js @@ -0,0 +1,7 @@ +const monitorNewItemsOptions = [ + { key: 'all', value: 'All Books' }, + { key: 'none', value: 'None' }, + { key: 'new', value: 'New' } +]; + +export default monitorNewItemsOptions; diff --git a/src/NzbDrone.Core.Test/MusicTests/MonitorNewBookServiceFixture.cs b/src/NzbDrone.Core.Test/MusicTests/MonitorNewBookServiceFixture.cs new file mode 100644 index 000000000..eb6082eab --- /dev/null +++ b/src/NzbDrone.Core.Test/MusicTests/MonitorNewBookServiceFixture.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Books; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.BookTests +{ + [TestFixture] + public class MonitorNewBookServiceFixture : CoreTest + { + private List _books; + + [SetUp] + public void Setup() + { + _books = Builder.CreateListOfSize(4) + .All() + .With(e => e.Monitored = true) + .With(e => e.ReleaseDate = DateTime.UtcNow.AddDays(-7)) + + //Future + .TheFirst(1) + .With(e => e.ReleaseDate = DateTime.UtcNow.AddDays(7)) + + //Future/TBA + .TheNext(1) + .With(e => e.ReleaseDate = null) + .Build() + .ToList(); + } + + [Test] + public void should_monitor_with_all() + { + foreach (var book in _books) + { + Subject.ShouldMonitorNewBook(book, _books, NewItemMonitorTypes.All).Should().BeTrue(); + } + } + + [Test] + public void should_not_monitor_with_none() + { + foreach (var book in _books) + { + Subject.ShouldMonitorNewBook(book, _books, NewItemMonitorTypes.None).Should().BeFalse(); + } + } + + [Test] + public void should_only_monitor_new_with_new() + { + Subject.ShouldMonitorNewBook(_books[0], _books, NewItemMonitorTypes.New).Should().BeTrue(); + + foreach (var book in _books.Skip(1)) + { + Subject.ShouldMonitorNewBook(book, _books, NewItemMonitorTypes.New).Should().BeFalse(); + } + } + } +} diff --git a/src/NzbDrone.Core.Test/MusicTests/RefreshArtistServiceFixture.cs b/src/NzbDrone.Core.Test/MusicTests/RefreshArtistServiceFixture.cs index eedf849cb..474e24a2f 100644 --- a/src/NzbDrone.Core.Test/MusicTests/RefreshArtistServiceFixture.cs +++ b/src/NzbDrone.Core.Test/MusicTests/RefreshArtistServiceFixture.cs @@ -62,7 +62,7 @@ namespace NzbDrone.Core.Test.MusicTests Mocker.GetMock() .Setup(s => s.FilterBooks(It.IsAny(), It.IsAny())) - .Returns(_books); + .Returns(_remoteBooks); Mocker.GetMock() .Setup(s => s.GetAuthorAndBooks(It.IsAny(), It.IsAny())) @@ -83,6 +83,10 @@ namespace NzbDrone.Core.Test.MusicTests Mocker.GetMock() .Setup(x => x.All()) .Returns(new List()); + + Mocker.GetMock() + .Setup(x => x.ShouldMonitorNewBook(It.IsAny(), It.IsAny>(), It.IsAny())) + .Returns(true); } private void GivenNewAuthorInfo(Author author) @@ -151,6 +155,29 @@ namespace NzbDrone.Core.Test.MusicTests VerifyEventPublished(); } + [Test] + public void should_call_new_book_monitor_service_when_adding_book() + { + var newBook = Builder.CreateNew() + .With(x => x.Id = 0) + .With(x => x.ForeignBookId = "3") + .Build(); + _remoteBooks.Add(newBook); + + var newAuthorInfo = _author.JsonClone(); + newAuthorInfo.Metadata = _author.Metadata.Value.JsonClone(); + newAuthorInfo.Books = _remoteBooks; + + GivenNewAuthorInfo(newAuthorInfo); + GivenBooksForRefresh(_books); + AllowAuthorUpdate(); + + Subject.Execute(new RefreshAuthorCommand(_author.Id)); + + Mocker.GetMock() + .Verify(x => x.ShouldMonitorNewBook(newBook, _books, _author.MonitorNewItems), Times.Once()); + } + [Test] public void should_log_error_and_delete_if_musicbrainz_id_not_found_and_author_has_no_files() { diff --git a/src/NzbDrone.Core/Books/Model/Author.cs b/src/NzbDrone.Core/Books/Model/Author.cs index c14d70d9d..9a5364e57 100644 --- a/src/NzbDrone.Core/Books/Model/Author.cs +++ b/src/NzbDrone.Core/Books/Model/Author.cs @@ -20,6 +20,7 @@ namespace NzbDrone.Core.Books public int AuthorMetadataId { get; set; } public string CleanName { get; set; } public bool Monitored { get; set; } + public NewItemMonitorTypes MonitorNewItems { get; set; } public DateTime? LastInfoSync { get; set; } public string Path { get; set; } public string RootFolderPath { get; set; } @@ -70,6 +71,7 @@ namespace NzbDrone.Core.Books Id = other.Id; AuthorMetadataId = other.AuthorMetadataId; Monitored = other.Monitored; + MonitorNewItems = other.MonitorNewItems; LastInfoSync = other.LastInfoSync; Path = other.Path; RootFolderPath = other.RootFolderPath; @@ -93,6 +95,7 @@ namespace NzbDrone.Core.Books AddOptions = other.AddOptions; RootFolderPath = other.RootFolderPath; Monitored = other.Monitored; + MonitorNewItems = other.MonitorNewItems; } } } diff --git a/src/NzbDrone.Core/Books/Model/MonitorTypes.cs b/src/NzbDrone.Core/Books/Model/MonitorTypes.cs new file mode 100644 index 000000000..1eee71579 --- /dev/null +++ b/src/NzbDrone.Core/Books/Model/MonitorTypes.cs @@ -0,0 +1,14 @@ +namespace NzbDrone.Core.Books +{ + public enum MonitorTypes + { + All, + Future, + Missing, + Existing, + Latest, + First, + None, + Unknown + } +} diff --git a/src/NzbDrone.Core/Books/Model/MonitoringOptions.cs b/src/NzbDrone.Core/Books/Model/MonitoringOptions.cs index c97d4e4a4..fd824c37f 100644 --- a/src/NzbDrone.Core/Books/Model/MonitoringOptions.cs +++ b/src/NzbDrone.Core/Books/Model/MonitoringOptions.cs @@ -14,16 +14,4 @@ namespace NzbDrone.Core.Books public List BooksToMonitor { get; set; } public bool Monitored { get; set; } } - - public enum MonitorTypes - { - All, - Future, - Missing, - Existing, - Latest, - First, - None, - Unknown - } } diff --git a/src/NzbDrone.Core/Books/Model/NewItemMonitorTypes.cs b/src/NzbDrone.Core/Books/Model/NewItemMonitorTypes.cs new file mode 100644 index 000000000..a93a012f3 --- /dev/null +++ b/src/NzbDrone.Core/Books/Model/NewItemMonitorTypes.cs @@ -0,0 +1,9 @@ +namespace NzbDrone.Core.Books +{ + public enum NewItemMonitorTypes + { + All, + None, + New + } +} diff --git a/src/NzbDrone.Core/Books/Services/MonitorNewBookService.cs b/src/NzbDrone.Core/Books/Services/MonitorNewBookService.cs new file mode 100644 index 000000000..2e1325a78 --- /dev/null +++ b/src/NzbDrone.Core/Books/Services/MonitorNewBookService.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NLog; + +namespace NzbDrone.Core.Books +{ + public interface IMonitorNewBookService + { + bool ShouldMonitorNewBook(Book addedBook, List existingBooks, NewItemMonitorTypes author); + } + + public class MonitorNewBookService : IMonitorNewBookService + { + private readonly Logger _logger; + + public MonitorNewBookService(Logger logger) + { + _logger = logger; + } + + public bool ShouldMonitorNewBook(Book addedBook, List existingBooks, NewItemMonitorTypes monitorNewItems) + { + if (monitorNewItems == NewItemMonitorTypes.None) + { + return false; + } + + if (monitorNewItems == NewItemMonitorTypes.All) + { + return true; + } + + if (monitorNewItems == NewItemMonitorTypes.New) + { + var newest = existingBooks.OrderByDescending(x => x.ReleaseDate ?? DateTime.MinValue).FirstOrDefault()?.ReleaseDate ?? DateTime.MinValue; + + return (addedBook.ReleaseDate ?? DateTime.MinValue) >= newest; + } + + throw new NotImplementedException($"Unknown new item monitor type {monitorNewItems}"); + } + } +} diff --git a/src/NzbDrone.Core/Books/Services/RefreshAuthorService.cs b/src/NzbDrone.Core/Books/Services/RefreshAuthorService.cs index 135d05308..85d284634 100644 --- a/src/NzbDrone.Core/Books/Services/RefreshAuthorService.cs +++ b/src/NzbDrone.Core/Books/Services/RefreshAuthorService.cs @@ -42,6 +42,7 @@ namespace NzbDrone.Core.Books private readonly IHistoryService _historyService; private readonly IRootFolderService _rootFolderService; private readonly ICheckIfAuthorShouldBeRefreshed _checkIfAuthorShouldBeRefreshed; + private readonly IMonitorNewBookService _monitorNewBookService; private readonly IConfigService _configService; private readonly IImportListExclusionService _importListExclusionService; private readonly Logger _logger; @@ -59,6 +60,7 @@ namespace NzbDrone.Core.Books IHistoryService historyService, IRootFolderService rootFolderService, ICheckIfAuthorShouldBeRefreshed checkIfAuthorShouldBeRefreshed, + IMonitorNewBookService monitorNewBookService, IConfigService configService, IImportListExclusionService importListExclusionService, Logger logger) @@ -76,6 +78,7 @@ namespace NzbDrone.Core.Books _historyService = historyService; _rootFolderService = rootFolderService; _checkIfAuthorShouldBeRefreshed = checkIfAuthorShouldBeRefreshed; + _monitorNewBookService = monitorNewBookService; _configService = configService; _importListExclusionService = importListExclusionService; _logger = logger; @@ -264,6 +267,14 @@ namespace NzbDrone.Core.Books remote.UseDbFieldsFrom(local); } + protected override void ProcessChildren(Author entity, SortedChildren children) + { + foreach (var book in children.Added) + { + book.Monitored = _monitorNewBookService.ShouldMonitorNewBook(book, children.UpToDate, entity.MonitorNewItems); + } + } + protected override void AddChildren(List children) { _bookService.InsertMany(children); diff --git a/src/NzbDrone.Core/Books/Services/RefreshEntityServiceBase.cs b/src/NzbDrone.Core/Books/Services/RefreshEntityServiceBase.cs index a5d4e199e..3405f5237 100644 --- a/src/NzbDrone.Core/Books/Services/RefreshEntityServiceBase.cs +++ b/src/NzbDrone.Core/Books/Services/RefreshEntityServiceBase.cs @@ -93,6 +93,11 @@ namespace NzbDrone.Core.Books protected abstract void PrepareNewChild(TChild child, TEntity entity); protected abstract void PrepareExistingChild(TChild local, TChild remote, TEntity entity); + + protected virtual void ProcessChildren(TEntity entity, SortedChildren children) + { + } + protected abstract void AddChildren(List children); protected abstract bool RefreshChildren(SortedChildren localChildren, List remoteChildren, Author remoteData, bool forceChildRefresh, bool forceUpdateFileTags, DateTime? lastUpdate); @@ -277,6 +282,8 @@ namespace NzbDrone.Core.Books sortedChildren.Deleted.Count); } + ProcessChildren(entity, sortedChildren); + // Add in the new children (we have checked that foreign IDs don't clash) AddChildren(sortedChildren.Added); diff --git a/src/NzbDrone.Core/Datastore/Migration/019_add_new_item_monitor_type.cs b/src/NzbDrone.Core/Datastore/Migration/019_add_new_item_monitor_type.cs new file mode 100644 index 000000000..7c9a6bc79 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/019_add_new_item_monitor_type.cs @@ -0,0 +1,16 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(19)] + public class AddNewItemMonitorType : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Alter.Table("Authors").AddColumn("MonitorNewItems").AsInt32().WithDefaultValue(0); + Alter.Table("RootFolders").AddColumn("DefaultNewItemMonitorOption").AsInt32().WithDefaultValue(0); + Alter.Table("ImportLists").AddColumn("MonitorNewItems").AsInt32().WithDefaultValue(0); + } + } +} diff --git a/src/NzbDrone.Core/ImportLists/ImportListDefinition.cs b/src/NzbDrone.Core/ImportLists/ImportListDefinition.cs index 849b5200b..9f83c9560 100644 --- a/src/NzbDrone.Core/ImportLists/ImportListDefinition.cs +++ b/src/NzbDrone.Core/ImportLists/ImportListDefinition.cs @@ -1,3 +1,4 @@ +using NzbDrone.Core.Books; using NzbDrone.Core.ThingiProvider; namespace NzbDrone.Core.ImportLists @@ -8,6 +9,7 @@ namespace NzbDrone.Core.ImportLists public ImportListMonitorType ShouldMonitor { get; set; } public bool ShouldMonitorExisting { get; set; } public bool ShouldSearch { get; set; } + public NewItemMonitorTypes MonitorNewItems { get; set; } public int ProfileId { get; set; } public int MetadataProfileId { get; set; } public string RootFolderPath { get; set; } diff --git a/src/NzbDrone.Core/ImportLists/ImportListSyncService.cs b/src/NzbDrone.Core/ImportLists/ImportListSyncService.cs index f6dfbdf0c..2c7faae5d 100644 --- a/src/NzbDrone.Core/ImportLists/ImportListSyncService.cs +++ b/src/NzbDrone.Core/ImportLists/ImportListSyncService.cs @@ -227,6 +227,7 @@ namespace NzbDrone.Core.ImportLists var toAddAuthor = new Author { Monitored = monitored, + MonitorNewItems = importList.MonitorNewItems, RootFolderPath = importList.RootFolderPath, QualityProfileId = importList.ProfileId, MetadataProfileId = importList.MetadataProfileId, diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 235d254b6..3e7b6df61 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -5,6 +5,7 @@ "About": "About", "Absolute": "Absolute", "Actions": "Actions", + "AddedAuthorSettings": "Added Author Settings", "AddImportListExclusionHelpText": "Prevent book from being added to Readarr by Import Lists or Author Refresh", "AddingTag": "Adding tag", "AddListExclusion": "Add List Exclusion", @@ -140,7 +141,7 @@ "Dates": "Dates", "DBMigration": "DB Migration", "DefaultMetadataProfileIdHelpText": "Default Metadata Profile for authors detected in this folder", - "DefaultMonitorOptionHelpText": "Default Monitoring Options for books by authors detected in this folder", + "DefaultMonitorOptionHelpText": "Which books should be monitored on initial add for authors detected in this folder", "DefaultQualityProfileIdHelpText": "Default Quality Profile for authors detected in this folder", "DefaultReadarrTags": "Default Readarr Tags", "DefaultTagsHelpText": "Default Readarr Tags for authors detected in this folder", @@ -291,7 +292,8 @@ "Importing": "Importing", "ImportListExclusions": "Import List Exclusions", "ImportLists": "Import Lists", - "ImportListSettings": "Import List Settings", + "ImportListSettings": "General Import List Settings", + "ImportListSpecificSettings": "Import List Specific Settings", "IncludeHealthWarningsHelpText": "Include Health Warnings", "IncludePreferredWhenRenaming": "Include Preferred when Renaming", "IncludeUnknownAuthorItemsHelpText": "Show items without a author in the queue, this could include removed authors, movies or anything else in Readarr's category", @@ -381,12 +383,16 @@ "Mode": "Mode", "MonitorAuthor": "Monitor Author", "MonitorBook": "Monitor Book", + "MonitorBookExistingOnlyWarning": "This is a one off adjustment of the monitored setting for each book. Use the option under Author/Edit to control what happens for newly added books", "Monitored": "Monitored", "MonitoredAuthorIsMonitored": "Author is monitored", "MonitoredAuthorIsUnmonitored": "Author is unmonitored", "MonitoredHelpText": "Readarr will search for and download book", "Monitoring": "Monitoring", "MonitoringOptions": "Monitoring Options", + "MonitoringOptionsHelpText": "Which books should be monitored after the author is added (one-time adjustment)", + "MonitorNewItems": "Monitor New Books", + "MonitorNewItemsHelpText": "Which new books should be monitored", "MonoVersion": "Mono Version", "MoreInfo": "More Info", "MusicBrainzAuthorID": "MusicBrainz Author ID", @@ -404,6 +410,7 @@ "NamingSettings": "Naming Settings", "NETCore": ".NET Core", "New": "New", + "NewBooks": "New Books", "NoBackupsAreAvailable": "No backups are available", "NoHistory": "No history.", "NoHistoryBlocklist": "No history blocklist", diff --git a/src/NzbDrone.Core/MediaFiles/BookImport/ImportApprovedBooks.cs b/src/NzbDrone.Core/MediaFiles/BookImport/ImportApprovedBooks.cs index f00bf134f..8a91c95bf 100644 --- a/src/NzbDrone.Core/MediaFiles/BookImport/ImportApprovedBooks.cs +++ b/src/NzbDrone.Core/MediaFiles/BookImport/ImportApprovedBooks.cs @@ -328,6 +328,7 @@ namespace NzbDrone.Core.MediaFiles.BookImport author.MetadataProfileId = rootFolder.DefaultMetadataProfileId; author.QualityProfileId = rootFolder.DefaultQualityProfileId; author.Monitored = rootFolder.DefaultMonitorOption != MonitorTypes.None; + author.MonitorNewItems = rootFolder.DefaultNewItemMonitorOption; author.Tags = rootFolder.DefaultTags; author.AddOptions = new AddAuthorOptions { diff --git a/src/NzbDrone.Core/RootFolders/RootFolder.cs b/src/NzbDrone.Core/RootFolders/RootFolder.cs index cdc8c7947..d41930671 100644 --- a/src/NzbDrone.Core/RootFolders/RootFolder.cs +++ b/src/NzbDrone.Core/RootFolders/RootFolder.cs @@ -12,6 +12,7 @@ namespace NzbDrone.Core.RootFolders public int DefaultMetadataProfileId { get; set; } public int DefaultQualityProfileId { get; set; } public MonitorTypes DefaultMonitorOption { get; set; } + public NewItemMonitorTypes DefaultNewItemMonitorOption { get; set; } public HashSet DefaultTags { get; set; } public bool IsCalibreLibrary { get; set; } public CalibreSettings CalibreSettings { get; set; } diff --git a/src/Readarr.Api.V1/Author/AuthorController.cs b/src/Readarr.Api.V1/Author/AuthorController.cs index 55ca08bcd..5eaa6e98f 100644 --- a/src/Readarr.Api.V1/Author/AuthorController.cs +++ b/src/Readarr.Api.V1/Author/AuthorController.cs @@ -18,7 +18,6 @@ using NzbDrone.Core.Validation; using NzbDrone.Core.Validation.Paths; using NzbDrone.Http.REST.Attributes; using NzbDrone.SignalR; -using Readarr.Api.V1.Books; using Readarr.Http; using Readarr.Http.Extensions; using Readarr.Http.REST; diff --git a/src/Readarr.Api.V1/Author/AuthorEditorController.cs b/src/Readarr.Api.V1/Author/AuthorEditorController.cs index febaf64ad..84dab433a 100644 --- a/src/Readarr.Api.V1/Author/AuthorEditorController.cs +++ b/src/Readarr.Api.V1/Author/AuthorEditorController.cs @@ -34,6 +34,11 @@ namespace Readarr.Api.V1.Author author.Monitored = resource.Monitored.Value; } + if (resource.MonitorNewItems.HasValue) + { + author.MonitorNewItems = resource.MonitorNewItems.Value; + } + if (resource.QualityProfileId.HasValue) { author.QualityProfileId = resource.QualityProfileId.Value; diff --git a/src/Readarr.Api.V1/Author/AuthorEditorResource.cs b/src/Readarr.Api.V1/Author/AuthorEditorResource.cs index c599a9714..9834792b4 100644 --- a/src/Readarr.Api.V1/Author/AuthorEditorResource.cs +++ b/src/Readarr.Api.V1/Author/AuthorEditorResource.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using NzbDrone.Core.Books; namespace Readarr.Api.V1.Author { @@ -6,6 +7,7 @@ namespace Readarr.Api.V1.Author { public List AuthorIds { get; set; } public bool? Monitored { get; set; } + public NewItemMonitorTypes? MonitorNewItems { get; set; } public int? QualityProfileId { get; set; } public int? MetadataProfileId { get; set; } public string RootFolderPath { get; set; } diff --git a/src/Readarr.Api.V1/Author/AuthorResource.cs b/src/Readarr.Api.V1/Author/AuthorResource.cs index be4bf0035..f6751b191 100644 --- a/src/Readarr.Api.V1/Author/AuthorResource.cs +++ b/src/Readarr.Api.V1/Author/AuthorResource.cs @@ -5,7 +5,6 @@ using Newtonsoft.Json; using NzbDrone.Common.Extensions; using NzbDrone.Core.Books; using NzbDrone.Core.MediaCover; -using Readarr.Api.V1.Books; using Readarr.Http.REST; namespace Readarr.Api.V1.Author @@ -43,6 +42,7 @@ namespace Readarr.Api.V1.Author //Editing Only public bool Monitored { get; set; } + public NewItemMonitorTypes MonitorNewItems { get; set; } public string RootFolderPath { get; set; } public List Genres { get; set; } @@ -91,6 +91,7 @@ namespace Readarr.Api.V1.Author Links = model.Metadata.Value.Links, Monitored = model.Monitored, + MonitorNewItems = model.MonitorNewItems, CleanName = model.CleanName, ForeignAuthorId = model.Metadata.Value.ForeignAuthorId, @@ -141,6 +142,7 @@ namespace Readarr.Api.V1.Author MetadataProfileId = resource.MetadataProfileId, Monitored = resource.Monitored, + MonitorNewItems = resource.MonitorNewItems, CleanName = resource.CleanName, RootFolderPath = resource.RootFolderPath, diff --git a/src/Readarr.Api.V1/BookShelf/BookshelfController.cs b/src/Readarr.Api.V1/BookShelf/BookshelfController.cs index b38f9b382..9f040190b 100644 --- a/src/Readarr.Api.V1/BookShelf/BookshelfController.cs +++ b/src/Readarr.Api.V1/BookShelf/BookshelfController.cs @@ -18,7 +18,7 @@ namespace Readarr.Api.V1.Bookshelf } [HttpPost] - public ActionResult UpdateAll([FromBody] BookshelfResource request) + public IActionResult UpdateAll([FromBody] BookshelfResource request) { //Read from request var authorToUpdate = _authorService.GetAuthors(request.Authors.Select(s => s.Id)); @@ -37,10 +37,15 @@ namespace Readarr.Api.V1.Bookshelf author.Monitored = false; } + if (request.MonitorNewItems.HasValue) + { + author.MonitorNewItems = request.MonitorNewItems.Value; + } + _bookMonitoredService.SetBookMonitoredStatus(author, request.MonitoringOptions); } - return Accepted(new object()); + return Accepted(request); } } } diff --git a/src/Readarr.Api.V1/BookShelf/BookshelfResource.cs b/src/Readarr.Api.V1/BookShelf/BookshelfResource.cs index 78d46a5e0..c036d9d0d 100644 --- a/src/Readarr.Api.V1/BookShelf/BookshelfResource.cs +++ b/src/Readarr.Api.V1/BookShelf/BookshelfResource.cs @@ -7,5 +7,6 @@ namespace Readarr.Api.V1.Bookshelf { public List Authors { get; set; } public MonitoringOptions MonitoringOptions { get; set; } + public NewItemMonitorTypes? MonitorNewItems { get; set; } } } diff --git a/src/Readarr.Api.V1/ImportLists/ImportListResource.cs b/src/Readarr.Api.V1/ImportLists/ImportListResource.cs index b87a69e52..d7eb46eea 100644 --- a/src/Readarr.Api.V1/ImportLists/ImportListResource.cs +++ b/src/Readarr.Api.V1/ImportLists/ImportListResource.cs @@ -1,3 +1,4 @@ +using NzbDrone.Core.Books; using NzbDrone.Core.ImportLists; namespace Readarr.Api.V1.ImportLists @@ -9,6 +10,7 @@ namespace Readarr.Api.V1.ImportLists public bool ShouldMonitorExisting { get; set; } public bool ShouldSearch { get; set; } public string RootFolderPath { get; set; } + public NewItemMonitorTypes MonitorNewItems { get; set; } public int QualityProfileId { get; set; } public int MetadataProfileId { get; set; } public ImportListType ListType { get; set; } @@ -31,6 +33,7 @@ namespace Readarr.Api.V1.ImportLists resource.ShouldMonitorExisting = definition.ShouldMonitorExisting; resource.ShouldSearch = definition.ShouldSearch; resource.RootFolderPath = definition.RootFolderPath; + resource.MonitorNewItems = definition.MonitorNewItems; resource.QualityProfileId = definition.ProfileId; resource.MetadataProfileId = definition.MetadataProfileId; resource.ListType = definition.ListType; @@ -53,6 +56,7 @@ namespace Readarr.Api.V1.ImportLists definition.ShouldMonitorExisting = resource.ShouldMonitorExisting; definition.ShouldSearch = resource.ShouldSearch; definition.RootFolderPath = resource.RootFolderPath; + definition.MonitorNewItems = resource.MonitorNewItems; definition.ProfileId = resource.QualityProfileId; definition.MetadataProfileId = resource.MetadataProfileId; definition.ListType = resource.ListType; diff --git a/src/Readarr.Api.V1/RootFolders/RootFolderResource.cs b/src/Readarr.Api.V1/RootFolders/RootFolderResource.cs index ad98501ef..0f67813b3 100644 --- a/src/Readarr.Api.V1/RootFolders/RootFolderResource.cs +++ b/src/Readarr.Api.V1/RootFolders/RootFolderResource.cs @@ -15,6 +15,7 @@ namespace Readarr.Api.V1.RootFolders public int DefaultMetadataProfileId { get; set; } public int DefaultQualityProfileId { get; set; } public MonitorTypes DefaultMonitorOption { get; set; } + public NewItemMonitorTypes DefaultNewItemMonitorOption { get; set; } public HashSet DefaultTags { get; set; } public bool IsCalibreLibrary { get; set; } public string Host { get; set; } @@ -50,6 +51,7 @@ namespace Readarr.Api.V1.RootFolders DefaultMetadataProfileId = model.DefaultMetadataProfileId, DefaultQualityProfileId = model.DefaultQualityProfileId, DefaultMonitorOption = model.DefaultMonitorOption, + DefaultNewItemMonitorOption = model.DefaultNewItemMonitorOption, DefaultTags = model.DefaultTags, IsCalibreLibrary = model.IsCalibreLibrary, Host = model.CalibreSettings?.Host, @@ -105,6 +107,7 @@ namespace Readarr.Api.V1.RootFolders DefaultMetadataProfileId = resource.DefaultMetadataProfileId, DefaultQualityProfileId = resource.DefaultQualityProfileId, DefaultMonitorOption = resource.DefaultMonitorOption, + DefaultNewItemMonitorOption = resource.DefaultNewItemMonitorOption, DefaultTags = resource.DefaultTags, IsCalibreLibrary = resource.IsCalibreLibrary, CalibreSettings = cs