@glissade/cli 0.9.0-pre.1 → 0.9.1-pre.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/dist/cli.js +2 -0
- package/dist/cues.js +15 -10
- package/dist/index.d.ts +2 -0
- package/dist/render.js +1 -1
- package/package.json +10 -10
package/dist/cli.js
CHANGED
|
@@ -61,6 +61,7 @@ render options:
|
|
|
61
61
|
--music <m> auto (default): mix a sibling *.music.timing.json bed, ducked under narration | off
|
|
62
62
|
--sfx <m> auto (default): mix effect hits from a sibling *.sfx.timing.json | off
|
|
63
63
|
--chapters <m> vtt: also write WebVTT chapters from cue markers (cues.json is always written when cues exist)
|
|
64
|
+
--chapters-kind <k[,k]> cue kinds that become VTT chapters (default: chapter); cues.json keeps all kinds
|
|
64
65
|
--strict fail on an unregistered font family or an uncovered glyph (§3.6; default: warn)
|
|
65
66
|
|
|
66
67
|
dev options:
|
|
@@ -189,6 +190,7 @@ async function main() {
|
|
|
189
190
|
...frameRange ? { frameRange } : {},
|
|
190
191
|
...formatFlag === "png-seq" ? { format: "png-seq" } : {},
|
|
191
192
|
...flags.get("chapters") === "vtt" ? { chapters: "vtt" } : {},
|
|
193
|
+
...flags.has("chapters-kind") ? { chapterKinds: new Set(flags.get("chapters-kind").split(",").map((s) => s.trim()).filter(Boolean)) } : {},
|
|
192
194
|
...flags.has("trace") ? { trace: flags.get("trace") } : {},
|
|
193
195
|
...flags.has("state") ? { state: flags.get("state") } : {},
|
|
194
196
|
...flags.has("force") ? { force: true } : {},
|
package/dist/cues.js
CHANGED
|
@@ -28,20 +28,25 @@ function vttTime(seconds) {
|
|
|
28
28
|
const p = (n, w = 2) => String(n).padStart(w, "0");
|
|
29
29
|
return `${p(Math.floor(ms / 36e5))}:${p(Math.floor(ms % 36e5 / 6e4))}:${p(Math.floor(ms % 6e4 / 1e3))}.${p(ms % 1e3, 3)}`;
|
|
30
30
|
}
|
|
31
|
+
/** The cue kinds that become WebVTT chapters by default (the YouTube use case). */
|
|
32
|
+
const DEFAULT_CHAPTER_KINDS = new Set(["chapter"]);
|
|
31
33
|
/**
|
|
32
|
-
* WebVTT chapters from cues
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
34
|
+
* WebVTT chapters from cues. Only cues whose `kind` is in `kinds` (default just
|
|
35
|
+
* `'chapter'`) become chapters — ad-break / plain `cue` markers stay out of the
|
|
36
|
+
* chapter list (they remain in `cues.json` for machines), so the VTT pastes
|
|
37
|
+
* straight into a YouTube description. Each chapter runs until its duration or
|
|
38
|
+
* the next chapter; the cue text is the human `title` (falling back to `name`),
|
|
39
|
+
* never the machine `kind`. When the earliest chapter starts after 0, a `00:00`
|
|
40
|
+
* "Intro" chapter is auto-anchored (valid WebVTT, and YouTube needs a 0:00 start).
|
|
37
41
|
*/
|
|
38
|
-
function cuesToVtt(cues, totalDuration) {
|
|
39
|
-
const
|
|
42
|
+
function cuesToVtt(cues, totalDuration, kinds = DEFAULT_CHAPTER_KINDS) {
|
|
43
|
+
const chapters = cues.filter((c) => kinds.has(c.kind));
|
|
44
|
+
const anchored = chapters.length > 0 && chapters[0].t > 0 ? [{
|
|
40
45
|
t: 0,
|
|
41
46
|
kind: "chapter",
|
|
42
47
|
name: "Intro",
|
|
43
48
|
title: "Intro"
|
|
44
|
-
}, ...
|
|
49
|
+
}, ...chapters] : chapters;
|
|
45
50
|
let out = "WEBVTT\n\n";
|
|
46
51
|
anchored.forEach((c, i) => {
|
|
47
52
|
const end = c.duration !== void 0 ? c.t + c.duration : anchored[i + 1]?.t ?? totalDuration;
|
|
@@ -54,7 +59,7 @@ function cuesToVtt(cues, totalDuration) {
|
|
|
54
59
|
* `<stem>.chapters.vtt`, next to the render output. Deterministic. Returns the
|
|
55
60
|
* paths written.
|
|
56
61
|
*/
|
|
57
|
-
function writeCueSidecars(outPath, markers, totalDuration, chaptersVtt) {
|
|
62
|
+
function writeCueSidecars(outPath, markers, totalDuration, chaptersVtt, chapterKinds = DEFAULT_CHAPTER_KINDS) {
|
|
58
63
|
const cues = collectCues(markers);
|
|
59
64
|
if (cues.length === 0) return [];
|
|
60
65
|
const isFile = /\.(mp4|webm)$/i.test(outPath);
|
|
@@ -66,7 +71,7 @@ function writeCueSidecars(outPath, markers, totalDuration, chaptersVtt) {
|
|
|
66
71
|
written.push(jsonPath);
|
|
67
72
|
if (chaptersVtt) {
|
|
68
73
|
const vttPath = join(dir, `${prefix}chapters.vtt`);
|
|
69
|
-
writeFileSync(vttPath, cuesToVtt(cues, totalDuration));
|
|
74
|
+
writeFileSync(vttPath, cuesToVtt(cues, totalDuration, chapterKinds));
|
|
70
75
|
written.push(vttPath);
|
|
71
76
|
}
|
|
72
77
|
return written;
|
package/dist/index.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ interface RenderOptions {
|
|
|
32
32
|
sfx?: 'auto' | 'off';
|
|
33
33
|
/** also write WebVTT chapters from cue markers ('vtt'); cues.json is always written when cues exist. */
|
|
34
34
|
chapters?: 'vtt' | 'off';
|
|
35
|
+
/** cue kinds that become VTT chapters (default just 'chapter'); cues.json keeps all kinds. */
|
|
36
|
+
chapterKinds?: ReadonlySet<string>;
|
|
35
37
|
/** --strict: font validation throws on an unregistered family / missing glyph (§3.6). Default dev-warn. */
|
|
36
38
|
strictFonts?: boolean;
|
|
37
39
|
onProgress?: (frame: number, total: number) => void;
|
package/dist/render.js
CHANGED
|
@@ -126,7 +126,7 @@ async function render(opts) {
|
|
|
126
126
|
process.stderr.write(`captions: ${srt}, ${vtt}\n`);
|
|
127
127
|
};
|
|
128
128
|
const emitCues = (target) => {
|
|
129
|
-
const written = writeCueSidecars(target, compiled.markers, duration, opts.chapters === "vtt");
|
|
129
|
+
const written = writeCueSidecars(target, compiled.markers, duration, opts.chapters === "vtt", opts.chapterKinds);
|
|
130
130
|
if (written.length) process.stderr.write(`cues: ${written.join(", ")}\n`);
|
|
131
131
|
};
|
|
132
132
|
if (!isVideo) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glissade/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1-pre.0",
|
|
4
4
|
"description": "glissade CLI: headless rendering via backend-skia (+ FFmpeg mux).",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -20,15 +20,15 @@
|
|
|
20
20
|
"@napi-rs/canvas": "^0.1.65",
|
|
21
21
|
"esbuild": "^0.28.0",
|
|
22
22
|
"jiti": "^2.4.2",
|
|
23
|
-
"@glissade/backend-skia": "0.9.
|
|
24
|
-
"@glissade/core": "0.9.
|
|
25
|
-
"@glissade/interact": "0.9.
|
|
26
|
-
"@glissade/lottie": "0.9.
|
|
27
|
-
"@glissade/svg": "0.9.
|
|
28
|
-
"@glissade/narrate": "0.9.
|
|
29
|
-
"@glissade/player": "0.9.
|
|
30
|
-
"@glissade/scene": "0.9.
|
|
31
|
-
"@glissade/sfx": "0.9.
|
|
23
|
+
"@glissade/backend-skia": "0.9.1-pre.0",
|
|
24
|
+
"@glissade/core": "0.9.1-pre.0",
|
|
25
|
+
"@glissade/interact": "0.9.1-pre.0",
|
|
26
|
+
"@glissade/lottie": "0.9.1-pre.0",
|
|
27
|
+
"@glissade/svg": "0.9.1-pre.0",
|
|
28
|
+
"@glissade/narrate": "0.9.1-pre.0",
|
|
29
|
+
"@glissade/player": "0.9.1-pre.0",
|
|
30
|
+
"@glissade/scene": "0.9.1-pre.0",
|
|
31
|
+
"@glissade/sfx": "0.9.1-pre.0"
|
|
32
32
|
},
|
|
33
33
|
"repository": {
|
|
34
34
|
"type": "git",
|