@mengine/medeo-client 1.3.1-alpha.0 → 1.3.1-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -11
- package/dist/{document-Caidonf8.js → document-Bf200CmD.js} +260 -72
- package/dist/{index-WxMNUbOa.d.ts → index-PYtGeXNk.d.ts} +36 -9
- package/dist/index.d.ts +79 -15
- package/dist/index.js +105 -113
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -44,8 +44,7 @@ boundary already fails rows whose media variants lack `external` or carry a
|
|
|
44
44
|
media is an explicit caller decision, and no implicit historical merge or
|
|
45
45
|
identity rewriting occurs. The
|
|
46
46
|
compatibility reader reads physical facts directly from the media variant;
|
|
47
|
-
Caption
|
|
48
|
-
`physical-asset`.
|
|
47
|
+
Caption text is assembled from its required AudioScript composition and never stored in an inline Asset.
|
|
49
48
|
|
|
50
49
|
`SequenceMarker` owns source/target ranges, duration, and time remapping. `Clip`
|
|
51
50
|
owns clip properties such as volume; `Track` owns track properties. References
|
|
@@ -74,15 +73,26 @@ their follow, keep-absolute, cascade, or detach decisions into the same entity
|
|
|
74
73
|
plan. A speech-overlap shift is explicit placement on the real visual Clips;
|
|
75
74
|
an uncovered time interval does not require an invented empty-media entity.
|
|
76
75
|
|
|
77
|
-
Voice links to
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
`
|
|
81
|
-
`
|
|
82
|
-
|
|
83
|
-
`
|
|
84
|
-
|
|
85
|
-
|
|
76
|
+
Generated Voice links to a pre-existing PhoneticScript through `phonetic-script-render`.
|
|
77
|
+
Caption and PhoneticScript each compose a real AudioScript through exactly one
|
|
78
|
+
`caption-composition` or `phonetic-script-composition` relation. AudioScript owns
|
|
79
|
+
`segments[].text`; the variants never persist a text copy. Read complete content
|
|
80
|
+
with `assembleCaptionContent` or `assemblePhoneticScriptContent`. Broken composition
|
|
81
|
+
fails explicitly. Recorded Audio/Video/Voice can be the ASR source via
|
|
82
|
+
`audio-script-source`, without creating a synthesis variant.
|
|
83
|
+
|
|
84
|
+
`insertCaptionClip` requires `audioScriptEntityId` and `selections`. Each selection
|
|
85
|
+
names a source `segmentId` and optionally a half-open Unicode code-point
|
|
86
|
+
`textRange: {start, end}`. This permits display re-segmentation without rewriting
|
|
87
|
+
the original script. `upsertVoiceoverTake` requires the real
|
|
88
|
+
`phoneticScriptEntityId` used for synthesis; its captions select the same script.
|
|
89
|
+
External speech identity and storage key stay on Voice.
|
|
90
|
+
|
|
91
|
+
AudioScript has no intrinsic Sequence and cannot enter a Clip. `audio-script-marker`
|
|
92
|
+
attaches directly assigned `segmentRanges` timing; annotation Markers never refer
|
|
93
|
+
to upstream Markers and cannot be Clip display Markers. Moving or aligning a
|
|
94
|
+
Caption changes its external display Marker, preserving intrinsic Caption extent.
|
|
95
|
+
Caption owns its styles and text selection. Background Audio's Marker declares
|
|
86
96
|
`durationPolicy: 'timeline'`: its source duration stays factual,
|
|
87
97
|
while the view fills the non-BGM timeline duration.
|
|
88
98
|
|
|
@@ -1524,6 +1524,123 @@ function isRecord$1(value) {
|
|
|
1524
1524
|
return typeof value === "object" && value != null && !Array.isArray(value);
|
|
1525
1525
|
}
|
|
1526
1526
|
//#endregion
|
|
1527
|
+
//#region ../medeo-dsl/src/composition.ts
|
|
1528
|
+
/**
|
|
1529
|
+
* Raised when a variant's complete content cannot be assembled from its
|
|
1530
|
+
* required composition Relation. Assembly never falls back to variant-local
|
|
1531
|
+
* text: a missing, ambiguous, or dangling source is an error, not an empty
|
|
1532
|
+
* read.
|
|
1533
|
+
*/
|
|
1534
|
+
var ScriptCompositionError = class extends Error {
|
|
1535
|
+
code;
|
|
1536
|
+
entityId;
|
|
1537
|
+
constructor(code, entityId, message) {
|
|
1538
|
+
super(message);
|
|
1539
|
+
this.code = code;
|
|
1540
|
+
this.entityId = entityId;
|
|
1541
|
+
this.name = "ScriptCompositionError";
|
|
1542
|
+
}
|
|
1543
|
+
};
|
|
1544
|
+
function compositionRelationKind(variantKind) {
|
|
1545
|
+
return variantKind === "caption" ? "caption-composition" : "phonetic-script-composition";
|
|
1546
|
+
}
|
|
1547
|
+
/**
|
|
1548
|
+
* Resolve the one AudioScript a variant composes. Relations are queried from
|
|
1549
|
+
* both endpoints, so persisted endpoint positions do not matter.
|
|
1550
|
+
*/
|
|
1551
|
+
function findComposedAudioScript(rows, variantEntityId, variantKind) {
|
|
1552
|
+
const kind = compositionRelationKind(variantKind);
|
|
1553
|
+
const edges = rows.relations.filter((relation) => relation.relationKind === kind && (relation.endpoint0EntityId === variantEntityId || relation.endpoint1EntityId === variantEntityId));
|
|
1554
|
+
if (edges.length === 0) throw new ScriptCompositionError("composition_missing", variantEntityId, `${variantKind} "${variantEntityId}" has no ${kind} Relation; it has no content without its AudioScript`);
|
|
1555
|
+
if (edges.length > 1) throw new ScriptCompositionError("composition_ambiguous", variantEntityId, `${variantKind} "${variantEntityId}" has ${edges.length} ${kind} Relations; exactly one AudioScript is required`);
|
|
1556
|
+
const edge = edges[0];
|
|
1557
|
+
const otherId = edge.endpoint0EntityId === variantEntityId ? edge.endpoint1EntityId : edge.endpoint0EntityId;
|
|
1558
|
+
const script = rows.entities.find((entity) => entity.entityId === otherId);
|
|
1559
|
+
if (script === void 0 || script.entityKind !== "audio-script") throw new ScriptCompositionError("composition_dangling", variantEntityId, `${variantKind} "${variantEntityId}" ${kind} Relation must resolve a live AudioScript, got "${script?.entityKind ?? "missing entity"}"`);
|
|
1560
|
+
return script;
|
|
1561
|
+
}
|
|
1562
|
+
/** Join the whole AudioScript text in segment order. */
|
|
1563
|
+
function assembleScriptText(script) {
|
|
1564
|
+
return scriptSegments(script).map((segment) => segment.text).join("");
|
|
1565
|
+
}
|
|
1566
|
+
function scriptSegments(script) {
|
|
1567
|
+
const segments = script.payload.segments;
|
|
1568
|
+
if (!Array.isArray(segments)) throw new ScriptCompositionError("composition_dangling", script.entityId, `AudioScript "${script.entityId}" requires segments`);
|
|
1569
|
+
if (!segments.every(isScriptSegment) || new Set(segments.map((s) => s.segmentId)).size !== segments.length) throw new ScriptCompositionError("invalid_script", script.entityId, "AudioScript requires valid segments with unique local segmentId and text");
|
|
1570
|
+
return segments;
|
|
1571
|
+
}
|
|
1572
|
+
function isScriptSegment(value) {
|
|
1573
|
+
if (typeof value !== "object" || value == null || Array.isArray(value)) return false;
|
|
1574
|
+
const segment = value;
|
|
1575
|
+
return typeof segment.segmentId === "string" && segment.segmentId.trim() !== "" && typeof segment.text === "string" && (segment.language === void 0 || typeof segment.language === "string");
|
|
1576
|
+
}
|
|
1577
|
+
/**
|
|
1578
|
+
* Assemble the complete Caption content from its AudioScript: the selected
|
|
1579
|
+
* segments in selection order, joined as display text. The Caption payload
|
|
1580
|
+
* never carries text, so a broken composition fails here instead of silently
|
|
1581
|
+
* rendering an empty caption.
|
|
1582
|
+
*/
|
|
1583
|
+
function assembleCaptionContent(rows, captionEntityId) {
|
|
1584
|
+
const caption = requireEntityKind(rows, captionEntityId, "caption");
|
|
1585
|
+
const script = findComposedAudioScript(rows, captionEntityId, "caption");
|
|
1586
|
+
const segments = selectAudioScriptSegments(script, captionSelections(caption));
|
|
1587
|
+
return {
|
|
1588
|
+
caption,
|
|
1589
|
+
audioScript: script,
|
|
1590
|
+
segments,
|
|
1591
|
+
text: segments.map((segment) => segment.text).join("")
|
|
1592
|
+
};
|
|
1593
|
+
}
|
|
1594
|
+
/**
|
|
1595
|
+
* Assemble the complete Phonetic Script content for TTS: the composed
|
|
1596
|
+
* AudioScript's base text plus the variant's own phoneme and prosody fields.
|
|
1597
|
+
*/
|
|
1598
|
+
function assemblePhoneticScriptContent(rows, phoneticScriptEntityId) {
|
|
1599
|
+
const phoneticScript = requireEntityKind(rows, phoneticScriptEntityId, "phonetic-script");
|
|
1600
|
+
const audioScript = findComposedAudioScript(rows, phoneticScriptEntityId, "phonetic-script");
|
|
1601
|
+
const segments = scriptSegments(audioScript);
|
|
1602
|
+
return {
|
|
1603
|
+
phoneticScript,
|
|
1604
|
+
audioScript,
|
|
1605
|
+
segments,
|
|
1606
|
+
text: segments.map((segment) => segment.text).join("")
|
|
1607
|
+
};
|
|
1608
|
+
}
|
|
1609
|
+
function captionSelections(caption) {
|
|
1610
|
+
const selections = caption.payload.selections;
|
|
1611
|
+
if (!Array.isArray(selections) || selections.length === 0) throw new ScriptCompositionError("empty_selection", caption.entityId, `Caption "${caption.entityId}" requires a non-empty segment selection into its AudioScript`);
|
|
1612
|
+
if (!selections.every(isSegmentSelection)) throw new ScriptCompositionError("invalid_selection", caption.entityId, "Caption selections require a segmentId and optional textRange");
|
|
1613
|
+
return selections;
|
|
1614
|
+
}
|
|
1615
|
+
function isSegmentSelection(value) {
|
|
1616
|
+
return typeof value === "object" && value != null && !Array.isArray(value) && typeof value.segmentId === "string" && value.segmentId.trim() !== "" && Object.keys(value).every((key) => key === "segmentId" || key === "textRange");
|
|
1617
|
+
}
|
|
1618
|
+
/** Select source text without creating another authoritative text field. */
|
|
1619
|
+
function selectAudioScriptSegments(script, selections) {
|
|
1620
|
+
if (!Array.isArray(selections) || selections.length === 0 || !selections.every(isSegmentSelection) || new Set(selections.map((s) => s.segmentId)).size !== selections.length) throw new ScriptCompositionError("invalid_selection", script.entityId, "Caption selections must be non-empty and name unique source segments");
|
|
1621
|
+
const bySegmentId = new Map(scriptSegments(script).map((segment) => [segment.segmentId, segment]));
|
|
1622
|
+
const selected = selections.map((selection) => {
|
|
1623
|
+
const segment = bySegmentId.get(selection.segmentId);
|
|
1624
|
+
if (segment === void 0) throw new ScriptCompositionError("unknown_segment", script.entityId, `Caption selection "${selection.segmentId}" does not name a segment of AudioScript "${script.entityId}"`);
|
|
1625
|
+
if (selection.textRange === void 0) return segment;
|
|
1626
|
+
const range = selection.textRange;
|
|
1627
|
+
const points = Array.from(segment.text);
|
|
1628
|
+
if (typeof range !== "object" || range === null || !Number.isSafeInteger(range.start) || !Number.isSafeInteger(range.end) || range.start < 0 || range.end <= range.start || range.end > points.length || Object.keys(range).some((key) => key !== "start" && key !== "end")) throw new ScriptCompositionError("invalid_selection", script.entityId, "Caption textRange must be a non-empty half-open Unicode code-point range within its source segment");
|
|
1629
|
+
return {
|
|
1630
|
+
...segment,
|
|
1631
|
+
text: points.slice(range.start, range.end).join("")
|
|
1632
|
+
};
|
|
1633
|
+
});
|
|
1634
|
+
if (!selected.map((segment) => segment.text).join("").trim()) throw new ScriptCompositionError("empty_selection", script.entityId, "Caption selection must contain visible source text");
|
|
1635
|
+
return selected;
|
|
1636
|
+
}
|
|
1637
|
+
function requireEntityKind(rows, entityIdValue, entityKind) {
|
|
1638
|
+
const entity = rows.entities.find((candidate) => candidate.entityId === entityIdValue);
|
|
1639
|
+
if (entity === void 0) throw new ScriptCompositionError("composition_dangling", entityIdValue, `Entity "${entityIdValue}" does not exist`);
|
|
1640
|
+
if (entity.entityKind !== entityKind) throw new ScriptCompositionError("composition_dangling", entityIdValue, `Entity "${entityIdValue}" must have kind "${entityKind}", got "${entity.entityKind}"`);
|
|
1641
|
+
return entity;
|
|
1642
|
+
}
|
|
1643
|
+
//#endregion
|
|
1527
1644
|
//#region ../medeo-dsl/src/ids.ts
|
|
1528
1645
|
function createEntityId(value) {
|
|
1529
1646
|
return createId(value, "EntityId");
|
|
@@ -1539,8 +1656,9 @@ function createId(value, label) {
|
|
|
1539
1656
|
//#region ../medeo-dsl/src/invariants.ts
|
|
1540
1657
|
/**
|
|
1541
1658
|
* Media variants own their Asset identity directly: a `physical-asset`
|
|
1542
|
-
* Relation may not bind them. Caption
|
|
1543
|
-
*
|
|
1659
|
+
* Relation may not bind them. Caption text is composed domain content, so
|
|
1660
|
+
* Captions do not bind Physical Assets either; the Relation vocabulary stays
|
|
1661
|
+
* open for future physical pipeline semantics.
|
|
1544
1662
|
*/
|
|
1545
1663
|
function validateMediaAssetIdentity(entity, index) {
|
|
1546
1664
|
return [...index.relationsOf(entity)].filter((relation) => relation.kind === "physical-asset").map(() => ({
|
|
@@ -1573,7 +1691,8 @@ function validateEntityRelationSet(entityRefs, index, options) {
|
|
|
1573
1691
|
issues.push(...validateClipPlacement(entity, index));
|
|
1574
1692
|
}
|
|
1575
1693
|
if (current.entityKind === "axvideo") issues.push(...validateAXVideoAdmission(entity, index));
|
|
1576
|
-
if (current.entityKind === "caption") issues.push(...
|
|
1694
|
+
if (current.entityKind === "caption") issues.push(...validateCaptionComposition(entity, index));
|
|
1695
|
+
if (current.entityKind === "phonetic-script") issues.push(...validatePhoneticComposition(entity, index));
|
|
1577
1696
|
issues.push(...validateSequenceComposition(entity));
|
|
1578
1697
|
}
|
|
1579
1698
|
issues.push(...validateClipAnchorCycles(entities, index));
|
|
@@ -1676,25 +1795,63 @@ function validateAXVideoAdmission(axVideo, index) {
|
|
|
1676
1795
|
message: "AXVideo must have exactly one live AXVideo-Marker Relation"
|
|
1677
1796
|
}];
|
|
1678
1797
|
}
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1798
|
+
/**
|
|
1799
|
+
* Variant composition is the content contract, not an optional label: a
|
|
1800
|
+
* Caption must compose exactly one live AudioScript and its segment selection
|
|
1801
|
+
* must name that script's own segments. Text is never stored on the variant,
|
|
1802
|
+
* so a missing source means no valid caption content and fails validation.
|
|
1803
|
+
*/
|
|
1804
|
+
function validateCaptionComposition(caption, index) {
|
|
1805
|
+
return validateVariantComposition(caption, index, "caption", "caption-composition", "caption_composition_required");
|
|
1806
|
+
}
|
|
1807
|
+
/** Same required-composition contract for the pronunciation variant. */
|
|
1808
|
+
function validatePhoneticComposition(phonetic, index) {
|
|
1809
|
+
return validateVariantComposition(phonetic, index, "phonetic-script", "phonetic-script-composition", "phonetic_script_composition_required");
|
|
1810
|
+
}
|
|
1811
|
+
function validateVariantComposition(variant, index, variantKind, compositionKind, issueCode) {
|
|
1812
|
+
const relations = [...index.relationsOf(variant)];
|
|
1813
|
+
const issues = [];
|
|
1814
|
+
const physicalEdges = ofKind(relations, "physical-asset");
|
|
1815
|
+
if (variantKind === "caption" && physicalEdges.length > 0) issues.push({
|
|
1816
|
+
code: "caption_physical_asset_forbidden",
|
|
1817
|
+
entityId: variant.entityId,
|
|
1818
|
+
message: "Caption text is composed from its AudioScript; Caption must not bind a Physical Asset"
|
|
1819
|
+
});
|
|
1820
|
+
const compositionEdges = ofKind(relations, compositionKind);
|
|
1821
|
+
if (compositionEdges.length !== 1) {
|
|
1822
|
+
issues.push({
|
|
1823
|
+
code: issueCode,
|
|
1824
|
+
entityId: variant.entityId,
|
|
1825
|
+
message: `${variantKind} must have exactly one ${compositionKind} Relation to a live AudioScript`
|
|
1826
|
+
});
|
|
1827
|
+
return issues;
|
|
1692
1828
|
}
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1829
|
+
const script = compositionEdges[0]?.other(variant)?.deref()?.current();
|
|
1830
|
+
if (script?.entityKind !== "audio-script") {
|
|
1831
|
+
issues.push({
|
|
1832
|
+
code: issueCode,
|
|
1833
|
+
entityId: variant.entityId,
|
|
1834
|
+
message: `${variantKind} ${compositionKind} Relation must resolve a live AudioScript`
|
|
1835
|
+
});
|
|
1836
|
+
return issues;
|
|
1837
|
+
}
|
|
1838
|
+
if (variantKind !== "caption") return issues;
|
|
1839
|
+
const selections = variant.current().selections;
|
|
1840
|
+
if (!Array.isArray(selections)) return issues;
|
|
1841
|
+
try {
|
|
1842
|
+
selectAudioScriptSegments({
|
|
1843
|
+
entityId: script.entityId,
|
|
1844
|
+
entityKind: "audio-script",
|
|
1845
|
+
payload: { segments: script.segments.map((segment) => ({ ...segment })) }
|
|
1846
|
+
}, selections);
|
|
1847
|
+
} catch (error) {
|
|
1848
|
+
issues.push({
|
|
1849
|
+
code: "caption_selection_invalid",
|
|
1850
|
+
entityId: variant.entityId,
|
|
1851
|
+
message: error instanceof Error ? error.message : "Invalid Caption selection"
|
|
1852
|
+
});
|
|
1853
|
+
}
|
|
1854
|
+
return issues;
|
|
1698
1855
|
}
|
|
1699
1856
|
function validateClipPlacement(clip, index) {
|
|
1700
1857
|
const marker = ofKind([...index.relationsOf(clip)], "clip-marker")[0]?.other(clip)?.deref();
|
|
@@ -1822,6 +1979,18 @@ function validateKnownEntityPayload(entity) {
|
|
|
1822
1979
|
const value = entity;
|
|
1823
1980
|
const problems = [];
|
|
1824
1981
|
if (value.lifecycle !== void 0 && !isRecord(value.lifecycle)) problems.push("lifecycle must be an object when present");
|
|
1982
|
+
if (entity.entityKind === "audio-script" || entity.entityKind === "phonetic-script") {
|
|
1983
|
+
for (const key of [
|
|
1984
|
+
"extent",
|
|
1985
|
+
"sampling",
|
|
1986
|
+
"coordinateSpace",
|
|
1987
|
+
"sourceRange",
|
|
1988
|
+
"targetRange",
|
|
1989
|
+
"duration",
|
|
1990
|
+
"startMs",
|
|
1991
|
+
"endMs"
|
|
1992
|
+
]) if (Object.hasOwn(value, key)) problems.push(`${key} is not intrinsic script data; assign an external annotation Marker`);
|
|
1993
|
+
}
|
|
1825
1994
|
switch (entity.entityKind) {
|
|
1826
1995
|
case "track":
|
|
1827
1996
|
validateOptionalField(value, "hidden", "boolean", problems);
|
|
@@ -1848,9 +2017,11 @@ function validateKnownEntityPayload(entity) {
|
|
|
1848
2017
|
validateMarkerPayload(value, problems);
|
|
1849
2018
|
break;
|
|
1850
2019
|
case "audio-script":
|
|
1851
|
-
case "phonetic-script":
|
|
1852
2020
|
validateScriptPayload(value, problems);
|
|
1853
2021
|
break;
|
|
2022
|
+
case "phonetic-script":
|
|
2023
|
+
validatePhoneticScriptPayload(value, problems);
|
|
2024
|
+
break;
|
|
1854
2025
|
case "timeline":
|
|
1855
2026
|
case "viewport": break;
|
|
1856
2027
|
case "clip":
|
|
@@ -1914,24 +2085,18 @@ function validateSegmentRanges(value, problems) {
|
|
|
1914
2085
|
function validateAssetPayload(value, problems) {
|
|
1915
2086
|
validateExternalLocator(value, problems);
|
|
1916
2087
|
validateStorageKey(value, problems);
|
|
1917
|
-
|
|
1918
|
-
if (inline !== void 0) if (!isRecord(inline)) problems.push("inline must be an object when present");
|
|
1919
|
-
else {
|
|
1920
|
-
if (inline.mediaType !== "text/plain") problems.push("inline.mediaType must be \"text/plain\"");
|
|
1921
|
-
if (typeof inline.text !== "string") problems.push("inline.text must be a string");
|
|
1922
|
-
}
|
|
1923
|
-
if (value.external !== void 0 && value.inline !== void 0) problems.push("Asset must not combine external and inline physical locations");
|
|
2088
|
+
if (value.inline !== void 0) problems.push("inline is not a physical location; text is domain content owned by its AudioScript");
|
|
1924
2089
|
}
|
|
1925
2090
|
/**
|
|
1926
2091
|
* Media variants own their Asset locator directly: `external` is required and
|
|
1927
|
-
*
|
|
2092
|
+
* textual domain content is owned by AudioScript; the physical-location
|
|
1928
2093
|
* vocabularies cannot mix.
|
|
1929
2094
|
*/
|
|
1930
2095
|
function validateMediaAssetFields(value, problems) {
|
|
1931
2096
|
if (value.external === void 0) problems.push("external is required; media variants own their Asset identity");
|
|
1932
2097
|
else validateExternalLocator(value, problems);
|
|
1933
2098
|
validateStorageKey(value, problems);
|
|
1934
|
-
if (value.inline !== void 0) problems.push("
|
|
2099
|
+
if (value.inline !== void 0) problems.push("media variants use external locators, not inline domain text");
|
|
1935
2100
|
}
|
|
1936
2101
|
function validateExternalLocator(value, problems) {
|
|
1937
2102
|
const external = value.external;
|
|
@@ -1958,7 +2123,27 @@ function validateVoicePayload(value, problems) {
|
|
|
1958
2123
|
if (voice.name !== void 0 && typeof voice.name !== "string") problems.push("voice.name must be a string when present");
|
|
1959
2124
|
}
|
|
1960
2125
|
function validateCaptionPayload(value, problems) {
|
|
1961
|
-
if (value.text !== void 0
|
|
2126
|
+
if (value.text !== void 0) problems.push("text is composed from the AudioScript; Caption must not store a text copy");
|
|
2127
|
+
const selections = value.selections;
|
|
2128
|
+
if (!Array.isArray(selections)) problems.push("selections must be a non-empty array of AudioScript segment selections");
|
|
2129
|
+
else {
|
|
2130
|
+
if (selections.length === 0) problems.push("selections must name at least one AudioScript segment");
|
|
2131
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2132
|
+
for (const [index, selection] of selections.entries()) {
|
|
2133
|
+
if (!isRecord(selection)) {
|
|
2134
|
+
problems.push(`selections[${index}] must be an object`);
|
|
2135
|
+
continue;
|
|
2136
|
+
}
|
|
2137
|
+
if (typeof selection.segmentId !== "string" || selection.segmentId.trim() === "") problems.push(`selections[${index}].segmentId must be a string`);
|
|
2138
|
+
else if (seen.has(selection.segmentId)) problems.push(`selections[${index}].segmentId must be unique within the Caption`);
|
|
2139
|
+
else seen.add(selection.segmentId);
|
|
2140
|
+
if (Object.keys(selection).some((key) => key !== "segmentId" && key !== "textRange")) problems.push(`selections[${index}] may only contain segmentId and textRange`);
|
|
2141
|
+
if (selection.textRange !== void 0) {
|
|
2142
|
+
const range = selection.textRange;
|
|
2143
|
+
if (!isRecord(range) || !Number.isSafeInteger(range.start) || !Number.isSafeInteger(range.end) || range.start < 0 || range.end <= range.start || Object.keys(range).some((key) => key !== "start" && key !== "end")) problems.push(`selections[${index}].textRange must be a non-empty half-open code-point range`);
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
1962
2147
|
const style = value.style;
|
|
1963
2148
|
if (style === void 0) return;
|
|
1964
2149
|
if (!isRecord(style)) {
|
|
@@ -1993,6 +2178,13 @@ function validateRange(value, path, required, problems) {
|
|
|
1993
2178
|
if (!Object.hasOwn(value, "start") || value.start === void 0) problems.push(`${path}.start is required`);
|
|
1994
2179
|
if (!Object.hasOwn(value, "end") || value.end === void 0) problems.push(`${path}.end is required`);
|
|
1995
2180
|
}
|
|
2181
|
+
/** Phonetic variants store pronunciation fields only; base text stays in the AudioScript. */
|
|
2182
|
+
function validatePhoneticScriptPayload(value, problems) {
|
|
2183
|
+
if (value.text !== void 0) problems.push("text is composed from AudioScript; PhoneticScript must not store a text copy");
|
|
2184
|
+
if (value.segments !== void 0) problems.push("segments carry the base text owned by the AudioScript; PhoneticScript stores pronunciation fields only");
|
|
2185
|
+
if (value.phonemeScript !== void 0 && (typeof value.phonemeScript !== "string" || value.phonemeScript.trim() === "")) problems.push("phonemeScript must be a non-empty string when present");
|
|
2186
|
+
if (value.prosody !== void 0 && !isRecord(value.prosody)) problems.push("prosody must be an object when present");
|
|
2187
|
+
}
|
|
1996
2188
|
function validateScriptPayload(value, problems) {
|
|
1997
2189
|
if (!Array.isArray(value.segments)) {
|
|
1998
2190
|
problems.push("segments must be an array");
|
|
@@ -2071,16 +2263,17 @@ function isOwnedLocalEntityValuePath(entityKind, path) {
|
|
|
2071
2263
|
].includes(entityKind) && /^(?:sampling|coordinateSpace|coordinateSpace\.unit|extent\.kind)$/.test(path)) return true;
|
|
2072
2264
|
if (entityKind === "sequence-marker" && /^(?:durationPolicy|duration\.mode|timeRemapping\.(?:kind|mode))$/.test(path)) return true;
|
|
2073
2265
|
if (entityKind === "sequence-marker" && /^segmentRanges\[\d+\]\.segmentId$/.test(path)) return true;
|
|
2074
|
-
if (entityKind === "asset" && /^(?:external\.(?:system|key)|storageKey
|
|
2266
|
+
if (entityKind === "asset" && /^(?:external\.(?:system|key)|storageKey)$/.test(path)) return true;
|
|
2075
2267
|
if (isMediaAssetVariantKind(entityKind) && /^(?:external\.(?:system|key)|storageKey)$/.test(path)) return true;
|
|
2076
2268
|
if (entityKind === "voice" && /^voice\.(?:system|key|name)$/.test(path)) return true;
|
|
2077
|
-
if (entityKind === "caption" && (path
|
|
2078
|
-
if (
|
|
2269
|
+
if (entityKind === "caption" && (path.startsWith("style.") || /^selections\[\d+\]\.segmentId$/.test(path))) return true;
|
|
2270
|
+
if (entityKind === "audio-script" && /^segments\[\d+\]\.(?:segmentId|text|language)$/.test(path)) return true;
|
|
2079
2271
|
return false;
|
|
2080
2272
|
}
|
|
2081
2273
|
function isOwnedLocalIdPath(entityKind, path) {
|
|
2082
2274
|
if (path === "lifecycle.actorId") return true;
|
|
2083
|
-
if (
|
|
2275
|
+
if (entityKind === "audio-script" && /^segments\[\d+\]\.segmentId$/.test(path)) return true;
|
|
2276
|
+
if (entityKind === "caption" && /^selections\[\d+\]\.segmentId$/.test(path)) return true;
|
|
2084
2277
|
if (entityKind === "sequence-marker" && /^segmentRanges\[\d+\]\.segmentId$/.test(path)) return true;
|
|
2085
2278
|
if (entityKind === "asset" && /^(?:tracks\[\d+\]\.trackId|renditions\[\d+\]\.renditionId)$/.test(path)) return true;
|
|
2086
2279
|
return false;
|
|
@@ -2187,8 +2380,15 @@ const generatedRelationSpec = Object.freeze({
|
|
|
2187
2380
|
validateEndpoints: (endpoints) => endpoints.every((endpoint) => isGeneratedMedia(endpoint.current())),
|
|
2188
2381
|
validateMetadata: isEmptyMetadata
|
|
2189
2382
|
});
|
|
2190
|
-
|
|
2191
|
-
|
|
2383
|
+
/**
|
|
2384
|
+
* Variant composition: the required content relation between a variant and its
|
|
2385
|
+
* AudioScript. This is the assembly source for the variant's base text — never
|
|
2386
|
+
* a downgradeable provenance label. A variant without exactly one live
|
|
2387
|
+
* composition Relation has no valid content and fails validation.
|
|
2388
|
+
*/
|
|
2389
|
+
const phoneticScriptCompositionRelationSpec = metadataSpec("phonetic-script-composition", "phonetic-script", "audio-script", isSegmentAlignmentMetadata);
|
|
2390
|
+
/** See {@link phoneticScriptCompositionRelationSpec}; Caption is the display variant. */
|
|
2391
|
+
const captionCompositionRelationSpec = metadataSpec("caption-composition", "caption", "audio-script", isSegmentAlignmentMetadata);
|
|
2192
2392
|
const captionAlignmentRelationSpec = Object.freeze({
|
|
2193
2393
|
kind: "caption-alignment",
|
|
2194
2394
|
validateEndpoints: (endpoints) => hasKinds(endpoints, new Set(["caption"]), new Set(["audio", "voice"])),
|
|
@@ -2200,19 +2400,20 @@ const clipAnchorRelationSpec = Object.freeze({
|
|
|
2200
2400
|
validateEndpoints: (endpoints) => endpoints[0].current().entityKind === "clip" && endpoints[1].current().entityKind === "clip",
|
|
2201
2401
|
validateMetadata: isEmptyMetadata
|
|
2202
2402
|
});
|
|
2203
|
-
/**
|
|
2204
|
-
const
|
|
2205
|
-
kind: "
|
|
2206
|
-
validateEndpoints: (endpoints) =>
|
|
2207
|
-
const outputKind = endpoints[0].current().entityKind;
|
|
2208
|
-
return (outputKind === "audio" || outputKind === "voice") && endpoints[1].current().entityKind === "audio-script";
|
|
2209
|
-
},
|
|
2403
|
+
/** Voice is generated from PhoneticScript; kinds determine roles regardless of endpoint positions. */
|
|
2404
|
+
const phoneticScriptRenderRelationSpec = Object.freeze({
|
|
2405
|
+
kind: "phonetic-script-render",
|
|
2406
|
+
validateEndpoints: (endpoints) => hasKinds(endpoints, new Set(["voice"]), new Set(["phonetic-script"])),
|
|
2210
2407
|
validateMetadata: isEmptyMetadata
|
|
2211
2408
|
});
|
|
2212
|
-
/**
|
|
2409
|
+
/** AudioScript was transcribed from Audio, Video, or recorded Voice; kinds determine roles. */
|
|
2213
2410
|
const audioScriptSourceRelationSpec = Object.freeze({
|
|
2214
2411
|
kind: "audio-script-source",
|
|
2215
|
-
validateEndpoints: (endpoints) => hasKinds(endpoints, new Set(["audio-script"]), new Set([
|
|
2412
|
+
validateEndpoints: (endpoints) => hasKinds(endpoints, new Set(["audio-script"]), new Set([
|
|
2413
|
+
"audio",
|
|
2414
|
+
"video",
|
|
2415
|
+
"voice"
|
|
2416
|
+
])),
|
|
2216
2417
|
validateMetadata: isEmptyMetadata
|
|
2217
2418
|
});
|
|
2218
2419
|
/**
|
|
@@ -2236,11 +2437,11 @@ const builtInRelationSpecs = Object.freeze([
|
|
|
2236
2437
|
markerTimelineRelationSpec,
|
|
2237
2438
|
physicalAssetRelationSpec,
|
|
2238
2439
|
generatedRelationSpec,
|
|
2239
|
-
|
|
2240
|
-
|
|
2440
|
+
phoneticScriptCompositionRelationSpec,
|
|
2441
|
+
captionCompositionRelationSpec,
|
|
2241
2442
|
captionAlignmentRelationSpec,
|
|
2242
2443
|
clipAnchorRelationSpec,
|
|
2243
|
-
|
|
2444
|
+
phoneticScriptRenderRelationSpec,
|
|
2244
2445
|
audioScriptSourceRelationSpec,
|
|
2245
2446
|
audioScriptMarkerRelationSpec
|
|
2246
2447
|
]);
|
|
@@ -2339,7 +2540,7 @@ var BiRelationIndex = class {
|
|
|
2339
2540
|
byRelationId = /* @__PURE__ */ new Map();
|
|
2340
2541
|
link(input) {
|
|
2341
2542
|
if (input.spec.kind === "generated") throw new Error("Author generated Relations with linkGenerated({ output, input })");
|
|
2342
|
-
if (input.spec.kind === "clip-anchor" || input.spec.kind === "
|
|
2543
|
+
if (input.spec.kind === "clip-anchor" || input.spec.kind === "phonetic-script-render" || input.spec.kind === "audio-script-source") throw new Error(`Author ordered ${input.spec.kind} Relations with the dedicated role-named method`);
|
|
2343
2544
|
return this.linkValidated(input);
|
|
2344
2545
|
}
|
|
2345
2546
|
/** Author `generated(output, input)` without exposing positional arguments. */
|
|
@@ -2362,12 +2563,12 @@ var BiRelationIndex = class {
|
|
|
2362
2563
|
trace: input.trace
|
|
2363
2564
|
});
|
|
2364
2565
|
}
|
|
2365
|
-
/** Author `
|
|
2366
|
-
|
|
2566
|
+
/** Author `phonetic-script-render(output, phoneticScript)` without exposing positional arguments. */
|
|
2567
|
+
linkPhoneticScriptRender(input) {
|
|
2367
2568
|
return this.linkValidated({
|
|
2368
2569
|
relationId: input.relationId,
|
|
2369
|
-
spec:
|
|
2370
|
-
endpoints: [input.output, input.
|
|
2570
|
+
spec: phoneticScriptRenderRelationSpec,
|
|
2571
|
+
endpoints: [input.output, input.phoneticScript],
|
|
2371
2572
|
metadata: {},
|
|
2372
2573
|
trace: input.trace
|
|
2373
2574
|
});
|
|
@@ -2860,7 +3061,7 @@ function projectEntityTimeline(rows, meta) {
|
|
|
2860
3061
|
const asset = mediaAssetFacts(graph, content);
|
|
2861
3062
|
requireUntrimmedAudio(content, marker, placement);
|
|
2862
3063
|
const external = externalLocator(asset, "memota-speech");
|
|
2863
|
-
const
|
|
3064
|
+
const assembled = graph.adjacent(content.entityId, "phonetic-script-render").length > 0 || content.payload.voice !== void 0 ? assemblePhoneticScriptContent(rows, graph.one(content.entityId, "phonetic-script-render", "phonetic-script").entityId) : void 0;
|
|
2864
3065
|
const voice = content.payload.voice;
|
|
2865
3066
|
if (voice !== void 0 && (!object(voice) || voice.system !== "voice-library" || typeof voice.key !== "string")) fail("Voice must use an explicit voice-library locator");
|
|
2866
3067
|
const captionIds = layout.tracks.flatMap((candidate) => candidate.role === "caption" ? candidate.clips.filter((caption) => caption.anchorClipEntityId === clip.entityId).map((caption) => caption.clipEntityId) : []);
|
|
@@ -2870,7 +3071,7 @@ function projectEntityTimeline(rows, meta) {
|
|
|
2870
3071
|
media_duration_ms: placement.duration,
|
|
2871
3072
|
audio_storage_key: storageKey(asset),
|
|
2872
3073
|
origin_speech_id: external.key,
|
|
2873
|
-
audio_script:
|
|
3074
|
+
audio_script: assembled?.text ?? (graph.adjacent(content.entityId, "audio-script-source").length > 0 ? assembleScriptText(graph.one(content.entityId, "audio-script-source", "audio-script")) : ""),
|
|
2874
3075
|
volume: volume.data,
|
|
2875
3076
|
voice: object(voice) ? {
|
|
2876
3077
|
id: typeof voice.key === "string" ? voice.key : void 0,
|
|
@@ -2879,12 +3080,7 @@ function projectEntityTimeline(rows, meta) {
|
|
|
2879
3080
|
caption_ids: captionIds
|
|
2880
3081
|
} };
|
|
2881
3082
|
} else if (track.role === "caption") {
|
|
2882
|
-
const text = content.
|
|
2883
|
-
if (typeof text !== "string") fail("Caption " + content.entityId + " requires its text");
|
|
2884
|
-
const asset = graph.one(content.entityId, "physical-asset", "asset");
|
|
2885
|
-
const inline = asset.payload.inline;
|
|
2886
|
-
if (inline !== void 0 && (!object(inline) || inline.mediaType !== "text/plain" || inline.text !== text)) fail("Inline Caption Asset and Caption text must agree");
|
|
2887
|
-
if (inline === void 0 && !object(asset.payload.external)) fail("Caption Asset must identify physical text or contain actual inline text");
|
|
3083
|
+
const text = assembleCaptionContent(rows, content.entityId).text;
|
|
2888
3084
|
if (marker.payload.timeRemapping !== void 0) fail("Caption timeRemapping is not supported by this reader");
|
|
2889
3085
|
const style = captionStyle(content.payload.style);
|
|
2890
3086
|
const anchor = placement.anchorClipEntityId === void 0 ? void 0 : layout.clips.get(placement.anchorClipEntityId);
|
|
@@ -2972,14 +3168,6 @@ function storageKey(asset) {
|
|
|
2972
3168
|
if (typeof asset.payload.storageKey !== "string" || asset.payload.storageKey.trim() === "") fail("Asset " + asset.entityId + " requires its factual storageKey");
|
|
2973
3169
|
return asset.payload.storageKey;
|
|
2974
3170
|
}
|
|
2975
|
-
function scriptText(script) {
|
|
2976
|
-
const segments = script.payload.segments;
|
|
2977
|
-
if (!Array.isArray(segments)) fail("AudioScript requires segments");
|
|
2978
|
-
return segments.map((segment) => {
|
|
2979
|
-
if (!object(segment) || typeof segment.text !== "string") fail("AudioScript segment requires text");
|
|
2980
|
-
return segment.text;
|
|
2981
|
-
}).join("");
|
|
2982
|
-
}
|
|
2983
3171
|
function captionStyle(value) {
|
|
2984
3172
|
if (value === void 0) return void 0;
|
|
2985
3173
|
if (!object(value)) fail("Caption style must be an object");
|
|
@@ -3351,4 +3539,4 @@ function createPlainMemoryAdapter(document, options) {
|
|
|
3351
3539
|
return new PlainMemoryAdapter(document, options);
|
|
3352
3540
|
}
|
|
3353
3541
|
//#endregion
|
|
3354
|
-
export {
|
|
3542
|
+
export { ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION as $, VideoDocumentValidationError as A, cascadeAfterVideoClipChanges as B, hasSequence as C, derivePositionFromAbs as D, buildSpeechHostMap as E, LANE_KINDS_IN_STACK_ORDER as F, resolveAllSpeechOverlaps as G, fillMainTrackTimeGaps as H, ensureLaneTrack as I, TIMELINE_SKELETON_DURATION_MS as J, resolveSpeechOverlapByShiftingVideos as K, findLaneTrack as L, validateVideoDocument as M, partUnionSchema as N, fromVideoDocument as O, videoDocumentSchema as P, DEFAULT_UNIT_TIME_MS as Q, laneTrackId as R, selectAudioScriptSegments as S, buildInitialVideoDocument as T, reassignSpeechesToVideoClipsByTime as U, arrangeMainTrackSeamlessly as V, recalculateTimelineDuration as W, partDurationMs as X, isEmptyVideoClip as Y, safeDurationMs as Z, ScriptCompositionError as _, applyEntityTimelineProjection as a, videoDocumentMirrorSchema as at, assembleScriptText as b, writeVideoDocumentToDraft as c, resolveEntityTimelineLayout as d, VIDEO_DOCUMENT_SCHEMA_VERSION as et, EntityTimelineProjectionError as f, createRelationId as g, createEntityId as h, MirrorVideoDocumentAdapter as i, recordEntries as it, assertValidVideoDocument as j, toVideoDocument as k, readVideoDocumentFromDraft as l, isJsonObject as m, createPlainMemoryAdapter as n, speedOf as nt, createMirrorVideoDocument as o, base64ToBytes as ot, decodeEntityRelationRows as p, syncAggregatedClipsTimePosition as q, generatePartId as r, partUnionToDraft as rt, createMirrorVideoDocumentAdapter as s, bytesToBase64 as st, PlainMemoryAdapter as t, effectiveVideoClipDurationMs as tt, projectEntityTimeline as u, assembleCaptionContent as v, isMediaAssetVariantKind as w, findComposedAudioScript as x, assemblePhoneticScriptContent as y, solveVideoDocument as z };
|
|
@@ -849,6 +849,13 @@ type RelationId = string & {
|
|
|
849
849
|
readonly [relationIdBrand]: 'RelationId';
|
|
850
850
|
};
|
|
851
851
|
//#endregion
|
|
852
|
+
//#region ../medeo-dsl/src/json-values.d.ts
|
|
853
|
+
type JsonPrimitive = string | number | boolean | null;
|
|
854
|
+
type JsonValue = JsonPrimitive | JsonObject | readonly JsonValue[];
|
|
855
|
+
type JsonObject = {
|
|
856
|
+
readonly [key: string]: JsonValue;
|
|
857
|
+
};
|
|
858
|
+
//#endregion
|
|
852
859
|
//#region ../medeo-dsl/src/entities.d.ts
|
|
853
860
|
type KnownEntityKind = 'axvideo' | 'timeline' | 'track' | 'clip' | 'asset' | 'video' | 'audio' | 'voice' | 'image' | 'sequence-marker' | 'viewport' | 'audio-script' | 'phonetic-script' | 'caption';
|
|
854
861
|
declare const extensionEntityKindBrand: unique symbol;
|
|
@@ -867,6 +874,11 @@ type SequenceDuration<Span = unknown> = {
|
|
|
867
874
|
readonly mode: 'fixed';
|
|
868
875
|
readonly value: Span;
|
|
869
876
|
};
|
|
877
|
+
interface ScriptTextSegment {
|
|
878
|
+
readonly segmentId: string;
|
|
879
|
+
readonly text: string;
|
|
880
|
+
readonly language?: string;
|
|
881
|
+
}
|
|
870
882
|
interface VoiceDescriptor {
|
|
871
883
|
readonly system: 'voice-library';
|
|
872
884
|
readonly key: string;
|
|
@@ -888,16 +900,31 @@ interface CaptionStyleFields {
|
|
|
888
900
|
readonly positionX?: number;
|
|
889
901
|
readonly positionY?: number;
|
|
890
902
|
}
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
903
|
+
/**
|
|
904
|
+
* Half-open `[start, end)` position window inside one Segment's text, counted
|
|
905
|
+
* in Unicode code points (not UTF-16 code units), so a boundary never splits a
|
|
906
|
+
* surrogate pair. Positions are non-negative safe integers with `start < end`;
|
|
907
|
+
* `end` must not exceed the Segment's code-point length.
|
|
908
|
+
*/
|
|
909
|
+
interface CaptionTextRange extends JsonObject {
|
|
910
|
+
readonly start: number;
|
|
911
|
+
readonly end: number;
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* One ordered entry of the Caption's segment selection. `segmentId` quotes the
|
|
915
|
+
* composed AudioScript's own stable segment identity — a local id quoted by the
|
|
916
|
+
* variant, never a peer Entity reference. Text itself is never copied here;
|
|
917
|
+
* complete Caption content is assembled along the caption-composition Relation.
|
|
918
|
+
* The optional `textRange` narrows one Segment to an intra-Segment sub-span
|
|
919
|
+
* (intra-segment re-segmentation); without it the whole Segment text is selected.
|
|
920
|
+
*/
|
|
921
|
+
type CaptionSegmentSelection = JsonObject & {
|
|
922
|
+
readonly segmentId: string;
|
|
923
|
+
readonly textRange?: CaptionTextRange;
|
|
897
924
|
};
|
|
898
925
|
//#endregion
|
|
899
926
|
//#region ../medeo-dsl/src/relations.d.ts
|
|
900
|
-
type KnownRelationKind = 'timeline-track' | 'track-clip' | 'clip-marker' | 'marker-content' | 'axvideo-marker' | 'marker-timeline' | 'physical-asset' | 'generated' | 'phonetic-script-
|
|
927
|
+
type KnownRelationKind = 'timeline-track' | 'track-clip' | 'clip-marker' | 'marker-content' | 'axvideo-marker' | 'marker-timeline' | 'physical-asset' | 'generated' | 'phonetic-script-composition' | 'caption-composition' | 'caption-alignment' | 'clip-anchor' | 'phonetic-script-render' | 'audio-script-source' | 'audio-script-marker';
|
|
901
928
|
type RelationKind = KnownRelationKind | (string & {});
|
|
902
929
|
type RelationTrace = JsonObject;
|
|
903
930
|
/**
|
|
@@ -1655,10 +1682,10 @@ declare const videoDocumentSchema: z.ZodObject<{
|
|
|
1655
1682
|
tracks: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
1656
1683
|
id: z.ZodOptional<z.ZodString>;
|
|
1657
1684
|
parts_kind: z.ZodOptional<z.ZodEnum<{
|
|
1685
|
+
video_clip: "video_clip";
|
|
1658
1686
|
speech: "speech";
|
|
1659
1687
|
caption: "caption";
|
|
1660
1688
|
bgm: "bgm";
|
|
1661
|
-
video_clip: "video_clip";
|
|
1662
1689
|
}>>;
|
|
1663
1690
|
is_hidden: z.ZodOptional<z.ZodBoolean>;
|
|
1664
1691
|
items: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -1740,4 +1767,4 @@ declare const videoDocumentSchema: z.ZodObject<{
|
|
|
1740
1767
|
}, z.core.$loose>]>>>;
|
|
1741
1768
|
}, z.core.$loose>;
|
|
1742
1769
|
//#endregion
|
|
1743
|
-
export { VoiceDescriptor as $, generatePartId as A,
|
|
1770
|
+
export { VoiceDescriptor as $, generatePartId as A, effectiveVideoClipDurationMs as At, ResolvedEntityClipPlacement as B, PlannedSemanticOpKind as C, VideoClipPart as Ct, SnapshotReadable as D, VideoDocumentValidationIssueCode as Dt, SchemaValidator as E, VideoDocumentValidationIssue as Et, videoDocumentMirrorSchema as F, PartAggregation as Ft, EntityTimelineProjectionError as G, ResolvedEntityTrack as H, VideoDocumentValidationError as I, SpeedShift as It, CaptionSegmentSelection as J, EntityRelationRows as K, assertValidVideoDocument as L, Timeline$1 as Lt, TrackItemDraft as M, Attachment as Mt, VideoDocumentDraft as N, CaptionPart$1 as Nt, ValidationError as O, VideoDraft as Ot, VideoDocumentMirrorSchema as P, CaptionStyle as Pt, SequenceRange as Q, validateVideoDocument as R, Track$1 as Rt, ImplementedSemanticOpKind as S, VIDEO_DOCUMENT_SCHEMA_VERSION as St, isImplementedSemanticOpKind as T, VideoDocumentSchemaVersion as Tt, resolveEntityTimelineLayout as U, ResolvedEntityTimelineLayout as V, projectEntityTimeline as W, ScriptTextSegment as X, CaptionStyleFields as Y, SequenceDuration as Z, SemanticEditor as _, SpeechPart as _t, PlainMemoryAdapter as a, DerivedItemPosition as at, TransactAudit as b, TrackItem as bt, MirrorVideoDocumentAdapter as c, derivePositionFromAbs as ct, createMirrorVideoDocument as d, BgmPart as dt, JsonObject as et, createMirrorVideoDocumentAdapter as f, CaptionPart as ft, SemanticDocumentAdapter as g, PartUnion as gt, OpActor as h, PartKind as ht, JournalEntry as i, buildInitialVideoDocument as it, TrackDraft as j, speedOf as jt, PartIdFactory as k, VideoDraftPartUnion as kt, MirrorVideoDocumentOptions as l, fromVideoDocument as lt, CommitOptions as m, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION as mt, videoDocumentSchema as n, EntityId as nt, PlainMemoryAdapterOptions as o, SpeechHostMap as ot, writeVideoDocumentToDraft as p, DEFAULT_UNIT_TIME_MS as pt, EntityRow as q, readVideoDocumentFromDraft as r, InitialDocumentFacts as rt, createPlainMemoryAdapter as s, buildSpeechHostMap as st, partUnionSchema as t, JsonValue as tt, applyEntityTimelineProjection as u, toVideoDocument as ut, SemanticOpInput as v, Timeline as vt, SemanticOpKind as w, VideoDocument as wt, IMPLEMENTED_SEMANTIC_OP_KINDS as x, TrackItemTimePosition as xt, SemanticOpName as y, Track as yt, EntityTimelineTrackRole as z, TrackItem$1 as zt };
|