#!/usr/bin/env bun
/**
* Uploads a prepared video directory to R2 under `videos/<id>/<version>/`:
* bun scripts/video/upload.ts --directory .artifacts/videos/intro/v1 [--bucket gitfor] [--local]
* Media goes first and master.m3u8 last, so a half-finished upload is never playable. An existing version is
* refused: published versions are immutable (the edge caches them forever), so re-encode as a new version.
*/
import { readFile, readdir, stat } from "node:fs/promises";
import { join, resolve } from "node:path";
import { parseArgs } from "node:util";
import { contentTypeForAsset, parseVideoPath, videoR2Key } from "../../src/lib/video";
const CONCURRENCY = 6;
const ATTEMPTS = 3;
async function wrangler(args: string[]): Promise<number> {
const proc = Bun.spawn(["bunx", "wrangler", ...args], { stdout: "ignore", stderr: "pipe" });
const code = await proc.exited;
if (code !== 0 && !args.includes("--pipe")) console.error(await new Response(proc.stderr).text());
return code;
}
function uploadOrder(asset: string): number {
if (asset === "master.m3u8") return 3;
if (asset.endsWith(".m3u8")) return 2;
if (asset.endsWith(".json")) return 1;
return 0;
}
const { values } = parseArgs({
options: { directory: { type: "string" }, bucket: { type: "string", default: "gitfor" }, local: { type: "boolean" } },
});
if (!values.directory) {
console.error("upload --directory <prepared dir> [--bucket gitfor] [--local]");
process.exit(1);
}
const dir = resolve(values.directory);
const { id, version } = JSON.parse(await readFile(join(dir, "prepared.json"), "utf8")) as {
id: string;
version: string;