mirror of
https://github.com/Radarr/Radarr.git
synced 2024-11-19 17:32:38 +01:00
New: Set Indexer flags in Manual Import
This commit is contained in:
parent
25ab396a2c
commit
9dd31be7b3
@ -282,6 +282,7 @@ FormInputGroup.propTypes = {
|
|||||||
includeNoChange: PropTypes.bool,
|
includeNoChange: PropTypes.bool,
|
||||||
includeNoChangeDisabled: PropTypes.bool,
|
includeNoChangeDisabled: PropTypes.bool,
|
||||||
selectedValueOptions: PropTypes.object,
|
selectedValueOptions: PropTypes.object,
|
||||||
|
indexerFlags: PropTypes.number,
|
||||||
pending: PropTypes.bool,
|
pending: PropTypes.bool,
|
||||||
errors: PropTypes.arrayOf(PropTypes.object),
|
errors: PropTypes.arrayOf(PropTypes.object),
|
||||||
warnings: PropTypes.arrayOf(PropTypes.object),
|
warnings: PropTypes.arrayOf(PropTypes.object),
|
||||||
|
@ -4,22 +4,18 @@ import { createSelector } from 'reselect';
|
|||||||
import AppState from 'App/State/AppState';
|
import AppState from 'App/State/AppState';
|
||||||
import EnhancedSelectInput from './EnhancedSelectInput';
|
import EnhancedSelectInput from './EnhancedSelectInput';
|
||||||
|
|
||||||
interface IndexerFlagsSelectInputProps {
|
|
||||||
name: string;
|
|
||||||
indexerFlags: number;
|
|
||||||
onChange(payload: object): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectIndexerFlagsValues = (selectedFlags: number) =>
|
const selectIndexerFlagsValues = (selectedFlags: number) =>
|
||||||
createSelector(
|
createSelector(
|
||||||
(state: AppState) => state.settings.indexerFlags,
|
(state: AppState) => state.settings.indexerFlags,
|
||||||
(indexerFlags) => {
|
(indexerFlags) => {
|
||||||
const value = indexerFlags.items
|
const value = indexerFlags.items.reduce((acc: number[], { id }) => {
|
||||||
.filter(
|
|
||||||
// eslint-disable-next-line no-bitwise
|
// eslint-disable-next-line no-bitwise
|
||||||
(item) => (selectedFlags & item.id) === item.id
|
if ((selectedFlags & id) === id) {
|
||||||
)
|
acc.push(id);
|
||||||
.map(({ id }) => id);
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
const values = indexerFlags.items.map(({ id, name }) => ({
|
const values = indexerFlags.items.map(({ id, name }) => ({
|
||||||
key: id,
|
key: id,
|
||||||
@ -33,6 +29,12 @@ const selectIndexerFlagsValues = (selectedFlags: number) =>
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
interface IndexerFlagsSelectInputProps {
|
||||||
|
name: string;
|
||||||
|
indexerFlags: number;
|
||||||
|
onChange(payload: object): void;
|
||||||
|
}
|
||||||
|
|
||||||
function IndexerFlagsSelectInput(props: IndexerFlagsSelectInputProps) {
|
function IndexerFlagsSelectInput(props: IndexerFlagsSelectInputProps) {
|
||||||
const { indexerFlags, onChange } = props;
|
const { indexerFlags, onChange } = props;
|
||||||
|
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Modal from 'Components/Modal/Modal';
|
||||||
|
import SelectIndexerFlagsModalContent from './SelectIndexerFlagsModalContent';
|
||||||
|
|
||||||
|
interface SelectIndexerFlagsModalProps {
|
||||||
|
isOpen: boolean;
|
||||||
|
indexerFlags: number;
|
||||||
|
modalTitle: string;
|
||||||
|
onIndexerFlagsSelect(indexerFlags: number): void;
|
||||||
|
onModalClose(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectIndexerFlagsModal(props: SelectIndexerFlagsModalProps) {
|
||||||
|
const {
|
||||||
|
isOpen,
|
||||||
|
indexerFlags,
|
||||||
|
modalTitle,
|
||||||
|
onIndexerFlagsSelect,
|
||||||
|
onModalClose,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal isOpen={isOpen} onModalClose={onModalClose}>
|
||||||
|
<SelectIndexerFlagsModalContent
|
||||||
|
indexerFlags={indexerFlags}
|
||||||
|
modalTitle={modalTitle}
|
||||||
|
onIndexerFlagsSelect={onIndexerFlagsSelect}
|
||||||
|
onModalClose={onModalClose}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SelectIndexerFlagsModal;
|
@ -0,0 +1,7 @@
|
|||||||
|
.modalBody {
|
||||||
|
composes: modalBody from '~Components/Modal/ModalBody.css';
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
7
frontend/src/InteractiveImport/IndexerFlags/SelectIndexerFlagsModalContent.css.d.ts
vendored
Normal file
7
frontend/src/InteractiveImport/IndexerFlags/SelectIndexerFlagsModalContent.css.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// This file is automatically generated.
|
||||||
|
// Please do not change this file!
|
||||||
|
interface CssExports {
|
||||||
|
'modalBody': string;
|
||||||
|
}
|
||||||
|
export const cssExports: CssExports;
|
||||||
|
export default cssExports;
|
@ -0,0 +1,75 @@
|
|||||||
|
import React, { useCallback, useState } from 'react';
|
||||||
|
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 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, scrollDirections } from 'Helpers/Props';
|
||||||
|
import translate from 'Utilities/String/translate';
|
||||||
|
import styles from './SelectIndexerFlagsModalContent.css';
|
||||||
|
|
||||||
|
interface SelectIndexerFlagsModalContentProps {
|
||||||
|
indexerFlags: number;
|
||||||
|
modalTitle: string;
|
||||||
|
onIndexerFlagsSelect(indexerFlags: number): void;
|
||||||
|
onModalClose(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectIndexerFlagsModalContent(
|
||||||
|
props: SelectIndexerFlagsModalContentProps
|
||||||
|
) {
|
||||||
|
const { modalTitle, onIndexerFlagsSelect, onModalClose } = props;
|
||||||
|
const [indexerFlags, setIndexerFlags] = useState(props.indexerFlags);
|
||||||
|
|
||||||
|
const onIndexerFlagsChange = useCallback(
|
||||||
|
({ value }: { value: number }) => {
|
||||||
|
setIndexerFlags(value);
|
||||||
|
},
|
||||||
|
[setIndexerFlags]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onIndexerFlagsSelectWrapper = useCallback(() => {
|
||||||
|
onIndexerFlagsSelect(indexerFlags);
|
||||||
|
}, [indexerFlags, onIndexerFlagsSelect]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ModalContent onModalClose={onModalClose}>
|
||||||
|
<ModalHeader>
|
||||||
|
{translate('SetIndexerFlagsModalTitle', { modalTitle })}
|
||||||
|
</ModalHeader>
|
||||||
|
|
||||||
|
<ModalBody
|
||||||
|
className={styles.modalBody}
|
||||||
|
scrollDirection={scrollDirections.NONE}
|
||||||
|
>
|
||||||
|
<Form>
|
||||||
|
<FormGroup>
|
||||||
|
<FormLabel>{translate('IndexerFlags')}</FormLabel>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.INDEXER_FLAGS_SELECT}
|
||||||
|
name="indexerFlags"
|
||||||
|
indexerFlags={indexerFlags}
|
||||||
|
autoFocus={true}
|
||||||
|
onChange={onIndexerFlagsChange}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
</Form>
|
||||||
|
</ModalBody>
|
||||||
|
|
||||||
|
<ModalFooter>
|
||||||
|
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
|
||||||
|
|
||||||
|
<Button kind={kinds.SUCCESS} onPress={onIndexerFlagsSelectWrapper}>
|
||||||
|
{translate('SetIndexerFlags')}
|
||||||
|
</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</ModalContent>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SelectIndexerFlagsModalContent;
|
@ -26,6 +26,7 @@ import usePrevious from 'Helpers/Hooks/usePrevious';
|
|||||||
import useSelectState from 'Helpers/Hooks/useSelectState';
|
import useSelectState from 'Helpers/Hooks/useSelectState';
|
||||||
import { align, icons, kinds, scrollDirections } from 'Helpers/Props';
|
import { align, icons, kinds, scrollDirections } from 'Helpers/Props';
|
||||||
import ImportMode from 'InteractiveImport/ImportMode';
|
import ImportMode from 'InteractiveImport/ImportMode';
|
||||||
|
import SelectIndexerFlagsModal from 'InteractiveImport/IndexerFlags/SelectIndexerFlagsModal';
|
||||||
import InteractiveImport, {
|
import InteractiveImport, {
|
||||||
InteractiveImportCommandOptions,
|
InteractiveImportCommandOptions,
|
||||||
} from 'InteractiveImport/InteractiveImport';
|
} from 'InteractiveImport/InteractiveImport';
|
||||||
@ -59,7 +60,13 @@ import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
|||||||
import InteractiveImportRow from './InteractiveImportRow';
|
import InteractiveImportRow from './InteractiveImportRow';
|
||||||
import styles from './InteractiveImportModalContent.css';
|
import styles from './InteractiveImportModalContent.css';
|
||||||
|
|
||||||
type SelectType = 'select' | 'movie' | 'releaseGroup' | 'quality' | 'language';
|
type SelectType =
|
||||||
|
| 'select'
|
||||||
|
| 'movie'
|
||||||
|
| 'releaseGroup'
|
||||||
|
| 'quality'
|
||||||
|
| 'language'
|
||||||
|
| 'indexerFlags';
|
||||||
|
|
||||||
type FilterExistingFiles = 'all' | 'new';
|
type FilterExistingFiles = 'all' | 'new';
|
||||||
|
|
||||||
@ -113,6 +120,15 @@ const COLUMNS = [
|
|||||||
isSortable: true,
|
isSortable: true,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'indexerFlags',
|
||||||
|
label: React.createElement(Icon, {
|
||||||
|
name: icons.FLAG,
|
||||||
|
title: () => translate('IndexerFlags'),
|
||||||
|
}),
|
||||||
|
isSortable: true,
|
||||||
|
isVisible: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'rejections',
|
name: 'rejections',
|
||||||
label: React.createElement(Icon, {
|
label: React.createElement(Icon, {
|
||||||
@ -257,8 +273,18 @@ function InteractiveImportModalContent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const showIndexerFlags = items.some((item) => item.indexerFlags);
|
||||||
|
|
||||||
|
if (!showIndexerFlags) {
|
||||||
|
const indexerFlagsColumn = result.find((c) => c.name === 'indexerFlags');
|
||||||
|
|
||||||
|
if (indexerFlagsColumn) {
|
||||||
|
indexerFlagsColumn.isVisible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}, [showMovie]);
|
}, [showMovie, items]);
|
||||||
|
|
||||||
const selectedIds: number[] = useMemo(() => {
|
const selectedIds: number[] = useMemo(() => {
|
||||||
return getSelectedIds(selectedState);
|
return getSelectedIds(selectedState);
|
||||||
@ -283,6 +309,10 @@ function InteractiveImportModalContent(
|
|||||||
key: 'language',
|
key: 'language',
|
||||||
value: translate('SelectLanguage'),
|
value: translate('SelectLanguage'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'indexerFlags',
|
||||||
|
value: translate('SelectIndexerFlags'),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
if (allowMovieChange) {
|
if (allowMovieChange) {
|
||||||
@ -416,7 +446,14 @@ function InteractiveImportModalContent(
|
|||||||
const isSelected = selectedIds.indexOf(item.id) > -1;
|
const isSelected = selectedIds.indexOf(item.id) > -1;
|
||||||
|
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
const { movie, releaseGroup, quality, languages, movieFileId } = item;
|
const {
|
||||||
|
movie,
|
||||||
|
releaseGroup,
|
||||||
|
quality,
|
||||||
|
languages,
|
||||||
|
indexerFlags,
|
||||||
|
movieFileId,
|
||||||
|
} = item;
|
||||||
|
|
||||||
if (!movie) {
|
if (!movie) {
|
||||||
setInteractiveImportErrorMessage(
|
setInteractiveImportErrorMessage(
|
||||||
@ -450,6 +487,7 @@ function InteractiveImportModalContent(
|
|||||||
releaseGroup,
|
releaseGroup,
|
||||||
quality,
|
quality,
|
||||||
languages,
|
languages,
|
||||||
|
indexerFlags,
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -463,6 +501,7 @@ function InteractiveImportModalContent(
|
|||||||
releaseGroup,
|
releaseGroup,
|
||||||
quality,
|
quality,
|
||||||
languages,
|
languages,
|
||||||
|
indexerFlags,
|
||||||
downloadId,
|
downloadId,
|
||||||
movieFileId,
|
movieFileId,
|
||||||
});
|
});
|
||||||
@ -620,6 +659,22 @@ function InteractiveImportModalContent(
|
|||||||
[selectedIds, dispatch]
|
[selectedIds, dispatch]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const onIndexerFlagsSelect = useCallback(
|
||||||
|
(indexerFlags: number) => {
|
||||||
|
dispatch(
|
||||||
|
updateInteractiveImportItems({
|
||||||
|
ids: selectedIds,
|
||||||
|
indexerFlags,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
dispatch(reprocessInteractiveImportItems({ ids: selectedIds }));
|
||||||
|
|
||||||
|
setSelectModalOpen(null);
|
||||||
|
},
|
||||||
|
[selectedIds, dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
const errorMessage = getErrorMessage(
|
const errorMessage = getErrorMessage(
|
||||||
error,
|
error,
|
||||||
translate('InteractiveImportLoadError')
|
translate('InteractiveImportLoadError')
|
||||||
@ -794,6 +849,14 @@ function InteractiveImportModalContent(
|
|||||||
onModalClose={onSelectModalClose}
|
onModalClose={onSelectModalClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<SelectIndexerFlagsModal
|
||||||
|
isOpen={selectModalOpen === 'indexerFlags'}
|
||||||
|
indexerFlags={0}
|
||||||
|
modalTitle={modalTitle}
|
||||||
|
onIndexerFlagsSelect={onIndexerFlagsSelect}
|
||||||
|
onModalClose={onSelectModalClose}
|
||||||
|
/>
|
||||||
|
|
||||||
<ConfirmModal
|
<ConfirmModal
|
||||||
isOpen={isConfirmDeleteModalOpen}
|
isOpen={isConfirmDeleteModalOpen}
|
||||||
kind={kinds.DANGER}
|
kind={kinds.DANGER}
|
||||||
|
@ -8,11 +8,13 @@ import Column from 'Components/Table/Column';
|
|||||||
import TableRow from 'Components/Table/TableRow';
|
import TableRow from 'Components/Table/TableRow';
|
||||||
import Popover from 'Components/Tooltip/Popover';
|
import Popover from 'Components/Tooltip/Popover';
|
||||||
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
||||||
|
import SelectIndexerFlagsModal from 'InteractiveImport/IndexerFlags/SelectIndexerFlagsModal';
|
||||||
import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal';
|
import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal';
|
||||||
import SelectMovieModal from 'InteractiveImport/Movie/SelectMovieModal';
|
import SelectMovieModal from 'InteractiveImport/Movie/SelectMovieModal';
|
||||||
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
|
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
|
||||||
import SelectReleaseGroupModal from 'InteractiveImport/ReleaseGroup/SelectReleaseGroupModal';
|
import SelectReleaseGroupModal from 'InteractiveImport/ReleaseGroup/SelectReleaseGroupModal';
|
||||||
import Language from 'Language/Language';
|
import Language from 'Language/Language';
|
||||||
|
import IndexerFlags from 'Movie/IndexerFlags';
|
||||||
import Movie from 'Movie/Movie';
|
import Movie from 'Movie/Movie';
|
||||||
import MovieFormats from 'Movie/MovieFormats';
|
import MovieFormats from 'Movie/MovieFormats';
|
||||||
import MovieLanguage from 'Movie/MovieLanguage';
|
import MovieLanguage from 'Movie/MovieLanguage';
|
||||||
@ -30,7 +32,12 @@ import translate from 'Utilities/String/translate';
|
|||||||
import InteractiveImportRowCellPlaceholder from './InteractiveImportRowCellPlaceholder';
|
import InteractiveImportRowCellPlaceholder from './InteractiveImportRowCellPlaceholder';
|
||||||
import styles from './InteractiveImportRow.css';
|
import styles from './InteractiveImportRow.css';
|
||||||
|
|
||||||
type SelectType = 'movie' | 'releaseGroup' | 'quality' | 'language';
|
type SelectType =
|
||||||
|
| 'movie'
|
||||||
|
| 'releaseGroup'
|
||||||
|
| 'quality'
|
||||||
|
| 'language'
|
||||||
|
| 'indexerFlags';
|
||||||
|
|
||||||
type SelectedChangeProps = SelectStateInputProps & {
|
type SelectedChangeProps = SelectStateInputProps & {
|
||||||
hasMovieFileId: boolean;
|
hasMovieFileId: boolean;
|
||||||
@ -47,6 +54,7 @@ interface InteractiveImportRowProps {
|
|||||||
size: number;
|
size: number;
|
||||||
customFormats?: object[];
|
customFormats?: object[];
|
||||||
customFormatScore?: number;
|
customFormatScore?: number;
|
||||||
|
indexerFlags: number;
|
||||||
rejections: Rejection[];
|
rejections: Rejection[];
|
||||||
columns: Column[];
|
columns: Column[];
|
||||||
movieFileId?: number;
|
movieFileId?: number;
|
||||||
@ -69,6 +77,7 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
|
|||||||
size,
|
size,
|
||||||
customFormats,
|
customFormats,
|
||||||
customFormatScore,
|
customFormatScore,
|
||||||
|
indexerFlags,
|
||||||
rejections,
|
rejections,
|
||||||
isSelected,
|
isSelected,
|
||||||
modalTitle,
|
modalTitle,
|
||||||
@ -84,6 +93,10 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
|
|||||||
() => columns.find((c) => c.name === 'movie')?.isVisible ?? false,
|
() => columns.find((c) => c.name === 'movie')?.isVisible ?? false,
|
||||||
[columns]
|
[columns]
|
||||||
);
|
);
|
||||||
|
const isIndexerFlagsColumnVisible = useMemo(
|
||||||
|
() => columns.find((c) => c.name === 'indexerFlags')?.isVisible ?? false,
|
||||||
|
[columns]
|
||||||
|
);
|
||||||
|
|
||||||
const [selectModalOpen, setSelectModalOpen] = useState<SelectType | null>(
|
const [selectModalOpen, setSelectModalOpen] = useState<SelectType | null>(
|
||||||
null
|
null
|
||||||
@ -223,12 +236,34 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
|
|||||||
[id, dispatch, setSelectModalOpen, selectRowAfterChange]
|
[id, dispatch, setSelectModalOpen, selectRowAfterChange]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const onSelectIndexerFlagsPress = useCallback(() => {
|
||||||
|
setSelectModalOpen('indexerFlags');
|
||||||
|
}, [setSelectModalOpen]);
|
||||||
|
|
||||||
|
const onIndexerFlagsSelect = useCallback(
|
||||||
|
(indexerFlags: number) => {
|
||||||
|
dispatch(
|
||||||
|
updateInteractiveImportItem({
|
||||||
|
id,
|
||||||
|
indexerFlags,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
dispatch(reprocessInteractiveImportItems({ ids: [id] }));
|
||||||
|
|
||||||
|
setSelectModalOpen(null);
|
||||||
|
selectRowAfterChange();
|
||||||
|
},
|
||||||
|
[id, dispatch, setSelectModalOpen, selectRowAfterChange]
|
||||||
|
);
|
||||||
|
|
||||||
const movieTitle = movie ? movie.title : '';
|
const movieTitle = movie ? movie.title : '';
|
||||||
|
|
||||||
const showMoviePlaceholder = isSelected && !movie;
|
const showMoviePlaceholder = isSelected && !movie;
|
||||||
const showReleaseGroupPlaceholder = isSelected && !releaseGroup;
|
const showReleaseGroupPlaceholder = isSelected && !releaseGroup;
|
||||||
const showQualityPlaceholder = isSelected && !quality;
|
const showQualityPlaceholder = isSelected && !quality;
|
||||||
const showLanguagePlaceholder = isSelected && !languages;
|
const showLanguagePlaceholder = isSelected && !languages;
|
||||||
|
const showIndexerFlagsPlaceholder = isSelected && !indexerFlags;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
@ -311,6 +346,28 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
|
|||||||
) : null}
|
) : null}
|
||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
|
|
||||||
|
{isIndexerFlagsColumnVisible ? (
|
||||||
|
<TableRowCellButton
|
||||||
|
title={translate('ClickToChangeIndexerFlags')}
|
||||||
|
onPress={onSelectIndexerFlagsPress}
|
||||||
|
>
|
||||||
|
{showIndexerFlagsPlaceholder ? (
|
||||||
|
<InteractiveImportRowCellPlaceholder isOptional={true} />
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{indexerFlags ? (
|
||||||
|
<Popover
|
||||||
|
anchor={<Icon name={icons.FLAG} kind={kinds.PRIMARY} />}
|
||||||
|
title={translate('IndexerFlags')}
|
||||||
|
body={<IndexerFlags indexerFlags={indexerFlags} />}
|
||||||
|
position={tooltipPositions.LEFT}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</TableRowCellButton>
|
||||||
|
) : null}
|
||||||
|
|
||||||
<TableRowCell>
|
<TableRowCell>
|
||||||
{rejections.length ? (
|
{rejections.length ? (
|
||||||
<Popover
|
<Popover
|
||||||
@ -361,6 +418,14 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
|
|||||||
onLanguagesSelect={onLanguagesSelect}
|
onLanguagesSelect={onLanguagesSelect}
|
||||||
onModalClose={onSelectModalClose}
|
onModalClose={onSelectModalClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<SelectIndexerFlagsModal
|
||||||
|
isOpen={selectModalOpen === 'indexerFlags'}
|
||||||
|
indexerFlags={indexerFlags ?? 0}
|
||||||
|
modalTitle={modalTitle}
|
||||||
|
onIndexerFlagsSelect={onIndexerFlagsSelect}
|
||||||
|
onModalClose={onSelectModalClose}
|
||||||
|
/>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ export interface InteractiveImportCommandOptions {
|
|||||||
releaseGroup?: string;
|
releaseGroup?: string;
|
||||||
quality: QualityModel;
|
quality: QualityModel;
|
||||||
languages: Language[];
|
languages: Language[];
|
||||||
|
indexerFlags: number;
|
||||||
downloadId?: string;
|
downloadId?: string;
|
||||||
movieFileId?: number;
|
movieFileId?: number;
|
||||||
}
|
}
|
||||||
@ -27,6 +28,7 @@ interface InteractiveImport extends ModelBase {
|
|||||||
movie?: Movie;
|
movie?: Movie;
|
||||||
qualityWeight: number;
|
qualityWeight: number;
|
||||||
customFormats: object[];
|
customFormats: object[];
|
||||||
|
indexerFlags: number;
|
||||||
rejections: Rejection[];
|
rejections: Rejection[];
|
||||||
movieFileId?: number;
|
movieFileId?: number;
|
||||||
}
|
}
|
||||||
|
@ -39,8 +39,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.rejected,
|
.rejected,
|
||||||
.indexerFlags,
|
.indexerFlags {
|
||||||
.download {
|
|
||||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||||
|
|
||||||
width: 50px;
|
width: 50px;
|
||||||
|
@ -11,6 +11,7 @@ import Tooltip from 'Components/Tooltip/Tooltip';
|
|||||||
import type DownloadProtocol from 'DownloadClient/DownloadProtocol';
|
import type DownloadProtocol from 'DownloadClient/DownloadProtocol';
|
||||||
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
||||||
import Language from 'Language/Language';
|
import Language from 'Language/Language';
|
||||||
|
import IndexerFlags from 'Movie/IndexerFlags';
|
||||||
import MovieFormats from 'Movie/MovieFormats';
|
import MovieFormats from 'Movie/MovieFormats';
|
||||||
import MovieLanguage from 'Movie/MovieLanguage';
|
import MovieLanguage from 'Movie/MovieLanguage';
|
||||||
import MovieQuality from 'Movie/MovieQuality';
|
import MovieQuality from 'Movie/MovieQuality';
|
||||||
@ -90,8 +91,8 @@ interface InteractiveSearchRowProps {
|
|||||||
customFormats: CustomFormat[];
|
customFormats: CustomFormat[];
|
||||||
customFormatScore: number;
|
customFormatScore: number;
|
||||||
mappedMovieId?: number;
|
mappedMovieId?: number;
|
||||||
|
indexerFlags: number;
|
||||||
rejections: string[];
|
rejections: string[];
|
||||||
indexerFlags: string[];
|
|
||||||
downloadAllowed: boolean;
|
downloadAllowed: boolean;
|
||||||
isGrabbing: boolean;
|
isGrabbing: boolean;
|
||||||
isGrabbed: boolean;
|
isGrabbed: boolean;
|
||||||
@ -125,8 +126,8 @@ function InteractiveSearchRow(props: InteractiveSearchRowProps) {
|
|||||||
customFormatScore,
|
customFormatScore,
|
||||||
customFormats,
|
customFormats,
|
||||||
mappedMovieId,
|
mappedMovieId,
|
||||||
|
indexerFlags = 0,
|
||||||
rejections = [],
|
rejections = [],
|
||||||
indexerFlags = [],
|
|
||||||
downloadAllowed,
|
downloadAllowed,
|
||||||
isGrabbing = false,
|
isGrabbing = false,
|
||||||
isGrabbed = false,
|
isGrabbed = false,
|
||||||
@ -276,22 +277,16 @@ function InteractiveSearchRow(props: InteractiveSearchRowProps) {
|
|||||||
customFormats.length
|
customFormats.length
|
||||||
)}
|
)}
|
||||||
tooltip={<MovieFormats formats={customFormats} />}
|
tooltip={<MovieFormats formats={customFormats} />}
|
||||||
position={tooltipPositions.TOP}
|
position={tooltipPositions.LEFT}
|
||||||
/>
|
/>
|
||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
|
|
||||||
<TableRowCell className={styles.indexerFlags}>
|
<TableRowCell className={styles.indexerFlags}>
|
||||||
{indexerFlags.length ? (
|
{indexerFlags ? (
|
||||||
<Popover
|
<Popover
|
||||||
anchor={<Icon name={icons.FLAG} kind={kinds.PRIMARY} />}
|
anchor={<Icon name={icons.FLAG} kind={kinds.PRIMARY} />}
|
||||||
title={translate('IndexerFlags')}
|
title={translate('IndexerFlags')}
|
||||||
body={
|
body={<IndexerFlags indexerFlags={indexerFlags} />}
|
||||||
<ul>
|
|
||||||
{indexerFlags.map((flag, index) => {
|
|
||||||
return <li key={index}>{flag}</li>;
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
}
|
|
||||||
position={tooltipPositions.LEFT}
|
position={tooltipPositions.LEFT}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
26
frontend/src/Movie/IndexerFlags.tsx
Normal file
26
frontend/src/Movie/IndexerFlags.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import createIndexerFlagsSelector from 'Store/Selectors/createIndexerFlagsSelector';
|
||||||
|
|
||||||
|
interface IndexerFlagsProps {
|
||||||
|
indexerFlags: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function IndexerFlags({ indexerFlags = 0 }: IndexerFlagsProps) {
|
||||||
|
const allIndexerFlags = useSelector(createIndexerFlagsSelector);
|
||||||
|
|
||||||
|
const flags = allIndexerFlags.items.filter(
|
||||||
|
// eslint-disable-next-line no-bitwise
|
||||||
|
(item) => (indexerFlags & item.id) === item.id
|
||||||
|
);
|
||||||
|
|
||||||
|
return flags.length ? (
|
||||||
|
<ul>
|
||||||
|
{flags.map((flag, index) => {
|
||||||
|
return <li key={index}>{flag.name}</li>;
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IndexerFlags;
|
@ -57,3 +57,9 @@
|
|||||||
|
|
||||||
width: 55px;
|
width: 55px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.indexerFlags {
|
||||||
|
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||||
|
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
@ -9,6 +9,7 @@ interface CssExports {
|
|||||||
'dateAdded': string;
|
'dateAdded': string;
|
||||||
'download': string;
|
'download': string;
|
||||||
'formats': string;
|
'formats': string;
|
||||||
|
'indexerFlags': string;
|
||||||
'language': string;
|
'language': string;
|
||||||
'languages': string;
|
'languages': string;
|
||||||
'quality': string;
|
'quality': string;
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import Icon from 'Components/Icon';
|
||||||
import IconButton from 'Components/Link/IconButton';
|
import IconButton from 'Components/Link/IconButton';
|
||||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||||
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
|
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
|
||||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||||
import TableRow from 'Components/Table/TableRow';
|
import TableRow from 'Components/Table/TableRow';
|
||||||
|
import Popover from 'Components/Tooltip/Popover';
|
||||||
import Tooltip from 'Components/Tooltip/Tooltip';
|
import Tooltip from 'Components/Tooltip/Tooltip';
|
||||||
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
||||||
|
import IndexerFlags from 'Movie/IndexerFlags';
|
||||||
import MovieFormats from 'Movie/MovieFormats';
|
import MovieFormats from 'Movie/MovieFormats';
|
||||||
import MovieLanguage from 'Movie/MovieLanguage';
|
import MovieLanguage from 'Movie/MovieLanguage';
|
||||||
import MovieQuality from 'Movie/MovieQuality';
|
import MovieQuality from 'Movie/MovieQuality';
|
||||||
@ -82,6 +85,7 @@ class MovieFileEditorRow extends Component {
|
|||||||
qualityCutoffNotMet,
|
qualityCutoffNotMet,
|
||||||
customFormats,
|
customFormats,
|
||||||
customFormatScore,
|
customFormatScore,
|
||||||
|
indexerFlags,
|
||||||
languages,
|
languages,
|
||||||
dateAdded,
|
dateAdded,
|
||||||
columns
|
columns
|
||||||
@ -143,12 +147,30 @@ class MovieFileEditorRow extends Component {
|
|||||||
customFormats.length
|
customFormats.length
|
||||||
)}
|
)}
|
||||||
tooltip={<MovieFormats formats={customFormats} />}
|
tooltip={<MovieFormats formats={customFormats} />}
|
||||||
position={tooltipPositions.TOP}
|
position={tooltipPositions.LEFT}
|
||||||
/>
|
/>
|
||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (name === 'indexerFlags') {
|
||||||
|
return (
|
||||||
|
<TableRowCell
|
||||||
|
key={name}
|
||||||
|
className={styles.indexerFlags}
|
||||||
|
>
|
||||||
|
{indexerFlags ? (
|
||||||
|
<Popover
|
||||||
|
anchor={<Icon name={icons.FLAG} kind={kinds.PRIMARY} />}
|
||||||
|
title={translate('IndexerFlags')}
|
||||||
|
body={<IndexerFlags indexerFlags={indexerFlags} />}
|
||||||
|
position={tooltipPositions.LEFT}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (name === 'languages') {
|
if (name === 'languages') {
|
||||||
return (
|
return (
|
||||||
<TableRowCell
|
<TableRowCell
|
||||||
@ -363,6 +385,7 @@ MovieFileEditorRow.propTypes = {
|
|||||||
releaseGroup: PropTypes.string,
|
releaseGroup: PropTypes.string,
|
||||||
customFormats: PropTypes.arrayOf(PropTypes.object).isRequired,
|
customFormats: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
customFormatScore: PropTypes.number.isRequired,
|
customFormatScore: PropTypes.number.isRequired,
|
||||||
|
indexerFlags: PropTypes.number.isRequired,
|
||||||
qualityCutoffNotMet: PropTypes.bool.isRequired,
|
qualityCutoffNotMet: PropTypes.bool.isRequired,
|
||||||
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
|
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
mediaInfo: PropTypes.object,
|
mediaInfo: PropTypes.object,
|
||||||
@ -372,7 +395,8 @@ MovieFileEditorRow.propTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
MovieFileEditorRow.defaultProps = {
|
MovieFileEditorRow.defaultProps = {
|
||||||
customFormats: []
|
customFormats: [],
|
||||||
|
indexerFlags: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MovieFileEditorRow;
|
export default MovieFileEditorRow;
|
||||||
|
@ -15,6 +15,7 @@ export interface MovieFile extends ModelBase {
|
|||||||
languages: Language[];
|
languages: Language[];
|
||||||
quality: QualityModel;
|
quality: QualityModel;
|
||||||
customFormats: CustomFormat[];
|
customFormats: CustomFormat[];
|
||||||
|
indexerFlags: number;
|
||||||
mediaInfo: MediaInfo;
|
mediaInfo: MediaInfo;
|
||||||
qualityCutoffNotMet: boolean;
|
qualityCutoffNotMet: boolean;
|
||||||
}
|
}
|
||||||
|
@ -159,6 +159,7 @@ export const actionHandlers = handleThunks({
|
|||||||
quality: item.quality,
|
quality: item.quality,
|
||||||
languages: item.languages,
|
languages: item.languages,
|
||||||
releaseGroup: item.releaseGroup,
|
releaseGroup: item.releaseGroup,
|
||||||
|
indexerFlags: item.indexerFlags,
|
||||||
downloadId: item.downloadId
|
downloadId: item.downloadId
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -104,6 +104,15 @@ export const defaultState = {
|
|||||||
isVisible: true,
|
isVisible: true,
|
||||||
isSortable: true
|
isSortable: true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'indexerFlags',
|
||||||
|
columnLabel: () => translate('IndexerFlags'),
|
||||||
|
label: React.createElement(Icon, {
|
||||||
|
name: icons.FLAG,
|
||||||
|
title: () => translate('IndexerFlags')
|
||||||
|
}),
|
||||||
|
isVisible: false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'dateAdded',
|
name: 'dateAdded',
|
||||||
label: () => translate('Added'),
|
label: () => translate('Added'),
|
||||||
|
@ -78,8 +78,8 @@ public List<CustomFormat> ParseCustomFormat(Blocklist blocklist, Movie movie)
|
|||||||
MovieInfo = movieInfo,
|
MovieInfo = movieInfo,
|
||||||
Movie = movie,
|
Movie = movie,
|
||||||
Size = blocklist.Size ?? 0,
|
Size = blocklist.Size ?? 0,
|
||||||
IndexerFlags = blocklist.IndexerFlags,
|
Languages = blocklist.Languages,
|
||||||
Languages = blocklist.Languages
|
IndexerFlags = blocklist.IndexerFlags
|
||||||
};
|
};
|
||||||
|
|
||||||
return ParseCustomFormat(input);
|
return ParseCustomFormat(input);
|
||||||
@ -90,7 +90,7 @@ public List<CustomFormat> ParseCustomFormat(MovieHistory history, Movie movie)
|
|||||||
var parsed = Parser.Parser.ParseMovieTitle(history.SourceTitle);
|
var parsed = Parser.Parser.ParseMovieTitle(history.SourceTitle);
|
||||||
|
|
||||||
long.TryParse(history.Data.GetValueOrDefault("size"), out var size);
|
long.TryParse(history.Data.GetValueOrDefault("size"), out var size);
|
||||||
Enum.TryParse(history.Data.GetValueOrDefault("indexerFlags"), true, out IndexerFlags flags);
|
Enum.TryParse(history.Data.GetValueOrDefault("indexerFlags"), true, out IndexerFlags indexerFlags);
|
||||||
|
|
||||||
var movieInfo = new ParsedMovieInfo
|
var movieInfo = new ParsedMovieInfo
|
||||||
{
|
{
|
||||||
@ -108,8 +108,8 @@ public List<CustomFormat> ParseCustomFormat(MovieHistory history, Movie movie)
|
|||||||
MovieInfo = movieInfo,
|
MovieInfo = movieInfo,
|
||||||
Movie = movie,
|
Movie = movie,
|
||||||
Size = size,
|
Size = size,
|
||||||
IndexerFlags = flags,
|
Languages = history.Languages,
|
||||||
Languages = history.Languages
|
IndexerFlags = indexerFlags
|
||||||
};
|
};
|
||||||
|
|
||||||
return ParseCustomFormat(input);
|
return ParseCustomFormat(input);
|
||||||
@ -117,7 +117,7 @@ public List<CustomFormat> ParseCustomFormat(MovieHistory history, Movie movie)
|
|||||||
|
|
||||||
public List<CustomFormat> ParseCustomFormat(LocalMovie localMovie)
|
public List<CustomFormat> ParseCustomFormat(LocalMovie localMovie)
|
||||||
{
|
{
|
||||||
var episodeInfo = new ParsedMovieInfo
|
var movieInfo = new ParsedMovieInfo
|
||||||
{
|
{
|
||||||
MovieTitles = new List<string>() { localMovie.Movie.Title },
|
MovieTitles = new List<string>() { localMovie.Movie.Title },
|
||||||
SimpleReleaseTitle = localMovie.SceneName.IsNotNullOrWhiteSpace() ? localMovie.SceneName.SimplifyReleaseTitle() : Path.GetFileName(localMovie.Path).SimplifyReleaseTitle(),
|
SimpleReleaseTitle = localMovie.SceneName.IsNotNullOrWhiteSpace() ? localMovie.SceneName.SimplifyReleaseTitle() : Path.GetFileName(localMovie.Path).SimplifyReleaseTitle(),
|
||||||
@ -130,10 +130,11 @@ public List<CustomFormat> ParseCustomFormat(LocalMovie localMovie)
|
|||||||
|
|
||||||
var input = new CustomFormatInput
|
var input = new CustomFormatInput
|
||||||
{
|
{
|
||||||
MovieInfo = episodeInfo,
|
MovieInfo = movieInfo,
|
||||||
Movie = localMovie.Movie,
|
Movie = localMovie.Movie,
|
||||||
Size = localMovie.Size,
|
Size = localMovie.Size,
|
||||||
Languages = localMovie.Languages,
|
Languages = localMovie.Languages,
|
||||||
|
IndexerFlags = localMovie.IndexerFlags,
|
||||||
Filename = Path.GetFileName(localMovie.Path)
|
Filename = Path.GetFileName(localMovie.Path)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -203,8 +204,8 @@ private List<CustomFormat> ParseCustomFormat(MovieFile movieFile, Movie movie, L
|
|||||||
MovieInfo = movieInfo,
|
MovieInfo = movieInfo,
|
||||||
Movie = movie,
|
Movie = movie,
|
||||||
Size = movieFile.Size,
|
Size = movieFile.Size,
|
||||||
IndexerFlags = movieFile.IndexerFlags,
|
|
||||||
Languages = movieFile.Languages,
|
Languages = movieFile.Languages,
|
||||||
|
IndexerFlags = movieFile.IndexerFlags,
|
||||||
Filename = Path.GetFileName(movieFile.RelativePath)
|
Filename = Path.GetFileName(movieFile.RelativePath)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ public IndexerFlagSpecificationValidator()
|
|||||||
{
|
{
|
||||||
if (!Enum.IsDefined(typeof(IndexerFlags), qualityValue))
|
if (!Enum.IsDefined(typeof(IndexerFlags), qualityValue))
|
||||||
{
|
{
|
||||||
context.AddFailure(string.Format("Invalid indexer flag condition value: {0}", qualityValue));
|
context.AddFailure($"Invalid indexer flag condition value: {qualityValue}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -23,17 +23,17 @@ public IndexerFlagSpecificationValidator()
|
|||||||
|
|
||||||
public class IndexerFlagSpecification : CustomFormatSpecificationBase
|
public class IndexerFlagSpecification : CustomFormatSpecificationBase
|
||||||
{
|
{
|
||||||
private static readonly IndexerFlagSpecificationValidator Validator = new IndexerFlagSpecificationValidator();
|
private static readonly IndexerFlagSpecificationValidator Validator = new ();
|
||||||
|
|
||||||
public override int Order => 4;
|
public override int Order => 4;
|
||||||
public override string ImplementationName => "Indexer Flag";
|
public override string ImplementationName => "Indexer Flag";
|
||||||
|
|
||||||
[FieldDefinition(1, Label = "Flag", Type = FieldType.Select, SelectOptions = typeof(IndexerFlags))]
|
[FieldDefinition(1, Label = "CustomFormatsSpecificationFlag", Type = FieldType.Select, SelectOptions = typeof(IndexerFlags))]
|
||||||
public int Value { get; set; }
|
public int Value { get; set; }
|
||||||
|
|
||||||
protected override bool IsSatisfiedByWithoutNegate(CustomFormatInput input)
|
protected override bool IsSatisfiedByWithoutNegate(CustomFormatInput input)
|
||||||
{
|
{
|
||||||
return input.IndexerFlags.HasFlag((IndexerFlags)Value) == true;
|
return input.IndexerFlags.HasFlag((IndexerFlags)Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override NzbDroneValidationResult Validate()
|
public override NzbDroneValidationResult Validate()
|
||||||
|
@ -140,12 +140,11 @@ public TrackedDownload TrackDownload(DownloadClientDefinition downloadClient, Do
|
|||||||
var firstHistoryItem = historyItems.FirstOrDefault();
|
var firstHistoryItem = historyItems.FirstOrDefault();
|
||||||
var grabbedEvent = historyItems.FirstOrDefault(v => v.EventType == MovieHistoryEventType.Grabbed);
|
var grabbedEvent = historyItems.FirstOrDefault(v => v.EventType == MovieHistoryEventType.Grabbed);
|
||||||
|
|
||||||
trackedDownload.Indexer = grabbedEvent?.Data["indexer"];
|
trackedDownload.Indexer = grabbedEvent?.Data?.GetValueOrDefault("indexer");
|
||||||
trackedDownload.Added = grabbedEvent?.Date;
|
trackedDownload.Added = grabbedEvent?.Date;
|
||||||
|
|
||||||
if (parsedMovieInfo == null ||
|
if (parsedMovieInfo == null ||
|
||||||
trackedDownload.RemoteMovie == null ||
|
trackedDownload.RemoteMovie?.Movie == null)
|
||||||
trackedDownload.RemoteMovie.Movie == null)
|
|
||||||
{
|
{
|
||||||
parsedMovieInfo = Parser.Parser.ParseMovieTitle(firstHistoryItem.SourceTitle);
|
parsedMovieInfo = Parser.Parser.ParseMovieTitle(firstHistoryItem.SourceTitle);
|
||||||
|
|
||||||
|
@ -39,18 +39,6 @@ public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
|||||||
{
|
{
|
||||||
var id = result.Id;
|
var id = result.Id;
|
||||||
|
|
||||||
IndexerFlags flags = 0;
|
|
||||||
|
|
||||||
if (result.FreeLeech)
|
|
||||||
{
|
|
||||||
flags |= IndexerFlags.G_Freeleech;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.Internal)
|
|
||||||
{
|
|
||||||
flags |= IndexerFlags.G_Internal;
|
|
||||||
}
|
|
||||||
|
|
||||||
var imdbId = 0;
|
var imdbId = 0;
|
||||||
if (result.ImdbId != null && result.ImdbId.Length > 2)
|
if (result.ImdbId != null && result.ImdbId.Length > 2)
|
||||||
{
|
{
|
||||||
@ -68,14 +56,29 @@ public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
|||||||
Peers = result.Leechers + result.Seeders,
|
Peers = result.Leechers + result.Seeders,
|
||||||
PublishDate = result.UploadDate,
|
PublishDate = result.UploadDate,
|
||||||
ImdbId = imdbId,
|
ImdbId = imdbId,
|
||||||
IndexerFlags = flags
|
IndexerFlags = GetIndexerFlags(result)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return torrentInfos.ToArray();
|
return torrentInfos.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
private static IndexerFlags GetIndexerFlags(FileListTorrent item)
|
||||||
|
{
|
||||||
|
IndexerFlags flags = 0;
|
||||||
|
|
||||||
|
if (item.FreeLeech)
|
||||||
|
{
|
||||||
|
flags |= IndexerFlags.G_Freeleech;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.Internal)
|
||||||
|
{
|
||||||
|
flags |= IndexerFlags.G_Internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
private string GetDownloadUrl(string torrentId)
|
private string GetDownloadUrl(string torrentId)
|
||||||
{
|
{
|
||||||
@ -95,5 +98,7 @@ private string GetInfoUrl(string torrentId)
|
|||||||
|
|
||||||
return url.FullUri;
|
return url.FullUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,19 +50,6 @@ public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
|||||||
foreach (var result in queryResults)
|
foreach (var result in queryResults)
|
||||||
{
|
{
|
||||||
var id = result.Id;
|
var id = result.Id;
|
||||||
var internalRelease = result.TypeOrigin == 1;
|
|
||||||
|
|
||||||
IndexerFlags flags = 0;
|
|
||||||
|
|
||||||
if (result.FreeLeech == "yes")
|
|
||||||
{
|
|
||||||
flags |= IndexerFlags.G_Freeleech;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (internalRelease)
|
|
||||||
{
|
|
||||||
flags |= IndexerFlags.G_Internal;
|
|
||||||
}
|
|
||||||
|
|
||||||
torrentInfos.Add(new HDBitsInfo
|
torrentInfos.Add(new HDBitsInfo
|
||||||
{
|
{
|
||||||
@ -75,16 +62,30 @@ public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
|||||||
Seeders = result.Seeders,
|
Seeders = result.Seeders,
|
||||||
Peers = result.Leechers + result.Seeders,
|
Peers = result.Leechers + result.Seeders,
|
||||||
PublishDate = result.Added.ToUniversalTime(),
|
PublishDate = result.Added.ToUniversalTime(),
|
||||||
Internal = internalRelease,
|
|
||||||
ImdbId = result.ImdbInfo?.Id ?? 0,
|
ImdbId = result.ImdbInfo?.Id ?? 0,
|
||||||
IndexerFlags = flags
|
IndexerFlags = GetIndexerFlags(result)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return torrentInfos.ToArray();
|
return torrentInfos.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
private static IndexerFlags GetIndexerFlags(TorrentQueryResponse item)
|
||||||
|
{
|
||||||
|
IndexerFlags flags = 0;
|
||||||
|
|
||||||
|
if (item.FreeLeech == "yes")
|
||||||
|
{
|
||||||
|
flags |= IndexerFlags.G_Freeleech;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.TypeOrigin == 1)
|
||||||
|
{
|
||||||
|
flags |= IndexerFlags.G_Internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
private string GetDownloadUrl(string torrentId)
|
private string GetDownloadUrl(string torrentId)
|
||||||
{
|
{
|
||||||
@ -104,5 +105,7 @@ private string GetInfoUrl(string torrentId)
|
|||||||
|
|
||||||
return url.FullUri;
|
return url.FullUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,6 +193,7 @@
|
|||||||
"Clear": "Clear",
|
"Clear": "Clear",
|
||||||
"ClearBlocklist": "Clear blocklist",
|
"ClearBlocklist": "Clear blocklist",
|
||||||
"ClearBlocklistMessageText": "Are you sure you want to clear all items from the blocklist?",
|
"ClearBlocklistMessageText": "Are you sure you want to clear all items from the blocklist?",
|
||||||
|
"ClickToChangeIndexerFlags": "Click to change indexer flags",
|
||||||
"ClickToChangeLanguage": "Click to change language",
|
"ClickToChangeLanguage": "Click to change language",
|
||||||
"ClickToChangeMovie": "Click to change movie",
|
"ClickToChangeMovie": "Click to change movie",
|
||||||
"ClickToChangeQuality": "Click to change quality",
|
"ClickToChangeQuality": "Click to change quality",
|
||||||
@ -255,6 +256,7 @@
|
|||||||
"CustomFormatsLoadError": "Unable to load Custom Formats",
|
"CustomFormatsLoadError": "Unable to load Custom Formats",
|
||||||
"CustomFormatsSettings": "Custom Formats Settings",
|
"CustomFormatsSettings": "Custom Formats Settings",
|
||||||
"CustomFormatsSettingsSummary": "Custom Formats and Settings",
|
"CustomFormatsSettingsSummary": "Custom Formats and Settings",
|
||||||
|
"CustomFormatsSpecificationFlag": "Flag",
|
||||||
"CustomFormatsSpecificationRegularExpression": "Regular Expression",
|
"CustomFormatsSpecificationRegularExpression": "Regular Expression",
|
||||||
"CustomFormatsSpecificationRegularExpressionHelpText": "Custom Format RegEx is Case Insensitive",
|
"CustomFormatsSpecificationRegularExpressionHelpText": "Custom Format RegEx is Case Insensitive",
|
||||||
"Cutoff": "Cutoff",
|
"Cutoff": "Cutoff",
|
||||||
@ -1483,6 +1485,7 @@
|
|||||||
"SelectDropdown": "Select...",
|
"SelectDropdown": "Select...",
|
||||||
"SelectFolder": "Select Folder",
|
"SelectFolder": "Select Folder",
|
||||||
"SelectFolderModalTitle": "{modalTitle} - Select Folder",
|
"SelectFolderModalTitle": "{modalTitle} - Select Folder",
|
||||||
|
"SelectIndexerFlags": "Select Indexer Flags",
|
||||||
"SelectLanguage": "Select Language",
|
"SelectLanguage": "Select Language",
|
||||||
"SelectLanguageModalTitle": "{modalTitle} - Select Language",
|
"SelectLanguageModalTitle": "{modalTitle} - Select Language",
|
||||||
"SelectLanguages": "Select Languages",
|
"SelectLanguages": "Select Languages",
|
||||||
@ -1490,6 +1493,8 @@
|
|||||||
"SelectQuality": "Select Quality",
|
"SelectQuality": "Select Quality",
|
||||||
"SelectReleaseGroup": "Select Release Group",
|
"SelectReleaseGroup": "Select Release Group",
|
||||||
"SendAnonymousUsageData": "Send Anonymous Usage Data",
|
"SendAnonymousUsageData": "Send Anonymous Usage Data",
|
||||||
|
"SetIndexerFlags": "Set Indexer Flags",
|
||||||
|
"SetIndexerFlagsModalTitle": "{modalTitle} - Set Indexer Flags",
|
||||||
"SetPermissions": "Set Permissions",
|
"SetPermissions": "Set Permissions",
|
||||||
"SetPermissionsLinuxHelpText": "Should chmod be run when files are imported/renamed?",
|
"SetPermissionsLinuxHelpText": "Should chmod be run when files are imported/renamed?",
|
||||||
"SetPermissionsLinuxHelpTextWarning": "If you're unsure what these settings do, do not alter them.",
|
"SetPermissionsLinuxHelpTextWarning": "If you're unsure what these settings do, do not alter them.",
|
||||||
|
@ -20,12 +20,12 @@ public class MovieFile : ModelBase
|
|||||||
public string OriginalFilePath { get; set; }
|
public string OriginalFilePath { get; set; }
|
||||||
public string SceneName { get; set; }
|
public string SceneName { get; set; }
|
||||||
public string ReleaseGroup { get; set; }
|
public string ReleaseGroup { get; set; }
|
||||||
public IndexerFlags IndexerFlags { get; set; }
|
|
||||||
public QualityModel Quality { get; set; }
|
public QualityModel Quality { get; set; }
|
||||||
public List<Language> Languages { get; set; }
|
public IndexerFlags IndexerFlags { get; set; }
|
||||||
public MediaInfoModel MediaInfo { get; set; }
|
public MediaInfoModel MediaInfo { get; set; }
|
||||||
public string Edition { get; set; }
|
public string Edition { get; set; }
|
||||||
public Movie Movie { get; set; }
|
public Movie Movie { get; set; }
|
||||||
|
public List<Language> Languages { get; set; }
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
@ -108,6 +108,10 @@ public List<ImportResult> Import(List<ImportDecision> decisions, bool newDownloa
|
|||||||
movieFile.IndexerFlags = flags;
|
movieFile.IndexerFlags = flags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
movieFile.IndexerFlags = localMovie.IndexerFlags;
|
||||||
|
}
|
||||||
|
|
||||||
bool copyOnly;
|
bool copyOnly;
|
||||||
switch (importMode)
|
switch (importMode)
|
||||||
|
@ -13,6 +13,7 @@ public class ManualImportFile : IEquatable<ManualImportFile>
|
|||||||
public QualityModel Quality { get; set; }
|
public QualityModel Quality { get; set; }
|
||||||
public List<Language> Languages { get; set; }
|
public List<Language> Languages { get; set; }
|
||||||
public string ReleaseGroup { get; set; }
|
public string ReleaseGroup { get; set; }
|
||||||
|
public int IndexerFlags { get; set; }
|
||||||
public string DownloadId { get; set; }
|
public string DownloadId { get; set; }
|
||||||
public int MovieId { get; set; }
|
public int MovieId { get; set; }
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ public class ManualImportItem
|
|||||||
public string DownloadId { get; set; }
|
public string DownloadId { get; set; }
|
||||||
public List<CustomFormat> CustomFormats { get; set; }
|
public List<CustomFormat> CustomFormats { get; set; }
|
||||||
public int CustomFormatScore { get; set; }
|
public int CustomFormatScore { get; set; }
|
||||||
|
public int IndexerFlags { get; set; }
|
||||||
public IEnumerable<Rejection> Rejections { get; set; }
|
public IEnumerable<Rejection> Rejections { get; set; }
|
||||||
public Movie Movie { get; set; }
|
public Movie Movie { get; set; }
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual
|
|||||||
public interface IManualImportService
|
public interface IManualImportService
|
||||||
{
|
{
|
||||||
List<ManualImportItem> GetMediaFiles(string path, string downloadId, int? movieId, bool filterExistingFiles);
|
List<ManualImportItem> GetMediaFiles(string path, string downloadId, int? movieId, bool filterExistingFiles);
|
||||||
ManualImportItem ReprocessItem(string path, string downloadId, int movieId, string releaseGroup, QualityModel quality, List<Language> languages);
|
ManualImportItem ReprocessItem(string path, string downloadId, int movieId, string releaseGroup, QualityModel quality, List<Language> languages, int indexerFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ManualImportService : IExecute<ManualImportCommand>, IManualImportService
|
public class ManualImportService : IExecute<ManualImportCommand>, IManualImportService
|
||||||
@ -97,7 +97,7 @@ public List<ManualImportItem> GetMediaFiles(string path, string downloadId, int?
|
|||||||
return ProcessFolder(path, path, downloadId, movieId, filterExistingFiles);
|
return ProcessFolder(path, path, downloadId, movieId, filterExistingFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ManualImportItem ReprocessItem(string path, string downloadId, int movieId, string releaseGroup, QualityModel quality, List<Language> languages)
|
public ManualImportItem ReprocessItem(string path, string downloadId, int movieId, string releaseGroup, QualityModel quality, List<Language> languages, int indexerFlags)
|
||||||
{
|
{
|
||||||
var rootFolder = Path.GetDirectoryName(path);
|
var rootFolder = Path.GetDirectoryName(path);
|
||||||
var movie = _movieService.GetMovie(movieId);
|
var movie = _movieService.GetMovie(movieId);
|
||||||
@ -122,9 +122,10 @@ public ManualImportItem ReprocessItem(string path, string downloadId, int movieI
|
|||||||
SceneSource = SceneSource(movie, rootFolder),
|
SceneSource = SceneSource(movie, rootFolder),
|
||||||
ExistingFile = movie.Path.IsParentPath(path),
|
ExistingFile = movie.Path.IsParentPath(path),
|
||||||
Size = _diskProvider.GetFileSize(path),
|
Size = _diskProvider.GetFileSize(path),
|
||||||
|
ReleaseGroup = releaseGroup.IsNullOrWhiteSpace() ? Parser.Parser.ParseReleaseGroup(path) : releaseGroup,
|
||||||
Languages = languages?.Count <= 1 && (languages?.SingleOrDefault() ?? Language.Unknown) == Language.Unknown ? languageParse : languages,
|
Languages = languages?.Count <= 1 && (languages?.SingleOrDefault() ?? Language.Unknown) == Language.Unknown ? languageParse : languages,
|
||||||
Quality = (quality?.Quality ?? Quality.Unknown) == Quality.Unknown ? QualityParser.ParseQuality(path) : quality,
|
Quality = (quality?.Quality ?? Quality.Unknown) == Quality.Unknown ? QualityParser.ParseQuality(path) : quality,
|
||||||
ReleaseGroup = releaseGroup.IsNullOrWhiteSpace() ? Parser.Parser.ParseReleaseGroup(path) : releaseGroup,
|
IndexerFlags = (IndexerFlags)indexerFlags
|
||||||
};
|
};
|
||||||
|
|
||||||
return MapItem(_importDecisionMaker.GetDecision(localMovie, downloadClientItem), rootFolder, downloadId, null);
|
return MapItem(_importDecisionMaker.GetDecision(localMovie, downloadClientItem), rootFolder, downloadId, null);
|
||||||
@ -320,6 +321,7 @@ private ManualImportItem MapItem(ImportDecision decision, string rootFolder, str
|
|||||||
item.Languages = decision.LocalMovie.Languages;
|
item.Languages = decision.LocalMovie.Languages;
|
||||||
item.ReleaseGroup = decision.LocalMovie.ReleaseGroup;
|
item.ReleaseGroup = decision.LocalMovie.ReleaseGroup;
|
||||||
item.Rejections = decision.Rejections;
|
item.Rejections = decision.Rejections;
|
||||||
|
item.IndexerFlags = (int)decision.LocalMovie.IndexerFlags;
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
@ -346,9 +348,10 @@ public void Execute(ManualImportCommand message)
|
|||||||
ExistingFile = existingFile,
|
ExistingFile = existingFile,
|
||||||
FileMovieInfo = fileMovieInfo,
|
FileMovieInfo = fileMovieInfo,
|
||||||
Path = file.Path,
|
Path = file.Path,
|
||||||
|
ReleaseGroup = file.ReleaseGroup,
|
||||||
Quality = file.Quality,
|
Quality = file.Quality,
|
||||||
Languages = file.Languages,
|
Languages = file.Languages,
|
||||||
ReleaseGroup = file.ReleaseGroup,
|
IndexerFlags = (IndexerFlags)file.IndexerFlags,
|
||||||
Movie = movie,
|
Movie = movie,
|
||||||
Size = 0
|
Size = 0
|
||||||
};
|
};
|
||||||
@ -373,9 +376,10 @@ public void Execute(ManualImportCommand message)
|
|||||||
|
|
||||||
// Apply the user-chosen values.
|
// Apply the user-chosen values.
|
||||||
localMovie.Movie = movie;
|
localMovie.Movie = movie;
|
||||||
|
localMovie.ReleaseGroup = file.ReleaseGroup;
|
||||||
localMovie.Quality = file.Quality;
|
localMovie.Quality = file.Quality;
|
||||||
localMovie.Languages = file.Languages;
|
localMovie.Languages = file.Languages;
|
||||||
localMovie.ReleaseGroup = file.ReleaseGroup;
|
localMovie.IndexerFlags = (IndexerFlags)file.IndexerFlags;
|
||||||
|
|
||||||
// TODO: Cleanup non-tracked downloads
|
// TODO: Cleanup non-tracked downloads
|
||||||
var importDecision = new ImportDecision(localMovie);
|
var importDecision = new ImportDecision(localMovie);
|
||||||
|
@ -26,6 +26,7 @@ public LocalMovie()
|
|||||||
public List<DeletedMovieFile> OldFiles { get; set; }
|
public List<DeletedMovieFile> OldFiles { get; set; }
|
||||||
public QualityModel Quality { get; set; }
|
public QualityModel Quality { get; set; }
|
||||||
public List<Language> Languages { get; set; }
|
public List<Language> Languages { get; set; }
|
||||||
|
public IndexerFlags IndexerFlags { get; set; }
|
||||||
public MediaInfoModel MediaInfo { get; set; }
|
public MediaInfoModel MediaInfo { get; set; }
|
||||||
public bool ExistingFile { get; set; }
|
public bool ExistingFile { get; set; }
|
||||||
public bool SceneSource { get; set; }
|
public bool SceneSource { get; set; }
|
||||||
|
@ -108,12 +108,12 @@ public enum IndexerFlags
|
|||||||
G_DoubleUpload = 4, // General
|
G_DoubleUpload = 4, // General
|
||||||
PTP_Golden = 8, // PTP
|
PTP_Golden = 8, // PTP
|
||||||
PTP_Approved = 16, // PTP
|
PTP_Approved = 16, // PTP
|
||||||
G_Internal = 32, // General, internal
|
G_Internal = 32, // General, uploader is an internal release group
|
||||||
[Obsolete]
|
[Obsolete]
|
||||||
AHD_Internal = 64, // AHD, internal
|
AHD_Internal = 64, // AHD, internal
|
||||||
G_Scene = 128, // General, the torrent comes from the "scene"
|
G_Scene = 128, // General, the torrent comes from a "scene" group
|
||||||
G_Freeleech75 = 256, // Currently only used for AHD, signifies a torrent counts towards 75 percent of your download quota.
|
G_Freeleech75 = 256, // Signifies a torrent counts towards 75 percent of your download quota.
|
||||||
G_Freeleech25 = 512, // Currently only used for AHD, signifies a torrent counts towards 25 percent of your download quota.
|
G_Freeleech25 = 512, // Signifies a torrent counts towards 25 percent of your download quota.
|
||||||
[Obsolete]
|
[Obsolete]
|
||||||
AHD_UserRelease = 1024 // AHD, internal
|
AHD_UserRelease = 1024 // AHD, internal
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,6 @@ public class ReleaseResource : RestResource
|
|||||||
public string InfoUrl { get; set; }
|
public string InfoUrl { get; set; }
|
||||||
public bool DownloadAllowed { get; set; }
|
public bool DownloadAllowed { get; set; }
|
||||||
public int ReleaseWeight { get; set; }
|
public int ReleaseWeight { get; set; }
|
||||||
public IEnumerable<string> IndexerFlags { get; set; }
|
|
||||||
public string Edition { get; set; }
|
public string Edition { get; set; }
|
||||||
|
|
||||||
public string MagnetUrl { get; set; }
|
public string MagnetUrl { get; set; }
|
||||||
@ -53,6 +52,7 @@ public class ReleaseResource : RestResource
|
|||||||
public int? Seeders { get; set; }
|
public int? Seeders { get; set; }
|
||||||
public int? Leechers { get; set; }
|
public int? Leechers { get; set; }
|
||||||
public DownloadProtocol Protocol { get; set; }
|
public DownloadProtocol Protocol { get; set; }
|
||||||
|
public int IndexerFlags { get; set; }
|
||||||
|
|
||||||
// Sent when queuing an unknown release
|
// Sent when queuing an unknown release
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||||
@ -76,7 +76,7 @@ public static ReleaseResource ToResource(this DownloadDecision model)
|
|||||||
var parsedMovieInfo = model.RemoteMovie.ParsedMovieInfo;
|
var parsedMovieInfo = model.RemoteMovie.ParsedMovieInfo;
|
||||||
var remoteMovie = model.RemoteMovie;
|
var remoteMovie = model.RemoteMovie;
|
||||||
var torrentInfo = (model.RemoteMovie.Release as TorrentInfo) ?? new TorrentInfo();
|
var torrentInfo = (model.RemoteMovie.Release as TorrentInfo) ?? new TorrentInfo();
|
||||||
var indexerFlags = torrentInfo.IndexerFlags.ToString().Split(new string[] { ", " }, StringSplitOptions.None).Where(x => x != "0");
|
var indexerFlags = torrentInfo.IndexerFlags;
|
||||||
|
|
||||||
// TODO: Clean this mess up. don't mix data from multiple classes, use sub-resources instead? (Got a huge Deja Vu, didn't we talk about this already once?)
|
// TODO: Clean this mess up. don't mix data from multiple classes, use sub-resources instead? (Got a huge Deja Vu, didn't we talk about this already once?)
|
||||||
return new ReleaseResource
|
return new ReleaseResource
|
||||||
@ -118,7 +118,7 @@ public static ReleaseResource ToResource(this DownloadDecision model)
|
|||||||
Seeders = torrentInfo.Seeders,
|
Seeders = torrentInfo.Seeders,
|
||||||
Leechers = (torrentInfo.Peers.HasValue && torrentInfo.Seeders.HasValue) ? (torrentInfo.Peers.Value - torrentInfo.Seeders.Value) : (int?)null,
|
Leechers = (torrentInfo.Peers.HasValue && torrentInfo.Seeders.HasValue) ? (torrentInfo.Peers.Value - torrentInfo.Seeders.Value) : (int?)null,
|
||||||
Protocol = releaseInfo.DownloadProtocol,
|
Protocol = releaseInfo.DownloadProtocol,
|
||||||
IndexerFlags = indexerFlags
|
IndexerFlags = (int)indexerFlags
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,9 +34,10 @@ public object ReprocessItems([FromBody] List<ManualImportReprocessResource> item
|
|||||||
{
|
{
|
||||||
foreach (var item in items)
|
foreach (var item in items)
|
||||||
{
|
{
|
||||||
var processedItem = _manualImportService.ReprocessItem(item.Path, item.DownloadId, item.MovieId, item.ReleaseGroup, item.Quality, item.Languages);
|
var processedItem = _manualImportService.ReprocessItem(item.Path, item.DownloadId, item.MovieId, item.ReleaseGroup, item.Quality, item.Languages, item.IndexerFlags);
|
||||||
|
|
||||||
item.Movie = processedItem.Movie.ToResource(0);
|
item.Movie = processedItem.Movie.ToResource(0);
|
||||||
|
item.IndexerFlags = processedItem.IndexerFlags;
|
||||||
item.Rejections = processedItem.Rejections;
|
item.Rejections = processedItem.Rejections;
|
||||||
item.CustomFormats = processedItem.CustomFormats.ToResource(false);
|
item.CustomFormats = processedItem.CustomFormats.ToResource(false);
|
||||||
item.CustomFormatScore = processedItem.CustomFormatScore;
|
item.CustomFormatScore = processedItem.CustomFormatScore;
|
||||||
|
@ -19,6 +19,7 @@ public class ManualImportReprocessResource : RestResource
|
|||||||
public string DownloadId { get; set; }
|
public string DownloadId { get; set; }
|
||||||
public List<CustomFormatResource> CustomFormats { get; set; }
|
public List<CustomFormatResource> CustomFormats { get; set; }
|
||||||
public int CustomFormatScore { get; set; }
|
public int CustomFormatScore { get; set; }
|
||||||
|
public int IndexerFlags { get; set; }
|
||||||
public IEnumerable<Rejection> Rejections { get; set; }
|
public IEnumerable<Rejection> Rejections { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ public class ManualImportResource : RestResource
|
|||||||
public string DownloadId { get; set; }
|
public string DownloadId { get; set; }
|
||||||
public List<CustomFormatResource> CustomFormats { get; set; }
|
public List<CustomFormatResource> CustomFormats { get; set; }
|
||||||
public int CustomFormatScore { get; set; }
|
public int CustomFormatScore { get; set; }
|
||||||
|
public int IndexerFlags { get; set; }
|
||||||
public IEnumerable<Rejection> Rejections { get; set; }
|
public IEnumerable<Rejection> Rejections { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +59,7 @@ public static ManualImportResource ToResource(this ManualImportItem model)
|
|||||||
|
|
||||||
// QualityWeight
|
// QualityWeight
|
||||||
DownloadId = model.DownloadId,
|
DownloadId = model.DownloadId,
|
||||||
|
IndexerFlags = model.IndexerFlags,
|
||||||
Rejections = model.Rejections
|
Rejections = model.Rejections
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -19,16 +19,17 @@ public class MovieFileResource : RestResource
|
|||||||
public long Size { get; set; }
|
public long Size { get; set; }
|
||||||
public DateTime DateAdded { get; set; }
|
public DateTime DateAdded { get; set; }
|
||||||
public string SceneName { get; set; }
|
public string SceneName { get; set; }
|
||||||
public int IndexerFlags { get; set; }
|
public string ReleaseGroup { get; set; }
|
||||||
|
public string Edition { get; set; }
|
||||||
|
public List<Language> Languages { get; set; }
|
||||||
public QualityModel Quality { get; set; }
|
public QualityModel Quality { get; set; }
|
||||||
public List<CustomFormatResource> CustomFormats { get; set; }
|
public List<CustomFormatResource> CustomFormats { get; set; }
|
||||||
public int CustomFormatScore { get; set; }
|
public int CustomFormatScore { get; set; }
|
||||||
|
public int? IndexerFlags { get; set; }
|
||||||
public MediaInfoResource MediaInfo { get; set; }
|
public MediaInfoResource MediaInfo { get; set; }
|
||||||
|
|
||||||
public string OriginalFilePath { get; set; }
|
public string OriginalFilePath { get; set; }
|
||||||
public bool QualityCutoffNotMet { get; set; }
|
public bool QualityCutoffNotMet { get; set; }
|
||||||
public List<Language> Languages { get; set; }
|
|
||||||
public string ReleaseGroup { get; set; }
|
|
||||||
public string Edition { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MovieFileResourceMapper
|
public static class MovieFileResourceMapper
|
||||||
@ -78,14 +79,14 @@ public static MovieFileResource ToResource(this MovieFile model, NzbDrone.Core.M
|
|||||||
Size = model.Size,
|
Size = model.Size,
|
||||||
DateAdded = model.DateAdded,
|
DateAdded = model.DateAdded,
|
||||||
SceneName = model.SceneName,
|
SceneName = model.SceneName,
|
||||||
IndexerFlags = (int)model.IndexerFlags,
|
|
||||||
Quality = model.Quality,
|
Quality = model.Quality,
|
||||||
Languages = model.Languages,
|
Languages = model.Languages,
|
||||||
Edition = model.Edition,
|
Edition = model.Edition,
|
||||||
ReleaseGroup = model.ReleaseGroup,
|
ReleaseGroup = model.ReleaseGroup,
|
||||||
MediaInfo = model.MediaInfo.ToResource(model.SceneName),
|
MediaInfo = model.MediaInfo.ToResource(model.SceneName),
|
||||||
QualityCutoffNotMet = upgradableSpecification?.QualityCutoffNotMet(movie.QualityProfile, model.Quality) ?? false,
|
QualityCutoffNotMet = upgradableSpecification?.QualityCutoffNotMet(movie.QualityProfile, model.Quality) ?? false,
|
||||||
OriginalFilePath = model.OriginalFilePath
|
OriginalFilePath = model.OriginalFilePath,
|
||||||
|
IndexerFlags = (int)model.IndexerFlags
|
||||||
};
|
};
|
||||||
|
|
||||||
if (formatCalculationService != null)
|
if (formatCalculationService != null)
|
||||||
|
Loading…
Reference in New Issue
Block a user