videobook 0.3.1 → 0.3.2
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 +62 -0
- package/dist/diagnostics.js +9 -3
- package/dist/goal-plan-v3.js +10 -5
- package/dist/jobs/_kie-upload.js +3 -1
- package/dist/jobs/generate-media.js +19 -10
- package/dist/media/catalog.js +5 -5
- package/dist/media/descriptor.js +9 -3
- package/dist/media/listing.js +26 -4
- package/dist/provider-usage.js +24 -9
- package/dist/tools/estimate-cost.js +9 -4
- package/dist/tools/reconcile-project-work.js +3 -3
- package/package.json +15 -15
- package/ui/assets/{alive-captions-CnLK22ED.js → alive-captions-BWk_4aX0.js} +1 -1
- package/ui/assets/{confirm-bodies-BaalBxp1.js → confirm-bodies-CNW9vLsi.js} +1 -1
- package/ui/assets/{fullscreen-DTJQJ6dX.js → fullscreen-ND_H86Ih.js} +1 -1
- package/ui/assets/{goal-ui-CN-kZTEO.js → goal-ui-CCTD4lxi.js} +1 -1
- package/ui/assets/{index-Dp81yChE.js → index-D0ftggO4.js} +2 -2
- package/ui/assets/{inspector-jeyma7HL.js → inspector-BZnbKsEZ.js} +1 -1
- package/ui/assets/{jobs-ui-D6S3LJ4j.js → jobs-ui-BNK0IPSl.js} +1 -1
- package/ui/assets/{music-video-CDqr0X6G.js → music-video-CoOI0cgW.js} +1 -1
- package/ui/assets/{ui-Cqs1-YNg.js → ui-koLWlu0t.js} +1 -1
- package/ui/assets/{vendor-BWf-WCsY.js → vendor-Ca2-b3hB.js} +14 -14
- package/ui/assets/{vendor-flow-DPvi8ynA.js → vendor-flow-C2NYBYCL.js} +1 -1
- package/ui/assets/{vendor-mcp-BSR9acpG.js → vendor-mcp-9gUvOX4H.js} +1 -1
- package/ui/assets/{videobook-b9VODNOA.js → videobook-B8dYNQrG.js} +2 -2
- package/ui/index.html +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,68 @@ and the package uses [Semantic Versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.3.2] - 2026-10-26
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- The KIE Grok Imagine Video 1.5 preview's 1080p tier, priced at $0.04 per
|
|
14
|
+
second. At 1080p it takes exactly one image (`image_urls`); 480p and 720p
|
|
15
|
+
still take more.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Every `@apicity` package is at 0.19.0.
|
|
20
|
+
- The KIE Grok Imagine Video 1.5 preview defaults to 1080p, its highest
|
|
21
|
+
resolution, as `kie:grok-imagine/image-to-video` already does. A request
|
|
22
|
+
with more than one image needs 480p or 720p and is refused before
|
|
23
|
+
anything is spent.
|
|
24
|
+
- The KIE Grok Imagine Video 1.5 preview sends `nsfw_checker: false` by
|
|
25
|
+
default, the default KIE documents and every other KIE video model with
|
|
26
|
+
the setting already sends. 0.3.1 sent `true`; pass `nsfw_checker: true` to
|
|
27
|
+
keep KIE's content filter on.
|
|
28
|
+
- KIE Seedance 2.5 keeps generating audio by default. apicity 0.19.0 now
|
|
29
|
+
defaults `generate_audio` to `false`, but Videobook still sends `true`
|
|
30
|
+
unless a request turns audio off.
|
|
31
|
+
- MachGen estimates follow the 0.19.0 pricebook. A MiniMax H3 run with a
|
|
32
|
+
first and a last frame is priced at the image-to-video rate ($0.035 per
|
|
33
|
+
second at 480p instead of $0.05), and Wan 3.0 references that include a
|
|
34
|
+
video add the reference video's seconds to the output's.
|
|
35
|
+
- KIE OmniHuman 2.0 generations turn KIE's watermark off by default
|
|
36
|
+
(`enable_watermark: false`); pass `enable_watermark: true` to keep it.
|
|
37
|
+
OmniHuman 2.0 videos generated with 0.3.1 carry the watermark. OmniHuman
|
|
38
|
+
1.5 has no watermark option.
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- A catalog model the installed apicity packages cannot resolve no longer
|
|
43
|
+
fails the whole model listing, which left every book looking empty on
|
|
44
|
+
load. The listing skips that model and logs a `model-unresolvable`
|
|
45
|
+
warning naming it.
|
|
46
|
+
- Queued KIE OmniHuman 1.5 and 2.0 generations pass their driving audio's
|
|
47
|
+
length to the cost estimate, so the KIE paygate estimate is bounded and the
|
|
48
|
+
usage row is priced.
|
|
49
|
+
- Queued KIE HappyHorse video edit and Kling 3.0 motion control generations
|
|
50
|
+
pass their source video's length, and Volcengine lip sync passes its audio's
|
|
51
|
+
length, so their paygate estimates and usage rows are priced too.
|
|
52
|
+
`estimate_cost` now prices Volcengine lip sync from the audio, whose length
|
|
53
|
+
the output follows, instead of the source video.
|
|
54
|
+
- The usage counter groups each catalog generation under its catalog media.
|
|
55
|
+
34 KIE and fal models, among them OmniHuman, the HeyGen digital twins, the
|
|
56
|
+
Gemini and ElevenLabs speech models and the Bria image models, were counted
|
|
57
|
+
as analysis, and fal Wan 2.7 image edit as video.
|
|
58
|
+
- KIE Suno music and sound generations now reach the usage counter as audio,
|
|
59
|
+
priced at KIE's flat rate per generation: $0.06 for music and $0.0125 for
|
|
60
|
+
sounds. Their status polls settle the row: a lyrics-only result stays
|
|
61
|
+
pending, and a failed generation is not counted as spend.
|
|
62
|
+
- KIE generations stay pending in the usage counter until their task
|
|
63
|
+
settles. A queuing or generating KIE task, or a Veo task that is still
|
|
64
|
+
generating, was counted as settled spend at its first status poll, and a
|
|
65
|
+
Veo generation that failed while generating (`successFlag` 3) was counted
|
|
66
|
+
as completed spend.
|
|
67
|
+
- A Veo generation that fails while generating now fails with KIE's error
|
|
68
|
+
message at the next status poll. It was treated as still processing and
|
|
69
|
+
polled until the pending-task timeout.
|
|
70
|
+
|
|
9
71
|
## [0.3.1] - 2026-10-25
|
|
10
72
|
|
|
11
73
|
### Added
|
package/dist/diagnostics.js
CHANGED
|
@@ -18,6 +18,7 @@ const EVENTS = [
|
|
|
18
18
|
"watermark-probe-fallback", "generation-error-clear-failed", "timeline-orientation-failed",
|
|
19
19
|
"generation-cost-estimate", "job-error", "semantic-index-deferred",
|
|
20
20
|
"tag-asset-failed", "voice-session-closed", "alive-captions-regions-failed",
|
|
21
|
+
"model-unresolvable",
|
|
21
22
|
];
|
|
22
23
|
const events = new Set(EVENTS);
|
|
23
24
|
const errorCodes = new Set([
|
|
@@ -25,9 +26,14 @@ const errorCodes = new Set([
|
|
|
25
26
|
"EIO", "EMFILE", "ENFILE", "ENOMEM", "ECONNREFUSED", "ECONNRESET",
|
|
26
27
|
"ETIMEDOUT", "EPIPE", "ENOTFOUND", "EADDRINUSE", "EADDRNOTAVAIL", "ABORT_ERR",
|
|
27
28
|
]);
|
|
28
|
-
const names = { tool: new Set(), jobType: new Set() };
|
|
29
|
+
const names = { tool: new Set(), jobType: new Set(), model: new Set() };
|
|
30
|
+
const NAME_PATTERNS = {
|
|
31
|
+
tool: /^[a-z][a-z0-9_]{0,95}$/,
|
|
32
|
+
jobType: /^[a-z][a-z0-9_]{0,95}$/,
|
|
33
|
+
model: /^[a-z][a-z0-9-]{0,31}:[a-z0-9][a-z0-9._/-]{0,159}$/,
|
|
34
|
+
};
|
|
29
35
|
export function registerDiagnosticName(kind, name) {
|
|
30
|
-
if (typeof name === "string" &&
|
|
36
|
+
if (typeof name === "string" && NAME_PATTERNS[kind].test(name))
|
|
31
37
|
names[kind].add(name);
|
|
32
38
|
}
|
|
33
39
|
function ownValue(value, key) {
|
|
@@ -82,7 +88,7 @@ export function diagnosticRecord(event, fields = {}) {
|
|
|
82
88
|
if (typeof value === "string" && ENUM_FIELDS[key].includes(value))
|
|
83
89
|
result[key] = value;
|
|
84
90
|
}
|
|
85
|
-
for (const key of ["tool", "jobType"]) {
|
|
91
|
+
for (const key of ["tool", "jobType", "model"]) {
|
|
86
92
|
const value = ownValue(fields, key);
|
|
87
93
|
if (typeof value === "string" && names[key].has(value))
|
|
88
94
|
result[key] = value;
|
package/dist/goal-plan-v3.js
CHANGED
|
@@ -5,7 +5,12 @@ import { LIGHTNING_COLD_OPEN_SECONDS, LIGHTNING_SCENE_ASPECT_RATIO, LIGHTNING_SC
|
|
|
5
5
|
const IMAGE_LIMIT = 30;
|
|
6
6
|
const VIDEO_LIMIT = 10;
|
|
7
7
|
const LEGACY_SCENE_RESOLUTION = "2K";
|
|
8
|
+
const SCENE_MODELS = ["kie:nano-banana-2-1"];
|
|
8
9
|
const SCENE_RESOLUTIONS = [LEGACY_SCENE_RESOLUTION, "4K"];
|
|
10
|
+
const SCENE_OUTPUT_FORMATS = ["jpg"];
|
|
11
|
+
const VIDEO_MODELS = ["kie:bytedance/seedance-2-5"];
|
|
12
|
+
const VIDEO_RESOLUTIONS = ["1080p"];
|
|
13
|
+
const VIDEO_OUTPUT_FORMATS = ["mp4"];
|
|
9
14
|
export const goalMediaRefSchema = z.object({
|
|
10
15
|
kind: z.enum(["image", "video"]),
|
|
11
16
|
artifactId: z.string().min(1),
|
|
@@ -22,21 +27,21 @@ export const goalPlanV3Schema = z.object({
|
|
|
22
27
|
scene: z.object({
|
|
23
28
|
prompt: z.string().trim().min(1).max(4000),
|
|
24
29
|
tool: z.literal("generate_image"),
|
|
25
|
-
model: z.
|
|
30
|
+
model: z.enum(SCENE_MODELS),
|
|
26
31
|
aspectRatio: z.enum(["16:9", "9:16", "1:1"]),
|
|
27
32
|
resolution: z.enum(SCENE_RESOLUTIONS),
|
|
28
|
-
outputFormat: z.
|
|
33
|
+
outputFormat: z.enum(SCENE_OUTPUT_FORMATS),
|
|
29
34
|
imageRefs: z.array(goalMediaRefSchema).max(IMAGE_LIMIT),
|
|
30
35
|
}).strict(),
|
|
31
36
|
video: z.object({
|
|
32
37
|
prompt: z.string().trim().min(1).max(4000),
|
|
33
38
|
tool: z.literal("generate_video"),
|
|
34
|
-
model: z.
|
|
39
|
+
model: z.enum(VIDEO_MODELS),
|
|
35
40
|
aspectRatio: z.enum(["16:9", "9:16", "1:1", "adaptive"]),
|
|
36
|
-
resolution: z.
|
|
41
|
+
resolution: z.enum(VIDEO_RESOLUTIONS),
|
|
37
42
|
durationSeconds: z.number().int().min(4).max(30),
|
|
38
43
|
generateAudio: z.literal(true),
|
|
39
|
-
outputFormat: z.
|
|
44
|
+
outputFormat: z.enum(VIDEO_OUTPUT_FORMATS),
|
|
40
45
|
imageRefs: z.array(goalMediaRefSchema).max(IMAGE_LIMIT),
|
|
41
46
|
videoRefs: z.array(goalMediaRefSchema).max(VIDEO_LIMIT),
|
|
42
47
|
}).strict(),
|
package/dist/jobs/_kie-upload.js
CHANGED
|
@@ -2,6 +2,7 @@ import { uploadKieFile } from "../usage-providers.js";
|
|
|
2
2
|
import { prepareAssetForUpload, uploadBytesToFreeHost, } from "../upload.js";
|
|
3
3
|
import { getApiKey } from "../api-key.js";
|
|
4
4
|
import { logger } from "../logger.js";
|
|
5
|
+
import { providerEndpoints } from "../media/endpoints.js";
|
|
5
6
|
// Upload prepared bytes to Kie's native storage via POST /api/file-stream-upload.
|
|
6
7
|
// Kie workers run in China — using their first-party CDN avoids the
|
|
7
8
|
// InvalidParameter.DataInspection failures we'd hit when the free-host URL
|
|
@@ -12,7 +13,8 @@ async function uploadPreparedToKie(data, hashedFilename, contentType) {
|
|
|
12
13
|
if (apiKey) {
|
|
13
14
|
try {
|
|
14
15
|
const blob = new Blob([new Uint8Array(data)], { type: contentType });
|
|
15
|
-
|
|
16
|
+
const uploadBaseURL = providerEndpoints().kieUploadBaseURL;
|
|
17
|
+
return await uploadKieFile({ apiKey, timeout: 120_000, ...(uploadBaseURL ? { uploadBaseURL } : {}) }, blob, hashedFilename);
|
|
16
18
|
}
|
|
17
19
|
catch (err) {
|
|
18
20
|
logger.warn("kie-upload-fallback", { error: err });
|
|
@@ -22,24 +22,33 @@ async function replaceAudioMeta(engine, ref) {
|
|
|
22
22
|
const input = await resolveRefInput(engine, "audio", ref);
|
|
23
23
|
return { replaceAudioWith: { assetId: input.assetId, filename: input.filename } };
|
|
24
24
|
}
|
|
25
|
+
async function sourceAudioSeconds(engine, assetIds) {
|
|
26
|
+
for (const assetId of assetIds) {
|
|
27
|
+
const metadata = await engine.metadata.artifacts.read(assetId, "original");
|
|
28
|
+
const seconds = metadata.ok ? metadata.value.duration : undefined;
|
|
29
|
+
if (typeof seconds === "number" && Number.isFinite(seconds) && seconds > 0)
|
|
30
|
+
return seconds;
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
25
34
|
export async function generationSourceCostHints(engine, refs, job) {
|
|
26
35
|
const draftHints = await seedanceDraftCostHints(engine, job.model, job.options ?? {});
|
|
27
36
|
if (Object.keys(draftHints).length > 0)
|
|
28
37
|
return draftHints;
|
|
38
|
+
const model = resolveModel(job.model);
|
|
39
|
+
if (model.entry.outputLength === "audio") {
|
|
40
|
+
const seconds = await sourceAudioSeconds(engine, refs.sourceAudioIds);
|
|
41
|
+
return seconds === undefined ? {} : { durationSeconds: seconds };
|
|
42
|
+
}
|
|
29
43
|
const videoSeconds = await referenceVideoDuration(engine, refs.sourceVideoIds);
|
|
30
44
|
if (videoSeconds !== undefined) {
|
|
31
|
-
|
|
45
|
+
const followsVideo = model.entry.outputLength === "video" || isSeedanceEdit(job.model, job.mode);
|
|
46
|
+
return { inputDurationSeconds: videoSeconds, ...(followsVideo ? { durationSeconds: videoSeconds } : {}) };
|
|
32
47
|
}
|
|
33
|
-
if (
|
|
48
|
+
if (model.provider !== "fal")
|
|
34
49
|
return {};
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const seconds = metadata.ok ? metadata.value.duration : undefined;
|
|
38
|
-
if (typeof seconds === "number" && Number.isFinite(seconds) && seconds > 0) {
|
|
39
|
-
return { inputDurationSeconds: seconds };
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return {};
|
|
50
|
+
const seconds = await sourceAudioSeconds(engine, refs.sourceAudioIds);
|
|
51
|
+
return seconds === undefined ? {} : { inputDurationSeconds: seconds };
|
|
43
52
|
}
|
|
44
53
|
function generationMeta(job, model, refs) {
|
|
45
54
|
return {
|
package/dist/media/catalog.js
CHANGED
|
@@ -174,7 +174,7 @@ export const MODEL_ENTRIES = [
|
|
|
174
174
|
{ id: "v2v_refs", label: "Edit with references", roles: ["video", "image"], requireAny: ["video"] },
|
|
175
175
|
],
|
|
176
176
|
},
|
|
177
|
-
{ id: "kie:kling-3.0/motion-control", media: "video", operations: ["motion_control"], guide: "kling30", dialect: "natural", defaults: { mode: "720p" } },
|
|
177
|
+
{ id: "kie:kling-3.0/motion-control", media: "video", operations: ["motion_control"], guide: "kling30", dialect: "natural", defaults: { mode: "720p" }, outputLength: "video" },
|
|
178
178
|
{ id: "kie:kling-4.0/reference-to-video", media: "video", operations: ["reference_to_video"], dialect: "kling4" },
|
|
179
179
|
{ id: "kie:kling-4.0/keyframe-to-video", media: "video", operations: ["image_to_video"], dialect: "kling4_keyframes", refs: { image: "keyframe_urls" } },
|
|
180
180
|
{ id: "kie:gemini-omni-video", media: "video", operations: ["image_to_video", "edit_video"], dialect: "natural_source_video", defaults: { duration: "8" }, modes: [{ id: "i2v", label: "Image to video", roles: ["image"] }, { id: "v2v", label: "Edit video", roles: ["video", "image"], requireAny: ["video"] }], refItem: { video: { start: 0, ends: 8 } }, aliases: { clip_start: "video_list.0.start", clip_end: "video_list.0.ends" } },
|
|
@@ -183,13 +183,13 @@ export const MODEL_ENTRIES = [
|
|
|
183
183
|
{ id: "kie:happyhorse-1-1/text-to-video", media: "video", operations: ["text_to_video"] },
|
|
184
184
|
{ id: "kie:happyhorse-1-1/image-to-video", media: "video", operations: ["image_to_video"], dialect: "strip_frames" },
|
|
185
185
|
{ id: "kie:happyhorse-1-1/reference-to-video", media: "video", operations: ["reference_to_video"], dialect: "brackets" },
|
|
186
|
-
{ id: "kie:happyhorse/video-edit", media: "video", operations: ["edit_video"], dialect: "happyhorse_edit" },
|
|
186
|
+
{ id: "kie:happyhorse/video-edit", media: "video", operations: ["edit_video"], dialect: "happyhorse_edit", outputLength: "video" },
|
|
187
187
|
{ id: "kie:minimax-h3/text-to-video", media: "video", operations: ["text_to_video"] },
|
|
188
188
|
{ id: "kie:minimax-h3/image-to-video", media: "video", operations: ["image_to_video"], dialect: "strip_frames" },
|
|
189
189
|
{ id: "kie:minimax-h3/reference-to-video", media: "video", operations: ["reference_to_video"], dialect: "natural", rules: { refDurationMs: MiniMaxH3ReferenceClipDurationMs } },
|
|
190
|
-
{ id: "kie:volcengine/video-to-video-lip-sync", media: "video", operations: ["lip_sync"] },
|
|
191
|
-
{ id: "kie:omnihuman-1-5", media: "video", operations: ["image_to_video", "lip_sync"], dialect: "natural" },
|
|
192
|
-
{ id: "kie:omnihuman-2-0", media: "video", operations: ["image_to_video", "lip_sync"], dialect: "natural" },
|
|
190
|
+
{ id: "kie:volcengine/video-to-video-lip-sync", media: "video", operations: ["lip_sync"], outputLength: "audio" },
|
|
191
|
+
{ id: "kie:omnihuman-1-5", media: "video", operations: ["image_to_video", "lip_sync"], dialect: "natural", outputLength: "audio" },
|
|
192
|
+
{ id: "kie:omnihuman-2-0", media: "video", operations: ["image_to_video", "lip_sync"], dialect: "natural", defaults: { enable_watermark: false }, outputLength: "audio" },
|
|
193
193
|
{ id: "kie:vidu-q4/image-to-video", media: "video", operations: ["image_to_video"], dialect: "natural_kinds" },
|
|
194
194
|
{ id: "kie:vidu-q4/reference-to-video", media: "video", operations: ["reference_to_video"], dialect: "natural_kinds" },
|
|
195
195
|
{ id: "kie:pixverse-v6-max/text-to-video", media: "video", operations: ["text_to_video"], defaults: { quality: "1080p" } },
|
package/dist/media/descriptor.js
CHANGED
|
@@ -139,6 +139,14 @@ function build(entry) {
|
|
|
139
139
|
modes: entry.modes ? [...entry.modes] : defaultModes(slots),
|
|
140
140
|
};
|
|
141
141
|
}
|
|
142
|
+
export function resolveEntry(entry) {
|
|
143
|
+
const cached = cache.get(entry.id);
|
|
144
|
+
if (cached)
|
|
145
|
+
return cached;
|
|
146
|
+
const resolved = build(entry);
|
|
147
|
+
cache.set(entry.id, resolved);
|
|
148
|
+
return resolved;
|
|
149
|
+
}
|
|
142
150
|
export function resolveModel(model) {
|
|
143
151
|
const cached = cache.get(model);
|
|
144
152
|
if (cached)
|
|
@@ -146,9 +154,7 @@ export function resolveModel(model) {
|
|
|
146
154
|
const entry = modelEntry(model);
|
|
147
155
|
if (!entry)
|
|
148
156
|
throw new UnknownModelError(model);
|
|
149
|
-
|
|
150
|
-
cache.set(model, resolved);
|
|
151
|
-
return resolved;
|
|
157
|
+
return resolveEntry(entry);
|
|
152
158
|
}
|
|
153
159
|
export function tryResolveModel(model) {
|
|
154
160
|
try {
|
package/dist/media/listing.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { modelFrontierRankings } from "./frontier.js";
|
|
2
2
|
import { PROVIDER_ENV_KEYS } from "./adapters/index.js";
|
|
3
3
|
import { MODEL_ENTRIES } from "./catalog.js";
|
|
4
|
-
import {
|
|
4
|
+
import { resolveEntry } from "./descriptor.js";
|
|
5
|
+
import { registerDiagnosticName } from "../diagnostics.js";
|
|
6
|
+
import { logger } from "../logger.js";
|
|
5
7
|
export function modelIsHidden(entry) {
|
|
6
8
|
return entry.hidden === true && modelFrontierRankings(entry.id).length === 0;
|
|
7
9
|
}
|
|
@@ -22,10 +24,30 @@ export function modelListing(model) {
|
|
|
22
24
|
frontier: modelFrontierRankings(model.id),
|
|
23
25
|
};
|
|
24
26
|
}
|
|
27
|
+
for (const entry of MODEL_ENTRIES)
|
|
28
|
+
registerDiagnosticName("model", entry.id);
|
|
29
|
+
const unresolvableReported = new Set();
|
|
30
|
+
function reportUnresolvable(entry, error) {
|
|
31
|
+
if (unresolvableReported.has(entry.id))
|
|
32
|
+
return;
|
|
33
|
+
unresolvableReported.add(entry.id);
|
|
34
|
+
logger.warn("model-unresolvable", { model: entry.id, error });
|
|
35
|
+
}
|
|
36
|
+
function resolveOrSkip(entry) {
|
|
37
|
+
try {
|
|
38
|
+
return [resolveEntry(entry)];
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
reportUnresolvable(entry, error);
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export function resolvableModels(entries) {
|
|
46
|
+
return entries.flatMap(resolveOrSkip);
|
|
47
|
+
}
|
|
25
48
|
export function listModels(filter = {}) {
|
|
26
|
-
return MODEL_ENTRIES
|
|
49
|
+
return resolvableModels(MODEL_ENTRIES
|
|
27
50
|
.filter((entry) => filter.includeHidden || !modelIsHidden(entry))
|
|
28
51
|
.filter((entry) => !filter.media || entry.media === filter.media)
|
|
29
|
-
.filter((entry) => !filter.operation || entry.operations.includes(filter.operation))
|
|
30
|
-
.map((entry) => resolveModel(entry.id));
|
|
52
|
+
.filter((entry) => !filter.operation || entry.operations.includes(filter.operation)));
|
|
31
53
|
}
|
package/dist/provider-usage.js
CHANGED
|
@@ -80,8 +80,8 @@ function historicalAverage(warnings) {
|
|
|
80
80
|
}
|
|
81
81
|
async function priceRequest(provider, model, payload, endpoint, hints) {
|
|
82
82
|
try {
|
|
83
|
-
const request = { provider, payload, ...(
|
|
84
|
-
const estimate = provider === "fal"
|
|
83
|
+
const request = { provider, payload, ...(endpoint ? { endpoint } : {}), ...(hints ? { costHints: hints } : {}) };
|
|
84
|
+
const estimate = provider === "fal" && endpoint
|
|
85
85
|
? await estimateFalRequest(endpoint, payload, hints)
|
|
86
86
|
: cost.estimate(request);
|
|
87
87
|
const historical = estimate.usd > 0 && historicalAverage(estimate.warnings);
|
|
@@ -92,7 +92,7 @@ async function priceRequest(provider, model, payload, endpoint, hints) {
|
|
|
92
92
|
...unknownPrice(historical ? estimate.warnings : []),
|
|
93
93
|
costUsd: estimate.usd,
|
|
94
94
|
basis: estimate.source === "free" ? "free" : "estimated",
|
|
95
|
-
rateSource: rateFor(provider, model)?.source.url ?? null,
|
|
95
|
+
rateSource: (rateFor(provider, model) ?? (endpoint ? rateFor(provider, endpoint) : undefined))?.source.url ?? null,
|
|
96
96
|
pricingVersion: `apicity-${COST_PACKAGE_VERSION}:${estimate.rateAsOf ?? (historical ? "fal-historical" : PRICING_AS_OF)}`,
|
|
97
97
|
units: estimate.breakdown.units ?? null,
|
|
98
98
|
unit: estimate.breakdown.unit ?? null,
|
|
@@ -102,11 +102,24 @@ async function priceRequest(provider, model, payload, endpoint, hints) {
|
|
|
102
102
|
return unknownPrice();
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
|
-
|
|
105
|
+
const MEDIA_ACTIVITY = { image: "images", video: "video", audio: "audio" };
|
|
106
|
+
function kieSunoApiId(provider, path) {
|
|
107
|
+
const match = provider === "kie" ? /\/api\/v1\/generate(\/sounds)?$/u.exec(path) : null;
|
|
108
|
+
if (!match)
|
|
109
|
+
return undefined;
|
|
110
|
+
return match[1] ? "suno/sounds-generate" : "suno/generate";
|
|
111
|
+
}
|
|
112
|
+
function catalogMedia(provider, model, path) {
|
|
113
|
+
return modelEntry(provider === "fal" ? `fal:${path.slice(1)}` : `${provider}:${kieSunoApiId(provider, path) ?? model}`)?.media;
|
|
114
|
+
}
|
|
115
|
+
function activityFor(provider, model, path, operation = "") {
|
|
106
116
|
if (/\/(responses|completions)$/u.test(path) && /chat|rewrite_prompt/u.test(operation))
|
|
107
117
|
return "chat";
|
|
108
118
|
if (/transcrib|speech.to.text|analy|describe|tag_|rename|suggest|translate|vision|image.subjects|regions|verify/iu.test(`${operation} ${path}`))
|
|
109
119
|
return "analysis";
|
|
120
|
+
const media = catalogMedia(provider, model, path);
|
|
121
|
+
if (media)
|
|
122
|
+
return MEDIA_ACTIVITY[media];
|
|
110
123
|
if (/video|veo|wan\/|kling|seedance|happyhorse|lipsync/iu.test(`${model} ${path}`))
|
|
111
124
|
return "video";
|
|
112
125
|
if (/audio|speech|music|sound|sfx|suno|vocal/iu.test(`${model} ${path}`))
|
|
@@ -121,7 +134,7 @@ function isBillable(provider, path, method) {
|
|
|
121
134
|
if (provider === "openai" || provider === "xai")
|
|
122
135
|
return /\/(responses|chat\/completions|images\/(generations|edits)|videos\/(generations|edits|extensions)|audio\/(speech|transcriptions|translations)|embeddings|tts|stt)$/u.test(path);
|
|
123
136
|
if (provider === "kie")
|
|
124
|
-
return /\/(createTask|veo\/(generate|extend))$/u.test(path);
|
|
137
|
+
return /\/(createTask|veo\/(generate|extend))$/u.test(path) || kieSunoApiId(provider, path) !== undefined;
|
|
125
138
|
if (provider === "fal")
|
|
126
139
|
return !/\/requests\//u.test(path)
|
|
127
140
|
&& (/^\/(fal-ai|alibaba)\//u.test(path) || modelEntry(`fal:${path.slice(1)}`) !== undefined);
|
|
@@ -169,7 +182,8 @@ function responseStatus(body, accepted) {
|
|
|
169
182
|
const data = object(body.data);
|
|
170
183
|
const output = object(body.output);
|
|
171
184
|
const state = String(body.status ?? data.state ?? data.status ?? output.task_status ?? "").toLowerCase();
|
|
172
|
-
if (body.error || data.failCode || (typeof body.code === "number" && body.code >= 400) || data.successFlag === 2 ||
|
|
185
|
+
if (body.error || data.failCode || (typeof body.code === "number" && body.code >= 400) || data.successFlag === 2 || data.successFlag === 3
|
|
186
|
+
|| ["failed", "fail", "error", "create_task_failed", "generate_audio_failed", "sensitive_word_error"].includes(state))
|
|
173
187
|
return "failed";
|
|
174
188
|
if (["cancelled", "canceled"].includes(state))
|
|
175
189
|
return "cancelled";
|
|
@@ -177,7 +191,8 @@ function responseStatus(body, accepted) {
|
|
|
177
191
|
return "uncertain";
|
|
178
192
|
if (data.successFlag === 1 || ["success", "succeeded", "completed", "done"].includes(state))
|
|
179
193
|
return "completed";
|
|
180
|
-
if (
|
|
194
|
+
if (data.successFlag === 0
|
|
195
|
+
|| ["created", "pending", "queued", "in_queue", "running", "in_progress", "processing", "started", "waiting", "queuing", "generating", "text_success"].includes(state))
|
|
181
196
|
return "pending";
|
|
182
197
|
return accepted ? "pending" : "completed";
|
|
183
198
|
}
|
|
@@ -232,12 +247,12 @@ export function providerUsageFetch(provider, transport = fetch) {
|
|
|
232
247
|
catch {
|
|
233
248
|
void 0;
|
|
234
249
|
}
|
|
235
|
-
const activity = provider === "machgen" ? "video" : activityFor(model, url.pathname, context.operation);
|
|
250
|
+
const activity = provider === "machgen" ? "video" : activityFor(provider, model, url.pathname, context.operation);
|
|
236
251
|
entry = {
|
|
237
252
|
id: randomUUID(), provider, model, activity, status: "pending",
|
|
238
253
|
tokenBased: /\/(responses|completions|embeddings)$/u.test(url.pathname) || rateFor(provider, model)?.kind === "tokens",
|
|
239
254
|
operation: context.operation ?? null, artifactId: context.artifactId ?? null,
|
|
240
|
-
...await priceRequest(provider, model, payload, endpoint, hints),
|
|
255
|
+
...await priceRequest(provider, model, payload, provider === "fal" ? endpoint : kieSunoApiId(provider, url.pathname), hints),
|
|
241
256
|
};
|
|
242
257
|
safeRecord(engine, entry);
|
|
243
258
|
}
|
|
@@ -51,13 +51,18 @@ async function sourceDuration(engine, refs) {
|
|
|
51
51
|
}
|
|
52
52
|
return undefined;
|
|
53
53
|
}
|
|
54
|
-
async function mediaHints(engine, refs) {
|
|
54
|
+
async function mediaHints(engine, refs, model) {
|
|
55
|
+
const audioSeconds = () => sourceDuration(engine, (refs.audio ?? []).filter((ref) => !ref.startsWith("http")));
|
|
56
|
+
if (model.entry.outputLength === "audio") {
|
|
57
|
+
const seconds = await audioSeconds();
|
|
58
|
+
return seconds === undefined ? {} : { durationSeconds: seconds };
|
|
59
|
+
}
|
|
55
60
|
const videos = (refs.video ?? []).filter((ref) => !ref.startsWith("http"));
|
|
56
61
|
const videoSeconds = videos.length > 0 ? await referenceVideoDuration(engine, videos) : undefined;
|
|
57
62
|
if (videoSeconds !== undefined)
|
|
58
63
|
return { inputDurationSeconds: videoSeconds };
|
|
59
|
-
const
|
|
60
|
-
return
|
|
64
|
+
const seconds = await audioSeconds();
|
|
65
|
+
return seconds === undefined ? {} : { inputDurationSeconds: seconds };
|
|
61
66
|
}
|
|
62
67
|
async function estimateMedia(engine, input) {
|
|
63
68
|
const modelId = text(input.model);
|
|
@@ -71,7 +76,7 @@ async function estimateMedia(engine, input) {
|
|
|
71
76
|
const sourceError = await checkSeedanceEditSource(engine, model, refs, input.mode);
|
|
72
77
|
if (sourceError)
|
|
73
78
|
return unavailable(sourceError);
|
|
74
|
-
const hints = { ...await mediaHints(engine, refs), ...await seedanceDraftCostHints(engine, model.id, options) };
|
|
79
|
+
const hints = { ...await mediaHints(engine, refs, model), ...await seedanceDraftCostHints(engine, model.id, options) };
|
|
75
80
|
const result = await estimateGeneration(model, {
|
|
76
81
|
prompt: text(input.prompt),
|
|
77
82
|
refUrls: placeholderRefs(refs),
|
|
@@ -778,7 +778,7 @@ export async function pollPendingProviderTasks(engine, book_id, options = {}) {
|
|
|
778
778
|
try {
|
|
779
779
|
const recordInfo = await provider.veo.get.api.v1.veo.recordInfo(task.taskId);
|
|
780
780
|
const data = recordInfo.data;
|
|
781
|
-
// Veo successFlag: 0=
|
|
781
|
+
// Veo successFlag: 0=generating, 1=success, 2=task creation failed, 3=generation failed
|
|
782
782
|
if (data?.successFlag === 1) {
|
|
783
783
|
const urls = data.response?.resultUrls ?? [];
|
|
784
784
|
if (urls.length === 0) {
|
|
@@ -806,7 +806,7 @@ export async function pollPendingProviderTasks(engine, book_id, options = {}) {
|
|
|
806
806
|
});
|
|
807
807
|
result.completed.push({ assetId: task.artifactId, taskType: task.taskType, jobId });
|
|
808
808
|
}
|
|
809
|
-
else if (data?.successFlag === 2) {
|
|
809
|
+
else if (data?.successFlag === 2 || data?.successFlag === 3) {
|
|
810
810
|
const failMsg = data.errorMessage ?? "Veo task failed";
|
|
811
811
|
result.failed.push({ assetId: task.artifactId, taskType: task.taskType, failMsg, failedAt: new Date().toISOString(), prompt });
|
|
812
812
|
await failPendingTaskAndLog(engine, task.artifactId, task.taskId, { message: failMsg, prompt });
|
|
@@ -816,7 +816,7 @@ export async function pollPendingProviderTasks(engine, book_id, options = {}) {
|
|
|
816
816
|
assetId: task.artifactId,
|
|
817
817
|
taskType: task.taskType,
|
|
818
818
|
progress: 0,
|
|
819
|
-
state:
|
|
819
|
+
state: "waiting",
|
|
820
820
|
prompt,
|
|
821
821
|
startedAt: task.createdAt,
|
|
822
822
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "videobook",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
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.
|
|
40
|
-
"@apicity/b2": "^0.
|
|
41
|
-
"@apicity/cost": "^0.
|
|
42
|
-
"@apicity/dropbox": "^0.
|
|
43
|
-
"@apicity/elevenlabs": "^0.
|
|
44
|
-
"@apicity/fal": "^0.
|
|
45
|
-
"@apicity/free-media-upload": "^0.
|
|
46
|
-
"@apicity/har": "^0.
|
|
47
|
-
"@apicity/kie": "^0.
|
|
48
|
-
"@apicity/kimicoding": "^0.
|
|
49
|
-
"@apicity/machgen": "^0.
|
|
50
|
-
"@apicity/openai": "^0.
|
|
51
|
-
"@apicity/x": "^0.
|
|
52
|
-
"@apicity/xai": "^0.
|
|
39
|
+
"@apicity/alibaba": "^0.19.0",
|
|
40
|
+
"@apicity/b2": "^0.19.0",
|
|
41
|
+
"@apicity/cost": "^0.19.0",
|
|
42
|
+
"@apicity/dropbox": "^0.19.0",
|
|
43
|
+
"@apicity/elevenlabs": "^0.19.0",
|
|
44
|
+
"@apicity/fal": "^0.19.0",
|
|
45
|
+
"@apicity/free-media-upload": "^0.19.0",
|
|
46
|
+
"@apicity/har": "^0.19.0",
|
|
47
|
+
"@apicity/kie": "^0.19.0",
|
|
48
|
+
"@apicity/kimicoding": "^0.19.0",
|
|
49
|
+
"@apicity/machgen": "^0.19.0",
|
|
50
|
+
"@apicity/openai": "^0.19.0",
|
|
51
|
+
"@apicity/x": "^0.19.0",
|
|
52
|
+
"@apicity/xai": "^0.19.0",
|
|
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{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};
|
|
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-B8dYNQrG.js";import{g as Le,a6 as ze,_ as Fe,h as He,X as Ie}from"./vendor-icons-D3KrGMJY.js";import"./vendor-Ca2-b3hB.js";import"./vendor-mcp-9gUvOX4H.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};
|