videobook 0.2.1 → 0.2.3
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 +41 -0
- package/README.md +7 -8
- package/dist/book-manager.js +40 -2
- package/dist/chat-router.js +1 -1
- package/dist/env-secrets.js +1 -0
- package/dist/guides/seedance_2_prompting_guide.md +1 -1
- package/dist/image-edit-models.js +2 -0
- package/dist/jobs/generate-media.js +18 -6
- package/dist/jobs/run-notebook.js +23 -4
- package/dist/media/adapters/fal.js +7 -0
- package/dist/media/catalog.js +17 -2
- package/dist/media/cost.js +80 -7
- package/dist/media/json-schema.js +7 -0
- package/dist/media/ref-fields.js +11 -3
- package/dist/media/refs.js +13 -0
- package/dist/media/request.js +56 -0
- package/dist/media/seedance-edit.js +9 -0
- package/dist/provider-usage.js +22 -8
- package/dist/tools/estimate-cost.js +8 -5
- package/dist/tools/generate-media.js +2 -1
- package/dist/tools/provider-key-status.js +2 -0
- package/dist/tools/reconcile-project-work.js +2 -1
- package/package.json +13 -13
- package/ui/assets/{alive-captions-e-n3xmCd.js → alive-captions-4QySEGdt.js} +1 -1
- package/ui/assets/confirm-bodies-Bw818V9J.js +1 -0
- package/ui/assets/{fullscreen-VY7f4mJ-.js → fullscreen-CzTnPPG5.js} +1 -1
- package/ui/assets/{goal-ui-B__NgZYz.js → goal-ui-CosrK_ko.js} +2 -2
- package/ui/assets/index-C9xjFEGL.js +37 -0
- package/ui/assets/{inspector-BBuZIaqg.js → inspector-BN2fezh4.js} +1 -1
- package/ui/assets/{jobs-ui-vmEH4zBT.js → jobs-ui-C4Wgy6I1.js} +1 -1
- package/ui/assets/{music-video-CklLKD1R.js → music-video-BSj8SgbQ.js} +1 -1
- package/ui/assets/ui-Cpr6zMTA.js +2 -0
- package/ui/assets/{vendor-flow-DY81i6dC.js → vendor-flow-zBavaNEW.js} +1 -1
- package/ui/assets/{vendor-mcp-BsGNAD4I.js → vendor-mcp-DQ7EusT9.js} +1 -1
- package/ui/assets/vendor-yctIZ9Dz.js +19 -0
- package/ui/assets/videobook-B5G0jMoi.js +20 -0
- package/ui/index.html +11 -11
- package/ui/assets/confirm-bodies-DS6jh0Kb.js +0 -1
- package/ui/assets/index-BPco0HoT.js +0 -37
- package/ui/assets/ui-CtYXY_po.js +0 -2
- package/ui/assets/vendor-OClqq_Da.js +0 -19
- package/ui/assets/videobook-lhLK6e6Q.js +0 -20
package/dist/media/request.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isSeedanceEdit } from "./seedance-edit.js";
|
|
1
2
|
import { insertVideoTimingError, isInsertVideoModel } from "./insert-video-timing.js";
|
|
2
3
|
function clone(value) {
|
|
3
4
|
return value === undefined ? value : structuredClone(value);
|
|
@@ -11,6 +12,15 @@ function childContainer(current, key, nextIsIndex) {
|
|
|
11
12
|
holder[key] = created;
|
|
12
13
|
return created;
|
|
13
14
|
}
|
|
15
|
+
function getPath(target, path) {
|
|
16
|
+
let current = target;
|
|
17
|
+
for (const segment of path.split(".")) {
|
|
18
|
+
if (current === null || typeof current !== "object")
|
|
19
|
+
return undefined;
|
|
20
|
+
current = current[segment];
|
|
21
|
+
}
|
|
22
|
+
return current;
|
|
23
|
+
}
|
|
14
24
|
function setPath(target, path, value) {
|
|
15
25
|
const segments = path.split(".");
|
|
16
26
|
let current = target;
|
|
@@ -66,12 +76,51 @@ function checkRefs(model, refs, mode) {
|
|
|
66
76
|
function refValue(field, url, item) {
|
|
67
77
|
return field.urlObject ? { ...item, url } : url;
|
|
68
78
|
}
|
|
79
|
+
function keyframeIndexes(count, lastFrame) {
|
|
80
|
+
if (count <= 1)
|
|
81
|
+
return [0];
|
|
82
|
+
return Array.from({ length: count }, (_, index) => Math.round((index * lastFrame) / (count - 1)));
|
|
83
|
+
}
|
|
84
|
+
function retimeKeyframeField(model, value, field) {
|
|
85
|
+
const fps = model.entry.keyframeFps;
|
|
86
|
+
if (!fps)
|
|
87
|
+
return;
|
|
88
|
+
const current = getPath(value, field.path);
|
|
89
|
+
if (!Array.isArray(current) || current.length === 0)
|
|
90
|
+
return;
|
|
91
|
+
const duration = typeof value.duration === "number" && Number.isFinite(value.duration) && value.duration > 0
|
|
92
|
+
? value.duration
|
|
93
|
+
: 5;
|
|
94
|
+
const indexes = keyframeIndexes(current.length, Math.round(duration * fps));
|
|
95
|
+
setPath(value, field.path, current.map((frame, index) => {
|
|
96
|
+
const imageUrl = typeof frame === "object" && frame !== null && "image_url" in frame
|
|
97
|
+
? frame.image_url
|
|
98
|
+
: frame;
|
|
99
|
+
return { image_url: imageUrl, frame_index: indexes[index] };
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
function retimeKeyframes(model, value) {
|
|
103
|
+
if (!model.entry.keyframeFps)
|
|
104
|
+
return;
|
|
105
|
+
for (const slot of model.slots) {
|
|
106
|
+
for (const field of slot.fields) {
|
|
107
|
+
if (field.keyframe)
|
|
108
|
+
retimeKeyframeField(model, value, field);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
69
112
|
function placeSlot(model, slot, value, urls) {
|
|
70
113
|
const item = model.entry.refItem?.[slot.role];
|
|
71
114
|
let cursor = 0;
|
|
72
115
|
for (const field of slot.fields) {
|
|
73
116
|
if (cursor >= urls.length)
|
|
74
117
|
return;
|
|
118
|
+
if (field.keyframe) {
|
|
119
|
+
const taken = field.max === null ? urls.slice(cursor) : urls.slice(cursor, cursor + field.max);
|
|
120
|
+
setPath(value, field.path, taken.map((url) => ({ image_url: url, frame_index: 0 })));
|
|
121
|
+
cursor += taken.length;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
75
124
|
if (!field.multi) {
|
|
76
125
|
setPath(value, field.path, refValue(field, urls[cursor], item));
|
|
77
126
|
cursor += 1;
|
|
@@ -162,6 +211,8 @@ export function buildWireRequest(model, call) {
|
|
|
162
211
|
const refError = checkRefs(model, refs, call.mode);
|
|
163
212
|
if (refError)
|
|
164
213
|
return { ok: false, error: refError };
|
|
214
|
+
if (isSeedanceEdit(model.id, call.mode) && refs.video?.length !== 1)
|
|
215
|
+
return { ok: false, error: "Seedance Edit video requires exactly one source video (4–30 seconds)." };
|
|
165
216
|
const promptError = checkPrompt(model, call.prompt);
|
|
166
217
|
if (promptError)
|
|
167
218
|
return { ok: false, error: promptError };
|
|
@@ -172,6 +223,11 @@ export function buildWireRequest(model, call) {
|
|
|
172
223
|
if (optionError)
|
|
173
224
|
return { ok: false, error: optionError };
|
|
174
225
|
applyFrameOptions(model, value, refs, call.mode);
|
|
226
|
+
retimeKeyframes(model, value);
|
|
227
|
+
if (isSeedanceEdit(model.id, call.mode)) {
|
|
228
|
+
value.aspect_ratio = "adaptive";
|
|
229
|
+
value.duration = -1;
|
|
230
|
+
}
|
|
175
231
|
const prompt = call.prompt?.trim();
|
|
176
232
|
if (model.promptField && prompt)
|
|
177
233
|
setPath(value, model.promptField, prompt);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const SEEDANCE_EDIT_DESCRIPTION = "Edit video follows the source aspect ratio and duration. Connect one 4–30 second video plus optional image or audio references.";
|
|
2
|
+
export function isSeedanceEdit(model, mode) {
|
|
3
|
+
return model === "kie:bytedance/seedance-2-5" && mode === "v2v";
|
|
4
|
+
}
|
|
5
|
+
export function seedanceEditFailure(model, message) {
|
|
6
|
+
if (model !== "kie:bytedance/seedance-2-5" || !/video edit/i.test(message))
|
|
7
|
+
return message;
|
|
8
|
+
return `${message} Select Edit video (mode v2v) with one 4–30 second source video; this sets aspect_ratio=adaptive and duration=-1. Review the preview before retrying.`;
|
|
9
|
+
}
|
package/dist/provider-usage.js
CHANGED
|
@@ -3,6 +3,8 @@ import { readFileSync } from "node:fs";
|
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { createCost, PRICING, PRICING_AS_OF } from "@apicity/cost";
|
|
6
|
+
import { modelEntry } from "./media/catalog.js";
|
|
7
|
+
import { estimateFalRequest } from "./media/cost.js";
|
|
6
8
|
import { currentBookContext } from "./book-context.js";
|
|
7
9
|
function installedPackageVersion(name) {
|
|
8
10
|
let dir = dirname(fileURLToPath(import.meta.resolve(name)));
|
|
@@ -90,16 +92,27 @@ function tokenPrice(provider, model, tokens) {
|
|
|
90
92
|
const usd = ((tokens.inputTokens - cached) * rate.rate.input + cached * (rate.rate.cacheRead ?? rate.rate.input) + tokens.outputTokens * rate.rate.output) / 1e6;
|
|
91
93
|
return { ...unknownPrice([]), costUsd: usd, basis: "estimated", rateSource: rate.source.url, unit: "tokens", units: tokens.inputTokens + tokens.outputTokens };
|
|
92
94
|
}
|
|
93
|
-
function
|
|
95
|
+
function historicalAverage(warnings) {
|
|
96
|
+
return warnings.length > 0 && warnings.every((warning) => warning.includes("historical average per call"));
|
|
97
|
+
}
|
|
98
|
+
async function priceRequest(provider, model, payload, endpoint, hints) {
|
|
94
99
|
try {
|
|
95
100
|
const request = { provider, payload, ...(provider === "fal" ? { endpoint } : {}), ...(hints ? { costHints: hints } : {}) };
|
|
96
|
-
const estimate =
|
|
97
|
-
|
|
101
|
+
const estimate = provider === "fal"
|
|
102
|
+
? await estimateFalRequest(endpoint, payload, hints)
|
|
103
|
+
: cost.estimate(request);
|
|
104
|
+
const historical = estimate.usd > 0 && historicalAverage(estimate.warnings);
|
|
105
|
+
if (!historical && (estimate.warnings.length || estimate.source === "tokens-heuristic+table")) {
|
|
98
106
|
return unknownPrice(estimate.warnings.length ? estimate.warnings : ["Waiting for reported token usage"]);
|
|
107
|
+
}
|
|
99
108
|
return {
|
|
100
|
-
...unknownPrice(
|
|
101
|
-
|
|
102
|
-
|
|
109
|
+
...unknownPrice(historical ? estimate.warnings : []),
|
|
110
|
+
costUsd: estimate.usd,
|
|
111
|
+
basis: estimate.source === "free" ? "free" : "estimated",
|
|
112
|
+
rateSource: rateFor(provider, model)?.source.url ?? null,
|
|
113
|
+
pricingVersion: `apicity-${COST_PACKAGE_VERSION}:${estimate.rateAsOf ?? (historical ? "fal-historical" : PRICING_AS_OF)}`,
|
|
114
|
+
units: estimate.breakdown.units ?? null,
|
|
115
|
+
unit: estimate.breakdown.unit ?? null,
|
|
103
116
|
};
|
|
104
117
|
}
|
|
105
118
|
catch {
|
|
@@ -127,7 +140,8 @@ function isBillable(provider, path, method) {
|
|
|
127
140
|
if (provider === "kie")
|
|
128
141
|
return /\/(createTask|veo\/(generate|extend))$/u.test(path);
|
|
129
142
|
if (provider === "fal")
|
|
130
|
-
return
|
|
143
|
+
return !/\/requests\//u.test(path)
|
|
144
|
+
&& (/^\/(fal-ai|alibaba)\//u.test(path) || modelEntry(`fal:${path.slice(1)}`) !== undefined);
|
|
131
145
|
if (provider === "alibaba")
|
|
132
146
|
return path.includes("/services/aigc/");
|
|
133
147
|
if (provider === "elevenlabs")
|
|
@@ -238,7 +252,7 @@ export function providerUsageFetch(provider, transport = fetch) {
|
|
|
238
252
|
id: randomUUID(), provider, model, activity, status: "pending",
|
|
239
253
|
tokenBased: /\/(responses|completions|embeddings)$/u.test(url.pathname) || rateFor(provider, model)?.kind === "tokens",
|
|
240
254
|
operation: context.operation ?? null, artifactId: context.artifactId ?? null,
|
|
241
|
-
...priceRequest(provider, model, payload, endpoint, hints),
|
|
255
|
+
...await priceRequest(provider, model, payload, endpoint, hints),
|
|
242
256
|
};
|
|
243
257
|
safeRecord(engine, entry);
|
|
244
258
|
}
|
|
@@ -5,7 +5,7 @@ import { previewPlaceholderUrl } from "../preview-payload.js";
|
|
|
5
5
|
import { DEFAULT_IMAGE_EDIT_MODEL_ID, findImageEditModel } from "../image-edit-models.js";
|
|
6
6
|
import { tryResolveModel } from "../media/descriptor.js";
|
|
7
7
|
import { estimateGeneration } from "../media/cost.js";
|
|
8
|
-
import { normalizeRefs } from "../media/refs.js";
|
|
8
|
+
import { checkSeedanceEditSource, normalizeRefs } from "../media/refs.js";
|
|
9
9
|
import { REF_ROLES } from "../media/types.js";
|
|
10
10
|
const GENERATION_TOOLS = new Set(["generate_image", "generate_video", "generate_audio"]);
|
|
11
11
|
const REWRITE_MODEL = "gpt-5.6-sol";
|
|
@@ -67,7 +67,10 @@ async function estimateMedia(engine, input) {
|
|
|
67
67
|
const options = input.options !== null && typeof input.options === "object" && !Array.isArray(input.options)
|
|
68
68
|
? input.options
|
|
69
69
|
: {};
|
|
70
|
-
const
|
|
70
|
+
const sourceError = await checkSeedanceEditSource(engine, model, refs, input.mode);
|
|
71
|
+
if (sourceError)
|
|
72
|
+
return unavailable(sourceError);
|
|
73
|
+
const result = await estimateGeneration(model, {
|
|
71
74
|
prompt: text(input.prompt),
|
|
72
75
|
refUrls: placeholderRefs(refs),
|
|
73
76
|
options,
|
|
@@ -75,7 +78,7 @@ async function estimateMedia(engine, input) {
|
|
|
75
78
|
}, await mediaHints(engine, refs));
|
|
76
79
|
return result.ok ? result.estimate : unavailable(result.error);
|
|
77
80
|
}
|
|
78
|
-
function estimateImageEdit(input) {
|
|
81
|
+
async function estimateImageEdit(input) {
|
|
79
82
|
if (input.model === "sharp/layer-composite" && input.operation === "remove")
|
|
80
83
|
return { ...FREE_ESTIMATE };
|
|
81
84
|
const editModel = findImageEditModel(text(input.model) ?? DEFAULT_IMAGE_EDIT_MODEL_ID);
|
|
@@ -83,7 +86,7 @@ function estimateImageEdit(input) {
|
|
|
83
86
|
if (!model)
|
|
84
87
|
return unavailable(`unknown image edit model '${String(input.model)}'`);
|
|
85
88
|
const imageCount = Array.isArray(input.image_refs) && input.image_refs.length > 0 ? input.image_refs.length : 1;
|
|
86
|
-
const result = estimateGeneration(model, {
|
|
89
|
+
const result = await estimateGeneration(model, {
|
|
87
90
|
prompt: text(input.prompt) ?? "edit",
|
|
88
91
|
refUrls: { image: Array.from({ length: imageCount }, (_, index) => `https://example.test/edit-${index + 1}.png`) },
|
|
89
92
|
});
|
|
@@ -142,7 +145,7 @@ export function estimateCostDef(engine, books) {
|
|
|
142
145
|
};
|
|
143
146
|
return {
|
|
144
147
|
name: "estimate_cost",
|
|
145
|
-
description: "Estimate the USD cost of one or more generate_image, generate_video or generate_audio calls, given as {tool_name, input}, before running them.
|
|
148
|
+
description: "Estimate the USD cost of one or more generate_image, generate_video or generate_audio calls, given as {tool_name, input}, before running them. Dynamically billed fal models use fal's historical average per call when FAL_ADMIN_API_KEY is set, and that estimate warns that it ignores the request. Without that key, or without a published rate, the estimate is $0 with a warning.",
|
|
146
149
|
schema,
|
|
147
150
|
handler: async (args) => {
|
|
148
151
|
const calls = args.calls;
|
|
@@ -4,7 +4,7 @@ import { generationLabel } from "../artifact-label.js";
|
|
|
4
4
|
import { previewPlaceholderUrl } from "../preview-payload.js";
|
|
5
5
|
import { resolveModel, UnknownModelError } from "../media/descriptor.js";
|
|
6
6
|
import { buildWireRequest } from "../media/request.js";
|
|
7
|
-
import { checkInsertVideoTiming, checkRefDurations, checkRefs, normalizeRefs } from "../media/refs.js";
|
|
7
|
+
import { checkSeedanceEditSource, checkInsertVideoTiming, checkRefDurations, checkRefs, normalizeRefs } from "../media/refs.js";
|
|
8
8
|
import { PROVIDER_ENV_KEYS } from "../media/adapters/index.js";
|
|
9
9
|
import { listModels, modelListing } from "../media/listing.js";
|
|
10
10
|
import { OPERATIONS_BY_MEDIA, REF_ROLES } from "../media/types.js";
|
|
@@ -80,6 +80,7 @@ async function validate(engine, model, args, refs) {
|
|
|
80
80
|
return built.error;
|
|
81
81
|
return (await checkRefs(engine, refs))
|
|
82
82
|
?? (await checkInsertVideoTiming(engine, model, refs, optionsOf(args.options)))
|
|
83
|
+
?? (await checkSeedanceEditSource(engine, model, refs, args.mode))
|
|
83
84
|
?? checkRefDurations(engine, model, refs);
|
|
84
85
|
}
|
|
85
86
|
async function enqueueGeneration(engine, model, args, refs) {
|
|
@@ -13,6 +13,7 @@ const KEY_REGISTRY = {
|
|
|
13
13
|
DROPBOX_CLIENT_SECRET: { provider: "dropbox", label: "Dropbox OAuth" },
|
|
14
14
|
KIMI_CODING_API_KEY: { provider: "kimicoding", label: "Kimi Coding" },
|
|
15
15
|
FAL_API_KEY: { provider: "fal", label: "FAL" },
|
|
16
|
+
FAL_ADMIN_API_KEY: { provider: "fal", label: "FAL admin" },
|
|
16
17
|
DASHSCOPE_API_KEY: { provider: "dashscope", label: "DashScope" },
|
|
17
18
|
B2_ACCESS_KEY_ID: { provider: "b2", label: "Backblaze B2" },
|
|
18
19
|
B2_SECRET_ACCESS_KEY: { provider: "b2", label: "Backblaze B2" },
|
|
@@ -32,6 +33,7 @@ const ROW_ORDER = [
|
|
|
32
33
|
"DROPBOX_CLIENT_SECRET",
|
|
33
34
|
"KIMI_CODING_API_KEY",
|
|
34
35
|
"FAL_API_KEY",
|
|
36
|
+
"FAL_ADMIN_API_KEY",
|
|
35
37
|
"DASHSCOPE_API_KEY",
|
|
36
38
|
"B2_ACCESS_KEY_ID",
|
|
37
39
|
"B2_SECRET_ACCESS_KEY",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { seedanceEditFailure } from "../media/seedance-edit.js";
|
|
1
2
|
import { createKie, createXai, createAlibaba, createFal } from "../usage-providers.js";
|
|
2
3
|
import { describeFalError } from "../jobs/_fal-shared.js";
|
|
3
4
|
import { currentBookContext, withBookContext } from "../book-context.js";
|
|
@@ -1276,7 +1277,7 @@ async function processKieTaskResult(engine, task, taskInfo, result, bookId) {
|
|
|
1276
1277
|
result.completed.push({ assetId: task.artifactId, taskType: task.taskType, jobId });
|
|
1277
1278
|
}
|
|
1278
1279
|
else if (data?.state === "fail") {
|
|
1279
|
-
const failMsg = data.failMsg ?? "unknown error";
|
|
1280
|
+
const failMsg = seedanceEditFailure(task.meta?.model, data.failMsg ?? "unknown error");
|
|
1280
1281
|
// A kie 500 is only retryable while the task is still in flight; once it
|
|
1281
1282
|
// has terminally completed, surface the failure instead of stranding the
|
|
1282
1283
|
// asset as "working" until the 30m reconciliation timeout. See isTransientKieFailure.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "videobook",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
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,18 +36,18 @@
|
|
|
36
36
|
"start": "node dist/index.js"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@apicity/alibaba": "^0.16.
|
|
40
|
-
"@apicity/b2": "^0.16.
|
|
41
|
-
"@apicity/cost": "^0.16.
|
|
42
|
-
"@apicity/dropbox": "^0.16.
|
|
43
|
-
"@apicity/elevenlabs": "^0.16.
|
|
44
|
-
"@apicity/fal": "^0.16.
|
|
45
|
-
"@apicity/free-media-upload": "^0.16.
|
|
46
|
-
"@apicity/kie": "^0.16.
|
|
47
|
-
"@apicity/kimicoding": "^0.16.
|
|
48
|
-
"@apicity/openai": "^0.16.
|
|
49
|
-
"@apicity/x": "^0.16.
|
|
50
|
-
"@apicity/xai": "^0.16.
|
|
39
|
+
"@apicity/alibaba": "^0.16.3",
|
|
40
|
+
"@apicity/b2": "^0.16.3",
|
|
41
|
+
"@apicity/cost": "^0.16.3",
|
|
42
|
+
"@apicity/dropbox": "^0.16.3",
|
|
43
|
+
"@apicity/elevenlabs": "^0.16.3",
|
|
44
|
+
"@apicity/fal": "^0.16.3",
|
|
45
|
+
"@apicity/free-media-upload": "^0.16.3",
|
|
46
|
+
"@apicity/kie": "^0.16.3",
|
|
47
|
+
"@apicity/kimicoding": "^0.16.3",
|
|
48
|
+
"@apicity/openai": "^0.16.3",
|
|
49
|
+
"@apicity/x": "^0.16.3",
|
|
50
|
+
"@apicity/xai": "^0.16.3",
|
|
51
51
|
"@devmehq/open-graph-extractor": "^1.1.1",
|
|
52
52
|
"@ffprobe-installer/ffprobe": "2.1.2",
|
|
53
53
|
"@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 xe,V as Se,A as pe,P as Ne}from"./vendor-remotion-CH1HXrlc.js";import{ea as Ce,eb as ke,ec as we,ed as $e,ee as Pe,ef as de,eg as Te,eh as me,ei as Re,ej as Ae,ek as Me,el as _e,em as Ee,en as Oe,eo as fe,bu as We}from"./videobook-lhLK6e6Q.js";import{g as Le,a6 as ze,_ as Fe,h as He,X as Ie}from"./vendor-icons-CGqhCIXV.js";import"./vendor-OClqq_Da.js";import"./vendor-mcp-BsGNAD4I.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}=xe();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=pe,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}=xe();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 x;e[27]!==c||e[28]!==i?(x=t.jsx(we,{cues:c,settings:i,strokeWidth:6,strokeColor:"#000000",shadowBlur:6,shadowOpacity:60}),e[27]=c,e[28]=i,e[29]=x):x=e[29];let k;return e[30]!==N||e[31]!==P||e[32]!==x?(k=t.jsxs(pe,{style:$,children:[N,P,x]}),e[30]=N,e[31]=P,e[32]=x,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"}],Ge=[{name:"Green",color:"#72E7AA"},{name:"Pink",color:"#F0B9D0"},{name:"Cyan",color:"#63C7D8"},{name:"Amber",color:"#E7C372"}];function Xe(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 qe(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:Xe(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 x;e[30]!==i||e[31]!==n?(x=t.jsx(re,{checked:n,onChange:i,children:"Show detected regions"}),e[30]=i,e[31]=n,e[32]=x):x=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]!==x||e[38]!==k?(M=t.jsxs("div",{className:"alive-field",children:[w,b,P,x,k]}),e[35]=b,e[36]=P,e[37]=x,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=Ge.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 p;e[51]!==l?(p=S=>l({textColor:S.target.value.toUpperCase()}),e[51]=l,e[52]=p):p=e[52];let L;e[53]!==s.textColor||e[54]!==p?(L=t.jsxs("label",{className:"alive-color-input",children:[R,t.jsx("input",{type:"color",value:s.textColor,onChange:p})]}),e[53]=s.textColor,e[54]=p,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 x;e[17]!==N?(x=t.jsx("button",{type:"button","aria-label":"Next frame",onClick:N,children:P}),e[17]=N,e[18]=x):x=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 p;e[31]!==W||e[32]!==R?(p=t.jsx("span",{className:"alive-drift","data-drifted":W,children:R}),e[31]=W,e[32]=R,e[33]=p):p=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]!==p||e[42]!==B||e[43]!==y||e[44]!==b||e[45]!==x?(S=t.jsxs("div",{className:"alive-transport",children:[y,b,x,M,_,H,p,B]}),e[39]=M,e[40]=_,e[41]=p,e[42]=B,e[43]=y,e[44]=b,e[45]=x,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 G;e[52]!==V?(G=t.jsx("div",{className:"alive-lane-ruler",children:V}),e[52]=V,e[53]=G):G=e[53];let X;e[54]!==l?(X=Te(l),e[54]=l,e[55]=X):X=e[55];let q;e[56]!==X?(q=t.jsx("svg",{viewBox:"0 0 1000 100",preserveAspectRatio:"none","aria-hidden":"true",children:t.jsx("path",{d:X})}),e[56]=X,e[57]=q):q=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]!==q||e[63]!==Y?(J=t.jsxs("div",{className:"alive-lane-audio",children:[q,Y]}),e[62]=q,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]!==G||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:[G,J,Z,te,le]}),e[90]=j,e[91]=K,e[92]=G,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]),x=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:x,phrases:l.phrases,settings:r,showRegions:g}),[a.mediaUrl,l,x,r,g]),O=Oe(x,N),_=p=>w.current?.seekTo(Math.max(0,Math.min(h-1,Math.round(p*i)))),H=p=>f(L=>({...L,...p})),W=async(p,L,I)=>{v(p),y(null);try{await L(),y(I)}catch(z){y(z instanceof Error?z.message:String(z))}finally{v(null)}},R=fe.find(p=>p.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(p=>t.jsx("button",{type:"button","aria-pressed":p.id===m,onClick:()=>d(p.id),children:p.label},p.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(qe,{rows:k,phraseLabels:x.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(x[O])} · ${x[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:x,activeCue:O,snapped:r.snapToOnsets,drift:M,onSeek:_,onStep:p=>_(N+p/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{ed as Ce,ee as ke,ef as we,eg as $e,eh as Pe,ei as de,ej as Te,ek as me,el as Re,em as Ae,en as Me,eo as _e,ep as Ee,eq as Oe,er as fe,bw as We}from"./videobook-B5G0jMoi.js";import{g as Le,a6 as ze,_ as Fe,h as He,X as Ie}from"./vendor-icons-CGqhCIXV.js";import"./vendor-yctIZ9Dz.js";import"./vendor-mcp-DQ7EusT9.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};
|