File size: 1,793 Bytes
ef4c36f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | import fs from "fs/promises";
import path from "path";
import type { Project } from "@/types";
export const STORAGE_ROOT = path.join(process.cwd(), "storage");
export const UPLOADS_DIR = path.join(STORAGE_ROOT, "uploads");
export const EXPORTS_DIR = path.join(STORAGE_ROOT, "exports");
export const RENDERS_DIR = path.join(STORAGE_ROOT, "renders");
export const PROJECTS_DIR = path.join(STORAGE_ROOT, "projects");
export async function ensureStorageDirs() {
await Promise.all([
fs.mkdir(UPLOADS_DIR, { recursive: true }),
fs.mkdir(EXPORTS_DIR, { recursive: true }),
fs.mkdir(RENDERS_DIR, { recursive: true }),
fs.mkdir(PROJECTS_DIR, { recursive: true }),
]);
}
export function projectPath(id: string) {
return path.join(PROJECTS_DIR, `${id}.json`);
}
export function uploadDir(id: string) {
return path.join(UPLOADS_DIR, id);
}
export function videoPath(id: string) {
return path.join(uploadDir(id), "video.mp4");
}
export function audioPath(id: string) {
return path.join(uploadDir(id), "voiceover.mp3");
}
export function renderDir(id: string) {
return path.join(RENDERS_DIR, id);
}
export function exportPath(id: string) {
return path.join(EXPORTS_DIR, `${id}_captioned.mp4`);
}
export async function saveProject(project: Project) {
await ensureStorageDirs();
// ponytail: write-then-rename so a concurrent autosave can't leave torn JSON behind
const target = projectPath(project.id);
const tmp = `${target}.${process.pid}.tmp`;
await fs.writeFile(tmp, JSON.stringify(project, null, 2));
await fs.rename(tmp, target);
}
export async function loadProject(id: string): Promise<Project | null> {
try {
const raw = await fs.readFile(projectPath(id), "utf-8");
return JSON.parse(raw) as Project;
} catch {
return null;
}
}
|