feat: täglicher Abgleich mit TMDB

Frischt laufende Serien auf, meldet neue Episoden und neu verfügbare
Watchlist-Titel, räumt Papierkorb und abgelaufene Sitzungen.

Grundsatz: Der Lauf darf nie an einem einzelnen Titel scheitern. Fehler werden
gezählt und protokolliert, der Lauf macht weiter.

Neue Episoden werden nur gemeldet, wenn sie zeitlich nicht in ferner
Vergangenheit liegen — sonst löste der erste Abgleich einer alten Serie hundert
Meldungen aus.

Der Zeitplan ist ein einfacher Timer statt einer Cron-Bibliothek: Flimmer
braucht genau einen täglichen Lauf. Wer mehr will, stösst /api/cron/sync von
aussen an.
This commit is contained in:
Florian Wilde
2026-09-01 20:24:47 +02:00
parent f49ac17922
commit 969353ab32
3 changed files with 354 additions and 0 deletions
+38
View File
@@ -0,0 +1,38 @@
import { NextResponse } from "next/server";
import { env } from "@/lib/env";
import { getSessionUser } from "@/lib/auth";
import { runSync } from "@/lib/sync";
export const dynamic = "force-dynamic";
export const maxDuration = 300;
/**
* Abgleich von außen anstoßen.
*
* curl -X POST -H "Authorization: Bearer $CRON_SECRET" \
* https://flimmer.example/api/cron/sync
*
* Zugelassen ist entweder das Cron-Geheimnis oder eine angemeldete
* Administration — Letzteres für den Knopf im Verwaltungsbereich.
*/
async function authorize(request: Request): Promise<boolean> {
const header = request.headers.get("authorization");
if (env.scheduler.cronSecret && header === `Bearer ${env.scheduler.cronSecret}`) return true;
const user = await getSessionUser();
return user?.role === "ADMIN";
}
export async function POST(request: Request) {
if (!(await authorize(request))) {
return NextResponse.json({ error: "Nicht berechtigt." }, { status: 401 });
}
const stats = await runSync();
return NextResponse.json({ ok: stats.errors.length === 0, ...stats });
}
/** GET erlaubt einfache Uptime-Cron-Dienste, die kein POST können. */
export async function GET(request: Request) {
return POST(request);
}