"use server"; import { revalidatePath } from "next/cache"; import path from "node:path"; import fs from "node:fs/promises"; import { rawDb } from "@/lib/db/client"; import { safeJoin } from "@/lib/safePath"; export type CategoryCoverSlot = "portrait" | "landscape"; const COVER_ROOT = path.join(process.cwd(), "data", "category-covers"); const SLOT_COLS: Record = { portrait: { path: "cover_portrait_path", zoom: "cover_portrait_zoom", ox: "cover_portrait_offset_x", oy: "cover_portrait_offset_y" }, landscape: { path: "cover_landscape_path", zoom: "cover_landscape_zoom", ox: "cover_landscape_offset_x", oy: "cover_landscape_offset_y" }, }; export async function setCategoryCoverTransform( categoryId: number, slot: CategoryCoverSlot, transform: { zoom: number; offsetX: number; offsetY: number }, ) { const c = SLOT_COLS[slot]; if (!c) return; const zoom = Math.max(0.5, Math.min(5, transform.zoom)); rawDb.prepare(` UPDATE tag_categories SET ${c.zoom} = ?, ${c.ox} = ?, ${c.oy} = ? WHERE id = ? `).run(zoom, transform.offsetX, transform.offsetY, categoryId); const row = rawDb.prepare(`SELECT slug FROM tag_categories WHERE id = ?`).get(categoryId) as { slug: string } | undefined; revalidatePath("/category"); if (row) revalidatePath(`/category/${row.slug}`); } export async function clearCategoryCover(categoryId: number, slot: CategoryCoverSlot) { const c = SLOT_COLS[slot]; if (!c) return; const row = rawDb.prepare(`SELECT slug, ${c.path} AS p FROM tag_categories WHERE id = ?`).get(categoryId) as | { slug: string; p: string | null } | undefined; if (!row) return; if (row.p) { const abs = safeJoin(COVER_ROOT, row.p); if (abs) await fs.rm(abs, { force: true }).catch(() => {}); } rawDb.prepare(` UPDATE tag_categories SET ${c.path} = NULL, ${c.zoom} = 1, ${c.ox} = 0, ${c.oy} = 0 WHERE id = ? `).run(categoryId); revalidatePath("/category"); revalidatePath(`/category/${row.slug}`); }