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 { try { const raw = await fs.readFile(projectPath(id), "utf-8"); return JSON.parse(raw) as Project; } catch { return null; } }