diff --git a/frontend/src/InteractiveImport/Interactive/InteractiveImportModalContent.js b/frontend/src/InteractiveImport/Interactive/InteractiveImportModalContent.js index 9203baf11..573a81f49 100644 --- a/frontend/src/InteractiveImport/Interactive/InteractiveImportModalContent.js +++ b/frontend/src/InteractiveImport/Interactive/InteractiveImportModalContent.js @@ -19,6 +19,7 @@ import { align, icons, kinds, scrollDirections } from 'Helpers/Props'; import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal'; import SelectMovieModal from 'InteractiveImport/Movie/SelectMovieModal'; import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal'; +import SelectReleaseGroupModal from 'InteractiveImport/ReleaseGroup/SelectReleaseGroupModal'; import getErrorMessage from 'Utilities/Object/getErrorMessage'; import translate from 'Utilities/String/translate'; import getSelectedIds from 'Utilities/Table/getSelectedIds'; @@ -40,6 +41,11 @@ const columns = [ isSortable: true, isVisible: true }, + { + name: 'releaseGroup', + label: translate('ReleaseGroup'), + isVisible: true + }, { name: 'quality', label: translate('Quality'), @@ -83,6 +89,7 @@ const SELECT = 'select'; const MOVIE = 'movie'; const LANGUAGE = 'language'; const QUALITY = 'quality'; +const RELEASE_GROUP = 'releaseGroup'; class InteractiveImportModalContent extends Component { @@ -202,10 +209,11 @@ class InteractiveImportModalContent extends Component { const errorMessage = getErrorMessage(error, translate('UnableToLoadManualImportItems')); const bulkSelectOptions = [ - { - key: SELECT, value: translate('SelectDotDot'), disabled: true }, + { key: SELECT, value: translate('SelectDotDot'), disabled: true }, { key: LANGUAGE, value: translate('SelectLanguage') }, - { key: QUALITY, value: translate('SelectQuality') }]; + { key: QUALITY, value: translate('SelectQuality') }, + { key: RELEASE_GROUP, value: translate('SelectReleaseGroup') } + ]; if (allowMovieChange) { bulkSelectOptions.splice(1, 0, { @@ -372,6 +380,13 @@ class InteractiveImportModalContent extends Component { real={false} onModalClose={this.onSelectModalClose} /> + + ); } diff --git a/frontend/src/InteractiveImport/Interactive/InteractiveImportModalContentConnector.js b/frontend/src/InteractiveImport/Interactive/InteractiveImportModalContentConnector.js index 75bedbc0d..4759814d8 100644 --- a/frontend/src/InteractiveImport/Interactive/InteractiveImportModalContentConnector.js +++ b/frontend/src/InteractiveImport/Interactive/InteractiveImportModalContentConnector.js @@ -110,7 +110,8 @@ class InteractiveImportModalContentConnector extends Component { const { movie, quality, - languages + languages, + releaseGroup } = item; if (!movie) { @@ -132,6 +133,7 @@ class InteractiveImportModalContentConnector extends Component { path: item.path, folderName: item.folderName, movieId: movie.id, + releaseGroup, quality, languages, downloadId: this.props.downloadId diff --git a/frontend/src/InteractiveImport/Interactive/InteractiveImportRow.js b/frontend/src/InteractiveImport/Interactive/InteractiveImportRow.js index 19a340893..27f8caee0 100644 --- a/frontend/src/InteractiveImport/Interactive/InteractiveImportRow.js +++ b/frontend/src/InteractiveImport/Interactive/InteractiveImportRow.js @@ -11,6 +11,7 @@ import { icons, kinds, tooltipPositions } from 'Helpers/Props'; import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal'; import SelectMovieModal from 'InteractiveImport/Movie/SelectMovieModal'; import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal'; +import SelectReleaseGroupModal from 'InteractiveImport/ReleaseGroup/SelectReleaseGroupModal'; import MovieLanguage from 'Movie/MovieLanguage'; import MovieQuality from 'Movie/MovieQuality'; import formatBytes from 'Utilities/Number/formatBytes'; @@ -28,6 +29,7 @@ class InteractiveImportRow extends Component { this.state = { isSelectMovieModalOpen: false, + isSelectReleaseGroupModalOpen: false, isSelectQualityModalOpen: false, isSelectLanguageModalOpen: false }; @@ -103,6 +105,10 @@ class InteractiveImportRow extends Component { this.setState({ isSelectMovieModalOpen: true }); } + onSelectReleaseGroupPress = () => { + this.setState({ isSelectReleaseGroupModalOpen: true }); + } + onSelectQualityPress = () => { this.setState({ isSelectQualityModalOpen: true }); } @@ -116,6 +122,11 @@ class InteractiveImportRow extends Component { this.selectRowAfterChange(changed); } + onSelectReleaseGroupModalClose = (changed) => { + this.setState({ isSelectReleaseGroupModalOpen: false }); + this.selectRowAfterChange(changed); + } + onSelectQualityModalClose = (changed) => { this.setState({ isSelectQualityModalOpen: false }); this.selectRowAfterChange(changed); @@ -137,6 +148,7 @@ class InteractiveImportRow extends Component { movie, quality, languages, + releaseGroup, size, rejections, isReprocessing, @@ -147,7 +159,8 @@ class InteractiveImportRow extends Component { const { isSelectMovieModalOpen, isSelectQualityModalOpen, - isSelectLanguageModalOpen + isSelectLanguageModalOpen, + isSelectReleaseGroupModalOpen } = this.state; const movieTitle = movie ? movie.title + ( movie.year > 0 ? ` (${movie.year})` : '') : ''; @@ -155,6 +168,7 @@ class InteractiveImportRow extends Component { const showMoviePlaceholder = isSelected && !movie; const showQualityPlaceholder = isSelected && !quality; const showLanguagePlaceholder = isSelected && !languages && !isReprocessing; + const showReleaseGroupPlaceholder = isSelected && !releaseGroup; return ( @@ -181,6 +195,17 @@ class InteractiveImportRow extends Component { } + + { + showReleaseGroupPlaceholder ? + : + releaseGroup + } + + + + + + + ); + } +} + +SelectReleaseGroupModal.propTypes = { + isOpen: PropTypes.bool.isRequired, + onModalClose: PropTypes.func.isRequired +}; + +export default SelectReleaseGroupModal; diff --git a/frontend/src/InteractiveImport/ReleaseGroup/SelectReleaseGroupModalContent.js b/frontend/src/InteractiveImport/ReleaseGroup/SelectReleaseGroupModalContent.js new file mode 100644 index 000000000..549abc22e --- /dev/null +++ b/frontend/src/InteractiveImport/ReleaseGroup/SelectReleaseGroupModalContent.js @@ -0,0 +1,99 @@ +import PropTypes from 'prop-types'; +import React, { Component } 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 } from 'Helpers/Props'; +import translate from 'Utilities/String/translate'; + +class SelectReleaseGroupModalContent extends Component { + + // + // Lifecycle + + constructor(props, context) { + super(props, context); + + const { + releaseGroup + } = props; + + this.state = { + releaseGroup + }; + } + + // + // Listeners + + onReleaseGroupChange = ({ value }) => { + this.setState({ releaseGroup: value }); + } + + onReleaseGroupSelect = () => { + this.props.onReleaseGroupSelect(this.state); + } + + // + // Render + + render() { + const { + onModalClose + } = this.props; + + const { + releaseGroup + } = this.state; + + return ( + + + {translate('ManualImportSetReleaseGroup')} + + + +
+ + {translate('ReleaseGroup')} + + + +
+
+ + + + + + +
+ ); + } +} + +SelectReleaseGroupModalContent.propTypes = { + releaseGroup: PropTypes.string.isRequired, + onReleaseGroupSelect: PropTypes.func.isRequired, + onModalClose: PropTypes.func.isRequired +}; + +export default SelectReleaseGroupModalContent; diff --git a/frontend/src/InteractiveImport/ReleaseGroup/SelectReleaseGroupModalContentConnector.js b/frontend/src/InteractiveImport/ReleaseGroup/SelectReleaseGroupModalContentConnector.js new file mode 100644 index 000000000..1dba63894 --- /dev/null +++ b/frontend/src/InteractiveImport/ReleaseGroup/SelectReleaseGroupModalContentConnector.js @@ -0,0 +1,54 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { reprocessInteractiveImportItems, updateInteractiveImportItems } from 'Store/Actions/interactiveImportActions'; +import SelectReleaseGroupModalContent from './SelectReleaseGroupModalContent'; + +const mapDispatchToProps = { + dispatchUpdateInteractiveImportItems: updateInteractiveImportItems, + dispatchReprocessInteractiveImportItems: reprocessInteractiveImportItems +}; + +class SelectReleaseGroupModalContentConnector extends Component { + + // + // Listeners + + onReleaseGroupSelect = ({ releaseGroup }) => { + const { + ids, + dispatchUpdateInteractiveImportItems, + dispatchReprocessInteractiveImportItems + } = this.props; + + dispatchUpdateInteractiveImportItems({ + ids, + releaseGroup + }); + + dispatchReprocessInteractiveImportItems({ ids }); + + this.props.onModalClose(true); + } + + // + // Render + + render() { + return ( + + ); + } +} + +SelectReleaseGroupModalContentConnector.propTypes = { + ids: PropTypes.arrayOf(PropTypes.number).isRequired, + dispatchUpdateInteractiveImportItems: PropTypes.func.isRequired, + dispatchReprocessInteractiveImportItems: PropTypes.func.isRequired, + onModalClose: PropTypes.func.isRequired +}; + +export default connect(null, mapDispatchToProps)(SelectReleaseGroupModalContentConnector); diff --git a/frontend/src/Store/Actions/interactiveImportActions.js b/frontend/src/Store/Actions/interactiveImportActions.js index 491c77fd4..55b91d1d6 100644 --- a/frontend/src/Store/Actions/interactiveImportActions.js +++ b/frontend/src/Store/Actions/interactiveImportActions.js @@ -148,9 +148,10 @@ export const actionHandlers = handleThunks({ return { id, path: item.path, - movieId: item.movie.id, + movieId: item.movie ? item.movie.id : undefined, quality: item.quality, languages: item.languages, + releaseGroup: item.releaseGroup, downloadId: item.downloadId }; }); diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 367e6ea2d..d0d2e5e58 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -128,6 +128,7 @@ "ClickToChangeLanguage": "Click to change language", "ClickToChangeMovie": "Click to change movie", "ClickToChangeQuality": "Click to change quality", + "ClickToChangeReleaseGroup": "Click to change release group", "ClientPriority": "Client Priority", "CloneCustomFormat": "Clone Custom Format", "CloneFormatTag": "Clone Format Tag", @@ -491,6 +492,7 @@ "ManualImportSelectLanguage": "Manual Import - Select Language", "ManualImportSelectMovie": "Manual Import - Select Movie", "ManualImportSelectQuality": " Manual Import - Select Quality", + "ManualImportSetReleaseGroup": "Manual Import - Set Release Group", "MappedDrivesRunningAsService": "Mapped network drives are not available when running as a Windows Service. Please see the FAQ for more information", "MarkAsFailed": "Mark as Failed", "MarkAsFailedMessageText": "Are you sure you want to mark '{0}' as failed?", @@ -881,6 +883,7 @@ "SelectLanguges": "Select Languages", "SelectMovie": "Select Movie", "SelectQuality": "Select Quality", + "SelectReleaseGroup": "Select Release Group", "SendAnonymousUsageData": "Send Anonymous Usage Data", "SetPermissions": "Set Permissions", "SetPermissionsLinuxHelpText": "Should chmod be run when files are imported/renamed?", diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateLanguage.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateLanguage.cs index 3df7c2f0a..60cadfcfe 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateLanguage.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Aggregation/Aggregators/AggregateLanguage.cs @@ -22,7 +22,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators public LocalMovie Aggregate(LocalMovie localMovie, DownloadClientItem downloadClientItem, bool otherFiles) { - var languages = new List { localMovie.Movie.OriginalLanguage ?? Language.Unknown }; + var languages = new List { localMovie.Movie?.OriginalLanguage ?? Language.Unknown }; var languagesConfidence = Confidence.Default; foreach (var augmentLanguage in _augmentLanguages) diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportFile.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportFile.cs index 0aab4af3f..87c500de1 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportFile.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportFile.cs @@ -12,6 +12,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual public string FolderName { get; set; } public QualityModel Quality { get; set; } public List Languages { get; set; } + public string ReleaseGroup { get; set; } public string DownloadId { get; set; } public int MovieId { get; set; } diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportItem.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportItem.cs index 613cc6ca7..6ed20c180 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportItem.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportItem.cs @@ -15,6 +15,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual public long Size { get; set; } public QualityModel Quality { get; set; } public List Languages { get; set; } + public string ReleaseGroup { get; set; } public string DownloadId { get; set; } public IEnumerable Rejections { get; set; } public Movie Movie { get; set; } diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportService.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportService.cs index c2909c7c7..e3099bd5f 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportService.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportService.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -22,7 +23,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual public interface IManualImportService { List GetMediaFiles(string path, string downloadId, int? movieId, bool filterExistingFiles); - ManualImportItem ReprocessItem(string path, string downloadId, int movieId, QualityModel quality, List languages); + ManualImportItem ReprocessItem(string path, string downloadId, int movieId, string releaseGroup, QualityModel quality, List languages); } public class ManualImportService : IExecute, IManualImportService @@ -92,13 +93,21 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual return ProcessFolder(path, path, downloadId, movieId, filterExistingFiles); } - public ManualImportItem ReprocessItem(string path, string downloadId, int movieId, QualityModel quality, List languages) + public ManualImportItem ReprocessItem(string path, string downloadId, int movieId, string releaseGroup, QualityModel quality, List languages) { var rootFolder = Path.GetDirectoryName(path); var movie = _movieService.GetMovie(movieId); var downloadClientItem = GetTrackedDownload(downloadId)?.DownloadItem; + var languageParse = LanguageParser.ParseLanguages(path); + + if (languageParse.Count <= 1 && languageParse.First() == Language.Unknown && movie != null) + { + languageParse = new List { movie.OriginalLanguage }; + _logger.Debug("Language couldn't be parsed from release, fallback to movie original language: {0}", movie.OriginalLanguage.Name); + } + var localEpisode = new LocalMovie { Movie = movie, @@ -108,8 +117,9 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual SceneSource = SceneSource(movie, rootFolder), ExistingFile = movie.Path.IsParentPath(path), Size = _diskProvider.GetFileSize(path), - Languages = (languages?.SingleOrDefault() ?? Language.Unknown) == Language.Unknown ? LanguageParser.ParseLanguages(path) : languages, - Quality = quality.Quality == Quality.Unknown ? QualityParser.ParseQuality(path) : quality + Languages = (languages?.SingleOrDefault() ?? Language.Unknown) == Language.Unknown ? languageParse : languages, + Quality = quality.Quality == Quality.Unknown ? QualityParser.ParseQuality(path) : quality, + ReleaseGroup = releaseGroup.IsNullOrWhiteSpace() ? Parser.Parser.ParseReleaseGroup(path) : releaseGroup, }; return MapItem(_importDecisionMaker.GetDecision(localEpisode, downloadClientItem), rootFolder, downloadId, null); @@ -118,6 +128,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual private List ProcessFolder(string rootFolder, string baseFolder, string downloadId, int? movieId, bool filterExistingFiles) { DownloadClientItem downloadClientItem = null; + var directoryInfo = new DirectoryInfo(baseFolder); var movie = movieId.HasValue ? @@ -165,50 +176,58 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual private ManualImportItem ProcessFile(string rootFolder, string baseFolder, string file, string downloadId, Movie movie = null) { - var trackedDownload = GetTrackedDownload(downloadId); - var relativeFile = baseFolder.GetRelativePath(file); - - if (movie == null) + try { - movie = _parsingService.GetMovie(relativeFile.Split('\\', '/')[0]); - } + var trackedDownload = GetTrackedDownload(downloadId); + var relativeFile = baseFolder.GetRelativePath(file); - if (movie == null) - { - movie = _parsingService.GetMovie(relativeFile); - } + if (movie == null) + { + movie = _parsingService.GetMovie(relativeFile.Split('\\', '/')[0]); + } - if (trackedDownload != null && movie == null) - { - movie = trackedDownload?.RemoteMovie?.Movie; - } + if (movie == null) + { + movie = _parsingService.GetMovie(relativeFile); + } - if (movie == null) - { - var relativeParseInfo = Parser.Parser.ParseMoviePath(relativeFile); + if (trackedDownload != null && movie == null) + { + movie = trackedDownload?.RemoteMovie?.Movie; + } - if (relativeParseInfo != null) + if (movie == null) { - movie = _movieService.FindByTitle(relativeParseInfo.PrimaryMovieTitle, relativeParseInfo.Year); + var relativeParseInfo = Parser.Parser.ParseMoviePath(relativeFile); + + if (relativeParseInfo != null) + { + movie = _movieService.FindByTitle(relativeParseInfo.PrimaryMovieTitle, relativeParseInfo.Year); + } } - } - if (movie == null) - { - var localMovie = new LocalMovie(); - localMovie.Path = file; - localMovie.Quality = QualityParser.ParseQuality(file); - localMovie.Languages = LanguageParser.ParseLanguages(file); - localMovie.Size = _diskProvider.GetFileSize(file); + if (movie == null) + { + var localMovie = new LocalMovie(); + localMovie.Path = file; + localMovie.FileMovieInfo = Parser.Parser.ParseMoviePath(file); + localMovie.DownloadClientMovieInfo = trackedDownload?.RemoteMovie?.ParsedMovieInfo; - return MapItem(new ImportDecision(localMovie, new Rejection("Unknown Movie")), rootFolder, downloadId, null); - } + localMovie = _aggregationService.Augment(localMovie, null, false); - var importDecisions = _importDecisionMaker.GetImportDecisions(new List { file }, movie, trackedDownload?.DownloadItem, null, SceneSource(movie, baseFolder)); + return MapItem(new ImportDecision(localMovie, new Rejection("Unknown Movie")), rootFolder, downloadId, null); + } - if (importDecisions.Any()) + var importDecisions = _importDecisionMaker.GetImportDecisions(new List { file }, movie, trackedDownload?.DownloadItem, null, SceneSource(movie, baseFolder)); + + if (importDecisions.Any()) + { + return MapItem(importDecisions.First(), rootFolder, downloadId, null); + } + } + catch (Exception ex) { - return MapItem(importDecisions.First(), rootFolder, downloadId, null); + _logger.Warn(ex, "Failed to process file: {0}", file); } return new ManualImportItem @@ -231,6 +250,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual localEpisode.Path = file; localEpisode.Quality = new QualityModel(Quality.Unknown); localEpisode.Languages = new List { Language.Unknown }; + localEpisode.ReleaseGroup = Parser.Parser.ParseReleaseGroup(file); localEpisode.Size = _diskProvider.GetFileSize(file); items.Add(MapItem(new ImportDecision(localEpisode), rootFolder, null, null)); @@ -274,6 +294,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual item.Quality = decision.LocalMovie.Quality; item.Size = _diskProvider.GetFileSize(decision.LocalMovie.Path); item.Languages = decision.LocalMovie.Languages; + item.ReleaseGroup = decision.LocalMovie.ReleaseGroup; item.Rejections = decision.Rejections; return item; @@ -303,6 +324,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual Path = file.Path, Quality = file.Quality, Languages = file.Languages, + ReleaseGroup = file.ReleaseGroup, Movie = movie, Size = 0 }; @@ -325,6 +347,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual localMovie.Movie = movie; localMovie.Quality = file.Quality; localMovie.Languages = file.Languages; + localMovie.ReleaseGroup = file.ReleaseGroup; //TODO: Cleanup non-tracked downloads var importDecision = new ImportDecision(localMovie); diff --git a/src/Radarr.Api.V3/ManualImport/ManualImportController.cs b/src/Radarr.Api.V3/ManualImport/ManualImportController.cs index 88d8b5896..769f94cba 100644 --- a/src/Radarr.Api.V3/ManualImport/ManualImportController.cs +++ b/src/Radarr.Api.V3/ManualImport/ManualImportController.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Mvc; +using NzbDrone.Common.Extensions; using NzbDrone.Core.Languages; using NzbDrone.Core.MediaFiles.MovieImport.Manual; using NzbDrone.Core.Qualities; @@ -30,7 +31,7 @@ namespace Radarr.Api.V3.ManualImport { foreach (var item in items) { - var processedItem = _manualImportService.ReprocessItem(item.Path, item.DownloadId, item.MovieId, item.Quality, item.Languages); + var processedItem = _manualImportService.ReprocessItem(item.Path, item.DownloadId, item.MovieId, item.ReleaseGroup, item.Quality, item.Languages); item.Movie = processedItem.Movie.ToResource(0); item.Rejections = processedItem.Rejections; @@ -43,6 +44,11 @@ namespace Radarr.Api.V3.ManualImport { item.Quality = processedItem.Quality; } + + if (item.ReleaseGroup.IsNotNullOrWhiteSpace()) + { + item.ReleaseGroup = processedItem.ReleaseGroup; + } } return items; diff --git a/src/Radarr.Api.V3/ManualImport/ManualImportReprocessResource.cs b/src/Radarr.Api.V3/ManualImport/ManualImportReprocessResource.cs index f610efbc5..4999ae42d 100644 --- a/src/Radarr.Api.V3/ManualImport/ManualImportReprocessResource.cs +++ b/src/Radarr.Api.V3/ManualImport/ManualImportReprocessResource.cs @@ -14,6 +14,7 @@ namespace Radarr.Api.V3.ManualImport public MovieResource Movie { get; set; } public QualityModel Quality { get; set; } public List Languages { get; set; } + public string ReleaseGroup { get; set; } public string DownloadId { get; set; } public IEnumerable Rejections { get; set; } diff --git a/src/Radarr.Api.V3/ManualImport/ManualImportResource.cs b/src/Radarr.Api.V3/ManualImport/ManualImportResource.cs index da6204c04..63c698c77 100644 --- a/src/Radarr.Api.V3/ManualImport/ManualImportResource.cs +++ b/src/Radarr.Api.V3/ManualImport/ManualImportResource.cs @@ -20,6 +20,7 @@ namespace Radarr.Api.V3.ManualImport public MovieResource Movie { get; set; } public QualityModel Quality { get; set; } public List Languages { get; set; } + public string ReleaseGroup { get; set; } public int QualityWeight { get; set; } public string DownloadId { get; set; } public IEnumerable Rejections { get; set; } @@ -45,6 +46,7 @@ namespace Radarr.Api.V3.ManualImport Movie = model.Movie.ToResource(0), Quality = model.Quality, Languages = model.Languages, + ReleaseGroup = model.ReleaseGroup, //QualityWeight DownloadId = model.DownloadId,