video-editing 2.0.0 → 3.1.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/README.md +36 -31
- package/dist/{chunk-SSXAUKGV.js → chunk-2OM7WV4W.js} +755 -801
- package/dist/cli.js +332 -131
- package/dist/index.d.ts +185 -138
- package/dist/index.js +43 -29
- package/package.json +2 -2
- package/skills/video-editing/SKILL.md +108 -74
- package/skills/video-editing/references/audio-joins.md +94 -0
- package/skills/video-editing/references/cli-reference.md +122 -72
package/dist/index.js
CHANGED
|
@@ -4,51 +4,55 @@ import {
|
|
|
4
4
|
CAPTION_STYLE_DEFAULTS,
|
|
5
5
|
CloudClient,
|
|
6
6
|
CloudHttpError,
|
|
7
|
-
DEFAULT_DESILENCE,
|
|
8
7
|
DEFAULT_DOWNLOAD_TIMEOUT_MS,
|
|
9
8
|
DEFAULT_TIMEOUT_MS,
|
|
10
9
|
INLINE_MAX_BYTES,
|
|
11
10
|
MAX_POLL_MS,
|
|
12
11
|
MAX_RUN_POLL_MS,
|
|
12
|
+
MULTIPART_THRESHOLD_BYTES,
|
|
13
|
+
RELAY_DIRECT_ATTEMPTS,
|
|
14
|
+
RELAY_SUBCHUNK_BYTES,
|
|
13
15
|
REVIEW_STAGES2,
|
|
14
16
|
assertRunCompleted,
|
|
15
17
|
assetContentType2,
|
|
16
18
|
assetsUrl,
|
|
17
|
-
buildMediaEntry,
|
|
18
19
|
bundledSkillDir,
|
|
20
|
+
bytesSource,
|
|
19
21
|
checkCapabilities,
|
|
20
22
|
collectPlanAssetRefs2,
|
|
21
23
|
compileRemote,
|
|
22
24
|
compileUrl,
|
|
23
|
-
composeCloud,
|
|
24
25
|
composeUrl,
|
|
25
26
|
defaultRenderOut,
|
|
26
27
|
defaultSkillTarget,
|
|
27
|
-
detectSilences,
|
|
28
|
-
detectSilencesForDoc,
|
|
29
28
|
diagnosticsPath2,
|
|
30
29
|
downloadTo,
|
|
31
30
|
emptyDiagnostics,
|
|
32
|
-
extractGuardedWav,
|
|
33
31
|
filesUrl,
|
|
34
|
-
findLocalTranscript,
|
|
35
32
|
formatRunEvent,
|
|
33
|
+
framesPngPath,
|
|
34
|
+
ingestArtifactSet,
|
|
35
|
+
ingestUrl,
|
|
36
36
|
initCloudJob,
|
|
37
37
|
installSkill,
|
|
38
38
|
instructionPath2,
|
|
39
39
|
isTerminalRunStatus,
|
|
40
40
|
isTerminalStatus,
|
|
41
41
|
jobJsonPath,
|
|
42
|
+
joinSourceWindows,
|
|
42
43
|
loadPublicConfigEnv,
|
|
43
44
|
loadTimeline2,
|
|
44
45
|
meUrl,
|
|
46
|
+
multipartRelayUrl,
|
|
47
|
+
multipartUrl,
|
|
48
|
+
openFileSource,
|
|
49
|
+
outWindowToSourceWindows,
|
|
45
50
|
parseFileContent,
|
|
46
51
|
parseFileList,
|
|
47
52
|
parseFilePresign,
|
|
48
53
|
parseRenderCreate,
|
|
49
54
|
parseRenderState,
|
|
50
55
|
parseRunState,
|
|
51
|
-
parseSilenceDetect,
|
|
52
56
|
parseTimeline,
|
|
53
57
|
planPath2,
|
|
54
58
|
pollRender,
|
|
@@ -63,13 +67,11 @@ import {
|
|
|
63
67
|
pushFiles,
|
|
64
68
|
pushStage2,
|
|
65
69
|
pushTimeline2,
|
|
66
|
-
|
|
67
|
-
qaFramesLocal,
|
|
68
|
-
qaWaveformArgs,
|
|
69
|
-
qaWaveformLocal,
|
|
70
|
-
qaWordsForWindow,
|
|
70
|
+
qaDir,
|
|
71
71
|
readJobFile,
|
|
72
72
|
readOutcomesFile2,
|
|
73
|
+
readPlanSegments,
|
|
74
|
+
readProbeDuration,
|
|
73
75
|
renderUrl,
|
|
74
76
|
rendersUrl,
|
|
75
77
|
resolveApiBase,
|
|
@@ -83,9 +85,10 @@ import {
|
|
|
83
85
|
roundJsonPath2,
|
|
84
86
|
runUrl,
|
|
85
87
|
sameSha,
|
|
88
|
+
sanitizeStem,
|
|
86
89
|
savePublicConfigKey,
|
|
87
90
|
sha256Hex,
|
|
88
|
-
|
|
91
|
+
shouldMultipart,
|
|
89
92
|
statAssetsForDoc,
|
|
90
93
|
stripTrailingSlash,
|
|
91
94
|
syncAssets2,
|
|
@@ -95,7 +98,9 @@ import {
|
|
|
95
98
|
transcribeArtifactSet,
|
|
96
99
|
transcribeCloud,
|
|
97
100
|
transcribeUrl,
|
|
101
|
+
uploadMultipart,
|
|
98
102
|
uploadVfsBytes,
|
|
103
|
+
uploadVfsPayload,
|
|
99
104
|
usesFromDoc,
|
|
100
105
|
validateLocal,
|
|
101
106
|
validateTimeline,
|
|
@@ -104,8 +109,10 @@ import {
|
|
|
104
109
|
vfsContentType,
|
|
105
110
|
vfsLocalPath,
|
|
106
111
|
videoIdFromJob,
|
|
112
|
+
waveformPngPath,
|
|
113
|
+
waveformWordsPath,
|
|
107
114
|
writeJobFile
|
|
108
|
-
} from "./chunk-
|
|
115
|
+
} from "./chunk-2OM7WV4W.js";
|
|
109
116
|
|
|
110
117
|
// src/timeline-v2/anchors.ts
|
|
111
118
|
function normalizeToken(text) {
|
|
@@ -227,55 +234,59 @@ export {
|
|
|
227
234
|
CAPTION_STYLE_DEFAULTS,
|
|
228
235
|
CloudClient,
|
|
229
236
|
CloudHttpError,
|
|
230
|
-
DEFAULT_DESILENCE,
|
|
231
237
|
DEFAULT_DOWNLOAD_TIMEOUT_MS,
|
|
232
238
|
DEFAULT_TIMEOUT_MS,
|
|
233
239
|
INLINE_MAX_BYTES,
|
|
234
240
|
MAX_POLL_MS,
|
|
235
241
|
MAX_RUN_POLL_MS,
|
|
242
|
+
MULTIPART_THRESHOLD_BYTES,
|
|
243
|
+
RELAY_DIRECT_ATTEMPTS,
|
|
244
|
+
RELAY_SUBCHUNK_BYTES,
|
|
236
245
|
REVIEW_STAGES2,
|
|
237
246
|
assertRunCompleted,
|
|
238
247
|
assetContentType2,
|
|
239
248
|
assetsUrl,
|
|
240
|
-
buildMediaEntry,
|
|
241
249
|
bundledSkillDir,
|
|
250
|
+
bytesSource,
|
|
242
251
|
checkCapabilities,
|
|
243
252
|
collectPlanAssetRefs2,
|
|
244
253
|
compileRemote,
|
|
245
254
|
compileUrl,
|
|
246
|
-
composeCloud,
|
|
247
255
|
composeUrl,
|
|
248
256
|
defaultRenderOut,
|
|
249
257
|
defaultSkillTarget,
|
|
250
|
-
detectSilences,
|
|
251
|
-
detectSilencesForDoc,
|
|
252
258
|
diagnosticsPath2,
|
|
253
259
|
downloadTo,
|
|
254
260
|
emptyDiagnostics,
|
|
255
|
-
extractGuardedWav,
|
|
256
261
|
filesUrl,
|
|
257
|
-
findLocalTranscript,
|
|
258
262
|
findPhrase,
|
|
259
263
|
formatRunEvent,
|
|
264
|
+
framesPngPath,
|
|
260
265
|
fuzzySuggestions,
|
|
266
|
+
ingestArtifactSet,
|
|
267
|
+
ingestUrl,
|
|
261
268
|
initCloudJob,
|
|
262
269
|
installSkill,
|
|
263
270
|
instructionPath2,
|
|
264
271
|
isTerminalRunStatus,
|
|
265
272
|
isTerminalStatus,
|
|
266
273
|
jobJsonPath,
|
|
274
|
+
joinSourceWindows,
|
|
267
275
|
loadPublicConfigEnv,
|
|
268
276
|
loadTimeline2,
|
|
269
277
|
meUrl,
|
|
278
|
+
multipartRelayUrl,
|
|
279
|
+
multipartUrl,
|
|
270
280
|
normalizePhrase,
|
|
271
281
|
normalizeToken,
|
|
282
|
+
openFileSource,
|
|
283
|
+
outWindowToSourceWindows,
|
|
272
284
|
parseFileContent,
|
|
273
285
|
parseFileList,
|
|
274
286
|
parseFilePresign,
|
|
275
287
|
parseRenderCreate,
|
|
276
288
|
parseRenderState,
|
|
277
289
|
parseRunState,
|
|
278
|
-
parseSilenceDetect,
|
|
279
290
|
parseTimeline,
|
|
280
291
|
planPath2,
|
|
281
292
|
pollRender,
|
|
@@ -290,13 +301,11 @@ export {
|
|
|
290
301
|
pushFiles,
|
|
291
302
|
pushStage2,
|
|
292
303
|
pushTimeline2,
|
|
293
|
-
|
|
294
|
-
qaFramesLocal,
|
|
295
|
-
qaWaveformArgs,
|
|
296
|
-
qaWaveformLocal,
|
|
297
|
-
qaWordsForWindow,
|
|
304
|
+
qaDir,
|
|
298
305
|
readJobFile,
|
|
299
306
|
readOutcomesFile2,
|
|
307
|
+
readPlanSegments,
|
|
308
|
+
readProbeDuration,
|
|
300
309
|
renderUrl,
|
|
301
310
|
rendersUrl,
|
|
302
311
|
resolveApiBase,
|
|
@@ -311,9 +320,10 @@ export {
|
|
|
311
320
|
roundJsonPath2,
|
|
312
321
|
runUrl,
|
|
313
322
|
sameSha,
|
|
323
|
+
sanitizeStem,
|
|
314
324
|
savePublicConfigKey,
|
|
315
325
|
sha256Hex,
|
|
316
|
-
|
|
326
|
+
shouldMultipart,
|
|
317
327
|
statAssetsForDoc,
|
|
318
328
|
stripTrailingSlash,
|
|
319
329
|
syncAssets2,
|
|
@@ -323,7 +333,9 @@ export {
|
|
|
323
333
|
transcribeArtifactSet,
|
|
324
334
|
transcribeCloud,
|
|
325
335
|
transcribeUrl,
|
|
336
|
+
uploadMultipart,
|
|
326
337
|
uploadVfsBytes,
|
|
338
|
+
uploadVfsPayload,
|
|
327
339
|
usesFromDoc,
|
|
328
340
|
validateLocal,
|
|
329
341
|
validateTimeline,
|
|
@@ -332,6 +344,8 @@ export {
|
|
|
332
344
|
vfsContentType,
|
|
333
345
|
vfsLocalPath,
|
|
334
346
|
videoIdFromJob,
|
|
347
|
+
waveformPngPath,
|
|
348
|
+
waveformWordsPath,
|
|
335
349
|
wordStream,
|
|
336
350
|
writeJobFile
|
|
337
351
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "video-editing",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "3.1.0",
|
|
4
|
+
"description": "Pure-API cloud CLI + client for editing talking-head reels with clipready: upload once, then transcription, timeline authoring, compile, render, verify and QA all run in the cloud. Node ≥ 20 + an API key — no ffmpeg.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
7
7
|
"author": "Itay Elgazar",
|
|
@@ -1,44 +1,47 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: video-editing
|
|
3
3
|
description: >-
|
|
4
|
-
Cloud
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
the user drops a talking-head clip / reel /
|
|
12
|
-
edited or tightened — "edit this reel",
|
|
13
|
-
|
|
14
|
-
an editing ask — or when
|
|
15
|
-
Hebrew/RTL.
|
|
4
|
+
Cloud agent workflow for editing a talking-head video into a tight, clean
|
|
5
|
+
cut with the `video-editing` CLI + the ClipReady cloud. The CLI is a PURE
|
|
6
|
+
API client — requirements are Node ≥ 20 and a ClipReady API key
|
|
7
|
+
(`CLIPREADY_API_KEY`) only; no ffmpeg, no ffprobe, no local rendering
|
|
8
|
+
tools. The source uploads once at init; transcription, editorial
|
|
9
|
+
screening, timeline compilation, rendering, verification, and QA visuals
|
|
10
|
+
all run server-side; the editorial brief arrives from the server as pulled
|
|
11
|
+
`prompts/*.md`. Use whenever the user drops a talking-head clip / reel /
|
|
12
|
+
vlog / interview and wants it edited or tightened — "edit this reel",
|
|
13
|
+
"cut the bad retakes", "clean up this recording", "tighten this",
|
|
14
|
+
"add captions", or just a video path with an editing ask — or when
|
|
15
|
+
working a ClipReady review round. Handles Hebrew/RTL.
|
|
16
16
|
---
|
|
17
17
|
|
|
18
|
-
# Video Editing (ClipReady cloud
|
|
18
|
+
# Video Editing (ClipReady cloud — pure API client)
|
|
19
19
|
|
|
20
|
-
Turn a raw talking-head recording into a tight, clean cut. The
|
|
21
|
-
CLI is a
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
Turn a raw talking-head recording into a tight, clean cut. The
|
|
21
|
+
**`video-editing`** CLI (v3) is a pure API client for the ClipReady cloud: the
|
|
22
|
+
cloud owns EVERYTHING executable — probing, transcription, screening,
|
|
23
|
+
editorial prompts, timeline compilation, rendering, verification, and QA
|
|
24
|
+
visuals. Your machine only streams the source up once and pulls small
|
|
25
|
+
artifacts back. **You** read the pulled transcript + brief and author
|
|
26
|
+
`timeline.json`; the CLI does the rest over HTTP.
|
|
25
27
|
|
|
26
28
|
## Install & auth
|
|
27
29
|
|
|
28
30
|
```bash
|
|
29
|
-
npm install -g video-editing # the CLI (
|
|
31
|
+
npm install -g video-editing # the CLI (v3)
|
|
30
32
|
npx skills add ItayElgazar/clipready --skill video-editing # this skill
|
|
31
33
|
```
|
|
32
34
|
|
|
33
|
-
Requirements:
|
|
35
|
+
Requirements — this is the FULL list:
|
|
34
36
|
|
|
35
37
|
- **Node ≥ 20**
|
|
36
|
-
- **
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
- **A ClipReady API key** — one-time login: `video-editing auth api-key` (paste
|
|
39
|
+
the key from the ClipReady settings page; the base URL defaults to the hosted
|
|
40
|
+
cloud). Env vars `CLIPREADY_API_KEY`/`CLIPREADY_API_BASE` override when set.
|
|
39
41
|
|
|
40
|
-
**No ElevenLabs key.**
|
|
41
|
-
|
|
42
|
+
**No ffmpeg. No ffprobe. No hyperframes. No ElevenLabs key.** Nothing runs on
|
|
43
|
+
the local machine except the CLI itself — do not install media tools, and do
|
|
44
|
+
not set or ask for `ELEVENLABS_API_KEY`.
|
|
42
45
|
|
|
43
46
|
**Every command fails without the API key.** If a verb errors with a
|
|
44
47
|
missing-key message, stop and ask the user for their ClipReady API key;
|
|
@@ -48,79 +51,111 @@ never work around it.
|
|
|
48
51
|
|
|
49
52
|
- Use **only** the `video-editing` CLI (`video-editing <subcommand>`). Run
|
|
50
53
|
`video-editing --help` to see commands.
|
|
51
|
-
- **NEVER** run ffmpeg/ffprobe/transcription by hand —
|
|
52
|
-
|
|
54
|
+
- **NEVER** run ffmpeg/ffprobe/transcription by hand — there is simply no
|
|
55
|
+
local media in this workflow at all; every frame lives in the cloud. If you
|
|
56
|
+
have a memory of local renders, `compose`, `--master`, or "extract the WAV
|
|
57
|
+
first", that memory is from a retired pipeline — discard it.
|
|
58
|
+
- If a capability seems missing, STOP and report it as a CLI gap. Do not
|
|
59
|
+
reach around the CLI.
|
|
53
60
|
- Your only hand-authored artifact is `<job>/timeline.json`.
|
|
61
|
+
- **Captions are timeline-authored and rendered by the cloud renderer —
|
|
62
|
+
NEVER ffmpeg subtitle filters, libass, `.srt` sidecars, or `drawtext`.**
|
|
54
63
|
|
|
55
64
|
## The workflow
|
|
56
65
|
|
|
57
|
-
1. **Init** — `video-editing init --
|
|
58
|
-
choose the working dir).
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
`
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
1. **Init** — `video-editing init --source "<path>"` (add `--job-dir "<dir>"`
|
|
67
|
+
to choose the working dir). ONE command does everything through
|
|
68
|
+
transcription: it streams the source up (chunked, retried, 2GB-safe),
|
|
69
|
+
creates the cloud job, runs server-side ingest (probe + transcription +
|
|
70
|
+
editorial screening), and pulls the results into the job dir:
|
|
71
|
+
`transcripts/`, `word_dump.txt`, `takes_packed.md`, `flags.txt`,
|
|
72
|
+
`coverage.json`, `probe.json` — **and `prompts/author-edl.prompt.md`**,
|
|
73
|
+
your editorial brief. Writes `<job>/job.json` (the `video_id` every later
|
|
74
|
+
verb uses) and prints the video's web link. There is no separate
|
|
75
|
+
transcribe step — `transcribe` exists only to re-pull/re-run later.
|
|
76
|
+
Filenames with apostrophes, spaces, or unicode are safe — the internal
|
|
77
|
+
stem is sanitized automatically; never rename the user's file.
|
|
78
|
+
2. **READ the pulled `prompts/*.md` and follow them** — they are your
|
|
66
79
|
editorial brief (what to cut, what to keep, the screening gate, the pad
|
|
67
80
|
and boundary rules). They are authoritative and may change between runs;
|
|
68
81
|
never edit them, never substitute a remembered brief.
|
|
69
|
-
|
|
82
|
+
3. **Author `<job>/timeline.json`** per the pulled brief plus
|
|
70
83
|
`references/timeline-v2-vocabulary.md` (cut ranges, captions, zooms,
|
|
71
|
-
overlays, audio).
|
|
72
|
-
|
|
84
|
+
overlays, audio). The **sources KEY must equal the transcript stem** (the
|
|
85
|
+
filename of `transcripts/<stem>.json`) — captions and resolve bind
|
|
86
|
+
through it. Resolve phrase → seconds ONLY with
|
|
87
|
+
`video-editing timeline resolve --phrase "…" [--occurrence <n>]`
|
|
73
88
|
— never eyeball `word_dump.txt`. Sanity-check locally anytime with
|
|
74
89
|
`video-editing timeline validate --job-dir "<job>" --json`.
|
|
75
|
-
|
|
90
|
+
4. **Compile** — `video-editing timeline compile --job-dir "<job>" --json`.
|
|
76
91
|
Compiles in the cloud; writes `resolved/plan.json` +
|
|
77
|
-
`resolved/diagnostics.json
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
verification of the rendered preview (catches retakes left in
|
|
88
|
-
join and dead air a visual check misses)
|
|
92
|
+
`resolved/diagnostics.json` and prints the `View & comment` watch link —
|
|
93
|
+
the user can already watch/comment on the compiled cut. Read the
|
|
94
|
+
diagnostics and fix until it exits `0` (`2` = validation failed — fix the
|
|
95
|
+
reported paths; `3` = ambiguous anchor — disambiguate with
|
|
96
|
+
`timeline resolve`). Never hand-edit `resolved/`.
|
|
97
|
+
5. **Render the preview** — `video-editing render --job-dir "<job>"`
|
|
98
|
+
(cloud render, preview mode, waits and downloads `<job>/preview.mp4` by
|
|
99
|
+
default; it works right after `timeline compile`). Share the printed
|
|
100
|
+
watch link with the user.
|
|
101
|
+
6. **Verify** — `video-editing verify --job-dir "<job>" --json`. Fully
|
|
102
|
+
server-side verification of the rendered preview (catches retakes left in
|
|
103
|
+
across a join and dead air a visual check misses); nothing is uploaded.
|
|
104
|
+
Can run while the user reviews. Fix `timeline.json`, re-compile,
|
|
89
105
|
re-render, re-verify until clean; cap at ~3 fix passes and surface
|
|
90
106
|
remaining findings rather than looping.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
107
|
+
7. **QA looks** — spot-check any window with server-rendered visuals.
|
|
108
|
+
THE close-look tool is
|
|
109
|
+
`video-editing qa inspect --start <a> --end <b> --job-dir "<job>"`:
|
|
110
|
+
one composite PNG with the filmstrip, the waveform, word labels, AND
|
|
111
|
+
the compiled plan's cut regions shaded red ("cut") — everything needed
|
|
112
|
+
to adjudicate a moment in a single image. Same addressing as frames:
|
|
113
|
+
`qa inspect --join <i>` (the two sides of plan join i → `-a`/`-b`
|
|
114
|
+
PNGs) and `qa inspect --out-start <a> --out-end <b>` (OUTPUT seconds
|
|
115
|
+
mapped through the compiled plan). The narrower views still exist:
|
|
116
|
+
`video-editing qa frames …` (filmstrip only, same addressing modes)
|
|
117
|
+
and `video-editing qa waveform --start <a> --end <b>` (waveform PNG +
|
|
118
|
+
word-timing sidecar JSON). Read the PNGs to adjudicate.
|
|
119
|
+
8. **Final** — `video-editing render --mode final --job-dir "<job>"`.
|
|
120
|
+
|
|
121
|
+
**Optional, any time after compile:** if joins sound clicky, chopped, or gappy,
|
|
122
|
+
run `video-editing smooth-joins --job-dir "<job>"` to apply an equal-power
|
|
123
|
+
audio crossfade to every cut, then re-render. It is NOT part of the sequence
|
|
124
|
+
above — renders are unaffected unless you run it, and it must be re-run after
|
|
125
|
+
each recompile you want it applied to. See `references/audio-joins.md`.
|
|
98
126
|
|
|
99
127
|
## Your editorial brief arrives from the cloud
|
|
100
128
|
|
|
101
129
|
The deep editorial brief — retake/keep rules, pause tightening, cold-open,
|
|
102
130
|
screening and verification procedure — is **not in this skill**. It is pulled
|
|
103
|
-
from the server into `<job>/prompts/*.md` by `
|
|
131
|
+
from the server into `<job>/prompts/*.md` by `init` (and refreshed by
|
|
104
132
|
`files pull`). Old references in this skill (`editing-brief.md`,
|
|
105
133
|
`hard-rules.md`, `adversarial-review.md`, `scribe-collapse.md`) are stubs
|
|
106
134
|
pointing there. If `prompts/author-edl.prompt.md` is missing, run
|
|
107
135
|
`video-editing files pull --job-dir "<job>"` — do not improvise a brief.
|
|
108
136
|
|
|
109
|
-
##
|
|
137
|
+
## Known caveats
|
|
110
138
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
139
|
+
- **`verify` over-triggers on thematically narrow monologues.** The
|
|
140
|
+
duplicated-phrase join check flags legitimately repeated wording as
|
|
141
|
+
"retake left in". If EVERY join comes back flagged — including plain
|
|
142
|
+
pause-tightening joins that obviously aren't retakes — adjudicate each
|
|
143
|
+
finding against `flags.txt` (the screening output) instead of blindly
|
|
144
|
+
recutting; only recut joins that flags.txt corroborates as real retakes.
|
|
145
|
+
- **Caption mistranscriptions** are fixed with a captions override in
|
|
146
|
+
`timeline.json` (anchored on the MIS-transcribed text — see
|
|
147
|
+
`references/timeline-v2-vocabulary.md`), then recompile + re-render.
|
|
148
|
+
Never with subtitle files or filters.
|
|
115
149
|
|
|
116
150
|
## File sync
|
|
117
151
|
|
|
118
152
|
`video-editing files pull --job-dir "<job>" [--only <name,name>]` fetches the
|
|
119
153
|
cloud job's artifacts into the job dir preserving relative paths (transcripts,
|
|
120
154
|
`prompts/*.md`, `resolved/plan.json`, `timeline.json`, …);
|
|
121
|
-
`video-editing files push --job-dir "<job>"
|
|
122
|
-
hand-authored `timeline.json`, referenced assets) back to the job. Use
|
|
123
|
-
to recover state on a fresh machine — the cloud job is the source of
|
|
155
|
+
`video-editing files push --job-dir "<job>" <paths…>` uploads local artifacts
|
|
156
|
+
(e.g. a hand-authored `timeline.json`, referenced assets) back to the job. Use
|
|
157
|
+
`pull` to recover state on a fresh machine — the cloud job is the source of
|
|
158
|
+
truth.
|
|
124
159
|
|
|
125
160
|
## Working a ClipReady review round
|
|
126
161
|
|
|
@@ -130,13 +165,12 @@ When the job is a clipready review round (the video has an active round):
|
|
|
130
165
|
`<job>/review/round.json` (round/run ids, requested changes) and
|
|
131
166
|
`<job>/review/instruction.md`; hydrates `<job>/timeline.json` from the
|
|
132
167
|
server only when you don't already have one (never overwrites yours).
|
|
133
|
-
Add `--source` if the source video isn't local yet.
|
|
134
168
|
2. Edit `timeline.json` per the instruction, then
|
|
135
169
|
`video-editing review push --timeline --job-dir "<job>"` after each
|
|
136
|
-
meaningful change — it compiles (diagnostics; exit `2` if
|
|
137
|
-
the review page updates live. Referenced assets (stickers,
|
|
138
|
-
upload automatically, sha256-cached.
|
|
139
|
-
3.
|
|
170
|
+
meaningful change — it compiles in the cloud (diagnostics; exit `2` if
|
|
171
|
+
not clean) and the review page updates live. Referenced assets (stickers,
|
|
172
|
+
audio beds) upload automatically, sha256-cached.
|
|
173
|
+
3. Render + verify exactly as in the workflow above.
|
|
140
174
|
4. `video-editing review push --complete --duration <s> --outcomes outcomes.json --job-dir "<job>"`
|
|
141
175
|
— compiles fresh (must be clean) and delivers the terminal payload.
|
|
142
176
|
`outcomes.json` is `[{"change_id": "chg_…", "ok": true, "note": "…"}]`,
|
|
@@ -152,7 +186,7 @@ caption grouping is the same characters in Hebrew.
|
|
|
152
186
|
|
|
153
187
|
## References
|
|
154
188
|
|
|
155
|
-
- `references/cli-reference.md` — every
|
|
189
|
+
- `references/cli-reference.md` — every v3 subcommand + flag.
|
|
156
190
|
- `references/timeline-v2-vocabulary.md` — the full `timeline.json` v2
|
|
157
191
|
vocabulary, one JSON example per feature (captions + word styling, karaoke,
|
|
158
192
|
zoom ramps, stickers, enter/exit, audio beds, grade).
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Smoothing the audio at cuts (`smooth-joins`)
|
|
2
|
+
|
|
3
|
+
**Optional.** Nothing here runs as part of a render. If you never call it,
|
|
4
|
+
renders behave exactly as they always have.
|
|
5
|
+
|
|
6
|
+
This is the Premiere move of selecting the whole timeline and hitting *Apply
|
|
7
|
+
Audio Transition*: the picture stays a hard cut, and every join gets a short
|
|
8
|
+
**Constant Power** (equal-power) audio crossfade built from the padding the cut
|
|
9
|
+
threw away. One invocation treats every join — you do not opt in per cut.
|
|
10
|
+
|
|
11
|
+
## Why you would run it
|
|
12
|
+
|
|
13
|
+
By default each kept range is extracted with a 30 ms fade in *and* out and the
|
|
14
|
+
clips are butt-joined, so every cut has a brief hole down to silence. Depending
|
|
15
|
+
on where the cut landed that reads as a click, a clipped syllable, or a gap of
|
|
16
|
+
dead air. The crossfade turns each one into a quick natural dip instead, and
|
|
17
|
+
because it is centred on the cut the total duration does not change.
|
|
18
|
+
|
|
19
|
+
Reach for it when a verify pass or a listen flags clicks, popping, or chopped
|
|
20
|
+
word endings at joins — and on any edit with a lot of tight desilence trims,
|
|
21
|
+
where joins are most frequent.
|
|
22
|
+
|
|
23
|
+
Requires a compiled timeline (run `timeline compile` first) and an ingested
|
|
24
|
+
source. Exits non-zero with `no_edl` if you run it too early.
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
video-editing smooth-joins --job-dir "<job>" # 130ms everywhere
|
|
30
|
+
video-editing smooth-joins --crossfade-ms 90 --job-dir "<job>"
|
|
31
|
+
video-editing smooth-joins --join 3:40 --join 7:220 --job-dir "<job>"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
| Flag | Default | Meaning |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| `--crossfade-ms <ms>` | `130` | Transition length at every join (Premiere's 4 frames). `0` disables. |
|
|
37
|
+
| `--curve equal-power\|linear` | `equal-power` | Fade shape. |
|
|
38
|
+
| `--max-ms <ms>` | `500` | Ceiling on any single join. |
|
|
39
|
+
| `--join <index>:<ms>` | — | Override one boundary. Repeatable. |
|
|
40
|
+
| `--json` | — | Machine-readable output. |
|
|
41
|
+
|
|
42
|
+
**Join `i` is the boundary between segment `i` and segment `i + 1`**, so an
|
|
43
|
+
N-segment edit has N−1 joins. Same indexing `verify` reports its join findings
|
|
44
|
+
against, so a verify finding at join 5 is `--join 5:<ms>` here.
|
|
45
|
+
|
|
46
|
+
Keep `--curve equal-power` unless you have a reason: it is the only curve that
|
|
47
|
+
holds loudness flat through the transition (`sin² + cos² = 1`). `linear` dips
|
|
48
|
+
~3 dB in the middle of every join.
|
|
49
|
+
|
|
50
|
+
Per-join overrides are for shaping, not rescue — `--join 3:40` to keep a hard
|
|
51
|
+
beat change tight, `--join 7:220` to let a take change breathe, `--join 9:0` to
|
|
52
|
+
leave one boundary exactly as it was.
|
|
53
|
+
|
|
54
|
+
## Reading the result
|
|
55
|
+
|
|
56
|
+
Writes `audio/joined.m4a` (the rebuilt track) and `audio/joined.json`:
|
|
57
|
+
|
|
58
|
+
```jsonc
|
|
59
|
+
{
|
|
60
|
+
"edl_sha256": "…",
|
|
61
|
+
"params": { "crossfade_ms": 130, "curve": "equal-power", "max_ms": 500 },
|
|
62
|
+
"total_duration_s": 47.213,
|
|
63
|
+
"segments": 42,
|
|
64
|
+
"joins": [
|
|
65
|
+
{ "index": 0, "requested_ms": 130, "applied_ms": 130, "handle_ms": 1840, "clamped": false },
|
|
66
|
+
{ "index": 1, "requested_ms": 130, "applied_ms": 52, "handle_ms": 52, "clamped": true,
|
|
67
|
+
"reason": "limited by the gap the cut removed" }
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`applied_ms` is what the join actually got; `handle_ms` is the longest
|
|
73
|
+
crossfade the surrounding material could support. **A crossfade can only borrow
|
|
74
|
+
material the cut removed**, so a tight desilence trim that only took out 50 ms
|
|
75
|
+
can only give you a 50 ms transition — it will come back `clamped` no matter
|
|
76
|
+
what you request. That is expected and still sounds clean; 50 ms of same-speaker
|
|
77
|
+
room tone is plenty. Joins between different takes have seconds of handle and
|
|
78
|
+
always get the full request.
|
|
79
|
+
|
|
80
|
+
Read the report before re-running: if a join you care about came back clamped
|
|
81
|
+
with `"limited by the gap the cut removed"`, asking for more milliseconds will
|
|
82
|
+
change nothing. Widen the cut range in `timeline.json` and recompile instead.
|
|
83
|
+
|
|
84
|
+
## How it interacts with rendering
|
|
85
|
+
|
|
86
|
+
Renders **consume** the artifact, they never trigger it:
|
|
87
|
+
|
|
88
|
+
- Run `smooth-joins`, then render → the render uses the crossfaded audio.
|
|
89
|
+
- Render without running it → unchanged from today.
|
|
90
|
+
- Recompile the timeline, then render → the artifact no longer matches the
|
|
91
|
+
edit and is ignored (it is keyed to the EDL). Re-run `smooth-joins`.
|
|
92
|
+
|
|
93
|
+
So the order is: `timeline compile` → `smooth-joins` → render. Re-running the
|
|
94
|
+
command is cheap; re-run it after every recompile you want it applied to.
|