diff --git a/src/config.test.ts b/src/config.test.ts index 095bef7..e1b05e9 100644 --- a/src/config.test.ts +++ b/src/config.test.ts @@ -157,7 +157,7 @@ describe("mergeConfigsAndTemplates", () => { base_url: "http://sonarr:8989", }; - const result = await mergeConfigsAndTemplates(inputConfig, "SONARR"); + const result = await mergeConfigsAndTemplates({}, inputConfig, "SONARR"); expect(result.config.custom_formats.length).toBe(3); expect(result.config.quality_profiles.length).toBe(3); @@ -197,7 +197,7 @@ describe("mergeConfigsAndTemplates", () => { base_url: "http://sonarr:8989", }; - const result = await mergeConfigsAndTemplates(inputConfig, "SONARR"); + const result = await mergeConfigsAndTemplates({}, inputConfig, "SONARR"); expect(result.config.custom_formats.length).toBe(0); expect(result.config.quality_profiles.length).toBe(0); @@ -236,7 +236,7 @@ describe("mergeConfigsAndTemplates", () => { base_url: "http://sonarr:8989", }; - const result = await mergeConfigsAndTemplates(inputConfig, "SONARR"); + const result = await mergeConfigsAndTemplates({}, inputConfig, "SONARR"); expect(result.config.custom_formats.length).toBe(2); expect(result.config.quality_profiles.length).toBe(1); @@ -282,13 +282,13 @@ describe("mergeConfigsAndTemplates", () => { base_url: "http://sonarr:8989", }; - const result = await mergeConfigsAndTemplates(inputConfig, "SONARR"); + const result = await mergeConfigsAndTemplates({}, inputConfig, "SONARR"); expect(result.config.custom_formats.length).toBe(0); expect(result.config.quality_profiles.length).toBe(0); }); test("should throw error for invalid input configuration", async () => { - await expect(mergeConfigsAndTemplates(null as any, "SONARR")).rejects.toThrow(); + await expect(mergeConfigsAndTemplates({}, null as any, "SONARR")).rejects.toThrow(); }); }); diff --git a/src/config.ts b/src/config.ts index 6dbf2ee..d3e8bd8 100644 --- a/src/config.ts +++ b/src/config.ts @@ -171,11 +171,12 @@ export const validateConfig = (input: InputConfigInstance): MergedConfigInstance /** * Load data from trash, recyclarr, custom configs and merge. * Afterwards do sanitize and check against required configuration. - * @param value + * @param instanceConfig * @param arrType */ export const mergeConfigsAndTemplates = async ( - value: InputConfigArrInstance, + globalConfig: InputConfigSchema, + instanceConfig: InputConfigArrInstance, arrType: ArrType, ): Promise<{ config: MergedConfigInstance }> => { const localTemplateMap = loadLocalRecyclarrTemplate(arrType); @@ -198,8 +199,8 @@ export const mergeConfigsAndTemplates = async ( }; // HINT: we assume customFormatDefinitions only exist in RECYCLARR - if (value.include) { - const mappedIncludes = value.include.reduce<{ recyclarr: InputConfigIncludeItem[]; trash: InputConfigIncludeItem[] }>( + if (instanceConfig.include) { + const mappedIncludes = instanceConfig.include.reduce<{ recyclarr: InputConfigIncludeItem[]; trash: InputConfigIncludeItem[] }>( (previous, current) => { switch (current.source) { case "TRASH": @@ -218,7 +219,7 @@ export const mergeConfigsAndTemplates = async ( ); logger.info( - `Found ${value.include.length} templates to include. Mapped to [recyclarr]=${mappedIncludes.recyclarr.length}, [trash]=${mappedIncludes.trash.length} ...`, + `Found ${instanceConfig.include.length} templates to include. Mapped to [recyclarr]=${mappedIncludes.recyclarr.length}, [trash]=${mappedIncludes.trash.length} ...`, ); mappedIncludes.recyclarr.forEach((e) => { @@ -287,41 +288,55 @@ export const mergeConfigsAndTemplates = async ( } // Config values overwrite template values - if (value.custom_formats) { - mergedTemplates.custom_formats.push(...value.custom_formats); + if (instanceConfig.custom_formats) { + mergedTemplates.custom_formats.push(...instanceConfig.custom_formats); } - if (value.quality_profiles) { - mergedTemplates.quality_profiles.push(...value.quality_profiles); + if (instanceConfig.quality_profiles) { + mergedTemplates.quality_profiles.push(...instanceConfig.quality_profiles); } - if (value.media_management) { - mergedTemplates.media_management = { ...mergedTemplates.media_management, ...value.media_management }; + if (instanceConfig.media_management) { + mergedTemplates.media_management = { ...mergedTemplates.media_management, ...instanceConfig.media_management }; } - if (value.media_naming) { + if (instanceConfig.media_naming) { mergedTemplates.media_naming_api = { ...mergedTemplates.media_naming_api, - ...(await mapConfigMediaNamingToApi(arrType, value.media_naming)), + ...(await mapConfigMediaNamingToApi(arrType, instanceConfig.media_naming)), }; } - if (value.media_naming_api) { - mergedTemplates.media_naming_api = { ...mergedTemplates.media_naming_api, ...value.media_naming_api }; + if (instanceConfig.media_naming_api) { + mergedTemplates.media_naming_api = { ...mergedTemplates.media_naming_api, ...instanceConfig.media_naming_api }; } - if (value.quality_definition) { - mergedTemplates.quality_definition = { ...mergedTemplates.quality_definition, ...value.quality_definition }; + if (instanceConfig.quality_definition) { + mergedTemplates.quality_definition = { ...mergedTemplates.quality_definition, ...instanceConfig.quality_definition }; } - if (value.customFormatDefinitions) { - if (Array.isArray(value.customFormatDefinitions)) { - mergedTemplates.customFormatDefinitions = [...(mergedTemplates.customFormatDefinitions || []), ...value.customFormatDefinitions]; + if (globalConfig.customFormatDefinitions) { + if (Array.isArray(globalConfig.customFormatDefinitions)) { + mergedTemplates.customFormatDefinitions = [ + ...(mergedTemplates.customFormatDefinitions || []), + ...globalConfig.customFormatDefinitions, + ]; } else { logger.warn(`CustomFormatDefinitions in config file must be an array. Ignoring.`); } } + if (instanceConfig.customFormatDefinitions) { + if (Array.isArray(instanceConfig.customFormatDefinitions)) { + mergedTemplates.customFormatDefinitions = [ + ...(mergedTemplates.customFormatDefinitions || []), + ...instanceConfig.customFormatDefinitions, + ]; + } else { + logger.warn(`CustomFormatDefinitions in instance config file must be an array. Ignoring.`); + } + } + const recyclarrProfilesMerged = mergedTemplates.quality_profiles.reduce>((p, c) => { const profile = p.get(c.name); diff --git a/src/index.ts b/src/index.ts index 6065910..bba9b87 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,13 +15,13 @@ import { calculateQualityProfilesDiff, loadQualityProfilesFromServer } from "./q import { cloneRecyclarrTemplateRepo } from "./recyclarr-importer"; import { cloneTrashRepo, loadQualityDefinitionFromTrash } from "./trash-guide"; import { ArrType } from "./types/common.types"; -import { InputConfigArrInstance } from "./types/config.types"; +import { InputConfigArrInstance, InputConfigSchema } from "./types/config.types"; import { TrashQualityDefintion } from "./types/trashguide.types"; -const pipeline = async (value: InputConfigArrInstance, arrType: ArrType) => { +const pipeline = async (globalConfig: InputConfigSchema, instanceConfig: InputConfigArrInstance, arrType: ArrType) => { const api = getUnifiedClient(); - const { config } = await mergeConfigsAndTemplates(value, arrType); + const { config } = await mergeConfigsAndTemplates(globalConfig, instanceConfig, arrType); const idsToManage = calculateCFsToManage(config); logger.debug(Array.from(idsToManage), `CustomFormats to manage`); @@ -157,14 +157,14 @@ const run = async () => { logger.info("DryRun: Running in dry-run mode!"); } - const applicationConfig = getConfig(); + const globalConfig = getConfig(); await cloneRecyclarrTemplateRepo(); await cloneTrashRepo(); // TODO currently this has to be run sequentially because of the centrally configured api - const sonarrConfig = applicationConfig.sonarr; + const sonarrConfig = globalConfig.sonarr; if (sonarrConfig == null || Array.isArray(sonarrConfig) || typeof sonarrConfig !== "object" || Object.keys(sonarrConfig).length <= 0) { logHeading(`No Sonarr instances defined.`); @@ -174,12 +174,12 @@ const run = async () => { for (const [instanceName, instance] of Object.entries(sonarrConfig)) { logger.info(`Processing Sonarr Instance: ${instanceName}`); await configureApi("SONARR", instance.base_url, instance.api_key); - await pipeline(instance, "SONARR"); + await pipeline(globalConfig, instance, "SONARR"); unsetApi(); } } - const radarrConfig = applicationConfig.radarr; + const radarrConfig = globalConfig.radarr; if (radarrConfig == null || Array.isArray(radarrConfig) || typeof radarrConfig !== "object" || Object.keys(radarrConfig).length <= 0) { logHeading(`No Radarr instances defined.`); @@ -189,12 +189,12 @@ const run = async () => { for (const [instanceName, instance] of Object.entries(radarrConfig)) { logger.info(`Processing Radarr Instance: ${instanceName}`); await configureApi("RADARR", instance.base_url, instance.api_key); - await pipeline(instance, "RADARR"); + await pipeline(globalConfig, instance, "RADARR"); unsetApi(); } } - const whisparrConfig = applicationConfig.whisparr; + const whisparrConfig = globalConfig.whisparr; if ( whisparrConfig == null || @@ -209,12 +209,12 @@ const run = async () => { for (const [instanceName, instance] of Object.entries(whisparrConfig)) { logger.info(`Processing Whisparr Instance: ${instanceName}`); await configureApi("WHISPARR", instance.base_url, instance.api_key); - await pipeline(instance, "WHISPARR"); + await pipeline(globalConfig, instance, "WHISPARR"); unsetApi(); } } - const readarrConfig = applicationConfig.readarr; + const readarrConfig = globalConfig.readarr; if ( readarrConfig == null || @@ -229,7 +229,7 @@ const run = async () => { for (const [instanceName, instance] of Object.entries(readarrConfig)) { logger.info(`Processing Readarr Instance: ${instanceName}`); await configureApi("READARR", instance.base_url, instance.api_key); - await pipeline(instance, "READARR"); + await pipeline(globalConfig, instance, "READARR"); unsetApi(); } }