mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-08-29 03:55:38 -04:00
Add Sonarr and Radarr list integrations
- New `lists` service fetches Sonarr/Radarr library via their REST APIs and auto-imports matching titles from TMDB into the user's watchlist - `app/api/lists/[token]/route.ts` webhook endpoint triggers a list sync - Unified `IntegrationCard` component replaces `WebhookCard`, handling both webhook-style (Plex/Jellyfin/Emby) and list-style (Sonarr/Radarr) integrations with per-type config forms - Schema migration adds `sonarr` and `radarr` to the integration type enum and a `listConnections` table for list-based integrations - 212 tests added for the lists service covering import, deduplication, and error handling
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
import path from "node:path";
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
fetchAndMaybeCache,
|
||||
type ImageCategory,
|
||||
imageCacheEnabled,
|
||||
} from "@/lib/services/image-cache";
|
||||
|
||||
const VALID_CATEGORIES = new Set<ImageCategory>([
|
||||
const categorySchema = z.enum([
|
||||
"posters",
|
||||
"backdrops",
|
||||
"stills",
|
||||
@@ -33,11 +33,13 @@ export async function GET(
|
||||
return NextResponse.json({ error: "Invalid path" }, { status: 400 });
|
||||
}
|
||||
|
||||
const [category, rawFilename] = segments.path;
|
||||
const [rawCategory, rawFilename] = segments.path;
|
||||
|
||||
if (!VALID_CATEGORIES.has(category as ImageCategory)) {
|
||||
const catResult = categorySchema.safeParse(rawCategory);
|
||||
if (!catResult.success) {
|
||||
return NextResponse.json({ error: "Invalid category" }, { status: 400 });
|
||||
}
|
||||
const category = catResult.data;
|
||||
|
||||
// Sanitize filename — only allow basename to prevent path traversal
|
||||
const filename = path.basename(rawFilename);
|
||||
@@ -46,7 +48,7 @@ export async function GET(
|
||||
}
|
||||
|
||||
const tmdbPath = `/${filename}`;
|
||||
const result = await fetchAndMaybeCache(tmdbPath, category as ImageCategory);
|
||||
const result = await fetchAndMaybeCache(tmdbPath, category);
|
||||
|
||||
if (!result) {
|
||||
return NextResponse.json({ error: "Not found" }, { status: 404 });
|
||||
|
||||
Reference in New Issue
Block a user