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;
  }
}