@mengine/medeo-client 1.2.1-alpha.0 → 1.2.1-alpha.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/dist/{document-49OdvviW.js → document-C5KDvMMR.js} +98 -138
- package/dist/{index-BO2fSUKi.d.ts → index-DrEHTguy.d.ts} +633 -111
- package/dist/index.d.ts +36 -30
- package/dist/index.js +683 -153
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -40
- package/package.json +4 -7
- package/dist/index-InEWX9rk.d.ts +0 -609
- package/dist/schemas.d.ts +0 -2
- package/dist/schemas.js +0 -518
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Mirror, schema } from "loro-mirror";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { LoroDoc } from "loro-crdt";
|
|
4
|
-
import { produce } from "immer";
|
|
5
4
|
//#region src/client/base64.ts
|
|
6
5
|
function bytesToBase64(bytes) {
|
|
7
6
|
let binary = "";
|
|
@@ -88,7 +87,8 @@ function jsonTransform() {
|
|
|
88
87
|
const trackItem = schema.LoroMap({
|
|
89
88
|
part_id: schema.String(),
|
|
90
89
|
time_position: schema.String().transform(jsonTransform()),
|
|
91
|
-
fallback_abs_ms: schema.Number({ required: false })
|
|
90
|
+
fallback_abs_ms: schema.Number({ required: false }),
|
|
91
|
+
duration_override_ms: schema.Number({ required: false })
|
|
92
92
|
});
|
|
93
93
|
const track = schema.LoroMap({
|
|
94
94
|
id: schema.String(),
|
|
@@ -322,6 +322,71 @@ function syncAggregatedClipsTimePosition(doc) {
|
|
|
322
322
|
}
|
|
323
323
|
}
|
|
324
324
|
/**
|
|
325
|
+
* Resolve authoritative `time_position` edges without inventing parents from
|
|
326
|
+
* geometric overlap. Roots stay absolute/sequential; every anchored descendant
|
|
327
|
+
* follows its declared parent, regardless of whether that parent is video, BGM,
|
|
328
|
+
* or speech.
|
|
329
|
+
*/
|
|
330
|
+
function resolveAnchoredClipsTimePosition(doc) {
|
|
331
|
+
const items = [
|
|
332
|
+
...doc.main_track,
|
|
333
|
+
...doc.bgm_track,
|
|
334
|
+
...doc.speech_track,
|
|
335
|
+
...doc.caption_track
|
|
336
|
+
];
|
|
337
|
+
const byPart = indexByPart(items);
|
|
338
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
339
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
340
|
+
const resolve = (item) => {
|
|
341
|
+
if (resolved.has(item.part_id)) return item.abs_time_position;
|
|
342
|
+
if (visiting.has(item.part_id)) throw new Error(`anchored position cycle at ${item.part_id}`);
|
|
343
|
+
visiting.add(item.part_id);
|
|
344
|
+
const position = item.time_position;
|
|
345
|
+
if (position.mode === "absolute") item.abs_time_position = Math.round(position.offsetMs);
|
|
346
|
+
else if (position.mode === "anchored") {
|
|
347
|
+
const parent = byPart.get(position.anchorPartId);
|
|
348
|
+
if (parent != null) item.abs_time_position = resolve(parent) + Math.round(position.offsetMs);
|
|
349
|
+
}
|
|
350
|
+
visiting.delete(item.part_id);
|
|
351
|
+
resolved.add(item.part_id);
|
|
352
|
+
return item.abs_time_position;
|
|
353
|
+
};
|
|
354
|
+
for (const item of items) resolve(item);
|
|
355
|
+
}
|
|
356
|
+
/** Preserve the historical orphan fallback without re-parenting valid roots. */
|
|
357
|
+
function recoverOrphanedSpeechAnchorsByTime(doc) {
|
|
358
|
+
const placedPartIds = new Set([
|
|
359
|
+
...doc.main_track,
|
|
360
|
+
...doc.bgm_track,
|
|
361
|
+
...doc.speech_track,
|
|
362
|
+
...doc.caption_track
|
|
363
|
+
].map((item) => item.part_id));
|
|
364
|
+
const ranges = doc.main_track.map((item) => ({
|
|
365
|
+
part_id: item.part_id,
|
|
366
|
+
start: item.abs_time_position,
|
|
367
|
+
end: item.abs_time_position + partDurationMs(doc, item.part_id)
|
|
368
|
+
}));
|
|
369
|
+
if (ranges.length === 0) return;
|
|
370
|
+
for (const speech of doc.speech_track) {
|
|
371
|
+
const position = speech.time_position;
|
|
372
|
+
if (position.mode !== "anchored" || placedPartIds.has(position.anchorPartId)) continue;
|
|
373
|
+
const range = ranges.find((candidate) => candidate.start <= speech.abs_time_position && speech.abs_time_position < candidate.end) ?? (speech.abs_time_position < ranges[0].start ? ranges[0] : ranges[ranges.length - 1]);
|
|
374
|
+
const relative = Math.max(0, Math.round(speech.abs_time_position - range.start));
|
|
375
|
+
let aggregation = doc.aggregations.find((candidate) => candidate.body_part_id === range.part_id);
|
|
376
|
+
if (aggregation == null) {
|
|
377
|
+
aggregation = {
|
|
378
|
+
body_part_id: range.part_id,
|
|
379
|
+
attachments: []
|
|
380
|
+
};
|
|
381
|
+
doc.aggregations.push(aggregation);
|
|
382
|
+
}
|
|
383
|
+
aggregation.attachments.push({
|
|
384
|
+
part_id: speech.part_id,
|
|
385
|
+
relative_time_position: relative
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
325
390
|
* Reassign each speech to the video clip whose time range contains its start,
|
|
326
391
|
* rebuilding `aggregations`. A speech before the first clip or after the last
|
|
327
392
|
* falls back to the first / last clip respectively (FE: see §4 note — FE falls
|
|
@@ -524,14 +589,14 @@ function hostVideoOf(doc, speechPartId) {
|
|
|
524
589
|
//#endregion
|
|
525
590
|
//#region src/timeline-core/entrypoints.ts
|
|
526
591
|
/**
|
|
527
|
-
* The full solve pipeline: arrange →
|
|
528
|
-
* fill-gaps → recalc. The single cascade the read-side projection runs; ops
|
|
592
|
+
* The full solve pipeline: arrange → resolve declared parent edges →
|
|
593
|
+
* resolve-overlap → fill-gaps → recalc. The single cascade the read-side projection runs; ops
|
|
529
594
|
* never call it (they write only facts — RFC 02 §7/§10).
|
|
530
595
|
*/
|
|
531
596
|
function cascadeAfterVideoClipChanges(doc, makeEmptyPart) {
|
|
532
597
|
arrangeMainTrackSeamlessly(doc);
|
|
533
|
-
|
|
534
|
-
|
|
598
|
+
resolveAnchoredClipsTimePosition(doc);
|
|
599
|
+
recoverOrphanedSpeechAnchorsByTime(doc);
|
|
535
600
|
resolveAllSpeechOverlaps(doc);
|
|
536
601
|
fillMainTrackTimeGaps(doc, makeEmptyPart);
|
|
537
602
|
recalculateTimelineDuration(doc);
|
|
@@ -605,7 +670,7 @@ function videoDocumentToTimelineDoc(document) {
|
|
|
605
670
|
caption_track: captionItems,
|
|
606
671
|
bgm_track: bgmItems,
|
|
607
672
|
part_library: partLibrary,
|
|
608
|
-
aggregations: seedAggregations(mainItems, speechItems),
|
|
673
|
+
aggregations: seedAggregations([...mainItems, ...bgmItems], speechItems),
|
|
609
674
|
timeline: {
|
|
610
675
|
duration_ms: 0,
|
|
611
676
|
unit_time_ms: document.timeline?.unit_time_ms ?? 0
|
|
@@ -629,19 +694,18 @@ function seedAbs(position, fallbackAbsMs) {
|
|
|
629
694
|
}
|
|
630
695
|
}
|
|
631
696
|
/**
|
|
632
|
-
* Build the
|
|
633
|
-
*
|
|
634
|
-
*
|
|
635
|
-
* caption→speech relations are recomputed by the cascade from `caption.start_ms`.
|
|
697
|
+
* Build the read-view `aggregations` parent-map from anchored speech items.
|
|
698
|
+
* Video and BGM roots are both valid hosts; absolute speech roots have no entry.
|
|
699
|
+
* Caption→speech ownership remains in `speech_part_id` / `caption_ids`.
|
|
636
700
|
*/
|
|
637
|
-
function seedAggregations(
|
|
638
|
-
const
|
|
701
|
+
function seedAggregations(hostItems, speechItems) {
|
|
702
|
+
const hostPartIds = new Set(hostItems.map((item) => item.part_id));
|
|
639
703
|
const byHost = /* @__PURE__ */ new Map();
|
|
640
704
|
const order = [];
|
|
641
705
|
for (const speech of speechItems) {
|
|
642
706
|
if (speech.time_position.mode !== "anchored") continue;
|
|
643
707
|
const host = speech.time_position.anchorPartId;
|
|
644
|
-
if (!
|
|
708
|
+
if (!hostPartIds.has(host)) continue;
|
|
645
709
|
let aggregation = byHost.get(host);
|
|
646
710
|
if (aggregation == null) {
|
|
647
711
|
aggregation = {
|
|
@@ -774,7 +838,8 @@ const trackItemTimePositionSchema = z.discriminatedUnion("mode", [
|
|
|
774
838
|
const trackItemSchema = z.object({
|
|
775
839
|
part_id: z.string(),
|
|
776
840
|
time_position: trackItemTimePositionSchema,
|
|
777
|
-
fallback_abs_ms: finiteNumber.optional()
|
|
841
|
+
fallback_abs_ms: finiteNumber.optional(),
|
|
842
|
+
duration_override_ms: z.number().finite().positive().optional()
|
|
778
843
|
}).passthrough();
|
|
779
844
|
const trackSchema = z.object({
|
|
780
845
|
id: z.string().optional(),
|
|
@@ -1327,7 +1392,7 @@ function fromVideoDocument(document) {
|
|
|
1327
1392
|
above_main_tracks: aboveTracks.map((t) => draftTrack(t, view.absByPartId)),
|
|
1328
1393
|
below_main_tracks: belowTracks.map((t) => draftTrack(t, view.absByPartId)),
|
|
1329
1394
|
part_aggregations: view.aggregations,
|
|
1330
|
-
part_library: toReadViewPartLibrary(view.partLibrary, view.durationMs, view.derivedFillerPartIds),
|
|
1395
|
+
part_library: toReadViewPartLibrary(view.partLibrary, view.durationMs, view.derivedFillerPartIds, captionDurationOverrides(document)),
|
|
1331
1396
|
version: document.meta.version
|
|
1332
1397
|
};
|
|
1333
1398
|
}
|
|
@@ -1348,7 +1413,7 @@ function fromVideoDocument(document) {
|
|
|
1348
1413
|
* and they are not part of the document (see `fromVideoDocument`). An empty clip a
|
|
1349
1414
|
* writer placed deliberately is NOT in that set and is projected normally.
|
|
1350
1415
|
*/
|
|
1351
|
-
function toReadViewPartLibrary(partLibrary, durationMs, derivedFillerPartIds) {
|
|
1416
|
+
function toReadViewPartLibrary(partLibrary, durationMs, derivedFillerPartIds, captionDurationByPartId) {
|
|
1352
1417
|
const out = {};
|
|
1353
1418
|
for (const [partId, part] of Object.entries(partLibrary)) {
|
|
1354
1419
|
if (derivedFillerPartIds.has(partId)) continue;
|
|
@@ -1368,7 +1433,7 @@ function toReadViewPartLibrary(partLibrary, durationMs, derivedFillerPartIds) {
|
|
|
1368
1433
|
const caption = clone(part.caption);
|
|
1369
1434
|
out[partId] = { caption: {
|
|
1370
1435
|
...caption,
|
|
1371
|
-
duration_ms: caption.initial_duration_ms
|
|
1436
|
+
duration_ms: captionDurationByPartId.get(partId) ?? caption.initial_duration_ms
|
|
1372
1437
|
} };
|
|
1373
1438
|
} else if (part.bgm != null) out[partId] = { bgm: {
|
|
1374
1439
|
...clone(part.bgm),
|
|
@@ -1377,6 +1442,14 @@ function toReadViewPartLibrary(partLibrary, durationMs, derivedFillerPartIds) {
|
|
|
1377
1442
|
}
|
|
1378
1443
|
return out;
|
|
1379
1444
|
}
|
|
1445
|
+
function captionDurationOverrides(document) {
|
|
1446
|
+
const result = /* @__PURE__ */ new Map();
|
|
1447
|
+
for (const track of document.tracks ?? []) {
|
|
1448
|
+
if (track.parts_kind !== "caption") continue;
|
|
1449
|
+
for (const item of track.items ?? []) if (item.duration_override_ms != null) result.set(item.part_id, item.duration_override_ms);
|
|
1450
|
+
}
|
|
1451
|
+
return result;
|
|
1452
|
+
}
|
|
1380
1453
|
/** Deep-clone a part payload, dropping the derived read-view `duration_ms`. */
|
|
1381
1454
|
function omitDurationMs(part) {
|
|
1382
1455
|
const { duration_ms: _drop, ...rest } = clone(part);
|
|
@@ -1539,6 +1612,7 @@ function rowToTrack(row) {
|
|
|
1539
1612
|
time_position: item.time_position
|
|
1540
1613
|
};
|
|
1541
1614
|
if (item.fallback_abs_ms != null) result.fallback_abs_ms = item.fallback_abs_ms;
|
|
1615
|
+
if (item.duration_override_ms != null) result.duration_override_ms = item.duration_override_ms;
|
|
1542
1616
|
return result;
|
|
1543
1617
|
})
|
|
1544
1618
|
};
|
|
@@ -1613,7 +1687,7 @@ function createMirrorVideoDocument(document, options = {}) {
|
|
|
1613
1687
|
doc,
|
|
1614
1688
|
schema: videoDocumentMirrorSchema
|
|
1615
1689
|
}).setState((draft) => {
|
|
1616
|
-
|
|
1690
|
+
seedDraft(draft, document);
|
|
1617
1691
|
}, { origin: options.origin ?? "mengine.bootstrap" });
|
|
1618
1692
|
return doc;
|
|
1619
1693
|
}
|
|
@@ -1621,8 +1695,8 @@ function createMirrorVideoDocument(document, options = {}) {
|
|
|
1621
1695
|
function createMirrorVideoDocumentAdapter(document, options) {
|
|
1622
1696
|
return new MirrorVideoDocumentAdapter(createMirrorVideoDocument(document, options));
|
|
1623
1697
|
}
|
|
1624
|
-
/** Write a whole `VideoDocument` into
|
|
1625
|
-
function
|
|
1698
|
+
/** Write a whole `VideoDocument` into the mirror draft (used to seed a fresh doc). */
|
|
1699
|
+
function seedDraft(draft, document) {
|
|
1626
1700
|
draft.meta = {
|
|
1627
1701
|
schema_version: document.meta.schema_version,
|
|
1628
1702
|
draft_id: document.meta.draft_id ?? void 0,
|
|
@@ -1647,124 +1721,10 @@ function toTrackRow(track) {
|
|
|
1647
1721
|
items: (track.items ?? []).map((item) => ({
|
|
1648
1722
|
part_id: item.part_id,
|
|
1649
1723
|
time_position: item.time_position,
|
|
1650
|
-
fallback_abs_ms: item.fallback_abs_ms
|
|
1724
|
+
fallback_abs_ms: item.fallback_abs_ms,
|
|
1725
|
+
duration_override_ms: item.duration_override_ms
|
|
1651
1726
|
}))
|
|
1652
1727
|
};
|
|
1653
1728
|
}
|
|
1654
1729
|
//#endregion
|
|
1655
|
-
|
|
1656
|
-
/**
|
|
1657
|
-
* Part-id generation, aligned with the online ecosystem.
|
|
1658
|
-
*
|
|
1659
|
-
* The authoritative online producers — agent-harness (`@harness/shared`
|
|
1660
|
-
* `genObjId`) and director.v2 (`common/obj_id.py` `gen_obj_id`) — both mint part
|
|
1661
|
-
* ids as `` `${prefix}_${ulid()}` ``, and real captured drafts use exactly that
|
|
1662
|
-
* shape (`clip_…` / `spe_…` / `cap_…` / `bgm_…`, each a 26-char ULID). The engine
|
|
1663
|
-
* previously emitted `vc_<base36 timestamp><6 random>`, a different prefix AND a
|
|
1664
|
-
* different encoding — the sole cross-repo id divergence. This module removes it
|
|
1665
|
-
* by emitting the same `<prefix>_<ULID>` bytes.
|
|
1666
|
-
*
|
|
1667
|
-
* The ULID is generated inline (Crockford Base32, 48-bit time + 80-bit random)
|
|
1668
|
-
* rather than pulling the `ulid` npm package: the randomness class matches the
|
|
1669
|
-
* old generator (both `Math.random`-based) and it keeps `@mengine/medeo-client`
|
|
1670
|
-
* dependency-free for a purely mechanical id string. Part ids only need to be
|
|
1671
|
-
* unique and lexicographically time-sortable, which this satisfies.
|
|
1672
|
-
*/
|
|
1673
|
-
/** Crockford Base32 alphabet (no I, L, O, U), per the ULID spec. */
|
|
1674
|
-
const CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
1675
|
-
const TIME_LEN = 10;
|
|
1676
|
-
const RANDOM_LEN = 16;
|
|
1677
|
-
function encodeTime(now) {
|
|
1678
|
-
let out = "";
|
|
1679
|
-
let ms = now;
|
|
1680
|
-
for (let i = TIME_LEN - 1; i >= 0; i--) {
|
|
1681
|
-
const mod = ms % 32;
|
|
1682
|
-
out = CROCKFORD[mod] + out;
|
|
1683
|
-
ms = (ms - mod) / 32;
|
|
1684
|
-
}
|
|
1685
|
-
return out;
|
|
1686
|
-
}
|
|
1687
|
-
function encodeRandom() {
|
|
1688
|
-
let out = "";
|
|
1689
|
-
for (let i = 0; i < RANDOM_LEN; i++) out += CROCKFORD[Math.floor(Math.random() * 32)];
|
|
1690
|
-
return out;
|
|
1691
|
-
}
|
|
1692
|
-
/** A 26-char Crockford Base32 ULID (10-char time + 16-char random). */
|
|
1693
|
-
function ulid() {
|
|
1694
|
-
return encodeTime(Date.now()) + encodeRandom();
|
|
1695
|
-
}
|
|
1696
|
-
function generatePartId(prefix) {
|
|
1697
|
-
return `${prefix}_${ulid()}`;
|
|
1698
|
-
}
|
|
1699
|
-
//#endregion
|
|
1700
|
-
//#region src/document/plain-memory-adapter.ts
|
|
1701
|
-
/**
|
|
1702
|
-
* Pure in-memory `SemanticDocumentAdapter` — no Loro/WASM. Holds a
|
|
1703
|
-
* `VideoDocumentDraft` object and applies each `transact` via immer `produce`,
|
|
1704
|
-
* journaling every audit that actually mutated state (plus any ids minted
|
|
1705
|
-
* during that transact).
|
|
1706
|
-
*
|
|
1707
|
-
* Known benign difference vs `MirrorVideoDocumentAdapter`: the editor's
|
|
1708
|
-
* `setPart` assigns a fresh part object on every call, so a same-value rewrite
|
|
1709
|
-
* produces a new immer state and IS journaled here, while the mirror's deep
|
|
1710
|
-
* diff emits no commit. Terminal `snapshot()` stays equal; replay is idempotent.
|
|
1711
|
-
*/
|
|
1712
|
-
var PlainMemoryAdapter = class {
|
|
1713
|
-
state;
|
|
1714
|
-
_journal = [];
|
|
1715
|
-
baseIdFactory;
|
|
1716
|
-
/** Non-null only while a `transact` edit callback is running. */
|
|
1717
|
-
pendingIds = null;
|
|
1718
|
-
/**
|
|
1719
|
-
* Recording wrapper around the underlying factory. Callers (sandbox editor)
|
|
1720
|
-
* use this so every minted id is appended to the current transact's list.
|
|
1721
|
-
*/
|
|
1722
|
-
idFactory;
|
|
1723
|
-
constructor(document, options) {
|
|
1724
|
-
assertValidVideoDocument(document);
|
|
1725
|
-
const draft = {};
|
|
1726
|
-
writeVideoDocumentToDraft(draft, document);
|
|
1727
|
-
this.state = draft;
|
|
1728
|
-
this.baseIdFactory = options?.idFactory ?? generatePartId;
|
|
1729
|
-
this.idFactory = (prefix) => {
|
|
1730
|
-
const id = this.baseIdFactory(prefix);
|
|
1731
|
-
if (this.pendingIds != null) this.pendingIds.push(id);
|
|
1732
|
-
return id;
|
|
1733
|
-
};
|
|
1734
|
-
}
|
|
1735
|
-
get journal() {
|
|
1736
|
-
return this._journal;
|
|
1737
|
-
}
|
|
1738
|
-
hasContent() {
|
|
1739
|
-
return (this.state.meta?.schema_version ?? "") !== "";
|
|
1740
|
-
}
|
|
1741
|
-
snapshot() {
|
|
1742
|
-
return readVideoDocumentFromDraft(this.state);
|
|
1743
|
-
}
|
|
1744
|
-
/**
|
|
1745
|
-
* Apply one op via immer. A throw in `edit` discards the draft (state and
|
|
1746
|
-
* journal unchanged). When `produce` returns the same reference, there was
|
|
1747
|
-
* no structural change — skip journal, matching mirror "no change, no commit".
|
|
1748
|
-
*/
|
|
1749
|
-
transact(edit, audit) {
|
|
1750
|
-
this.pendingIds = [];
|
|
1751
|
-
try {
|
|
1752
|
-
const next = produce(this.state, edit);
|
|
1753
|
-
if (next !== this.state) {
|
|
1754
|
-
this.state = next;
|
|
1755
|
-
this._journal.push({
|
|
1756
|
-
...audit,
|
|
1757
|
-
generated_ids: this.pendingIds
|
|
1758
|
-
});
|
|
1759
|
-
}
|
|
1760
|
-
} finally {
|
|
1761
|
-
this.pendingIds = null;
|
|
1762
|
-
}
|
|
1763
|
-
}
|
|
1764
|
-
};
|
|
1765
|
-
/** Build a `PlainMemoryAdapter` seeded with `document`. */
|
|
1766
|
-
function createPlainMemoryAdapter(document, options) {
|
|
1767
|
-
return new PlainMemoryAdapter(document, options);
|
|
1768
|
-
}
|
|
1769
|
-
//#endregion
|
|
1770
|
-
export { resolveSpeechOverlapByShiftingVideos as A, partUnionToDraft as B, solveVideoDocument as C, reassignSpeechesToVideoClipsByTime as D, fillMainTrackTimeGaps as E, safeDurationMs as F, videoDocumentMirrorSchema as H, DEFAULT_UNIT_TIME_MS as I, VIDEO_DOCUMENT_SCHEMA_VERSION as L, TIMELINE_SKELETON_DURATION_MS as M, isEmptyVideoClip as N, recalculateTimelineDuration as O, partDurationMs as P, effectiveVideoClipDurationMs as R, laneTrackId as S, arrangeMainTrackSeamlessly as T, base64ToBytes as U, recordEntries as V, bytesToBase64 as W, partUnionSchema as _, createMirrorVideoDocument as a, ensureLaneTrack as b, readVideoDocumentFromDraft as c, derivePositionFromAbs as d, fromVideoDocument as f, validateVideoDocument as g, assertValidVideoDocument as h, MirrorVideoDocumentAdapter as i, syncAggregatedClipsTimePosition as j, resolveAllSpeechOverlaps as k, buildInitialVideoDocument as l, VideoDocumentValidationError as m, createPlainMemoryAdapter as n, createMirrorVideoDocumentAdapter as o, toVideoDocument as p, generatePartId as r, writeVideoDocumentToDraft as s, PlainMemoryAdapter as t, buildSpeechHostMap as u, videoDocumentSchema as v, cascadeAfterVideoClipChanges as w, findLaneTrack as x, LANE_KINDS_IN_STACK_ORDER as y, speedOf as z };
|
|
1730
|
+
export { TIMELINE_SKELETON_DURATION_MS as A, base64ToBytes as B, reassignSpeechesToVideoClipsByTime as C, resolveAnchoredClipsTimePosition as D, resolveAllSpeechOverlaps as E, VIDEO_DOCUMENT_SCHEMA_VERSION as F, effectiveVideoClipDurationMs as I, partUnionToDraft as L, partDurationMs as M, safeDurationMs as N, resolveSpeechOverlapByShiftingVideos as O, DEFAULT_UNIT_TIME_MS as P, recordEntries as R, fillMainTrackTimeGaps as S, recoverOrphanedSpeechAnchorsByTime as T, bytesToBase64 as V, findLaneTrack as _, buildInitialVideoDocument as a, cascadeAfterVideoClipChanges as b, fromVideoDocument as c, assertValidVideoDocument as d, validateVideoDocument as f, ensureLaneTrack as g, LANE_KINDS_IN_STACK_ORDER as h, readVideoDocumentFromDraft as i, isEmptyVideoClip as j, syncAggregatedClipsTimePosition as k, toVideoDocument as l, videoDocumentSchema as m, createMirrorVideoDocument as n, buildSpeechHostMap as o, partUnionSchema as p, createMirrorVideoDocumentAdapter as r, derivePositionFromAbs as s, MirrorVideoDocumentAdapter as t, VideoDocumentValidationError as u, laneTrackId as v, recalculateTimelineDuration as w, arrangeMainTrackSeamlessly as x, solveVideoDocument as y, videoDocumentMirrorSchema as z };
|