@mieweb/pulsevault 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -1
- package/OPERATIONS.md +65 -0
- package/PROTOCOL.md +6 -0
- package/README.md +14 -9
- package/dist/app.d.ts +8 -9
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +1 -0
- package/dist/app.js.map +1 -1
- package/dist/core.d.ts +2 -0
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +1 -0
- package/dist/core.js.map +1 -1
- package/dist/lib/options.d.ts +2 -2
- package/dist/lib/options.js +2 -2
- package/dist/lib/pulsevaultTus.d.ts.map +1 -1
- package/dist/lib/pulsevaultTus.js +19 -3
- package/dist/lib/pulsevaultTus.js.map +1 -1
- package/dist/lib/web-ready.d.ts +60 -0
- package/dist/lib/web-ready.d.ts.map +1 -0
- package/dist/lib/web-ready.js +223 -0
- package/dist/lib/web-ready.js.map +1 -0
- package/dist/storage/local.d.ts +3 -1
- package/dist/storage/local.d.ts.map +1 -1
- package/dist/storage/local.js +10 -2
- package/dist/storage/local.js.map +1 -1
- package/dist/storage/s3.d.ts +2 -0
- package/dist/storage/s3.d.ts.map +1 -1
- package/dist/storage/s3.js +10 -2
- package/dist/storage/s3.js.map +1 -1
- package/dist/storage/types.d.ts +17 -0
- package/dist/storage/types.d.ts.map +1 -1
- package/package.json +12 -11
- package/scripts/web-ready-migrate.mjs +102 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Make every already-uploaded video artifact in a local-storage workspace
|
|
3
|
+
// web-playable, in place. New uploads are handled by the `onUploadComplete`
|
|
4
|
+
// web-ready hook (see examples/fastify-demo/server.mjs); this script is the
|
|
5
|
+
// one-time backfill for artifacts that landed before the hook existed.
|
|
6
|
+
//
|
|
7
|
+
// For each ready `kind: "video"` sidecar in `<workspaceDir>/.pulsevault/`:
|
|
8
|
+
// - moov atom at the end of the file → lossless faststart remux (sub-second)
|
|
9
|
+
// - non-H.264 video codec (e.g. HEVC) → one-time libx264 transcode
|
|
10
|
+
// - already web-ready / not MP4 bytes → untouched
|
|
11
|
+
//
|
|
12
|
+
// Rewrites are atomic (tmp file + rename), so interrupting the script never
|
|
13
|
+
// corrupts an artifact — rerun it and it picks up where it left off (already
|
|
14
|
+
// fixed files report `none` and are skipped for free).
|
|
15
|
+
//
|
|
16
|
+
// Usage:
|
|
17
|
+
// node scripts/web-ready-migrate.mjs <workspaceDir> [--dry-run] [--no-transcode]
|
|
18
|
+
//
|
|
19
|
+
// Requires ffmpeg + ffprobe on PATH (apt install ffmpeg / brew install ffmpeg).
|
|
20
|
+
|
|
21
|
+
import fs from "node:fs/promises";
|
|
22
|
+
import path from "node:path";
|
|
23
|
+
import process from "node:process";
|
|
24
|
+
import { ensureWebReady, scanMoovPosition } from "../dist/app.js";
|
|
25
|
+
|
|
26
|
+
const args = process.argv.slice(2);
|
|
27
|
+
const dryRun = args.includes("--dry-run");
|
|
28
|
+
const transcode = !args.includes("--no-transcode");
|
|
29
|
+
const workspaceDir = args.find((a) => !a.startsWith("--"));
|
|
30
|
+
|
|
31
|
+
if (!workspaceDir) {
|
|
32
|
+
console.error(
|
|
33
|
+
"Usage: node scripts/web-ready-migrate.mjs <workspaceDir> [--dry-run] [--no-transcode]",
|
|
34
|
+
);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const root = path.resolve(workspaceDir);
|
|
39
|
+
const sidecarDir = path.join(root, ".pulsevault");
|
|
40
|
+
|
|
41
|
+
let sidecarFiles;
|
|
42
|
+
try {
|
|
43
|
+
sidecarFiles = (await fs.readdir(sidecarDir)).filter((f) => f.endsWith(".json"));
|
|
44
|
+
} catch {
|
|
45
|
+
console.error(`No .pulsevault directory in ${root} — is this a local-storage workspace?`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const counts = { none: 0, remuxed: 0, transcoded: 0, skipped: 0, missing: 0 };
|
|
50
|
+
let processed = 0;
|
|
51
|
+
|
|
52
|
+
for (const sidecarFile of sidecarFiles) {
|
|
53
|
+
let sidecar;
|
|
54
|
+
try {
|
|
55
|
+
sidecar = JSON.parse(await fs.readFile(path.join(sidecarDir, sidecarFile), "utf8"));
|
|
56
|
+
} catch {
|
|
57
|
+
continue; // unreadable sidecar — not this script's problem
|
|
58
|
+
}
|
|
59
|
+
// Old sidecars predate `kind` and are videos by definition. Mirror the
|
|
60
|
+
// storage adapter's status semantics (src/storage/local.ts): anything that
|
|
61
|
+
// isn't explicitly "uploading" is ready — legacy sidecars predate `status`
|
|
62
|
+
// too, and those pre-hook artifacts are exactly what this script exists for.
|
|
63
|
+
const kind = sidecar.kind ?? "video";
|
|
64
|
+
const status = sidecar.status === "uploading" ? "uploading" : "ready";
|
|
65
|
+
if (kind !== "video" || status !== "ready") continue;
|
|
66
|
+
|
|
67
|
+
const artifactId = path.basename(sidecarFile, ".json");
|
|
68
|
+
const filePath = path.join(root, kind, `${artifactId}${sidecar.ext ?? ".mp4"}`);
|
|
69
|
+
processed += 1;
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
await fs.access(filePath);
|
|
73
|
+
} catch {
|
|
74
|
+
counts.missing += 1;
|
|
75
|
+
console.warn(`missing bytes ${artifactId}`);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (dryRun) {
|
|
80
|
+
// Report what WOULD happen: the moov scan is free; the codec check is
|
|
81
|
+
// ffprobe-cheap but we keep dry-run dependency-free and byte-only.
|
|
82
|
+
const moov = await scanMoovPosition(filePath);
|
|
83
|
+
console.log(`would inspect ${artifactId} (moov: ${moov})`);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const result = await ensureWebReady(filePath, { transcode, logger: console });
|
|
88
|
+
counts[result.action] += 1;
|
|
89
|
+
if (result.action !== "none") {
|
|
90
|
+
console.log(`${result.action.padEnd(11)} ${artifactId} (${result.reason})`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (dryRun) {
|
|
95
|
+
console.log(`\nDry run: inspected ${processed} ready video artifact(s); nothing was modified.`);
|
|
96
|
+
} else {
|
|
97
|
+
console.log(
|
|
98
|
+
`\nDone: ${processed} ready video artifact(s) — ` +
|
|
99
|
+
`${counts.remuxed} remuxed, ${counts.transcoded} transcoded, ` +
|
|
100
|
+
`${counts.none} already web-ready, ${counts.skipped} skipped, ${counts.missing} missing.`,
|
|
101
|
+
);
|
|
102
|
+
}
|