{selectedCount} Artist(s) Selected
diff --git a/frontend/src/Artist/Edit/EditArtistModalContent.js b/frontend/src/Artist/Edit/EditArtistModalContent.js
index 8cd311269..7205ee032 100644
--- a/frontend/src/Artist/Edit/EditArtistModalContent.js
+++ b/frontend/src/Artist/Edit/EditArtistModalContent.js
@@ -1,6 +1,7 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import ArtistMetadataProfilePopoverContent from 'AddArtist/ArtistMetadataProfilePopoverContent';
+import ArtistMonitorNewItemsOptionsPopoverContent from 'AddArtist/ArtistMonitorNewItemsOptionsPopoverContent';
import MoveArtistModal from 'Artist/MoveArtist/MoveArtistModal';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
@@ -73,6 +74,7 @@ class EditArtistModalContent extends Component {
const {
monitored,
+ monitorNewItems,
qualityProfileId,
metadataProfileId,
path,
@@ -101,6 +103,31 @@ class EditArtistModalContent extends Component {
/>
+
+
+ {translate('MonitorNewItems')}
+
+ }
+ title={translate('MonitorNewItems')}
+ body={}
+ position={tooltipPositions.RIGHT}
+ />
+
+
+
+
+
{translate('QualityProfile')}
diff --git a/frontend/src/Artist/Edit/EditArtistModalContentConnector.js b/frontend/src/Artist/Edit/EditArtistModalContentConnector.js
index 9c9ae4433..bd9592d42 100644
--- a/frontend/src/Artist/Edit/EditArtistModalContentConnector.js
+++ b/frontend/src/Artist/Edit/EditArtistModalContentConnector.js
@@ -39,6 +39,7 @@ function createMapStateToProps() {
const artistSettings = _.pick(artist, [
'monitored',
+ 'monitorNewItems',
'qualityProfileId',
'metadataProfileId',
'path',
diff --git a/frontend/src/Artist/Editor/ArtistEditorFooter.js b/frontend/src/Artist/Editor/ArtistEditorFooter.js
index f6cf007d1..174996ad0 100644
--- a/frontend/src/Artist/Editor/ArtistEditorFooter.js
+++ b/frontend/src/Artist/Editor/ArtistEditorFooter.js
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import MoveArtistModal from 'Artist/MoveArtist/MoveArtistModal';
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 ArtistEditorFooter extends Component {
this.state = {
monitored: NO_CHANGE,
+ monitorNewItems: NO_CHANGE,
qualityProfileId: NO_CHANGE,
metadataProfileId: NO_CHANGE,
rootFolderPath: NO_CHANGE,
@@ -46,6 +48,7 @@ class ArtistEditorFooter extends Component {
if (prevProps.isSaving && !isSaving && !saveError) {
this.setState({
monitored: NO_CHANGE,
+ monitorNewItems: NO_CHANGE,
qualityProfileId: NO_CHANGE,
metadataProfileId: NO_CHANGE,
rootFolderPath: NO_CHANGE,
@@ -146,6 +149,7 @@ class ArtistEditorFooter extends Component {
const {
monitored,
+ monitorNewItems,
qualityProfileId,
metadataProfileId,
rootFolderPath,
@@ -179,6 +183,21 @@ class ArtistEditorFooter extends Component {
/>
+
+
{
columns.map((column) => {
const {
diff --git a/frontend/src/Artist/MonitoringOptions/MonitoringOptionsModalContent.js b/frontend/src/Artist/MonitoringOptions/MonitoringOptionsModalContent.js
new file mode 100644
index 000000000..0057ab30f
--- /dev/null
+++ b/frontend/src/Artist/MonitoringOptions/MonitoringOptionsModalContent.js
@@ -0,0 +1,149 @@
+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';
+import FormLabel from 'Components/Form/FormLabel';
+import Button from 'Components/Link/Button';
+import SpinnerButton from 'Components/Link/SpinnerButton';
+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, kinds } from 'Helpers/Props';
+import translate from 'Utilities/String/translate';
+
+const NO_CHANGE = 'noChange';
+
+class MonitoringOptionsModalContent extends Component {
+
+ //
+ // Lifecycle
+
+ constructor(props, context) {
+ super(props, context);
+
+ this.state = {
+ monitor: NO_CHANGE
+ };
+ }
+
+ componentDidUpdate(prevProps) {
+ const {
+ isSaving,
+ saveError
+ } = prevProps;
+
+ if (prevProps.isSaving && !isSaving && !saveError) {
+ this.setState({
+ monitor: NO_CHANGE
+ });
+ }
+ }
+
+ onInputChange = ({ name, value }) => {
+ this.setState({ [name]: value });
+ };
+
+ //
+ // Listeners
+
+ onSavePress = () => {
+ const {
+ onSavePress,
+ isSaving
+ } = this.props;
+ const {
+ monitor
+ } = this.state;
+
+ if (monitor !== NO_CHANGE) {
+ onSavePress({ monitor });
+ }
+
+ if (!isSaving) {
+ this.onModalClose();
+ }
+ };
+
+ onModalClose = () => {
+ this.props.onModalClose();
+ };
+
+ //
+ // Render
+
+ render() {
+ const {
+ isSaving,
+ onInputChange,
+ onModalClose,
+ ...otherProps
+ } = this.props;
+
+ const {
+ monitor
+ } = this.state;
+
+ return (
+
+
+ {translate('MonitorAlbum')}
+
+
+
+
+
+ {translate('MonitorAlbumExistingOnlyWarning')}
+
+
+
+
+
+
+
+
+
+
+ {translate('Save')}
+
+
+
+ );
+ }
+}
+
+MonitoringOptionsModalContent.propTypes = {
+ authorId: PropTypes.number.isRequired,
+ saveError: PropTypes.object,
+ isSaving: PropTypes.bool.isRequired,
+ onInputChange: PropTypes.func.isRequired,
+ onSavePress: PropTypes.func.isRequired,
+ onModalClose: PropTypes.func.isRequired
+};
+
+MonitoringOptionsModalContent.defaultProps = {
+ isSaving: false
+};
+
+export default MonitoringOptionsModalContent;
diff --git a/frontend/src/Components/Form/FormInputGroup.js b/frontend/src/Components/Form/FormInputGroup.js
index 5338786b4..4919e5027 100644
--- a/frontend/src/Components/Form/FormInputGroup.js
+++ b/frontend/src/Components/Form/FormInputGroup.js
@@ -14,6 +14,7 @@ import IndexerSelectInputConnector from './IndexerSelectInputConnector';
import KeyValueListInput from './KeyValueListInput';
import MetadataProfileSelectInputConnector from './MetadataProfileSelectInputConnector';
import MonitorAlbumsSelectInput from './MonitorAlbumsSelectInput';
+import MonitorNewItemsSelectInput from './MonitorNewItemsSelectInput';
import NumberInput from './NumberInput';
import OAuthInputConnector from './OAuthInputConnector';
import PasswordInput from './PasswordInput';
@@ -52,6 +53,9 @@ function getComponent(type) {
case inputTypes.MONITOR_ALBUMS_SELECT:
return MonitorAlbumsSelectInput;
+ 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..0152c0a2d
--- /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/Artist/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 4c4c55784..2f04d5213 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 PLAYLIST = 'playlist';
export const KEY_VALUE_LIST = 'keyValueList';
export const MONITOR_ALBUMS_SELECT = 'monitorAlbumsSelect';
+export const MONITOR_NEW_ITEMS_SELECT = 'monitorNewItemsSelect';
export const NUMBER = 'number';
export const OAUTH = 'oauth';
export const PASSWORD = 'password';
@@ -31,6 +32,7 @@ export const all = [
PLAYLIST,
KEY_VALUE_LIST,
MONITOR_ALBUMS_SELECT,
+ MONITOR_NEW_ITEMS_SELECT,
NUMBER,
OAUTH,
PASSWORD,
diff --git a/frontend/src/Search/Album/AddNewAlbumModalContentConnector.js b/frontend/src/Search/Album/AddNewAlbumModalContentConnector.js
index cbdb93df5..fa18374e6 100644
--- a/frontend/src/Search/Album/AddNewAlbumModalContentConnector.js
+++ b/frontend/src/Search/Album/AddNewAlbumModalContentConnector.js
@@ -85,6 +85,7 @@ class AddNewAlbumModalContentConnector extends Component {
foreignAlbumId,
rootFolderPath,
monitor,
+ monitorNewItems,
qualityProfileId,
metadataProfileId,
tags
@@ -94,6 +95,7 @@ class AddNewAlbumModalContentConnector extends Component {
foreignAlbumId,
rootFolderPath: rootFolderPath.value,
monitor: monitor.value,
+ monitorNewItems: monitorNewItems.value,
qualityProfileId: qualityProfileId.value,
metadataProfileId: metadataProfileId.value,
tags: tags.value,
@@ -120,6 +122,7 @@ AddNewAlbumModalContentConnector.propTypes = {
foreignAlbumId: PropTypes.string.isRequired,
rootFolderPath: PropTypes.object,
monitor: PropTypes.object.isRequired,
+ monitorNewItems: PropTypes.object.isRequired,
qualityProfileId: PropTypes.object,
metadataProfileId: PropTypes.object,
noneMetadataProfileId: PropTypes.number.isRequired,
diff --git a/frontend/src/Search/Artist/AddNewArtistModalContentConnector.js b/frontend/src/Search/Artist/AddNewArtistModalContentConnector.js
index b5454ca43..acd168f0b 100644
--- a/frontend/src/Search/Artist/AddNewArtistModalContentConnector.js
+++ b/frontend/src/Search/Artist/AddNewArtistModalContentConnector.js
@@ -57,6 +57,7 @@ class AddNewArtistModalContentConnector extends Component {
foreignArtistId,
rootFolderPath,
monitor,
+ monitorNewItems,
qualityProfileId,
metadataProfileId,
tags
@@ -66,6 +67,7 @@ class AddNewArtistModalContentConnector extends Component {
foreignArtistId,
rootFolderPath: rootFolderPath.value,
monitor: monitor.value,
+ monitorNewItems: monitorNewItems.value,
qualityProfileId: qualityProfileId.value,
metadataProfileId: metadataProfileId.value,
tags: tags.value,
@@ -91,6 +93,7 @@ AddNewArtistModalContentConnector.propTypes = {
foreignArtistId: 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/AddArtistOptionsForm.js b/frontend/src/Search/Common/AddArtistOptionsForm.js
index dbabed7c9..e620ad379 100644
--- a/frontend/src/Search/Common/AddArtistOptionsForm.js
+++ b/frontend/src/Search/Common/AddArtistOptionsForm.js
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import ArtistMetadataProfilePopoverContent from 'AddArtist/ArtistMetadataProfilePopoverContent';
import ArtistMonitoringOptionsPopoverContent from 'AddArtist/ArtistMonitoringOptionsPopoverContent';
+import ArtistMonitorNewItemsOptionsPopoverContent from 'AddArtist/ArtistMonitorNewItemsOptionsPopoverContent';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
@@ -32,6 +33,7 @@ class AddArtistOptionsForm extends Component {
const {
rootFolderPath,
monitor,
+ monitorNewItems,
qualityProfileId,
metadataProfileId,
includeNoneMetadataProfile,
@@ -76,11 +78,37 @@ class AddArtistOptionsForm extends Component {
+
+
+ {translate('MonitorNewItems')}
+
+ }
+ title={translate('MonitorNewItems')}
+ body={}
+ position={tooltipPositions.RIGHT}
+ />
+
+
+
+
+
{translate('QualityProfile')}
@@ -143,6 +171,7 @@ class AddArtistOptionsForm extends Component {
AddArtistOptionsForm.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 dd01331d5..8f18926fa 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 ArtistMonitorNewItemsOptionsPopoverContent from 'AddArtist/ArtistMonitorNewItemsOptionsPopoverContent';
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';
@@ -74,6 +76,7 @@ function EditImportListModalContent(props) {
enableAutomaticAdd,
shouldMonitor,
rootFolderPath,
+ monitorNewItems,
qualityProfileId,
metadataProfileId,
tags,
@@ -112,120 +115,150 @@ function EditImportListModalContent(props) {
{message.value.message}
}
-
-
- {translate('Name')}
-
-
-
-
-
-
-
- {translate('EnableAutomaticAdd')}
-
-
-
-
-
-
-
- Monitor
-
-
- }
- title={translate('MonitoringOptions')}
- body={}
- position={tooltipPositions.RIGHT}
+
+
+
+
-
-
-
-
-
-
- {translate('RootFolder')}
-
-
-
-
-
-
-
- {translate('QualityProfile')}
-
-
-
-
-
-
-
- {translate('MetadataProfile')}
-
-
-
-
-
-
-
- {translate('LidarrTags')}
-
-
-
-
+
+
{
!!fields && !!fields.length &&
-
+
+
}
diff --git a/frontend/src/Settings/MediaManagement/RootFolder/EditRootFolderModalContent.js b/frontend/src/Settings/MediaManagement/RootFolder/EditRootFolderModalContent.js
index 237cdcc22..e68f03459 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 ArtistMetadataProfilePopoverContent from 'AddArtist/ArtistMetadataProfilePopoverContent';
import ArtistMonitoringOptionsPopoverContent from 'AddArtist/ArtistMonitoringOptionsPopoverContent';
+import ArtistMonitorNewItemsOptionsPopoverContent from 'AddArtist/ArtistMonitorNewItemsOptionsPopoverContent';
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
} = item;
@@ -99,7 +101,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/albumStudioActions.js b/frontend/src/Store/Actions/albumStudioActions.js
index c473950a2..786e3a575 100644
--- a/frontend/src/Store/Actions/albumStudioActions.js
+++ b/frontend/src/Store/Actions/albumStudioActions.js
@@ -102,7 +102,8 @@ export const actionHandlers = handleThunks({
const {
artistIds,
monitored,
- monitor
+ monitor,
+ monitorNewItems
} = payload;
const artist = [];
@@ -127,7 +128,8 @@ export const actionHandlers = handleThunks({
method: 'POST',
data: JSON.stringify({
artist,
- monitoringOptions: { monitor }
+ monitoringOptions: { monitor },
+ monitorNewItems
}),
dataType: 'json'
}).request;
diff --git a/frontend/src/Utilities/Artist/getNewArtist.js b/frontend/src/Utilities/Artist/getNewArtist.js
index 6f6ee7051..ed1a6fb11 100644
--- a/frontend/src/Utilities/Artist/getNewArtist.js
+++ b/frontend/src/Utilities/Artist/getNewArtist.js
@@ -3,6 +3,7 @@ function getNewArtist(artist, payload) {
const {
rootFolderPath,
monitor,
+ monitorNewItems,
qualityProfileId,
metadataProfileId,
artistType,
@@ -17,6 +18,7 @@ function getNewArtist(artist, payload) {
artist.addOptions = addOptions;
artist.monitored = true;
+ artist.monitorNewItems = monitorNewItems;
artist.qualityProfileId = qualityProfileId;
artist.metadataProfileId = metadataProfileId;
artist.rootFolderPath = rootFolderPath;
diff --git a/frontend/src/Utilities/Artist/monitorNewItemsOptions.js b/frontend/src/Utilities/Artist/monitorNewItemsOptions.js
new file mode 100644
index 000000000..32e86e41f
--- /dev/null
+++ b/frontend/src/Utilities/Artist/monitorNewItemsOptions.js
@@ -0,0 +1,7 @@
+const monitorNewItemsOptions = [
+ { key: 'all', value: 'All Albums' },
+ { key: 'none', value: 'None' },
+ { key: 'new', value: 'New' }
+];
+
+export default monitorNewItemsOptions;
diff --git a/src/Lidarr.Api.V1/AlbumStudio/AlbumStudioController.cs b/src/Lidarr.Api.V1/AlbumStudio/AlbumStudioController.cs
index 2561d6d26..edde38573 100644
--- a/src/Lidarr.Api.V1/AlbumStudio/AlbumStudioController.cs
+++ b/src/Lidarr.Api.V1/AlbumStudio/AlbumStudioController.cs
@@ -36,10 +36,15 @@ namespace Lidarr.Api.V1.AlbumStudio
artist.Monitored = false;
}
+ if (request.MonitorNewItems.HasValue)
+ {
+ artist.MonitorNewItems = request.MonitorNewItems.Value;
+ }
+
_albumMonitoredService.SetAlbumMonitoredStatus(artist, request.MonitoringOptions);
}
- return Accepted();
+ return Accepted(request);
}
}
}
diff --git a/src/Lidarr.Api.V1/AlbumStudio/AlbumStudioResource.cs b/src/Lidarr.Api.V1/AlbumStudio/AlbumStudioResource.cs
index f89b6c962..97dbbc81f 100644
--- a/src/Lidarr.Api.V1/AlbumStudio/AlbumStudioResource.cs
+++ b/src/Lidarr.Api.V1/AlbumStudio/AlbumStudioResource.cs
@@ -7,5 +7,6 @@ namespace Lidarr.Api.V1.AlbumStudio
{
public List Artist { get; set; }
public MonitoringOptions MonitoringOptions { get; set; }
+ public NewItemMonitorTypes? MonitorNewItems { get; set; }
}
}
diff --git a/src/Lidarr.Api.V1/Artist/ArtistEditorController.cs b/src/Lidarr.Api.V1/Artist/ArtistEditorController.cs
index 99860c3f1..a7e103105 100644
--- a/src/Lidarr.Api.V1/Artist/ArtistEditorController.cs
+++ b/src/Lidarr.Api.V1/Artist/ArtistEditorController.cs
@@ -34,6 +34,11 @@ namespace Lidarr.Api.V1.Artist
artist.Monitored = resource.Monitored.Value;
}
+ if (resource.MonitorNewItems.HasValue)
+ {
+ artist.MonitorNewItems = resource.MonitorNewItems.Value;
+ }
+
if (resource.QualityProfileId.HasValue)
{
artist.QualityProfileId = resource.QualityProfileId.Value;
diff --git a/src/Lidarr.Api.V1/Artist/ArtistEditorResource.cs b/src/Lidarr.Api.V1/Artist/ArtistEditorResource.cs
index 805348a69..71b0eb396 100644
--- a/src/Lidarr.Api.V1/Artist/ArtistEditorResource.cs
+++ b/src/Lidarr.Api.V1/Artist/ArtistEditorResource.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using NzbDrone.Core.Music;
namespace Lidarr.Api.V1.Artist
{
@@ -6,6 +7,7 @@ namespace Lidarr.Api.V1.Artist
{
public List ArtistIds { 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/Lidarr.Api.V1/Artist/ArtistResource.cs b/src/Lidarr.Api.V1/Artist/ArtistResource.cs
index 96a7805e5..4d6977104 100644
--- a/src/Lidarr.Api.V1/Artist/ArtistResource.cs
+++ b/src/Lidarr.Api.V1/Artist/ArtistResource.cs
@@ -46,6 +46,7 @@ namespace Lidarr.Api.V1.Artist
//Editing Only
public bool Monitored { get; set; }
+ public NewItemMonitorTypes MonitorNewItems { get; set; }
public string RootFolderPath { get; set; }
public List Genres { get; set; }
@@ -91,6 +92,7 @@ namespace Lidarr.Api.V1.Artist
Links = model.Metadata.Value.Links,
Monitored = model.Monitored,
+ MonitorNewItems = model.MonitorNewItems,
CleanName = model.CleanName,
ForeignArtistId = model.Metadata.Value.ForeignArtistId,
@@ -138,6 +140,7 @@ namespace Lidarr.Api.V1.Artist
MetadataProfileId = resource.MetadataProfileId,
Monitored = resource.Monitored,
+ MonitorNewItems = resource.MonitorNewItems,
CleanName = resource.CleanName,
RootFolderPath = resource.RootFolderPath,
diff --git a/src/Lidarr.Api.V1/ImportLists/ImportListResource.cs b/src/Lidarr.Api.V1/ImportLists/ImportListResource.cs
index 87950df72..3a7596094 100644
--- a/src/Lidarr.Api.V1/ImportLists/ImportListResource.cs
+++ b/src/Lidarr.Api.V1/ImportLists/ImportListResource.cs
@@ -1,4 +1,5 @@
using NzbDrone.Core.ImportLists;
+using NzbDrone.Core.Music;
namespace Lidarr.Api.V1.ImportLists
{
@@ -7,6 +8,7 @@ namespace Lidarr.Api.V1.ImportLists
public bool EnableAutomaticAdd { get; set; }
public ImportListMonitorType ShouldMonitor { 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; }
@@ -27,6 +29,7 @@ namespace Lidarr.Api.V1.ImportLists
resource.EnableAutomaticAdd = definition.EnableAutomaticAdd;
resource.ShouldMonitor = definition.ShouldMonitor;
resource.RootFolderPath = definition.RootFolderPath;
+ resource.MonitorNewItems = definition.MonitorNewItems;
resource.QualityProfileId = definition.ProfileId;
resource.MetadataProfileId = definition.MetadataProfileId;
resource.ListType = definition.ListType;
@@ -47,6 +50,7 @@ namespace Lidarr.Api.V1.ImportLists
definition.EnableAutomaticAdd = resource.EnableAutomaticAdd;
definition.ShouldMonitor = resource.ShouldMonitor;
definition.RootFolderPath = resource.RootFolderPath;
+ definition.MonitorNewItems = resource.MonitorNewItems;
definition.ProfileId = resource.QualityProfileId;
definition.MetadataProfileId = resource.MetadataProfileId;
definition.ListType = resource.ListType;
diff --git a/src/Lidarr.Api.V1/RootFolders/RootFolderResource.cs b/src/Lidarr.Api.V1/RootFolders/RootFolderResource.cs
index 563eb4c08..3e82f3585 100644
--- a/src/Lidarr.Api.V1/RootFolders/RootFolderResource.cs
+++ b/src/Lidarr.Api.V1/RootFolders/RootFolderResource.cs
@@ -13,6 +13,7 @@ namespace Lidarr.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 Accessible { get; set; }
@@ -38,6 +39,7 @@ namespace Lidarr.Api.V1.RootFolders
DefaultMetadataProfileId = model.DefaultMetadataProfileId,
DefaultQualityProfileId = model.DefaultQualityProfileId,
DefaultMonitorOption = model.DefaultMonitorOption,
+ DefaultNewItemMonitorOption = model.DefaultNewItemMonitorOption,
DefaultTags = model.DefaultTags,
Accessible = model.Accessible,
@@ -62,7 +64,8 @@ namespace Lidarr.Api.V1.RootFolders
DefaultMetadataProfileId = resource.DefaultMetadataProfileId,
DefaultQualityProfileId = resource.DefaultQualityProfileId,
DefaultMonitorOption = resource.DefaultMonitorOption,
- DefaultTags = resource.DefaultTags
+ DefaultNewItemMonitorOption = resource.DefaultNewItemMonitorOption,
+ DefaultTags = resource.DefaultTags,
};
}
diff --git a/src/NzbDrone.Core.Test/MusicTests/MonitorNewAlbumServiceFixture.cs b/src/NzbDrone.Core.Test/MusicTests/MonitorNewAlbumServiceFixture.cs
new file mode 100644
index 000000000..83e937e1e
--- /dev/null
+++ b/src/NzbDrone.Core.Test/MusicTests/MonitorNewAlbumServiceFixture.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.Music;
+using NzbDrone.Core.Test.Framework;
+
+namespace NzbDrone.Core.Test.AlbumTests
+{
+ [TestFixture]
+ public class MonitorNewAlbumServiceFixture : CoreTest
+ {
+ private List _albums;
+
+ [SetUp]
+ public void Setup()
+ {
+ _albums = 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 album in _albums)
+ {
+ Subject.ShouldMonitorNewAlbum(album, _albums, NewItemMonitorTypes.All).Should().BeTrue();
+ }
+ }
+
+ [Test]
+ public void should_not_monitor_with_none()
+ {
+ foreach (var album in _albums)
+ {
+ Subject.ShouldMonitorNewAlbum(album, _albums, NewItemMonitorTypes.None).Should().BeFalse();
+ }
+ }
+
+ [Test]
+ public void should_only_monitor_new_with_new()
+ {
+ Subject.ShouldMonitorNewAlbum(_albums[0], _albums, NewItemMonitorTypes.New).Should().BeTrue();
+
+ foreach (var album in _albums.Skip(1))
+ {
+ Subject.ShouldMonitorNewAlbum(album, _albums, NewItemMonitorTypes.New).Should().BeFalse();
+ }
+ }
+ }
+}
diff --git a/src/NzbDrone.Core.Test/MusicTests/RefreshArtistServiceFixture.cs b/src/NzbDrone.Core.Test/MusicTests/RefreshArtistServiceFixture.cs
index 18d3fe716..f6a865f52 100644
--- a/src/NzbDrone.Core.Test/MusicTests/RefreshArtistServiceFixture.cs
+++ b/src/NzbDrone.Core.Test/MusicTests/RefreshArtistServiceFixture.cs
@@ -74,6 +74,10 @@ namespace NzbDrone.Core.Test.MusicTests
Mocker.GetMock()
.Setup(x => x.All())
.Returns(new List());
+
+ Mocker.GetMock()
+ .Setup(x => x.ShouldMonitorNewAlbum(It.IsAny(), It.IsAny>(), It.IsAny()))
+ .Returns(true);
}
private void GivenNewArtistInfo(Artist artist)
@@ -143,7 +147,30 @@ namespace NzbDrone.Core.Test.MusicTests
}
[Test]
- public void should_log_error_and_delete_if_musicbrainz_id_not_found_and_artist_has_no_files()
+ public void should_call_new_album_monitor_service_when_adding_album()
+ {
+ var newAlbum = Builder.CreateNew()
+ .With(x => x.Id = 0)
+ .With(x => x.ForeignAlbumId = "3")
+ .Build();
+ _remoteAlbums.Add(newAlbum);
+
+ var newAuthorInfo = _artist.JsonClone();
+ newAuthorInfo.Metadata = _artist.Metadata.Value.JsonClone();
+ newAuthorInfo.Albums = _remoteAlbums;
+
+ GivenNewArtistInfo(newAuthorInfo);
+ GivenAlbumsForRefresh(_albums);
+ AllowArtistUpdate();
+
+ Subject.Execute(new RefreshArtistCommand(_artist.Id));
+
+ Mocker.GetMock()
+ .Verify(x => x.ShouldMonitorNewAlbum(newAlbum, _albums, _artist.MonitorNewItems), Times.Once());
+ }
+
+ [Test]
+ public void should_log_error_and_delete_if_musicbrainz_id_not_found_and_author_has_no_files()
{
Mocker.GetMock()
.Setup(x => x.DeleteArtist(It.IsAny(), It.IsAny(), It.IsAny()));
diff --git a/src/NzbDrone.Core/Datastore/Migration/056_add_new_item_monitor_type.cs b/src/NzbDrone.Core/Datastore/Migration/056_add_new_item_monitor_type.cs
new file mode 100644
index 000000000..77749365a
--- /dev/null
+++ b/src/NzbDrone.Core/Datastore/Migration/056_add_new_item_monitor_type.cs
@@ -0,0 +1,16 @@
+using FluentMigrator;
+using NzbDrone.Core.Datastore.Migration.Framework;
+
+namespace NzbDrone.Core.Datastore.Migration
+{
+ [Migration(56)]
+ public class AddNewItemMonitorType : NzbDroneMigrationBase
+ {
+ protected override void MainDbUpgrade()
+ {
+ Alter.Table("Artists").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 39473a044..825bf0d68 100644
--- a/src/NzbDrone.Core/ImportLists/ImportListDefinition.cs
+++ b/src/NzbDrone.Core/ImportLists/ImportListDefinition.cs
@@ -1,3 +1,4 @@
+using NzbDrone.Core.Music;
using NzbDrone.Core.ThingiProvider;
namespace NzbDrone.Core.ImportLists
@@ -6,6 +7,7 @@ namespace NzbDrone.Core.ImportLists
{
public bool EnableAutomaticAdd { get; set; }
public ImportListMonitorType ShouldMonitor { 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 0a99a2195..74dba1253 100644
--- a/src/NzbDrone.Core/ImportLists/ImportListSyncService.cs
+++ b/src/NzbDrone.Core/ImportLists/ImportListSyncService.cs
@@ -270,6 +270,7 @@ namespace NzbDrone.Core.ImportLists
Name = report.Artist
},
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 d6092b948..8dc396cab 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",
+ "AddedArtistSettings": "Added Artist Settings",
"AddImportListExclusionHelpText": "Prevent artist from being added to Lidarr by Import lists",
"AddingTag": "Adding tag",
"AddListExclusion": "Add List Exclusion",
@@ -113,7 +114,7 @@
"DBMigration": "DB Migration",
"DefaultLidarrTags": "Default Lidarr Tags",
"DefaultMetadataProfileIdHelpText": "Default Metadata Profile for artists detected in this folder",
- "DefaultMonitorOptionHelpText": "Default Monitoring Options for albums by artists detected in this folder",
+ "DefaultMonitorOptionHelpText": "Which albums should be monitored on initial add for artists detected in this folder",
"DefaultQualityProfileIdHelpText": "Default Quality Profile for artists detected in this folder",
"DefaultTagsHelpText": "Default Lidarr Tags for artists detected in this folder",
"DelayingDownloadUntilInterp": "Delaying download until {0} at {1}",
@@ -261,7 +262,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",
"IncludeUnknownArtistItemsHelpText": "Show items without a artist in the queue, this could include removed artists, movies or anything else in Lidarr's category",
@@ -348,10 +350,15 @@
"MissingTracksArtistMonitored": "Missing Tracks (Artist monitored)",
"MissingTracksArtistNotMonitored": "Missing Tracks (Artist not monitored)",
"Mode": "Mode",
+ "MonitorAlbumExistingOnlyWarning": "This is a one off adjustment of the monitored setting for each album. Use the option under Artist/Edit to control what happens for newly added albums",
"MonitorArtist": "Monitor Artist",
"Monitored": "Monitored",
"MonitoredHelpText": "Download monitored albums from this artist",
"MonitoringOptions": "Monitoring Options",
+ "MonitoringOptionsHelpText": "Which albums should be monitored after the artist is added (one-time adjustment)",
+ "MonitorNewItems": "Monitor New Albums",
+ "MonitorNewItemsHelpText": "Which new albums should be monitored",
+ "MonoVersion": "Mono Version",
"MoreInfo": "More Info",
"MultiDiscTrackFormat": "Multi Disc Track Format",
"MusicBrainzAlbumID": "MusicBrainz Album ID",
@@ -366,6 +373,7 @@
"NamingSettings": "Naming Settings",
"NETCore": ".NET",
"New": "New",
+ "NewAlbums": "New Albums",
"NoBackupsAreAvailable": "No backups are available",
"NoHistory": "No history.",
"NoLeaveIt": "No, Leave It",
diff --git a/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs b/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs
index aecf64d3a..7b89b343b 100644
--- a/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs
+++ b/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs
@@ -337,6 +337,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport
artist.MetadataProfileId = rootFolder.DefaultMetadataProfileId;
artist.QualityProfileId = rootFolder.DefaultQualityProfileId;
artist.Monitored = rootFolder.DefaultMonitorOption != MonitorTypes.None;
+ artist.MonitorNewItems = rootFolder.DefaultNewItemMonitorOption;
artist.Tags = rootFolder.DefaultTags;
artist.AddOptions = new AddArtistOptions
{
diff --git a/src/NzbDrone.Core/Music/Model/Artist.cs b/src/NzbDrone.Core/Music/Model/Artist.cs
index cd9d5cbf8..a1f840e46 100644
--- a/src/NzbDrone.Core/Music/Model/Artist.cs
+++ b/src/NzbDrone.Core/Music/Model/Artist.cs
@@ -21,6 +21,7 @@ namespace NzbDrone.Core.Music
public string CleanName { get; set; }
public string SortName { 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.Music
Id = other.Id;
ArtistMetadataId = other.ArtistMetadataId;
Monitored = other.Monitored;
+ MonitorNewItems = other.MonitorNewItems;
LastInfoSync = other.LastInfoSync;
Path = other.Path;
RootFolderPath = other.RootFolderPath;
@@ -93,6 +95,7 @@ namespace NzbDrone.Core.Music
AddOptions = other.AddOptions;
RootFolderPath = other.RootFolderPath;
Monitored = other.Monitored;
+ MonitorNewItems = other.MonitorNewItems;
}
}
}
diff --git a/src/NzbDrone.Core/Music/Model/MonitorTypes.cs b/src/NzbDrone.Core/Music/Model/MonitorTypes.cs
new file mode 100644
index 000000000..26bd89015
--- /dev/null
+++ b/src/NzbDrone.Core/Music/Model/MonitorTypes.cs
@@ -0,0 +1,14 @@
+namespace NzbDrone.Core.Music
+{
+ public enum MonitorTypes
+ {
+ All,
+ Future,
+ Missing,
+ Existing,
+ Latest,
+ First,
+ None,
+ Unknown
+ }
+}
diff --git a/src/NzbDrone.Core/Music/Model/MonitoringOptions.cs b/src/NzbDrone.Core/Music/Model/MonitoringOptions.cs
index 382c40a57..d50e278c8 100644
--- a/src/NzbDrone.Core/Music/Model/MonitoringOptions.cs
+++ b/src/NzbDrone.Core/Music/Model/MonitoringOptions.cs
@@ -14,16 +14,4 @@ namespace NzbDrone.Core.Music
public List AlbumsToMonitor { get; set; }
public bool Monitored { get; set; }
}
-
- public enum MonitorTypes
- {
- All,
- Future,
- Missing,
- Existing,
- Latest,
- First,
- None,
- Unknown
- }
}
diff --git a/src/NzbDrone.Core/Music/Model/NewItemMonitorTypes.cs b/src/NzbDrone.Core/Music/Model/NewItemMonitorTypes.cs
new file mode 100644
index 000000000..4ea719b5c
--- /dev/null
+++ b/src/NzbDrone.Core/Music/Model/NewItemMonitorTypes.cs
@@ -0,0 +1,9 @@
+namespace NzbDrone.Core.Music
+{
+ public enum NewItemMonitorTypes
+ {
+ All,
+ None,
+ New
+ }
+}
diff --git a/src/NzbDrone.Core/Music/Services/MonitorNewAlbumService.cs b/src/NzbDrone.Core/Music/Services/MonitorNewAlbumService.cs
new file mode 100644
index 000000000..767913f94
--- /dev/null
+++ b/src/NzbDrone.Core/Music/Services/MonitorNewAlbumService.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NLog;
+
+namespace NzbDrone.Core.Music
+{
+ public interface IMonitorNewAlbumService
+ {
+ bool ShouldMonitorNewAlbum(Album addedAlbum, List existingAlbums, NewItemMonitorTypes monitorNewItems);
+ }
+
+ public class MonitorNewAlbumService : IMonitorNewAlbumService
+ {
+ private readonly Logger _logger;
+
+ public MonitorNewAlbumService(Logger logger)
+ {
+ _logger = logger;
+ }
+
+ public bool ShouldMonitorNewAlbum(Album addedAlbum, List existingAlbums, NewItemMonitorTypes monitorNewItems)
+ {
+ if (monitorNewItems == NewItemMonitorTypes.None)
+ {
+ return false;
+ }
+
+ if (monitorNewItems == NewItemMonitorTypes.All)
+ {
+ return true;
+ }
+
+ if (monitorNewItems == NewItemMonitorTypes.New)
+ {
+ var newest = existingAlbums.OrderByDescending(x => x.ReleaseDate ?? DateTime.MinValue).FirstOrDefault()?.ReleaseDate ?? DateTime.MinValue;
+
+ return (addedAlbum.ReleaseDate ?? DateTime.MinValue) >= newest;
+ }
+
+ throw new NotImplementedException($"Unknown new item monitor type {monitorNewItems}");
+ }
+ }
+}
diff --git a/src/NzbDrone.Core/Music/Services/RefreshAlbumReleaseService.cs b/src/NzbDrone.Core/Music/Services/RefreshAlbumReleaseService.cs
index 294610a35..a02791501 100644
--- a/src/NzbDrone.Core/Music/Services/RefreshAlbumReleaseService.cs
+++ b/src/NzbDrone.Core/Music/Services/RefreshAlbumReleaseService.cs
@@ -103,10 +103,8 @@ namespace NzbDrone.Core.Music
local.AlbumRelease = entity;
local.AlbumReleaseId = entity.Id;
local.ArtistMetadataId = remote.ArtistMetadata.Value.Id;
- remote.Id = local.Id;
- remote.TrackFileId = local.TrackFileId;
- remote.AlbumReleaseId = local.AlbumReleaseId;
- remote.ArtistMetadataId = local.ArtistMetadataId;
+
+ remote.UseDbFieldsFrom(local);
}
protected override void AddChildren(List