Skip to content

Commit a2494db

Browse files
committed
fix: correctly handle diffs for minFormatScores
* problem with 0/1 truthy values correctly handled
1 parent 909ec8d commit a2494db

File tree

4 files changed

+407
-16
lines changed

4 files changed

+407
-16
lines changed

src/quality-profiles.test.ts

+121-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
1+
import path from "path";
12
import { describe, expect, test } from "vitest";
2-
import { MergedQualityDefinitionResource } from "./__generated__/mergedTypes";
3-
import { doAllQualitiesExist, isOrderOfQualitiesEqual, mapQualities } from "./quality-profiles";
4-
import { ConfigQualityProfile, ConfigQualityProfileItem } from "./types/config.types";
3+
import { MergedCustomFormatResource, MergedQualityDefinitionResource, MergedQualityProfileResource } from "./__generated__/mergedTypes";
4+
import { calculateQualityProfilesDiff, doAllQualitiesExist, isOrderOfQualitiesEqual, mapQualities } from "./quality-profiles";
5+
import { CFProcessing } from "./types/common.types";
6+
import { ConfigQualityProfile, ConfigQualityProfileItem, MergedConfigInstance } from "./types/config.types";
7+
import { cloneWithJSON, loadJsonFile } from "./util";
58

69
describe("QualityProfiles", async () => {
10+
const sampleQualityProfile = loadJsonFile<MergedQualityProfileResource>(
11+
path.resolve(__dirname, `../tests/samples/single_quality_profile.json`),
12+
);
13+
14+
const sampleQualityDefinitions = loadJsonFile<MergedQualityDefinitionResource[]>(
15+
path.resolve(__dirname, `../tests/samples/qualityDefinition.json`),
16+
);
17+
18+
const sampleCustomFormat = loadJsonFile<MergedCustomFormatResource>(
19+
path.resolve(__dirname, `../tests/samples/single_custom_format.json`),
20+
);
21+
722
test("doAllQualitiesExist - all exist", async ({}) => {
823
const fromConfig: ConfigQualityProfileItem[] = [
924
{ name: "WEB 1080p", qualities: ["WEBDL-1080p", "WEBRip-1080p"] },
@@ -184,12 +199,111 @@ describe("QualityProfiles", async () => {
184199
expect(result[2]!.allowed).toBe(true);
185200
});
186201

187-
test("calculateQualityProfilesDiff - should diff if minUpgradeFormatScore is different", async ({}) => {
188-
// TODO
202+
test("calculateQualityProfilesDiff - should diff if minUpgradeFormatScore / minFormatScore is different", async ({}) => {
203+
const cfMap: CFProcessing = { carrIdMapping: new Map(), cfNameToCarrConfig: new Map() };
204+
205+
const fromConfig: ConfigQualityProfileItem[] = [{ name: "HDTV-1080p", enabled: false }];
206+
207+
const resources: MergedQualityDefinitionResource[] = [
208+
{ id: 1, title: "HDTV-1080p", weight: 2, quality: { id: 1, name: "HDTV-1080p" } },
209+
];
210+
211+
const profile: ConfigQualityProfile = {
212+
name: "hi",
213+
min_format_score: 2,
214+
qualities: fromConfig,
215+
quality_sort: "sort",
216+
upgrade: { allowed: true, until_quality: "HDTV-1080p", until_score: 1000 },
217+
score_set: "default",
218+
};
219+
220+
const config: MergedConfigInstance = {
221+
custom_formats: [],
222+
quality_profiles: [profile],
223+
customFormatDefinitions: [],
224+
media_management: {},
225+
media_naming: {},
226+
};
227+
228+
const serverProfile = cloneWithJSON(sampleQualityProfile);
229+
serverProfile.name = "hi";
230+
serverProfile.formatItems = [];
231+
serverProfile.minUpgradeFormatScore = 3;
232+
serverProfile.minFormatScore = 3;
233+
serverProfile.cutoff = 1;
234+
serverProfile.items = [{ allowed: false, items: [], quality: { id: 1, name: "HDTV-1080p" } }];
235+
236+
const serverQP: MergedQualityProfileResource[] = [serverProfile];
237+
const serverQD: MergedQualityDefinitionResource[] = resources;
238+
const serverCF: MergedCustomFormatResource[] = [cloneWithJSON(sampleCustomFormat)];
239+
240+
let diff = await calculateQualityProfilesDiff(cfMap, config, serverQP, serverQD, serverCF);
241+
expect(diff.changedQPs.length).toBe(1);
242+
expect(diff.create.length).toBe(0);
243+
expect(diff.noChanges.length).toBe(0);
244+
245+
serverProfile.minFormatScore = 0;
246+
diff = await calculateQualityProfilesDiff(cfMap, config, serverQP, serverQD, serverCF);
247+
expect(diff.changedQPs.length).toBe(1);
248+
expect(diff.create.length).toBe(0);
249+
expect(diff.noChanges.length).toBe(0);
250+
251+
serverProfile.minUpgradeFormatScore = 0;
252+
diff = await calculateQualityProfilesDiff(cfMap, config, serverQP, serverQD, serverCF);
253+
expect(diff.changedQPs.length).toBe(1);
254+
expect(diff.create.length).toBe(0);
255+
expect(diff.noChanges.length).toBe(0);
256+
257+
profile.min_format_score = 0;
258+
serverProfile.minFormatScore = 1;
259+
diff = await calculateQualityProfilesDiff(cfMap, config, serverQP, serverQD, serverCF);
260+
expect(diff.changedQPs.length).toBe(1);
261+
expect(diff.create.length).toBe(0);
262+
expect(diff.noChanges.length).toBe(0);
189263
});
190264

191-
test("calculateQualityProfilesDiff - should not diff if minUpgradeFormatScore is equal", async ({}) => {
192-
// TODO
265+
test("calculateQualityProfilesDiff - should not diff if minFormatScore is equal", async ({}) => {
266+
const cfMap: CFProcessing = { carrIdMapping: new Map(), cfNameToCarrConfig: new Map() };
267+
268+
const fromConfig: ConfigQualityProfileItem[] = [{ name: "HDTV-1080p", enabled: false }];
269+
270+
const resources: MergedQualityDefinitionResource[] = [
271+
{ id: 1, title: "HDTV-1080p", weight: 2, quality: { id: 1, name: "HDTV-1080p" } },
272+
];
273+
274+
const profile: ConfigQualityProfile = {
275+
name: "hi",
276+
min_format_score: 2,
277+
qualities: fromConfig,
278+
quality_sort: "sort",
279+
upgrade: { allowed: true, until_quality: "HDTV-1080p", until_score: 1000 },
280+
score_set: "default",
281+
};
282+
283+
const config: MergedConfigInstance = {
284+
custom_formats: [],
285+
quality_profiles: [profile],
286+
customFormatDefinitions: [],
287+
media_management: {},
288+
media_naming: {},
289+
};
290+
291+
const serverProfile = cloneWithJSON(sampleQualityProfile);
292+
serverProfile.name = "hi";
293+
serverProfile.formatItems = [];
294+
serverProfile.minUpgradeFormatScore = 3;
295+
serverProfile.minFormatScore = 2;
296+
serverProfile.cutoff = 1;
297+
serverProfile.items = [{ allowed: false, items: [], quality: { id: 1, name: "HDTV-1080p" } }];
298+
299+
const serverQP: MergedQualityProfileResource[] = [serverProfile];
300+
const serverQD: MergedQualityDefinitionResource[] = resources;
301+
const serverCF: MergedCustomFormatResource[] = [cloneWithJSON(sampleCustomFormat)];
302+
303+
const diff = await calculateQualityProfilesDiff(cfMap, config, serverQP, serverQD, serverCF);
304+
expect(diff.changedQPs.length).toBe(0);
305+
expect(diff.create.length).toBe(0);
306+
expect(diff.noChanges.length).toBe(1);
193307
});
194308

195309
test("calculateQualityProfilesDiff - should not diff if minUpgradeFormatScore is not configured", async ({}) => {

src/quality-profiles.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ export const doAllQualitiesExist = (serverResource: ConfigQualityProfileItem[],
186186
const sortedServerConfig = serverCloned.sort((a, b) => (a.name < b.name ? -1 : 1));
187187
const sortedLocalConfig = localCloned.sort((a, b) => (a.name < b.name ? -1 : 1));
188188

189-
if (sortedLocalConfig.length !== sortedServerConfig.length) {
189+
if (sortedLocalConfig.length !== sortedServerConfig.length || sortedLocalConfig.length === 0) {
190190
return false;
191191
}
192192

@@ -256,7 +256,7 @@ export const calculateQualityProfilesDiff = async (
256256
return p;
257257
}, new Map()) ?? new Map();
258258

259-
if (!serverMatch) {
259+
if (serverMatch == null) {
260260
logger.info(`QualityProfile '${name}' not found in server. Will be created.`);
261261
const mappedQ = mapQualities(serverQD, value);
262262

@@ -350,10 +350,10 @@ export const calculateQualityProfilesDiff = async (
350350

351351
// TODO do we want to enforce the whole structure or only match those which are enabled by us?
352352
if (!doAllQualitiesExist(serverQualitiesMapped, value.qualities)) {
353-
logger.info(`QualityProfile items mismatch will update whole array`);
353+
logger.info(`QualityProfile qualities mismatch will update whole array`);
354354
diffExist = true;
355355

356-
changeList.push(`QualityProfile items do not match`);
356+
changeList.push(`QualityProfile qualities mismatch will update whole array`);
357357
updatedServerObject.items = mapQualities(serverQD, value);
358358
} else {
359359
if (!isOrderOfQualitiesEqual(value.qualities, serverQualitiesMapped.toReversed())) {
@@ -378,15 +378,15 @@ export const calculateQualityProfilesDiff = async (
378378
return p;
379379
}, new Map());
380380

381-
if (value.min_format_score) {
381+
if (value.min_format_score != null) {
382382
if (serverMatch.minFormatScore !== value.min_format_score) {
383383
updatedServerObject.minFormatScore = value.min_format_score;
384384
diffExist = true;
385385
changeList.push(`MinFormatScore diff: server: ${serverMatch.minFormatScore} - expected: ${value.min_format_score}`);
386386
}
387387
}
388388

389-
if (value.upgrade) {
389+
if (value.upgrade != null) {
390390
if (serverMatch.upgradeAllowed !== value.upgrade.allowed) {
391391
updatedServerObject.upgradeAllowed = value.upgrade.allowed;
392392
diffExist = true;
@@ -396,7 +396,7 @@ export const calculateQualityProfilesDiff = async (
396396

397397
const upgradeUntil = qualityToId.get(value.upgrade.until_quality);
398398

399-
if (!upgradeUntil) {
399+
if (upgradeUntil == null) {
400400
throw new Error(`Did not find expected Quality to upgrade until: ${value.upgrade.until_quality}`);
401401
}
402402

@@ -431,7 +431,7 @@ export const calculateQualityProfilesDiff = async (
431431

432432
let scoringDiff = false;
433433

434-
if (scoringForQP) {
434+
if (scoringForQP != null) {
435435
const newCFFormats: MergedProfileFormatItemResource[] = [];
436436

437437
for (const [scoreKey, scoreValue] of scoringForQP.entries()) {
@@ -477,7 +477,7 @@ export const calculateQualityProfilesDiff = async (
477477

478478
updatedServerObject.formatItems = newCFFormats;
479479
} else {
480-
logger.info(`No scoring for QualityProfile ${serverMatch.name!} found`);
480+
logger.info(`No scoring for QualityProfile '${serverMatch.name!}' found`);
481481
}
482482

483483
logger.debug(
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"id": 1,
3+
"name": "BR-DISK",
4+
"includeCustomFormatWhenRenaming": false,
5+
"specifications": [
6+
{
7+
"name": "BR-DISK",
8+
"implementation": "ReleaseTitleSpecification",
9+
"implementationName": "Release Title",
10+
"infoLink": "https://wiki.servarr.com/sonarr/settings#custom-formats-2",
11+
"negate": false,
12+
"required": true,
13+
"fields": [
14+
{
15+
"order": 0,
16+
"name": "value",
17+
"label": "Regular Expression",
18+
"helpText": "Custom Format RegEx is Case Insensitive",
19+
"value": "^(?!.*\\b((?<!HD[._ -]|HD)DVD|BDRip|720p|MKV|XviD|WMV|d3g|(BD)?REMUX|^(?=.*1080p)(?=.*HEVC)|[xh][-_. ]?26[45]|German.*[DM]L|((?<=\\d{4}).*German.*([DM]L)?)(?=.*\\b(AVC|HEVC|VC[-_. ]?1|MVC|MPEG[-_. ]?2)\\b))\\b)(((?=.*\\b(Blu[-_. ]?ray|BD|HD[-_. ]?DVD)\\b)(?=.*\\b(AVC|HEVC|VC[-_. ]?1|MVC|MPEG[-_. ]?2|BDMV|ISO)\\b))|^((?=.*\\b(((?=.*\\b((.*_)?COMPLETE.*|Dis[ck])\\b)(?=.*(Blu[-_. ]?ray|HD[-_. ]?DVD)))|3D[-_. ]?BD|BR[-_. ]?DISK|Full[-_. ]?Blu[-_. ]?ray|^((?=.*((BD|UHD)[-_. ]?(25|50|66|100|ISO)))))))).*",
20+
"type": "textbox",
21+
"advanced": false,
22+
"privacy": "normal",
23+
"isFloat": false
24+
}
25+
]
26+
}
27+
]
28+
}

0 commit comments

Comments
 (0)