mirror of
https://github.com/Radarr/Radarr.git
synced 2025-04-24 14:37:07 -04:00
Fixed: Updating movie files via Manage Files
This commit is contained in:
parent
1d855aed00
commit
35f1a61bf8
9 changed files with 85 additions and 513 deletions
|
@ -86,18 +86,18 @@ class FileEditModalContentConnector extends Component {
|
||||||
real: real ? 1 : 0
|
real: real ? 1 : 0
|
||||||
};
|
};
|
||||||
|
|
||||||
const movieFileIds = [this.props.movieFileId];
|
|
||||||
|
|
||||||
this.props.dispatchUpdateMovieFiles({
|
this.props.dispatchUpdateMovieFiles({
|
||||||
movieFileIds,
|
files: [{
|
||||||
languages,
|
id: this.props.movieFileId,
|
||||||
indexerFlags,
|
languages,
|
||||||
edition,
|
indexerFlags,
|
||||||
releaseGroup,
|
edition,
|
||||||
quality: {
|
releaseGroup,
|
||||||
quality,
|
quality: {
|
||||||
revision
|
quality,
|
||||||
}
|
revision
|
||||||
|
}
|
||||||
|
}]
|
||||||
});
|
});
|
||||||
|
|
||||||
this.props.onModalClose(true);
|
this.props.onModalClose(true);
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import Modal from 'Components/Modal/Modal';
|
|
||||||
import SelectLanguageModalContentConnector from './SelectLanguageModalContentConnector';
|
|
||||||
|
|
||||||
class SelectLanguageModal extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
isOpen,
|
|
||||||
onModalClose,
|
|
||||||
...otherProps
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
isOpen={isOpen}
|
|
||||||
onModalClose={onModalClose}
|
|
||||||
>
|
|
||||||
<SelectLanguageModalContentConnector
|
|
||||||
{...otherProps}
|
|
||||||
onModalClose={onModalClose}
|
|
||||||
/>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SelectLanguageModal.propTypes = {
|
|
||||||
isOpen: PropTypes.bool.isRequired,
|
|
||||||
onModalClose: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SelectLanguageModal;
|
|
|
@ -1,97 +0,0 @@
|
||||||
import _ from 'lodash';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { createSelector } from 'reselect';
|
|
||||||
import SelectLanguageModalContent from 'InteractiveImport/Language/SelectLanguageModalContent';
|
|
||||||
import { updateMovieFiles } from 'Store/Actions/movieFileActions';
|
|
||||||
import { fetchLanguages } from 'Store/Actions/settingsActions';
|
|
||||||
|
|
||||||
function createMapStateToProps() {
|
|
||||||
return createSelector(
|
|
||||||
(state) => state.settings.languages,
|
|
||||||
(languages) => {
|
|
||||||
const {
|
|
||||||
isFetching,
|
|
||||||
isPopulated,
|
|
||||||
error,
|
|
||||||
items
|
|
||||||
} = languages;
|
|
||||||
|
|
||||||
const filterItems = ['Any', 'Original'];
|
|
||||||
const filteredLanguages = items.filter((lang) => !filterItems.includes(lang.name));
|
|
||||||
|
|
||||||
return {
|
|
||||||
isFetching,
|
|
||||||
isPopulated,
|
|
||||||
error,
|
|
||||||
items: filteredLanguages
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
|
||||||
dispatchFetchLanguages: fetchLanguages,
|
|
||||||
dispatchupdateMovieFiles: updateMovieFiles
|
|
||||||
};
|
|
||||||
|
|
||||||
class SelectLanguageModalContentConnector extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Lifecycle
|
|
||||||
|
|
||||||
componentDidMount = () => {
|
|
||||||
if (!this.props.isPopulated) {
|
|
||||||
this.props.dispatchFetchLanguages();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Listeners
|
|
||||||
|
|
||||||
onLanguageSelect = ({ languageIds }) => {
|
|
||||||
const languages = [];
|
|
||||||
|
|
||||||
languageIds.forEach((languageId) => {
|
|
||||||
const language = _.find(this.props.items,
|
|
||||||
(item) => item.id === parseInt(languageId));
|
|
||||||
|
|
||||||
if (language !== undefined) {
|
|
||||||
languages.push(language);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.props.dispatchupdateMovieFiles({
|
|
||||||
movieFileIds: this.props.ids,
|
|
||||||
languages
|
|
||||||
});
|
|
||||||
|
|
||||||
this.props.onModalClose(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<SelectLanguageModalContent
|
|
||||||
{...this.props}
|
|
||||||
onLanguageSelect={this.onLanguageSelect}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SelectLanguageModalContentConnector.propTypes = {
|
|
||||||
ids: PropTypes.arrayOf(PropTypes.number).isRequired,
|
|
||||||
isFetching: PropTypes.bool.isRequired,
|
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
|
||||||
error: PropTypes.object,
|
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
dispatchFetchLanguages: PropTypes.func.isRequired,
|
|
||||||
dispatchupdateMovieFiles: PropTypes.func.isRequired,
|
|
||||||
onModalClose: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(SelectLanguageModalContentConnector);
|
|
|
@ -1,37 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import Modal from 'Components/Modal/Modal';
|
|
||||||
import SelectQualityModalContentConnector from './SelectQualityModalContentConnector';
|
|
||||||
|
|
||||||
class SelectQualityModal extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
isOpen,
|
|
||||||
onModalClose,
|
|
||||||
...otherProps
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
isOpen={isOpen}
|
|
||||||
onModalClose={onModalClose}
|
|
||||||
>
|
|
||||||
<SelectQualityModalContentConnector
|
|
||||||
{...otherProps}
|
|
||||||
onModalClose={onModalClose}
|
|
||||||
/>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SelectQualityModal.propTypes = {
|
|
||||||
isOpen: PropTypes.bool.isRequired,
|
|
||||||
onModalClose: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SelectQualityModal;
|
|
|
@ -1,170 +0,0 @@
|
||||||
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 LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
|
||||||
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';
|
|
||||||
|
|
||||||
class SelectQualityModalContent extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Lifecycle
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
|
|
||||||
const {
|
|
||||||
qualityId,
|
|
||||||
proper,
|
|
||||||
real
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
qualityId,
|
|
||||||
proper,
|
|
||||||
real
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Listeners
|
|
||||||
|
|
||||||
onQualityChange = ({ value }) => {
|
|
||||||
this.setState({ qualityId: parseInt(value) });
|
|
||||||
};
|
|
||||||
|
|
||||||
onProperChange = ({ value }) => {
|
|
||||||
this.setState({ proper: value });
|
|
||||||
};
|
|
||||||
|
|
||||||
onRealChange = ({ value }) => {
|
|
||||||
this.setState({ real: value });
|
|
||||||
};
|
|
||||||
|
|
||||||
onQualitySelect = () => {
|
|
||||||
this.props.onQualitySelect(this.state);
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
isFetching,
|
|
||||||
isPopulated,
|
|
||||||
error,
|
|
||||||
items,
|
|
||||||
onModalClose
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const {
|
|
||||||
qualityId,
|
|
||||||
proper,
|
|
||||||
real
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
const qualityOptions = items.map(({ id, name }) => {
|
|
||||||
return {
|
|
||||||
key: id,
|
|
||||||
value: name
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ModalContent onModalClose={onModalClose}>
|
|
||||||
<ModalHeader>
|
|
||||||
{translate('ManualImportSelectQuality')}
|
|
||||||
</ModalHeader>
|
|
||||||
|
|
||||||
<ModalBody>
|
|
||||||
{
|
|
||||||
isFetching &&
|
|
||||||
<LoadingIndicator />
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
!isFetching && !!error &&
|
|
||||||
<Alert kind={kinds.DANGER}>
|
|
||||||
{translate('QualitiesLoadError')}
|
|
||||||
</Alert>
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
isPopulated && !error &&
|
|
||||||
<Form>
|
|
||||||
<FormGroup>
|
|
||||||
<FormLabel>{translate('Quality')}</FormLabel>
|
|
||||||
|
|
||||||
<FormInputGroup
|
|
||||||
type={inputTypes.SELECT}
|
|
||||||
name="quality"
|
|
||||||
value={qualityId}
|
|
||||||
values={qualityOptions}
|
|
||||||
onChange={this.onQualityChange}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
|
|
||||||
<FormGroup>
|
|
||||||
<FormLabel>{translate('Proper')}</FormLabel>
|
|
||||||
|
|
||||||
<FormInputGroup
|
|
||||||
type={inputTypes.CHECK}
|
|
||||||
name="proper"
|
|
||||||
value={proper}
|
|
||||||
onChange={this.onProperChange}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
|
|
||||||
<FormGroup>
|
|
||||||
<FormLabel>{translate('Real')}</FormLabel>
|
|
||||||
|
|
||||||
<FormInputGroup
|
|
||||||
type={inputTypes.CHECK}
|
|
||||||
name="real"
|
|
||||||
value={real}
|
|
||||||
onChange={this.onRealChange}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
</Form>
|
|
||||||
}
|
|
||||||
</ModalBody>
|
|
||||||
|
|
||||||
<ModalFooter>
|
|
||||||
<Button onPress={onModalClose}>
|
|
||||||
{translate('Cancel')}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
kind={kinds.SUCCESS}
|
|
||||||
onPress={this.onQualitySelect}
|
|
||||||
>
|
|
||||||
{translate('SelectQuality')}
|
|
||||||
</Button>
|
|
||||||
</ModalFooter>
|
|
||||||
</ModalContent>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SelectQualityModalContent.propTypes = {
|
|
||||||
qualityId: PropTypes.number.isRequired,
|
|
||||||
proper: PropTypes.bool.isRequired,
|
|
||||||
real: PropTypes.bool.isRequired,
|
|
||||||
isFetching: PropTypes.bool.isRequired,
|
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
|
||||||
error: PropTypes.object,
|
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
onQualitySelect: PropTypes.func.isRequired,
|
|
||||||
onModalClose: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SelectQualityModalContent;
|
|
|
@ -1,97 +0,0 @@
|
||||||
import _ from 'lodash';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { createSelector } from 'reselect';
|
|
||||||
import { updateMovieFiles } from 'Store/Actions/movieFileActions';
|
|
||||||
import { fetchQualityProfileSchema } from 'Store/Actions/settingsActions';
|
|
||||||
import getQualities from 'Utilities/Quality/getQualities';
|
|
||||||
import SelectQualityModalContent from './SelectQualityModalContent';
|
|
||||||
|
|
||||||
function createMapStateToProps() {
|
|
||||||
return createSelector(
|
|
||||||
(state) => state.settings.qualityProfiles,
|
|
||||||
(qualityProfiles) => {
|
|
||||||
const {
|
|
||||||
isSchemaFetching: isFetching,
|
|
||||||
isSchemaPopulated: isPopulated,
|
|
||||||
schemaError: error,
|
|
||||||
schema
|
|
||||||
} = qualityProfiles;
|
|
||||||
|
|
||||||
return {
|
|
||||||
isFetching,
|
|
||||||
isPopulated,
|
|
||||||
error,
|
|
||||||
items: getQualities(schema.items)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
|
||||||
dispatchFetchQualityProfileSchema: fetchQualityProfileSchema,
|
|
||||||
dispatchupdateMovieFiles: updateMovieFiles
|
|
||||||
};
|
|
||||||
|
|
||||||
class SelectQualityModalContentConnector extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Lifecycle
|
|
||||||
|
|
||||||
componentDidMount = () => {
|
|
||||||
if (!this.props.isPopulated) {
|
|
||||||
this.props.dispatchFetchQualityProfileSchema();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Listeners
|
|
||||||
|
|
||||||
onQualitySelect = ({ qualityId, proper, real }) => {
|
|
||||||
const quality = _.find(this.props.items,
|
|
||||||
(item) => item.id === qualityId);
|
|
||||||
|
|
||||||
const revision = {
|
|
||||||
version: proper ? 2 : 1,
|
|
||||||
real: real ? 1 : 0
|
|
||||||
};
|
|
||||||
|
|
||||||
const movieFileIds = this.props.ids;
|
|
||||||
|
|
||||||
this.props.dispatchupdateMovieFiles({
|
|
||||||
movieFileIds,
|
|
||||||
quality: {
|
|
||||||
quality,
|
|
||||||
revision
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.props.onModalClose(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<SelectQualityModalContent
|
|
||||||
{...this.props}
|
|
||||||
onQualitySelect={this.onQualitySelect}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SelectQualityModalContentConnector.propTypes = {
|
|
||||||
ids: PropTypes.arrayOf(PropTypes.number).isRequired,
|
|
||||||
isFetching: PropTypes.bool.isRequired,
|
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
|
||||||
error: PropTypes.object,
|
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
dispatchFetchQualityProfileSchema: PropTypes.func.isRequired,
|
|
||||||
dispatchupdateMovieFiles: PropTypes.func.isRequired,
|
|
||||||
onModalClose: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(SelectQualityModalContentConnector);
|
|
|
@ -29,6 +29,7 @@ export const defaultState = {
|
||||||
isReprocessing: false,
|
isReprocessing: false,
|
||||||
error: null,
|
error: null,
|
||||||
items: [],
|
items: [],
|
||||||
|
originalItems: [],
|
||||||
sortKey: 'relativePath',
|
sortKey: 'relativePath',
|
||||||
sortDirection: sortDirections.ASCENDING,
|
sortDirection: sortDirections.ASCENDING,
|
||||||
favoriteFolders: [],
|
favoriteFolders: [],
|
||||||
|
@ -119,7 +120,8 @@ export const actionHandlers = handleThunks({
|
||||||
section,
|
section,
|
||||||
isFetching: false,
|
isFetching: false,
|
||||||
isPopulated: true,
|
isPopulated: true,
|
||||||
error: null
|
error: null,
|
||||||
|
originalItems: data
|
||||||
})
|
})
|
||||||
]));
|
]));
|
||||||
});
|
});
|
||||||
|
@ -228,13 +230,13 @@ export const reducers = createHandleActions({
|
||||||
},
|
},
|
||||||
|
|
||||||
[UPDATE_INTERACTIVE_IMPORT_ITEMS]: (state, { payload }) => {
|
[UPDATE_INTERACTIVE_IMPORT_ITEMS]: (state, { payload }) => {
|
||||||
const ids = payload.ids;
|
const { ids, ...otherPayload } = payload;
|
||||||
const newState = Object.assign({}, state);
|
const newState = Object.assign({}, state);
|
||||||
const items = [...newState.items];
|
const items = [...newState.items];
|
||||||
|
|
||||||
ids.forEach((id) => {
|
ids.forEach((id) => {
|
||||||
const index = items.findIndex((item) => item.id === id);
|
const index = items.findIndex((item) => item.id === id);
|
||||||
const item = Object.assign({}, items[index], payload);
|
const item = Object.assign({}, items[index], otherPayload);
|
||||||
|
|
||||||
items.splice(index, 1, item);
|
items.splice(index, 1, item);
|
||||||
});
|
});
|
||||||
|
|
|
@ -248,44 +248,14 @@ export const actionHandlers = handleThunks({
|
||||||
},
|
},
|
||||||
|
|
||||||
[UPDATE_MOVIE_FILES]: function(getState, payload, dispatch) {
|
[UPDATE_MOVIE_FILES]: function(getState, payload, dispatch) {
|
||||||
|
const { files } = payload;
|
||||||
const {
|
|
||||||
movieFileIds,
|
|
||||||
languages,
|
|
||||||
indexerFlags,
|
|
||||||
quality,
|
|
||||||
edition,
|
|
||||||
releaseGroup
|
|
||||||
} = payload;
|
|
||||||
|
|
||||||
dispatch(set({ section, isSaving: true }));
|
dispatch(set({ section, isSaving: true }));
|
||||||
|
|
||||||
const requestData = {
|
const requestData = files;
|
||||||
movieFileIds
|
|
||||||
};
|
|
||||||
|
|
||||||
if (languages) {
|
|
||||||
requestData.languages = languages;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (indexerFlags !== undefined) {
|
|
||||||
requestData.indexerFlags = indexerFlags;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (quality) {
|
|
||||||
requestData.quality = quality;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (releaseGroup !== undefined) {
|
|
||||||
requestData.releaseGroup = releaseGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (edition !== undefined) {
|
|
||||||
requestData.edition = edition;
|
|
||||||
}
|
|
||||||
|
|
||||||
const promise = createAjaxRequest({
|
const promise = createAjaxRequest({
|
||||||
url: '/movieFile/editor',
|
url: '/movieFile/bulk',
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
data: JSON.stringify(requestData)
|
data: JSON.stringify(requestData)
|
||||||
|
@ -293,36 +263,25 @@ export const actionHandlers = handleThunks({
|
||||||
|
|
||||||
promise.done((data) => {
|
promise.done((data) => {
|
||||||
dispatch(batchActions([
|
dispatch(batchActions([
|
||||||
...movieFileIds.map((id) => {
|
...files.map((file) => {
|
||||||
const movieFile = data.find((file) => file.id === id);
|
const id = file.id;
|
||||||
|
const props = {};
|
||||||
|
const movieFile = data.find((f) => f.id === id);
|
||||||
|
|
||||||
const props = {
|
props.qualityCutoffNotMet = movieFile.qualityCutoffNotMet;
|
||||||
customFormats: movieFile.customFormats,
|
props.customFormats = movieFile.customFormats;
|
||||||
customFormatScore: movieFile.customFormatScore,
|
props.customFormatScore = movieFile.customFormatScore;
|
||||||
qualityCutoffNotMet: movieFile.qualityCutoffNotMet
|
props.edition = movieFile.edition;
|
||||||
};
|
props.languages = file.languages;
|
||||||
|
props.quality = file.quality;
|
||||||
|
props.releaseGroup = file.releaseGroup;
|
||||||
|
props.indexerFlags = file.indexerFlags;
|
||||||
|
|
||||||
if (languages) {
|
return updateItem({
|
||||||
props.languages = languages;
|
section,
|
||||||
}
|
id,
|
||||||
|
...props
|
||||||
if (indexerFlags !== undefined) {
|
});
|
||||||
props.indexerFlags = indexerFlags;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (quality) {
|
|
||||||
props.quality = quality;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (edition !== undefined) {
|
|
||||||
props.edition = edition;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (releaseGroup !== undefined) {
|
|
||||||
props.releaseGroup = releaseGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
return updateItem({ section, id, ...props });
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
set({
|
set({
|
||||||
|
|
|
@ -183,6 +183,55 @@ namespace Radarr.Api.V3.MovieFiles
|
||||||
return new { };
|
return new { };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPut("bulk")]
|
||||||
|
[Consumes("application/json")]
|
||||||
|
public object SetPropertiesBulk([FromBody] List<MovieFileResource> resources)
|
||||||
|
{
|
||||||
|
var movieFiles = _mediaFileService.GetMovies(resources.Select(r => r.Id));
|
||||||
|
|
||||||
|
foreach (var movieFile in movieFiles)
|
||||||
|
{
|
||||||
|
var resourceMovieFile = resources.Single(r => r.Id == movieFile.Id);
|
||||||
|
|
||||||
|
if (resourceMovieFile.Languages != null)
|
||||||
|
{
|
||||||
|
// Don't allow user to set files with 'Any' or 'Original' language
|
||||||
|
movieFile.Languages = resourceMovieFile.Languages.Where(l => l != null && l != Language.Any && l != Language.Original).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resourceMovieFile.Quality != null)
|
||||||
|
{
|
||||||
|
movieFile.Quality = resourceMovieFile.Quality;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resourceMovieFile.SceneName != null && SceneChecker.IsSceneTitle(resourceMovieFile.SceneName))
|
||||||
|
{
|
||||||
|
movieFile.SceneName = resourceMovieFile.SceneName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resourceMovieFile.Edition != null)
|
||||||
|
{
|
||||||
|
movieFile.Edition = resourceMovieFile.Edition;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resourceMovieFile.ReleaseGroup != null)
|
||||||
|
{
|
||||||
|
movieFile.ReleaseGroup = resourceMovieFile.ReleaseGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resourceMovieFile.IndexerFlags.HasValue)
|
||||||
|
{
|
||||||
|
movieFile.IndexerFlags = (IndexerFlags)resourceMovieFile.IndexerFlags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_mediaFileService.Update(movieFiles);
|
||||||
|
|
||||||
|
var movie = _movieService.GetMovie(movieFiles.First().MovieId);
|
||||||
|
|
||||||
|
return Accepted(movieFiles.ConvertAll(f => f.ToResource(movie, _upgradableSpecification, _formatCalculator)));
|
||||||
|
}
|
||||||
|
|
||||||
[NonAction]
|
[NonAction]
|
||||||
public void Handle(MovieFileAddedEvent message)
|
public void Handle(MovieFileAddedEvent message)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue