From b9ad772418fd041f72fd9432d89bb2adf54b083b Mon Sep 17 00:00:00 2001 From: Eduard Marbach Date: Wed, 20 Nov 2024 14:11:01 +0100 Subject: [PATCH 1/2] refactor: improve typings for client --- src/clients/radarr-client.ts | 34 +++++++----------- src/clients/readarr-client.ts | 26 ++++++++------ src/clients/sonarr-client.ts | 36 ++++++++----------- src/clients/unified-client.ts | 66 ++++++++++++++++++---------------- src/clients/whisparr-client.ts | 30 +++++----------- 5 files changed, 87 insertions(+), 105 deletions(-) diff --git a/src/clients/radarr-client.ts b/src/clients/radarr-client.ts index e0a3492..fd6d6d3 100644 --- a/src/clients/radarr-client.ts +++ b/src/clients/radarr-client.ts @@ -1,10 +1,10 @@ import { KyHttpClient } from "../__generated__/ky-client"; -import { MergedCustomFormatResource } from "../__generated__/mergedTypes"; import { Api } from "../__generated__/radarr/Api"; +import { CustomFormatResource, QualityDefinitionResource, QualityProfileResource } from "../__generated__/radarr/data-contracts"; import { logger } from "../logger"; import { IArrClient, validateClientParams } from "./unified-client"; -export class RadarrClient implements IArrClient { +export class RadarrClient implements IArrClient { private api!: Api; constructor(baseUrl: string, apiKey: string) { @@ -29,20 +29,23 @@ export class RadarrClient implements IArrClient { return this.api.v3QualitydefinitionList(); } - updateQualityDefinitions(definitions: any) { - return this.api.v3QualitydefinitionUpdateUpdate(definitions); + async updateQualityDefinitions(definitions: QualityDefinitionResource[]) { + await this.api.v3QualitydefinitionUpdateUpdate(definitions); + return this.getQualityDefinitions(); } // Quality Profiles - getQualityProfiles() { + getQualityProfiles(): Promise { return this.api.v3QualityprofileList(); } - createQualityProfile(profile: any) { + createQualityProfile(profile: QualityProfileResource): Promise { + if (profile.language) { + } return this.api.v3QualityprofileCreate(profile); } - updateQualityProfile(id: string, profile: any) { + updateQualityProfile(id: string, profile: QualityProfileResource): Promise { return this.api.v3QualityprofileUpdate(id, profile); } @@ -51,11 +54,11 @@ export class RadarrClient implements IArrClient { return this.api.v3CustomformatList(); } - createCustomFormat(format: MergedCustomFormatResource) { + createCustomFormat(format: CustomFormatResource) { return this.api.v3CustomformatCreate(format); } - updateCustomFormat(id: string, format: MergedCustomFormatResource) { + updateCustomFormat(id: string, format: CustomFormatResource) { return this.api.v3CustomformatUpdate(id, format); } @@ -63,19 +66,6 @@ export class RadarrClient implements IArrClient { return this.api.v3CustomformatDelete(+id); } - // Metadata Profiles - async getMetadataProfiles() { - throw new Error("Metadata profiles are not supported in Radarr"); - } - - async createMetadataProfile(profile: any) { - throw new Error("Metadata profiles are not supported in Radarr"); - } - - async updateMetadataProfile(id: number, profile: any) { - throw new Error("Metadata profiles are not supported in Radarr"); - } - // System/Health Check getSystemStatus() { return this.api.v3SystemStatusList(); diff --git a/src/clients/readarr-client.ts b/src/clients/readarr-client.ts index e88aa3f..dd4f062 100644 --- a/src/clients/readarr-client.ts +++ b/src/clients/readarr-client.ts @@ -1,10 +1,15 @@ import { KyHttpClient } from "../__generated__/ky-client"; -import { MergedCustomFormatResource } from "../__generated__/mergedTypes"; import { Api } from "../__generated__/readarr/Api"; +import { + CustomFormatResource, + MetadataProfileResource, + QualityDefinitionResource, + QualityProfileResource, +} from "../__generated__/readarr/data-contracts"; import { logger } from "../logger"; import { IArrClient, validateClientParams } from "./unified-client"; -export class ReadarrClient implements IArrClient { +export class ReadarrClient implements IArrClient { private api!: Api; constructor(baseUrl: string, apiKey: string) { @@ -29,8 +34,9 @@ export class ReadarrClient implements IArrClient { return this.api.v1QualitydefinitionList(); } - updateQualityDefinitions(definitions: any) { - return this.api.v1QualitydefinitionUpdateUpdate(definitions); + async updateQualityDefinitions(definitions: QualityDefinitionResource[]) { + await this.api.v1QualitydefinitionUpdateUpdate(definitions); + return this.api.v1QualitydefinitionList(); } // Quality Profiles @@ -38,11 +44,11 @@ export class ReadarrClient implements IArrClient { return this.api.v1QualityprofileList(); } - createQualityProfile(profile: any) { + createQualityProfile(profile: QualityProfileResource) { return this.api.v1QualityprofileCreate(profile); } - updateQualityProfile(id: string, profile: any) { + updateQualityProfile(id: string, profile: QualityProfileResource) { return this.api.v1QualityprofileUpdate(id, profile); } @@ -51,11 +57,11 @@ export class ReadarrClient implements IArrClient { return this.api.v1CustomformatList(); } - createCustomFormat(format: MergedCustomFormatResource) { + createCustomFormat(format: CustomFormatResource) { return this.api.v1CustomformatCreate(format); } - updateCustomFormat(id: string, format: MergedCustomFormatResource) { + updateCustomFormat(id: string, format: CustomFormatResource) { return this.api.v1CustomformatUpdate(id, format); } @@ -68,11 +74,11 @@ export class ReadarrClient implements IArrClient { return this.api.v1MetadataprofileList(); } - async createMetadataProfile(profile: any) { + async createMetadataProfile(profile: MetadataProfileResource) { return this.api.v1MetadataprofileCreate(profile); } - async updateMetadataProfile(id: number, profile: any) { + async updateMetadataProfile(id: number, profile: MetadataProfileResource) { return this.api.v1MetadataprofileUpdate(id.toString(), profile); } diff --git a/src/clients/sonarr-client.ts b/src/clients/sonarr-client.ts index b901708..f7234b8 100644 --- a/src/clients/sonarr-client.ts +++ b/src/clients/sonarr-client.ts @@ -1,10 +1,16 @@ import { KyHttpClient } from "../__generated__/ky-client"; -import { MergedCustomFormatResource } from "../__generated__/mergedTypes"; import { Api } from "../__generated__/sonarr/Api"; +import { CustomFormatResource, QualityDefinitionResource, QualityProfileResource } from "../__generated__/sonarr/data-contracts"; import { logger } from "../logger"; import { IArrClient, validateClientParams } from "./unified-client"; -export class SonarrClient implements IArrClient { +export type SonarrQualityProfileResource = { + id?: number; + name?: string; + // Add other common properties that all quality profiles share +}; + +export class SonarrClient implements IArrClient { private api!: Api; constructor(baseUrl: string, apiKey: string) { @@ -29,8 +35,9 @@ export class SonarrClient implements IArrClient { return this.api.v3QualitydefinitionList(); } - updateQualityDefinitions(definitions: any) { - return this.api.v3QualitydefinitionUpdateUpdate(definitions); + async updateQualityDefinitions(definitions: QualityDefinitionResource[]) { + this.api.v3QualitydefinitionUpdateUpdate(definitions); + return this.api.v3QualitydefinitionList(); } // Quality Profiles @@ -38,11 +45,11 @@ export class SonarrClient implements IArrClient { return this.api.v3QualityprofileList(); } - createQualityProfile(profile: any) { + createQualityProfile(profile: SonarrQualityProfileResource) { return this.api.v3QualityprofileCreate(profile); } - updateQualityProfile(id: string, profile: any) { + updateQualityProfile(id: string, profile: SonarrQualityProfileResource) { return this.api.v3QualityprofileUpdate(id, profile); } @@ -51,11 +58,11 @@ export class SonarrClient implements IArrClient { return this.api.v3CustomformatList(); } - createCustomFormat(format: MergedCustomFormatResource) { + createCustomFormat(format: CustomFormatResource) { return this.api.v3CustomformatCreate(format); } - updateCustomFormat(id: string, format: MergedCustomFormatResource) { + updateCustomFormat(id: string, format: CustomFormatResource) { return this.api.v3CustomformatUpdate(id, format); } @@ -63,19 +70,6 @@ export class SonarrClient implements IArrClient { return this.api.v3CustomformatDelete(+id); } - // Metadata Profiles - async getMetadataProfiles() { - throw new Error("Metadata profiles are not supported in Sonarr"); - } - - async createMetadataProfile(profile: any) { - throw new Error("Metadata profiles are not supported in Sonarr"); - } - - async updateMetadataProfile(id: number, profile: any) { - throw new Error("Metadata profiles are not supported in Sonarr"); - } - // System/Health Check getSystemStatus() { return this.api.v3SystemStatusList(); diff --git a/src/clients/unified-client.ts b/src/clients/unified-client.ts index 263e9ce..dd02069 100644 --- a/src/clients/unified-client.ts +++ b/src/clients/unified-client.ts @@ -1,4 +1,4 @@ -import { MergedCustomFormatResource } from "../__generated__/mergedTypes"; +import { MergedCustomFormatResource, MergedQualityDefinitionResource, MergedQualityProfileResource } from "../__generated__/mergedTypes"; import { logger } from "../logger"; import { ArrType } from "../types/common.types"; import { RadarrClient } from "./radarr-client"; @@ -70,27 +70,40 @@ export const configureApi = async (type: ArrType, baseUrl: string, apiKey: strin return unifiedClient; }; -export interface IArrClient { +export type ArrClientCustomFormat = { + id?: number; +}; + +export type ArrClientQualityDefinition = { + id?: number; +}; + +export type ArrClientQualityProfile = { + id?: number; + name?: string | null; + // Add other common properties that all quality profiles share +}; + +export interface IArrClient< + QP extends ArrClientQualityProfile = MergedQualityProfileResource, + QD extends ArrClientQualityDefinition = MergedQualityDefinitionResource, + CF extends ArrClientCustomFormat = MergedCustomFormatResource, +> { // Quality Management - getQualityDefinitions(): Promise; - updateQualityDefinitions(definitions: any): Promise; + getQualityDefinitions(): Promise; + updateQualityDefinitions(definitions: QD[]): Promise; // Quality Profiles - getQualityProfiles(): Promise; - createQualityProfile(profile: any): Promise; - updateQualityProfile(id: string, profile: any): Promise; + getQualityProfiles(): Promise; + createQualityProfile(profile: QP): Promise; + updateQualityProfile(id: string, profile: QP): Promise; // Custom Formats - getCustomFormats(): Promise; - createCustomFormat(format: MergedCustomFormatResource): Promise; - updateCustomFormat(id: string, format: MergedCustomFormatResource): Promise; + getCustomFormats(): Promise; + createCustomFormat(format: CF): Promise; + updateCustomFormat(id: string, format: CF): Promise; deleteCustomFormat(id: string): Promise; - // Metadata Profiles (Readarr-specific) - getMetadataProfiles(): Promise; - createMetadataProfile(profile: any): Promise; - updateMetadataProfile(id: number, profile: any): Promise; - // System/Health Check getSystemStatus(): Promise; testConnection(): Promise; @@ -121,15 +134,19 @@ export class UnifiedClient implements IArrClient { } } + getSpecificClient(): T { + return this.api as T; + } + async getQualityDefinitions() { return await this.api.getQualityDefinitions(); } - async updateQualityDefinitions(definitions: any) { + async updateQualityDefinitions(definitions: MergedQualityDefinitionResource[]) { return await this.api.updateQualityDefinitions(definitions); } - async createQualityProfile(profile: any) { + async createQualityProfile(profile: MergedQualityProfileResource) { return await this.api.createQualityProfile(profile); } @@ -137,23 +154,10 @@ export class UnifiedClient implements IArrClient { return await this.api.getQualityProfiles(); } - async updateQualityProfile(id: string, profile: any) { + async updateQualityProfile(id: string, profile: MergedQualityProfileResource) { return await this.api.updateQualityProfile(id, profile); } - // Readarr-specific methods - async createMetadataProfile(profile: any) { - return await this.api.createMetadataProfile(profile); - } - - async getMetadataProfiles() { - return await this.api.getMetadataProfiles(); - } - - async updateMetadataProfile(id: number, profile: any) { - return await this.api.updateMetadataProfile(id, profile); - } - async getCustomFormats() { return await this.api.getCustomFormats(); } diff --git a/src/clients/whisparr-client.ts b/src/clients/whisparr-client.ts index 4e7b90c..8e21191 100644 --- a/src/clients/whisparr-client.ts +++ b/src/clients/whisparr-client.ts @@ -1,10 +1,10 @@ import { KyHttpClient } from "../__generated__/ky-client"; -import { MergedCustomFormatResource } from "../__generated__/mergedTypes"; import { Api } from "../__generated__/whisparr/Api"; +import { CustomFormatResource, QualityDefinitionResource, QualityProfileResource } from "../__generated__/whisparr/data-contracts"; import { logger } from "../logger"; import { IArrClient, validateClientParams } from "./unified-client"; -export class WhisparrClient implements IArrClient { +export class WhisparrClient implements IArrClient { private api!: Api; constructor(baseUrl: string, apiKey: string) { @@ -29,8 +29,9 @@ export class WhisparrClient implements IArrClient { return this.api.v3QualitydefinitionList(); } - updateQualityDefinitions(definitions: any) { - return this.api.v3QualitydefinitionUpdateUpdate(definitions); + async updateQualityDefinitions(definitions: QualityDefinitionResource[]) { + await this.api.v3QualitydefinitionUpdateUpdate(definitions); + return this.api.v3QualitydefinitionList(); } // Quality Profiles @@ -38,11 +39,11 @@ export class WhisparrClient implements IArrClient { return this.api.v3QualityprofileList(); } - createQualityProfile(profile: any) { + createQualityProfile(profile: QualityProfileResource) { return this.api.v3QualityprofileCreate(profile); } - updateQualityProfile(id: string, profile: any) { + updateQualityProfile(id: string, profile: QualityProfileResource) { return this.api.v3QualityprofileUpdate(id, profile); } @@ -51,11 +52,11 @@ export class WhisparrClient implements IArrClient { return this.api.v3CustomformatList(); } - createCustomFormat(format: MergedCustomFormatResource) { + createCustomFormat(format: CustomFormatResource) { return this.api.v3CustomformatCreate(format); } - updateCustomFormat(id: string, format: MergedCustomFormatResource) { + updateCustomFormat(id: string, format: CustomFormatResource) { return this.api.v3CustomformatUpdate(id, format); } @@ -63,19 +64,6 @@ export class WhisparrClient implements IArrClient { return this.api.v3CustomformatDelete(+id); } - // Metadata Profiles - async getMetadataProfiles() { - throw new Error("Metadata profiles are not supported in Whisparr"); - } - - async createMetadataProfile(profile: any) { - throw new Error("Metadata profiles are not supported in Whisparr"); - } - - async updateMetadataProfile(id: number, profile: any) { - throw new Error("Metadata profiles are not supported in Whisparr"); - } - // System/Health Check getSystemStatus() { return this.api.v3SystemStatusList(); From ffd6faae718df8e13e520db8bf7d4525bcc31d5b Mon Sep 17 00:00:00 2001 From: Eduard Marbach Date: Wed, 20 Nov 2024 14:16:30 +0100 Subject: [PATCH 2/2] fix: set default language for new profiles to any * this only applies to products which do have languages in profiles --- src/clients/radarr-client.ts | 31 ++++++++++++++++++++----- src/clients/readarr-client.ts | 9 +++++++- src/clients/sonarr-client.ts | 13 +++++++++-- src/clients/unified-client.ts | 13 +++++++++++ src/clients/whisparr-client.ts | 41 ++++++++++++++++++++++++++++++---- 5 files changed, 95 insertions(+), 12 deletions(-) diff --git a/src/clients/radarr-client.ts b/src/clients/radarr-client.ts index fd6d6d3..e76e68f 100644 --- a/src/clients/radarr-client.ts +++ b/src/clients/radarr-client.ts @@ -1,11 +1,18 @@ import { KyHttpClient } from "../__generated__/ky-client"; import { Api } from "../__generated__/radarr/Api"; -import { CustomFormatResource, QualityDefinitionResource, QualityProfileResource } from "../__generated__/radarr/data-contracts"; +import { + CustomFormatResource, + LanguageResource, + QualityDefinitionResource, + QualityProfileResource, +} from "../__generated__/radarr/data-contracts"; import { logger } from "../logger"; +import { cloneWithJSON } from "../util"; import { IArrClient, validateClientParams } from "./unified-client"; -export class RadarrClient implements IArrClient { +export class RadarrClient implements IArrClient { private api!: Api; + private languageMap: Map = new Map(); constructor(baseUrl: string, apiKey: string) { this.initialize(baseUrl, apiKey); @@ -24,6 +31,10 @@ export class RadarrClient implements IArrClient { - if (profile.language) { + async createQualityProfile(profile: QualityProfileResource): Promise { + const cloned = cloneWithJSON(profile); + + if (this.languageMap.size <= 0) { + const languages = await this.getLanguages(); + this.languageMap = new Map(languages.map((i) => [i.name!, i])); } - return this.api.v3QualityprofileCreate(profile); + + if (profile.language == null) { + cloned.language = this.languageMap.get("Any"); + } + + return this.api.v3QualityprofileCreate(cloned); } updateQualityProfile(id: string, profile: QualityProfileResource): Promise { diff --git a/src/clients/readarr-client.ts b/src/clients/readarr-client.ts index dd4f062..63c58cd 100644 --- a/src/clients/readarr-client.ts +++ b/src/clients/readarr-client.ts @@ -2,6 +2,7 @@ import { KyHttpClient } from "../__generated__/ky-client"; import { Api } from "../__generated__/readarr/Api"; import { CustomFormatResource, + LanguageResource, MetadataProfileResource, QualityDefinitionResource, QualityProfileResource, @@ -9,7 +10,9 @@ import { import { logger } from "../logger"; import { IArrClient, validateClientParams } from "./unified-client"; -export class ReadarrClient implements IArrClient { +export class ReadarrClient + implements IArrClient +{ private api!: Api; constructor(baseUrl: string, apiKey: string) { @@ -29,6 +32,10 @@ export class ReadarrClient implements IArrClient { +export class SonarrClient implements IArrClient { private api!: Api; constructor(baseUrl: string, apiKey: string) { @@ -30,6 +35,10 @@ export class SonarrClient implements IArrClient { // Quality Management getQualityDefinitions(): Promise; @@ -104,6 +111,8 @@ export interface IArrClient< updateCustomFormat(id: string, format: CF): Promise; deleteCustomFormat(id: string): Promise; + getLanguages(): Promise; + // System/Health Check getSystemStatus(): Promise; testConnection(): Promise; @@ -138,6 +147,10 @@ export class UnifiedClient implements IArrClient { return this.api as T; } + async getLanguages() { + return this.api.getLanguages(); + } + async getQualityDefinitions() { return await this.api.getQualityDefinitions(); } diff --git a/src/clients/whisparr-client.ts b/src/clients/whisparr-client.ts index 8e21191..1e08187 100644 --- a/src/clients/whisparr-client.ts +++ b/src/clients/whisparr-client.ts @@ -1,11 +1,29 @@ import { KyHttpClient } from "../__generated__/ky-client"; import { Api } from "../__generated__/whisparr/Api"; -import { CustomFormatResource, QualityDefinitionResource, QualityProfileResource } from "../__generated__/whisparr/data-contracts"; +import { + CustomFormatResource, + LanguageResource, + QualityDefinitionResource, + QualityProfileResource, +} from "../__generated__/whisparr/data-contracts"; import { logger } from "../logger"; +import { cloneWithJSON } from "../util"; import { IArrClient, validateClientParams } from "./unified-client"; -export class WhisparrClient implements IArrClient { +/** + * Overwrite wrong types for now + */ +declare module "../__generated__/whisparr/data-contracts" { + export interface QualityProfileResource { + language?: Language; + } +} + +export class WhisparrClient + implements IArrClient +{ private api!: Api; + private languageMap: Map = new Map(); constructor(baseUrl: string, apiKey: string) { this.initialize(baseUrl, apiKey); @@ -24,6 +42,10 @@ export class WhisparrClient implements IArrClient { + const cloned = cloneWithJSON(profile); + + if (this.languageMap.size <= 0) { + const languages = await this.getLanguages(); + this.languageMap = new Map(languages.map((i) => [i.name!, i])); + } + + if (profile.language == null) { + cloned.language = this.languageMap.get("Any"); + } + + return this.api.v3QualityprofileCreate(cloned); } updateQualityProfile(id: string, profile: QualityProfileResource) {