New: Show Custom Formats on Manual Import / Manage Episodes

Closes #5241
This commit is contained in:
Mark McDowall 2022-12-03 17:16:08 -08:00 committed by Mark McDowall
parent 6216a71f8c
commit da4f6b7df9
8 changed files with 82 additions and 2 deletions

View File

@ -77,6 +77,15 @@ const columns = [
isSortable: true, isSortable: true,
isVisible: true isVisible: true
}, },
{
name: 'customFormats',
label: React.createElement(Icon, {
name: icons.INTERACTIVE,
title: 'Custom Format'
}),
isSortable: true,
isVisible: true
},
{ {
name: 'rejections', name: 'rejections',
label: React.createElement(Icon, { label: React.createElement(Icon, {

View File

@ -23,3 +23,7 @@
margin-top: 0; margin-top: 0;
text-align: start; text-align: start;
} }
.customFormatTooltip {
max-width: 250px;
}

View File

@ -7,6 +7,7 @@ import TableRowCellButton from 'Components/Table/Cells/TableRowCellButton';
import TableSelectCell from 'Components/Table/Cells/TableSelectCell'; import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
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 EpisodeFormats from 'Episode/EpisodeFormats';
import EpisodeLanguages from 'Episode/EpisodeLanguages'; import EpisodeLanguages from 'Episode/EpisodeLanguages';
import EpisodeQuality from 'Episode/EpisodeQuality'; import EpisodeQuality from 'Episode/EpisodeQuality';
import { icons, kinds, tooltipPositions } from 'Helpers/Props'; import { icons, kinds, tooltipPositions } from 'Helpers/Props';
@ -213,6 +214,7 @@ class InteractiveImportRow extends Component {
languages, languages,
releaseGroup, releaseGroup,
size, size,
customFormats,
rejections, rejections,
isReprocessing, isReprocessing,
isSelected, isSelected,
@ -366,7 +368,26 @@ class InteractiveImportRow extends Component {
<TableRowCell> <TableRowCell>
{ {
rejections && rejections.length ? customFormats?.length ?
<Popover
anchor={
<Icon name={icons.INTERACTIVE} />
}
title="Formats"
body={
<div className={styles.customFormatTooltip}>
<EpisodeFormats formats={customFormats} />
</div>
}
position={tooltipPositions.LEFT}
/> :
null
}
</TableRowCell>
<TableRowCell>
{
rejections.length ?
<Popover <Popover
anchor={ anchor={
<Icon <Icon
@ -389,6 +410,7 @@ class InteractiveImportRow extends Component {
</ul> </ul>
} }
position={tooltipPositions.LEFT} position={tooltipPositions.LEFT}
canFlip={false}
/> : /> :
null null
} }
@ -462,6 +484,7 @@ InteractiveImportRow.propTypes = {
quality: PropTypes.object, quality: PropTypes.object,
languages: PropTypes.arrayOf(PropTypes.object), languages: PropTypes.arrayOf(PropTypes.object),
size: PropTypes.number.isRequired, size: PropTypes.number.isRequired,
customFormats: PropTypes.arrayOf(PropTypes.object),
rejections: PropTypes.arrayOf(PropTypes.object).isRequired, rejections: PropTypes.arrayOf(PropTypes.object).isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired, columns: PropTypes.arrayOf(PropTypes.object).isRequired,
episodeFileId: PropTypes.number, episodeFileId: PropTypes.number,

View File

@ -18,6 +18,7 @@ namespace NzbDrone.Core.CustomFormats
List<CustomFormat> ParseCustomFormat(EpisodeFile episodeFile); List<CustomFormat> ParseCustomFormat(EpisodeFile episodeFile);
List<CustomFormat> ParseCustomFormat(Blocklist blocklist, Series series); List<CustomFormat> ParseCustomFormat(Blocklist blocklist, Series series);
List<CustomFormat> ParseCustomFormat(EpisodeHistory history, Series series); List<CustomFormat> ParseCustomFormat(EpisodeHistory history, Series series);
List<CustomFormat> ParseCustomFormat(LocalEpisode localEpisode);
} }
public class CustomFormatCalculationService : ICustomFormatCalculationService public class CustomFormatCalculationService : ICustomFormatCalculationService
@ -102,6 +103,28 @@ namespace NzbDrone.Core.CustomFormats
return ParseCustomFormat(input); return ParseCustomFormat(input);
} }
public List<CustomFormat> ParseCustomFormat(LocalEpisode localEpisode)
{
var episodeInfo = new ParsedEpisodeInfo
{
SeriesTitle = localEpisode.Series.Title,
ReleaseTitle = localEpisode.SceneName,
Quality = localEpisode.Quality,
Languages = localEpisode.Languages,
ReleaseGroup = localEpisode.ReleaseGroup
};
var input = new CustomFormatInput
{
EpisodeInfo = episodeInfo,
Series = localEpisode.Series,
Size = localEpisode.Size,
Languages = localEpisode.Languages
};
return ParseCustomFormat(input);
}
private List<CustomFormat> ParseCustomFormat(CustomFormatInput input) private List<CustomFormat> ParseCustomFormat(CustomFormatInput input)
{ {
return ParseCustomFormat(input, _formatService.All()); return ParseCustomFormat(input, _formatService.All());
@ -148,7 +171,7 @@ namespace NzbDrone.Core.CustomFormats
var episodeInfo = new ParsedEpisodeInfo var episodeInfo = new ParsedEpisodeInfo
{ {
SeriesTitle = episodeFile.Series.Value.Title, SeriesTitle = series.Title,
ReleaseTitle = sceneName, ReleaseTitle = sceneName,
Quality = episodeFile.Quality, Quality = episodeFile.Quality,
Languages = episodeFile.Languages, Languages = episodeFile.Languages,

View File

@ -4,6 +4,7 @@ using System.Linq;
using NLog; using NLog;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation; using NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation;
@ -28,6 +29,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
private readonly IAggregationService _aggregationService; private readonly IAggregationService _aggregationService;
private readonly IDiskProvider _diskProvider; private readonly IDiskProvider _diskProvider;
private readonly IDetectSample _detectSample; private readonly IDetectSample _detectSample;
private readonly ICustomFormatCalculationService _formatCalculator;
private readonly Logger _logger; private readonly Logger _logger;
public ImportDecisionMaker(IEnumerable<IImportDecisionEngineSpecification> specifications, public ImportDecisionMaker(IEnumerable<IImportDecisionEngineSpecification> specifications,
@ -35,6 +37,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
IAggregationService aggregationService, IAggregationService aggregationService,
IDiskProvider diskProvider, IDiskProvider diskProvider,
IDetectSample detectSample, IDetectSample detectSample,
ICustomFormatCalculationService formatCalculator,
Logger logger) Logger logger)
{ {
_specifications = specifications; _specifications = specifications;
@ -42,6 +45,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
_aggregationService = aggregationService; _aggregationService = aggregationService;
_diskProvider = diskProvider; _diskProvider = diskProvider;
_detectSample = detectSample; _detectSample = detectSample;
_formatCalculator = formatCalculator;
_logger = logger; _logger = logger;
} }

View File

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Languages; using NzbDrone.Core.Languages;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
@ -21,6 +22,12 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
public List<Language> Languages { get; set; } public List<Language> Languages { get; set; }
public string ReleaseGroup { get; set; } public string ReleaseGroup { get; set; }
public string DownloadId { get; set; } public string DownloadId { get; set; }
public List<CustomFormat> CustomFormats { get; set; }
public IEnumerable<Rejection> Rejections { get; set; } public IEnumerable<Rejection> Rejections { get; set; }
public ManualImportItem()
{
CustomFormats = new List<CustomFormat>();
}
} }
} }

View File

@ -6,6 +6,7 @@ using NLog;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Instrumentation.Extensions; using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.Download.TrackedDownloads; using NzbDrone.Core.Download.TrackedDownloads;
@ -40,6 +41,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
private readonly ITrackedDownloadService _trackedDownloadService; private readonly ITrackedDownloadService _trackedDownloadService;
private readonly IDownloadedEpisodesImportService _downloadedEpisodesImportService; private readonly IDownloadedEpisodesImportService _downloadedEpisodesImportService;
private readonly IMediaFileService _mediaFileService; private readonly IMediaFileService _mediaFileService;
private readonly ICustomFormatCalculationService _formatCalculator;
private readonly IEventAggregator _eventAggregator; private readonly IEventAggregator _eventAggregator;
private readonly Logger _logger; private readonly Logger _logger;
@ -54,6 +56,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
ITrackedDownloadService trackedDownloadService, ITrackedDownloadService trackedDownloadService,
IDownloadedEpisodesImportService downloadedEpisodesImportService, IDownloadedEpisodesImportService downloadedEpisodesImportService,
IMediaFileService mediaFileService, IMediaFileService mediaFileService,
ICustomFormatCalculationService formatCalculator,
IEventAggregator eventAggregator, IEventAggregator eventAggregator,
Logger logger) Logger logger)
{ {
@ -68,6 +71,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
_trackedDownloadService = trackedDownloadService; _trackedDownloadService = trackedDownloadService;
_downloadedEpisodesImportService = downloadedEpisodesImportService; _downloadedEpisodesImportService = downloadedEpisodesImportService;
_mediaFileService = mediaFileService; _mediaFileService = mediaFileService;
_formatCalculator = formatCalculator;
_eventAggregator = eventAggregator; _eventAggregator = eventAggregator;
_logger = logger; _logger = logger;
} }
@ -382,6 +386,8 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
if (decision.LocalEpisode.Series != null) if (decision.LocalEpisode.Series != null)
{ {
item.Series = decision.LocalEpisode.Series; item.Series = decision.LocalEpisode.Series;
item.CustomFormats = _formatCalculator.ParseCustomFormat(decision.LocalEpisode);
} }
if (decision.LocalEpisode.Episodes.Any() && decision.LocalEpisode.Episodes.Select(c => c.SeasonNumber).Distinct().Count() == 1) if (decision.LocalEpisode.Episodes.Any() && decision.LocalEpisode.Episodes.Select(c => c.SeasonNumber).Distinct().Count() == 1)
@ -429,6 +435,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
item.Size = _diskProvider.GetFileSize(item.Path); item.Size = _diskProvider.GetFileSize(item.Path);
item.Rejections = Enumerable.Empty<Rejection>(); item.Rejections = Enumerable.Empty<Rejection>();
item.EpisodeFileId = episodeFile.Id; item.EpisodeFileId = episodeFile.Id;
item.CustomFormats = _formatCalculator.ParseCustomFormat(episodeFile, series);
return item; return item;
} }

View File

@ -5,6 +5,7 @@ using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Languages; using NzbDrone.Core.Languages;
using NzbDrone.Core.MediaFiles.EpisodeImport.Manual; using NzbDrone.Core.MediaFiles.EpisodeImport.Manual;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using Sonarr.Api.V3.CustomFormats;
using Sonarr.Api.V3.Episodes; using Sonarr.Api.V3.Episodes;
using Sonarr.Api.V3.Series; using Sonarr.Api.V3.Series;
using Sonarr.Http.REST; using Sonarr.Http.REST;
@ -27,6 +28,7 @@ namespace Sonarr.Api.V3.ManualImport
public List<Language> Languages { get; set; } public List<Language> Languages { get; set; }
public int QualityWeight { get; set; } public int QualityWeight { get; set; }
public string DownloadId { get; set; } public string DownloadId { get; set; }
public List<CustomFormatResource> CustomFormats { get; set; }
public IEnumerable<Rejection> Rejections { get; set; } public IEnumerable<Rejection> Rejections { get; set; }
} }
@ -54,6 +56,7 @@ namespace Sonarr.Api.V3.ManualImport
ReleaseGroup = model.ReleaseGroup, ReleaseGroup = model.ReleaseGroup,
Quality = model.Quality, Quality = model.Quality,
Languages = model.Languages, Languages = model.Languages,
CustomFormats = model.CustomFormats.ToResource(),
// QualityWeight // QualityWeight
DownloadId = model.DownloadId, DownloadId = model.DownloadId,