Files
netfelix-audio-fix/server/services/sonarr.ts
Felix Förtsch 874f04b7a5 wire scheduler into queue, add retry, dev-reset cleanup, biome 2.4 migrate
- execute: actually call isInScheduleWindow/waitForWindow/sleepBetweenJobs in runSequential (they were dead code); emit queue_status SSE events (running/paused/sleeping/idle) so the pipeline's existing QueueStatus listener lights up
- review: POST /:id/retry resets an errored plan to approved, wipes old done/error jobs, rebuilds command from current decisions, queues fresh job
- scan: dev-mode DELETE now also wipes jobs + subtitle_files (previously orphaned after every dev reset)
- biome: migrate config to 2.4 schema, autoformat 68 files (strings + indentation), relax opinionated a11y/hooks-deps/index-key rules that don't fit this codebase
- routeTree.gen.ts regenerated after /nodes removal
2026-04-13 07:41:19 +02:00

83 lines
1.9 KiB
TypeScript

import { normalizeLanguage } from "./jellyfin";
export interface SonarrConfig {
url: string;
apiKey: string;
}
function headers(apiKey: string): Record<string, string> {
return { "X-Api-Key": apiKey };
}
export async function testConnection(cfg: SonarrConfig): Promise<{ ok: boolean; error?: string }> {
try {
const res = await fetch(`${cfg.url}/api/v3/system/status`, {
headers: headers(cfg.apiKey),
});
if (!res.ok) return { ok: false, error: `HTTP ${res.status}` };
return { ok: true };
} catch (e) {
return { ok: false, error: String(e) };
}
}
interface SonarrSeries {
tvdbId?: number;
originalLanguage?: { name: string };
}
/** Returns ISO 639-2 original language for a series or null. */
export async function getOriginalLanguage(cfg: SonarrConfig, tvdbId: string): Promise<string | null> {
try {
const res = await fetch(`${cfg.url}/api/v3/series?tvdbId=${tvdbId}`, {
headers: headers(cfg.apiKey),
});
if (!res.ok) return null;
const list = (await res.json()) as SonarrSeries[];
const series = list[0];
if (!series?.originalLanguage) return null;
return languageNameToCode(series.originalLanguage.name) ?? null;
} catch {
return null;
}
}
const NAME_TO_639_2: Record<string, string> = {
english: "eng",
french: "fra",
german: "deu",
spanish: "spa",
italian: "ita",
portuguese: "por",
japanese: "jpn",
korean: "kor",
chinese: "zho",
arabic: "ara",
russian: "rus",
dutch: "nld",
swedish: "swe",
norwegian: "nor",
danish: "dan",
finnish: "fin",
polish: "pol",
turkish: "tur",
thai: "tha",
hindi: "hin",
hungarian: "hun",
czech: "ces",
romanian: "ron",
greek: "ell",
hebrew: "heb",
persian: "fas",
ukrainian: "ukr",
indonesian: "ind",
malay: "msa",
vietnamese: "vie",
};
function languageNameToCode(name: string): string | null {
const key = name.toLowerCase().trim();
return NAME_TO_639_2[key] ?? normalizeLanguage(key.slice(0, 3)) ?? null;
}