New: Optionally show Custom Format Score for episodes on Series Details

This commit is contained in:
jack-mil 2023-07-15 13:28:38 -04:00 committed by GitHub
parent ef6ff370ba
commit eadd0c4e10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 50 additions and 2 deletions

View File

@ -56,3 +56,9 @@
width: 120px; width: 120px;
} }
.customFormatScore {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 55px;
}

View File

@ -3,6 +3,7 @@
interface CssExports { interface CssExports {
'audio': string; 'audio': string;
'audioLanguages': string; 'audioLanguages': string;
'customFormatScore': string;
'episodeNumber': string; 'episodeNumber': string;
'episodeNumberAnime': string; 'episodeNumberAnime': string;
'languages': string; 'languages': string;

View File

@ -4,6 +4,7 @@ import MonitorToggleButton from 'Components/MonitorToggleButton';
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 Tooltip from 'Components/Tooltip/Tooltip';
import EpisodeFormats from 'Episode/EpisodeFormats'; import EpisodeFormats from 'Episode/EpisodeFormats';
import EpisodeNumber from 'Episode/EpisodeNumber'; import EpisodeNumber from 'Episode/EpisodeNumber';
import EpisodeSearchCellConnector from 'Episode/EpisodeSearchCellConnector'; import EpisodeSearchCellConnector from 'Episode/EpisodeSearchCellConnector';
@ -12,7 +13,9 @@ import EpisodeTitleLink from 'Episode/EpisodeTitleLink';
import EpisodeFileLanguageConnector from 'EpisodeFile/EpisodeFileLanguageConnector'; import EpisodeFileLanguageConnector from 'EpisodeFile/EpisodeFileLanguageConnector';
import MediaInfoConnector from 'EpisodeFile/MediaInfoConnector'; import MediaInfoConnector from 'EpisodeFile/MediaInfoConnector';
import * as mediaInfoTypes from 'EpisodeFile/mediaInfoTypes'; import * as mediaInfoTypes from 'EpisodeFile/mediaInfoTypes';
import { tooltipPositions } from 'Helpers/Props';
import formatBytes from 'Utilities/Number/formatBytes'; import formatBytes from 'Utilities/Number/formatBytes';
import formatPreferredWordScore from 'Utilities/Number/formatPreferredWordScore';
import formatRuntime from 'Utilities/Number/formatRuntime'; import formatRuntime from 'Utilities/Number/formatRuntime';
import styles from './EpisodeRow.css'; import styles from './EpisodeRow.css';
@ -72,6 +75,7 @@ class EpisodeRow extends Component {
episodeFileSize, episodeFileSize,
releaseGroup, releaseGroup,
customFormats, customFormats,
customFormatScore,
alternateTitles, alternateTitles,
columns columns
} = this.props; } = this.props;
@ -193,6 +197,24 @@ class EpisodeRow extends Component {
); );
} }
if (name === 'customFormatScore') {
return (
<TableRowCell
key={name}
className={styles.customFormatScore}
>
<Tooltip
anchor={formatPreferredWordScore(
customFormatScore,
customFormats.length
)}
tooltip={<EpisodeFormats formats={customFormats} />}
position={tooltipPositions.BOTTOM}
/>
</TableRowCell>
);
}
if (name === 'languages') { if (name === 'languages') {
return ( return (
<TableRowCell <TableRowCell
@ -355,6 +377,7 @@ EpisodeRow.propTypes = {
episodeFileSize: PropTypes.number, episodeFileSize: PropTypes.number,
releaseGroup: PropTypes.string, releaseGroup: PropTypes.string,
customFormats: PropTypes.arrayOf(PropTypes.object), customFormats: PropTypes.arrayOf(PropTypes.object),
customFormatScore: PropTypes.number.isRequired,
mediaInfo: PropTypes.object, mediaInfo: PropTypes.object,
alternateTitles: PropTypes.arrayOf(PropTypes.object).isRequired, alternateTitles: PropTypes.arrayOf(PropTypes.object).isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired, columns: PropTypes.arrayOf(PropTypes.object).isRequired,

View File

@ -19,6 +19,7 @@ function createMapStateToProps() {
episodeFileSize: episodeFile ? episodeFile.size : null, episodeFileSize: episodeFile ? episodeFile.size : null,
releaseGroup: episodeFile ? episodeFile.releaseGroup : null, releaseGroup: episodeFile ? episodeFile.releaseGroup : null,
customFormats: episodeFile ? episodeFile.customFormats : [], customFormats: episodeFile ? episodeFile.customFormats : [],
customFormatScore: episodeFile ? episodeFile.customFormatScore : 0,
alternateTitles: series.alternateTitles alternateTitles: series.alternateTitles
}; };
} }

View File

@ -1,10 +1,13 @@
import _ from 'lodash'; import _ from 'lodash';
import React from 'react';
import { createAction } from 'redux-actions'; import { createAction } from 'redux-actions';
import { batchActions } from 'redux-batched-actions'; import { batchActions } from 'redux-batched-actions';
import Icon from 'Components/Icon';
import episodeEntities from 'Episode/episodeEntities'; import episodeEntities from 'Episode/episodeEntities';
import { sortDirections } from 'Helpers/Props'; import { icons, sortDirections } from 'Helpers/Props';
import { createThunk, handleThunks } from 'Store/thunks'; import { createThunk, handleThunks } from 'Store/thunks';
import createAjaxRequest from 'Utilities/createAjaxRequest'; import createAjaxRequest from 'Utilities/createAjaxRequest';
import translate from 'Utilities/String/translate';
import { updateItem } from './baseActions'; import { updateItem } from './baseActions';
import createFetchHandler from './Creators/createFetchHandler'; import createFetchHandler from './Creators/createFetchHandler';
import createHandleActions from './Creators/createHandleActions'; import createHandleActions from './Creators/createHandleActions';
@ -109,6 +112,15 @@ export const defaultState = {
label: 'Formats', label: 'Formats',
isVisible: false isVisible: false
}, },
{
name: 'customFormatScore',
columnLabel: translate('CustomFormatScore'),
label: React.createElement(Icon, {
name: icons.SCORE,
title: translate('CustomFormatScore')
}),
isVisible: false
},
{ {
name: 'status', name: 'status',
label: 'Status', label: 'Status',

View File

@ -25,6 +25,7 @@
"CountImportListsSelected": "{count} import list(s) selected", "CountImportListsSelected": "{count} import list(s) selected",
"CountIndexersSelected": "{count} indexer(s) selected", "CountIndexersSelected": "{count} indexer(s) selected",
"CountSeasons": "{count} seasons", "CountSeasons": "{count} seasons",
"CustomFormatScore": "Custom Format Score",
"Delete": "Delete", "Delete": "Delete",
"DeleteCondition": "Delete Condition", "DeleteCondition": "Delete Condition",
"DeleteConditionMessageText": "Are you sure you want to delete the condition '{0}'?", "DeleteConditionMessageText": "Are you sure you want to delete the condition '{0}'?",

View File

@ -24,6 +24,7 @@ namespace Sonarr.Api.V3.EpisodeFiles
public List<Language> Languages { 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 MediaInfoResource MediaInfo { get; set; } public MediaInfoResource MediaInfo { get; set; }
public bool QualityCutoffNotMet { get; set; } public bool QualityCutoffNotMet { get; set; }
@ -67,6 +68,8 @@ namespace Sonarr.Api.V3.EpisodeFiles
} }
model.Series = series; model.Series = series;
var customFormats = formatCalculationService?.ParseCustomFormat(model, model.Series);
var customFormatScore = series?.QualityProfile?.Value?.CalculateCustomFormatScore(customFormats) ?? 0;
return new EpisodeFileResource return new EpisodeFileResource
{ {
@ -84,7 +87,8 @@ namespace Sonarr.Api.V3.EpisodeFiles
Quality = model.Quality, Quality = model.Quality,
MediaInfo = model.MediaInfo.ToResource(model.SceneName), MediaInfo = model.MediaInfo.ToResource(model.SceneName),
QualityCutoffNotMet = upgradableSpecification.QualityCutoffNotMet(series.QualityProfile.Value, model.Quality), QualityCutoffNotMet = upgradableSpecification.QualityCutoffNotMet(series.QualityProfile.Value, model.Quality),
CustomFormats = formatCalculationService.ParseCustomFormat(model).ToResource(false) CustomFormats = customFormats.ToResource(false),
CustomFormatScore = customFormatScore
}; };
} }
} }