mirror of
https://github.com/Radarr/Radarr.git
synced 2024-09-11 20:12:41 +02:00
New: Reprocess items after selection in Manual Import
Fixes #5199 Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
This commit is contained in:
parent
f33f004aa9
commit
2a93686360
@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { updateInteractiveImportItems } from 'Store/Actions/interactiveImportActions';
|
||||
import { reprocessInteractiveImportItems, updateInteractiveImportItems } from 'Store/Actions/interactiveImportActions';
|
||||
import { fetchLanguages } from 'Store/Actions/settingsActions';
|
||||
import SelectLanguageModalContent from './SelectLanguageModalContent';
|
||||
|
||||
@ -33,6 +33,7 @@ function createMapStateToProps() {
|
||||
|
||||
const mapDispatchToProps = {
|
||||
dispatchFetchLanguages: fetchLanguages,
|
||||
dispatchReprocessInteractiveImportItems: reprocessInteractiveImportItems,
|
||||
dispatchUpdateInteractiveImportItems: updateInteractiveImportItems
|
||||
};
|
||||
|
||||
@ -51,6 +52,12 @@ class SelectLanguageModalContentConnector extends Component {
|
||||
// Listeners
|
||||
|
||||
onLanguageSelect = ({ languageIds }) => {
|
||||
const {
|
||||
ids,
|
||||
dispatchUpdateInteractiveImportItems,
|
||||
dispatchReprocessInteractiveImportItems
|
||||
} = this.props;
|
||||
|
||||
const languages = [];
|
||||
|
||||
languageIds.forEach((languageId) => {
|
||||
@ -62,11 +69,13 @@ class SelectLanguageModalContentConnector extends Component {
|
||||
}
|
||||
});
|
||||
|
||||
this.props.dispatchUpdateInteractiveImportItems({
|
||||
ids: this.props.ids,
|
||||
dispatchUpdateInteractiveImportItems({
|
||||
ids,
|
||||
languages
|
||||
});
|
||||
|
||||
dispatchReprocessInteractiveImportItems({ ids });
|
||||
|
||||
this.props.onModalClose(true);
|
||||
}
|
||||
|
||||
@ -91,6 +100,7 @@ SelectLanguageModalContentConnector.propTypes = {
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
dispatchFetchLanguages: PropTypes.func.isRequired,
|
||||
dispatchUpdateInteractiveImportItems: PropTypes.func.isRequired,
|
||||
dispatchReprocessInteractiveImportItems: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
|
@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { updateInteractiveImportItems } from 'Store/Actions/interactiveImportActions';
|
||||
import { reprocessInteractiveImportItems, updateInteractiveImportItems } from 'Store/Actions/interactiveImportActions';
|
||||
import { fetchQualityProfileSchema } from 'Store/Actions/settingsActions';
|
||||
import getQualities from 'Utilities/Quality/getQualities';
|
||||
import SelectQualityModalContent from './SelectQualityModalContent';
|
||||
@ -31,6 +31,7 @@ function createMapStateToProps() {
|
||||
|
||||
const mapDispatchToProps = {
|
||||
dispatchFetchQualityProfileSchema: fetchQualityProfileSchema,
|
||||
dispatchReprocessInteractiveImportItems: reprocessInteractiveImportItems,
|
||||
dispatchUpdateInteractiveImportItems: updateInteractiveImportItems
|
||||
};
|
||||
|
||||
@ -49,6 +50,12 @@ class SelectQualityModalContentConnector extends Component {
|
||||
// Listeners
|
||||
|
||||
onQualitySelect = ({ qualityId, proper, real }) => {
|
||||
const {
|
||||
ids,
|
||||
dispatchUpdateInteractiveImportItems,
|
||||
dispatchReprocessInteractiveImportItems
|
||||
} = this.props;
|
||||
|
||||
const quality = _.find(this.props.items,
|
||||
(item) => item.id === qualityId);
|
||||
|
||||
@ -57,14 +64,16 @@ class SelectQualityModalContentConnector extends Component {
|
||||
real: real ? 1 : 0
|
||||
};
|
||||
|
||||
this.props.dispatchUpdateInteractiveImportItems({
|
||||
ids: this.props.ids,
|
||||
dispatchUpdateInteractiveImportItems({
|
||||
ids,
|
||||
quality: {
|
||||
quality,
|
||||
revision
|
||||
}
|
||||
});
|
||||
|
||||
dispatchReprocessInteractiveImportItems({ ids });
|
||||
|
||||
this.props.onModalClose(true);
|
||||
}
|
||||
|
||||
@ -88,6 +97,7 @@ SelectQualityModalContentConnector.propTypes = {
|
||||
error: PropTypes.object,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
dispatchFetchQualityProfileSchema: PropTypes.func.isRequired,
|
||||
dispatchReprocessInteractiveImportItems: PropTypes.func.isRequired,
|
||||
dispatchUpdateInteractiveImportItems: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
@ -149,6 +149,8 @@ export const actionHandlers = handleThunks({
|
||||
id,
|
||||
path: item.path,
|
||||
movieId: item.movie.id,
|
||||
quality: item.quality,
|
||||
languages: item.languages,
|
||||
downloadId: item.downloadId
|
||||
};
|
||||
});
|
||||
|
@ -18,6 +18,7 @@ public interface IMakeImportDecision
|
||||
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie);
|
||||
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, DownloadClientItem downloadClientItem, ParsedMovieInfo folderInfo, bool sceneSource);
|
||||
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, DownloadClientItem downloadClientItem, ParsedMovieInfo folderInfo, bool sceneSource, bool filterExistingFiles);
|
||||
ImportDecision GetDecision(LocalMovie localMovie, DownloadClientItem downloadClientItem);
|
||||
}
|
||||
|
||||
public class ImportDecisionMaker : IMakeImportDecision
|
||||
@ -93,6 +94,14 @@ public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie mo
|
||||
return decisions;
|
||||
}
|
||||
|
||||
public ImportDecision GetDecision(LocalMovie localMovie, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
var reasons = _specifications.Select(c => EvaluateSpec(c, localMovie, downloadClientItem))
|
||||
.Where(c => c != null);
|
||||
|
||||
return new ImportDecision(localMovie, reasons.ToArray());
|
||||
}
|
||||
|
||||
private ImportDecision GetDecision(LocalMovie localMovie, DownloadClientItem downloadClientItem, bool otherFiles)
|
||||
{
|
||||
ImportDecision decision = null;
|
||||
@ -147,14 +156,6 @@ private ImportDecision GetDecision(LocalMovie localMovie, DownloadClientItem dow
|
||||
return decision;
|
||||
}
|
||||
|
||||
private ImportDecision GetDecision(LocalMovie localMovie, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
var reasons = _specifications.Select(c => EvaluateSpec(c, localMovie, downloadClientItem))
|
||||
.Where(c => c != null);
|
||||
|
||||
return new ImportDecision(localMovie, reasons.ToArray());
|
||||
}
|
||||
|
||||
private Rejection EvaluateSpec(IImportDecisionEngineSpecification spec, LocalMovie localMovie, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
try
|
||||
|
@ -8,19 +8,21 @@
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.TrackedDownloads;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.MediaFiles.MovieImport.Aggregation;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.MovieImport.Manual
|
||||
{
|
||||
public interface IManualImportService
|
||||
{
|
||||
List<ManualImportItem> GetMediaFiles(string path, string downloadId, int? movieId, bool filterExistingFiles);
|
||||
ManualImportItem ReprocessItem(string path, string downloadId, int movieId);
|
||||
ManualImportItem ReprocessItem(string path, string downloadId, int movieId, QualityModel quality, List<Language> languages);
|
||||
}
|
||||
|
||||
public class ManualImportService : IExecute<ManualImportCommand>, IManualImportService
|
||||
@ -90,12 +92,27 @@ public List<ManualImportItem> GetMediaFiles(string path, string downloadId, int?
|
||||
return ProcessFolder(path, path, downloadId, movieId, filterExistingFiles);
|
||||
}
|
||||
|
||||
public ManualImportItem ReprocessItem(string path, string downloadId, int movieId)
|
||||
public ManualImportItem ReprocessItem(string path, string downloadId, int movieId, QualityModel quality, List<Language> languages)
|
||||
{
|
||||
var rootFolder = Path.GetDirectoryName(path);
|
||||
var movie = _movieService.GetMovie(movieId);
|
||||
|
||||
return ProcessFile(rootFolder, rootFolder, path, downloadId, movie);
|
||||
var downloadClientItem = GetTrackedDownload(downloadId)?.DownloadItem;
|
||||
|
||||
var localEpisode = new LocalMovie
|
||||
{
|
||||
Movie = movie,
|
||||
FileMovieInfo = Parser.Parser.ParseMoviePath(path),
|
||||
DownloadClientMovieInfo = downloadClientItem == null ? null : Parser.Parser.ParseMovieTitle(downloadClientItem.Title),
|
||||
Path = path,
|
||||
SceneSource = SceneSource(movie, rootFolder),
|
||||
ExistingFile = movie.Path.IsParentPath(path),
|
||||
Size = _diskProvider.GetFileSize(path),
|
||||
Languages = languages,
|
||||
Quality = quality
|
||||
};
|
||||
|
||||
return MapItem(_importDecisionMaker.GetDecision(localEpisode, downloadClientItem), rootFolder, downloadId, null);
|
||||
}
|
||||
|
||||
private List<ManualImportItem> ProcessFolder(string rootFolder, string baseFolder, string downloadId, int? movieId, bool filterExistingFiles)
|
||||
@ -141,7 +158,7 @@ private List<ManualImportItem> ProcessFolder(string rootFolder, string baseFolde
|
||||
|
||||
private ManualImportItem ProcessFile(string rootFolder, string baseFolder, string file, string downloadId, Movie movie = null)
|
||||
{
|
||||
DownloadClientItem downloadClientItem = null;
|
||||
var trackedDownload = GetTrackedDownload(downloadId);
|
||||
var relativeFile = baseFolder.GetRelativePath(file);
|
||||
|
||||
if (movie == null)
|
||||
@ -154,16 +171,10 @@ private ManualImportItem ProcessFile(string rootFolder, string baseFolder, strin
|
||||
movie = _parsingService.GetMovie(relativeFile);
|
||||
}
|
||||
|
||||
if (downloadId.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
var trackedDownload = _trackedDownloadService.Find(downloadId);
|
||||
downloadClientItem = trackedDownload?.DownloadItem;
|
||||
|
||||
if (movie == null)
|
||||
if (trackedDownload != null && movie == null)
|
||||
{
|
||||
movie = trackedDownload?.RemoteMovie?.Movie;
|
||||
}
|
||||
}
|
||||
|
||||
if (movie == null)
|
||||
{
|
||||
@ -186,7 +197,7 @@ private ManualImportItem ProcessFile(string rootFolder, string baseFolder, strin
|
||||
return MapItem(new ImportDecision(localMovie, new Rejection("Unknown Movie")), rootFolder, downloadId, null);
|
||||
}
|
||||
|
||||
var importDecisions = _importDecisionMaker.GetImportDecisions(new List<string> { file }, movie, downloadClientItem, null, SceneSource(movie, baseFolder));
|
||||
var importDecisions = _importDecisionMaker.GetImportDecisions(new List<string> { file }, movie, trackedDownload?.DownloadItem, null, SceneSource(movie, baseFolder));
|
||||
|
||||
if (importDecisions.Any())
|
||||
{
|
||||
@ -208,6 +219,18 @@ private bool SceneSource(Movie movie, string folder)
|
||||
return !(movie.Path.PathEquals(folder) || movie.Path.IsParentPath(folder));
|
||||
}
|
||||
|
||||
private TrackedDownload GetTrackedDownload(string downloadId)
|
||||
{
|
||||
if (downloadId.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
var trackedDownload = _trackedDownloadService.Find(downloadId);
|
||||
|
||||
return trackedDownload;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private ManualImportItem MapItem(ImportDecision decision, string rootFolder, string downloadId, string folderName)
|
||||
{
|
||||
var item = new ManualImportItem();
|
||||
|
@ -37,7 +37,7 @@ private object ReprocessItems()
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
var processedItem = _manualImportService.ReprocessItem(item.Path, item.DownloadId, item.MovieId);
|
||||
var processedItem = _manualImportService.ReprocessItem(item.Path, item.DownloadId, item.MovieId, item.Quality, item.Languages);
|
||||
|
||||
item.Movie = processedItem.Movie.ToResource(0);
|
||||
item.Rejections = processedItem.Rejections;
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using Radarr.Api.V3.Movies;
|
||||
using Radarr.Http.REST;
|
||||
|
||||
@ -11,9 +12,10 @@ public class ManualImportReprocessResource : RestResource
|
||||
public string Path { get; set; }
|
||||
public int MovieId { get; set; }
|
||||
public MovieResource Movie { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public List<Language> Languages { get; set; }
|
||||
public string DownloadId { get; set; }
|
||||
|
||||
public IEnumerable<Rejection> Rejections { get; set; }
|
||||
public List<Language> Languages { get; set; }
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user