New: Option to search for upgrades when adding new series

Closes #712
This commit is contained in:
Mark McDowall 2020-09-09 00:58:55 -07:00
parent accf8d5c81
commit 5a42d2a36d
9 changed files with 87 additions and 25 deletions

View File

@ -25,23 +25,24 @@
margin-left: 8px; margin-left: 8px;
} }
.searchForMissingEpisodesLabelContainer { .searchLabelContainer {
display: flex; display: flex;
justify-content: flex-end;
margin-top: 2px; margin-top: 2px;
} }
.searchForMissingEpisodesLabel { .searchLabel {
margin-right: 8px; margin-right: 8px;
font-weight: normal; font-weight: normal;
} }
.searchForMissingEpisodesContainer { .searchInputContainer {
composes: container from '~Components/Form/CheckInput.css'; composes: container from '~Components/Form/CheckInput.css';
flex: 0 1 0; flex: 0 1 0;
} }
.searchForMissingEpisodesInput { .searchInput {
composes: input from '~Components/Form/CheckInput.css'; composes: input from '~Components/Form/CheckInput.css';
margin-top: 0; margin-top: 0;

View File

@ -31,7 +31,8 @@ class AddNewSeriesModalContent extends Component {
seriesType: props.initialSeriesType === seriesTypes.STANDARD ? seriesType: props.initialSeriesType === seriesTypes.STANDARD ?
props.seriesType.value : props.seriesType.value :
props.initialSeriesType, props.initialSeriesType,
searchForMissingEpisodes: false searchForMissingEpisodes: false,
searchForCutoffUnmetEpisodes: false
}; };
} }
@ -48,6 +49,10 @@ class AddNewSeriesModalContent extends Component {
this.setState({ searchForMissingEpisodes: value }); this.setState({ searchForMissingEpisodes: value });
} }
onSearchForCutoffUnmetEpisodesChange = ({ value }) => {
this.setState({ searchForCutoffUnmetEpisodes: value });
}
onQualityProfileIdChange = ({ value }) => { onQualityProfileIdChange = ({ value }) => {
this.props.onInputChange({ name: 'qualityProfileId', value: parseInt(value) }); this.props.onInputChange({ name: 'qualityProfileId', value: parseInt(value) });
} }
@ -59,10 +64,15 @@ class AddNewSeriesModalContent extends Component {
onAddSeriesPress = () => { onAddSeriesPress = () => {
const { const {
searchForMissingEpisodes, searchForMissingEpisodes,
searchForCutoffUnmetEpisodes,
seriesType seriesType
} = this.state; } = this.state;
this.props.onAddSeriesPress(searchForMissingEpisodes, seriesType); this.props.onAddSeriesPress(
searchForMissingEpisodes,
searchForCutoffUnmetEpisodes,
seriesType
);
} }
// //
@ -91,6 +101,11 @@ class AddNewSeriesModalContent extends Component {
...otherProps ...otherProps
} = this.props; } = this.props;
const {
searchForMissingEpisodes,
searchForCutoffUnmetEpisodes
} = this.state;
return ( return (
<ModalContent onModalClose={onModalClose}> <ModalContent onModalClose={onModalClose}>
<ModalHeader> <ModalHeader>
@ -246,19 +261,35 @@ class AddNewSeriesModalContent extends Component {
</ModalBody> </ModalBody>
<ModalFooter className={styles.modalFooter}> <ModalFooter className={styles.modalFooter}>
<label className={styles.searchForMissingEpisodesLabelContainer}> <div>
<span className={styles.searchForMissingEpisodesLabel}> <label className={styles.searchLabelContainer}>
<span className={styles.searchLabel}>
Start search for missing episodes Start search for missing episodes
</span> </span>
<CheckInput <CheckInput
containerClassName={styles.searchForMissingEpisodesContainer} containerClassName={styles.searchInputContainer}
className={styles.searchForMissingEpisodesInput} className={styles.searchInput}
name="searchForMissingEpisodes" name="searchForMissingEpisodes"
value={this.state.searchForMissingEpisodes} value={searchForMissingEpisodes}
onChange={this.onSearchForMissingEpisodesChange} onChange={this.onSearchForMissingEpisodesChange}
/> />
</label> </label>
<label className={styles.searchLabelContainer}>
<span className={styles.searchLabel}>
Start search for cutoff unmet episodes
</span>
<CheckInput
containerClassName={styles.searchInputContainer}
className={styles.searchInput}
name="searchForCutoffUnmetEpisodes"
value={searchForCutoffUnmetEpisodes}
onChange={this.onSearchForCutoffUnmetEpisodesChange}
/>
</label>
</div>
<SpinnerButton <SpinnerButton
className={styles.addButton} className={styles.addButton}

View File

@ -55,7 +55,7 @@ class AddNewSeriesModalContentConnector extends Component {
this.props.setAddSeriesDefault({ [name]: value }); this.props.setAddSeriesDefault({ [name]: value });
} }
onAddSeriesPress = (searchForMissingEpisodes, seriesType) => { onAddSeriesPress = (searchForMissingEpisodes, searchForCutoffUnmetEpisodes, seriesType) => {
const { const {
tvdbId, tvdbId,
rootFolderPath, rootFolderPath,
@ -75,7 +75,8 @@ class AddNewSeriesModalContentConnector extends Component {
seriesType, seriesType,
seasonFolder: seasonFolder.value, seasonFolder: seasonFolder.value,
tags: tags.value, tags: tags.value,
searchForMissingEpisodes searchForMissingEpisodes,
searchForCutoffUnmetEpisodes
}); });
} }

View File

@ -8,12 +8,14 @@ function getNewSeries(series, payload) {
seriesType, seriesType,
seasonFolder, seasonFolder,
tags, tags,
searchForMissingEpisodes = false searchForMissingEpisodes = false,
searchForCutoffUnmetEpisodes = false
} = payload; } = payload;
const addOptions = { const addOptions = {
monitor, monitor,
searchForMissingEpisodes searchForMissingEpisodes,
searchForCutoffUnmetEpisodes
}; };
series.addOptions = addOptions; series.addOptions = addOptions;

View File

@ -159,7 +159,8 @@ namespace NzbDrone.Core.IndexerSearch
if (message.SeriesId.HasValue) if (message.SeriesId.HasValue)
{ {
pagingSpec.FilterExpressions.Add(v => v.SeriesId == message.SeriesId.Value); var seriesId = message.SeriesId.Value;
pagingSpec.FilterExpressions.Add(v => v.SeriesId == seriesId);
} }
if (monitored) if (monitored)

View File

@ -7,5 +7,14 @@ namespace NzbDrone.Core.IndexerSearch
public int SeriesId { get; set; } public int SeriesId { get; set; }
public override bool SendUpdatesToClient => true; public override bool SendUpdatesToClient => true;
public SeriesSearchCommand()
{
}
public SeriesSearchCommand(int seriesId)
{
SeriesId = seriesId;
}
} }
} }

View File

@ -3,5 +3,6 @@
public class AddSeriesOptions : MonitoringOptions public class AddSeriesOptions : MonitoringOptions
{ {
public bool SearchForMissingEpisodes { get; set; } public bool SearchForMissingEpisodes { get; set; }
public bool SearchForCutoffUnmetEpisodes { get; set; }
} }
} }

View File

@ -206,7 +206,7 @@ namespace NzbDrone.Core.Tv
private SortBuilder<Episode> EpisodesWhereCutoffUnmetQuery(PagingSpec<Episode> pagingSpec, List<QualitiesBelowCutoff> qualitiesBelowCutoff, List<LanguagesBelowCutoff> languagesBelowCutoff, int startingSeasonNumber) private SortBuilder<Episode> EpisodesWhereCutoffUnmetQuery(PagingSpec<Episode> pagingSpec, List<QualitiesBelowCutoff> qualitiesBelowCutoff, List<LanguagesBelowCutoff> languagesBelowCutoff, int startingSeasonNumber)
{ {
return Query.Join<Episode, Series>(JoinType.Inner, e => e.Series, (e, s) => e.SeriesId == s.Id) return Query.Join<Episode, Series>(JoinType.Inner, e => e.Series, (e, s) => e.SeriesId == s.Id)
.Join<Episode, EpisodeFile>(JoinType.Left, e => e.EpisodeFile, (e, s) => e.EpisodeFileId == s.Id) .Join<Episode, EpisodeFile>(JoinType.Left, e => e.EpisodeFile, (e, f) => e.EpisodeFileId == f.Id)
.Where(pagingSpec.FilterExpressions.FirstOrDefault()) .Where(pagingSpec.FilterExpressions.FirstOrDefault())
.AndWhere(e => e.EpisodeFileId != 0) .AndWhere(e => e.EpisodeFileId != 0)
.AndWhere(e => e.SeasonNumber >= startingSeasonNumber) .AndWhere(e => e.SeasonNumber >= startingSeasonNumber)

View File

@ -40,9 +40,25 @@ namespace NzbDrone.Core.Tv
_logger.Info("[{0}] was recently added, performing post-add actions", series.Title); _logger.Info("[{0}] was recently added, performing post-add actions", series.Title);
_episodeMonitoredService.SetEpisodeMonitoredStatus(series, series.AddOptions); _episodeMonitoredService.SetEpisodeMonitoredStatus(series, series.AddOptions);
if (series.AddOptions.SearchForMissingEpisodes) // If both options are enabled search for the whole series, which will only include monitored episodes.
// This way multiple searches for the same season are skipped, though a season that can't be upgraded may be
// searched, but the logs will be more explicit.
if (series.AddOptions.SearchForMissingEpisodes && series.AddOptions.SearchForCutoffUnmetEpisodes)
{ {
_commandQueueManager.Push(new MissingEpisodeSearchCommand(series.Id)); _commandQueueManager.Push(new SeriesSearchCommand(series.Id));
}
else
{
if (series.AddOptions.SearchForMissingEpisodes)
{
_commandQueueManager.Push(new MissingEpisodeSearchCommand(series.Id));
}
if (series.AddOptions.SearchForCutoffUnmetEpisodes)
{
_commandQueueManager.Push(new CutoffUnmetEpisodeSearchCommand(series.Id));
}
} }
series.AddOptions = null; series.AddOptions = null;