From b6333db1a14a4ac68da3c74e43ac9a1a2a15179f Mon Sep 17 00:00:00 2001 From: Eduard Marbach Date: Mon, 4 Nov 2024 11:45:41 +0100 Subject: [PATCH 1/2] feat: implement preferredRatio --- src/index.ts | 2 +- src/quality-definitions.test.ts | 118 +++++++++++++------------------- src/quality-definitions.ts | 37 +++++++++- src/types/config.types.ts | 1 + 4 files changed, 83 insertions(+), 75 deletions(-) diff --git a/src/index.ts b/src/index.ts index 25b4d46..387d03a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -225,7 +225,7 @@ const pipeline = async (value: InputConfigArrInstance, arrType: ArrType) => { throw new Error(`Unsupported quality defintion ${qualityDefinition}`); } - const { changeMap, create, restData } = calculateQualityDefinitionDiff(serverQD, qdTrash); + const { changeMap, create, restData } = calculateQualityDefinitionDiff(serverQD, qdTrash, config.quality_definition?.preferred_ratio); if (changeMap.size > 0) { if (IS_DRY_RUN) { diff --git a/src/quality-definitions.test.ts b/src/quality-definitions.test.ts index 3fbb36a..d613174 100644 --- a/src/quality-definitions.test.ts +++ b/src/quality-definitions.test.ts @@ -1,78 +1,8 @@ import { describe, expect, test } from "vitest"; import { MergedQualityDefinitionResource } from "./__generated__/mergedTypes"; -import { calculateQualityDefinitionDiff } from "./quality-definitions"; +import { calculateQualityDefinitionDiff, interpolateSize } from "./quality-definitions"; import { TrashQualityDefintion } from "./types/trashguide.types"; -const exampleCFImplementations = { - name: "TestSpec", - includeCustomFormatWhenRenaming: false, - specifications: [ - { - name: "ReleaseTitleSpec", - implementation: "ReleaseTitleSpecification", - negate: false, - required: false, - fields: { - value: "expres", - }, - }, - { - name: "LanguageUnknown", - implementation: "LanguageSpecification", - negate: false, - required: false, - fields: { - value: 0, - }, - }, - { - name: "LanguageOrgi", - implementation: "LanguageSpecification", - negate: false, - required: false, - fields: { - value: -2, - }, - }, - { - name: "IndexerFlag", - implementation: "IndexerFlagSpecification", - negate: false, - required: false, - fields: { - value: 1, - }, - }, - { - name: "SourceSpec", - implementation: "SourceSpecification", - negate: false, - required: false, - fields: { - value: 6, - }, - }, - { - name: "Resolution", - implementation: "ResolutionSpecification", - negate: false, - required: false, - fields: { - value: 540, - }, - }, - { - name: "ReleaseGroup", - implementation: "ReleaseGroupSpecification", - negate: false, - required: false, - fields: { - value: "regex", - }, - }, - ], -}; - describe("QualityDefinitions", async () => { const server: MergedQualityDefinitionResource[] = [ { @@ -164,4 +94,50 @@ describe("QualityDefinitions", async () => { expect(result.changeMap.size).toBe(0); expect(result.create).toHaveLength(1); }); + + test("calculateQualityDefinitionDiff - diff preferred size with ratio", async ({}) => { + const clone: TrashQualityDefintion = JSON.parse(JSON.stringify(client)); + + const result = calculateQualityDefinitionDiff(server, clone, 0.5); + expect(result.changeMap.size).toBe(0); + expect(result.create).toHaveLength(0); + + const resultLow = calculateQualityDefinitionDiff(server, clone, 0.0); + console.log(resultLow); + expect(resultLow.changeMap.size).toBe(1); + expect(resultLow.create).toHaveLength(0); + + const resultHigh = calculateQualityDefinitionDiff(server, clone, 1.0); + console.log(resultHigh); + expect(resultHigh.changeMap.size).toBe(1); + expect(resultHigh.create).toHaveLength(0); + }); + + test("calculateQualityDefinitionDiff - diff preferred size with ratio, ignore if out of range", async ({}) => { + const clone: TrashQualityDefintion = JSON.parse(JSON.stringify(client)); + + const result = calculateQualityDefinitionDiff(server, clone, -0.5); + expect(result.changeMap.size).toBe(0); + expect(result.create).toHaveLength(0); + + const resultLow = calculateQualityDefinitionDiff(server, clone, 1.5); + expect(resultLow.changeMap.size).toBe(0); + expect(resultLow.create).toHaveLength(0); + }); + + test("interpolateSize - expected values", async ({}) => { + expect(interpolateSize(0, 100, 50, 0.5)).toBe(50); + expect(interpolateSize(0, 100, 50, 0.0)).toBe(0); + expect(interpolateSize(0, 100, 50, 1.0)).toBe(100); + expect(interpolateSize(0, 100, 50, 0.25)).toBe(25); + + expect(interpolateSize(2, 100, 95, 0.5)).toBe(95); + expect(interpolateSize(2, 100, 95, 0.0)).toBe(2); + expect(interpolateSize(2, 100, 95, 1.0)).toBe(100); + }); + + test("interpolateSize - should fail", async ({}) => { + expect(() => interpolateSize(0, 100, 50, -0.5)).toThrowError(); + expect(() => interpolateSize(0, 100, 50, 1.1)).toThrowError(); + }); }); diff --git a/src/quality-definitions.ts b/src/quality-definitions.ts index 71ac641..650cbce 100644 --- a/src/quality-definitions.ts +++ b/src/quality-definitions.ts @@ -1,6 +1,7 @@ import path from "node:path"; import { MergedQualityDefinitionResource } from "./__generated__/mergedTypes"; import { getArrApi } from "./api"; +import { logger } from "./logger"; import { TrashQualityDefintion, TrashQualityDefintionQuality } from "./types/trashguide.types"; import { IS_LOCAL_SAMPLE_MODE, loadJsonFile } from "./util"; @@ -11,7 +12,11 @@ export const loadQualityDefinitionFromServer = async (): Promise { +export const calculateQualityDefinitionDiff = ( + serverQDs: MergedQualityDefinitionResource[], + trashQD: TrashQualityDefintion, + preferedRatio?: number, +) => { const serverMap = serverQDs.reduce((p, c) => { p.set(c.title!, c); return p; @@ -34,8 +39,21 @@ export const calculateQualityDefinitionDiff = (serverQDs: MergedQualityDefinitio if (element.maxSize !== tq.max) { changes.push(`MaxSize diff: Server ${element.maxSize} - Config ${tq.max}`); } - if (element.preferredSize !== tq.preferred) { - changes.push(`PreferredSize diff: Server ${element.preferredSize} - Config ${tq.preferred}`); + + let preferred = tq.preferred; + + if (preferedRatio != null) { + if (preferedRatio < 0 || preferedRatio > 1) { + logger.warn(`QualityDefinition: PreferredRatio must be between 0 and 1. Ignoring`); + } else { + preferred = interpolateSize(tq.min, tq.max, tq.preferred, preferedRatio); + console.log(tq, preferred, preferedRatio); + logger.debug(`QualityDefinition adjusting preferred by ratio ${preferedRatio}`); + } + } + + if (element.preferredSize !== preferred) { + changes.push(`PreferredSize diff: Server ${element.preferredSize} - Config ${preferred}`); } if (changes.length > 0) { @@ -57,3 +75,16 @@ export const calculateQualityDefinitionDiff = (serverQDs: MergedQualityDefinitio return { changeMap, restData, create }; }; + +export function interpolateSize(min: number, max: number, pref: number, ratio: number): number { + if (ratio < 0 || ratio > 1) { + throw new Error(`Unexpected ratio range. Should be between 0 <= ratio <= 1`); + } + if (ratio <= 0.5) { + // Interpolate between min and pref + return min + (pref - min) * (ratio / 0.5); + } else { + // Interpolate between pref and max + return pref + (max - pref) * ((ratio - 0.5) / 0.5); + } +} diff --git a/src/types/config.types.ts b/src/types/config.types.ts index 946044b..1b3f9df 100644 --- a/src/types/config.types.ts +++ b/src/types/config.types.ts @@ -27,6 +27,7 @@ export type InputConfigArrInstance = { api_key: string; quality_definition?: { type: string; + preferred_ratio?: number; // 0.0 - 1.0 }; include?: InputConfigIncludeItem[]; custom_formats?: InputConfigCustomFormat[]; From 795ecbd2baf9dfbd0a448763b74e838d01c8c904 Mon Sep 17 00:00:00 2001 From: Eduard Marbach Date: Mon, 4 Nov 2024 11:45:54 +0100 Subject: [PATCH 2/2] refactor: adjust some logging --- src/quality-profiles.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/quality-profiles.ts b/src/quality-profiles.ts index 11f118f..4552a14 100644 --- a/src/quality-profiles.ts +++ b/src/quality-profiles.ts @@ -479,7 +479,9 @@ export const calculateQualityProfilesDiff = async ( logger.info(`No scoring for QualityProfile ${serverMatch.name!} found`); } - logger.debug(`QualityProfile (${value.name}) - CF Changes: ${scoringDiff}, Some other diff: ${diffExist}`); + logger.debug( + `QualityProfile (${value.name}) - In Sync: ${changeList.length <= 0}, CF Changes: ${scoringDiff}, Some other diff: ${diffExist}`, + ); if (scoringDiff || diffExist) { changedQPs.push(updatedServerObject); @@ -488,10 +490,7 @@ export const calculateQualityProfilesDiff = async ( } if (changeList.length > 0) { - logger.debug(`QualityProfile (${value.name}) is not in sync. Will be updated.`); logger.debug(changeList, `ChangeList for QualityProfile`); - } else { - logger.debug(`QualityProfile (${value.name}) is in sync.`); } }