Initial commit

This commit is contained in:
admin
2026-05-26 22:46:00 +02:00
commit 7e2c2ff89c
256 changed files with 51523 additions and 0 deletions
+108
View File
@@ -0,0 +1,108 @@
"use server";
import { revalidatePath } from "next/cache";
import { rawDb, uniqueSlug } from "@/lib/db/client";
const EXCLUSIVE_GROUPS: string[][] = [["favorite", "vip"]];
function getExclusivePeers(categoryId: number): number[] {
const cat = rawDb.prepare(`SELECT slug FROM actress_categories WHERE id = ?`).get(categoryId) as { slug: string } | undefined;
if (!cat) return [];
const group = EXCLUSIVE_GROUPS.find((g) => g.includes(cat.slug));
if (!group) return [];
const peers = group.filter((s) => s !== cat.slug);
if (peers.length === 0) return [];
const placeholders = peers.map(() => "?").join(",");
const rows = rawDb.prepare(`SELECT id FROM actress_categories WHERE slug IN (${placeholders})`).all(...peers) as Array<{ id: number }>;
return rows.map((r) => r.id);
}
export async function toggleActressCategory(actressId: number, categoryId: number) {
const exists = rawDb.prepare(`
SELECT 1 FROM actress_categories_map WHERE actress_id = ? AND category_id = ?
`).get(actressId, categoryId);
if (exists) {
rawDb.prepare(`DELETE FROM actress_categories_map WHERE actress_id = ? AND category_id = ?`).run(actressId, categoryId);
} else {
// Adding: also remove any peer category in an exclusive group.
const peers = getExclusivePeers(categoryId);
const tx = rawDb.transaction(() => {
if (peers.length > 0) {
const placeholders = peers.map(() => "?").join(",");
rawDb.prepare(`
DELETE FROM actress_categories_map
WHERE actress_id = ? AND category_id IN (${placeholders})
`).run(actressId, ...peers);
}
rawDb.prepare(`INSERT INTO actress_categories_map (actress_id, category_id) VALUES (?, ?)`).run(actressId, categoryId);
});
tx();
}
const a = rawDb.prepare(`SELECT slug FROM actresses WHERE id = ?`).get(actressId) as { slug: string } | undefined;
revalidatePath("/actress");
if (a) revalidatePath(`/actress/${a.slug}`);
return { added: !exists };
}
export async function setActressCategories(actressId: number, categoryIds: number[]) {
const tx = rawDb.transaction(() => {
rawDb.prepare(`DELETE FROM actress_categories_map WHERE actress_id = ?`).run(actressId);
const ins = rawDb.prepare(`INSERT INTO actress_categories_map (actress_id, category_id) VALUES (?, ?)`);
for (const id of categoryIds) ins.run(actressId, id);
});
tx();
const a = rawDb.prepare(`SELECT slug FROM actresses WHERE id = ?`).get(actressId) as { slug: string } | undefined;
revalidatePath("/actress");
if (a) revalidatePath(`/actress/${a.slug}`);
}
export async function createActressCategory(input: { name: string; color?: string | null; icon?: string | null; priority?: number }) {
const trimmed = input.name.trim();
if (!trimmed) return null;
const existing = rawDb.prepare(`SELECT id, slug FROM actress_categories WHERE name = ?`).get(trimmed) as { id: number; slug: string } | undefined;
if (existing) return existing;
const slug = uniqueSlug(rawDb, "actress_categories", trimmed);
const row = rawDb.prepare(`
INSERT INTO actress_categories (name, slug, color, icon, priority, builtin)
VALUES (?, ?, ?, ?, ?, 0) RETURNING id
`).get(trimmed, slug, input.color ?? null, input.icon ?? null, input.priority ?? 50) as { id: number };
revalidatePath("/actress");
return { id: row.id, slug };
}
export async function bulkAddCategory(actressIds: number[], categoryId: number) {
if (actressIds.length === 0) return;
const peers = getExclusivePeers(categoryId);
const ins = rawDb.prepare(`INSERT OR IGNORE INTO actress_categories_map (actress_id, category_id) VALUES (?, ?)`);
const tx = rawDb.transaction(() => {
if (peers.length > 0) {
const peerPh = peers.map(() => "?").join(",");
const idPh = actressIds.map(() => "?").join(",");
rawDb.prepare(`
DELETE FROM actress_categories_map
WHERE actress_id IN (${idPh}) AND category_id IN (${peerPh})
`).run(...actressIds, ...peers);
}
for (const id of actressIds) ins.run(id, categoryId);
});
tx();
revalidatePath("/actress");
}
export async function bulkRemoveCategory(actressIds: number[], categoryId: number) {
if (actressIds.length === 0) return;
const placeholders = actressIds.map(() => "?").join(",");
rawDb.prepare(`
DELETE FROM actress_categories_map
WHERE category_id = ? AND actress_id IN (${placeholders})
`).run(categoryId, ...actressIds);
revalidatePath("/actress");
}
export async function deleteActressCategory(categoryId: number) {
const row = rawDb.prepare(`SELECT builtin FROM actress_categories WHERE id = ?`).get(categoryId) as { builtin: number } | undefined;
if (!row) return { ok: false, reason: "not found" };
if (row.builtin) return { ok: false, reason: "built-in category cannot be deleted" };
rawDb.prepare(`DELETE FROM actress_categories WHERE id = ?`).run(categoryId);
revalidatePath("/actress");
return { ok: true };
}