New: Quality Preferred Setting

Co-authored-by: Qstick <qstick@gmail.com>
Closes #724
This commit is contained in:
Mark McDowall 2022-12-10 09:59:54 -08:00 committed by GitHub
parent b2b9172c92
commit d08f33ae21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 200 additions and 45 deletions

View File

@ -31,7 +31,7 @@
background-color: var(--sliderAccentColor); background-color: var(--sliderAccentColor);
box-shadow: 0 0 0 #000; box-shadow: 0 0 0 #000;
&:nth-child(odd) { &:nth-child(3n+1) {
background-color: #ddd; background-color: #ddd;
} }
} }
@ -56,7 +56,7 @@
.megabytesPerMinute { .megabytesPerMinute {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
flex: 0 0 250px; flex: 0 0 400px;
} }
.sizeInput { .sizeInput {

View File

@ -51,7 +51,8 @@ class QualityDefinition extends Component {
this.state = { this.state = {
sliderMinSize: getSliderValue(props.minSize, slider.min), sliderMinSize: getSliderValue(props.minSize, slider.min),
sliderMaxSize: getSliderValue(props.maxSize, slider.max) sliderMaxSize: getSliderValue(props.maxSize, slider.max),
sliderPreferredSize: getSliderValue(props.preferredSize, (slider.max - 3))
}; };
} }
@ -93,14 +94,16 @@ class QualityDefinition extends Component {
// //
// Listeners // Listeners
onSliderChange = ([sliderMinSize, sliderMaxSize]) => { onSliderChange = ([sliderMinSize, sliderPreferredSize, sliderMaxSize]) => {
this.setState({ this.setState({
sliderMinSize, sliderMinSize,
sliderMaxSize sliderMaxSize,
sliderPreferredSize
}); });
this.props.onSizeChange({ this.props.onSizeChange({
minSize: roundNumber(Math.pow(sliderMinSize, 1.1)), minSize: roundNumber(Math.pow(sliderMinSize, 1.1)),
preferredSize: sliderPreferredSize === (slider.max - 3) ? null : roundNumber(Math.pow(sliderPreferredSize, 1.1)),
maxSize: sliderMaxSize === slider.max ? null : roundNumber(Math.pow(sliderMaxSize, 1.1)) maxSize: sliderMaxSize === slider.max ? null : roundNumber(Math.pow(sliderMaxSize, 1.1))
}); });
}; };
@ -108,12 +111,14 @@ class QualityDefinition extends Component {
onAfterSliderChange = () => { onAfterSliderChange = () => {
const { const {
minSize, minSize,
maxSize maxSize,
preferredSize
} = this.props; } = this.props;
this.setState({ this.setState({
sliderMiSize: getSliderValue(minSize, slider.min), sliderMiSize: getSliderValue(minSize, slider.min),
sliderMaxSize: getSliderValue(maxSize, slider.max) sliderMaxSize: getSliderValue(maxSize, slider.max),
sliderPreferredSize: getSliderValue(preferredSize, (slider.max - 3)) // fix
}); });
}; };
@ -126,7 +131,22 @@ class QualityDefinition extends Component {
this.props.onSizeChange({ this.props.onSizeChange({
minSize, minSize,
maxSize: this.props.maxSize maxSize: this.props.maxSize,
preferredSize: this.props.preferredSize
});
};
onPreferredSizeChange = ({ value }) => {
const preferredSize = value === (MAX - 3) ? null : getValue(value);
this.setState({
sliderPreferredSize: getSliderValue(preferredSize, slider.preferred)
});
this.props.onSizeChange({
minSize: this.props.minSize,
maxSize: this.props.maxSize,
preferredSize
}); });
}; };
@ -139,7 +159,8 @@ class QualityDefinition extends Component {
this.props.onSizeChange({ this.props.onSizeChange({
minSize: this.props.minSize, minSize: this.props.minSize,
maxSize maxSize,
preferredSize: this.props.preferredSize
}); });
}; };
@ -153,18 +174,23 @@ class QualityDefinition extends Component {
title, title,
minSize, minSize,
maxSize, maxSize,
preferredSize,
advancedSettings, advancedSettings,
onTitleChange onTitleChange
} = this.props; } = this.props;
const { const {
sliderMinSize, sliderMinSize,
sliderMaxSize sliderMaxSize,
sliderPreferredSize
} = this.state; } = this.state;
const minBytes = minSize * 1024 * 1024; const minBytes = minSize * 1024 * 1024;
const minSixty = `${formatBytes(minBytes * 60)}/h`; const minSixty = `${formatBytes(minBytes * 60)}/h`;
const preferredBytes = preferredSize * 1024 * 1024;
const preferredSixty = preferredBytes ? `${formatBytes(preferredBytes * 60)}/h` : 'Unlimited';
const maxBytes = maxSize && maxSize * 1024 * 1024; const maxBytes = maxSize && maxSize * 1024 * 1024;
const maxSixty = maxBytes ? `${formatBytes(maxBytes * 60)}/h` : 'Unlimited'; const maxSixty = maxBytes ? `${formatBytes(maxBytes * 60)}/h` : 'Unlimited';
@ -188,9 +214,10 @@ class QualityDefinition extends Component {
min={slider.min} min={slider.min}
max={slider.max} max={slider.max}
step={slider.step} step={slider.step}
minDistance={MIN_DISTANCE * 5} minDistance={3}
value={[sliderMinSize, sliderMaxSize]} value={[sliderMinSize, sliderPreferredSize, sliderMaxSize]}
withTracks={true} withTracks={true}
allowCross={false}
snapDragDisabled={true} snapDragDisabled={true}
renderThumb={this.thumbRenderer} renderThumb={this.thumbRenderer}
renderTrack={this.trackRenderer} renderTrack={this.trackRenderer}
@ -215,6 +242,22 @@ class QualityDefinition extends Component {
/> />
</div> </div>
<div>
<Popover
anchor={
<Label kind={kinds.SUCCESS}>{preferredSixty}</Label>
}
title="Preferred Size"
body={
<QualityDefinitionLimits
bytes={preferredBytes}
message="No limit for any runtime"
/>
}
position={tooltipPositions.BOTTOM}
/>
</div>
<div> <div>
<Popover <Popover
anchor={ anchor={
@ -244,13 +287,28 @@ class QualityDefinition extends Component {
name={`${id}.min`} name={`${id}.min`}
value={minSize || MIN} value={minSize || MIN}
min={MIN} min={MIN}
max={maxSize ? maxSize - MIN_DISTANCE : MAX - MIN_DISTANCE} max={preferredSize ? preferredSize - 5 : MAX - 5}
step={0.1} step={0.1}
isFloat={true} isFloat={true}
onChange={this.onMinSizeChange} onChange={this.onMinSizeChange}
/> />
</div> </div>
<div>
Preferred
<NumberInput
className={styles.sizeInput}
name={`${id}.min`}
value={preferredSize || MAX - 5}
min={MIN}
max={maxSize ? maxSize - 5 : MAX - 5}
step={0.1}
isFloat={true}
onChange={this.onPreferredSizeChange}
/>
</div>
<div> <div>
Max Max
@ -278,6 +336,7 @@ QualityDefinition.propTypes = {
title: PropTypes.string.isRequired, title: PropTypes.string.isRequired,
minSize: PropTypes.number, minSize: PropTypes.number,
maxSize: PropTypes.number, maxSize: PropTypes.number,
preferredSize: PropTypes.number,
advancedSettings: PropTypes.bool.isRequired, advancedSettings: PropTypes.bool.isRequired,
onTitleChange: PropTypes.func.isRequired, onTitleChange: PropTypes.func.isRequired,
onSizeChange: PropTypes.func.isRequired onSizeChange: PropTypes.func.isRequired

View File

@ -23,11 +23,12 @@ class QualityDefinitionConnector extends Component {
this.props.setQualityDefinitionValue({ id: this.props.id, name: 'title', value }); this.props.setQualityDefinitionValue({ id: this.props.id, name: 'title', value });
}; };
onSizeChange = ({ minSize, maxSize }) => { onSizeChange = ({ minSize, maxSize, preferredSize }) => {
const { const {
id, id,
minSize: currentMinSize, minSize: currentMinSize,
maxSize: currentMaxSize maxSize: currentMaxSize,
preferredSize: currentPreferredSize
} = this.props; } = this.props;
if (minSize !== currentMinSize) { if (minSize !== currentMinSize) {
@ -37,6 +38,10 @@ class QualityDefinitionConnector extends Component {
if (maxSize !== currentMaxSize) { if (maxSize !== currentMaxSize) {
this.props.setQualityDefinitionValue({ id, name: 'maxSize', value: maxSize }); this.props.setQualityDefinitionValue({ id, name: 'maxSize', value: maxSize });
} }
if (preferredSize !== currentPreferredSize) {
this.props.setQualityDefinitionValue({ id, name: 'preferredSize', value: preferredSize });
}
}; };
// //
@ -57,6 +62,7 @@ QualityDefinitionConnector.propTypes = {
id: PropTypes.number.isRequired, id: PropTypes.number.isRequired,
minSize: PropTypes.number, minSize: PropTypes.number,
maxSize: PropTypes.number, maxSize: PropTypes.number,
preferredSize: PropTypes.number,
setQualityDefinitionValue: PropTypes.func.isRequired, setQualityDefinitionValue: PropTypes.func.isRequired,
clearPendingChanges: PropTypes.func.isRequired clearPendingChanges: PropTypes.func.isRequired
}; };

View File

@ -15,7 +15,6 @@ using NzbDrone.Core.Profiles.Delay;
using NzbDrone.Core.Profiles.Qualities; using NzbDrone.Core.Profiles.Qualities;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Test.Languages;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.DecisionEngineTests namespace NzbDrone.Core.Test.DecisionEngineTests
@ -27,6 +26,17 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void Setup() public void Setup()
{ {
GivenPreferredDownloadProtocol(DownloadProtocol.Usenet); GivenPreferredDownloadProtocol(DownloadProtocol.Usenet);
Mocker.GetMock<IQualityDefinitionService>()
.Setup(s => s.Get(It.IsAny<Quality>()))
.Returns(new QualityDefinition { PreferredSize = null });
}
private void GivenPreferredSize(double? size)
{
Mocker.GetMock<IQualityDefinitionService>()
.Setup(s => s.Get(It.IsAny<Quality>()))
.Returns(new QualityDefinition { PreferredSize = size });
} }
private Episode GivenEpisode(int id) private Episode GivenEpisode(int id)
@ -54,6 +64,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
remoteEpisode.Release.IndexerPriority = indexerPriority; remoteEpisode.Release.IndexerPriority = indexerPriority;
remoteEpisode.Series = Builder<Series>.CreateNew() remoteEpisode.Series = Builder<Series>.CreateNew()
.With(e => e.Runtime = 60)
.With(e => e.QualityProfile = new QualityProfile .With(e => e.QualityProfile = new QualityProfile
{ {
Items = Qualities.QualityFixture.GetDefaultQualities() Items = Qualities.QualityFixture.GetDefaultQualities()
@ -161,6 +172,44 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
qualifiedReports.First().RemoteEpisode.Should().Be(remoteEpisodeHdLargeYoung); qualifiedReports.First().RemoteEpisode.Should().Be(remoteEpisodeHdLargeYoung);
} }
[Test]
public void should_order_by_closest_to_preferred_size_if_both_under()
{
// 200 MB/Min * 60 Min Runtime = 12000 MB
GivenPreferredSize(200);
var remoteEpisodeSmall = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.HDTV720p), Language.English, size: 1200.Megabytes(), age: 1);
var remoteEpisodeLarge = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.HDTV720p), Language.English, size: 10000.Megabytes(), age: 1);
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisodeSmall));
decisions.Add(new DownloadDecision(remoteEpisodeLarge));
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.Should().Be(remoteEpisodeLarge);
}
[Test]
public void should_order_by_closest_to_preferred_size_if_preferred_is_in_between()
{
// 46 MB/Min * 60 Min Runtime = 6900 MB
GivenPreferredSize(46);
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.HDTV720p), Language.English, size: 500.Megabytes(), age: 1);
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.HDTV720p), Language.English, size: 2000.Megabytes(), age: 1);
var remoteEpisode3 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.HDTV720p), Language.English, size: 3000.Megabytes(), age: 1);
var remoteEpisode4 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.HDTV720p), Language.English, size: 5000.Megabytes(), age: 1);
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1));
decisions.Add(new DownloadDecision(remoteEpisode2));
decisions.Add(new DownloadDecision(remoteEpisode3));
decisions.Add(new DownloadDecision(remoteEpisode4));
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.Should().Be(remoteEpisode3);
}
[Test] [Test]
public void should_order_by_youngest() public void should_order_by_youngest()
{ {

View File

@ -0,0 +1,16 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(181)]
public class quality_definition_preferred_size : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("QualityDefinitions").AddColumn("PreferredSize").AsDouble().Nullable();
Execute.Sql("UPDATE QualityDefinitions SET PreferredSize = MaxSize - 5 WHERE MaxSize > 5");
}
}
}

View File

@ -14,14 +14,16 @@ namespace NzbDrone.Core.DecisionEngine
{ {
private readonly IConfigService _configService; private readonly IConfigService _configService;
private readonly IDelayProfileService _delayProfileService; private readonly IDelayProfileService _delayProfileService;
private readonly IQualityDefinitionService _qualityDefinitionService;
public delegate int CompareDelegate(DownloadDecision x, DownloadDecision y); public delegate int CompareDelegate(DownloadDecision x, DownloadDecision y);
public delegate int CompareDelegate<TSubject, TValue>(DownloadDecision x, DownloadDecision y); public delegate int CompareDelegate<TSubject, TValue>(DownloadDecision x, DownloadDecision y);
public DownloadDecisionComparer(IConfigService configService, IDelayProfileService delayProfileService) public DownloadDecisionComparer(IConfigService configService, IDelayProfileService delayProfileService, IQualityDefinitionService qualityDefinitionService)
{ {
_configService = configService; _configService = configService;
_delayProfileService = delayProfileService; _delayProfileService = delayProfileService;
_qualityDefinitionService = qualityDefinitionService;
} }
public int Compare(DownloadDecision x, DownloadDecision y) public int Compare(DownloadDecision x, DownloadDecision y)
@ -180,9 +182,25 @@ namespace NzbDrone.Core.DecisionEngine
private int CompareSize(DownloadDecision x, DownloadDecision y) private int CompareSize(DownloadDecision x, DownloadDecision y)
{ {
// TODO: Is smaller better? Smaller for usenet could mean no par2 files. var sizeCompare = CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode =>
{
var preferredSize = _qualityDefinitionService.Get(remoteEpisode.ParsedEpisodeInfo.Quality.Quality).PreferredSize;
return CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.Release.Size.Round(200.Megabytes())); // If no value for preferred it means unlimited so fallback to sort largest is best
if (preferredSize.HasValue && remoteEpisode.Series.Runtime > 0)
{
var preferredMovieSize = remoteEpisode.Series.Runtime * preferredSize.Value.Megabytes();
// Calculate closest to the preferred size
return Math.Abs((remoteEpisode.Release.Size - preferredMovieSize).Round(200.Megabytes())) * (-1);
}
else
{
return remoteEpisode.Release.Size.Round(200.Megabytes());
}
});
return sizeCompare;
} }
} }
} }

View File

@ -1,7 +1,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Profiles.Delay; using NzbDrone.Core.Profiles.Delay;
using NzbDrone.Core.Qualities;
namespace NzbDrone.Core.DecisionEngine namespace NzbDrone.Core.DecisionEngine
{ {
@ -14,11 +15,13 @@ namespace NzbDrone.Core.DecisionEngine
{ {
private readonly IConfigService _configService; private readonly IConfigService _configService;
private readonly IDelayProfileService _delayProfileService; private readonly IDelayProfileService _delayProfileService;
private readonly IQualityDefinitionService _qualityDefinitionService;
public DownloadDecisionPriorizationService(IConfigService configService, IDelayProfileService delayProfileService) public DownloadDecisionPriorizationService(IConfigService configService, IDelayProfileService delayProfileService, IQualityDefinitionService qualityDefinitionService)
{ {
_configService = configService; _configService = configService;
_delayProfileService = delayProfileService; _delayProfileService = delayProfileService;
_qualityDefinitionService = qualityDefinitionService;
} }
public List<DownloadDecision> PrioritizeDecisions(List<DownloadDecision> decisions) public List<DownloadDecision> PrioritizeDecisions(List<DownloadDecision> decisions)
@ -26,7 +29,7 @@ namespace NzbDrone.Core.DecisionEngine
return decisions.Where(c => c.RemoteEpisode.Series != null) return decisions.Where(c => c.RemoteEpisode.Series != null)
.GroupBy(c => c.RemoteEpisode.Series.Id, (seriesId, downloadDecisions) => .GroupBy(c => c.RemoteEpisode.Series.Id, (seriesId, downloadDecisions) =>
{ {
return downloadDecisions.OrderByDescending(decision => decision, new DownloadDecisionComparer(_configService, _delayProfileService)); return downloadDecisions.OrderByDescending(decision => decision, new DownloadDecisionComparer(_configService, _delayProfileService, _qualityDefinitionService));
}) })
.SelectMany(c => c) .SelectMany(c => c)
.Union(decisions.Where(c => c.RemoteEpisode.Series == null)) .Union(decisions.Where(c => c.RemoteEpisode.Series == null))

View File

@ -149,27 +149,27 @@ namespace NzbDrone.Core.Qualities
DefaultQualityDefinitions = new HashSet<QualityDefinition> DefaultQualityDefinitions = new HashSet<QualityDefinition>
{ {
new QualityDefinition(Quality.Unknown) { Weight = 1, MinSize = 1, MaxSize = 199.9 }, new QualityDefinition(Quality.Unknown) { Weight = 1, MinSize = 1, MaxSize = 199.9, PreferredSize = 95 },
new QualityDefinition(Quality.SDTV) { Weight = 2, MinSize = 2, MaxSize = 100 }, new QualityDefinition(Quality.SDTV) { Weight = 2, MinSize = 2, MaxSize = 100, PreferredSize = 95 },
new QualityDefinition(Quality.WEBRip480p) { Weight = 3, MinSize = 2, MaxSize = 100, GroupName = "WEB 480p" }, new QualityDefinition(Quality.WEBRip480p) { Weight = 3, MinSize = 2, MaxSize = 100, PreferredSize = 95, GroupName = "WEB 480p" },
new QualityDefinition(Quality.WEBDL480p) { Weight = 3, MinSize = 2, MaxSize = 100, GroupName = "WEB 480p" }, new QualityDefinition(Quality.WEBDL480p) { Weight = 3, MinSize = 2, MaxSize = 100, PreferredSize = 95, GroupName = "WEB 480p" },
new QualityDefinition(Quality.DVD) { Weight = 4, MinSize = 2, MaxSize = 100, GroupName = "DVD" }, new QualityDefinition(Quality.DVD) { Weight = 4, MinSize = 2, MaxSize = 100, PreferredSize = 95, GroupName = "DVD" },
new QualityDefinition(Quality.Bluray480p) { Weight = 5, MinSize = 2, MaxSize = 100, GroupName = "DVD" }, new QualityDefinition(Quality.Bluray480p) { Weight = 5, MinSize = 2, MaxSize = 100, PreferredSize = 95, GroupName = "DVD" },
new QualityDefinition(Quality.HDTV720p) { Weight = 6, MinSize = 3, MaxSize = 125 }, new QualityDefinition(Quality.HDTV720p) { Weight = 6, MinSize = 3, MaxSize = 125, PreferredSize = 95 },
new QualityDefinition(Quality.HDTV1080p) { Weight = 7, MinSize = 4, MaxSize = 125 }, new QualityDefinition(Quality.HDTV1080p) { Weight = 7, MinSize = 4, MaxSize = 125, PreferredSize = 95 },
new QualityDefinition(Quality.RAWHD) { Weight = 8, MinSize = 4, MaxSize = null }, new QualityDefinition(Quality.RAWHD) { Weight = 8, MinSize = 4, MaxSize = null, PreferredSize = 95 },
new QualityDefinition(Quality.WEBRip720p) { Weight = 9, MinSize = 3, MaxSize = 130, GroupName = "WEB 720p" }, new QualityDefinition(Quality.WEBRip720p) { Weight = 9, MinSize = 3, MaxSize = 130, PreferredSize = 95, GroupName = "WEB 720p" },
new QualityDefinition(Quality.WEBDL720p) { Weight = 9, MinSize = 3, MaxSize = 130, GroupName = "WEB 720p" }, new QualityDefinition(Quality.WEBDL720p) { Weight = 9, MinSize = 3, MaxSize = 130, PreferredSize = 95, GroupName = "WEB 720p" },
new QualityDefinition(Quality.Bluray720p) { Weight = 10, MinSize = 4, MaxSize = 130 }, new QualityDefinition(Quality.Bluray720p) { Weight = 10, MinSize = 4, MaxSize = 130, PreferredSize = 95 },
new QualityDefinition(Quality.WEBRip1080p) { Weight = 11, MinSize = 4, MaxSize = 130, GroupName = "WEB 1080p" }, new QualityDefinition(Quality.WEBRip1080p) { Weight = 11, MinSize = 4, MaxSize = 130, PreferredSize = 95, GroupName = "WEB 1080p" },
new QualityDefinition(Quality.WEBDL1080p) { Weight = 11, MinSize = 4, MaxSize = 130, GroupName = "WEB 1080p" }, new QualityDefinition(Quality.WEBDL1080p) { Weight = 11, MinSize = 4, MaxSize = 130, PreferredSize = 95, GroupName = "WEB 1080p" },
new QualityDefinition(Quality.Bluray1080p) { Weight = 12, MinSize = 4, MaxSize = 155 }, new QualityDefinition(Quality.Bluray1080p) { Weight = 12, MinSize = 4, MaxSize = 155, PreferredSize = 95 },
new QualityDefinition(Quality.Bluray1080pRemux) { Weight = 13, MinSize = 35, MaxSize = null }, new QualityDefinition(Quality.Bluray1080pRemux) { Weight = 13, MinSize = 35, MaxSize = null, PreferredSize = 95 },
new QualityDefinition(Quality.HDTV2160p) { Weight = 14, MinSize = 35, MaxSize = 199.9 }, new QualityDefinition(Quality.HDTV2160p) { Weight = 14, MinSize = 35, MaxSize = 199.9, PreferredSize = 95 },
new QualityDefinition(Quality.WEBRip2160p) { Weight = 15, MinSize = 35, MaxSize = null, GroupName = "WEB 2160p" }, new QualityDefinition(Quality.WEBRip2160p) { Weight = 15, MinSize = 35, MaxSize = null, PreferredSize = 95, GroupName = "WEB 2160p" },
new QualityDefinition(Quality.WEBDL2160p) { Weight = 15, MinSize = 35, MaxSize = null, GroupName = "WEB 2160p" }, new QualityDefinition(Quality.WEBDL2160p) { Weight = 15, MinSize = 35, MaxSize = null, PreferredSize = 95, GroupName = "WEB 2160p" },
new QualityDefinition(Quality.Bluray2160p) { Weight = 16, MinSize = 35, MaxSize = null }, new QualityDefinition(Quality.Bluray2160p) { Weight = 16, MinSize = 35, MaxSize = null, PreferredSize = 95 },
new QualityDefinition(Quality.Bluray2160pRemux) { Weight = 17, MinSize = 35, MaxSize = null } new QualityDefinition(Quality.Bluray2160pRemux) { Weight = 17, MinSize = 35, MaxSize = null, PreferredSize = 95 }
}; };
} }

View File

@ -14,6 +14,7 @@ namespace NzbDrone.Core.Qualities
public double? MinSize { get; set; } public double? MinSize { get; set; }
public double? MaxSize { get; set; } public double? MaxSize { get; set; }
public double? PreferredSize { get; set; }
public QualityDefinition() public QualityDefinition()
{ {

View File

@ -15,6 +15,7 @@ namespace Sonarr.Api.V3.Qualities
public double? MinSize { get; set; } public double? MinSize { get; set; }
public double? MaxSize { get; set; } public double? MaxSize { get; set; }
public double? PreferredSize { get; set; }
} }
public static class QualityDefinitionResourceMapper public static class QualityDefinitionResourceMapper
@ -33,7 +34,8 @@ namespace Sonarr.Api.V3.Qualities
Title = model.Title, Title = model.Title,
Weight = model.Weight, Weight = model.Weight,
MinSize = model.MinSize, MinSize = model.MinSize,
MaxSize = model.MaxSize MaxSize = model.MaxSize,
PreferredSize = model.PreferredSize
}; };
} }
@ -51,7 +53,8 @@ namespace Sonarr.Api.V3.Qualities
Title = resource.Title, Title = resource.Title,
Weight = resource.Weight, Weight = resource.Weight,
MinSize = resource.MinSize, MinSize = resource.MinSize,
MaxSize = resource.MaxSize MaxSize = resource.MaxSize,
PreferredSize = resource.PreferredSize
}; };
} }