mirror of
https://github.com/Radarr/Radarr.git
synced 2024-10-26 22:52:40 +02:00
Fixed: List Exclusions, List Processing Tweaks
This commit is contained in:
parent
ed0e69de53
commit
06b1c03053
@ -5,6 +5,7 @@ import { createSelector } from 'reselect';
|
|||||||
import parseUrl from 'Utilities/String/parseUrl';
|
import parseUrl from 'Utilities/String/parseUrl';
|
||||||
import { lookupMovie, clearAddMovie } from 'Store/Actions/addMovieActions';
|
import { lookupMovie, clearAddMovie } from 'Store/Actions/addMovieActions';
|
||||||
import { fetchRootFolders } from 'Store/Actions/rootFolderActions';
|
import { fetchRootFolders } from 'Store/Actions/rootFolderActions';
|
||||||
|
import { fetchNetImportExclusions } from 'Store/Actions/Settings/netImportExclusions';
|
||||||
import AddNewMovie from './AddNewMovie';
|
import AddNewMovie from './AddNewMovie';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
@ -25,7 +26,8 @@ function createMapStateToProps() {
|
|||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
lookupMovie,
|
lookupMovie,
|
||||||
clearAddMovie,
|
clearAddMovie,
|
||||||
fetchRootFolders
|
fetchRootFolders,
|
||||||
|
fetchNetImportExclusions
|
||||||
};
|
};
|
||||||
|
|
||||||
class AddNewMovieConnector extends Component {
|
class AddNewMovieConnector extends Component {
|
||||||
@ -41,6 +43,7 @@ class AddNewMovieConnector extends Component {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.fetchRootFolders();
|
this.props.fetchRootFolders();
|
||||||
|
this.props.fetchNetImportExclusions();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
@ -96,7 +99,8 @@ AddNewMovieConnector.propTypes = {
|
|||||||
term: PropTypes.string,
|
term: PropTypes.string,
|
||||||
lookupMovie: PropTypes.func.isRequired,
|
lookupMovie: PropTypes.func.isRequired,
|
||||||
clearAddMovie: PropTypes.func.isRequired,
|
clearAddMovie: PropTypes.func.isRequired,
|
||||||
fetchRootFolders: PropTypes.func.isRequired
|
fetchRootFolders: PropTypes.func.isRequired,
|
||||||
|
fetchNetImportExclusions: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(AddNewMovieConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(AddNewMovieConnector);
|
||||||
|
@ -35,6 +35,11 @@
|
|||||||
color: #37bc9b;
|
color: #37bc9b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.exclusionIcon {
|
||||||
|
margin-left: 10px;
|
||||||
|
color: #bc3737;
|
||||||
|
}
|
||||||
|
|
||||||
.overview {
|
.overview {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ class AddNewMovieSearchResult extends Component {
|
|||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
if (!prevProps.isExistingMovie && this.props.isExistingMovie) {
|
if (!prevProps.isExistingMovie && this.props.isExistingMovie) {
|
||||||
this.onAddSerisModalClose();
|
this.onAddMovieModalClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ class AddNewMovieSearchResult extends Component {
|
|||||||
this.setState({ isNewAddMovieModalOpen: true });
|
this.setState({ isNewAddMovieModalOpen: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
onAddSerisModalClose = () => {
|
onAddMovieModalClose = () => {
|
||||||
this.setState({ isNewAddMovieModalOpen: false });
|
this.setState({ isNewAddMovieModalOpen: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,6 +54,7 @@ class AddNewMovieSearchResult extends Component {
|
|||||||
ratings,
|
ratings,
|
||||||
images,
|
images,
|
||||||
isExistingMovie,
|
isExistingMovie,
|
||||||
|
isExclusionMovie,
|
||||||
isSmallScreen
|
isSmallScreen
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const {
|
const {
|
||||||
@ -97,6 +98,16 @@ class AddNewMovieSearchResult extends Component {
|
|||||||
title="Already in your library"
|
title="Already in your library"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
isExclusionMovie &&
|
||||||
|
<Icon
|
||||||
|
className={styles.exclusionIcon}
|
||||||
|
name={icons.DANGER}
|
||||||
|
size={36}
|
||||||
|
title="Movie is on Net Import Exclusion List"
|
||||||
|
/>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@ -138,7 +149,7 @@ class AddNewMovieSearchResult extends Component {
|
|||||||
year={year}
|
year={year}
|
||||||
overview={overview}
|
overview={overview}
|
||||||
images={images}
|
images={images}
|
||||||
onModalClose={this.onAddSerisModalClose}
|
onModalClose={this.onAddMovieModalClose}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -156,6 +167,7 @@ AddNewMovieSearchResult.propTypes = {
|
|||||||
ratings: PropTypes.object.isRequired,
|
ratings: PropTypes.object.isRequired,
|
||||||
images: PropTypes.arrayOf(PropTypes.object).isRequired,
|
images: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
isExistingMovie: PropTypes.bool.isRequired,
|
isExistingMovie: PropTypes.bool.isRequired,
|
||||||
|
isExclusionMovie: PropTypes.bool.isRequired,
|
||||||
isSmallScreen: PropTypes.bool.isRequired
|
isSmallScreen: PropTypes.bool.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import createExistingMovieSelector from 'Store/Selectors/createExistingMovieSelector';
|
import createExistingMovieSelector from 'Store/Selectors/createExistingMovieSelector';
|
||||||
|
import createExclusionMovieSelector from 'Store/Selectors/createExclusionMovieSelector';
|
||||||
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
|
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
|
||||||
import AddNewMovieSearchResult from './AddNewMovieSearchResult';
|
import AddNewMovieSearchResult from './AddNewMovieSearchResult';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
createExistingMovieSelector(),
|
createExistingMovieSelector(),
|
||||||
|
createExclusionMovieSelector(),
|
||||||
createDimensionsSelector(),
|
createDimensionsSelector(),
|
||||||
(isExistingMovie, dimensions) => {
|
(isExistingMovie, isExclusionMovie, dimensions) => {
|
||||||
return {
|
return {
|
||||||
isExistingMovie,
|
isExistingMovie,
|
||||||
|
isExclusionMovie,
|
||||||
isSmallScreen: dimensions.isSmallScreen
|
isSmallScreen: dimensions.isSmallScreen
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,8 @@ class DeleteMovieModalContent extends Component {
|
|||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
deleteFiles: false
|
deleteFiles: false,
|
||||||
|
addNetImportExclusion: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,11 +34,17 @@ class DeleteMovieModalContent extends Component {
|
|||||||
this.setState({ deleteFiles: value });
|
this.setState({ deleteFiles: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onAddNetImportExclusionChange = ({ value }) => {
|
||||||
|
this.setState({ addNetImportExclusion: value });
|
||||||
|
}
|
||||||
|
|
||||||
onDeleteMovieConfirmed = () => {
|
onDeleteMovieConfirmed = () => {
|
||||||
const deleteFiles = this.state.deleteFiles;
|
const deleteFiles = this.state.deleteFiles;
|
||||||
|
const addNetImportExclusion = this.state.addNetImportExclusion;
|
||||||
|
|
||||||
this.setState({ deleteFiles: false });
|
this.setState({ deleteFiles: false });
|
||||||
this.props.onDeletePress(deleteFiles);
|
this.setState({ addNetImportExclusion: false });
|
||||||
|
this.props.onDeletePress(deleteFiles, addNetImportExclusion);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -57,6 +64,8 @@ class DeleteMovieModalContent extends Component {
|
|||||||
} = statistics;
|
} = statistics;
|
||||||
|
|
||||||
const deleteFiles = this.state.deleteFiles;
|
const deleteFiles = this.state.deleteFiles;
|
||||||
|
const addNetImportExclusion = this.state.addNetImportExclusion;
|
||||||
|
|
||||||
let deleteFilesLabel = `Delete ${movieFileCount} Movie Files`;
|
let deleteFilesLabel = `Delete ${movieFileCount} Movie Files`;
|
||||||
let deleteFilesHelpText = 'Delete the movie files and movie folder';
|
let deleteFilesHelpText = 'Delete the movie files and movie folder';
|
||||||
|
|
||||||
@ -108,6 +117,19 @@ class DeleteMovieModalContent extends Component {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<FormGroup>
|
||||||
|
<FormLabel>Add List Exclusion</FormLabel>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.CHECK}
|
||||||
|
name="addNetImportExclusion"
|
||||||
|
value={addNetImportExclusion}
|
||||||
|
helpText="Prevent movie from being added to Radarr by lists"
|
||||||
|
kind={kinds.DANGER}
|
||||||
|
onChange={this.onAddNetImportExclusionChange}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
|
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
|
@ -24,10 +24,11 @@ class DeleteMovieModalContentConnector extends Component {
|
|||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onDeletePress = (deleteFiles) => {
|
onDeletePress = (deleteFiles, addNetImportExclusion) => {
|
||||||
this.props.deleteMovie({
|
this.props.deleteMovie({
|
||||||
id: this.props.movieId,
|
id: this.props.movieId,
|
||||||
deleteFiles
|
deleteFiles,
|
||||||
|
addNetImportExclusion
|
||||||
});
|
});
|
||||||
|
|
||||||
this.props.onModalClose(true);
|
this.props.onModalClose(true);
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import { sizes } from 'Helpers/Props';
|
||||||
|
import Modal from 'Components/Modal/Modal';
|
||||||
|
import EditNetImportExclusionModalContentConnector from './EditNetImportExclusionModalContentConnector';
|
||||||
|
|
||||||
|
function EditNetImportExclusionModal({ isOpen, onModalClose, ...otherProps }) {
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
size={sizes.MEDIUM}
|
||||||
|
isOpen={isOpen}
|
||||||
|
onModalClose={onModalClose}
|
||||||
|
>
|
||||||
|
<EditNetImportExclusionModalContentConnector
|
||||||
|
{...otherProps}
|
||||||
|
onModalClose={onModalClose}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditNetImportExclusionModal.propTypes = {
|
||||||
|
isOpen: PropTypes.bool.isRequired,
|
||||||
|
onModalClose: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditNetImportExclusionModal;
|
@ -0,0 +1,43 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { clearPendingChanges } from 'Store/Actions/baseActions';
|
||||||
|
import EditNetImportExclusionModal from './EditNetImportExclusionModal';
|
||||||
|
|
||||||
|
function mapStateToProps() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapDispatchToProps = {
|
||||||
|
clearPendingChanges
|
||||||
|
};
|
||||||
|
|
||||||
|
class EditNetImportExclusionModalConnector extends Component {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Listeners
|
||||||
|
|
||||||
|
onModalClose = () => {
|
||||||
|
this.props.clearPendingChanges({ section: 'settings.netImportExclusions' });
|
||||||
|
this.props.onModalClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Render
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<EditNetImportExclusionModal
|
||||||
|
{...this.props}
|
||||||
|
onModalClose={this.onModalClose}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditNetImportExclusionModalConnector.propTypes = {
|
||||||
|
onModalClose: PropTypes.func.isRequired,
|
||||||
|
clearPendingChanges: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(EditNetImportExclusionModalConnector);
|
@ -0,0 +1,11 @@
|
|||||||
|
.body {
|
||||||
|
composes: modalBody from '~Components/Modal/ModalBody.css';
|
||||||
|
|
||||||
|
flex: 1 1 430px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deleteButton {
|
||||||
|
composes: button from '~Components/Link/Button.css';
|
||||||
|
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
@ -0,0 +1,143 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import { inputTypes, kinds } from 'Helpers/Props';
|
||||||
|
import Button from 'Components/Link/Button';
|
||||||
|
import SpinnerErrorButton from 'Components/Link/SpinnerErrorButton';
|
||||||
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
|
import ModalContent from 'Components/Modal/ModalContent';
|
||||||
|
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||||
|
import ModalBody from 'Components/Modal/ModalBody';
|
||||||
|
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||||
|
import Form from 'Components/Form/Form';
|
||||||
|
import FormGroup from 'Components/Form/FormGroup';
|
||||||
|
import FormLabel from 'Components/Form/FormLabel';
|
||||||
|
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||||
|
import styles from './EditNetImportExclusionModalContent.css';
|
||||||
|
|
||||||
|
function EditNetImportExclusionModalContent(props) {
|
||||||
|
const {
|
||||||
|
id,
|
||||||
|
isFetching,
|
||||||
|
error,
|
||||||
|
isSaving,
|
||||||
|
saveError,
|
||||||
|
item,
|
||||||
|
onInputChange,
|
||||||
|
onSavePress,
|
||||||
|
onModalClose,
|
||||||
|
onDeleteNetImportExclusionPress,
|
||||||
|
...otherProps
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const {
|
||||||
|
movieTitle = '',
|
||||||
|
tmdbId,
|
||||||
|
movieYear
|
||||||
|
} = item;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ModalContent onModalClose={onModalClose}>
|
||||||
|
<ModalHeader>
|
||||||
|
{id ? 'Edit List Exclusion' : 'Add List Exclusion'}
|
||||||
|
</ModalHeader>
|
||||||
|
|
||||||
|
<ModalBody className={styles.body}>
|
||||||
|
{
|
||||||
|
isFetching &&
|
||||||
|
<LoadingIndicator />
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
!isFetching && !!error &&
|
||||||
|
<div>Unable to add a new list exclusion, please try again.</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
!isFetching && !error &&
|
||||||
|
<Form
|
||||||
|
{...otherProps}
|
||||||
|
>
|
||||||
|
<FormGroup>
|
||||||
|
<FormLabel>TMDB Id</FormLabel>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.NUMBER}
|
||||||
|
name="tmdbId"
|
||||||
|
helpText="The TMDB Id of the movie to exclude"
|
||||||
|
{...tmdbId}
|
||||||
|
onChange={onInputChange}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
|
||||||
|
<FormGroup>
|
||||||
|
<FormLabel>Movie Title</FormLabel>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.TEXT}
|
||||||
|
name="movieTitle"
|
||||||
|
helpText="The title of the movie to exclude (can be anything meaningful)"
|
||||||
|
{...movieTitle}
|
||||||
|
onChange={onInputChange}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
|
||||||
|
<FormGroup>
|
||||||
|
<FormLabel>Movie Year</FormLabel>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.NUMBER}
|
||||||
|
name="movieYear"
|
||||||
|
helpText="The year of the movie to exclude"
|
||||||
|
{...movieYear}
|
||||||
|
onChange={onInputChange}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
|
||||||
|
</Form>
|
||||||
|
}
|
||||||
|
</ModalBody>
|
||||||
|
|
||||||
|
<ModalFooter>
|
||||||
|
{
|
||||||
|
id &&
|
||||||
|
<Button
|
||||||
|
className={styles.deleteButton}
|
||||||
|
kind={kinds.DANGER}
|
||||||
|
onPress={onDeleteNetImportExclusionPress}
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
onPress={onModalClose}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<SpinnerErrorButton
|
||||||
|
isSpinning={isSaving}
|
||||||
|
error={saveError}
|
||||||
|
onPress={onSavePress}
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</SpinnerErrorButton>
|
||||||
|
</ModalFooter>
|
||||||
|
</ModalContent>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditNetImportExclusionModalContent.propTypes = {
|
||||||
|
id: PropTypes.number,
|
||||||
|
isFetching: PropTypes.bool.isRequired,
|
||||||
|
error: PropTypes.object,
|
||||||
|
isSaving: PropTypes.bool.isRequired,
|
||||||
|
saveError: PropTypes.object,
|
||||||
|
item: PropTypes.object.isRequired,
|
||||||
|
onInputChange: PropTypes.func.isRequired,
|
||||||
|
onSavePress: PropTypes.func.isRequired,
|
||||||
|
onModalClose: PropTypes.func.isRequired,
|
||||||
|
onDeleteNetImportExclusionPress: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditNetImportExclusionModalContent;
|
@ -0,0 +1,118 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
|
import selectSettings from 'Store/Selectors/selectSettings';
|
||||||
|
import { setNetImportExclusionValue, saveNetImportExclusion } from 'Store/Actions/settingsActions';
|
||||||
|
import EditNetImportExclusionModalContent from './EditNetImportExclusionModalContent';
|
||||||
|
|
||||||
|
const newNetImportExclusion = {
|
||||||
|
artistName: '',
|
||||||
|
foreignId: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
function createNetImportExclusionSelector() {
|
||||||
|
return createSelector(
|
||||||
|
(state, { id }) => id,
|
||||||
|
(state) => state.settings.netImportExclusions,
|
||||||
|
(id, netImportExclusions) => {
|
||||||
|
const {
|
||||||
|
isFetching,
|
||||||
|
error,
|
||||||
|
isSaving,
|
||||||
|
saveError,
|
||||||
|
pendingChanges,
|
||||||
|
items
|
||||||
|
} = netImportExclusions;
|
||||||
|
|
||||||
|
const mapping = id ? _.find(items, { id }) : newNetImportExclusion;
|
||||||
|
const settings = selectSettings(mapping, pendingChanges, saveError);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
isFetching,
|
||||||
|
error,
|
||||||
|
isSaving,
|
||||||
|
saveError,
|
||||||
|
item: settings.settings,
|
||||||
|
...settings
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createMapStateToProps() {
|
||||||
|
return createSelector(
|
||||||
|
createNetImportExclusionSelector(),
|
||||||
|
(netImportExclusion) => {
|
||||||
|
return {
|
||||||
|
...netImportExclusion
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapDispatchToProps = {
|
||||||
|
setNetImportExclusionValue,
|
||||||
|
saveNetImportExclusion
|
||||||
|
};
|
||||||
|
|
||||||
|
class EditNetImportExclusionModalContentConnector extends Component {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Lifecycle
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (!this.props.id) {
|
||||||
|
Object.keys(newNetImportExclusion).forEach((name) => {
|
||||||
|
this.props.setNetImportExclusionValue({
|
||||||
|
name,
|
||||||
|
value: newNetImportExclusion[name]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps, prevState) {
|
||||||
|
if (prevProps.isSaving && !this.props.isSaving && !this.props.saveError) {
|
||||||
|
this.props.onModalClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Listeners
|
||||||
|
|
||||||
|
onInputChange = ({ name, value }) => {
|
||||||
|
this.props.setNetImportExclusionValue({ name, value });
|
||||||
|
}
|
||||||
|
|
||||||
|
onSavePress = () => {
|
||||||
|
this.props.saveNetImportExclusion({ id: this.props.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Render
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<EditNetImportExclusionModalContent
|
||||||
|
{...this.props}
|
||||||
|
onSavePress={this.onSavePress}
|
||||||
|
onInputChange={this.onInputChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditNetImportExclusionModalContentConnector.propTypes = {
|
||||||
|
id: PropTypes.number,
|
||||||
|
isSaving: PropTypes.bool.isRequired,
|
||||||
|
saveError: PropTypes.object,
|
||||||
|
item: PropTypes.object.isRequired,
|
||||||
|
setNetImportExclusionValue: PropTypes.func.isRequired,
|
||||||
|
saveNetImportExclusion: PropTypes.func.isRequired,
|
||||||
|
onModalClose: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(createMapStateToProps, mapDispatchToProps)(EditNetImportExclusionModalContentConnector);
|
@ -0,0 +1,24 @@
|
|||||||
|
.netImportExclusion {
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
height: 30px;
|
||||||
|
border-bottom: 1px solid $borderColor;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.movieTitle {
|
||||||
|
flex: 0 0 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tmdbId,
|
||||||
|
.movieYear {
|
||||||
|
flex: 0 0 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
flex: 1 0 auto;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { icons, kinds } from 'Helpers/Props';
|
||||||
|
import Icon from 'Components/Icon';
|
||||||
|
import Link from 'Components/Link/Link';
|
||||||
|
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||||
|
import EditNetImportExclusionModalConnector from './EditNetImportExclusionModalConnector';
|
||||||
|
import styles from './NetImportExclusion.css';
|
||||||
|
|
||||||
|
class NetImportExclusion extends Component {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Lifecycle
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
isEditNetImportExclusionModalOpen: false,
|
||||||
|
isDeleteNetImportExclusionModalOpen: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Listeners
|
||||||
|
|
||||||
|
onEditNetImportExclusionPress = () => {
|
||||||
|
this.setState({ isEditNetImportExclusionModalOpen: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
onEditNetImportExclusionModalClose = () => {
|
||||||
|
this.setState({ isEditNetImportExclusionModalOpen: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeleteNetImportExclusionPress = () => {
|
||||||
|
this.setState({
|
||||||
|
isEditNetImportExclusionModalOpen: false,
|
||||||
|
isDeleteNetImportExclusionModalOpen: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeleteNetImportExclusionModalClose = () => {
|
||||||
|
this.setState({ isDeleteNetImportExclusionModalOpen: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
onConfirmDeleteNetImportExclusion = () => {
|
||||||
|
this.props.onConfirmDeleteNetImportExclusion(this.props.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Render
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
id,
|
||||||
|
movieTitle,
|
||||||
|
tmdbId,
|
||||||
|
movieYear
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
styles.netImportExclusion,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className={styles.tmdbId}>{tmdbId}</div>
|
||||||
|
<div className={styles.movieTitle}>{movieTitle}</div>
|
||||||
|
<div className={styles.movieYear}>{movieYear}</div>
|
||||||
|
|
||||||
|
<div className={styles.actions}>
|
||||||
|
<Link
|
||||||
|
onPress={this.onEditNetImportExclusionPress}
|
||||||
|
>
|
||||||
|
<Icon name={icons.EDIT} />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<EditNetImportExclusionModalConnector
|
||||||
|
id={id}
|
||||||
|
isOpen={this.state.isEditNetImportExclusionModalOpen}
|
||||||
|
onModalClose={this.onEditNetImportExclusionModalClose}
|
||||||
|
onDeleteNetImportExclusionPress={this.onDeleteNetImportExclusionPress}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ConfirmModal
|
||||||
|
isOpen={this.state.isDeleteNetImportExclusionModalOpen}
|
||||||
|
kind={kinds.DANGER}
|
||||||
|
title="Delete Import List Exclusion"
|
||||||
|
message="Are you sure you want to delete this import list exclusion?"
|
||||||
|
confirmLabel="Delete"
|
||||||
|
onConfirm={this.onConfirmDeleteNetImportExclusion}
|
||||||
|
onCancel={this.onDeleteNetImportExclusionModalClose}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NetImportExclusion.propTypes = {
|
||||||
|
id: PropTypes.number.isRequired,
|
||||||
|
movieTitle: PropTypes.string.isRequired,
|
||||||
|
tmdbId: PropTypes.number.isRequired,
|
||||||
|
movieYear: PropTypes.number.isRequired,
|
||||||
|
onConfirmDeleteNetImportExclusion: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
NetImportExclusion.defaultProps = {
|
||||||
|
// The drag preview will not connect the drag handle.
|
||||||
|
connectDragSource: (node) => node
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NetImportExclusion;
|
@ -0,0 +1,24 @@
|
|||||||
|
.netImportExclusionsHeader {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
flex: 0 0 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tmdbId,
|
||||||
|
.movieYear {
|
||||||
|
flex: 0 0 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.addNetImportExclusion {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.addButton {
|
||||||
|
text-align: center;
|
||||||
|
}
|
@ -0,0 +1,101 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { icons } from 'Helpers/Props';
|
||||||
|
import FieldSet from 'Components/FieldSet';
|
||||||
|
import Icon from 'Components/Icon';
|
||||||
|
import Link from 'Components/Link/Link';
|
||||||
|
import PageSectionContent from 'Components/Page/PageSectionContent';
|
||||||
|
import NetImportExclusion from './NetImportExclusion';
|
||||||
|
import EditNetImportExclusionModalConnector from './EditNetImportExclusionModalConnector';
|
||||||
|
import styles from './NetImportExclusions.css';
|
||||||
|
|
||||||
|
class NetImportExclusions extends Component {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Lifecycle
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
isAddNetImportExclusionModalOpen: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Listeners
|
||||||
|
|
||||||
|
onAddNetImportExclusionPress = () => {
|
||||||
|
this.setState({ isAddNetImportExclusionModalOpen: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
onModalClose = () => {
|
||||||
|
this.setState({ isAddNetImportExclusionModalOpen: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Render
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
items,
|
||||||
|
onConfirmDeleteNetImportExclusion,
|
||||||
|
...otherProps
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FieldSet legend="List Exclusions">
|
||||||
|
<PageSectionContent
|
||||||
|
errorMessage="Unable to load List Exclusions"
|
||||||
|
{...otherProps}
|
||||||
|
>
|
||||||
|
<div className={styles.netImportExclusionsHeader}>
|
||||||
|
<div className={styles.tmdbId}>TMDB Id</div>
|
||||||
|
<div className={styles.title}>Title</div>
|
||||||
|
<div className={styles.movieYear}>Year</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
items.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<NetImportExclusion
|
||||||
|
key={item.id}
|
||||||
|
{...item}
|
||||||
|
{...otherProps}
|
||||||
|
index={index}
|
||||||
|
onConfirmDeleteNetImportExclusion={onConfirmDeleteNetImportExclusion}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.addNetImportExclusion}>
|
||||||
|
<Link
|
||||||
|
className={styles.addButton}
|
||||||
|
onPress={this.onAddNetImportExclusionPress}
|
||||||
|
>
|
||||||
|
<Icon name={icons.ADD} />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<EditNetImportExclusionModalConnector
|
||||||
|
isOpen={this.state.isAddNetImportExclusionModalOpen}
|
||||||
|
onModalClose={this.onModalClose}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</PageSectionContent>
|
||||||
|
</FieldSet>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NetImportExclusions.propTypes = {
|
||||||
|
isFetching: PropTypes.bool.isRequired,
|
||||||
|
error: PropTypes.object,
|
||||||
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
|
onConfirmDeleteNetImportExclusion: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NetImportExclusions;
|
@ -0,0 +1,59 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
|
import { fetchNetImportExclusions, deleteNetImportExclusion } from 'Store/Actions/settingsActions';
|
||||||
|
import NetImportExclusions from './NetImportExclusions';
|
||||||
|
|
||||||
|
function createMapStateToProps() {
|
||||||
|
return createSelector(
|
||||||
|
(state) => state.settings.netImportExclusions,
|
||||||
|
(netImportExclusions) => {
|
||||||
|
return {
|
||||||
|
...netImportExclusions
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapDispatchToProps = {
|
||||||
|
fetchNetImportExclusions,
|
||||||
|
deleteNetImportExclusion
|
||||||
|
};
|
||||||
|
|
||||||
|
class NetImportExclusionsConnector extends Component {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Lifecycle
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.fetchNetImportExclusions();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Listeners
|
||||||
|
|
||||||
|
onConfirmDeleteNetImportExclusion = (id) => {
|
||||||
|
this.props.deleteNetImportExclusion({ id });
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Render
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<NetImportExclusions
|
||||||
|
{...this.state}
|
||||||
|
{...this.props}
|
||||||
|
onConfirmDeleteNetImportExclusion={this.onConfirmDeleteNetImportExclusion}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NetImportExclusionsConnector.propTypes = {
|
||||||
|
fetchNetImportExclusions: PropTypes.func.isRequired,
|
||||||
|
deleteNetImportExclusion: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(createMapStateToProps, mapDispatchToProps)(NetImportExclusionsConnector);
|
@ -8,7 +8,7 @@ import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
|
|||||||
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
|
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
|
||||||
import NetImportsConnector from './NetImport/NetImportsConnector';
|
import NetImportsConnector from './NetImport/NetImportsConnector';
|
||||||
import NetImportOptionsConnector from './Options/NetImportOptionsConnector';
|
import NetImportOptionsConnector from './Options/NetImportOptionsConnector';
|
||||||
// import ImportExclusionsConnector from './ImportExclusions/ImportExclusionsConnector';
|
import NetImportExclusionsConnector from './NetImportExclusions/NetImportExclusionsConnector';
|
||||||
|
|
||||||
class NetImportSettings extends Component {
|
class NetImportSettings extends Component {
|
||||||
|
|
||||||
@ -85,6 +85,8 @@ class NetImportSettings extends Component {
|
|||||||
onChildStateChange={this.onChildStateChange}
|
onChildStateChange={this.onChildStateChange}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<NetImportExclusionsConnector />
|
||||||
|
|
||||||
</PageContentBodyConnector>
|
</PageContentBodyConnector>
|
||||||
</PageContent>
|
</PageContent>
|
||||||
);
|
);
|
||||||
|
69
frontend/src/Store/Actions/Settings/netImportExclusions.js
Normal file
69
frontend/src/Store/Actions/Settings/netImportExclusions.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import { createAction } from 'redux-actions';
|
||||||
|
import { createThunk } from 'Store/thunks';
|
||||||
|
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
|
||||||
|
import createFetchHandler from 'Store/Actions/Creators/createFetchHandler';
|
||||||
|
import createSaveProviderHandler from 'Store/Actions/Creators/createSaveProviderHandler';
|
||||||
|
import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler';
|
||||||
|
|
||||||
|
//
|
||||||
|
// Variables
|
||||||
|
|
||||||
|
const section = 'settings.netImportExclusions';
|
||||||
|
|
||||||
|
//
|
||||||
|
// Actions Types
|
||||||
|
|
||||||
|
export const FETCH_NET_IMPORT_EXCLUSIONS = 'settings/netImportExclusions/fetchNetImportExclusions';
|
||||||
|
export const SAVE_NET_IMPORT_EXCLUSION = 'settings/netImportExclusions/saveNetImportExclusion';
|
||||||
|
export const DELETE_NET_IMPORT_EXCLUSION = 'settings/netImportExclusions/deleteNetImportExclusion';
|
||||||
|
export const SET_NET_IMPORT_EXCLUSION_VALUE = 'settings/netImportExclusions/setNetImportExclusionValue';
|
||||||
|
|
||||||
|
//
|
||||||
|
// Action Creators
|
||||||
|
|
||||||
|
export const fetchNetImportExclusions = createThunk(FETCH_NET_IMPORT_EXCLUSIONS);
|
||||||
|
export const saveNetImportExclusion = createThunk(SAVE_NET_IMPORT_EXCLUSION);
|
||||||
|
export const deleteNetImportExclusion = createThunk(DELETE_NET_IMPORT_EXCLUSION);
|
||||||
|
|
||||||
|
export const setNetImportExclusionValue = createAction(SET_NET_IMPORT_EXCLUSION_VALUE, (payload) => {
|
||||||
|
return {
|
||||||
|
section,
|
||||||
|
...payload
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
// Details
|
||||||
|
|
||||||
|
export default {
|
||||||
|
|
||||||
|
//
|
||||||
|
// State
|
||||||
|
|
||||||
|
defaultState: {
|
||||||
|
isFetching: false,
|
||||||
|
isPopulated: false,
|
||||||
|
error: null,
|
||||||
|
items: [],
|
||||||
|
isSaving: false,
|
||||||
|
saveError: null,
|
||||||
|
pendingChanges: {}
|
||||||
|
},
|
||||||
|
|
||||||
|
//
|
||||||
|
// Action Handlers
|
||||||
|
|
||||||
|
actionHandlers: {
|
||||||
|
[FETCH_NET_IMPORT_EXCLUSIONS]: createFetchHandler(section, '/exclusions'),
|
||||||
|
[SAVE_NET_IMPORT_EXCLUSION]: createSaveProviderHandler(section, '/exclusions'),
|
||||||
|
[DELETE_NET_IMPORT_EXCLUSION]: createRemoveItemHandler(section, '/exclusions')
|
||||||
|
},
|
||||||
|
|
||||||
|
//
|
||||||
|
// Reducers
|
||||||
|
|
||||||
|
reducers: {
|
||||||
|
[SET_NET_IMPORT_EXCLUSION_VALUE]: createSetSettingValueReducer(section)
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
@ -9,6 +9,7 @@ import general from './Settings/general';
|
|||||||
import indexerOptions from './Settings/indexerOptions';
|
import indexerOptions from './Settings/indexerOptions';
|
||||||
import indexers from './Settings/indexers';
|
import indexers from './Settings/indexers';
|
||||||
import languages from './Settings/languages';
|
import languages from './Settings/languages';
|
||||||
|
import netImportExclusions from './Settings/netImportExclusions';
|
||||||
import netImportOptions from './Settings/netImportOptions';
|
import netImportOptions from './Settings/netImportOptions';
|
||||||
import netImports from './Settings/netImports';
|
import netImports from './Settings/netImports';
|
||||||
import mediaManagement from './Settings/mediaManagement';
|
import mediaManagement from './Settings/mediaManagement';
|
||||||
@ -30,6 +31,7 @@ export * from './Settings/general';
|
|||||||
export * from './Settings/indexerOptions';
|
export * from './Settings/indexerOptions';
|
||||||
export * from './Settings/indexers';
|
export * from './Settings/indexers';
|
||||||
export * from './Settings/languages';
|
export * from './Settings/languages';
|
||||||
|
export * from './Settings/netImportExclusions';
|
||||||
export * from './Settings/netImportOptions';
|
export * from './Settings/netImportOptions';
|
||||||
export * from './Settings/netImports';
|
export * from './Settings/netImports';
|
||||||
export * from './Settings/mediaManagement';
|
export * from './Settings/mediaManagement';
|
||||||
@ -62,6 +64,7 @@ export const defaultState = {
|
|||||||
indexerOptions: indexerOptions.defaultState,
|
indexerOptions: indexerOptions.defaultState,
|
||||||
indexers: indexers.defaultState,
|
indexers: indexers.defaultState,
|
||||||
languages: languages.defaultState,
|
languages: languages.defaultState,
|
||||||
|
netImportExclusions: netImportExclusions.defaultState,
|
||||||
netImportOptions: netImportOptions.defaultState,
|
netImportOptions: netImportOptions.defaultState,
|
||||||
netImports: netImports.defaultState,
|
netImports: netImports.defaultState,
|
||||||
mediaManagement: mediaManagement.defaultState,
|
mediaManagement: mediaManagement.defaultState,
|
||||||
@ -102,6 +105,7 @@ export const actionHandlers = handleThunks({
|
|||||||
...indexerOptions.actionHandlers,
|
...indexerOptions.actionHandlers,
|
||||||
...indexers.actionHandlers,
|
...indexers.actionHandlers,
|
||||||
...languages.actionHandlers,
|
...languages.actionHandlers,
|
||||||
|
...netImportExclusions.actionHandlers,
|
||||||
...netImportOptions.actionHandlers,
|
...netImportOptions.actionHandlers,
|
||||||
...netImports.actionHandlers,
|
...netImports.actionHandlers,
|
||||||
...mediaManagement.actionHandlers,
|
...mediaManagement.actionHandlers,
|
||||||
@ -133,6 +137,7 @@ export const reducers = createHandleActions({
|
|||||||
...indexerOptions.reducers,
|
...indexerOptions.reducers,
|
||||||
...indexers.reducers,
|
...indexers.reducers,
|
||||||
...languages.reducers,
|
...languages.reducers,
|
||||||
|
...netImportExclusions.reducers,
|
||||||
...netImportOptions.reducers,
|
...netImportOptions.reducers,
|
||||||
...netImports.reducers,
|
...netImports.reducers,
|
||||||
...mediaManagement.reducers,
|
...mediaManagement.reducers,
|
||||||
|
14
frontend/src/Store/Selectors/createExclusionMovieSelector.js
Normal file
14
frontend/src/Store/Selectors/createExclusionMovieSelector.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
|
function createExclusionMovieSelector() {
|
||||||
|
return createSelector(
|
||||||
|
(state, { tmdbId }) => tmdbId,
|
||||||
|
(state) => state.settings.netImportExclusions,
|
||||||
|
(tmdbId, netImportExclusions) => {
|
||||||
|
return _.some(netImportExclusions.items, { tmdbId });
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default createExclusionMovieSelector;
|
@ -1,7 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Core.Messaging.Commands;
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
using NzbDrone.Core.MetadataSource;
|
using NzbDrone.Core.MetadataSource;
|
||||||
@ -9,8 +8,6 @@
|
|||||||
using NzbDrone.Core.Movies;
|
using NzbDrone.Core.Movies;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Instrumentation.Extensions;
|
|
||||||
using NzbDrone.Core.DecisionEngine;
|
|
||||||
using NzbDrone.Core.Download;
|
using NzbDrone.Core.Download;
|
||||||
using NzbDrone.Core.IndexerSearch;
|
using NzbDrone.Core.IndexerSearch;
|
||||||
using NzbDrone.Core.NetImport.ImportExclusions;
|
using NzbDrone.Core.NetImport.ImportExclusions;
|
||||||
@ -134,43 +131,33 @@ public void Execute(NetImportSyncCommand message)
|
|||||||
_logger.Info($"Found {listedMovies.Count()} movies on your auto enabled lists not in your library");
|
_logger.Info($"Found {listedMovies.Count()} movies on your auto enabled lists not in your library");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var importExclusions = new List<string>();
|
var importExclusions = new List<string>();
|
||||||
|
var moviesToAdd = new List<Movie>();
|
||||||
|
|
||||||
//var downloadedCount = 0;
|
|
||||||
foreach (var movie in listedMovies)
|
foreach (var movie in listedMovies)
|
||||||
{
|
{
|
||||||
var mapped = _movieSearch.MapMovieToTmdbMovie(movie);
|
var mapped = _movieSearch.MapMovieToTmdbMovie(movie);
|
||||||
if (mapped != null && !_exclusionService.IsMovieExcluded(mapped.TmdbId))
|
|
||||||
|
if (mapped == null)
|
||||||
{
|
{
|
||||||
//List<DownloadDecision> decisions;
|
_logger.Debug($"{movie.Title} could not be mapped to a valid tmdb ID, will not be added from list");
|
||||||
mapped.AddOptions = new AddMovieOptions {SearchForMovie = true};
|
}
|
||||||
_movieService.AddMovie(mapped);
|
else if (_exclusionService.IsMovieExcluded(mapped.TmdbId))
|
||||||
|
{
|
||||||
//// Search for movie
|
_logger.Debug($"{mapped.Title} ({mapped.TitleSlug}) will not be added since it was found on the exclusions list");
|
||||||
//try
|
}
|
||||||
//{
|
else if (_movieService.MovieExists(mapped))
|
||||||
// decisions = _nzbSearchService.MovieSearch(mapped.Id, false);
|
{
|
||||||
//}
|
_logger.Debug($"{mapped.Title} ({mapped.TitleSlug}) will not be added since it exists in DB");
|
||||||
//catch (Exception ex)
|
|
||||||
//{
|
|
||||||
// _logger.Error(ex, $"Unable to search in list for movie {mapped.Id}");
|
|
||||||
// continue;
|
|
||||||
//}
|
|
||||||
|
|
||||||
//var processed = _processDownloadDecisions.ProcessDecisions(decisions);
|
|
||||||
//downloadedCount += processed.Grabbed.Count;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (mapped != null)
|
mapped.AddOptions = new AddMovieOptions { SearchForMovie = true };
|
||||||
{
|
moviesToAdd.Add(mapped);
|
||||||
_logger.Info($"{mapped.Title} ({mapped.TitleSlug}) will not be added since it was found on the exclusions list");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//_logger.ProgressInfo("Movie search completed. {0} reports downloaded.", downloadedCount);
|
_movieService.AddMovies(moviesToAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CleanLibrary(List<Movie> movies)
|
private void CleanLibrary(List<Movie> movies)
|
||||||
|
@ -117,7 +117,7 @@ private void UpdateMovie(MovieResource moviesResource)
|
|||||||
private void DeleteMovie(int id)
|
private void DeleteMovie(int id)
|
||||||
{
|
{
|
||||||
var addExclusion = false;
|
var addExclusion = false;
|
||||||
var addExclusionQuery = Request.Query.addExclusion;
|
var addExclusionQuery = Request.Query.addNetImportExclusion;
|
||||||
|
|
||||||
var deleteFiles = Request.GetBooleanQueryParameter("deleteFiles");
|
var deleteFiles = Request.GetBooleanQueryParameter("deleteFiles");
|
||||||
|
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using Radarr.Http.ClientSchema;
|
|
||||||
using NzbDrone.Core.NetImport;
|
using NzbDrone.Core.NetImport;
|
||||||
using NzbDrone.Core.NetImport.ImportExclusions;
|
using NzbDrone.Core.NetImport.ImportExclusions;
|
||||||
using NzbDrone.Core.Validation.Paths;
|
|
||||||
using Radarr.Http;
|
using Radarr.Http;
|
||||||
|
|
||||||
namespace Radarr.Api.V2.NetImport
|
namespace Radarr.Api.V2.NetImport
|
||||||
@ -19,6 +17,10 @@ public ImportExclusionsModule(NetImportFactory netImportFactory, IImportExclusio
|
|||||||
CreateResource = AddExclusion;
|
CreateResource = AddExclusion;
|
||||||
DeleteResource = RemoveExclusion;
|
DeleteResource = RemoveExclusion;
|
||||||
GetResourceById = GetById;
|
GetResourceById = GetById;
|
||||||
|
|
||||||
|
SharedValidator.RuleFor(c => c.TmdbId).GreaterThan(0);
|
||||||
|
SharedValidator.RuleFor(c => c.MovieTitle).NotEmpty();
|
||||||
|
SharedValidator.RuleFor(c => c.MovieYear).GreaterThan(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ImportExclusionsResource> GetAll()
|
public List<ImportExclusionsResource> GetAll()
|
||||||
@ -35,6 +37,8 @@ public int AddExclusion(ImportExclusionsResource exclusionResource)
|
|||||||
{
|
{
|
||||||
var model = exclusionResource.ToModel();
|
var model = exclusionResource.ToModel();
|
||||||
|
|
||||||
|
// TODO: Add some more validation here and auto pull the title if not provided
|
||||||
|
|
||||||
return _exclusionService.AddExclusion(model).Id;
|
return _exclusionService.AddExclusion(model).Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user