Files
pinkudex/app/actions/actressPortrait.ts
T
2026-05-26 22:46:00 +02:00

94 lines
3.7 KiB
TypeScript

"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 type { PortraitSlotKey } from "@/lib/db/queries";
import { safeJoin } from "@/lib/safePath";
const PORTRAIT_ROOT = path.join(process.cwd(), "data", "portraits");
const SLOT_COLS: Record<PortraitSlotKey, { path: string; zoom: string; ox: string; oy: string }> = {
"1": { path: "portrait_path", zoom: "portrait_zoom", ox: "portrait_offset_x", oy: "portrait_offset_y" },
"2": { path: "portrait2_path", zoom: "portrait2_zoom", ox: "portrait2_offset_x", oy: "portrait2_offset_y" },
"3": { path: "portrait3_path", zoom: "portrait3_zoom", ox: "portrait3_offset_x", oy: "portrait3_offset_y" },
"4": { path: "portrait4_path", zoom: "portrait4_zoom", ox: "portrait4_offset_x", oy: "portrait4_offset_y" },
"h": { path: "portraith_path", zoom: "portraith_zoom", ox: "portraith_offset_x", oy: "portraith_offset_y" },
};
export async function setActressPortraitTransform(
actressId: number,
slot: PortraitSlotKey,
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 actresses SET ${c.zoom} = ?, ${c.ox} = ?, ${c.oy} = ? WHERE id = ?
`).run(zoom, transform.offsetX, transform.offsetY, actressId);
const a = rawDb.prepare(`SELECT slug FROM actresses WHERE id = ?`).get(actressId) as { slug: string } | undefined;
revalidatePath("/actress");
if (a) revalidatePath(`/actress/${a.slug}`);
}
type PortraitTuple = [string | null, number, number, number];
export async function reorderActressPortraitSlots(
actressId: number,
src: PortraitSlotKey,
dest: PortraitSlotKey,
) {
if (src === dest) return;
if (src === "h" || dest === "h") return;
const order: PortraitSlotKey[] = ["1", "2", "3", "4"];
if (!order.includes(src) || !order.includes(dest)) return;
const cols = order.map((s) => SLOT_COLS[s]);
const selectFrag = cols
.map((c, i) => `${c.path} AS p${i}, ${c.zoom} AS z${i}, ${c.ox} AS x${i}, ${c.oy} AS y${i}`)
.join(", ");
const row = rawDb.prepare(`SELECT slug, ${selectFrag} FROM actresses WHERE id = ?`).get(actressId) as
| (Record<string, string | number | null> & { slug: string })
| undefined;
if (!row) return;
const current: PortraitTuple[] = order.map((_, i) => [
(row[`p${i}`] as string | null) ?? null,
Number(row[`z${i}`] ?? 1),
Number(row[`x${i}`] ?? 0),
Number(row[`y${i}`] ?? 0),
]);
const srcIdx = order.indexOf(src);
const destIdx = order.indexOf(dest);
const next = [...current];
const [moved] = next.splice(srcIdx, 1);
next.splice(destIdx, 0, moved);
const setFrag = cols.map((c) => `${c.path} = ?, ${c.zoom} = ?, ${c.ox} = ?, ${c.oy} = ?`).join(", ");
const params = next.flatMap((t) => [t[0], t[1], t[2], t[3]]);
rawDb.prepare(`UPDATE actresses SET ${setFrag} WHERE id = ?`).run(...params, actressId);
revalidatePath("/actress");
revalidatePath(`/actress/${row.slug}`);
}
export async function clearActressPortrait(actressId: number, slot: PortraitSlotKey) {
const c = SLOT_COLS[slot];
if (!c) return;
const row = rawDb.prepare(`SELECT slug, ${c.path} AS p FROM actresses WHERE id = ?`).get(actressId) as
| { slug: string; p: string | null }
| undefined;
if (!row) return;
if (row.p) {
const abs = safeJoin(PORTRAIT_ROOT, row.p);
if (abs) await fs.rm(abs, { force: true }).catch(() => {});
}
rawDb.prepare(`
UPDATE actresses SET ${c.path} = NULL, ${c.zoom} = 1, ${c.ox} = 0, ${c.oy} = 0 WHERE id = ?
`).run(actressId);
revalidatePath("/actress");
revalidatePath(`/actress/${row.slug}`);
}