Files
pinkudex/lib/video/manualSubtitles.ts
2026-05-26 22:46:00 +02:00

59 lines
1.9 KiB
TypeScript

import "server-only";
import path from "node:path";
import { rawDb } from "@/lib/db/client";
export interface ManualSubtitle {
code: string;
partIdx: number;
absPath: string;
attachedAt: number;
}
interface ManualSubtitleRow {
code: string;
part_idx: number;
abs_path: string;
attached_at: number;
}
function rowToEntry(r: ManualSubtitleRow): ManualSubtitle {
return { code: r.code, partIdx: r.part_idx, absPath: r.abs_path, attachedAt: r.attached_at };
}
export function listManualSubtitlesForVariant(code: string, partIdx: number): ManualSubtitle[] {
const rows = rawDb.prepare(`
SELECT code, part_idx, abs_path, attached_at FROM manual_subtitles
WHERE code = ? AND part_idx = ?
ORDER BY attached_at DESC
`).all(code, partIdx) as ManualSubtitleRow[];
return rows.map(rowToEntry);
}
/** True iff this exact abs path is recorded against any (code, part). */
export function isManualSubtitlePath(abs: string): boolean {
const resolved = path.resolve(abs);
// Windows paths are case-insensitive on disk but stored as-typed.
// Compare with a case-insensitive LIKE on Windows, exact on POSIX.
if (process.platform === "win32") {
const row = rawDb.prepare(`
SELECT 1 FROM manual_subtitles WHERE LOWER(abs_path) = LOWER(?) LIMIT 1
`).get(resolved);
return !!row;
}
const row = rawDb.prepare(`SELECT 1 FROM manual_subtitles WHERE abs_path = ? LIMIT 1`).get(resolved);
return !!row;
}
export function attachManualSubtitle(code: string, partIdx: number, absPath: string): void {
rawDb.prepare(`
INSERT OR REPLACE INTO manual_subtitles (code, part_idx, abs_path, attached_at)
VALUES (?, ?, ?, ?)
`).run(code, partIdx, path.resolve(absPath), Date.now());
}
export function detachManualSubtitle(code: string, partIdx: number, absPath: string): void {
rawDb.prepare(`
DELETE FROM manual_subtitles WHERE code = ? AND part_idx = ? AND abs_path = ?
`).run(code, partIdx, path.resolve(absPath));
}