videobook 0.3.0 → 0.3.1
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 +73 -0
- package/dist/asset-media-projection.js +161 -0
- package/dist/command-reference.js +3 -1
- package/dist/diagnostics.js +1 -1
- package/dist/generation-reference-mentions.js +19 -0
- package/dist/goal-plan-v3.js +11 -1
- package/dist/goal-plan.js +1 -1
- package/dist/goal-store.js +2 -2
- package/dist/har-capture.js +36 -3
- package/dist/jobs/_image-edit-adapter.js +2 -0
- package/dist/jobs/assess-media-probes.js +94 -0
- package/dist/jobs/complete-provider-task.js +2 -5
- package/dist/jobs/generate-media.js +3 -2
- package/dist/jobs/image-subjects.js +2 -0
- package/dist/jobs/kie-paygate.js +3 -3
- package/dist/jobs/register-all.js +2 -0
- package/dist/jobs/run-notebook.js +16 -1
- package/dist/library-asset-projection.js +141 -0
- package/dist/lightning-defaults.js +4 -4
- package/dist/media/catalog.js +8 -2
- package/dist/media/descriptor.js +7 -4
- package/dist/media/frontier-gaps.js +0 -1
- package/dist/media/har-endpoint.js +25 -0
- package/dist/media/json-schema.js +3 -0
- package/dist/media/preferred-defaults.js +161 -0
- package/dist/media/prompt-dialects.js +9 -1
- package/dist/media-library.js +158 -153
- package/dist/notebook-sticky-settings.js +60 -0
- package/dist/tools/reconcile-project-work.js +34 -181
- package/dist/tools/videobook-domain.js +16 -1
- package/dist/usage-providers.js +3 -3
- package/package.json +15 -15
- package/ui/assets/{alive-captions-Cj8C1tCN.js → alive-captions-CnLK22ED.js} +1 -1
- package/ui/assets/confirm-bodies-BaalBxp1.js +1 -0
- package/ui/assets/{fullscreen-DyEncSdm.js → fullscreen-DTJQJ6dX.js} +1 -1
- package/ui/assets/{goal-ui-BdFeoSWh.js → goal-ui-CN-kZTEO.js} +1 -1
- package/ui/assets/index-CTPstLYq.css +1 -0
- package/ui/assets/index-Dp81yChE.js +37 -0
- package/ui/assets/inspector-jeyma7HL.js +1 -0
- package/ui/assets/{jobs-ui-BudI4w0r.js → jobs-ui-D6S3LJ4j.js} +1 -1
- package/ui/assets/{music-video-CT4C55ok.js → music-video-CDqr0X6G.js} +1 -1
- package/ui/assets/{ui-mq0uIS5P.css → ui-BBM3YCY6.css} +1 -1
- package/ui/assets/ui-Cqs1-YNg.js +2 -0
- package/ui/assets/vendor-BWf-WCsY.js +19 -0
- package/ui/assets/{vendor-flow-nqTFQmTh.js → vendor-flow-DPvi8ynA.js} +1 -1
- package/ui/assets/vendor-icons-D3KrGMJY.js +1 -0
- package/ui/assets/{vendor-mcp-D_C3EZPv.js → vendor-mcp-BSR9acpG.js} +2 -2
- package/ui/assets/videobook-b9VODNOA.js +21 -0
- package/ui/index.html +14 -14
- package/ui/assets/confirm-bodies-BxWXwDf0.js +0 -1
- package/ui/assets/index-DWfR79lA.css +0 -1
- package/ui/assets/index-QZ8lbemN.js +0 -37
- package/ui/assets/inspector-BC6xWkJU.js +0 -1
- package/ui/assets/ui-z5r-p0K9.js +0 -2
- package/ui/assets/vendor-D8XcMav4.js +0 -19
- package/ui/assets/vendor-icons-CGqhCIXV.js +0 -1
- package/ui/assets/videobook-CsW453sb.js +0 -21
|
@@ -7,7 +7,6 @@ import { legacyMediaForTaskType } from "../media/legacy-task-types.js";
|
|
|
7
7
|
import { parseModelId } from "../media/model-id.js";
|
|
8
8
|
import { computeArtifactStatus, QUEUED_TASK_ID } from "videobook-engine";
|
|
9
9
|
import { z } from "zod";
|
|
10
|
-
import { createHash } from "node:crypto";
|
|
11
10
|
import { join } from "node:path";
|
|
12
11
|
import { KieError } from "@apicity/kie";
|
|
13
12
|
import { XaiError } from "@apicity/xai";
|
|
@@ -18,20 +17,19 @@ import { EMPTY_TAG_SUMMARY, readAssetTagSummaries, } from "../asset-tags.js";
|
|
|
18
17
|
import { logger } from "../logger.js";
|
|
19
18
|
import { queue } from "../queue.js";
|
|
20
19
|
import { getApiKey } from "../api-key.js";
|
|
21
|
-
import { findVideoFile, findAudioFile,
|
|
20
|
+
import { findVideoFile, findAudioFile, RENDER_ORIENTATIONS as MEDIA_RENDER_ORIENTATIONS, } from "videobook-engine";
|
|
22
21
|
import { readAndAssessDialog } from "../dialog-quality.js";
|
|
23
22
|
import { hasSpokenAudio, PLAIN_TRANSCRIPT_FILE, readAssetTranscriptSources, TIMED_TRANSCRIPT_FILE, } from "../transcript-projection.js";
|
|
24
23
|
import { isAnalyzableVideo, readVideoAnalysisSummary, VIDEO_ANALYSIS_FILE, } from "../video-analysis-projection.js";
|
|
25
24
|
import { failPendingTaskAndLog } from "../jobs/task-failure.js";
|
|
26
25
|
import { findUnprocessedUploads, processExternalUpload } from "../jobs/process-upload.js";
|
|
27
26
|
import { planVideoTranscriptJobs } from "../jobs/process-video.js";
|
|
28
|
-
import { probeVideo } from "../ffmpeg.js";
|
|
29
27
|
import { providerEndpoints } from "../media/endpoints.js";
|
|
30
28
|
import { machgenProvider } from "../media/adapters/machgen.js";
|
|
31
29
|
import { MEDIA_TASK_TYPES } from "../media/adapters/types.js";
|
|
32
30
|
import { submitQueuedKieTask } from "../jobs/kie-paygate.js";
|
|
33
31
|
import { DEFAULT_KEYWORD_GRAPHICS_LINGER_SECONDS, DEFAULT_KEYWORD_GRAPHICS_MAX_COUNT, } from "../remotion/keyword-graphics.js";
|
|
34
|
-
import {
|
|
32
|
+
import { assetDuration, assetMediaUrls, assetStreamProfile, findAssetMediaFile, groupByArtifactId, indexByArtifactId, PARTIAL_DOWNLOAD_RE, scheduleMissingVideoPoster, servedVideoProxyFile, } from "../asset-media-projection.js";
|
|
35
33
|
/** Upper bound on how long a pending task may sit without reaching success/fail
|
|
36
34
|
* before reconciliation ages it out. Guards against providers leaving jobs in an
|
|
37
35
|
* intermediate "waiting" state indefinitely. */
|
|
@@ -153,29 +151,6 @@ async function analysisOutputProjection(engine, artifactId) {
|
|
|
153
151
|
return null;
|
|
154
152
|
}
|
|
155
153
|
}
|
|
156
|
-
function findAssetMediaFile(files, asset) {
|
|
157
|
-
return asset.kind === "audio"
|
|
158
|
-
? findAudioFile(files, asset.kind)
|
|
159
|
-
: asset.kind === "video"
|
|
160
|
-
? findVideoFile(files.filter((file) => file.name !== "proxy.mp4"))
|
|
161
|
-
: findPrimaryMediaFile(files, asset.kind);
|
|
162
|
-
}
|
|
163
|
-
async function assessStoredVideoProxy(engine, assetId, sourceFile, proxyFile, sourceProfile) {
|
|
164
|
-
let assessment;
|
|
165
|
-
try {
|
|
166
|
-
const proxy = await probeStoredVideoFile(engine, assetId, proxyFile.name);
|
|
167
|
-
const error = videoProxyValidationError(sourceProfile, proxy);
|
|
168
|
-
assessment = error
|
|
169
|
-
? invalidVideoProxyMetadata(sourceFile, proxyFile, error)
|
|
170
|
-
: videoProxyMetadata(sourceFile, proxyFile, proxy);
|
|
171
|
-
}
|
|
172
|
-
catch (cause) {
|
|
173
|
-
const error = cause instanceof Error ? cause.message : String(cause);
|
|
174
|
-
assessment = invalidVideoProxyMetadata(sourceFile, proxyFile, error);
|
|
175
|
-
}
|
|
176
|
-
await engine.metadata.artifacts.write(assetId, "proxy", assessment);
|
|
177
|
-
return assessment.valid;
|
|
178
|
-
}
|
|
179
154
|
/** Read the OSG overlay summary from the asset's render metadata. OSG is stored
|
|
180
155
|
* identically across orientations, so the first orientation that carries an
|
|
181
156
|
* osgAssetId wins. Returns null when no overlay is configured. */
|
|
@@ -277,9 +252,7 @@ function scheduleWaveformExtraction(bookId, assetId, videoFilename) {
|
|
|
277
252
|
logger.error("waveform-enqueue-failed", { assetId, error: err });
|
|
278
253
|
});
|
|
279
254
|
}
|
|
280
|
-
const PARTIAL_DOWNLOAD_RE = /\.(mp4|mov)\.part$/i;
|
|
281
255
|
/** Media extensions whose duration can be recovered via ffprobe when metadata lacks it. */
|
|
282
|
-
const DURATION_PROBE_EXT_RE = /\.(mp4|mov|webm|mkv|mp3|wav|m4a|aac|ogg|flac)$/i;
|
|
283
256
|
export const RENDER_ORIENTATIONS = MEDIA_RENDER_ORIENTATIONS;
|
|
284
257
|
export async function readRenderSettings(engine, assetId, orientations) {
|
|
285
258
|
const result = {};
|
|
@@ -377,30 +350,6 @@ async function readAnalysisRecommendations(engine, assetId) {
|
|
|
377
350
|
return {};
|
|
378
351
|
}
|
|
379
352
|
}
|
|
380
|
-
// Content fingerprint covering every file in the asset directory. Changes
|
|
381
|
-
// whenever any file is added, removed, resized, or rewritten, so every URL
|
|
382
|
-
// derived from an asset's filePath (including alternate-orientation renders
|
|
383
|
-
// like portrait.mp4 / landscape.mp4) invalidates together. Cheap: no file
|
|
384
|
-
// reads — just hashes the immutable manifest tuples. Partial downloads are
|
|
385
|
-
// excluded: their size grows on every poll while no served URL points at
|
|
386
|
-
// them, and including them made every media URL churn (and the browser
|
|
387
|
-
// refetch) once per poll tick for the whole duration of a download.
|
|
388
|
-
function computeAssetFingerprint(files) {
|
|
389
|
-
const settled = files.filter((f) => !PARTIAL_DOWNLOAD_RE.test(f.name));
|
|
390
|
-
if (settled.length === 0)
|
|
391
|
-
return "";
|
|
392
|
-
const sorted = [...settled].sort((a, b) => a.name.localeCompare(b.name));
|
|
393
|
-
const hash = createHash("sha1");
|
|
394
|
-
for (const f of sorted) {
|
|
395
|
-
hash.update(f.name);
|
|
396
|
-
hash.update("\0");
|
|
397
|
-
hash.update(String(f.sizeBytes ?? 0));
|
|
398
|
-
hash.update("\0");
|
|
399
|
-
hash.update(f.objectHash);
|
|
400
|
-
hash.update("\0");
|
|
401
|
-
}
|
|
402
|
-
return hash.digest("hex").slice(0, 12);
|
|
403
|
-
}
|
|
404
353
|
function renderedOrientationsFor(files, kind) {
|
|
405
354
|
const fileSet = new Set(files.map((f) => f.name));
|
|
406
355
|
if (kind === "final") {
|
|
@@ -408,23 +357,6 @@ function renderedOrientationsFor(files, kind) {
|
|
|
408
357
|
}
|
|
409
358
|
return RENDER_ORIENTATIONS.filter((o) => fileSet.has(`${o}.mp4`));
|
|
410
359
|
}
|
|
411
|
-
function indexByArtifactId(rows) {
|
|
412
|
-
const map = new Map();
|
|
413
|
-
for (const row of rows)
|
|
414
|
-
map.set(row.artifactId, row);
|
|
415
|
-
return map;
|
|
416
|
-
}
|
|
417
|
-
function groupByArtifactId(rows) {
|
|
418
|
-
const map = new Map();
|
|
419
|
-
for (const row of rows) {
|
|
420
|
-
const list = map.get(row.artifactId);
|
|
421
|
-
if (list)
|
|
422
|
-
list.push(row);
|
|
423
|
-
else
|
|
424
|
-
map.set(row.artifactId, [row]);
|
|
425
|
-
}
|
|
426
|
-
return map;
|
|
427
|
-
}
|
|
428
360
|
export async function buildAssetList(engine, book_id, sort) {
|
|
429
361
|
const assets = engine.artifacts.list({ ...(sort ? { sort } : {}) });
|
|
430
362
|
const pendingAll = engine.jobs.pending.findAll();
|
|
@@ -468,30 +400,9 @@ export async function buildAssetList(engine, book_id, sort) {
|
|
|
468
400
|
const mediaFile = findAssetMediaFile(files, a);
|
|
469
401
|
const meta = metadata.ok ? metadata.value : null;
|
|
470
402
|
const streams = streamsByArtifact.get(a.artifactId) ?? [];
|
|
471
|
-
const
|
|
472
|
-
const audioStream
|
|
473
|
-
const frameRate = videoStream?.video?.averageFrameRate
|
|
474
|
-
?? videoStream?.video?.nominalFrameRate;
|
|
475
|
-
const streamDuration = videoStream
|
|
476
|
-
? videoStream.durationTicks
|
|
477
|
-
* videoStream.timeBase.numerator
|
|
478
|
-
/ videoStream.timeBase.denominator
|
|
479
|
-
: 0;
|
|
480
|
-
const metadataDuration = Number(meta?.duration);
|
|
481
|
-
const sourceDuration = streamDuration > 0
|
|
482
|
-
? streamDuration
|
|
483
|
-
: Number.isFinite(metadataDuration) ? metadataDuration : 0;
|
|
484
|
-
const sourceProfile = sourceDuration > 0
|
|
485
|
-
? {
|
|
486
|
-
videoDuration: sourceDuration,
|
|
487
|
-
avgFps: frameRate
|
|
488
|
-
? frameRate.numerator / frameRate.denominator
|
|
489
|
-
: null,
|
|
490
|
-
hasAudio: audioStream !== undefined || meta?.hasAudio === true,
|
|
491
|
-
}
|
|
492
|
-
: null;
|
|
403
|
+
const profile = assetStreamProfile(streams, meta);
|
|
404
|
+
const { audioStream, frameRate } = profile;
|
|
493
405
|
const fileNames = new Set(files.map((f) => f.name));
|
|
494
|
-
const hasThumbnail = fileNames.has("original.jpg");
|
|
495
406
|
const renders = renderedOrientationsFor(files, a.kind);
|
|
496
407
|
const hasPartFile = files.some((f) => PARTIAL_DOWNLOAD_RE.test(f.name));
|
|
497
408
|
const frameDirs = buildFrameDirs(directories, book_id, a.artifactId);
|
|
@@ -509,64 +420,22 @@ export async function buildAssetList(engine, book_id, sort) {
|
|
|
509
420
|
: Promise.resolve(null),
|
|
510
421
|
]);
|
|
511
422
|
const waveform = await readWaveformOrSchedule(engine, a.artifactId, book_id, mediaFile?.name ?? null);
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
}
|
|
529
|
-
// Character assets: free-form folders have no original.* media. Project
|
|
530
|
-
// the first image in the folder so sidebar thumbs and drag-drop keep working.
|
|
531
|
-
let charImage = null;
|
|
532
|
-
if (a.kind === "character") {
|
|
533
|
-
charImage = files.find((f) => /\.(jpg|jpeg|png|webp|gif)$/i.test(f.name)) ?? null;
|
|
534
|
-
}
|
|
535
|
-
const proxyCandidate = a.kind === "video"
|
|
536
|
-
? files.find((file) => file.name === "proxy.mp4")
|
|
537
|
-
: null;
|
|
538
|
-
let proxyFile = null;
|
|
539
|
-
if (proxyCandidate && mediaFile) {
|
|
540
|
-
if (proxyMetadata.ok
|
|
541
|
-
&& videoProxyMetadataMatches(proxyMetadata.value, mediaFile, proxyCandidate)) {
|
|
542
|
-
proxyFile = proxyCandidate;
|
|
543
|
-
}
|
|
544
|
-
else {
|
|
545
|
-
const assessmentMatches = proxyMetadata.ok
|
|
546
|
-
&& videoProxyAssessmentMatches(proxyMetadata.value, mediaFile, proxyCandidate);
|
|
547
|
-
const active = assetWorkRow.ok
|
|
548
|
-
&& assetWorkRow.value !== null
|
|
549
|
-
&& (assetWorkRow.value.status === "pending" || assetWorkRow.value.status === "working");
|
|
550
|
-
if (!assessmentMatches && !active && sourceProfile) {
|
|
551
|
-
const valid = await assessStoredVideoProxy(engine, a.artifactId, mediaFile, proxyCandidate, sourceProfile);
|
|
552
|
-
if (valid)
|
|
553
|
-
proxyFile = proxyCandidate;
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
const media_url = charImage
|
|
558
|
-
? `/files/${book_id}/${a.artifactId}/${charImage.name}${cacheBust}`
|
|
559
|
-
: proxyFile
|
|
560
|
-
? `/files/${book_id}/${a.artifactId}/${proxyFile.name}${cacheBust}`
|
|
561
|
-
: mediaFile
|
|
562
|
-
? `/files/${book_id}/${a.artifactId}/${mediaFile.name}${cacheBust}`
|
|
563
|
-
: null;
|
|
564
|
-
const isImage = a.kind === "image";
|
|
565
|
-
const thumbnail_url = charImage
|
|
566
|
-
? `/files/${book_id}/${a.artifactId}/${charImage.name}${cacheBust}`
|
|
567
|
-
: hasThumbnail
|
|
568
|
-
? `/files/${book_id}/${a.artifactId}/original.jpg${cacheBust}`
|
|
569
|
-
: isImage ? media_url : null;
|
|
423
|
+
const proxyFile = servedVideoProxyFile({
|
|
424
|
+
bookId: book_id,
|
|
425
|
+
artifact: a,
|
|
426
|
+
files,
|
|
427
|
+
mediaFile,
|
|
428
|
+
proxyMetadata,
|
|
429
|
+
work: assetWorkRow.value,
|
|
430
|
+
sourceProfile: profile.sourceProfile,
|
|
431
|
+
});
|
|
432
|
+
const { media_url, thumbnail_url } = assetMediaUrls({
|
|
433
|
+
bookId: book_id,
|
|
434
|
+
artifact: a,
|
|
435
|
+
files,
|
|
436
|
+
mediaFile,
|
|
437
|
+
proxyFile,
|
|
438
|
+
});
|
|
570
439
|
// Status derivation lives in videobook-engine (`computeArtifactStatus`). We pass
|
|
571
440
|
// the asset-type-aware primary media name we already computed so the
|
|
572
441
|
// engine doesn't have to redo media-type heuristics.
|
|
@@ -587,20 +456,13 @@ export async function buildAssetList(engine, book_id, sort) {
|
|
|
587
456
|
}
|
|
588
457
|
: null,
|
|
589
458
|
});
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
sourceFilename: mediaFile.name,
|
|
598
|
-
sourceHash: mediaFile.objectHash,
|
|
599
|
-
}).catch((error) => {
|
|
600
|
-
logger.error("poster-enqueue-failed", { assetId: a.artifactId, error });
|
|
601
|
-
});
|
|
602
|
-
}
|
|
603
|
-
}
|
|
459
|
+
await scheduleMissingVideoPoster(engine, {
|
|
460
|
+
bookId: book_id,
|
|
461
|
+
artifact: a,
|
|
462
|
+
files,
|
|
463
|
+
mediaFile,
|
|
464
|
+
status,
|
|
465
|
+
});
|
|
604
466
|
const archiveMeta = archiveMetadata.ok ? archiveMetadata.value : null;
|
|
605
467
|
const analysisInfo = analysisInfoFromMetadata(meta);
|
|
606
468
|
if (analysisInfo && fileNames.has("analysis.json")) {
|
|
@@ -612,22 +474,13 @@ export async function buildAssetList(engine, book_id, sort) {
|
|
|
612
474
|
analysisInfo.llm_exchanges = output.llmExchanges;
|
|
613
475
|
}
|
|
614
476
|
}
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
duration = probe.duration;
|
|
623
|
-
// Persist so we don't re-probe next time
|
|
624
|
-
if (metadata.ok) {
|
|
625
|
-
await engine.metadata.artifacts.write(a.artifactId, "original", { ...metadata.value, duration });
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
catch { /* non-fatal */ }
|
|
630
|
-
}
|
|
477
|
+
const duration = assetDuration({
|
|
478
|
+
bookId: book_id,
|
|
479
|
+
artifactId: a.artifactId,
|
|
480
|
+
meta,
|
|
481
|
+
mediaFile,
|
|
482
|
+
profile,
|
|
483
|
+
});
|
|
631
484
|
const audio_info = audioStream?.audio
|
|
632
485
|
? {
|
|
633
486
|
codec: audioStream.codec,
|
|
@@ -17,6 +17,7 @@ import { listNotebookActions, markDescendantsStale, normalizeCellActionFields, n
|
|
|
17
17
|
import { hydrateNotebookProviderFailures } from "../notebook-provider-failure.js";
|
|
18
18
|
import { buildSevenStageScaffold } from "../notebook-workflow.js";
|
|
19
19
|
import { previewGeneration } from "../media/preview.js";
|
|
20
|
+
import { readNotebookStickySettings, rememberNotebookStickySettings, seedNotebookStickySettings, } from "../notebook-sticky-settings.js";
|
|
20
21
|
import { generationInputMentions, remapGenerationInputPrompt } from "../generation-input-mentions.js";
|
|
21
22
|
import { applyPreviewPlaceholderUrls } from "../preview-payload.js";
|
|
22
23
|
import { jobProviderTaskStatus } from "../provider-task-status.js";
|
|
@@ -559,6 +560,7 @@ function notebookPayload(engine, notebook) {
|
|
|
559
560
|
cells: normalized.cells.map(cellPayload),
|
|
560
561
|
posts: notebookPosts(engine, normalized),
|
|
561
562
|
edges: normalized.edges,
|
|
563
|
+
generation_settings_memory: readNotebookStickySettings(engine, normalized.id),
|
|
562
564
|
};
|
|
563
565
|
}
|
|
564
566
|
const entityKindSchema = z.enum(["prompt", "scene", "character"]);
|
|
@@ -1158,6 +1160,7 @@ export function videobookDomainDefs(engine, books) {
|
|
|
1158
1160
|
if (args.cell.type === "goal")
|
|
1159
1161
|
return failure(GOAL_TILE_CREATE_ERROR);
|
|
1160
1162
|
let cell = engine.notebooks.createCell(cellFromInput(args.cell));
|
|
1163
|
+
let requestedCell = cell;
|
|
1161
1164
|
let outputCell = null;
|
|
1162
1165
|
let outputEdge = null;
|
|
1163
1166
|
try {
|
|
@@ -1167,6 +1170,8 @@ export function videobookDomainDefs(engine, books) {
|
|
|
1167
1170
|
throw new Error(`Stale notebook revision: expected ${args.expected_revision}`);
|
|
1168
1171
|
}
|
|
1169
1172
|
cell = normalizeCellActionFields(cell, notebook);
|
|
1173
|
+
requestedCell = cell;
|
|
1174
|
+
cell = seedNotebookStickySettings(cell, readNotebookStickySettings(engine, String(args.notebook_id)));
|
|
1170
1175
|
const withCell = seedInitialGenerationPrompt({
|
|
1171
1176
|
...notebook,
|
|
1172
1177
|
cells: [...notebook.cells, cell],
|
|
@@ -1209,6 +1214,8 @@ export function videobookDomainDefs(engine, books) {
|
|
|
1209
1214
|
],
|
|
1210
1215
|
};
|
|
1211
1216
|
}, { cellId: cell.id });
|
|
1217
|
+
if (result.ok)
|
|
1218
|
+
rememberNotebookStickySettings(engine, String(args.notebook_id), requestedCell);
|
|
1212
1219
|
return result.ok
|
|
1213
1220
|
? json({
|
|
1214
1221
|
...cellPayload(cell),
|
|
@@ -1239,6 +1246,7 @@ export function videobookDomainDefs(engine, books) {
|
|
|
1239
1246
|
return failure(`Stale notebook revision: expected ${args.expected_revision}`);
|
|
1240
1247
|
}
|
|
1241
1248
|
const patch = args.cell;
|
|
1249
|
+
const edited = {};
|
|
1242
1250
|
try {
|
|
1243
1251
|
const result = await mutateNotebook(engine, String(args.notebook_id), "update_notebook_cell", (notebook) => {
|
|
1244
1252
|
if (typeof args.expected_revision === "string"
|
|
@@ -1298,10 +1306,15 @@ export function videobookDomainDefs(engine, books) {
|
|
|
1298
1306
|
? {}
|
|
1299
1307
|
: { pinnedResults: patch.pinned_results.map(pinnedResultFromInput) }),
|
|
1300
1308
|
}, document);
|
|
1301
|
-
const
|
|
1309
|
+
const reconciled = reconcileInitialGenerationPrompt(cell, normalized);
|
|
1310
|
+
const next = reconciled.model !== cell.model
|
|
1311
|
+
? seedNotebookStickySettings(reconciled, readNotebookStickySettings(engine, String(args.notebook_id)))
|
|
1312
|
+
: reconciled;
|
|
1302
1313
|
const validation = validateCellConfiguration(next, document);
|
|
1303
1314
|
if (!validation.ok)
|
|
1304
1315
|
throw new Error(validation.message);
|
|
1316
|
+
edited.previous = cell;
|
|
1317
|
+
edited.next = reconciled;
|
|
1305
1318
|
return next;
|
|
1306
1319
|
});
|
|
1307
1320
|
if (!found)
|
|
@@ -1312,6 +1325,8 @@ export function videobookDomainDefs(engine, books) {
|
|
|
1312
1325
|
});
|
|
1313
1326
|
return markDescendantsStale(updated, String(args.cell_id));
|
|
1314
1327
|
}, { cellId: args.cell_id });
|
|
1328
|
+
if (result.ok && edited.next)
|
|
1329
|
+
rememberNotebookStickySettings(engine, String(args.notebook_id), edited.next, edited.previous);
|
|
1315
1330
|
return result.ok
|
|
1316
1331
|
? json({ cell_id: args.cell_id, revision: result.value.hash })
|
|
1317
1332
|
: failure(result.error.message);
|
package/dist/usage-providers.js
CHANGED
|
@@ -53,13 +53,13 @@ export function createFreeMediaUpload(options = {}) {
|
|
|
53
53
|
return capturedProvider("free-media-upload", (fetch) => freemediaupload({ ...options, fetch }), options?.fetch);
|
|
54
54
|
}
|
|
55
55
|
export function uploadFalFile(options, input) {
|
|
56
|
-
return withHarCapture({ provider: "fal", endpoint: "
|
|
56
|
+
return withHarCapture({ provider: "fal", endpoint: "storage.upload.initiate", input }, (fetch) => falUpload(fal({ ...options, fetch }), input), providerUsageFetch("fal", options.fetch));
|
|
57
57
|
}
|
|
58
58
|
export function uploadAlibabaFile(options, input) {
|
|
59
|
-
return withHarCapture({ provider: "alibaba", endpoint: "
|
|
59
|
+
return withHarCapture({ provider: "alibaba", endpoint: "api.v1.uploads", input }, (fetch) => alibabaUpload(alibaba({ ...options, fetch }), input), providerUsageFetch("alibaba", options.fetch));
|
|
60
60
|
}
|
|
61
61
|
export function uploadKieFile(options, file, filename) {
|
|
62
|
-
return withHarCapture({ provider: "kie", endpoint: "
|
|
62
|
+
return withHarCapture({ provider: "kie", endpoint: "api.fileStreamUpload", input: { file, filename } }, (fetch) => kieUpload(kie({ ...options, fetch }), file, filename), providerUsageFetch("kie", options.fetch));
|
|
63
63
|
}
|
|
64
64
|
export function submitMediaJob(...args) {
|
|
65
65
|
const [provider, request, approval] = args;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "videobook",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Local-first MCP server and web UI for AI video creation: notebooks, generation, editing, rendering and publishing.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -36,20 +36,20 @@
|
|
|
36
36
|
"start": "node dist/index.js"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@apicity/alibaba": "^0.18.
|
|
40
|
-
"@apicity/b2": "^0.18.
|
|
41
|
-
"@apicity/cost": "^0.18.
|
|
42
|
-
"@apicity/dropbox": "^0.18.
|
|
43
|
-
"@apicity/elevenlabs": "^0.18.
|
|
44
|
-
"@apicity/fal": "^0.18.
|
|
45
|
-
"@apicity/free-media-upload": "^0.18.
|
|
46
|
-
"@apicity/har": "^0.18.
|
|
47
|
-
"@apicity/kie": "^0.18.
|
|
48
|
-
"@apicity/kimicoding": "^0.18.
|
|
49
|
-
"@apicity/machgen": "^0.18.
|
|
50
|
-
"@apicity/openai": "^0.18.
|
|
51
|
-
"@apicity/x": "^0.18.
|
|
52
|
-
"@apicity/xai": "^0.18.
|
|
39
|
+
"@apicity/alibaba": "^0.18.1",
|
|
40
|
+
"@apicity/b2": "^0.18.1",
|
|
41
|
+
"@apicity/cost": "^0.18.1",
|
|
42
|
+
"@apicity/dropbox": "^0.18.1",
|
|
43
|
+
"@apicity/elevenlabs": "^0.18.1",
|
|
44
|
+
"@apicity/fal": "^0.18.1",
|
|
45
|
+
"@apicity/free-media-upload": "^0.18.1",
|
|
46
|
+
"@apicity/har": "^0.18.1",
|
|
47
|
+
"@apicity/kie": "^0.18.1",
|
|
48
|
+
"@apicity/kimicoding": "^0.18.1",
|
|
49
|
+
"@apicity/machgen": "^0.18.1",
|
|
50
|
+
"@apicity/openai": "^0.18.1",
|
|
51
|
+
"@apicity/x": "^0.18.1",
|
|
52
|
+
"@apicity/xai": "^0.18.1",
|
|
53
53
|
"@devmehq/open-graph-extractor": "^1.1.1",
|
|
54
54
|
"@ffprobe-installer/ffprobe": "2.1.2",
|
|
55
55
|
"@modelcontextprotocol/client": "^2.2.0",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as F,j as t,a as A}from"./vendor-react-Dj7D1fD4.js";import{u as be,a as pe,V as Se,A as xe,P as Ne}from"./vendor-remotion-CH1HXrlc.js";import{eh as Ce,ei as ke,ej as we,ek as $e,el as Pe,em as de,en as Te,eo as me,ep as Re,eq as Ae,er as Me,es as _e,et as Ee,eu as Oe,ev as fe,by as We}from"./videobook-CsW453sb.js";import{g as Le,a6 as ze,_ as Fe,h as He,X as Ie}from"./vendor-icons-CGqhCIXV.js";import"./vendor-D8XcMav4.js";import"./vendor-mcp-D_C3EZPv.js";const Be={face:"#63c7d8",text:"#f0a860",graphic:"#f0a860"};function De(a){const e=F.c(25),{phrase:s,cue:n,settings:o,sourceWidth:c,sourceHeight:l}=a,{width:i,height:h}=pe();let r,f,m,d;if(e[0]!==h||e[1]!==s.id||e[2]!==s.regions||e[3]!==o||e[4]!==l||e[5]!==c||e[6]!==i){const j={sourceWidth:c,sourceHeight:l,targetWidth:i,targetHeight:h};let v;e[11]!==s.regions||e[12]!==o?(v=new Set($e(s.regions,o)),e[11]=s.regions,e[12]=o,e[13]=v):v=e[13];const C=v;let y;e[14]!==i?(y=Math.round(i/480),e[14]=i,e[15]=y):y=e[15],f=Math.max(2,y),r=xe,e[16]===Symbol.for("react.memo_cache_sentinel")?(m={pointerEvents:"none"},e[16]=m):m=e[16],d=s.regions.map((w,$)=>{const b=Pe(w,j);return t.jsx("div",{style:{position:"absolute",left:b.x*i,top:b.y*h,width:b.width*i,height:b.height*h,border:`${f}px dashed ${Be[w.kind]}`,opacity:C.has(w)?1:.4,borderRadius:f*2}},`${s.id}-${$}`)}),e[0]=h,e[1]=s.id,e[2]=s.regions,e[3]=o,e[4]=l,e[5]=c,e[6]=i,e[7]=r,e[8]=f,e[9]=m,e[10]=d}else r=e[7],f=e[8],m=e[9],d=e[10];let g;e[17]!==n.column||e[18]!==f?(g=t.jsx(Ue,{column:n.column,stroke:f}),e[17]=n.column,e[18]=f,e[19]=g):g=e[19];let u;return e[20]!==r||e[21]!==m||e[22]!==d||e[23]!==g?(u=t.jsxs(r,{style:m,children:[d,g]}),e[20]=r,e[21]=m,e[22]=d,e[23]=g,e[24]=u):u=e[24],u}function Ue(a){const e=F.c(7),{column:s,stroke:n}=a,o=`${Math.max(1,n/2)}px dashed rgba(114, 231, 170, 0.6)`,c=n*2;let l;return e[0]!==s.height||e[1]!==s.width||e[2]!==s.x||e[3]!==s.y||e[4]!==o||e[5]!==c?(l=t.jsx("div",{style:{position:"absolute",left:s.x,top:s.y,width:s.width,height:s.height,border:o,borderRadius:c}}),e[0]=s.height,e[1]=s.width,e[2]=s.x,e[3]=s.y,e[4]=o,e[5]=c,e[6]=l):l=e[6],l}function Ke(a){const e=F.c(34),{mediaUrl:s,sourceWidth:n,sourceHeight:o,cues:c,phrases:l,settings:i,showRegions:h}=a,r=be(),{fps:f,width:m,height:d}=pe();let g;e[0]!==d||e[1]!==o||e[2]!==n||e[3]!==m?(g=ke({sourceWidth:n,sourceHeight:o,targetWidth:m,targetHeight:d}),e[0]=d,e[1]=o,e[2]=n,e[3]=m,e[4]=g):g=e[4];const u=g,j=r/f;let v;e[5]!==c||e[6]!==j?(v=Ce(c,j),e[5]=c,e[6]=j,e[7]=v):v=e[7];const C=v;let y;e[8]!==C||e[9]!==l?(y=C?l.find(M=>M.id===C.id):void 0,e[8]=C,e[9]=l,e[10]=y):y=e[10];const w=y;let $;e[11]===Symbol.for("react.memo_cache_sentinel")?($={background:"#000000"},e[11]=$):$=e[11];let b;e[12]!==u.height||e[13]!==u.width||e[14]!==u.x||e[15]!==u.y?(b={position:"absolute",left:u.x,top:u.y,width:u.width,height:u.height},e[12]=u.height,e[13]=u.width,e[14]=u.x,e[15]=u.y,e[16]=b):b=e[16];let N;e[17]!==s||e[18]!==b?(N=t.jsx(Se,{src:s,style:b}),e[17]=s,e[18]=b,e[19]=N):N=e[19];let P;e[20]!==C||e[21]!==w||e[22]!==i||e[23]!==h||e[24]!==o||e[25]!==n?(P=h&&C&&w&&t.jsx(De,{phrase:w,cue:C,settings:i,sourceWidth:n,sourceHeight:o}),e[20]=C,e[21]=w,e[22]=i,e[23]=h,e[24]=o,e[25]=n,e[26]=P):P=e[26];let p;e[27]!==c||e[28]!==i?(p=t.jsx(we,{cues:c,settings:i,strokeWidth:6,strokeColor:"#000000",shadowBlur:6,shadowOpacity:60}),e[27]=c,e[28]=i,e[29]=p):p=e[29];let k;return e[30]!==N||e[31]!==P||e[32]!==p?(k=t.jsxs(xe,{style:$,children:[N,P,p]}),e[30]=N,e[31]=P,e[32]=p,e[33]=k):k=e[33],k}const ue=[{id:"stack",label:"Stack",hint:"Words land one by one and build a stacked block beside the subject, each line sized to fill the column."},{id:"punch",label:"Punch",hint:"One word at a time, as big as the free space allows. Best on fast verses."},{id:"karaoke",label:"Karaoke",hint:"The whole stacked phrase shows dimmed and lights up word by word."}],Ve=[{id:"pop",label:"Pop"},{id:"slam",label:"Slam"},{id:"rise",label:"Rise"}],qe=[{name:"Green",color:"#72E7AA"},{name:"Pink",color:"#F0B9D0"},{name:"Cyan",color:"#63C7D8"},{name:"Amber",color:"#E7C372"}];function Ge(a,e){if(!a.drifted)return de(a.start);const s=a.driftMs>0?"+":"";return e?`${de(a.start)} · snapped`:`${de(a.start)} · ${s}${a.driftMs}ms`}function Xe(a){const e=F.c(21),{rows:s,phraseLabels:n,activePhrase:o,time:c,snapped:l,onSeek:i}=a;let h;e[0]===Symbol.for("react.memo_cache_sentinel")?(h=t.jsx("h3",{children:"Transcript"}),e[0]=h):h=e[0];let r;e[1]!==s.length?(r=t.jsxs("header",{className:"alive-panel-header",children:[h,t.jsxs("p",{children:[s.length," words · timed to the vocal"]})]}),e[1]=s.length,e[2]=r):r=e[2];let f;if(e[3]!==o||e[4]!==i||e[5]!==n||e[6]!==s||e[7]!==l||e[8]!==c){let g;e[10]!==o||e[11]!==i||e[12]!==s||e[13]!==l||e[14]!==c?(g=(u,j)=>t.jsxs("div",{className:"alive-phrase","data-active":j===o||void 0,children:[t.jsxs("div",{className:"alive-phrase-head",children:[t.jsxs("span",{children:["Phrase ",j+1]}),t.jsx("span",{children:u})]}),t.jsx("div",{className:"alive-phrase-words",children:s.filter(v=>v.phraseIndex===j).map(v=>t.jsxs("button",{type:"button",className:"alive-word","data-active":c>=v.start&&c<v.end||void 0,"data-drifted":v.drifted&&!l||void 0,onClick:()=>i(v.start+.03),children:[t.jsx("span",{children:v.text}),t.jsx("small",{children:Ge(v,l)})]},v.key))})]},`${j}-${u}`),e[10]=o,e[11]=i,e[12]=s,e[13]=l,e[14]=c,e[15]=g):g=e[15],f=n.map(g),e[3]=o,e[4]=i,e[5]=n,e[6]=s,e[7]=l,e[8]=c,e[9]=f}else f=e[9];let m;e[16]!==f?(m=t.jsx("div",{className:"alive-transcript-list",children:f}),e[16]=f,e[17]=m):m=e[17];let d;return e[18]!==r||e[19]!==m?(d=t.jsxs("section",{className:"alive-panel alive-transcript","aria-label":"Transcript",children:[r,m]}),e[18]=r,e[19]=m,e[20]=d):d=e[20],d}function ve(a){const e=F.c(10),{label:s,options:n,value:o,onChange:c}=a;let l;if(e[0]!==c||e[1]!==n||e[2]!==o){let h;e[4]!==c||e[5]!==o?(h=r=>t.jsx("button",{type:"button","aria-pressed":r.id===o,onClick:()=>c(r.id),children:r.label},r.id),e[4]=c,e[5]=o,e[6]=h):h=e[6],l=n.map(h),e[0]=c,e[1]=n,e[2]=o,e[3]=l}else l=e[3];let i;return e[7]!==s||e[8]!==l?(i=t.jsx("div",{className:"alive-segmented",role:"group","aria-label":s,children:l}),e[7]=s,e[8]=l,e[9]=i):i=e[9],i}function re(a){const e=F.c(8),{checked:s,onChange:n,children:o}=a;let c;e[0]!==n?(c=h=>n(h.target.checked),e[0]=n,e[1]=c):c=e[1];let l;e[2]!==s||e[3]!==c?(l=t.jsx("input",{type:"checkbox",checked:s,onChange:c}),e[2]=s,e[3]=c,e[4]=l):l=e[4];let i;return e[5]!==o||e[6]!==l?(i=t.jsxs("label",{className:"alive-toggle",children:[l,o]}),e[5]=o,e[6]=l,e[7]=i):i=e[7],i}function Ye(a){const e=F.c(69),{settings:s,showRegions:n,regionsAnalyzed:o,working:c,onChange:l,onShowRegions:i,onReanalyze:h}=a;let r;e[0]!==s.style?(r=ue.find(S=>S.id===s.style)?.hint,e[0]=s.style,e[1]=r):r=e[1];const f=r;let m;e[2]===Symbol.for("react.memo_cache_sentinel")?(m=t.jsx("h4",{children:"Style"}),e[2]=m):m=e[2];let d;e[3]!==l?(d=S=>l({style:S}),e[3]=l,e[4]=d):d=e[4];let g;e[5]!==s.style||e[6]!==d?(g=t.jsx(ve,{label:"Caption style",options:ue,value:s.style,onChange:d}),e[5]=s.style,e[6]=d,e[7]=g):g=e[7];let u;e[8]!==f?(u=t.jsx("p",{className:"alive-hint",children:f}),e[8]=f,e[9]=u):u=e[9];let j;e[10]!==g||e[11]!==u?(j=t.jsxs("div",{className:"alive-field",children:[m,g,u]}),e[10]=g,e[11]=u,e[12]=j):j=e[12];let v;e[13]===Symbol.for("react.memo_cache_sentinel")?(v=t.jsx("h4",{children:"Word entrance"}),e[13]=v):v=e[13];let C;e[14]!==l?(C=S=>l({motion:S}),e[14]=l,e[15]=C):C=e[15];let y;e[16]!==s.motion||e[17]!==C?(y=t.jsxs("div",{className:"alive-field",children:[v,t.jsx(ve,{label:"Word entrance",options:Ve,value:s.motion,onChange:C})]}),e[16]=s.motion,e[17]=C,e[18]=y):y=e[18];let w;e[19]===Symbol.for("react.memo_cache_sentinel")?(w=t.jsx("h4",{children:"Frame awareness"}),e[19]=w):w=e[19];let $;e[20]!==l?($=S=>l({avoidFaces:S}),e[20]=l,e[21]=$):$=e[21];let b;e[22]!==s.avoidFaces||e[23]!==$?(b=t.jsx(re,{checked:s.avoidFaces,onChange:$,children:"Keep words off faces"}),e[22]=s.avoidFaces,e[23]=$,e[24]=b):b=e[24];let N;e[25]!==l?(N=S=>l({avoidText:S}),e[25]=l,e[26]=N):N=e[26];let P;e[27]!==s.avoidText||e[28]!==N?(P=t.jsx(re,{checked:s.avoidText,onChange:N,children:"Keep words off on-screen text"}),e[27]=s.avoidText,e[28]=N,e[29]=P):P=e[29];let p;e[30]!==i||e[31]!==n?(p=t.jsx(re,{checked:n,onChange:i,children:"Show detected regions"}),e[30]=i,e[31]=n,e[32]=p):p=e[32];let k;e[33]!==o?(k=!o&&t.jsx("p",{className:"alive-hint alive-warning",children:"Face and text detection did not run, so stacks use the default columns. Set OPENAI_API_KEY and re-run the analysis."}),e[33]=o,e[34]=k):k=e[34];let M;e[35]!==b||e[36]!==P||e[37]!==p||e[38]!==k?(M=t.jsxs("div",{className:"alive-field",children:[w,b,P,p,k]}),e[35]=b,e[36]=P,e[37]=p,e[38]=k,e[39]=M):M=e[39];let D;e[40]===Symbol.for("react.memo_cache_sentinel")?(D=t.jsx("h4",{children:"Audio"}),e[40]=D):D=e[40];let O;e[41]!==l?(O=S=>l({energySizing:S}),e[41]=l,e[42]=O):O=e[42];let _;e[43]!==s.energySizing||e[44]!==O?(_=t.jsxs("div",{className:"alive-field",children:[D,t.jsx(re,{checked:s.energySizing,onChange:O,children:"Size words by vocal energy"})]}),e[43]=s.energySizing,e[44]=O,e[45]=_):_=e[45];let H;e[46]===Symbol.for("react.memo_cache_sentinel")?(H=t.jsx("h4",{children:"Hit color"}),e[46]=H):H=e[46];let W;e[47]!==l||e[48]!==s.hitColor?(W=qe.map(S=>t.jsx("button",{type:"button","aria-label":S.name,"aria-pressed":s.hitColor.toUpperCase()===S.color,onClick:()=>l({hitColor:S.color}),children:t.jsx("span",{style:{background:S.color}})},S.color)),e[47]=l,e[48]=s.hitColor,e[49]=W):W=e[49];let R;e[50]===Symbol.for("react.memo_cache_sentinel")?(R=t.jsx("span",{children:"Text"}),e[50]=R):R=e[50];let x;e[51]!==l?(x=S=>l({textColor:S.target.value.toUpperCase()}),e[51]=l,e[52]=x):x=e[52];let L;e[53]!==s.textColor||e[54]!==x?(L=t.jsxs("label",{className:"alive-color-input",children:[R,t.jsx("input",{type:"color",value:s.textColor,onChange:x})]}),e[53]=s.textColor,e[54]=x,e[55]=L):L=e[55];let I;e[56]!==W||e[57]!==L?(I=t.jsxs("div",{className:"alive-field",children:[H,t.jsxs("div",{className:"alive-swatches",children:[W,L]})]}),e[56]=W,e[57]=L,e[58]=I):I=e[58];let z;e[59]!==h||e[60]!==c?(z=t.jsx("div",{className:"alive-field",children:t.jsx("button",{type:"button",className:"alive-secondary",disabled:c,onClick:h,children:"Re-run analysis"})}),e[59]=h,e[60]=c,e[61]=z):z=e[61];let B;return e[62]!==M||e[63]!==_||e[64]!==I||e[65]!==z||e[66]!==j||e[67]!==y?(B=t.jsxs("section",{className:"alive-panel alive-settings","aria-label":"Caption settings",children:[j,y,M,_,I,z]}),e[62]=M,e[63]=_,e[64]=I,e[65]=z,e[66]=j,e[67]=y,e[68]=B):B=e[68],B}const Je=90;function U(a,e){return`${Math.max(0,a)/e*100}%`}function Qe(a,e,s){if(e.count===0)return`All ${s} words already sit on their vocal onsets`;if(a)return`${e.count} words snapped to their vocal onsets`;const n=e.minMs===e.maxMs?`${e.maxMs}`:`${e.minMs}–${e.maxMs}`;return`${e.count} words start ${n} ms off the vocal`}function Ze(a){const e=a>120?10:a>30?5:1,s=[];for(let n=0;n<=a;n+=e)s.push(n);return s}function et(a,e,s){const n=F.c(5),o=A.useRef(null);let c,l;return n[0]!==e||n[1]!==s||n[2]!==a?(c=()=>{const i=o.current;if(!i||!s)return;const h=a/e*i.scrollWidth;(h<i.scrollLeft||h>i.scrollLeft+i.clientWidth*.85)&&(i.scrollLeft=Math.max(0,h-i.clientWidth*.2))},l=[a,e,s],n[0]=e,n[1]=s,n[2]=a,n[3]=c,n[4]=l):(c=n[3],l=n[4]),A.useEffect(c,l),o}function tt(a){const e=F.c(105),{duration:s,fps:n,time:o,playing:c,envelope:l,rows:i,cues:h,activeCue:r,snapped:f,drift:m}=a,d=Math.max(s,.1),g=et(o,d,c);let u;e[0]!==a||e[1]!==d?(u=T=>{const E=T.currentTarget.getBoundingClientRect();a.onSeek((T.clientX-E.left)/E.width*d)},e[0]=a,e[1]=d,e[2]=u):u=e[2];const j=u;let v;e[3]!==a?(v=()=>a.onStep(-1),e[3]=a,e[4]=v):v=e[4];let C;e[5]===Symbol.for("react.memo_cache_sentinel")?(C=t.jsx(Le,{size:16}),e[5]=C):C=e[5];let y;e[6]!==v?(y=t.jsx("button",{type:"button","aria-label":"Previous frame",onClick:v,children:C}),e[6]=v,e[7]=y):y=e[7];const w=c?"Pause":"Play";let $;e[8]!==c?($=c?t.jsx(ze,{size:16}):t.jsx(Fe,{size:16}),e[8]=c,e[9]=$):$=e[9];let b;e[10]!==a.onTogglePlay||e[11]!==w||e[12]!==$?(b=t.jsx("button",{type:"button",className:"alive-play","aria-label":w,onClick:a.onTogglePlay,children:$}),e[10]=a.onTogglePlay,e[11]=w,e[12]=$,e[13]=b):b=e[13];let N;e[14]!==a?(N=()=>a.onStep(1),e[14]=a,e[15]=N):N=e[15];let P;e[16]===Symbol.for("react.memo_cache_sentinel")?(P=t.jsx(He,{size:16}),e[16]=P):P=e[16];let p;e[17]!==N?(p=t.jsx("button",{type:"button","aria-label":"Next frame",onClick:N,children:P}),e[17]=N,e[18]=p):p=e[18];let k;e[19]!==o?(k=de(o),e[19]=o,e[20]=k):k=e[20];let M;e[21]!==k?(M=t.jsx("strong",{className:"alive-clock",children:k}),e[21]=k,e[22]=M):M=e[22];const D=Math.floor(o*n),O=Math.floor(d*n);let _;e[23]!==D||e[24]!==O?(_=t.jsxs("span",{className:"alive-muted",children:["frame ",D," / ",O]}),e[23]=D,e[24]=O,e[25]=_):_=e[25];let H;e[26]===Symbol.for("react.memo_cache_sentinel")?(H=t.jsx("span",{className:"alive-spacer"}),e[26]=H):H=e[26];const W=m.count>0&&!f||void 0;let R;e[27]!==m||e[28]!==i.length||e[29]!==f?(R=Qe(f,m,i.length),e[27]=m,e[28]=i.length,e[29]=f,e[30]=R):R=e[30];let x;e[31]!==W||e[32]!==R?(x=t.jsx("span",{className:"alive-drift","data-drifted":W,children:R}),e[31]=W,e[32]=R,e[33]=x):x=e[33];const L=f?"alive-secondary":"alive-primary alive-warn",I=m.count===0,z=f?"Use transcript timing":"Snap words to audio";let B;e[34]!==a.onToggleSnap||e[35]!==L||e[36]!==I||e[37]!==z?(B=t.jsx("button",{type:"button",className:L,disabled:I,onClick:a.onToggleSnap,children:z}),e[34]=a.onToggleSnap,e[35]=L,e[36]=I,e[37]=z,e[38]=B):B=e[38];let S;e[39]!==M||e[40]!==_||e[41]!==x||e[42]!==B||e[43]!==y||e[44]!==b||e[45]!==p?(S=t.jsxs("div",{className:"alive-transport",children:[y,b,p,M,_,H,x,B]}),e[39]=M,e[40]=_,e[41]=x,e[42]=B,e[43]=y,e[44]=b,e[45]=p,e[46]=S):S=e[46];let ne;e[47]===Symbol.for("react.memo_cache_sentinel")?(ne=t.jsxs("div",{className:"alive-lane-labels","aria-hidden":"true",children:[t.jsx("span",{className:"alive-lane-ruler"}),t.jsx("span",{className:"alive-lane-audio",children:"Audio"}),t.jsx("span",{className:"alive-lane-words",children:"Words"}),t.jsx("span",{className:"alive-lane-stacks",children:"Stacks"})]}),e[47]=ne):ne=e[47];const he=d*Je;let K;e[48]!==he?(K={minWidth:he},e[48]=he,e[49]=K):K=e[49];let V;e[50]!==d?(V=Ze(d).map(T=>t.jsxs("span",{style:{left:U(T,d)},children:[T,"s"]},T)),e[50]=d,e[51]=V):V=e[51];let q;e[52]!==V?(q=t.jsx("div",{className:"alive-lane-ruler",children:V}),e[52]=V,e[53]=q):q=e[53];let G;e[54]!==l?(G=Te(l),e[54]=l,e[55]=G):G=e[55];let X;e[56]!==G?(X=t.jsx("svg",{viewBox:"0 0 1000 100",preserveAspectRatio:"none","aria-hidden":"true",children:t.jsx("path",{d:G})}),e[56]=G,e[57]=X):X=e[57];let Y;e[58]!==i||e[59]!==d||e[60]!==f?(Y=!f&&i.filter(st).map(T=>t.jsx("span",{className:"alive-onset",style:{left:U(T.onset,d)}},T.key)),e[58]=i,e[59]=d,e[60]=f,e[61]=Y):Y=e[61];let J;e[62]!==X||e[63]!==Y?(J=t.jsxs("div",{className:"alive-lane-audio",children:[X,Y]}),e[62]=X,e[63]=Y,e[64]=J):J=e[64];let Q;if(e[65]!==i||e[66]!==d||e[67]!==f||e[68]!==o){let T;e[70]!==d||e[71]!==f||e[72]!==o?(T=E=>t.jsx("span",{className:"alive-chip","data-active":o>=E.start&&o<E.end||void 0,"data-drifted":E.drifted&&!f||void 0,style:{left:U(E.start,d),width:U(E.end-E.start,d)},children:E.text},E.key),e[70]=d,e[71]=f,e[72]=o,e[73]=T):T=e[73],Q=i.map(T),e[65]=i,e[66]=d,e[67]=f,e[68]=o,e[69]=Q}else Q=e[69];let Z;e[74]!==Q?(Z=t.jsx("div",{className:"alive-lane-words",children:Q}),e[74]=Q,e[75]=Z):Z=e[75];let ee;if(e[76]!==r||e[77]!==h||e[78]!==d){let T;e[80]!==r||e[81]!==d?(T=(E,ye)=>t.jsx("span",{className:"alive-stack-bar","data-active":ye===r||void 0,style:{left:U(E.start,d),width:U(E.end-E.start,d)},children:me(E)},E.id),e[80]=r,e[81]=d,e[82]=T):T=e[82],ee=h.map(T),e[76]=r,e[77]=h,e[78]=d,e[79]=ee}else ee=e[79];let te;e[83]!==ee?(te=t.jsx("div",{className:"alive-lane-stacks",children:ee}),e[83]=ee,e[84]=te):te=e[84];let se;e[85]!==d||e[86]!==o?(se=U(o,d),e[85]=d,e[86]=o,e[87]=se):se=e[87];let le;e[88]!==se?(le=t.jsx("span",{className:"alive-playhead",style:{left:se}}),e[88]=se,e[89]=le):le=e[89];let ae;e[90]!==j||e[91]!==K||e[92]!==q||e[93]!==J||e[94]!==Z||e[95]!==te||e[96]!==le?(ae=t.jsxs("div",{className:"alive-lane-tracks",style:K,onClick:j,role:"presentation",children:[q,J,Z,te,le]}),e[90]=j,e[91]=K,e[92]=q,e[93]=J,e[94]=Z,e[95]=te,e[96]=le,e[97]=ae):ae=e[97];let ie;e[98]!==g||e[99]!==ae?(ie=t.jsxs("div",{className:"alive-lanes",children:[ne,t.jsx("div",{className:"alive-lane-scroll",ref:g,children:ae})]}),e[98]=g,e[99]=ae,e[100]=ie):ie=e[100];let oe;e[101]===Symbol.for("react.memo_cache_sentinel")?(oe=t.jsxs("div",{className:"alive-legend","aria-hidden":"true",children:[t.jsxs("span",{children:[t.jsx("i",{className:"alive-legend-chip"}),"Transcript word"]}),t.jsxs("span",{children:[t.jsx("i",{className:"alive-legend-drift"}),"Word off its vocal onset"]}),t.jsxs("span",{children:[t.jsx("i",{className:"alive-legend-onset"}),"Detected vocal onset"]})]}),e[101]=oe):oe=e[101];let ce;return e[102]!==S||e[103]!==ie?(ce=t.jsxs("section",{className:"alive-panel alive-timeline","aria-label":"Caption timeline",children:[S,ie,oe]}),e[102]=S,e[103]=ie,e[104]=ce):ce=e[104],ce}function st(a){return a.drifted}const ge=30;function lt(a){const e=F.c(3),s=A.useRef(null);let n,o;return e[0]!==a?(n=()=>{const c=s.current;return c?.showModal(),c?.querySelector(".alive-close")?.focus(),()=>{c?.close(),We(a)}},o=[a],e[0]=a,e[1]=n,e[2]=o):(n=e[1],o=e[2]),A.useEffect(n,o),s}function at(a){const e=F.c(6),[s,n]=A.useState(0),[o,c]=A.useState(!1);let l,i;e[0]!==a?(l=()=>{const r=a.current;if(!r)return;const f=g=>n(g.detail.frame),m=()=>c(!0),d=()=>c(!1);return r.addEventListener("frameupdate",f),r.addEventListener("play",m),r.addEventListener("pause",d),()=>{r.removeEventListener("frameupdate",f),r.removeEventListener("play",m),r.removeEventListener("pause",d)}},i=[a],e[0]=a,e[1]=l,e[2]=i):(l=e[1],i=e[2]),A.useEffect(l,i);let h;return e[3]!==s||e[4]!==o?(h={frame:s,playing:o},e[3]=s,e[4]=o,e[5]=h):h=e[5],h}function ft(a){const e=F.c(14),{asset:s,state:n,returnFocus:o,onClose:c}=a,l=lt(o),i=`Alive captions for ${s.label}`;let h;e[0]!==c?(h=m=>{m.preventDefault(),c()},e[0]=c,e[1]=h):h=e[1];let r;e[2]!==s.label||e[3]!==c||e[4]!==a||e[5]!==n.data||e[6]!==n.message||e[7]!==n.status?(r=n.status==="ready"?t.jsx(it,{...a,data:n.data}):t.jsxs("div",{className:"alive-studio-message",children:[t.jsx(je,{label:s.label,detail:null,onClose:c}),t.jsx("p",{role:n.status==="error"?"alert":"status",children:n.status==="error"?n.message:"Analysing vocals, phrases and faces…"})]}),e[2]=s.label,e[3]=c,e[4]=a,e[5]=n.data,e[6]=n.message,e[7]=n.status,e[8]=r):r=e[8];let f;return e[9]!==l||e[10]!==i||e[11]!==h||e[12]!==r?(f=t.jsx("dialog",{className:"alive-studio","aria-label":i,onCancel:h,ref:l,children:r}),e[9]=l,e[10]=i,e[11]=h,e[12]=r,e[13]=f):f=e[13],f}function je(a){const e=F.c(12),{label:s,detail:n,onClose:o,children:c}=a;let l;e[0]===Symbol.for("react.memo_cache_sentinel")?(l=t.jsx("h2",{children:"Alive captions"}),e[0]=l):l=e[0];const i=n?` · ${n}`:"";let h;e[1]!==s||e[2]!==i?(h=t.jsxs("span",{className:"alive-muted",children:[s,i]}),e[1]=s,e[2]=i,e[3]=h):h=e[3];let r;e[4]===Symbol.for("react.memo_cache_sentinel")?(r=t.jsx("span",{className:"alive-spacer"}),e[4]=r):r=e[4];let f;e[5]===Symbol.for("react.memo_cache_sentinel")?(f=t.jsx(Ie,{size:16}),e[5]=f):f=e[5];let m;e[6]!==o?(m=t.jsx("button",{type:"button",className:"alive-close","aria-label":"Close alive captions",onClick:o,children:f}),e[6]=o,e[7]=m):m=e[7];let d;return e[8]!==c||e[9]!==h||e[10]!==m?(d=t.jsxs("header",{className:"alive-header",children:[l,h,r,c,m]}),e[8]=c,e[9]=h,e[10]=m,e[11]=d):d=e[11],d}function it({asset:a,data:e,onClose:s,onSave:n,onRender:o,onReanalyze:c}){const{analysis:l}=e,i=Math.round(a.fps??ge)||ge,h=Math.max(1,Math.round(l.durationSeconds*i)),[r,f]=A.useState(e.settings),[m,d]=A.useState(()=>Re(a.width,a.height)),[g,u]=A.useState(!0),[j,v]=A.useState(null),[C,y]=A.useState(null),w=A.useRef(null),{frame:$,playing:b}=at(w),N=$/i,P=A.useMemo(()=>Ae(l,m),[l,m]),p=A.useMemo(()=>Me(l.phrases,r,P),[l.phrases,r,P]),k=A.useMemo(()=>_e(l,r),[l,r]),M=A.useMemo(()=>Ee(k),[k]),D=A.useMemo(()=>({mediaUrl:a.mediaUrl,sourceWidth:l.sourceWidth,sourceHeight:l.sourceHeight,cues:p,phrases:l.phrases,settings:r,showRegions:g}),[a.mediaUrl,l,p,r,g]),O=Oe(p,N),_=x=>w.current?.seekTo(Math.max(0,Math.min(h-1,Math.round(x*i)))),H=x=>f(L=>({...L,...x})),W=async(x,L,I)=>{v(x),y(null);try{await L(),y(I)}catch(z){y(z instanceof Error?z.message:String(z))}finally{v(null)}},R=fe.find(x=>x.id===m)??fe[0];return t.jsxs("div",{className:"alive-studio-body",children:[t.jsxs(je,{label:a.label,detail:`${l.sourceWidth}×${l.sourceHeight} · ${i} fps`,onClose:s,children:[t.jsx("div",{className:"alive-segmented",role:"group","aria-label":"Preview orientation",children:fe.map(x=>t.jsx("button",{type:"button","aria-pressed":x.id===m,onClick:()=>d(x.id),children:x.label},x.id))}),t.jsx("button",{type:"button",className:"alive-secondary",disabled:j!==null,onClick:()=>{W("Saving",()=>n(r),"Saved. Renders of this video now use alive captions.")},children:"Save"}),t.jsxs("button",{type:"button",className:"alive-primary",disabled:j!==null,onClick:()=>{W("Rendering",()=>o(r,m),`Saved and queued a ${R.label} render.`)},children:["Render ",R.label]})]}),t.jsxs("div",{className:"alive-main",children:[t.jsx(Xe,{rows:k,phraseLabels:p.map(me),activePhrase:O,time:N,snapped:r.snapToOnsets,onSeek:_}),t.jsxs("div",{className:"alive-stage",children:[t.jsx("div",{className:"alive-player",style:{aspectRatio:`${R.width} / ${R.height}`},children:t.jsx(Ne,{ref:w,component:Ke,inputProps:D,durationInFrames:h,fps:i,compositionWidth:R.width,compositionHeight:R.height,style:{width:"100%",height:"100%"},clickToPlay:!0,spaceKeyToPlayOrPause:!0})}),t.jsx("p",{className:"alive-status",role:"status",children:j?`${j}…`:C??(O>=0?`${me(p[O])} · ${p[O].lines.length} lines`:"Between phrases")})]}),t.jsx(Ye,{settings:r,showRegions:g,regionsAnalyzed:l.regionsAnalyzed,working:j!==null,onChange:H,onShowRegions:u,onReanalyze:()=>{W("Re-running analysis",c,"Analysis refreshed.")}})]}),t.jsx(tt,{duration:l.durationSeconds,fps:i,time:N,playing:b,envelope:l.envelope,rows:k,cues:p,activeCue:O,snapped:r.snapToOnsets,drift:M,onSeek:_,onStep:x=>_(N+x/i),onTogglePlay:()=>w.current?.toggle(),onToggleSnap:()=>H({snapToOnsets:!r.snapToOnsets})})]})}export{ft as AliveCaptionsStudio};
|
|
1
|
+
import{c as F,j as t,a as A}from"./vendor-react-Dj7D1fD4.js";import{u as be,a as pe,V as Se,A as xe,P as Ne}from"./vendor-remotion-CH1HXrlc.js";import{ei as Ce,ej as ke,ek as we,el as $e,em as Pe,en as de,eo as Te,ep as me,eq as Re,er as Ae,es as Me,et as _e,eu as Ee,ev as Oe,ew as fe,by as We}from"./videobook-b9VODNOA.js";import{g as Le,a6 as ze,_ as Fe,h as He,X as Ie}from"./vendor-icons-D3KrGMJY.js";import"./vendor-BWf-WCsY.js";import"./vendor-mcp-BSR9acpG.js";const Be={face:"#63c7d8",text:"#f0a860",graphic:"#f0a860"};function De(a){const e=F.c(25),{phrase:s,cue:n,settings:o,sourceWidth:c,sourceHeight:l}=a,{width:i,height:h}=pe();let r,f,m,d;if(e[0]!==h||e[1]!==s.id||e[2]!==s.regions||e[3]!==o||e[4]!==l||e[5]!==c||e[6]!==i){const j={sourceWidth:c,sourceHeight:l,targetWidth:i,targetHeight:h};let v;e[11]!==s.regions||e[12]!==o?(v=new Set($e(s.regions,o)),e[11]=s.regions,e[12]=o,e[13]=v):v=e[13];const C=v;let y;e[14]!==i?(y=Math.round(i/480),e[14]=i,e[15]=y):y=e[15],f=Math.max(2,y),r=xe,e[16]===Symbol.for("react.memo_cache_sentinel")?(m={pointerEvents:"none"},e[16]=m):m=e[16],d=s.regions.map((w,$)=>{const b=Pe(w,j);return t.jsx("div",{style:{position:"absolute",left:b.x*i,top:b.y*h,width:b.width*i,height:b.height*h,border:`${f}px dashed ${Be[w.kind]}`,opacity:C.has(w)?1:.4,borderRadius:f*2}},`${s.id}-${$}`)}),e[0]=h,e[1]=s.id,e[2]=s.regions,e[3]=o,e[4]=l,e[5]=c,e[6]=i,e[7]=r,e[8]=f,e[9]=m,e[10]=d}else r=e[7],f=e[8],m=e[9],d=e[10];let g;e[17]!==n.column||e[18]!==f?(g=t.jsx(Ue,{column:n.column,stroke:f}),e[17]=n.column,e[18]=f,e[19]=g):g=e[19];let u;return e[20]!==r||e[21]!==m||e[22]!==d||e[23]!==g?(u=t.jsxs(r,{style:m,children:[d,g]}),e[20]=r,e[21]=m,e[22]=d,e[23]=g,e[24]=u):u=e[24],u}function Ue(a){const e=F.c(7),{column:s,stroke:n}=a,o=`${Math.max(1,n/2)}px dashed rgba(114, 231, 170, 0.6)`,c=n*2;let l;return e[0]!==s.height||e[1]!==s.width||e[2]!==s.x||e[3]!==s.y||e[4]!==o||e[5]!==c?(l=t.jsx("div",{style:{position:"absolute",left:s.x,top:s.y,width:s.width,height:s.height,border:o,borderRadius:c}}),e[0]=s.height,e[1]=s.width,e[2]=s.x,e[3]=s.y,e[4]=o,e[5]=c,e[6]=l):l=e[6],l}function Ke(a){const e=F.c(34),{mediaUrl:s,sourceWidth:n,sourceHeight:o,cues:c,phrases:l,settings:i,showRegions:h}=a,r=be(),{fps:f,width:m,height:d}=pe();let g;e[0]!==d||e[1]!==o||e[2]!==n||e[3]!==m?(g=ke({sourceWidth:n,sourceHeight:o,targetWidth:m,targetHeight:d}),e[0]=d,e[1]=o,e[2]=n,e[3]=m,e[4]=g):g=e[4];const u=g,j=r/f;let v;e[5]!==c||e[6]!==j?(v=Ce(c,j),e[5]=c,e[6]=j,e[7]=v):v=e[7];const C=v;let y;e[8]!==C||e[9]!==l?(y=C?l.find(M=>M.id===C.id):void 0,e[8]=C,e[9]=l,e[10]=y):y=e[10];const w=y;let $;e[11]===Symbol.for("react.memo_cache_sentinel")?($={background:"#000000"},e[11]=$):$=e[11];let b;e[12]!==u.height||e[13]!==u.width||e[14]!==u.x||e[15]!==u.y?(b={position:"absolute",left:u.x,top:u.y,width:u.width,height:u.height},e[12]=u.height,e[13]=u.width,e[14]=u.x,e[15]=u.y,e[16]=b):b=e[16];let N;e[17]!==s||e[18]!==b?(N=t.jsx(Se,{src:s,style:b}),e[17]=s,e[18]=b,e[19]=N):N=e[19];let P;e[20]!==C||e[21]!==w||e[22]!==i||e[23]!==h||e[24]!==o||e[25]!==n?(P=h&&C&&w&&t.jsx(De,{phrase:w,cue:C,settings:i,sourceWidth:n,sourceHeight:o}),e[20]=C,e[21]=w,e[22]=i,e[23]=h,e[24]=o,e[25]=n,e[26]=P):P=e[26];let p;e[27]!==c||e[28]!==i?(p=t.jsx(we,{cues:c,settings:i,strokeWidth:6,strokeColor:"#000000",shadowBlur:6,shadowOpacity:60}),e[27]=c,e[28]=i,e[29]=p):p=e[29];let k;return e[30]!==N||e[31]!==P||e[32]!==p?(k=t.jsxs(xe,{style:$,children:[N,P,p]}),e[30]=N,e[31]=P,e[32]=p,e[33]=k):k=e[33],k}const ue=[{id:"stack",label:"Stack",hint:"Words land one by one and build a stacked block beside the subject, each line sized to fill the column."},{id:"punch",label:"Punch",hint:"One word at a time, as big as the free space allows. Best on fast verses."},{id:"karaoke",label:"Karaoke",hint:"The whole stacked phrase shows dimmed and lights up word by word."}],Ve=[{id:"pop",label:"Pop"},{id:"slam",label:"Slam"},{id:"rise",label:"Rise"}],qe=[{name:"Green",color:"#72E7AA"},{name:"Pink",color:"#F0B9D0"},{name:"Cyan",color:"#63C7D8"},{name:"Amber",color:"#E7C372"}];function Ge(a,e){if(!a.drifted)return de(a.start);const s=a.driftMs>0?"+":"";return e?`${de(a.start)} · snapped`:`${de(a.start)} · ${s}${a.driftMs}ms`}function Xe(a){const e=F.c(21),{rows:s,phraseLabels:n,activePhrase:o,time:c,snapped:l,onSeek:i}=a;let h;e[0]===Symbol.for("react.memo_cache_sentinel")?(h=t.jsx("h3",{children:"Transcript"}),e[0]=h):h=e[0];let r;e[1]!==s.length?(r=t.jsxs("header",{className:"alive-panel-header",children:[h,t.jsxs("p",{children:[s.length," words · timed to the vocal"]})]}),e[1]=s.length,e[2]=r):r=e[2];let f;if(e[3]!==o||e[4]!==i||e[5]!==n||e[6]!==s||e[7]!==l||e[8]!==c){let g;e[10]!==o||e[11]!==i||e[12]!==s||e[13]!==l||e[14]!==c?(g=(u,j)=>t.jsxs("div",{className:"alive-phrase","data-active":j===o||void 0,children:[t.jsxs("div",{className:"alive-phrase-head",children:[t.jsxs("span",{children:["Phrase ",j+1]}),t.jsx("span",{children:u})]}),t.jsx("div",{className:"alive-phrase-words",children:s.filter(v=>v.phraseIndex===j).map(v=>t.jsxs("button",{type:"button",className:"alive-word","data-active":c>=v.start&&c<v.end||void 0,"data-drifted":v.drifted&&!l||void 0,onClick:()=>i(v.start+.03),children:[t.jsx("span",{children:v.text}),t.jsx("small",{children:Ge(v,l)})]},v.key))})]},`${j}-${u}`),e[10]=o,e[11]=i,e[12]=s,e[13]=l,e[14]=c,e[15]=g):g=e[15],f=n.map(g),e[3]=o,e[4]=i,e[5]=n,e[6]=s,e[7]=l,e[8]=c,e[9]=f}else f=e[9];let m;e[16]!==f?(m=t.jsx("div",{className:"alive-transcript-list",children:f}),e[16]=f,e[17]=m):m=e[17];let d;return e[18]!==r||e[19]!==m?(d=t.jsxs("section",{className:"alive-panel alive-transcript","aria-label":"Transcript",children:[r,m]}),e[18]=r,e[19]=m,e[20]=d):d=e[20],d}function ve(a){const e=F.c(10),{label:s,options:n,value:o,onChange:c}=a;let l;if(e[0]!==c||e[1]!==n||e[2]!==o){let h;e[4]!==c||e[5]!==o?(h=r=>t.jsx("button",{type:"button","aria-pressed":r.id===o,onClick:()=>c(r.id),children:r.label},r.id),e[4]=c,e[5]=o,e[6]=h):h=e[6],l=n.map(h),e[0]=c,e[1]=n,e[2]=o,e[3]=l}else l=e[3];let i;return e[7]!==s||e[8]!==l?(i=t.jsx("div",{className:"alive-segmented",role:"group","aria-label":s,children:l}),e[7]=s,e[8]=l,e[9]=i):i=e[9],i}function re(a){const e=F.c(8),{checked:s,onChange:n,children:o}=a;let c;e[0]!==n?(c=h=>n(h.target.checked),e[0]=n,e[1]=c):c=e[1];let l;e[2]!==s||e[3]!==c?(l=t.jsx("input",{type:"checkbox",checked:s,onChange:c}),e[2]=s,e[3]=c,e[4]=l):l=e[4];let i;return e[5]!==o||e[6]!==l?(i=t.jsxs("label",{className:"alive-toggle",children:[l,o]}),e[5]=o,e[6]=l,e[7]=i):i=e[7],i}function Ye(a){const e=F.c(69),{settings:s,showRegions:n,regionsAnalyzed:o,working:c,onChange:l,onShowRegions:i,onReanalyze:h}=a;let r;e[0]!==s.style?(r=ue.find(S=>S.id===s.style)?.hint,e[0]=s.style,e[1]=r):r=e[1];const f=r;let m;e[2]===Symbol.for("react.memo_cache_sentinel")?(m=t.jsx("h4",{children:"Style"}),e[2]=m):m=e[2];let d;e[3]!==l?(d=S=>l({style:S}),e[3]=l,e[4]=d):d=e[4];let g;e[5]!==s.style||e[6]!==d?(g=t.jsx(ve,{label:"Caption style",options:ue,value:s.style,onChange:d}),e[5]=s.style,e[6]=d,e[7]=g):g=e[7];let u;e[8]!==f?(u=t.jsx("p",{className:"alive-hint",children:f}),e[8]=f,e[9]=u):u=e[9];let j;e[10]!==g||e[11]!==u?(j=t.jsxs("div",{className:"alive-field",children:[m,g,u]}),e[10]=g,e[11]=u,e[12]=j):j=e[12];let v;e[13]===Symbol.for("react.memo_cache_sentinel")?(v=t.jsx("h4",{children:"Word entrance"}),e[13]=v):v=e[13];let C;e[14]!==l?(C=S=>l({motion:S}),e[14]=l,e[15]=C):C=e[15];let y;e[16]!==s.motion||e[17]!==C?(y=t.jsxs("div",{className:"alive-field",children:[v,t.jsx(ve,{label:"Word entrance",options:Ve,value:s.motion,onChange:C})]}),e[16]=s.motion,e[17]=C,e[18]=y):y=e[18];let w;e[19]===Symbol.for("react.memo_cache_sentinel")?(w=t.jsx("h4",{children:"Frame awareness"}),e[19]=w):w=e[19];let $;e[20]!==l?($=S=>l({avoidFaces:S}),e[20]=l,e[21]=$):$=e[21];let b;e[22]!==s.avoidFaces||e[23]!==$?(b=t.jsx(re,{checked:s.avoidFaces,onChange:$,children:"Keep words off faces"}),e[22]=s.avoidFaces,e[23]=$,e[24]=b):b=e[24];let N;e[25]!==l?(N=S=>l({avoidText:S}),e[25]=l,e[26]=N):N=e[26];let P;e[27]!==s.avoidText||e[28]!==N?(P=t.jsx(re,{checked:s.avoidText,onChange:N,children:"Keep words off on-screen text"}),e[27]=s.avoidText,e[28]=N,e[29]=P):P=e[29];let p;e[30]!==i||e[31]!==n?(p=t.jsx(re,{checked:n,onChange:i,children:"Show detected regions"}),e[30]=i,e[31]=n,e[32]=p):p=e[32];let k;e[33]!==o?(k=!o&&t.jsx("p",{className:"alive-hint alive-warning",children:"Face and text detection did not run, so stacks use the default columns. Set OPENAI_API_KEY and re-run the analysis."}),e[33]=o,e[34]=k):k=e[34];let M;e[35]!==b||e[36]!==P||e[37]!==p||e[38]!==k?(M=t.jsxs("div",{className:"alive-field",children:[w,b,P,p,k]}),e[35]=b,e[36]=P,e[37]=p,e[38]=k,e[39]=M):M=e[39];let D;e[40]===Symbol.for("react.memo_cache_sentinel")?(D=t.jsx("h4",{children:"Audio"}),e[40]=D):D=e[40];let O;e[41]!==l?(O=S=>l({energySizing:S}),e[41]=l,e[42]=O):O=e[42];let _;e[43]!==s.energySizing||e[44]!==O?(_=t.jsxs("div",{className:"alive-field",children:[D,t.jsx(re,{checked:s.energySizing,onChange:O,children:"Size words by vocal energy"})]}),e[43]=s.energySizing,e[44]=O,e[45]=_):_=e[45];let H;e[46]===Symbol.for("react.memo_cache_sentinel")?(H=t.jsx("h4",{children:"Hit color"}),e[46]=H):H=e[46];let W;e[47]!==l||e[48]!==s.hitColor?(W=qe.map(S=>t.jsx("button",{type:"button","aria-label":S.name,"aria-pressed":s.hitColor.toUpperCase()===S.color,onClick:()=>l({hitColor:S.color}),children:t.jsx("span",{style:{background:S.color}})},S.color)),e[47]=l,e[48]=s.hitColor,e[49]=W):W=e[49];let R;e[50]===Symbol.for("react.memo_cache_sentinel")?(R=t.jsx("span",{children:"Text"}),e[50]=R):R=e[50];let x;e[51]!==l?(x=S=>l({textColor:S.target.value.toUpperCase()}),e[51]=l,e[52]=x):x=e[52];let L;e[53]!==s.textColor||e[54]!==x?(L=t.jsxs("label",{className:"alive-color-input",children:[R,t.jsx("input",{type:"color",value:s.textColor,onChange:x})]}),e[53]=s.textColor,e[54]=x,e[55]=L):L=e[55];let I;e[56]!==W||e[57]!==L?(I=t.jsxs("div",{className:"alive-field",children:[H,t.jsxs("div",{className:"alive-swatches",children:[W,L]})]}),e[56]=W,e[57]=L,e[58]=I):I=e[58];let z;e[59]!==h||e[60]!==c?(z=t.jsx("div",{className:"alive-field",children:t.jsx("button",{type:"button",className:"alive-secondary",disabled:c,onClick:h,children:"Re-run analysis"})}),e[59]=h,e[60]=c,e[61]=z):z=e[61];let B;return e[62]!==M||e[63]!==_||e[64]!==I||e[65]!==z||e[66]!==j||e[67]!==y?(B=t.jsxs("section",{className:"alive-panel alive-settings","aria-label":"Caption settings",children:[j,y,M,_,I,z]}),e[62]=M,e[63]=_,e[64]=I,e[65]=z,e[66]=j,e[67]=y,e[68]=B):B=e[68],B}const Je=90;function U(a,e){return`${Math.max(0,a)/e*100}%`}function Qe(a,e,s){if(e.count===0)return`All ${s} words already sit on their vocal onsets`;if(a)return`${e.count} words snapped to their vocal onsets`;const n=e.minMs===e.maxMs?`${e.maxMs}`:`${e.minMs}–${e.maxMs}`;return`${e.count} words start ${n} ms off the vocal`}function Ze(a){const e=a>120?10:a>30?5:1,s=[];for(let n=0;n<=a;n+=e)s.push(n);return s}function et(a,e,s){const n=F.c(5),o=A.useRef(null);let c,l;return n[0]!==e||n[1]!==s||n[2]!==a?(c=()=>{const i=o.current;if(!i||!s)return;const h=a/e*i.scrollWidth;(h<i.scrollLeft||h>i.scrollLeft+i.clientWidth*.85)&&(i.scrollLeft=Math.max(0,h-i.clientWidth*.2))},l=[a,e,s],n[0]=e,n[1]=s,n[2]=a,n[3]=c,n[4]=l):(c=n[3],l=n[4]),A.useEffect(c,l),o}function tt(a){const e=F.c(105),{duration:s,fps:n,time:o,playing:c,envelope:l,rows:i,cues:h,activeCue:r,snapped:f,drift:m}=a,d=Math.max(s,.1),g=et(o,d,c);let u;e[0]!==a||e[1]!==d?(u=T=>{const E=T.currentTarget.getBoundingClientRect();a.onSeek((T.clientX-E.left)/E.width*d)},e[0]=a,e[1]=d,e[2]=u):u=e[2];const j=u;let v;e[3]!==a?(v=()=>a.onStep(-1),e[3]=a,e[4]=v):v=e[4];let C;e[5]===Symbol.for("react.memo_cache_sentinel")?(C=t.jsx(Le,{size:16}),e[5]=C):C=e[5];let y;e[6]!==v?(y=t.jsx("button",{type:"button","aria-label":"Previous frame",onClick:v,children:C}),e[6]=v,e[7]=y):y=e[7];const w=c?"Pause":"Play";let $;e[8]!==c?($=c?t.jsx(ze,{size:16}):t.jsx(Fe,{size:16}),e[8]=c,e[9]=$):$=e[9];let b;e[10]!==a.onTogglePlay||e[11]!==w||e[12]!==$?(b=t.jsx("button",{type:"button",className:"alive-play","aria-label":w,onClick:a.onTogglePlay,children:$}),e[10]=a.onTogglePlay,e[11]=w,e[12]=$,e[13]=b):b=e[13];let N;e[14]!==a?(N=()=>a.onStep(1),e[14]=a,e[15]=N):N=e[15];let P;e[16]===Symbol.for("react.memo_cache_sentinel")?(P=t.jsx(He,{size:16}),e[16]=P):P=e[16];let p;e[17]!==N?(p=t.jsx("button",{type:"button","aria-label":"Next frame",onClick:N,children:P}),e[17]=N,e[18]=p):p=e[18];let k;e[19]!==o?(k=de(o),e[19]=o,e[20]=k):k=e[20];let M;e[21]!==k?(M=t.jsx("strong",{className:"alive-clock",children:k}),e[21]=k,e[22]=M):M=e[22];const D=Math.floor(o*n),O=Math.floor(d*n);let _;e[23]!==D||e[24]!==O?(_=t.jsxs("span",{className:"alive-muted",children:["frame ",D," / ",O]}),e[23]=D,e[24]=O,e[25]=_):_=e[25];let H;e[26]===Symbol.for("react.memo_cache_sentinel")?(H=t.jsx("span",{className:"alive-spacer"}),e[26]=H):H=e[26];const W=m.count>0&&!f||void 0;let R;e[27]!==m||e[28]!==i.length||e[29]!==f?(R=Qe(f,m,i.length),e[27]=m,e[28]=i.length,e[29]=f,e[30]=R):R=e[30];let x;e[31]!==W||e[32]!==R?(x=t.jsx("span",{className:"alive-drift","data-drifted":W,children:R}),e[31]=W,e[32]=R,e[33]=x):x=e[33];const L=f?"alive-secondary":"alive-primary alive-warn",I=m.count===0,z=f?"Use transcript timing":"Snap words to audio";let B;e[34]!==a.onToggleSnap||e[35]!==L||e[36]!==I||e[37]!==z?(B=t.jsx("button",{type:"button",className:L,disabled:I,onClick:a.onToggleSnap,children:z}),e[34]=a.onToggleSnap,e[35]=L,e[36]=I,e[37]=z,e[38]=B):B=e[38];let S;e[39]!==M||e[40]!==_||e[41]!==x||e[42]!==B||e[43]!==y||e[44]!==b||e[45]!==p?(S=t.jsxs("div",{className:"alive-transport",children:[y,b,p,M,_,H,x,B]}),e[39]=M,e[40]=_,e[41]=x,e[42]=B,e[43]=y,e[44]=b,e[45]=p,e[46]=S):S=e[46];let ne;e[47]===Symbol.for("react.memo_cache_sentinel")?(ne=t.jsxs("div",{className:"alive-lane-labels","aria-hidden":"true",children:[t.jsx("span",{className:"alive-lane-ruler"}),t.jsx("span",{className:"alive-lane-audio",children:"Audio"}),t.jsx("span",{className:"alive-lane-words",children:"Words"}),t.jsx("span",{className:"alive-lane-stacks",children:"Stacks"})]}),e[47]=ne):ne=e[47];const he=d*Je;let K;e[48]!==he?(K={minWidth:he},e[48]=he,e[49]=K):K=e[49];let V;e[50]!==d?(V=Ze(d).map(T=>t.jsxs("span",{style:{left:U(T,d)},children:[T,"s"]},T)),e[50]=d,e[51]=V):V=e[51];let q;e[52]!==V?(q=t.jsx("div",{className:"alive-lane-ruler",children:V}),e[52]=V,e[53]=q):q=e[53];let G;e[54]!==l?(G=Te(l),e[54]=l,e[55]=G):G=e[55];let X;e[56]!==G?(X=t.jsx("svg",{viewBox:"0 0 1000 100",preserveAspectRatio:"none","aria-hidden":"true",children:t.jsx("path",{d:G})}),e[56]=G,e[57]=X):X=e[57];let Y;e[58]!==i||e[59]!==d||e[60]!==f?(Y=!f&&i.filter(st).map(T=>t.jsx("span",{className:"alive-onset",style:{left:U(T.onset,d)}},T.key)),e[58]=i,e[59]=d,e[60]=f,e[61]=Y):Y=e[61];let J;e[62]!==X||e[63]!==Y?(J=t.jsxs("div",{className:"alive-lane-audio",children:[X,Y]}),e[62]=X,e[63]=Y,e[64]=J):J=e[64];let Q;if(e[65]!==i||e[66]!==d||e[67]!==f||e[68]!==o){let T;e[70]!==d||e[71]!==f||e[72]!==o?(T=E=>t.jsx("span",{className:"alive-chip","data-active":o>=E.start&&o<E.end||void 0,"data-drifted":E.drifted&&!f||void 0,style:{left:U(E.start,d),width:U(E.end-E.start,d)},children:E.text},E.key),e[70]=d,e[71]=f,e[72]=o,e[73]=T):T=e[73],Q=i.map(T),e[65]=i,e[66]=d,e[67]=f,e[68]=o,e[69]=Q}else Q=e[69];let Z;e[74]!==Q?(Z=t.jsx("div",{className:"alive-lane-words",children:Q}),e[74]=Q,e[75]=Z):Z=e[75];let ee;if(e[76]!==r||e[77]!==h||e[78]!==d){let T;e[80]!==r||e[81]!==d?(T=(E,ye)=>t.jsx("span",{className:"alive-stack-bar","data-active":ye===r||void 0,style:{left:U(E.start,d),width:U(E.end-E.start,d)},children:me(E)},E.id),e[80]=r,e[81]=d,e[82]=T):T=e[82],ee=h.map(T),e[76]=r,e[77]=h,e[78]=d,e[79]=ee}else ee=e[79];let te;e[83]!==ee?(te=t.jsx("div",{className:"alive-lane-stacks",children:ee}),e[83]=ee,e[84]=te):te=e[84];let se;e[85]!==d||e[86]!==o?(se=U(o,d),e[85]=d,e[86]=o,e[87]=se):se=e[87];let le;e[88]!==se?(le=t.jsx("span",{className:"alive-playhead",style:{left:se}}),e[88]=se,e[89]=le):le=e[89];let ae;e[90]!==j||e[91]!==K||e[92]!==q||e[93]!==J||e[94]!==Z||e[95]!==te||e[96]!==le?(ae=t.jsxs("div",{className:"alive-lane-tracks",style:K,onClick:j,role:"presentation",children:[q,J,Z,te,le]}),e[90]=j,e[91]=K,e[92]=q,e[93]=J,e[94]=Z,e[95]=te,e[96]=le,e[97]=ae):ae=e[97];let ie;e[98]!==g||e[99]!==ae?(ie=t.jsxs("div",{className:"alive-lanes",children:[ne,t.jsx("div",{className:"alive-lane-scroll",ref:g,children:ae})]}),e[98]=g,e[99]=ae,e[100]=ie):ie=e[100];let oe;e[101]===Symbol.for("react.memo_cache_sentinel")?(oe=t.jsxs("div",{className:"alive-legend","aria-hidden":"true",children:[t.jsxs("span",{children:[t.jsx("i",{className:"alive-legend-chip"}),"Transcript word"]}),t.jsxs("span",{children:[t.jsx("i",{className:"alive-legend-drift"}),"Word off its vocal onset"]}),t.jsxs("span",{children:[t.jsx("i",{className:"alive-legend-onset"}),"Detected vocal onset"]})]}),e[101]=oe):oe=e[101];let ce;return e[102]!==S||e[103]!==ie?(ce=t.jsxs("section",{className:"alive-panel alive-timeline","aria-label":"Caption timeline",children:[S,ie,oe]}),e[102]=S,e[103]=ie,e[104]=ce):ce=e[104],ce}function st(a){return a.drifted}const ge=30;function lt(a){const e=F.c(3),s=A.useRef(null);let n,o;return e[0]!==a?(n=()=>{const c=s.current;return c?.showModal(),c?.querySelector(".alive-close")?.focus(),()=>{c?.close(),We(a)}},o=[a],e[0]=a,e[1]=n,e[2]=o):(n=e[1],o=e[2]),A.useEffect(n,o),s}function at(a){const e=F.c(6),[s,n]=A.useState(0),[o,c]=A.useState(!1);let l,i;e[0]!==a?(l=()=>{const r=a.current;if(!r)return;const f=g=>n(g.detail.frame),m=()=>c(!0),d=()=>c(!1);return r.addEventListener("frameupdate",f),r.addEventListener("play",m),r.addEventListener("pause",d),()=>{r.removeEventListener("frameupdate",f),r.removeEventListener("play",m),r.removeEventListener("pause",d)}},i=[a],e[0]=a,e[1]=l,e[2]=i):(l=e[1],i=e[2]),A.useEffect(l,i);let h;return e[3]!==s||e[4]!==o?(h={frame:s,playing:o},e[3]=s,e[4]=o,e[5]=h):h=e[5],h}function ft(a){const e=F.c(14),{asset:s,state:n,returnFocus:o,onClose:c}=a,l=lt(o),i=`Alive captions for ${s.label}`;let h;e[0]!==c?(h=m=>{m.preventDefault(),c()},e[0]=c,e[1]=h):h=e[1];let r;e[2]!==s.label||e[3]!==c||e[4]!==a||e[5]!==n.data||e[6]!==n.message||e[7]!==n.status?(r=n.status==="ready"?t.jsx(it,{...a,data:n.data}):t.jsxs("div",{className:"alive-studio-message",children:[t.jsx(je,{label:s.label,detail:null,onClose:c}),t.jsx("p",{role:n.status==="error"?"alert":"status",children:n.status==="error"?n.message:"Analysing vocals, phrases and faces…"})]}),e[2]=s.label,e[3]=c,e[4]=a,e[5]=n.data,e[6]=n.message,e[7]=n.status,e[8]=r):r=e[8];let f;return e[9]!==l||e[10]!==i||e[11]!==h||e[12]!==r?(f=t.jsx("dialog",{className:"alive-studio","aria-label":i,onCancel:h,ref:l,children:r}),e[9]=l,e[10]=i,e[11]=h,e[12]=r,e[13]=f):f=e[13],f}function je(a){const e=F.c(12),{label:s,detail:n,onClose:o,children:c}=a;let l;e[0]===Symbol.for("react.memo_cache_sentinel")?(l=t.jsx("h2",{children:"Alive captions"}),e[0]=l):l=e[0];const i=n?` · ${n}`:"";let h;e[1]!==s||e[2]!==i?(h=t.jsxs("span",{className:"alive-muted",children:[s,i]}),e[1]=s,e[2]=i,e[3]=h):h=e[3];let r;e[4]===Symbol.for("react.memo_cache_sentinel")?(r=t.jsx("span",{className:"alive-spacer"}),e[4]=r):r=e[4];let f;e[5]===Symbol.for("react.memo_cache_sentinel")?(f=t.jsx(Ie,{size:16}),e[5]=f):f=e[5];let m;e[6]!==o?(m=t.jsx("button",{type:"button",className:"alive-close","aria-label":"Close alive captions",onClick:o,children:f}),e[6]=o,e[7]=m):m=e[7];let d;return e[8]!==c||e[9]!==h||e[10]!==m?(d=t.jsxs("header",{className:"alive-header",children:[l,h,r,c,m]}),e[8]=c,e[9]=h,e[10]=m,e[11]=d):d=e[11],d}function it({asset:a,data:e,onClose:s,onSave:n,onRender:o,onReanalyze:c}){const{analysis:l}=e,i=Math.round(a.fps??ge)||ge,h=Math.max(1,Math.round(l.durationSeconds*i)),[r,f]=A.useState(e.settings),[m,d]=A.useState(()=>Re(a.width,a.height)),[g,u]=A.useState(!0),[j,v]=A.useState(null),[C,y]=A.useState(null),w=A.useRef(null),{frame:$,playing:b}=at(w),N=$/i,P=A.useMemo(()=>Ae(l,m),[l,m]),p=A.useMemo(()=>Me(l.phrases,r,P),[l.phrases,r,P]),k=A.useMemo(()=>_e(l,r),[l,r]),M=A.useMemo(()=>Ee(k),[k]),D=A.useMemo(()=>({mediaUrl:a.mediaUrl,sourceWidth:l.sourceWidth,sourceHeight:l.sourceHeight,cues:p,phrases:l.phrases,settings:r,showRegions:g}),[a.mediaUrl,l,p,r,g]),O=Oe(p,N),_=x=>w.current?.seekTo(Math.max(0,Math.min(h-1,Math.round(x*i)))),H=x=>f(L=>({...L,...x})),W=async(x,L,I)=>{v(x),y(null);try{await L(),y(I)}catch(z){y(z instanceof Error?z.message:String(z))}finally{v(null)}},R=fe.find(x=>x.id===m)??fe[0];return t.jsxs("div",{className:"alive-studio-body",children:[t.jsxs(je,{label:a.label,detail:`${l.sourceWidth}×${l.sourceHeight} · ${i} fps`,onClose:s,children:[t.jsx("div",{className:"alive-segmented",role:"group","aria-label":"Preview orientation",children:fe.map(x=>t.jsx("button",{type:"button","aria-pressed":x.id===m,onClick:()=>d(x.id),children:x.label},x.id))}),t.jsx("button",{type:"button",className:"alive-secondary",disabled:j!==null,onClick:()=>{W("Saving",()=>n(r),"Saved. Renders of this video now use alive captions.")},children:"Save"}),t.jsxs("button",{type:"button",className:"alive-primary",disabled:j!==null,onClick:()=>{W("Rendering",()=>o(r,m),`Saved and queued a ${R.label} render.`)},children:["Render ",R.label]})]}),t.jsxs("div",{className:"alive-main",children:[t.jsx(Xe,{rows:k,phraseLabels:p.map(me),activePhrase:O,time:N,snapped:r.snapToOnsets,onSeek:_}),t.jsxs("div",{className:"alive-stage",children:[t.jsx("div",{className:"alive-player",style:{aspectRatio:`${R.width} / ${R.height}`},children:t.jsx(Ne,{ref:w,component:Ke,inputProps:D,durationInFrames:h,fps:i,compositionWidth:R.width,compositionHeight:R.height,style:{width:"100%",height:"100%"},clickToPlay:!0,spaceKeyToPlayOrPause:!0})}),t.jsx("p",{className:"alive-status",role:"status",children:j?`${j}…`:C??(O>=0?`${me(p[O])} · ${p[O].lines.length} lines`:"Between phrases")})]}),t.jsx(Ye,{settings:r,showRegions:g,regionsAnalyzed:l.regionsAnalyzed,working:j!==null,onChange:H,onShowRegions:u,onReanalyze:()=>{W("Re-running analysis",c,"Analysis refreshed.")}})]}),t.jsx(tt,{duration:l.durationSeconds,fps:i,time:N,playing:b,envelope:l.envelope,rows:k,cues:p,activeCue:O,snapped:r.snapToOnsets,drift:M,onSeek:_,onStep:x=>_(N+x/i),onTogglePlay:()=>w.current?.toggle(),onToggleSnap:()=>H({snapToOnsets:!r.snapToOnsets})})]})}export{ft as AliveCaptionsStudio};
|