mirror of
https://github.com/lidarr/lidarr.git
synced 2025-07-15 01:23:53 -07:00
New: Option to control which new artist albums get monitored
(cherry picked from commit c51ae664aa6e6f5330be67e68476af76c55352f5)
This commit is contained in:
parent
d0fd0024e3
commit
2318c43536
41 changed files with 795 additions and 160 deletions
|
@ -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 ArtistMonitorNewItemsOptionsPopoverContent() {
|
||||||
|
return (
|
||||||
|
<DescriptionList>
|
||||||
|
<DescriptionListItem
|
||||||
|
title={translate('AllAlbums')}
|
||||||
|
data="Monitor all new albums"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<DescriptionListItem
|
||||||
|
title={translate('NewAlbums')}
|
||||||
|
data="Monitor new albums released after the newest existing album"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<DescriptionListItem
|
||||||
|
title={translate('None')}
|
||||||
|
data="Don't monitor any new albums"
|
||||||
|
/>
|
||||||
|
</DescriptionList>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ArtistMonitorNewItemsOptionsPopoverContent;
|
|
@ -1,10 +1,15 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import Alert from 'Components/Alert';
|
||||||
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
||||||
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
|
|
||||||
function ArtistMonitoringOptionsPopoverContent() {
|
function ArtistMonitoringOptionsPopoverContent() {
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Alert>
|
||||||
|
This is a one time adjustment to set which albums are monitored
|
||||||
|
</Alert>
|
||||||
<DescriptionList>
|
<DescriptionList>
|
||||||
<DescriptionListItem
|
<DescriptionListItem
|
||||||
title={translate('AllAlbums')}
|
title={translate('AllAlbums')}
|
||||||
|
@ -41,6 +46,7 @@ function ArtistMonitoringOptionsPopoverContent() {
|
||||||
data={translate('NoneData')}
|
data={translate('NoneData')}
|
||||||
/>
|
/>
|
||||||
</DescriptionList>
|
</DescriptionList>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import MonitorAlbumsSelectInput from 'Components/Form/MonitorAlbumsSelectInput';
|
import MonitorAlbumsSelectInput from 'Components/Form/MonitorAlbumsSelectInput';
|
||||||
|
import MonitorNewItemsSelectInput from 'Components/Form/MonitorNewItemsSelectInput';
|
||||||
import SelectInput from 'Components/Form/SelectInput';
|
import SelectInput from 'Components/Form/SelectInput';
|
||||||
import SpinnerButton from 'Components/Link/SpinnerButton';
|
import SpinnerButton from 'Components/Link/SpinnerButton';
|
||||||
import PageContentFooter from 'Components/Page/PageContentFooter';
|
import PageContentFooter from 'Components/Page/PageContentFooter';
|
||||||
|
@ -19,7 +20,8 @@ class AlbumStudioFooter extends Component {
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
monitored: NO_CHANGE,
|
monitored: NO_CHANGE,
|
||||||
monitor: NO_CHANGE
|
monitor: NO_CHANGE,
|
||||||
|
monitorNewItems: NO_CHANGE
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +34,8 @@ class AlbumStudioFooter extends Component {
|
||||||
if (prevProps.isSaving && !isSaving && !saveError) {
|
if (prevProps.isSaving && !isSaving && !saveError) {
|
||||||
this.setState({
|
this.setState({
|
||||||
monitored: NO_CHANGE,
|
monitored: NO_CHANGE,
|
||||||
monitor: NO_CHANGE
|
monitor: NO_CHANGE,
|
||||||
|
monitorNewItems: NO_CHANGE
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +50,8 @@ class AlbumStudioFooter extends Component {
|
||||||
onUpdateSelectedPress = () => {
|
onUpdateSelectedPress = () => {
|
||||||
const {
|
const {
|
||||||
monitor,
|
monitor,
|
||||||
monitored
|
monitored,
|
||||||
|
monitorNewItems
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
const changes = {};
|
const changes = {};
|
||||||
|
@ -60,6 +64,10 @@ class AlbumStudioFooter extends Component {
|
||||||
changes.monitor = monitor;
|
changes.monitor = monitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (monitorNewItems !== NO_CHANGE) {
|
||||||
|
changes.monitorNewItems = monitorNewItems;
|
||||||
|
}
|
||||||
|
|
||||||
this.props.onUpdateSelectedPress(changes);
|
this.props.onUpdateSelectedPress(changes);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -74,7 +82,8 @@ class AlbumStudioFooter extends Component {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
monitored,
|
monitored,
|
||||||
monitor
|
monitor,
|
||||||
|
monitorNewItems
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
const monitoredOptions = [
|
const monitoredOptions = [
|
||||||
|
@ -83,7 +92,9 @@ class AlbumStudioFooter extends Component {
|
||||||
{ key: 'unmonitored', value: 'Unmonitored' }
|
{ key: 'unmonitored', value: 'Unmonitored' }
|
||||||
];
|
];
|
||||||
|
|
||||||
const noChanges = monitored === NO_CHANGE && monitor === NO_CHANGE;
|
const noChanges = monitored === NO_CHANGE &&
|
||||||
|
monitor === NO_CHANGE &&
|
||||||
|
monitorNewItems === NO_CHANGE;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContentFooter>
|
<PageContentFooter>
|
||||||
|
@ -103,7 +114,7 @@ class AlbumStudioFooter extends Component {
|
||||||
|
|
||||||
<div className={styles.inputContainer}>
|
<div className={styles.inputContainer}>
|
||||||
<div className={styles.label}>
|
<div className={styles.label}>
|
||||||
Monitor Albums
|
Monitor Existing Albums
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<MonitorAlbumsSelectInput
|
<MonitorAlbumsSelectInput
|
||||||
|
@ -115,6 +126,20 @@ class AlbumStudioFooter extends Component {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.inputContainer}>
|
||||||
|
<div className={styles.label}>
|
||||||
|
Monitor New Albums
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<MonitorNewItemsSelectInput
|
||||||
|
name="monitorNewItems"
|
||||||
|
value={monitorNewItems}
|
||||||
|
includeNoChange={true}
|
||||||
|
isDisabled={!selectedCount}
|
||||||
|
onChange={this.onInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div className={styles.label}>
|
<div className={styles.label}>
|
||||||
{selectedCount} Artist(s) Selected
|
{selectedCount} Artist(s) Selected
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import ArtistMetadataProfilePopoverContent from 'AddArtist/ArtistMetadataProfilePopoverContent';
|
import ArtistMetadataProfilePopoverContent from 'AddArtist/ArtistMetadataProfilePopoverContent';
|
||||||
|
import ArtistMonitorNewItemsOptionsPopoverContent from 'AddArtist/ArtistMonitorNewItemsOptionsPopoverContent';
|
||||||
import MoveArtistModal from 'Artist/MoveArtist/MoveArtistModal';
|
import MoveArtistModal from 'Artist/MoveArtist/MoveArtistModal';
|
||||||
import Form from 'Components/Form/Form';
|
import Form from 'Components/Form/Form';
|
||||||
import FormGroup from 'Components/Form/FormGroup';
|
import FormGroup from 'Components/Form/FormGroup';
|
||||||
|
@ -73,6 +74,7 @@ class EditArtistModalContent extends Component {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
monitored,
|
monitored,
|
||||||
|
monitorNewItems,
|
||||||
qualityProfileId,
|
qualityProfileId,
|
||||||
metadataProfileId,
|
metadataProfileId,
|
||||||
path,
|
path,
|
||||||
|
@ -101,6 +103,31 @@ class EditArtistModalContent extends Component {
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
|
<FormGroup>
|
||||||
|
<FormLabel>
|
||||||
|
{translate('MonitorNewItems')}
|
||||||
|
<Popover
|
||||||
|
anchor={
|
||||||
|
<Icon
|
||||||
|
className={styles.labelIcon}
|
||||||
|
name={icons.INFO}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
title={translate('MonitorNewItems')}
|
||||||
|
body={<ArtistMonitorNewItemsOptionsPopoverContent />}
|
||||||
|
position={tooltipPositions.RIGHT}
|
||||||
|
/>
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.MONITOR_NEW_ITEMS_SELECT}
|
||||||
|
name="monitorNewItems"
|
||||||
|
helpText={translate('MonitorNewItemsHelpText')}
|
||||||
|
{...monitorNewItems}
|
||||||
|
onChange={onInputChange}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{translate('QualityProfile')}
|
{translate('QualityProfile')}
|
||||||
|
|
|
@ -39,6 +39,7 @@ function createMapStateToProps() {
|
||||||
|
|
||||||
const artistSettings = _.pick(artist, [
|
const artistSettings = _.pick(artist, [
|
||||||
'monitored',
|
'monitored',
|
||||||
|
'monitorNewItems',
|
||||||
'qualityProfileId',
|
'qualityProfileId',
|
||||||
'metadataProfileId',
|
'metadataProfileId',
|
||||||
'path',
|
'path',
|
||||||
|
|
|
@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import MoveArtistModal from 'Artist/MoveArtist/MoveArtistModal';
|
import MoveArtistModal from 'Artist/MoveArtist/MoveArtistModal';
|
||||||
import MetadataProfileSelectInputConnector from 'Components/Form/MetadataProfileSelectInputConnector';
|
import MetadataProfileSelectInputConnector from 'Components/Form/MetadataProfileSelectInputConnector';
|
||||||
|
import MonitorNewItemsSelectInput from 'Components/Form/MonitorNewItemsSelectInput';
|
||||||
import QualityProfileSelectInputConnector from 'Components/Form/QualityProfileSelectInputConnector';
|
import QualityProfileSelectInputConnector from 'Components/Form/QualityProfileSelectInputConnector';
|
||||||
import RootFolderSelectInputConnector from 'Components/Form/RootFolderSelectInputConnector';
|
import RootFolderSelectInputConnector from 'Components/Form/RootFolderSelectInputConnector';
|
||||||
import SelectInput from 'Components/Form/SelectInput';
|
import SelectInput from 'Components/Form/SelectInput';
|
||||||
|
@ -26,6 +27,7 @@ class ArtistEditorFooter extends Component {
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
monitored: NO_CHANGE,
|
monitored: NO_CHANGE,
|
||||||
|
monitorNewItems: NO_CHANGE,
|
||||||
qualityProfileId: NO_CHANGE,
|
qualityProfileId: NO_CHANGE,
|
||||||
metadataProfileId: NO_CHANGE,
|
metadataProfileId: NO_CHANGE,
|
||||||
rootFolderPath: NO_CHANGE,
|
rootFolderPath: NO_CHANGE,
|
||||||
|
@ -46,6 +48,7 @@ class ArtistEditorFooter extends Component {
|
||||||
if (prevProps.isSaving && !isSaving && !saveError) {
|
if (prevProps.isSaving && !isSaving && !saveError) {
|
||||||
this.setState({
|
this.setState({
|
||||||
monitored: NO_CHANGE,
|
monitored: NO_CHANGE,
|
||||||
|
monitorNewItems: NO_CHANGE,
|
||||||
qualityProfileId: NO_CHANGE,
|
qualityProfileId: NO_CHANGE,
|
||||||
metadataProfileId: NO_CHANGE,
|
metadataProfileId: NO_CHANGE,
|
||||||
rootFolderPath: NO_CHANGE,
|
rootFolderPath: NO_CHANGE,
|
||||||
|
@ -146,6 +149,7 @@ class ArtistEditorFooter extends Component {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
monitored,
|
monitored,
|
||||||
|
monitorNewItems,
|
||||||
qualityProfileId,
|
qualityProfileId,
|
||||||
metadataProfileId,
|
metadataProfileId,
|
||||||
rootFolderPath,
|
rootFolderPath,
|
||||||
|
@ -179,6 +183,21 @@ class ArtistEditorFooter extends Component {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.inputContainer}>
|
||||||
|
<ArtistEditorFooterLabel
|
||||||
|
label={translate('MonitorNewItems')}
|
||||||
|
isSaving={isSaving && monitored !== NO_CHANGE}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MonitorNewItemsSelectInput
|
||||||
|
name="monitorNewItems"
|
||||||
|
value={monitorNewItems}
|
||||||
|
includeNoChange={true}
|
||||||
|
isDisabled={!selectedCount}
|
||||||
|
onChange={this.onInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{
|
{
|
||||||
columns.map((column) => {
|
columns.map((column) => {
|
||||||
const {
|
const {
|
||||||
|
|
|
@ -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 (
|
||||||
|
<ModalContent onModalClose={onModalClose}>
|
||||||
|
<ModalHeader>
|
||||||
|
{translate('MonitorAlbum')}
|
||||||
|
</ModalHeader>
|
||||||
|
|
||||||
|
<ModalBody>
|
||||||
|
<Alert kind={kinds.INFO}>
|
||||||
|
<div>
|
||||||
|
{translate('MonitorAlbumExistingOnlyWarning')}
|
||||||
|
</div>
|
||||||
|
</Alert>
|
||||||
|
|
||||||
|
<Form {...otherProps}>
|
||||||
|
<FormGroup>
|
||||||
|
<FormLabel>{translate('Monitoring')}</FormLabel>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.MONITOR_ALBUMS_SELECT}
|
||||||
|
name="monitor"
|
||||||
|
value={monitor}
|
||||||
|
includeNoChange={true}
|
||||||
|
onChange={this.onInputChange}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</Form>
|
||||||
|
</ModalBody>
|
||||||
|
|
||||||
|
<ModalFooter>
|
||||||
|
<Button
|
||||||
|
onPress={onModalClose}
|
||||||
|
>
|
||||||
|
{translate('Cancel')}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<SpinnerButton
|
||||||
|
isSpinning={isSaving}
|
||||||
|
onPress={this.onSavePress}
|
||||||
|
>
|
||||||
|
{translate('Save')}
|
||||||
|
</SpinnerButton>
|
||||||
|
</ModalFooter>
|
||||||
|
</ModalContent>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
|
@ -14,6 +14,7 @@ import IndexerSelectInputConnector from './IndexerSelectInputConnector';
|
||||||
import KeyValueListInput from './KeyValueListInput';
|
import KeyValueListInput from './KeyValueListInput';
|
||||||
import MetadataProfileSelectInputConnector from './MetadataProfileSelectInputConnector';
|
import MetadataProfileSelectInputConnector from './MetadataProfileSelectInputConnector';
|
||||||
import MonitorAlbumsSelectInput from './MonitorAlbumsSelectInput';
|
import MonitorAlbumsSelectInput from './MonitorAlbumsSelectInput';
|
||||||
|
import MonitorNewItemsSelectInput from './MonitorNewItemsSelectInput';
|
||||||
import NumberInput from './NumberInput';
|
import NumberInput from './NumberInput';
|
||||||
import OAuthInputConnector from './OAuthInputConnector';
|
import OAuthInputConnector from './OAuthInputConnector';
|
||||||
import PasswordInput from './PasswordInput';
|
import PasswordInput from './PasswordInput';
|
||||||
|
@ -52,6 +53,9 @@ function getComponent(type) {
|
||||||
case inputTypes.MONITOR_ALBUMS_SELECT:
|
case inputTypes.MONITOR_ALBUMS_SELECT:
|
||||||
return MonitorAlbumsSelectInput;
|
return MonitorAlbumsSelectInput;
|
||||||
|
|
||||||
|
case inputTypes.MONITOR_NEW_ITEMS_SELECT:
|
||||||
|
return MonitorNewItemsSelectInput;
|
||||||
|
|
||||||
case inputTypes.NUMBER:
|
case inputTypes.NUMBER:
|
||||||
return NumberInput;
|
return NumberInput;
|
||||||
|
|
||||||
|
|
50
frontend/src/Components/Form/MonitorNewItemsSelectInput.js
Normal file
50
frontend/src/Components/Form/MonitorNewItemsSelectInput.js
Normal file
|
@ -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 (
|
||||||
|
<SelectInput
|
||||||
|
values={values}
|
||||||
|
{...otherProps}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
MonitorNewItemsSelectInput.propTypes = {
|
||||||
|
includeNoChange: PropTypes.bool.isRequired,
|
||||||
|
includeMixed: PropTypes.bool.isRequired,
|
||||||
|
onChange: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
MonitorNewItemsSelectInput.defaultProps = {
|
||||||
|
includeNoChange: false,
|
||||||
|
includeMixed: false
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MonitorNewItemsSelectInput;
|
|
@ -5,6 +5,7 @@ export const DEVICE = 'device';
|
||||||
export const PLAYLIST = 'playlist';
|
export const PLAYLIST = 'playlist';
|
||||||
export const KEY_VALUE_LIST = 'keyValueList';
|
export const KEY_VALUE_LIST = 'keyValueList';
|
||||||
export const MONITOR_ALBUMS_SELECT = 'monitorAlbumsSelect';
|
export const MONITOR_ALBUMS_SELECT = 'monitorAlbumsSelect';
|
||||||
|
export const MONITOR_NEW_ITEMS_SELECT = 'monitorNewItemsSelect';
|
||||||
export const NUMBER = 'number';
|
export const NUMBER = 'number';
|
||||||
export const OAUTH = 'oauth';
|
export const OAUTH = 'oauth';
|
||||||
export const PASSWORD = 'password';
|
export const PASSWORD = 'password';
|
||||||
|
@ -31,6 +32,7 @@ export const all = [
|
||||||
PLAYLIST,
|
PLAYLIST,
|
||||||
KEY_VALUE_LIST,
|
KEY_VALUE_LIST,
|
||||||
MONITOR_ALBUMS_SELECT,
|
MONITOR_ALBUMS_SELECT,
|
||||||
|
MONITOR_NEW_ITEMS_SELECT,
|
||||||
NUMBER,
|
NUMBER,
|
||||||
OAUTH,
|
OAUTH,
|
||||||
PASSWORD,
|
PASSWORD,
|
||||||
|
|
|
@ -85,6 +85,7 @@ class AddNewAlbumModalContentConnector extends Component {
|
||||||
foreignAlbumId,
|
foreignAlbumId,
|
||||||
rootFolderPath,
|
rootFolderPath,
|
||||||
monitor,
|
monitor,
|
||||||
|
monitorNewItems,
|
||||||
qualityProfileId,
|
qualityProfileId,
|
||||||
metadataProfileId,
|
metadataProfileId,
|
||||||
tags
|
tags
|
||||||
|
@ -94,6 +95,7 @@ class AddNewAlbumModalContentConnector extends Component {
|
||||||
foreignAlbumId,
|
foreignAlbumId,
|
||||||
rootFolderPath: rootFolderPath.value,
|
rootFolderPath: rootFolderPath.value,
|
||||||
monitor: monitor.value,
|
monitor: monitor.value,
|
||||||
|
monitorNewItems: monitorNewItems.value,
|
||||||
qualityProfileId: qualityProfileId.value,
|
qualityProfileId: qualityProfileId.value,
|
||||||
metadataProfileId: metadataProfileId.value,
|
metadataProfileId: metadataProfileId.value,
|
||||||
tags: tags.value,
|
tags: tags.value,
|
||||||
|
@ -120,6 +122,7 @@ AddNewAlbumModalContentConnector.propTypes = {
|
||||||
foreignAlbumId: PropTypes.string.isRequired,
|
foreignAlbumId: PropTypes.string.isRequired,
|
||||||
rootFolderPath: PropTypes.object,
|
rootFolderPath: PropTypes.object,
|
||||||
monitor: PropTypes.object.isRequired,
|
monitor: PropTypes.object.isRequired,
|
||||||
|
monitorNewItems: PropTypes.object.isRequired,
|
||||||
qualityProfileId: PropTypes.object,
|
qualityProfileId: PropTypes.object,
|
||||||
metadataProfileId: PropTypes.object,
|
metadataProfileId: PropTypes.object,
|
||||||
noneMetadataProfileId: PropTypes.number.isRequired,
|
noneMetadataProfileId: PropTypes.number.isRequired,
|
||||||
|
|
|
@ -57,6 +57,7 @@ class AddNewArtistModalContentConnector extends Component {
|
||||||
foreignArtistId,
|
foreignArtistId,
|
||||||
rootFolderPath,
|
rootFolderPath,
|
||||||
monitor,
|
monitor,
|
||||||
|
monitorNewItems,
|
||||||
qualityProfileId,
|
qualityProfileId,
|
||||||
metadataProfileId,
|
metadataProfileId,
|
||||||
tags
|
tags
|
||||||
|
@ -66,6 +67,7 @@ class AddNewArtistModalContentConnector extends Component {
|
||||||
foreignArtistId,
|
foreignArtistId,
|
||||||
rootFolderPath: rootFolderPath.value,
|
rootFolderPath: rootFolderPath.value,
|
||||||
monitor: monitor.value,
|
monitor: monitor.value,
|
||||||
|
monitorNewItems: monitorNewItems.value,
|
||||||
qualityProfileId: qualityProfileId.value,
|
qualityProfileId: qualityProfileId.value,
|
||||||
metadataProfileId: metadataProfileId.value,
|
metadataProfileId: metadataProfileId.value,
|
||||||
tags: tags.value,
|
tags: tags.value,
|
||||||
|
@ -91,6 +93,7 @@ AddNewArtistModalContentConnector.propTypes = {
|
||||||
foreignArtistId: PropTypes.string.isRequired,
|
foreignArtistId: PropTypes.string.isRequired,
|
||||||
rootFolderPath: PropTypes.object,
|
rootFolderPath: PropTypes.object,
|
||||||
monitor: PropTypes.object.isRequired,
|
monitor: PropTypes.object.isRequired,
|
||||||
|
monitorNewItems: PropTypes.object.isRequired,
|
||||||
qualityProfileId: PropTypes.object,
|
qualityProfileId: PropTypes.object,
|
||||||
metadataProfileId: PropTypes.object,
|
metadataProfileId: PropTypes.object,
|
||||||
tags: PropTypes.object.isRequired,
|
tags: PropTypes.object.isRequired,
|
||||||
|
|
|
@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import ArtistMetadataProfilePopoverContent from 'AddArtist/ArtistMetadataProfilePopoverContent';
|
import ArtistMetadataProfilePopoverContent from 'AddArtist/ArtistMetadataProfilePopoverContent';
|
||||||
import ArtistMonitoringOptionsPopoverContent from 'AddArtist/ArtistMonitoringOptionsPopoverContent';
|
import ArtistMonitoringOptionsPopoverContent from 'AddArtist/ArtistMonitoringOptionsPopoverContent';
|
||||||
|
import ArtistMonitorNewItemsOptionsPopoverContent from 'AddArtist/ArtistMonitorNewItemsOptionsPopoverContent';
|
||||||
import Form from 'Components/Form/Form';
|
import Form from 'Components/Form/Form';
|
||||||
import FormGroup from 'Components/Form/FormGroup';
|
import FormGroup from 'Components/Form/FormGroup';
|
||||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||||
|
@ -32,6 +33,7 @@ class AddArtistOptionsForm extends Component {
|
||||||
const {
|
const {
|
||||||
rootFolderPath,
|
rootFolderPath,
|
||||||
monitor,
|
monitor,
|
||||||
|
monitorNewItems,
|
||||||
qualityProfileId,
|
qualityProfileId,
|
||||||
metadataProfileId,
|
metadataProfileId,
|
||||||
includeNoneMetadataProfile,
|
includeNoneMetadataProfile,
|
||||||
|
@ -76,11 +78,37 @@ class AddArtistOptionsForm extends Component {
|
||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.MONITOR_ALBUMS_SELECT}
|
type={inputTypes.MONITOR_ALBUMS_SELECT}
|
||||||
name="monitor"
|
name="monitor"
|
||||||
|
helpText={translate('MonitoringOptionsHelpText')}
|
||||||
onChange={onInputChange}
|
onChange={onInputChange}
|
||||||
{...monitor}
|
{...monitor}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
|
<FormGroup>
|
||||||
|
<FormLabel>
|
||||||
|
{translate('MonitorNewItems')}
|
||||||
|
<Popover
|
||||||
|
anchor={
|
||||||
|
<Icon
|
||||||
|
className={styles.labelIcon}
|
||||||
|
name={icons.INFO}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
title={translate('MonitorNewItems')}
|
||||||
|
body={<ArtistMonitorNewItemsOptionsPopoverContent />}
|
||||||
|
position={tooltipPositions.RIGHT}
|
||||||
|
/>
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.MONITOR_NEW_ITEMS_SELECT}
|
||||||
|
name="monitorNewItems"
|
||||||
|
helpText={translate('MonitorNewItemsHelpText')}
|
||||||
|
{...monitorNewItems}
|
||||||
|
onChange={onInputChange}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{translate('QualityProfile')}
|
{translate('QualityProfile')}
|
||||||
|
@ -143,6 +171,7 @@ class AddArtistOptionsForm extends Component {
|
||||||
AddArtistOptionsForm.propTypes = {
|
AddArtistOptionsForm.propTypes = {
|
||||||
rootFolderPath: PropTypes.object,
|
rootFolderPath: PropTypes.object,
|
||||||
monitor: PropTypes.object.isRequired,
|
monitor: PropTypes.object.isRequired,
|
||||||
|
monitorNewItems: PropTypes.string.isRequired,
|
||||||
qualityProfileId: PropTypes.object,
|
qualityProfileId: PropTypes.object,
|
||||||
metadataProfileId: PropTypes.object,
|
metadataProfileId: PropTypes.object,
|
||||||
showMetadataProfile: PropTypes.bool.isRequired,
|
showMetadataProfile: PropTypes.bool.isRequired,
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import ArtistMonitorNewItemsOptionsPopoverContent from 'AddArtist/ArtistMonitorNewItemsOptionsPopoverContent';
|
||||||
import Alert from 'Components/Alert';
|
import Alert from 'Components/Alert';
|
||||||
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
||||||
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
||||||
|
import FieldSet from 'Components/FieldSet';
|
||||||
import Form from 'Components/Form/Form';
|
import Form from 'Components/Form/Form';
|
||||||
import FormGroup from 'Components/Form/FormGroup';
|
import FormGroup from 'Components/Form/FormGroup';
|
||||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||||
|
@ -74,6 +76,7 @@ function EditImportListModalContent(props) {
|
||||||
enableAutomaticAdd,
|
enableAutomaticAdd,
|
||||||
shouldMonitor,
|
shouldMonitor,
|
||||||
rootFolderPath,
|
rootFolderPath,
|
||||||
|
monitorNewItems,
|
||||||
qualityProfileId,
|
qualityProfileId,
|
||||||
metadataProfileId,
|
metadataProfileId,
|
||||||
tags,
|
tags,
|
||||||
|
@ -112,6 +115,8 @@ function EditImportListModalContent(props) {
|
||||||
{message.value.message}
|
{message.value.message}
|
||||||
</Alert>
|
</Alert>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<FieldSet legend={translate('ImportListSettings')} >
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{translate('Name')}
|
{translate('Name')}
|
||||||
|
@ -165,7 +170,9 @@ function EditImportListModalContent(props) {
|
||||||
onChange={onInputChange}
|
onChange={onInputChange}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
</FieldSet>
|
||||||
|
|
||||||
|
<FieldSet legend={translate('AddedArtistSettings')} >
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{translate('RootFolder')}
|
{translate('RootFolder')}
|
||||||
|
@ -180,6 +187,31 @@ function EditImportListModalContent(props) {
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
|
<FormGroup>
|
||||||
|
<FormLabel>
|
||||||
|
{translate('MonitorNewItems')}
|
||||||
|
<Popover
|
||||||
|
anchor={
|
||||||
|
<Icon
|
||||||
|
className={styles.labelIcon}
|
||||||
|
name={icons.INFO}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
title={translate('MonitorNewItems')}
|
||||||
|
body={<ArtistMonitorNewItemsOptionsPopoverContent />}
|
||||||
|
position={tooltipPositions.RIGHT}
|
||||||
|
/>
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.MONITOR_NEW_ITEMS_SELECT}
|
||||||
|
name="monitorNewItems"
|
||||||
|
helpText={translate('MonitorNewItemsHelpText')}
|
||||||
|
{...monitorNewItems}
|
||||||
|
onChange={onInputChange}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{translate('QualityProfile')}
|
{translate('QualityProfile')}
|
||||||
|
@ -211,7 +243,7 @@ function EditImportListModalContent(props) {
|
||||||
|
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{translate('LidarrTags')}
|
{translate('ReadarrTags')}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
|
||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
|
@ -222,10 +254,11 @@ function EditImportListModalContent(props) {
|
||||||
onChange={onInputChange}
|
onChange={onInputChange}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
</FieldSet>
|
||||||
|
|
||||||
{
|
{
|
||||||
!!fields && !!fields.length &&
|
!!fields && !!fields.length &&
|
||||||
<div>
|
<FieldSet legend={translate('ImportListSpecificSettings')} >
|
||||||
{
|
{
|
||||||
fields.map((field) => {
|
fields.map((field) => {
|
||||||
return (
|
return (
|
||||||
|
@ -241,7 +274,7 @@ function EditImportListModalContent(props) {
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</div>
|
</FieldSet>
|
||||||
}
|
}
|
||||||
|
|
||||||
</Form>
|
</Form>
|
||||||
|
|
|
@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ArtistMetadataProfilePopoverContent from 'AddArtist/ArtistMetadataProfilePopoverContent';
|
import ArtistMetadataProfilePopoverContent from 'AddArtist/ArtistMetadataProfilePopoverContent';
|
||||||
import ArtistMonitoringOptionsPopoverContent from 'AddArtist/ArtistMonitoringOptionsPopoverContent';
|
import ArtistMonitoringOptionsPopoverContent from 'AddArtist/ArtistMonitoringOptionsPopoverContent';
|
||||||
|
import ArtistMonitorNewItemsOptionsPopoverContent from 'AddArtist/ArtistMonitorNewItemsOptionsPopoverContent';
|
||||||
import Form from 'Components/Form/Form';
|
import Form from 'Components/Form/Form';
|
||||||
import FormGroup from 'Components/Form/FormGroup';
|
import FormGroup from 'Components/Form/FormGroup';
|
||||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||||
|
@ -43,6 +44,7 @@ function EditRootFolderModalContent(props) {
|
||||||
defaultQualityProfileId,
|
defaultQualityProfileId,
|
||||||
defaultMetadataProfileId,
|
defaultMetadataProfileId,
|
||||||
defaultMonitorOption,
|
defaultMonitorOption,
|
||||||
|
defaultNewItemMonitorOption,
|
||||||
defaultTags
|
defaultTags
|
||||||
} = item;
|
} = item;
|
||||||
|
|
||||||
|
@ -99,7 +101,7 @@ function EditRootFolderModalContent(props) {
|
||||||
|
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
Monitor
|
{translate('Monitor')}
|
||||||
|
|
||||||
<Popover
|
<Popover
|
||||||
anchor={
|
anchor={
|
||||||
|
@ -124,6 +126,31 @@ function EditRootFolderModalContent(props) {
|
||||||
|
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
|
<FormGroup>
|
||||||
|
<FormLabel>
|
||||||
|
{translate('MonitorNewItems')}
|
||||||
|
<Popover
|
||||||
|
anchor={
|
||||||
|
<Icon
|
||||||
|
className={styles.labelIcon}
|
||||||
|
name={icons.INFO}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
title={translate('MonitorNewItems')}
|
||||||
|
body={<ArtistMonitorNewItemsOptionsPopoverContent />}
|
||||||
|
position={tooltipPositions.RIGHT}
|
||||||
|
/>
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.MONITOR_NEW_ITEMS_SELECT}
|
||||||
|
name="defaultNewItemMonitorOption"
|
||||||
|
{...defaultNewItemMonitorOption}
|
||||||
|
onChange={onInputChange}
|
||||||
|
helpText={translate('MonitorNewItemsHelpText')}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{translate('QualityProfile')}
|
{translate('QualityProfile')}
|
||||||
|
|
|
@ -102,7 +102,8 @@ export const actionHandlers = handleThunks({
|
||||||
const {
|
const {
|
||||||
artistIds,
|
artistIds,
|
||||||
monitored,
|
monitored,
|
||||||
monitor
|
monitor,
|
||||||
|
monitorNewItems
|
||||||
} = payload;
|
} = payload;
|
||||||
|
|
||||||
const artist = [];
|
const artist = [];
|
||||||
|
@ -127,7 +128,8 @@ export const actionHandlers = handleThunks({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
artist,
|
artist,
|
||||||
monitoringOptions: { monitor }
|
monitoringOptions: { monitor },
|
||||||
|
monitorNewItems
|
||||||
}),
|
}),
|
||||||
dataType: 'json'
|
dataType: 'json'
|
||||||
}).request;
|
}).request;
|
||||||
|
|
|
@ -3,6 +3,7 @@ function getNewArtist(artist, payload) {
|
||||||
const {
|
const {
|
||||||
rootFolderPath,
|
rootFolderPath,
|
||||||
monitor,
|
monitor,
|
||||||
|
monitorNewItems,
|
||||||
qualityProfileId,
|
qualityProfileId,
|
||||||
metadataProfileId,
|
metadataProfileId,
|
||||||
artistType,
|
artistType,
|
||||||
|
@ -17,6 +18,7 @@ function getNewArtist(artist, payload) {
|
||||||
|
|
||||||
artist.addOptions = addOptions;
|
artist.addOptions = addOptions;
|
||||||
artist.monitored = true;
|
artist.monitored = true;
|
||||||
|
artist.monitorNewItems = monitorNewItems;
|
||||||
artist.qualityProfileId = qualityProfileId;
|
artist.qualityProfileId = qualityProfileId;
|
||||||
artist.metadataProfileId = metadataProfileId;
|
artist.metadataProfileId = metadataProfileId;
|
||||||
artist.rootFolderPath = rootFolderPath;
|
artist.rootFolderPath = rootFolderPath;
|
||||||
|
|
7
frontend/src/Utilities/Artist/monitorNewItemsOptions.js
Normal file
7
frontend/src/Utilities/Artist/monitorNewItemsOptions.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
const monitorNewItemsOptions = [
|
||||||
|
{ key: 'all', value: 'All Albums' },
|
||||||
|
{ key: 'none', value: 'None' },
|
||||||
|
{ key: 'new', value: 'New' }
|
||||||
|
];
|
||||||
|
|
||||||
|
export default monitorNewItemsOptions;
|
|
@ -36,10 +36,15 @@ namespace Lidarr.Api.V1.AlbumStudio
|
||||||
artist.Monitored = false;
|
artist.Monitored = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.MonitorNewItems.HasValue)
|
||||||
|
{
|
||||||
|
artist.MonitorNewItems = request.MonitorNewItems.Value;
|
||||||
|
}
|
||||||
|
|
||||||
_albumMonitoredService.SetAlbumMonitoredStatus(artist, request.MonitoringOptions);
|
_albumMonitoredService.SetAlbumMonitoredStatus(artist, request.MonitoringOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Accepted();
|
return Accepted(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,5 +7,6 @@ namespace Lidarr.Api.V1.AlbumStudio
|
||||||
{
|
{
|
||||||
public List<AlbumStudioArtistResource> Artist { get; set; }
|
public List<AlbumStudioArtistResource> Artist { get; set; }
|
||||||
public MonitoringOptions MonitoringOptions { get; set; }
|
public MonitoringOptions MonitoringOptions { get; set; }
|
||||||
|
public NewItemMonitorTypes? MonitorNewItems { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,11 @@ namespace Lidarr.Api.V1.Artist
|
||||||
artist.Monitored = resource.Monitored.Value;
|
artist.Monitored = resource.Monitored.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resource.MonitorNewItems.HasValue)
|
||||||
|
{
|
||||||
|
artist.MonitorNewItems = resource.MonitorNewItems.Value;
|
||||||
|
}
|
||||||
|
|
||||||
if (resource.QualityProfileId.HasValue)
|
if (resource.QualityProfileId.HasValue)
|
||||||
{
|
{
|
||||||
artist.QualityProfileId = resource.QualityProfileId.Value;
|
artist.QualityProfileId = resource.QualityProfileId.Value;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Core.Music;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Artist
|
namespace Lidarr.Api.V1.Artist
|
||||||
{
|
{
|
||||||
|
@ -6,6 +7,7 @@ namespace Lidarr.Api.V1.Artist
|
||||||
{
|
{
|
||||||
public List<int> ArtistIds { get; set; }
|
public List<int> ArtistIds { get; set; }
|
||||||
public bool? Monitored { get; set; }
|
public bool? Monitored { get; set; }
|
||||||
|
public NewItemMonitorTypes? MonitorNewItems { get; set; }
|
||||||
public int? QualityProfileId { get; set; }
|
public int? QualityProfileId { get; set; }
|
||||||
public int? MetadataProfileId { get; set; }
|
public int? MetadataProfileId { get; set; }
|
||||||
public string RootFolderPath { get; set; }
|
public string RootFolderPath { get; set; }
|
||||||
|
|
|
@ -46,6 +46,7 @@ namespace Lidarr.Api.V1.Artist
|
||||||
|
|
||||||
//Editing Only
|
//Editing Only
|
||||||
public bool Monitored { get; set; }
|
public bool Monitored { get; set; }
|
||||||
|
public NewItemMonitorTypes MonitorNewItems { get; set; }
|
||||||
|
|
||||||
public string RootFolderPath { get; set; }
|
public string RootFolderPath { get; set; }
|
||||||
public List<string> Genres { get; set; }
|
public List<string> Genres { get; set; }
|
||||||
|
@ -91,6 +92,7 @@ namespace Lidarr.Api.V1.Artist
|
||||||
Links = model.Metadata.Value.Links,
|
Links = model.Metadata.Value.Links,
|
||||||
|
|
||||||
Monitored = model.Monitored,
|
Monitored = model.Monitored,
|
||||||
|
MonitorNewItems = model.MonitorNewItems,
|
||||||
|
|
||||||
CleanName = model.CleanName,
|
CleanName = model.CleanName,
|
||||||
ForeignArtistId = model.Metadata.Value.ForeignArtistId,
|
ForeignArtistId = model.Metadata.Value.ForeignArtistId,
|
||||||
|
@ -138,6 +140,7 @@ namespace Lidarr.Api.V1.Artist
|
||||||
MetadataProfileId = resource.MetadataProfileId,
|
MetadataProfileId = resource.MetadataProfileId,
|
||||||
|
|
||||||
Monitored = resource.Monitored,
|
Monitored = resource.Monitored,
|
||||||
|
MonitorNewItems = resource.MonitorNewItems,
|
||||||
|
|
||||||
CleanName = resource.CleanName,
|
CleanName = resource.CleanName,
|
||||||
RootFolderPath = resource.RootFolderPath,
|
RootFolderPath = resource.RootFolderPath,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using NzbDrone.Core.ImportLists;
|
using NzbDrone.Core.ImportLists;
|
||||||
|
using NzbDrone.Core.Music;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.ImportLists
|
namespace Lidarr.Api.V1.ImportLists
|
||||||
{
|
{
|
||||||
|
@ -7,6 +8,7 @@ namespace Lidarr.Api.V1.ImportLists
|
||||||
public bool EnableAutomaticAdd { get; set; }
|
public bool EnableAutomaticAdd { get; set; }
|
||||||
public ImportListMonitorType ShouldMonitor { get; set; }
|
public ImportListMonitorType ShouldMonitor { get; set; }
|
||||||
public string RootFolderPath { get; set; }
|
public string RootFolderPath { get; set; }
|
||||||
|
public NewItemMonitorTypes MonitorNewItems { get; set; }
|
||||||
public int QualityProfileId { get; set; }
|
public int QualityProfileId { get; set; }
|
||||||
public int MetadataProfileId { get; set; }
|
public int MetadataProfileId { get; set; }
|
||||||
public ImportListType ListType { get; set; }
|
public ImportListType ListType { get; set; }
|
||||||
|
@ -27,6 +29,7 @@ namespace Lidarr.Api.V1.ImportLists
|
||||||
resource.EnableAutomaticAdd = definition.EnableAutomaticAdd;
|
resource.EnableAutomaticAdd = definition.EnableAutomaticAdd;
|
||||||
resource.ShouldMonitor = definition.ShouldMonitor;
|
resource.ShouldMonitor = definition.ShouldMonitor;
|
||||||
resource.RootFolderPath = definition.RootFolderPath;
|
resource.RootFolderPath = definition.RootFolderPath;
|
||||||
|
resource.MonitorNewItems = definition.MonitorNewItems;
|
||||||
resource.QualityProfileId = definition.ProfileId;
|
resource.QualityProfileId = definition.ProfileId;
|
||||||
resource.MetadataProfileId = definition.MetadataProfileId;
|
resource.MetadataProfileId = definition.MetadataProfileId;
|
||||||
resource.ListType = definition.ListType;
|
resource.ListType = definition.ListType;
|
||||||
|
@ -47,6 +50,7 @@ namespace Lidarr.Api.V1.ImportLists
|
||||||
definition.EnableAutomaticAdd = resource.EnableAutomaticAdd;
|
definition.EnableAutomaticAdd = resource.EnableAutomaticAdd;
|
||||||
definition.ShouldMonitor = resource.ShouldMonitor;
|
definition.ShouldMonitor = resource.ShouldMonitor;
|
||||||
definition.RootFolderPath = resource.RootFolderPath;
|
definition.RootFolderPath = resource.RootFolderPath;
|
||||||
|
definition.MonitorNewItems = resource.MonitorNewItems;
|
||||||
definition.ProfileId = resource.QualityProfileId;
|
definition.ProfileId = resource.QualityProfileId;
|
||||||
definition.MetadataProfileId = resource.MetadataProfileId;
|
definition.MetadataProfileId = resource.MetadataProfileId;
|
||||||
definition.ListType = resource.ListType;
|
definition.ListType = resource.ListType;
|
||||||
|
|
|
@ -13,6 +13,7 @@ namespace Lidarr.Api.V1.RootFolders
|
||||||
public int DefaultMetadataProfileId { get; set; }
|
public int DefaultMetadataProfileId { get; set; }
|
||||||
public int DefaultQualityProfileId { get; set; }
|
public int DefaultQualityProfileId { get; set; }
|
||||||
public MonitorTypes DefaultMonitorOption { get; set; }
|
public MonitorTypes DefaultMonitorOption { get; set; }
|
||||||
|
public NewItemMonitorTypes DefaultNewItemMonitorOption { get; set; }
|
||||||
public HashSet<int> DefaultTags { get; set; }
|
public HashSet<int> DefaultTags { get; set; }
|
||||||
|
|
||||||
public bool Accessible { get; set; }
|
public bool Accessible { get; set; }
|
||||||
|
@ -38,6 +39,7 @@ namespace Lidarr.Api.V1.RootFolders
|
||||||
DefaultMetadataProfileId = model.DefaultMetadataProfileId,
|
DefaultMetadataProfileId = model.DefaultMetadataProfileId,
|
||||||
DefaultQualityProfileId = model.DefaultQualityProfileId,
|
DefaultQualityProfileId = model.DefaultQualityProfileId,
|
||||||
DefaultMonitorOption = model.DefaultMonitorOption,
|
DefaultMonitorOption = model.DefaultMonitorOption,
|
||||||
|
DefaultNewItemMonitorOption = model.DefaultNewItemMonitorOption,
|
||||||
DefaultTags = model.DefaultTags,
|
DefaultTags = model.DefaultTags,
|
||||||
|
|
||||||
Accessible = model.Accessible,
|
Accessible = model.Accessible,
|
||||||
|
@ -62,7 +64,8 @@ namespace Lidarr.Api.V1.RootFolders
|
||||||
DefaultMetadataProfileId = resource.DefaultMetadataProfileId,
|
DefaultMetadataProfileId = resource.DefaultMetadataProfileId,
|
||||||
DefaultQualityProfileId = resource.DefaultQualityProfileId,
|
DefaultQualityProfileId = resource.DefaultQualityProfileId,
|
||||||
DefaultMonitorOption = resource.DefaultMonitorOption,
|
DefaultMonitorOption = resource.DefaultMonitorOption,
|
||||||
DefaultTags = resource.DefaultTags
|
DefaultNewItemMonitorOption = resource.DefaultNewItemMonitorOption,
|
||||||
|
DefaultTags = resource.DefaultTags,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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<MonitorNewAlbumService>
|
||||||
|
{
|
||||||
|
private List<Album> _albums;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_albums = Builder<Album>.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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -74,6 +74,10 @@ namespace NzbDrone.Core.Test.MusicTests
|
||||||
Mocker.GetMock<IRootFolderService>()
|
Mocker.GetMock<IRootFolderService>()
|
||||||
.Setup(x => x.All())
|
.Setup(x => x.All())
|
||||||
.Returns(new List<RootFolder>());
|
.Returns(new List<RootFolder>());
|
||||||
|
|
||||||
|
Mocker.GetMock<IMonitorNewAlbumService>()
|
||||||
|
.Setup(x => x.ShouldMonitorNewAlbum(It.IsAny<Album>(), It.IsAny<List<Album>>(), It.IsAny<NewItemMonitorTypes>()))
|
||||||
|
.Returns(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenNewArtistInfo(Artist artist)
|
private void GivenNewArtistInfo(Artist artist)
|
||||||
|
@ -143,7 +147,30 @@ namespace NzbDrone.Core.Test.MusicTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[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<Album>.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<IMonitorNewAlbumService>()
|
||||||
|
.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<IArtistService>()
|
Mocker.GetMock<IArtistService>()
|
||||||
.Setup(x => x.DeleteArtist(It.IsAny<int>(), It.IsAny<bool>(), It.IsAny<bool>()));
|
.Setup(x => x.DeleteArtist(It.IsAny<int>(), It.IsAny<bool>(), It.IsAny<bool>()));
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
using NzbDrone.Core.Music;
|
||||||
using NzbDrone.Core.ThingiProvider;
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
|
||||||
namespace NzbDrone.Core.ImportLists
|
namespace NzbDrone.Core.ImportLists
|
||||||
|
@ -6,6 +7,7 @@ namespace NzbDrone.Core.ImportLists
|
||||||
{
|
{
|
||||||
public bool EnableAutomaticAdd { get; set; }
|
public bool EnableAutomaticAdd { get; set; }
|
||||||
public ImportListMonitorType ShouldMonitor { get; set; }
|
public ImportListMonitorType ShouldMonitor { get; set; }
|
||||||
|
public NewItemMonitorTypes MonitorNewItems { get; set; }
|
||||||
public int ProfileId { get; set; }
|
public int ProfileId { get; set; }
|
||||||
public int MetadataProfileId { get; set; }
|
public int MetadataProfileId { get; set; }
|
||||||
public string RootFolderPath { get; set; }
|
public string RootFolderPath { get; set; }
|
||||||
|
|
|
@ -270,6 +270,7 @@ namespace NzbDrone.Core.ImportLists
|
||||||
Name = report.Artist
|
Name = report.Artist
|
||||||
},
|
},
|
||||||
Monitored = monitored,
|
Monitored = monitored,
|
||||||
|
MonitorNewItems = importList.MonitorNewItems,
|
||||||
RootFolderPath = importList.RootFolderPath,
|
RootFolderPath = importList.RootFolderPath,
|
||||||
QualityProfileId = importList.ProfileId,
|
QualityProfileId = importList.ProfileId,
|
||||||
MetadataProfileId = importList.MetadataProfileId,
|
MetadataProfileId = importList.MetadataProfileId,
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
"About": "About",
|
"About": "About",
|
||||||
"Absolute": "Absolute",
|
"Absolute": "Absolute",
|
||||||
"Actions": "Actions",
|
"Actions": "Actions",
|
||||||
|
"AddedArtistSettings": "Added Artist Settings",
|
||||||
"AddImportListExclusionHelpText": "Prevent artist from being added to Lidarr by Import lists",
|
"AddImportListExclusionHelpText": "Prevent artist from being added to Lidarr by Import lists",
|
||||||
"AddingTag": "Adding tag",
|
"AddingTag": "Adding tag",
|
||||||
"AddListExclusion": "Add List Exclusion",
|
"AddListExclusion": "Add List Exclusion",
|
||||||
|
@ -113,7 +114,7 @@
|
||||||
"DBMigration": "DB Migration",
|
"DBMigration": "DB Migration",
|
||||||
"DefaultLidarrTags": "Default Lidarr Tags",
|
"DefaultLidarrTags": "Default Lidarr Tags",
|
||||||
"DefaultMetadataProfileIdHelpText": "Default Metadata Profile for artists detected in this folder",
|
"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",
|
"DefaultQualityProfileIdHelpText": "Default Quality Profile for artists detected in this folder",
|
||||||
"DefaultTagsHelpText": "Default Lidarr Tags for artists detected in this folder",
|
"DefaultTagsHelpText": "Default Lidarr Tags for artists detected in this folder",
|
||||||
"DelayingDownloadUntilInterp": "Delaying download until {0} at {1}",
|
"DelayingDownloadUntilInterp": "Delaying download until {0} at {1}",
|
||||||
|
@ -261,7 +262,8 @@
|
||||||
"Importing": "Importing",
|
"Importing": "Importing",
|
||||||
"ImportListExclusions": "Import List Exclusions",
|
"ImportListExclusions": "Import List Exclusions",
|
||||||
"ImportLists": "Import Lists",
|
"ImportLists": "Import Lists",
|
||||||
"ImportListSettings": "Import List Settings",
|
"ImportListSettings": "General Import List Settings",
|
||||||
|
"ImportListSpecificSettings": "Import List Specific Settings",
|
||||||
"IncludeHealthWarningsHelpText": "Include Health Warnings",
|
"IncludeHealthWarningsHelpText": "Include Health Warnings",
|
||||||
"IncludePreferredWhenRenaming": "Include Preferred when Renaming",
|
"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",
|
"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)",
|
"MissingTracksArtistMonitored": "Missing Tracks (Artist monitored)",
|
||||||
"MissingTracksArtistNotMonitored": "Missing Tracks (Artist not monitored)",
|
"MissingTracksArtistNotMonitored": "Missing Tracks (Artist not monitored)",
|
||||||
"Mode": "Mode",
|
"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",
|
"MonitorArtist": "Monitor Artist",
|
||||||
"Monitored": "Monitored",
|
"Monitored": "Monitored",
|
||||||
"MonitoredHelpText": "Download monitored albums from this artist",
|
"MonitoredHelpText": "Download monitored albums from this artist",
|
||||||
"MonitoringOptions": "Monitoring Options",
|
"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",
|
"MoreInfo": "More Info",
|
||||||
"MultiDiscTrackFormat": "Multi Disc Track Format",
|
"MultiDiscTrackFormat": "Multi Disc Track Format",
|
||||||
"MusicBrainzAlbumID": "MusicBrainz Album ID",
|
"MusicBrainzAlbumID": "MusicBrainz Album ID",
|
||||||
|
@ -366,6 +373,7 @@
|
||||||
"NamingSettings": "Naming Settings",
|
"NamingSettings": "Naming Settings",
|
||||||
"NETCore": ".NET",
|
"NETCore": ".NET",
|
||||||
"New": "New",
|
"New": "New",
|
||||||
|
"NewAlbums": "New Albums",
|
||||||
"NoBackupsAreAvailable": "No backups are available",
|
"NoBackupsAreAvailable": "No backups are available",
|
||||||
"NoHistory": "No history.",
|
"NoHistory": "No history.",
|
||||||
"NoLeaveIt": "No, Leave It",
|
"NoLeaveIt": "No, Leave It",
|
||||||
|
|
|
@ -337,6 +337,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport
|
||||||
artist.MetadataProfileId = rootFolder.DefaultMetadataProfileId;
|
artist.MetadataProfileId = rootFolder.DefaultMetadataProfileId;
|
||||||
artist.QualityProfileId = rootFolder.DefaultQualityProfileId;
|
artist.QualityProfileId = rootFolder.DefaultQualityProfileId;
|
||||||
artist.Monitored = rootFolder.DefaultMonitorOption != MonitorTypes.None;
|
artist.Monitored = rootFolder.DefaultMonitorOption != MonitorTypes.None;
|
||||||
|
artist.MonitorNewItems = rootFolder.DefaultNewItemMonitorOption;
|
||||||
artist.Tags = rootFolder.DefaultTags;
|
artist.Tags = rootFolder.DefaultTags;
|
||||||
artist.AddOptions = new AddArtistOptions
|
artist.AddOptions = new AddArtistOptions
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,7 @@ namespace NzbDrone.Core.Music
|
||||||
public string CleanName { get; set; }
|
public string CleanName { get; set; }
|
||||||
public string SortName { get; set; }
|
public string SortName { get; set; }
|
||||||
public bool Monitored { get; set; }
|
public bool Monitored { get; set; }
|
||||||
|
public NewItemMonitorTypes MonitorNewItems { get; set; }
|
||||||
public DateTime? LastInfoSync { get; set; }
|
public DateTime? LastInfoSync { get; set; }
|
||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
public string RootFolderPath { get; set; }
|
public string RootFolderPath { get; set; }
|
||||||
|
@ -70,6 +71,7 @@ namespace NzbDrone.Core.Music
|
||||||
Id = other.Id;
|
Id = other.Id;
|
||||||
ArtistMetadataId = other.ArtistMetadataId;
|
ArtistMetadataId = other.ArtistMetadataId;
|
||||||
Monitored = other.Monitored;
|
Monitored = other.Monitored;
|
||||||
|
MonitorNewItems = other.MonitorNewItems;
|
||||||
LastInfoSync = other.LastInfoSync;
|
LastInfoSync = other.LastInfoSync;
|
||||||
Path = other.Path;
|
Path = other.Path;
|
||||||
RootFolderPath = other.RootFolderPath;
|
RootFolderPath = other.RootFolderPath;
|
||||||
|
@ -93,6 +95,7 @@ namespace NzbDrone.Core.Music
|
||||||
AddOptions = other.AddOptions;
|
AddOptions = other.AddOptions;
|
||||||
RootFolderPath = other.RootFolderPath;
|
RootFolderPath = other.RootFolderPath;
|
||||||
Monitored = other.Monitored;
|
Monitored = other.Monitored;
|
||||||
|
MonitorNewItems = other.MonitorNewItems;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
src/NzbDrone.Core/Music/Model/MonitorTypes.cs
Normal file
14
src/NzbDrone.Core/Music/Model/MonitorTypes.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
namespace NzbDrone.Core.Music
|
||||||
|
{
|
||||||
|
public enum MonitorTypes
|
||||||
|
{
|
||||||
|
All,
|
||||||
|
Future,
|
||||||
|
Missing,
|
||||||
|
Existing,
|
||||||
|
Latest,
|
||||||
|
First,
|
||||||
|
None,
|
||||||
|
Unknown
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,16 +14,4 @@ namespace NzbDrone.Core.Music
|
||||||
public List<string> AlbumsToMonitor { get; set; }
|
public List<string> AlbumsToMonitor { get; set; }
|
||||||
public bool Monitored { get; set; }
|
public bool Monitored { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum MonitorTypes
|
|
||||||
{
|
|
||||||
All,
|
|
||||||
Future,
|
|
||||||
Missing,
|
|
||||||
Existing,
|
|
||||||
Latest,
|
|
||||||
First,
|
|
||||||
None,
|
|
||||||
Unknown
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
9
src/NzbDrone.Core/Music/Model/NewItemMonitorTypes.cs
Normal file
9
src/NzbDrone.Core/Music/Model/NewItemMonitorTypes.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace NzbDrone.Core.Music
|
||||||
|
{
|
||||||
|
public enum NewItemMonitorTypes
|
||||||
|
{
|
||||||
|
All,
|
||||||
|
None,
|
||||||
|
New
|
||||||
|
}
|
||||||
|
}
|
44
src/NzbDrone.Core/Music/Services/MonitorNewAlbumService.cs
Normal file
44
src/NzbDrone.Core/Music/Services/MonitorNewAlbumService.cs
Normal file
|
@ -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<Album> existingAlbums, NewItemMonitorTypes monitorNewItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MonitorNewAlbumService : IMonitorNewAlbumService
|
||||||
|
{
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public MonitorNewAlbumService(Logger logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShouldMonitorNewAlbum(Album addedAlbum, List<Album> 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}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -103,10 +103,8 @@ namespace NzbDrone.Core.Music
|
||||||
local.AlbumRelease = entity;
|
local.AlbumRelease = entity;
|
||||||
local.AlbumReleaseId = entity.Id;
|
local.AlbumReleaseId = entity.Id;
|
||||||
local.ArtistMetadataId = remote.ArtistMetadata.Value.Id;
|
local.ArtistMetadataId = remote.ArtistMetadata.Value.Id;
|
||||||
remote.Id = local.Id;
|
|
||||||
remote.TrackFileId = local.TrackFileId;
|
remote.UseDbFieldsFrom(local);
|
||||||
remote.AlbumReleaseId = local.AlbumReleaseId;
|
|
||||||
remote.ArtistMetadataId = local.ArtistMetadataId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void AddChildren(List<Track> children)
|
protected override void AddChildren(List<Track> children)
|
||||||
|
|
|
@ -35,6 +35,7 @@ namespace NzbDrone.Core.Music
|
||||||
private readonly IHistoryService _historyService;
|
private readonly IHistoryService _historyService;
|
||||||
private readonly IRootFolderService _rootFolderService;
|
private readonly IRootFolderService _rootFolderService;
|
||||||
private readonly ICheckIfArtistShouldBeRefreshed _checkIfArtistShouldBeRefreshed;
|
private readonly ICheckIfArtistShouldBeRefreshed _checkIfArtistShouldBeRefreshed;
|
||||||
|
private readonly IMonitorNewAlbumService _monitorNewAlbumService;
|
||||||
private readonly IConfigService _configService;
|
private readonly IConfigService _configService;
|
||||||
private readonly IImportListExclusionService _importListExclusionService;
|
private readonly IImportListExclusionService _importListExclusionService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
@ -50,6 +51,7 @@ namespace NzbDrone.Core.Music
|
||||||
IHistoryService historyService,
|
IHistoryService historyService,
|
||||||
IRootFolderService rootFolderService,
|
IRootFolderService rootFolderService,
|
||||||
ICheckIfArtistShouldBeRefreshed checkIfArtistShouldBeRefreshed,
|
ICheckIfArtistShouldBeRefreshed checkIfArtistShouldBeRefreshed,
|
||||||
|
IMonitorNewAlbumService monitorNewAlbumService,
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
IImportListExclusionService importListExclusionService,
|
IImportListExclusionService importListExclusionService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
|
@ -65,6 +67,7 @@ namespace NzbDrone.Core.Music
|
||||||
_historyService = historyService;
|
_historyService = historyService;
|
||||||
_rootFolderService = rootFolderService;
|
_rootFolderService = rootFolderService;
|
||||||
_checkIfArtistShouldBeRefreshed = checkIfArtistShouldBeRefreshed;
|
_checkIfArtistShouldBeRefreshed = checkIfArtistShouldBeRefreshed;
|
||||||
|
_monitorNewAlbumService = monitorNewAlbumService;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
_importListExclusionService = importListExclusionService;
|
_importListExclusionService = importListExclusionService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
@ -238,6 +241,15 @@ namespace NzbDrone.Core.Music
|
||||||
local.ArtistMetadataId = entity.Metadata.Value.Id;
|
local.ArtistMetadataId = entity.Metadata.Value.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void ProcessChildren(Artist entity, SortedChildren children)
|
||||||
|
{
|
||||||
|
foreach (var album in children.Added)
|
||||||
|
{
|
||||||
|
// all existing child albums count as updated as we don't have proper data yet.
|
||||||
|
album.Monitored = _monitorNewAlbumService.ShouldMonitorNewAlbum(album, children.Updated, entity.MonitorNewItems);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void AddChildren(List<Album> children)
|
protected override void AddChildren(List<Album> children)
|
||||||
{
|
{
|
||||||
_albumService.InsertMany(children);
|
_albumService.InsertMany(children);
|
||||||
|
|
|
@ -93,6 +93,11 @@ namespace NzbDrone.Core.Music
|
||||||
|
|
||||||
protected abstract void PrepareNewChild(TChild child, TEntity entity);
|
protected abstract void PrepareNewChild(TChild child, TEntity entity);
|
||||||
protected abstract void PrepareExistingChild(TChild local, TChild remote, 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<TChild> children);
|
protected abstract void AddChildren(List<TChild> children);
|
||||||
protected abstract bool RefreshChildren(SortedChildren localChildren, List<TChild> remoteChildren, bool forceChildRefresh, bool forceUpdateFileTags, DateTime? lastUpdate);
|
protected abstract bool RefreshChildren(SortedChildren localChildren, List<TChild> remoteChildren, bool forceChildRefresh, bool forceUpdateFileTags, DateTime? lastUpdate);
|
||||||
|
|
||||||
|
@ -274,6 +279,8 @@ namespace NzbDrone.Core.Music
|
||||||
sortedChildren.Merged.Count,
|
sortedChildren.Merged.Count,
|
||||||
sortedChildren.Deleted.Count);
|
sortedChildren.Deleted.Count);
|
||||||
|
|
||||||
|
ProcessChildren(entity, sortedChildren);
|
||||||
|
|
||||||
// Add in the new children (we have checked that foreign IDs don't clash)
|
// Add in the new children (we have checked that foreign IDs don't clash)
|
||||||
AddChildren(sortedChildren.Added);
|
AddChildren(sortedChildren.Added);
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace NzbDrone.Core.RootFolders
|
||||||
public int DefaultMetadataProfileId { get; set; }
|
public int DefaultMetadataProfileId { get; set; }
|
||||||
public int DefaultQualityProfileId { get; set; }
|
public int DefaultQualityProfileId { get; set; }
|
||||||
public MonitorTypes DefaultMonitorOption { get; set; }
|
public MonitorTypes DefaultMonitorOption { get; set; }
|
||||||
|
public NewItemMonitorTypes DefaultNewItemMonitorOption { get; set; }
|
||||||
public HashSet<int> DefaultTags { get; set; }
|
public HashSet<int> DefaultTags { get; set; }
|
||||||
|
|
||||||
public bool Accessible { get; set; }
|
public bool Accessible { get; set; }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue