@bendyline/squisq-video-react 2.4.11 → 2.4.12
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/NOTICE.md +20 -9
- package/THIRD_PARTY_LICENSES.txt +378 -0
- package/dist/{chunk-BRE3IRIM.js → chunk-3EJKBFEK.js} +1 -1
- package/dist/chunk-4GFZ3GUE.js +24645 -0
- package/dist/{chunk-4NI2QIFE.js → chunk-7ZMJ25DC.js} +316 -18
- package/dist/{chunk-JGSJQZGU.js → chunk-BNUM3BXO.js} +39 -3
- package/dist/{chunk-BGS2NEYC.js → chunk-ED7QK6VC.js} +5 -3
- package/dist/{chunk-32QCPFXE.js → chunk-GBIYYDMY.js} +31 -1
- package/dist/chunk-IFQJAW4V.js +321 -0
- package/dist/chunk-SLLH2RTX.js +452 -0
- package/dist/chunk-TL2IMDIZ.js +27 -0
- package/dist/components/index.d.ts +9 -2
- package/dist/components/index.js +6 -5
- package/dist/cover-image/index.js +3 -2
- package/dist/dashboard-image/index.js +2 -1
- package/dist/encoder/index.js +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.js +4 -3
- package/dist/index.d.ts +4 -1
- package/dist/index.js +19 -5
- package/dist/media-edit/index.d.ts +29 -0
- package/dist/media-edit/index.js +15 -0
- package/dist/mediaEditEngine-ZLG7D3TB.js +13 -0
- package/dist/mediaEditRenderManager-W_o6RRhT.d.ts +167 -0
- package/dist/{useVideoExport-B2eVCvTX.d.ts → useVideoExport-DsNDpjmO.d.ts} +7 -1
- package/dist/workers/mediaEdit.worker.d.ts +2 -0
- package/dist/workers/mediaEdit.worker.js +63 -0
- package/package.json +11 -5
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createRnnoiseDenoiserFactory
|
|
3
|
+
} from "./chunk-TL2IMDIZ.js";
|
|
4
|
+
|
|
5
|
+
// src/mediaEdit/mediaEditRenderer.ts
|
|
6
|
+
var inlineDenoiser = createRnnoiseDenoiserFactory(
|
|
7
|
+
() => import("@shiguredo/rnnoise-wasm").then(({ Rnnoise }) => Rnnoise.load())
|
|
8
|
+
);
|
|
9
|
+
async function inlineEngine() {
|
|
10
|
+
return import("./mediaEditEngine-ZLG7D3TB.js");
|
|
11
|
+
}
|
|
12
|
+
function inlineOptions(options) {
|
|
13
|
+
return { ...options, denoiser: options.denoiser ?? inlineDenoiser };
|
|
14
|
+
}
|
|
15
|
+
function defaultWorker() {
|
|
16
|
+
return new Worker(new URL("./workers/mediaEdit.worker.js", import.meta.url), { type: "module" });
|
|
17
|
+
}
|
|
18
|
+
function abortError() {
|
|
19
|
+
return new DOMException("The media-edit job was cancelled.", "AbortError");
|
|
20
|
+
}
|
|
21
|
+
function createMediaEditRenderer(options = {}) {
|
|
22
|
+
let worker;
|
|
23
|
+
let nextId = 1;
|
|
24
|
+
const pending = /* @__PURE__ */ new Map();
|
|
25
|
+
const failAll = (reason) => {
|
|
26
|
+
for (const job of pending.values()) job.reject(reason);
|
|
27
|
+
pending.clear();
|
|
28
|
+
};
|
|
29
|
+
const ensureWorker = () => {
|
|
30
|
+
if (worker !== void 0) return worker;
|
|
31
|
+
try {
|
|
32
|
+
worker = (options.createWorker ?? defaultWorker)();
|
|
33
|
+
} catch {
|
|
34
|
+
worker = null;
|
|
35
|
+
}
|
|
36
|
+
if (worker) {
|
|
37
|
+
worker.onmessage = (event) => {
|
|
38
|
+
const msg = event.data;
|
|
39
|
+
const job = pending.get(msg.id);
|
|
40
|
+
if (!job) return;
|
|
41
|
+
if (msg.type === "progress") {
|
|
42
|
+
job.onProgress?.(msg.fraction);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
pending.delete(msg.id);
|
|
46
|
+
if (msg.type === "error") job.reject(msg.aborted ? abortError() : new Error(msg.message));
|
|
47
|
+
else job.resolve(msg.result);
|
|
48
|
+
};
|
|
49
|
+
worker.onerror = (event) => {
|
|
50
|
+
event.preventDefault();
|
|
51
|
+
worker?.terminate();
|
|
52
|
+
worker = null;
|
|
53
|
+
const orphans = [...pending.values()];
|
|
54
|
+
pending.clear();
|
|
55
|
+
for (const job of orphans) job.inline().then(job.resolve, job.reject);
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return worker;
|
|
59
|
+
};
|
|
60
|
+
function dispatch(request, jobOptions, inline) {
|
|
61
|
+
const target = ensureWorker();
|
|
62
|
+
if (!target) return inline();
|
|
63
|
+
return new Promise((resolve, reject) => {
|
|
64
|
+
if (jobOptions.signal?.aborted) {
|
|
65
|
+
reject(abortError());
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
pending.set(request.id, {
|
|
69
|
+
resolve,
|
|
70
|
+
reject,
|
|
71
|
+
onProgress: jobOptions.onProgress,
|
|
72
|
+
inline
|
|
73
|
+
});
|
|
74
|
+
jobOptions.signal?.addEventListener(
|
|
75
|
+
"abort",
|
|
76
|
+
() => target.postMessage({ type: "cancel", id: request.id }),
|
|
77
|
+
{ once: true }
|
|
78
|
+
);
|
|
79
|
+
target.postMessage(request);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
render(request, jobOptions = {}) {
|
|
84
|
+
return dispatch(
|
|
85
|
+
{ ...request, type: "render", id: nextId++ },
|
|
86
|
+
jobOptions,
|
|
87
|
+
async () => (await inlineEngine()).renderMediaEditAudio(request, inlineOptions(jobOptions))
|
|
88
|
+
);
|
|
89
|
+
},
|
|
90
|
+
analyze(request, jobOptions = {}) {
|
|
91
|
+
return dispatch(
|
|
92
|
+
{ ...request, type: "analyze", id: nextId++ },
|
|
93
|
+
jobOptions,
|
|
94
|
+
async () => (await inlineEngine()).analyzeMediaEditAudio(request, inlineOptions(jobOptions))
|
|
95
|
+
);
|
|
96
|
+
},
|
|
97
|
+
preview(request, jobOptions = {}) {
|
|
98
|
+
return dispatch(
|
|
99
|
+
{ ...request, type: "preview", id: nextId++ },
|
|
100
|
+
jobOptions,
|
|
101
|
+
async () => (await inlineEngine()).previewMediaEditAudio(request, inlineOptions(jobOptions))
|
|
102
|
+
);
|
|
103
|
+
},
|
|
104
|
+
pauses(request, jobOptions = {}) {
|
|
105
|
+
return dispatch(
|
|
106
|
+
{ ...request, type: "pauses", id: nextId++ },
|
|
107
|
+
jobOptions,
|
|
108
|
+
async () => (await inlineEngine()).analyzeMediaEditPauses(request, jobOptions)
|
|
109
|
+
);
|
|
110
|
+
},
|
|
111
|
+
dispose() {
|
|
112
|
+
failAll(abortError());
|
|
113
|
+
worker?.terminate();
|
|
114
|
+
worker = null;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/mediaEdit/mediaEditRenderManager.ts
|
|
120
|
+
import {
|
|
121
|
+
MEDIA_FX_ORDER,
|
|
122
|
+
MEDIA_RENDER_MANIFEST_VERSION,
|
|
123
|
+
buildMediaRenderIndex,
|
|
124
|
+
collectDocMediaClips,
|
|
125
|
+
mediaClipRenderKey,
|
|
126
|
+
mediaRenderFilePath,
|
|
127
|
+
mediaRenderManifestPath,
|
|
128
|
+
mediaRenderStaleness,
|
|
129
|
+
parseMediaRenderManifest,
|
|
130
|
+
referencedMediaRenderKeys,
|
|
131
|
+
selectMediaRendersForGc,
|
|
132
|
+
serializeMediaFx,
|
|
133
|
+
serializeMediaRenderManifest
|
|
134
|
+
} from "@bendyline/squisq/mediaEdit";
|
|
135
|
+
function sourceSizeOf(sizes, src) {
|
|
136
|
+
const direct = sizes.get(src);
|
|
137
|
+
if (direct != null) return direct;
|
|
138
|
+
for (const [name, size] of sizes) if (name.endsWith(`/${src}`)) return size;
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
function createMediaEditRenderManager(options) {
|
|
142
|
+
const provider = options.mediaProvider;
|
|
143
|
+
const ownsRenderer = !options.renderer;
|
|
144
|
+
const renderer = options.renderer ?? createMediaEditRenderer();
|
|
145
|
+
const fetchImpl = options.fetch ?? ((input, init) => fetch(input, init));
|
|
146
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
147
|
+
let index = /* @__PURE__ */ new Map();
|
|
148
|
+
let sourceSizes = /* @__PURE__ */ new Map();
|
|
149
|
+
const manifests = /* @__PURE__ */ new Map();
|
|
150
|
+
const staleKeys = /* @__PURE__ */ new Set();
|
|
151
|
+
const statuses = /* @__PURE__ */ new Map();
|
|
152
|
+
const queue = [];
|
|
153
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
154
|
+
let version = 0;
|
|
155
|
+
let indexVersion = 0;
|
|
156
|
+
let indexLoad = null;
|
|
157
|
+
let running = null;
|
|
158
|
+
let disposed = false;
|
|
159
|
+
let latestDoc = null;
|
|
160
|
+
let lastExtras = [];
|
|
161
|
+
const indexSignature = () => [...index].filter(([key]) => !staleKeys.has(key)).map(([key, entry]) => `${key}=${entry.path}`).sort().join("|");
|
|
162
|
+
const notify = () => {
|
|
163
|
+
version++;
|
|
164
|
+
for (const listener of listeners) listener();
|
|
165
|
+
};
|
|
166
|
+
const loadText = async (path) => {
|
|
167
|
+
try {
|
|
168
|
+
const url = await provider.resolveUrl(path);
|
|
169
|
+
const response = await fetchImpl(url);
|
|
170
|
+
return response.ok ? await response.text() : null;
|
|
171
|
+
} catch {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
const manifestFor = async (key) => {
|
|
176
|
+
if (manifests.has(key)) return manifests.get(key) ?? null;
|
|
177
|
+
const entry = index.get(key);
|
|
178
|
+
const manifest = entry?.manifestPath ? parseMediaRenderManifest(await loadText(entry.manifestPath) ?? "") : null;
|
|
179
|
+
manifests.set(key, manifest);
|
|
180
|
+
return manifest;
|
|
181
|
+
};
|
|
182
|
+
const refreshIndex = async () => {
|
|
183
|
+
const entries = await provider.listMedia();
|
|
184
|
+
const before = indexSignature();
|
|
185
|
+
index = buildMediaRenderIndex(entries);
|
|
186
|
+
sourceSizes = new Map(entries.map((e) => [e.name, e.size]));
|
|
187
|
+
staleKeys.clear();
|
|
188
|
+
for (const [key] of index) {
|
|
189
|
+
const manifest = await manifestFor(key);
|
|
190
|
+
if (!manifest) continue;
|
|
191
|
+
const staleness = mediaRenderStaleness(manifest, {
|
|
192
|
+
sourceSize: sourceSizeOf(sourceSizes, manifest.src),
|
|
193
|
+
knownOps: MEDIA_FX_ORDER
|
|
194
|
+
});
|
|
195
|
+
if (staleness) staleKeys.add(key);
|
|
196
|
+
}
|
|
197
|
+
if (indexSignature() !== before) indexVersion++;
|
|
198
|
+
notify();
|
|
199
|
+
};
|
|
200
|
+
const ensureIndex = () => {
|
|
201
|
+
indexLoad ?? (indexLoad = refreshIndex().catch(() => {
|
|
202
|
+
indexLoad = null;
|
|
203
|
+
}));
|
|
204
|
+
return indexLoad;
|
|
205
|
+
};
|
|
206
|
+
const isCurrent = (key) => index.has(key) && !staleKeys.has(key);
|
|
207
|
+
const pump = async () => {
|
|
208
|
+
if (running || disposed) return;
|
|
209
|
+
const job = queue.shift();
|
|
210
|
+
if (!job) return;
|
|
211
|
+
const controller = new AbortController();
|
|
212
|
+
running = { key: job.key, controller };
|
|
213
|
+
statuses.set(job.key, { key: job.key, state: "rendering", progress: 0 });
|
|
214
|
+
notify();
|
|
215
|
+
let lastReported = 0;
|
|
216
|
+
try {
|
|
217
|
+
const source = await loadSource(job.clip.src);
|
|
218
|
+
const result = await renderer.render(
|
|
219
|
+
{ source, fx: job.fx },
|
|
220
|
+
{
|
|
221
|
+
signal: controller.signal,
|
|
222
|
+
onProgress: (fraction) => {
|
|
223
|
+
if (fraction - lastReported < 0.01 && fraction < 1) return;
|
|
224
|
+
lastReported = fraction;
|
|
225
|
+
statuses.set(job.key, { key: job.key, state: "rendering", progress: fraction });
|
|
226
|
+
notify();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
);
|
|
230
|
+
const renderPath = await provider.addMedia(
|
|
231
|
+
mediaRenderFilePath(job.clip.src, job.key, result.extension),
|
|
232
|
+
result.bytes,
|
|
233
|
+
result.mimeType
|
|
234
|
+
);
|
|
235
|
+
const manifest = {
|
|
236
|
+
version: MEDIA_RENDER_MANIFEST_VERSION,
|
|
237
|
+
src: job.clip.src,
|
|
238
|
+
key: job.key,
|
|
239
|
+
fx: job.fx,
|
|
240
|
+
ignoredOps: result.ignoredOps,
|
|
241
|
+
file: renderPath,
|
|
242
|
+
mimeType: result.mimeType,
|
|
243
|
+
sourceSize: source.size,
|
|
244
|
+
sourceDuration: result.sourceDuration,
|
|
245
|
+
engine: result.engine,
|
|
246
|
+
createdAt: now().toISOString(),
|
|
247
|
+
analysis: {
|
|
248
|
+
...result.analysis.integratedLufs != null ? { integratedLufs: result.analysis.integratedLufs } : {},
|
|
249
|
+
appliedGainDb: result.analysis.loudnessGainDb,
|
|
250
|
+
breathCount: result.analysis.breaths.length
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
const manifestPath = await provider.addMedia(
|
|
254
|
+
mediaRenderManifestPath(job.clip.src, job.key),
|
|
255
|
+
new TextEncoder().encode(serializeMediaRenderManifest(manifest)),
|
|
256
|
+
"application/json"
|
|
257
|
+
);
|
|
258
|
+
index.set(job.key, {
|
|
259
|
+
key: job.key,
|
|
260
|
+
path: renderPath,
|
|
261
|
+
manifestPath,
|
|
262
|
+
size: result.bytes.byteLength
|
|
263
|
+
});
|
|
264
|
+
manifests.set(job.key, manifest);
|
|
265
|
+
staleKeys.delete(job.key);
|
|
266
|
+
indexVersion++;
|
|
267
|
+
statuses.set(job.key, { key: job.key, state: "ready" });
|
|
268
|
+
} catch (err) {
|
|
269
|
+
const aborted = err instanceof DOMException && err.name === "AbortError";
|
|
270
|
+
if (aborted) statuses.delete(job.key);
|
|
271
|
+
else {
|
|
272
|
+
statuses.set(job.key, {
|
|
273
|
+
key: job.key,
|
|
274
|
+
state: "failed",
|
|
275
|
+
error: err instanceof Error ? err.message : String(err)
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
} finally {
|
|
279
|
+
running = null;
|
|
280
|
+
notify();
|
|
281
|
+
void pump();
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
const enqueue = (clip, force) => {
|
|
285
|
+
const key = mediaClipRenderKey(clip);
|
|
286
|
+
const fx = clip.edits?.fx;
|
|
287
|
+
if (!key || !fx) return;
|
|
288
|
+
if (!force && (isCurrent(key) || statuses.get(key)?.state === "failed")) return;
|
|
289
|
+
if (running?.key === key || queue.some((job) => job.key === key)) return;
|
|
290
|
+
queue.push({ key, clip, fx: serializeMediaFx({ ops: fx.ops, unknown: [] }) });
|
|
291
|
+
statuses.set(key, { key, state: "queued" });
|
|
292
|
+
};
|
|
293
|
+
async function loadSource(src) {
|
|
294
|
+
const url = await provider.resolveUrl(src);
|
|
295
|
+
const response = await fetchImpl(url);
|
|
296
|
+
if (!response.ok) throw new Error(`Could not read ${src} (${response.status}).`);
|
|
297
|
+
return response.blob();
|
|
298
|
+
}
|
|
299
|
+
const requiredKeys = (doc) => {
|
|
300
|
+
const keys = referencedMediaRenderKeys(doc);
|
|
301
|
+
for (const clip of lastExtras) {
|
|
302
|
+
const key = mediaClipRenderKey(clip);
|
|
303
|
+
if (key) keys.add(key);
|
|
304
|
+
}
|
|
305
|
+
return keys;
|
|
306
|
+
};
|
|
307
|
+
const manager = {
|
|
308
|
+
renderer,
|
|
309
|
+
sync(doc, extraClips) {
|
|
310
|
+
latestDoc = doc;
|
|
311
|
+
const extras = extraClips ?? lastExtras;
|
|
312
|
+
lastExtras = extras;
|
|
313
|
+
void ensureIndex().then(() => {
|
|
314
|
+
if (disposed || latestDoc !== doc) return;
|
|
315
|
+
const clips = [...collectDocMediaClips(doc), ...extras];
|
|
316
|
+
const wanted = new Set(
|
|
317
|
+
clips.map((clip) => mediaClipRenderKey(clip)).filter((key) => key != null)
|
|
318
|
+
);
|
|
319
|
+
for (let i = queue.length - 1; i >= 0; i--) {
|
|
320
|
+
if (!wanted.has(queue[i].key)) {
|
|
321
|
+
statuses.delete(queue[i].key);
|
|
322
|
+
queue.splice(i, 1);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
for (const clip of clips) enqueue(clip, false);
|
|
326
|
+
notify();
|
|
327
|
+
void pump();
|
|
328
|
+
});
|
|
329
|
+
},
|
|
330
|
+
processedAudio(clip) {
|
|
331
|
+
const key = mediaClipRenderKey(clip);
|
|
332
|
+
return key && isCurrent(key) ? index.get(key)?.path : void 0;
|
|
333
|
+
},
|
|
334
|
+
status(clip) {
|
|
335
|
+
const key = mediaClipRenderKey(clip);
|
|
336
|
+
if (!key) return null;
|
|
337
|
+
if (isCurrent(key)) return statuses.get(key) ?? { key, state: "ready" };
|
|
338
|
+
return statuses.get(key) ?? { key, state: "queued" };
|
|
339
|
+
},
|
|
340
|
+
whenReady(doc, signal) {
|
|
341
|
+
manager.sync(doc);
|
|
342
|
+
return new Promise((resolve, reject) => {
|
|
343
|
+
const check = () => {
|
|
344
|
+
if (signal?.aborted) {
|
|
345
|
+
unsubscribe();
|
|
346
|
+
reject(new DOMException("Waiting for renders was cancelled.", "AbortError"));
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const pending = [...requiredKeys(doc)].some((key) => {
|
|
350
|
+
if (isCurrent(key)) return false;
|
|
351
|
+
return statuses.get(key)?.state !== "failed";
|
|
352
|
+
});
|
|
353
|
+
if (!pending && indexLoad) {
|
|
354
|
+
unsubscribe();
|
|
355
|
+
resolve();
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
const unsubscribe = manager.subscribe(check);
|
|
359
|
+
signal?.addEventListener("abort", check, { once: true });
|
|
360
|
+
void ensureIndex().then(check);
|
|
361
|
+
});
|
|
362
|
+
},
|
|
363
|
+
retry(clip) {
|
|
364
|
+
const key = mediaClipRenderKey(clip);
|
|
365
|
+
if (!key) return;
|
|
366
|
+
statuses.delete(key);
|
|
367
|
+
enqueue(clip, true);
|
|
368
|
+
notify();
|
|
369
|
+
void pump();
|
|
370
|
+
},
|
|
371
|
+
loadSource,
|
|
372
|
+
async collectGarbage(doc, at = now()) {
|
|
373
|
+
await refreshIndex();
|
|
374
|
+
const docSources = new Set(
|
|
375
|
+
[...collectDocMediaClips(doc), ...lastExtras].map((clip) => clip.src)
|
|
376
|
+
);
|
|
377
|
+
const busy = /* @__PURE__ */ new Set([...queue.map((job) => job.key), ...running ? [running.key] : []]);
|
|
378
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
379
|
+
const loaded = /* @__PURE__ */ new Map();
|
|
380
|
+
for (const [key, entry] of index) {
|
|
381
|
+
const manifest = await manifestFor(key);
|
|
382
|
+
if (!manifest || !docSources.has(manifest.src) || busy.has(key)) continue;
|
|
383
|
+
candidates.set(key, entry);
|
|
384
|
+
loaded.set(key, manifest);
|
|
385
|
+
}
|
|
386
|
+
const paths = selectMediaRendersForGc(candidates, requiredKeys(doc), loaded, at);
|
|
387
|
+
for (const path of paths) await provider.removeMedia(path);
|
|
388
|
+
if (paths.length > 0) {
|
|
389
|
+
for (const key of candidates.keys()) {
|
|
390
|
+
const entry = index.get(key);
|
|
391
|
+
if (entry && paths.includes(entry.path)) {
|
|
392
|
+
index.delete(key);
|
|
393
|
+
manifests.delete(key);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
indexVersion++;
|
|
397
|
+
notify();
|
|
398
|
+
}
|
|
399
|
+
return paths;
|
|
400
|
+
},
|
|
401
|
+
subscribe(listener) {
|
|
402
|
+
listeners.add(listener);
|
|
403
|
+
return () => listeners.delete(listener);
|
|
404
|
+
},
|
|
405
|
+
getVersion: () => version,
|
|
406
|
+
getIndexVersion: () => indexVersion,
|
|
407
|
+
dispose() {
|
|
408
|
+
disposed = true;
|
|
409
|
+
queue.length = 0;
|
|
410
|
+
running?.controller.abort();
|
|
411
|
+
listeners.clear();
|
|
412
|
+
if (ownsRenderer) renderer.dispose();
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
return manager;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// src/mediaEdit/useMediaEditRenders.ts
|
|
419
|
+
import { useCallback, useEffect, useSyncExternalStore } from "react";
|
|
420
|
+
var noSubscribe = () => () => {
|
|
421
|
+
};
|
|
422
|
+
var zero = () => 0;
|
|
423
|
+
function useProcessedAudio(manager) {
|
|
424
|
+
const indexVersion = useSyncExternalStore(
|
|
425
|
+
manager ? manager.subscribe : noSubscribe,
|
|
426
|
+
manager ? manager.getIndexVersion : zero,
|
|
427
|
+
zero
|
|
428
|
+
);
|
|
429
|
+
return useCallback((clip) => manager?.processedAudio(clip), [manager, indexVersion]);
|
|
430
|
+
}
|
|
431
|
+
function useMediaEditStatus(manager) {
|
|
432
|
+
const version = useSyncExternalStore(
|
|
433
|
+
manager ? manager.subscribe : noSubscribe,
|
|
434
|
+
manager ? manager.getVersion : zero,
|
|
435
|
+
zero
|
|
436
|
+
);
|
|
437
|
+
return useCallback((clip) => manager?.status(clip) ?? null, [manager, version]);
|
|
438
|
+
}
|
|
439
|
+
function useMediaEditRenders(manager, doc) {
|
|
440
|
+
useEffect(() => {
|
|
441
|
+
if (manager && doc) manager.sync(doc);
|
|
442
|
+
}, [manager, doc]);
|
|
443
|
+
return { processedAudio: useProcessedAudio(manager), status: useMediaEditStatus(manager) };
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
export {
|
|
447
|
+
createMediaEditRenderer,
|
|
448
|
+
createMediaEditRenderManager,
|
|
449
|
+
useProcessedAudio,
|
|
450
|
+
useMediaEditStatus,
|
|
451
|
+
useMediaEditRenders
|
|
452
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// src/mediaEdit/rnnoiseDenoiser.ts
|
|
2
|
+
var RNNOISE_SAMPLE_RATE = 48e3;
|
|
3
|
+
var RNNOISE_LATENCY = 960;
|
|
4
|
+
var PCM16_SCALE = 32768;
|
|
5
|
+
function createRnnoiseDenoiserFactory(load) {
|
|
6
|
+
let loading = null;
|
|
7
|
+
return async () => {
|
|
8
|
+
loading ?? (loading = load());
|
|
9
|
+
const rnnoise = await loading;
|
|
10
|
+
const state = rnnoise.createDenoiseState();
|
|
11
|
+
return {
|
|
12
|
+
frameSize: rnnoise.frameSize,
|
|
13
|
+
sampleRate: RNNOISE_SAMPLE_RATE,
|
|
14
|
+
latency: RNNOISE_LATENCY,
|
|
15
|
+
processFrame(frame) {
|
|
16
|
+
for (let i = 0; i < frame.length; i++) frame[i] *= PCM16_SCALE;
|
|
17
|
+
state.processFrame(frame);
|
|
18
|
+
for (let i = 0; i < frame.length; i++) frame[i] /= PCM16_SCALE;
|
|
19
|
+
},
|
|
20
|
+
dispose: () => state.destroy()
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
createRnnoiseDenoiserFactory
|
|
27
|
+
};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { Doc, MediaProvider } from '@bendyline/squisq/schemas';
|
|
3
|
-
import {
|
|
3
|
+
import { e as MediaEditRenderManager } from '../mediaEditRenderManager-W_o6RRhT.js';
|
|
4
|
+
import { b as VideoExportConfig, f as VideoOutputFormat } from '../useVideoExport-DsNDpjmO.js';
|
|
4
5
|
export { CoverImageExportFormat, CoverImageExportModal, CoverImageExportModalProps, coverImageFilename, validateCoverImageDimensions } from '../cover-image/index.js';
|
|
6
|
+
import '@bendyline/squisq/mediaEdit';
|
|
5
7
|
import '@bendyline/squisq/markdown';
|
|
6
8
|
import '@bendyline/squisq/doc';
|
|
7
9
|
import '@bendyline/squisq-video';
|
|
@@ -24,6 +26,11 @@ interface VideoExportModalProps {
|
|
|
24
26
|
images?: Map<string, ArrayBuffer>;
|
|
25
27
|
/** Pre-collected audio map */
|
|
26
28
|
audio?: Map<string, ArrayBuffer>;
|
|
29
|
+
/**
|
|
30
|
+
* Processed-audio renders for media-edit recipes. Export waits for pending
|
|
31
|
+
* renders, then mixes each edited clip's render instead of its original.
|
|
32
|
+
*/
|
|
33
|
+
mediaEditRenders?: MediaEditRenderManager | null;
|
|
27
34
|
/**
|
|
28
35
|
* Seeds the modal's initial format, motion, quality, FPS, orientation, and
|
|
29
36
|
* caption selections. It is merged (as a base) into the config passed to the
|
|
@@ -59,7 +66,7 @@ interface VideoExportPalette {
|
|
|
59
66
|
success: string;
|
|
60
67
|
danger: string;
|
|
61
68
|
}
|
|
62
|
-
declare function VideoExportModal({ doc, playerScript, mediaProvider, images, audio, defaultConfig, colorScheme, uiPalette, saveOutput, saveActionLabel, onClose, }: VideoExportModalProps): react_jsx_runtime.JSX.Element;
|
|
69
|
+
declare function VideoExportModal({ doc, playerScript, mediaProvider, images, audio, mediaEditRenders, defaultConfig, colorScheme, uiPalette, saveOutput, saveActionLabel, onClose, }: VideoExportModalProps): react_jsx_runtime.JSX.Element;
|
|
63
70
|
|
|
64
71
|
interface VideoExportButtonProps {
|
|
65
72
|
/** The document to export */
|
package/dist/components/index.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
VideoExportButton,
|
|
3
3
|
VideoExportModal
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-BNUM3BXO.js";
|
|
5
5
|
import {
|
|
6
6
|
CoverImageExportModal,
|
|
7
7
|
coverImageFilename,
|
|
8
8
|
validateCoverImageDimensions
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-3EJKBFEK.js";
|
|
10
10
|
import "../chunk-3NJDHK62.js";
|
|
11
|
-
import "../chunk-
|
|
12
|
-
import "../chunk-
|
|
13
|
-
import "../chunk-
|
|
11
|
+
import "../chunk-ED7QK6VC.js";
|
|
12
|
+
import "../chunk-7ZMJ25DC.js";
|
|
13
|
+
import "../chunk-4GFZ3GUE.js";
|
|
14
|
+
import "../chunk-GBIYYDMY.js";
|
|
14
15
|
import "../chunk-5MFQMJ5Z.js";
|
|
15
16
|
export {
|
|
16
17
|
CoverImageExportModal,
|
|
@@ -2,9 +2,10 @@ import {
|
|
|
2
2
|
CoverImageExportModal,
|
|
3
3
|
coverImageFilename,
|
|
4
4
|
validateCoverImageDimensions
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-3EJKBFEK.js";
|
|
6
6
|
import "../chunk-3NJDHK62.js";
|
|
7
|
-
import "../chunk-
|
|
7
|
+
import "../chunk-7ZMJ25DC.js";
|
|
8
|
+
import "../chunk-4GFZ3GUE.js";
|
|
8
9
|
export {
|
|
9
10
|
CoverImageExportModal,
|
|
10
11
|
coverImageFilename,
|
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
} from "../chunk-3NJDHK62.js";
|
|
8
8
|
import {
|
|
9
9
|
useFrameCapture
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-7ZMJ25DC.js";
|
|
11
|
+
import "../chunk-4GFZ3GUE.js";
|
|
11
12
|
|
|
12
13
|
// src/DashboardImageExportModal.tsx
|
|
13
14
|
import { useCallback, useId, useMemo, useRef, useState } from "react";
|
package/dist/encoder/index.js
CHANGED
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { D as DEFAULT_VIDEO_COVER_PRE_ROLL_SECONDS, R as ResolvedVideoExportCover, U as UseVideoExportOptions, V as VideoAudioPolicy, a as VideoCoverFramePlan, b as VideoExportConfig, c as VideoExportFramePreview, d as VideoExportResult, e as VideoExportState, f as VideoOutputFormat, r as resolveVideoCoverFramePlan, g as resolveVideoExportCover, u as useVideoExport } from '../useVideoExport-
|
|
1
|
+
export { D as DEFAULT_VIDEO_COVER_PRE_ROLL_SECONDS, R as ResolvedVideoExportCover, U as UseVideoExportOptions, V as VideoAudioPolicy, a as VideoCoverFramePlan, b as VideoExportConfig, c as VideoExportFramePreview, d as VideoExportResult, e as VideoExportState, f as VideoOutputFormat, r as resolveVideoCoverFramePlan, g as resolveVideoExportCover, u as useVideoExport } from '../useVideoExport-DsNDpjmO.js';
|
|
2
2
|
import * as _bendyline_squisq_doc from '@bendyline/squisq/doc';
|
|
3
3
|
import { Doc, MediaProvider } from '@bendyline/squisq/schemas';
|
|
4
4
|
import { RenderHtmlOptions } from '@bendyline/squisq-video';
|
package/dist/hooks/index.js
CHANGED
|
@@ -3,11 +3,12 @@ import {
|
|
|
3
3
|
resolveVideoCoverFramePlan,
|
|
4
4
|
resolveVideoExportCover,
|
|
5
5
|
useVideoExport
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-ED7QK6VC.js";
|
|
7
7
|
import {
|
|
8
8
|
useFrameCapture
|
|
9
|
-
} from "../chunk-
|
|
10
|
-
import "../chunk-
|
|
9
|
+
} from "../chunk-7ZMJ25DC.js";
|
|
10
|
+
import "../chunk-4GFZ3GUE.js";
|
|
11
|
+
import "../chunk-GBIYYDMY.js";
|
|
11
12
|
import "../chunk-5MFQMJ5Z.js";
|
|
12
13
|
export {
|
|
13
14
|
DEFAULT_VIDEO_COVER_PRE_ROLL_SECONDS,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
export { VideoExportButton, VideoExportButtonProps, VideoExportModal, VideoExportModalProps, VideoExportPalette } from './components/index.js';
|
|
2
2
|
export { CoverImageExportFormat, CoverImageExportModal, CoverImageExportModalProps, coverImageFilename, validateCoverImageDimensions } from './cover-image/index.js';
|
|
3
|
-
export { D as DEFAULT_VIDEO_COVER_PRE_ROLL_SECONDS, R as ResolvedVideoExportCover, U as UseVideoExportOptions, V as VideoAudioPolicy, a as VideoCoverFramePlan, b as VideoExportConfig, c as VideoExportFramePreview, d as VideoExportResult, e as VideoExportState, f as VideoOutputFormat, r as resolveVideoCoverFramePlan, g as resolveVideoExportCover, u as useVideoExport } from './useVideoExport-
|
|
3
|
+
export { D as DEFAULT_VIDEO_COVER_PRE_ROLL_SECONDS, R as ResolvedVideoExportCover, U as UseVideoExportOptions, V as VideoAudioPolicy, a as VideoCoverFramePlan, b as VideoExportConfig, c as VideoExportFramePreview, d as VideoExportResult, e as VideoExportState, f as VideoOutputFormat, r as resolveVideoCoverFramePlan, g as resolveVideoExportCover, u as useVideoExport } from './useVideoExport-DsNDpjmO.js';
|
|
4
4
|
export { FrameCaptureHandle, FrameCaptureOptions, FrameCaptureRenderOptions, useFrameCapture } from './hooks/index.js';
|
|
5
5
|
export { E as EncoderConfig, a as EncoderFrameSource, M as MainThreadEncoder, c as createEncoder, s as supportsWebCodecs, b as supportsWebCodecsH264 } from './mainThreadEncoder-BVCLjlfj.js';
|
|
6
6
|
export { FfmpegWasmLoadConfig } from '@bendyline/squisq-video';
|
|
7
7
|
export { supportsWebCodecsAac } from './encoder/index.js';
|
|
8
|
+
export { M as MediaEditJobOptions, a as MediaEditPausesRequest, b as MediaEditPausesResult, c as MediaEditPreviewRequest, d as MediaEditPreviewResult, e as MediaEditRenderManager, f as MediaEditRenderManagerOptions, g as MediaEditRenderRequest, h as MediaEditRenderResult, i as MediaEditRenderState, j as MediaEditRenderStatus, k as MediaEditRenderer, l as MediaEditRendererOptions, m as createMediaEditRenderManager, n as createMediaEditRenderer } from './mediaEditRenderManager-W_o6RRhT.js';
|
|
9
|
+
export { MediaEditRendersView, useMediaEditRenders, useMediaEditStatus, useProcessedAudio } from './media-edit/index.js';
|
|
8
10
|
import 'react/jsx-runtime';
|
|
9
11
|
import '@bendyline/squisq/schemas';
|
|
10
12
|
import '@bendyline/squisq/doc';
|
|
11
13
|
import './imageExportShared-B6nqWtE-.js';
|
|
12
14
|
import '@bendyline/squisq/markdown';
|
|
13
15
|
import '@bendyline/squisq-react';
|
|
16
|
+
import '@bendyline/squisq/mediaEdit';
|
package/dist/index.js
CHANGED
|
@@ -1,28 +1,37 @@
|
|
|
1
1
|
import {
|
|
2
2
|
VideoExportButton,
|
|
3
3
|
VideoExportModal
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BNUM3BXO.js";
|
|
5
5
|
import {
|
|
6
6
|
CoverImageExportModal,
|
|
7
7
|
coverImageFilename,
|
|
8
8
|
validateCoverImageDimensions
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-3EJKBFEK.js";
|
|
10
10
|
import "./chunk-3NJDHK62.js";
|
|
11
11
|
import {
|
|
12
12
|
DEFAULT_VIDEO_COVER_PRE_ROLL_SECONDS,
|
|
13
13
|
resolveVideoCoverFramePlan,
|
|
14
14
|
resolveVideoExportCover,
|
|
15
15
|
useVideoExport
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-ED7QK6VC.js";
|
|
17
17
|
import {
|
|
18
18
|
useFrameCapture
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-7ZMJ25DC.js";
|
|
20
|
+
import "./chunk-4GFZ3GUE.js";
|
|
20
21
|
import {
|
|
21
22
|
createEncoder,
|
|
22
23
|
supportsWebCodecs,
|
|
23
24
|
supportsWebCodecsAac,
|
|
24
25
|
supportsWebCodecsH264
|
|
25
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-GBIYYDMY.js";
|
|
27
|
+
import {
|
|
28
|
+
createMediaEditRenderManager,
|
|
29
|
+
createMediaEditRenderer,
|
|
30
|
+
useMediaEditRenders,
|
|
31
|
+
useMediaEditStatus,
|
|
32
|
+
useProcessedAudio
|
|
33
|
+
} from "./chunk-SLLH2RTX.js";
|
|
34
|
+
import "./chunk-TL2IMDIZ.js";
|
|
26
35
|
import "./chunk-5MFQMJ5Z.js";
|
|
27
36
|
export {
|
|
28
37
|
CoverImageExportModal,
|
|
@@ -31,12 +40,17 @@ export {
|
|
|
31
40
|
VideoExportModal,
|
|
32
41
|
coverImageFilename,
|
|
33
42
|
createEncoder,
|
|
43
|
+
createMediaEditRenderManager,
|
|
44
|
+
createMediaEditRenderer,
|
|
34
45
|
resolveVideoCoverFramePlan,
|
|
35
46
|
resolveVideoExportCover,
|
|
36
47
|
supportsWebCodecs,
|
|
37
48
|
supportsWebCodecsAac,
|
|
38
49
|
supportsWebCodecsH264,
|
|
39
50
|
useFrameCapture,
|
|
51
|
+
useMediaEditRenders,
|
|
52
|
+
useMediaEditStatus,
|
|
53
|
+
useProcessedAudio,
|
|
40
54
|
useVideoExport,
|
|
41
55
|
validateCoverImageDimensions
|
|
42
56
|
};
|