@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/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as index_d_exports } from "./index-CMa6ZCtX.js";
|
|
2
|
-
import { $ as VoiceDescriptor, A as generatePartId, At as
|
|
2
|
+
import { $ as VoiceDescriptor, A as generatePartId, At as effectiveVideoClipDurationMs, B as ResolvedEntityClipPlacement, C as PlannedSemanticOpKind, Ct as VideoClipPart, D as SnapshotReadable, Dt as VideoDocumentValidationIssueCode, E as SchemaValidator, Et as VideoDocumentValidationIssue, F as videoDocumentMirrorSchema, Ft as PartAggregation, G as EntityTimelineProjectionError, H as ResolvedEntityTrack, I as VideoDocumentValidationError, It as SpeedShift, J as CaptionSegmentSelection, K as EntityRelationRows, L as assertValidVideoDocument, Lt as Timeline$1, M as TrackItemDraft, Mt as Attachment, N as VideoDocumentDraft, Nt as CaptionPart$1, O as ValidationError, Ot as VideoDraft, P as VideoDocumentMirrorSchema, Pt as CaptionStyle, Q as SequenceRange, R as validateVideoDocument, Rt as Track$1, S as ImplementedSemanticOpKind, St as VIDEO_DOCUMENT_SCHEMA_VERSION, T as isImplementedSemanticOpKind, Tt as VideoDocumentSchemaVersion, U as resolveEntityTimelineLayout, V as ResolvedEntityTimelineLayout, W as projectEntityTimeline, X as ScriptTextSegment, Y as CaptionStyleFields, Z as SequenceDuration, _ as SemanticEditor, _t as SpeechPart, a as PlainMemoryAdapter, at as DerivedItemPosition, b as TransactAudit, bt as TrackItem, c as MirrorVideoDocumentAdapter, ct as derivePositionFromAbs, d as createMirrorVideoDocument, dt as BgmPart, et as JsonObject, f as createMirrorVideoDocumentAdapter, ft as CaptionPart, g as SemanticDocumentAdapter, gt as PartUnion, h as OpActor, ht as PartKind, i as JournalEntry, it as buildInitialVideoDocument, j as TrackDraft, jt as speedOf, k as PartIdFactory, kt as VideoDraftPartUnion, l as MirrorVideoDocumentOptions, lt as fromVideoDocument, m as CommitOptions, mt as ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, n as videoDocumentSchema, nt as EntityId, o as PlainMemoryAdapterOptions, ot as SpeechHostMap, p as writeVideoDocumentToDraft, pt as DEFAULT_UNIT_TIME_MS, q as EntityRow, r as readVideoDocumentFromDraft, rt as InitialDocumentFacts, s as createPlainMemoryAdapter, st as buildSpeechHostMap, t as partUnionSchema, tt as JsonValue, u as applyEntityTimelineProjection, ut as toVideoDocument, v as SemanticOpInput, vt as Timeline, w as SemanticOpKind, wt as VideoDocument, x as IMPLEMENTED_SEMANTIC_OP_KINDS, xt as TrackItemTimePosition, y as SemanticOpName, yt as Track, z as EntityTimelineTrackRole, zt as TrackItem$1 } from "./index-PYtGeXNk.js";
|
|
3
3
|
import { PeerID } from "loro-crdt";
|
|
4
4
|
import { DocState } from "@mengine/sync";
|
|
5
5
|
import { BaseDocStorage, Connection, DocDiff, DocPushReceipt, DocSnapshotRecord, DocStorage, DocStorageOptions, DocUpdate, DocUpdateRecord } from "@mengine/storage";
|
|
@@ -178,6 +178,57 @@ interface MengineEventStreamOptions {
|
|
|
178
178
|
}
|
|
179
179
|
declare function readMengineEventStream(options: MengineEventStreamOptions): Promise<void>;
|
|
180
180
|
//#endregion
|
|
181
|
+
//#region ../medeo-dsl/src/composition.d.ts
|
|
182
|
+
type ScriptCompositionIssueCode = 'composition_missing' | 'composition_ambiguous' | 'composition_dangling' | 'unknown_segment' | 'empty_selection' | 'invalid_script' | 'invalid_selection';
|
|
183
|
+
/**
|
|
184
|
+
* Raised when a variant's complete content cannot be assembled from its
|
|
185
|
+
* required composition Relation. Assembly never falls back to variant-local
|
|
186
|
+
* text: a missing, ambiguous, or dangling source is an error, not an empty
|
|
187
|
+
* read.
|
|
188
|
+
*/
|
|
189
|
+
declare class ScriptCompositionError extends Error {
|
|
190
|
+
readonly code: ScriptCompositionIssueCode;
|
|
191
|
+
readonly entityId: EntityId;
|
|
192
|
+
constructor(code: ScriptCompositionIssueCode, entityId: EntityId, message: string);
|
|
193
|
+
}
|
|
194
|
+
interface AssembledCaptionContent {
|
|
195
|
+
readonly caption: EntityRow<'caption'>;
|
|
196
|
+
readonly audioScript: EntityRow<'audio-script'>;
|
|
197
|
+
/** Selected AudioScript segments in Caption selection order. */
|
|
198
|
+
readonly segments: readonly ScriptTextSegment[];
|
|
199
|
+
/** Complete display text: the selected segments' text joined in order. */
|
|
200
|
+
readonly text: string;
|
|
201
|
+
}
|
|
202
|
+
interface AssembledPhoneticScriptContent {
|
|
203
|
+
readonly phoneticScript: EntityRow<'phonetic-script'>;
|
|
204
|
+
readonly audioScript: EntityRow<'audio-script'>;
|
|
205
|
+
/** All AudioScript segments in script order; the pronunciation variant never reorders text. */
|
|
206
|
+
readonly segments: readonly ScriptTextSegment[];
|
|
207
|
+
/** Complete base text owned by the AudioScript. */
|
|
208
|
+
readonly text: string;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Resolve the one AudioScript a variant composes. Relations are queried from
|
|
212
|
+
* both endpoints, so persisted endpoint positions do not matter.
|
|
213
|
+
*/
|
|
214
|
+
declare function findComposedAudioScript(rows: EntityRelationRows, variantEntityId: EntityId, variantKind: 'caption' | 'phonetic-script'): EntityRow<'audio-script'>;
|
|
215
|
+
/** Join the whole AudioScript text in segment order. */
|
|
216
|
+
declare function assembleScriptText(script: EntityRow<'audio-script'>): string;
|
|
217
|
+
/**
|
|
218
|
+
* Assemble the complete Caption content from its AudioScript: the selected
|
|
219
|
+
* segments in selection order, joined as display text. The Caption payload
|
|
220
|
+
* never carries text, so a broken composition fails here instead of silently
|
|
221
|
+
* rendering an empty caption.
|
|
222
|
+
*/
|
|
223
|
+
declare function assembleCaptionContent(rows: EntityRelationRows, captionEntityId: EntityId): AssembledCaptionContent;
|
|
224
|
+
/**
|
|
225
|
+
* Assemble the complete Phonetic Script content for TTS: the composed
|
|
226
|
+
* AudioScript's base text plus the variant's own phoneme and prosody fields.
|
|
227
|
+
*/
|
|
228
|
+
declare function assemblePhoneticScriptContent(rows: EntityRelationRows, phoneticScriptEntityId: EntityId): AssembledPhoneticScriptContent;
|
|
229
|
+
/** Select source text without creating another authoritative text field. */
|
|
230
|
+
declare function selectAudioScriptSegments(script: EntityRow<'audio-script'>, selections: readonly CaptionSegmentSelection[]): readonly ScriptTextSegment[];
|
|
231
|
+
//#endregion
|
|
181
232
|
//#region src/entity-editor/entity-graph-http-client.d.ts
|
|
182
233
|
/** One authenticated revision of the authoritative Medeo Entity graph. */
|
|
183
234
|
interface EntityGraphState {
|
|
@@ -288,7 +339,8 @@ interface DeleteClipTreeInput {
|
|
|
288
339
|
interface VoiceoverCaptionFact {
|
|
289
340
|
/** Stable placed caption identity supplied by the materialized side effect. */
|
|
290
341
|
readonly captionClipEntityId: string;
|
|
291
|
-
|
|
342
|
+
/** Ordered selection of AudioScript segments; caption text is never passed inline. */
|
|
343
|
+
readonly selections: readonly CaptionSegmentSelection[];
|
|
292
344
|
readonly startMs: number;
|
|
293
345
|
readonly durationMs: number;
|
|
294
346
|
readonly style?: CaptionStyleFields;
|
|
@@ -296,8 +348,8 @@ interface VoiceoverCaptionFact {
|
|
|
296
348
|
type VoiceoverTakeInput = {
|
|
297
349
|
readonly timelineEntityId: string; /** Stable placed speech identity, distinct from media.assetId. */
|
|
298
350
|
readonly voiceoverClipEntityId: string;
|
|
299
|
-
readonly media: VoiceMediaAssetFact; /**
|
|
300
|
-
readonly
|
|
351
|
+
readonly media: VoiceMediaAssetFact; /** Existing pronunciation variant; its composed AudioScript stays the text owner. */
|
|
352
|
+
readonly phoneticScriptEntityId: string;
|
|
301
353
|
readonly volume: number;
|
|
302
354
|
readonly captions: readonly VoiceoverCaptionFact[];
|
|
303
355
|
} & ({
|
|
@@ -373,6 +425,9 @@ interface TrimClipInput {
|
|
|
373
425
|
interface VoiceoverTakeResult {
|
|
374
426
|
readonly voiceoverClipEntityId: string;
|
|
375
427
|
readonly voiceEntityId: string;
|
|
428
|
+
/** The pronunciation variant the Voice was rendered from. */
|
|
429
|
+
readonly phoneticScriptEntityId: string;
|
|
430
|
+
/** The base-text owner resolved along the phonetic composition Relation. */
|
|
376
431
|
readonly audioScriptEntityId: string;
|
|
377
432
|
readonly captionClipEntityIds: readonly string[];
|
|
378
433
|
}
|
|
@@ -405,7 +460,10 @@ interface InsertCaptionClipInput {
|
|
|
405
460
|
readonly timelineEntityId: string;
|
|
406
461
|
/** Stable placed caption identity, distinct from the Caption content identity. */
|
|
407
462
|
readonly captionClipEntityId?: string;
|
|
408
|
-
|
|
463
|
+
/** Existing base-text owner; the Caption composes it instead of storing text. */
|
|
464
|
+
readonly audioScriptEntityId: string;
|
|
465
|
+
/** Ordered selection of the AudioScript segments this Caption displays. */
|
|
466
|
+
readonly selections: readonly CaptionSegmentSelection[];
|
|
409
467
|
/** Intrinsic cue length of the Caption entity itself; display comes from the placement. */
|
|
410
468
|
readonly durationMs: number;
|
|
411
469
|
readonly style?: CaptionStyleFields;
|
|
@@ -490,18 +548,26 @@ declare class EntityTimelineEditor {
|
|
|
490
548
|
setCaptionVisibility(input: SetCaptionVisibilityInput): void;
|
|
491
549
|
patchCaptionStyle(input: PatchCaptionStyleInput): void;
|
|
492
550
|
/**
|
|
493
|
-
* Place
|
|
494
|
-
*
|
|
495
|
-
*
|
|
496
|
-
* the returned Clip later changes the Clip/Marker,
|
|
551
|
+
* Place a Caption as a composed variant of an existing AudioScript: the
|
|
552
|
+
* entity stores only its selection, style, and inherent cue-bounded
|
|
553
|
+
* Sequence — never text. The Clip and its display Marker describe this use;
|
|
554
|
+
* moving or stretching the returned Clip later changes the Clip/Marker,
|
|
555
|
+
* never the Caption entity or the AudioScript.
|
|
497
556
|
*/
|
|
498
557
|
insertCaptionClip(input: InsertCaptionClipInput): ClipEntityId;
|
|
499
558
|
private insertPlacedClipIntoDraft;
|
|
500
559
|
private ensureRoleTrack;
|
|
501
|
-
|
|
560
|
+
/** The existing pronunciation variant a Voice consumes; composition is required. */
|
|
561
|
+
private requireComposedPhoneticScript;
|
|
562
|
+
/** Preserve the factual synthesis input, regardless of persisted endpoint positions. */
|
|
563
|
+
private ensurePhoneticRender;
|
|
502
564
|
private reconcileVoiceoverCaptions;
|
|
503
565
|
private ensureRoleTrackForClip;
|
|
504
566
|
private replaceCaptionSemanticRelations;
|
|
567
|
+
/**
|
|
568
|
+
* Remove one placed Caption use. The composed AudioScript outlives the
|
|
569
|
+
* caption: it may anchor further captions and remains the text owner.
|
|
570
|
+
*/
|
|
505
571
|
private removeCaptionClipGraph;
|
|
506
572
|
private replaceAnchorHost;
|
|
507
573
|
/** Rebuild the legacy edit baseline from current visual order before a high-level cascade. */
|
|
@@ -538,8 +604,7 @@ interface EditorFoundation {
|
|
|
538
604
|
* Image/Video/Audio/Voice Entity must carry its own external locator, every
|
|
539
605
|
* external asset id has exactly one claimant, and no media variant may be
|
|
540
606
|
* bound through a legacy `physical-asset` Relation. Dual-entity media graphs
|
|
541
|
-
* are rejected, not migrated. Caption
|
|
542
|
-
* `physical-asset` binding.
|
|
607
|
+
* are rejected, not migrated. Caption composes AudioScript text and has no physical text Asset.
|
|
543
608
|
*/
|
|
544
609
|
declare function assertCanonicalEditorResources(rows: EntityRelationRows): void;
|
|
545
610
|
/**
|
|
@@ -550,8 +615,7 @@ declare function assertCanonicalEditorResources(rows: EntityRelationRows): void;
|
|
|
550
615
|
*
|
|
551
616
|
* 1. every Image/Video/Audio/Voice Entity carries its own Asset `external`
|
|
552
617
|
* identity;
|
|
553
|
-
* 2. no `physical-asset` Relation may bind a media variant
|
|
554
|
-
* text keeps its inline Asset and binding);
|
|
618
|
+
* 2. no `physical-asset` Relation may bind a media variant or Caption;
|
|
555
619
|
* 3. a self-carried media identity is immutable — it cannot be rewritten to
|
|
556
620
|
* another asset id.
|
|
557
621
|
*
|
|
@@ -1491,4 +1555,4 @@ declare function hostForAbsMs(ranges: MainClipRange[], absMs: number): MainClipR
|
|
|
1491
1555
|
*/
|
|
1492
1556
|
declare function relativePositionForAbs(ranges: MainClipRange[], absMs: number): TrackItemTimePosition;
|
|
1493
1557
|
//#endregion
|
|
1494
|
-
export { type Aggregation, type Attachment, type AudioMediaAssetFact, type BgmPart, type CaptionPart, type CaptionStyle, type ClipEntityId, type ClipPlacement, type CommitOptions, DEFAULT_UNIT_TIME_MS, type DeleteBgmInput, type DeleteClipInput, type DeleteClipTreeInput, type DeleteVoiceoverInput, type DerivedItemPosition, type DocStorageLike, type DocVersionMark, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, type EditorFoundation, type EntityGraphCommitOptions, EntityGraphHttpClient, type EntityGraphState, EntityTimelineEditor, type EntityTimelineIdFactory, EntityTimelineProjectionError, type EntityTimelineTrackRole, IMPLEMENTED_SEMANTIC_OP_KINDS, type ImageMediaAssetFact, type ImplementedSemanticOpKind, type ImportedMediaAsset, type InitialDocumentFacts, type InsertCaptionClipInput, type InsertClipInput, type InsertMediaClipInput, type InsertMediaClipsInput, type InsertPlacedClipInput, type JournalEntry, LANE_KINDS_IN_STACK_ORDER, type LaneKind, type LinearClipSpeed, type MainClipRange, type MakeEmptyPart, ManualSyncDoc, type ManualSyncDocOptions, MedeoHttpDocStorage, type MedeoHttpDocStorageOptions, type MediaAssetFact, type MediaClipInsertion, MemoryDocStorage, MengineAckFailedError, type MengineAuditEntry, type MengineAuditResponse, MengineDocSession, type MengineDocSessionOptions, type MengineDocSessionUpdateEvent, type MengineDocumentVersion, type MengineEventStreamOptions, MengineHttpClient, type MengineHttpClientOptions, MengineHttpRequestError, MenginePushRejectedError, type MenginePushResponse, type MenginePushUpdateResponse, type MengineRejectedResponse, type MengineSnapshotResponse, type MengineSseUpdateEvent, type MengineSyncResponse, type MengineUpdateMeta, MirrorVideoDocumentAdapter, type MirrorVideoDocumentOptions, type MoveClipInput, type MoveClipsToStartsInput, type MoveSequentialClipsInput, type MoveVoiceoverInput, type OpActor, type PartAggregation, type PartIdFactory, type PartKind, type PartUnion, type PatchCaptionStyleInput, PlainMemoryAdapter, type PlainMemoryAdapterOptions, type PlannedSemanticOpKind, type PullFailureReason, type PullResult, type PushOutcome, type PushOutcomeKind, type PushResult, type PushResultKind, type ReplaceClipContentInput, type ReplaceMediaClipInput, type ReplaceSequentialClipsInput, type ReplacementMediaClipInput, type ResolvedEntityClipPlacement, type ResolvedEntityTimelineLayout, type ResolvedEntityTrack, SchemaValidator, type SemanticDocumentAdapter, SemanticEditor, type SemanticOpInput, type SemanticOpKind, type SemanticOpName, type SequentialClipAnchor, type SetBgmInput, type SetCaptionVisibilityInput, type SetClipPlacementInput, type SetClipSpeedInput, type SetClipVolumeInput, type SnapshotReadable, type SolvedVideoDocument, type SpeechHostMap, type SpeechPart, type SpeedShift, TIMELINE_SKELETON_DURATION_MS, type Timeline, type TimelineDoc, type TimelineItem, type Track, type TrackDraft, type TrackItem, type TrackItemDraft, type TrackItemTimePosition, type TransactAudit, type TrimClipInput, type UpdateClipInput, type UpdateClipMarkerInput, VIDEO_DOCUMENT_SCHEMA_VERSION, ValidationError, type VideoClipPart, type VideoDocument, type VideoDocumentDraft, type VideoDocumentMirrorSchema, type VideoDocumentSchemaVersion, VideoDocumentValidationError, type VideoDocumentValidationIssue, type VideoDocumentValidationIssueCode, type VideoDraft, type CaptionPart$1 as VideoDraftCaptionPart, type VideoDraftPartUnion, type Timeline$1 as VideoDraftTimeline, type Track$1 as VideoDraftTrack, type TrackItem$1 as VideoDraftTrackItem, type VideoMediaAssetFact, type VisualMediaAssetFact, type VoiceMediaAssetFact, type VoiceoverCaptionFact, type VoiceoverTakeInput, type VoiceoverTakeResult, type WaitForServerAckOptions, applyEntityTimelineProjection, arrangeMainTrackSeamlessly, assertCanonicalEditorResources, assertEntityProjectionPreservesLegacy, assertMediaAssetWritePolicy, assertValidVideoDocument, base64ToBytes, buildInitialVideoDocument, buildSpeechHostMap, bytesToBase64, cascadeAfterVideoClipChanges, createEditSandbox, createMirrorVideoDocument, createMirrorVideoDocumentAdapter, createPlainMemoryAdapter, decodeDocVersionMark, derivePositionFromAbs, effectiveVideoClipDurationMs, encodeDocVersionMark, ensureEditorFoundation, ensureLaneTrack, fillMainTrackTimeGaps, findLaneTrack, fromVideoDocument, generatePartId, getAt, hostForAbsMs, importMediaAsset, isEmptyVideoClip, isImplementedSemanticOpKind, isMap, laneTrackId, mainTrackRanges, migrateLegacyTimelineToEntities, partDurationMs, partUnionSchema, projectEntityTimeline, readMainTrackItems, readMengineEventStream, readPart, readPartDurationMs, readVideoDocumentFromDraft, reassignSpeechesToVideoClipsByTime, recalculateTimelineDuration, relativePositionForAbs, replayJournal, resolveAllSpeechOverlaps, resolveEntityTimelineLayout, resolveSpeechOverlapByShiftingVideos, safeDurationMs, index_d_exports as schemas, snapshotToPlain, solveVideoDocument, speedOf, syncAggregatedClipsTimePosition, toVideoDocument, validateVideoDocument, videoDocumentMirrorSchema, videoDocumentSchema, writeVideoDocumentToDraft };
|
|
1558
|
+
export { type Aggregation, type AssembledCaptionContent, type AssembledPhoneticScriptContent, type Attachment, type AudioMediaAssetFact, type BgmPart, type CaptionPart, type CaptionSegmentSelection, type CaptionStyle, type ClipEntityId, type ClipPlacement, type CommitOptions, DEFAULT_UNIT_TIME_MS, type DeleteBgmInput, type DeleteClipInput, type DeleteClipTreeInput, type DeleteVoiceoverInput, type DerivedItemPosition, type DocStorageLike, type DocVersionMark, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, type EditorFoundation, type EntityGraphCommitOptions, EntityGraphHttpClient, type EntityGraphState, EntityTimelineEditor, type EntityTimelineIdFactory, EntityTimelineProjectionError, type EntityTimelineTrackRole, IMPLEMENTED_SEMANTIC_OP_KINDS, type ImageMediaAssetFact, type ImplementedSemanticOpKind, type ImportedMediaAsset, type InitialDocumentFacts, type InsertCaptionClipInput, type InsertClipInput, type InsertMediaClipInput, type InsertMediaClipsInput, type InsertPlacedClipInput, type JournalEntry, LANE_KINDS_IN_STACK_ORDER, type LaneKind, type LinearClipSpeed, type MainClipRange, type MakeEmptyPart, ManualSyncDoc, type ManualSyncDocOptions, MedeoHttpDocStorage, type MedeoHttpDocStorageOptions, type MediaAssetFact, type MediaClipInsertion, MemoryDocStorage, MengineAckFailedError, type MengineAuditEntry, type MengineAuditResponse, MengineDocSession, type MengineDocSessionOptions, type MengineDocSessionUpdateEvent, type MengineDocumentVersion, type MengineEventStreamOptions, MengineHttpClient, type MengineHttpClientOptions, MengineHttpRequestError, MenginePushRejectedError, type MenginePushResponse, type MenginePushUpdateResponse, type MengineRejectedResponse, type MengineSnapshotResponse, type MengineSseUpdateEvent, type MengineSyncResponse, type MengineUpdateMeta, MirrorVideoDocumentAdapter, type MirrorVideoDocumentOptions, type MoveClipInput, type MoveClipsToStartsInput, type MoveSequentialClipsInput, type MoveVoiceoverInput, type OpActor, type PartAggregation, type PartIdFactory, type PartKind, type PartUnion, type PatchCaptionStyleInput, PlainMemoryAdapter, type PlainMemoryAdapterOptions, type PlannedSemanticOpKind, type PullFailureReason, type PullResult, type PushOutcome, type PushOutcomeKind, type PushResult, type PushResultKind, type ReplaceClipContentInput, type ReplaceMediaClipInput, type ReplaceSequentialClipsInput, type ReplacementMediaClipInput, type ResolvedEntityClipPlacement, type ResolvedEntityTimelineLayout, type ResolvedEntityTrack, SchemaValidator, ScriptCompositionError, type SemanticDocumentAdapter, SemanticEditor, type SemanticOpInput, type SemanticOpKind, type SemanticOpName, type SequentialClipAnchor, type SetBgmInput, type SetCaptionVisibilityInput, type SetClipPlacementInput, type SetClipSpeedInput, type SetClipVolumeInput, type SnapshotReadable, type SolvedVideoDocument, type SpeechHostMap, type SpeechPart, type SpeedShift, TIMELINE_SKELETON_DURATION_MS, type Timeline, type TimelineDoc, type TimelineItem, type Track, type TrackDraft, type TrackItem, type TrackItemDraft, type TrackItemTimePosition, type TransactAudit, type TrimClipInput, type UpdateClipInput, type UpdateClipMarkerInput, VIDEO_DOCUMENT_SCHEMA_VERSION, ValidationError, type VideoClipPart, type VideoDocument, type VideoDocumentDraft, type VideoDocumentMirrorSchema, type VideoDocumentSchemaVersion, VideoDocumentValidationError, type VideoDocumentValidationIssue, type VideoDocumentValidationIssueCode, type VideoDraft, type CaptionPart$1 as VideoDraftCaptionPart, type VideoDraftPartUnion, type Timeline$1 as VideoDraftTimeline, type Track$1 as VideoDraftTrack, type TrackItem$1 as VideoDraftTrackItem, type VideoMediaAssetFact, type VisualMediaAssetFact, type VoiceMediaAssetFact, type VoiceoverCaptionFact, type VoiceoverTakeInput, type VoiceoverTakeResult, type WaitForServerAckOptions, applyEntityTimelineProjection, arrangeMainTrackSeamlessly, assembleCaptionContent, assemblePhoneticScriptContent, assembleScriptText, assertCanonicalEditorResources, assertEntityProjectionPreservesLegacy, assertMediaAssetWritePolicy, assertValidVideoDocument, base64ToBytes, buildInitialVideoDocument, buildSpeechHostMap, bytesToBase64, cascadeAfterVideoClipChanges, createEditSandbox, createMirrorVideoDocument, createMirrorVideoDocumentAdapter, createPlainMemoryAdapter, decodeDocVersionMark, derivePositionFromAbs, effectiveVideoClipDurationMs, encodeDocVersionMark, ensureEditorFoundation, ensureLaneTrack, fillMainTrackTimeGaps, findComposedAudioScript, findLaneTrack, fromVideoDocument, generatePartId, getAt, hostForAbsMs, importMediaAsset, isEmptyVideoClip, isImplementedSemanticOpKind, isMap, laneTrackId, mainTrackRanges, migrateLegacyTimelineToEntities, partDurationMs, partUnionSchema, projectEntityTimeline, readMainTrackItems, readMengineEventStream, readPart, readPartDurationMs, readVideoDocumentFromDraft, reassignSpeechesToVideoClipsByTime, recalculateTimelineDuration, relativePositionForAbs, replayJournal, resolveAllSpeechOverlaps, resolveEntityTimelineLayout, resolveSpeechOverlapByShiftingVideos, safeDurationMs, index_d_exports as schemas, selectAudioScriptSegments, snapshotToPlain, solveVideoDocument, speedOf, syncAggregatedClipsTimePosition, toVideoDocument, validateVideoDocument, videoDocumentMirrorSchema, videoDocumentSchema, writeVideoDocumentToDraft };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, A as VideoDocumentValidationError, B as cascadeAfterVideoClipChanges, C as hasSequence, D as derivePositionFromAbs, E as buildSpeechHostMap, F as LANE_KINDS_IN_STACK_ORDER, G as resolveAllSpeechOverlaps, H as fillMainTrackTimeGaps, I as ensureLaneTrack, J as TIMELINE_SKELETON_DURATION_MS, K as resolveSpeechOverlapByShiftingVideos, L as findLaneTrack, M as validateVideoDocument, N as partUnionSchema, O as fromVideoDocument, P as videoDocumentSchema, Q as DEFAULT_UNIT_TIME_MS, R as laneTrackId, S as selectAudioScriptSegments, T as buildInitialVideoDocument, U as reassignSpeechesToVideoClipsByTime, V as arrangeMainTrackSeamlessly, W as recalculateTimelineDuration, X as partDurationMs, Y as isEmptyVideoClip, Z as safeDurationMs, _ as ScriptCompositionError, a as applyEntityTimelineProjection, at as videoDocumentMirrorSchema, b as assembleScriptText, c as writeVideoDocumentToDraft, d as resolveEntityTimelineLayout, et as VIDEO_DOCUMENT_SCHEMA_VERSION, f as EntityTimelineProjectionError, g as createRelationId, h as createEntityId, i as MirrorVideoDocumentAdapter, it as recordEntries, j as assertValidVideoDocument, k as toVideoDocument, l as readVideoDocumentFromDraft, m as isJsonObject, n as createPlainMemoryAdapter, nt as speedOf, o as createMirrorVideoDocument, ot as base64ToBytes, p as decodeEntityRelationRows, q as syncAggregatedClipsTimePosition, r as generatePartId, rt as partUnionToDraft, s as createMirrorVideoDocumentAdapter, st as bytesToBase64, t as PlainMemoryAdapter, tt as effectiveVideoClipDurationMs, u as projectEntityTimeline, v as assembleCaptionContent, w as isMediaAssetVariantKind, x as findComposedAudioScript, y as assemblePhoneticScriptContent, z as solveVideoDocument } from "./document-Bf200CmD.js";
|
|
2
2
|
import { addSpeechesInputSchema, addVideoClipsInputSchema, adjustBgmVolumeInputSchema, adjustSpeechVolumeInputSchema, adjustVideoClipDurationInputSchema, adjustVideoClipVolumeInputSchema, changeSpeechScriptInputSchema, changeSpeechVoiceInputSchema, deleteBgmInputSchema, deleteSpeechesInputSchema, deleteVideoClipsInputSchema, moveSpeechesInputSchema, moveVideoClipsByAnchorInputSchema, moveVideoClipsInputSchema, replaceVideoClipContentInputSchema, replaceVideoClipSequenceInputSchema, setBgmInputSchema, setCaptionStyleInputSchema, setCaptionVisibilityInputSchema, setVideoClipSpeedShiftInputSchema, t as schemas_exports } from "./schemas.js";
|
|
3
3
|
import { LoroDoc, VersionVector } from "loro-crdt";
|
|
4
4
|
import { ClientServerSynchronizer, DocManager } from "@mengine/sync";
|
|
@@ -231,8 +231,7 @@ const roleOrder$1 = {
|
|
|
231
231
|
* Image/Video/Audio/Voice Entity must carry its own external locator, every
|
|
232
232
|
* external asset id has exactly one claimant, and no media variant may be
|
|
233
233
|
* bound through a legacy `physical-asset` Relation. Dual-entity media graphs
|
|
234
|
-
* are rejected, not migrated. Caption
|
|
235
|
-
* `physical-asset` binding.
|
|
234
|
+
* are rejected, not migrated. Caption composes AudioScript text and has no physical text Asset.
|
|
236
235
|
*/
|
|
237
236
|
function assertCanonicalEditorResources(rows) {
|
|
238
237
|
if (rows.entities.filter((row) => row.entityKind === "timeline").length > 1) throw new EntityTimelineProjectionError("Editor requires exactly one Timeline");
|
|
@@ -263,8 +262,7 @@ function assertCanonicalEditorResources(rows) {
|
|
|
263
262
|
*
|
|
264
263
|
* 1. every Image/Video/Audio/Voice Entity carries its own Asset `external`
|
|
265
264
|
* identity;
|
|
266
|
-
* 2. no `physical-asset` Relation may bind a media variant
|
|
267
|
-
* text keeps its inline Asset and binding);
|
|
265
|
+
* 2. no `physical-asset` Relation may bind a media variant or Caption;
|
|
268
266
|
* 3. a self-carried media identity is immutable — it cannot be rewritten to
|
|
269
267
|
* another asset id.
|
|
270
268
|
*
|
|
@@ -608,6 +606,19 @@ function sameVoice(left, right) {
|
|
|
608
606
|
}
|
|
609
607
|
//#endregion
|
|
610
608
|
//#region src/entity-editor/entity-timeline-editor.ts
|
|
609
|
+
/**
|
|
610
|
+
* Resolve the AudioScript a PhoneticScript composes. The composition is the
|
|
611
|
+
* required text source: a variant without it has no content and fails here.
|
|
612
|
+
*/
|
|
613
|
+
function requireComposedAudioScript(rows, phoneticScriptEntityId) {
|
|
614
|
+
return assemblePhoneticScriptContent(rows, phoneticScriptEntityId).audioScript.entityId;
|
|
615
|
+
}
|
|
616
|
+
function captionSelections(selections) {
|
|
617
|
+
return structuredClone(selections);
|
|
618
|
+
}
|
|
619
|
+
function assertSelectionNamesScriptSegments(rows, audioScriptEntityId, selections) {
|
|
620
|
+
selectAudioScriptSegments(requireEntityKind(rows, audioScriptEntityId, "audio-script"), selections);
|
|
621
|
+
}
|
|
611
622
|
const roleOrder = {
|
|
612
623
|
caption: 0,
|
|
613
624
|
video_clip: 1,
|
|
@@ -1129,7 +1140,8 @@ var EntityTimelineEditor = class {
|
|
|
1129
1140
|
const imported = importMediaAsset(draft, input.media, this.idFactory);
|
|
1130
1141
|
replaceRows(draft, imported.rows);
|
|
1131
1142
|
const voice = requireEntityKind(draft, imported.contentEntityId, "voice");
|
|
1132
|
-
const
|
|
1143
|
+
const phonetic = this.requireComposedPhoneticScript(draft, input.phoneticScriptEntityId);
|
|
1144
|
+
this.ensurePhoneticRender(draft, voice.entityId, phonetic.entityId);
|
|
1133
1145
|
const speechTrack = this.ensureRoleTrack(draft, input.timelineEntityId, "speech");
|
|
1134
1146
|
const existing = draft.entities.find((row) => row.entityId === input.voiceoverClipEntityId);
|
|
1135
1147
|
let voiceoverClipEntityId;
|
|
@@ -1179,12 +1191,13 @@ var EntityTimelineEditor = class {
|
|
|
1179
1191
|
}
|
|
1180
1192
|
});
|
|
1181
1193
|
}
|
|
1182
|
-
this.reconcileVoiceoverCaptions(draft, voiceoverClipEntityId, voice.entityId,
|
|
1194
|
+
this.reconcileVoiceoverCaptions(draft, voiceoverClipEntityId, voice.entityId, phonetic.entityId, input.captions);
|
|
1183
1195
|
this.resolveOneVoiceoverOverlap(draft);
|
|
1184
1196
|
return {
|
|
1185
1197
|
voiceoverClipEntityId,
|
|
1186
1198
|
voiceEntityId: voice.entityId,
|
|
1187
|
-
|
|
1199
|
+
phoneticScriptEntityId: phonetic.entityId,
|
|
1200
|
+
audioScriptEntityId: requireComposedAudioScript(draft, phonetic.entityId),
|
|
1188
1201
|
captionClipEntityIds: input.captions.map((caption) => caption.captionClipEntityId)
|
|
1189
1202
|
};
|
|
1190
1203
|
});
|
|
@@ -1287,14 +1300,18 @@ var EntityTimelineEditor = class {
|
|
|
1287
1300
|
});
|
|
1288
1301
|
}
|
|
1289
1302
|
/**
|
|
1290
|
-
* Place
|
|
1291
|
-
*
|
|
1292
|
-
*
|
|
1293
|
-
* the returned Clip later changes the Clip/Marker,
|
|
1303
|
+
* Place a Caption as a composed variant of an existing AudioScript: the
|
|
1304
|
+
* entity stores only its selection, style, and inherent cue-bounded
|
|
1305
|
+
* Sequence — never text. The Clip and its display Marker describe this use;
|
|
1306
|
+
* moving or stretching the returned Clip later changes the Clip/Marker,
|
|
1307
|
+
* never the Caption entity or the AudioScript.
|
|
1294
1308
|
*/
|
|
1295
1309
|
insertCaptionClip(input) {
|
|
1296
1310
|
return this.transact((draft) => {
|
|
1297
1311
|
const durationMs = finitePositive(input.durationMs, "Caption durationMs");
|
|
1312
|
+
const selections = captionSelections(input.selections);
|
|
1313
|
+
const script = requireEntityKind(draft, input.audioScriptEntityId, "audio-script");
|
|
1314
|
+
assertSelectionNamesScriptSegments(draft, script.entityId, selections);
|
|
1298
1315
|
const track = this.ensureRoleTrack(draft, input.timelineEntityId, "caption");
|
|
1299
1316
|
const content = {
|
|
1300
1317
|
entityId: this.mintEntityId(draft),
|
|
@@ -1307,20 +1324,12 @@ var EntityTimelineEditor = class {
|
|
|
1307
1324
|
},
|
|
1308
1325
|
sampling: "native",
|
|
1309
1326
|
coordinateSpace: "milliseconds",
|
|
1310
|
-
|
|
1327
|
+
selections,
|
|
1311
1328
|
...input.style === void 0 ? {} : { style: cloneJsonObject(input.style, "Caption style") }
|
|
1312
1329
|
}
|
|
1313
1330
|
};
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
entityKind: "asset",
|
|
1317
|
-
payload: { inline: {
|
|
1318
|
-
mediaType: "text/plain",
|
|
1319
|
-
text: input.text
|
|
1320
|
-
} }
|
|
1321
|
-
};
|
|
1322
|
-
draft.entities.push(content, asset);
|
|
1323
|
-
draft.relations.push(this.createRelation(draft, "physical-asset", content.entityId, asset.entityId));
|
|
1331
|
+
draft.entities.push(content);
|
|
1332
|
+
draft.relations.push(this.createRelation(draft, "caption-composition", content.entityId, script.entityId, { segmentAlignment: [] }));
|
|
1324
1333
|
return this.insertPlacedClipIntoDraft(draft, {
|
|
1325
1334
|
trackEntityId: track.entityId,
|
|
1326
1335
|
contentEntityId: content.entityId,
|
|
@@ -1398,34 +1407,24 @@ var EntityTimelineEditor = class {
|
|
|
1398
1407
|
draft.relations.push(this.createRelation(draft, "timeline-track", timeline.entityId, track.entityId));
|
|
1399
1408
|
return track;
|
|
1400
1409
|
}
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1410
|
+
/** The existing pronunciation variant a Voice consumes; composition is required. */
|
|
1411
|
+
requireComposedPhoneticScript(draft, phoneticScriptEntityId) {
|
|
1412
|
+
const phonetic = requireEntityKind(draft, phoneticScriptEntityId, "phonetic-script");
|
|
1413
|
+
requireComposedAudioScript(draft, phonetic.entityId);
|
|
1414
|
+
return phonetic;
|
|
1415
|
+
}
|
|
1416
|
+
/** Preserve the factual synthesis input, regardless of persisted endpoint positions. */
|
|
1417
|
+
ensurePhoneticRender(draft, voiceEntityId, phoneticScriptEntityId) {
|
|
1418
|
+
const renders = draft.relations.filter((relation) => relation.relationKind === "phonetic-script-render" && (relation.endpoint0EntityId === voiceEntityId || relation.endpoint1EntityId === voiceEntityId));
|
|
1419
|
+
if (renders.length > 1) throw new Error(`Voice "${voiceEntityId}" has multiple PhoneticScript render relations`);
|
|
1404
1420
|
if (renders[0] !== void 0) {
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
...script,
|
|
1408
|
-
payload: { segments: [{
|
|
1409
|
-
segmentId: "segment-0",
|
|
1410
|
-
text
|
|
1411
|
-
}] }
|
|
1412
|
-
};
|
|
1413
|
-
replaceEntity(draft, script.entityId, replacement);
|
|
1414
|
-
return replacement;
|
|
1421
|
+
if (otherEndpoint(renders[0], voiceEntityId) === phoneticScriptEntityId) return;
|
|
1422
|
+
throw new Error(`Voice "${voiceEntityId}" already has a different PhoneticScript synthesis input`);
|
|
1415
1423
|
}
|
|
1416
|
-
|
|
1417
|
-
entityId: this.mintEntityId(draft),
|
|
1418
|
-
entityKind: "audio-script",
|
|
1419
|
-
payload: { segments: [{
|
|
1420
|
-
segmentId: "segment-0",
|
|
1421
|
-
text
|
|
1422
|
-
}] }
|
|
1423
|
-
};
|
|
1424
|
-
draft.entities.push(script);
|
|
1425
|
-
draft.relations.push(this.createRelation(draft, "audio-script-render", voiceEntityId, script.entityId));
|
|
1426
|
-
return script;
|
|
1424
|
+
draft.relations.push(this.createRelation(draft, "phonetic-script-render", voiceEntityId, phoneticScriptEntityId));
|
|
1427
1425
|
}
|
|
1428
|
-
reconcileVoiceoverCaptions(draft, voiceoverClipEntityId, voiceEntityId,
|
|
1426
|
+
reconcileVoiceoverCaptions(draft, voiceoverClipEntityId, voiceEntityId, phoneticScriptEntityId, captions) {
|
|
1427
|
+
const audioScriptEntityId = requireComposedAudioScript(draft, phoneticScriptEntityId);
|
|
1429
1428
|
const requested = new Set(captions.map((caption) => caption.captionClipEntityId));
|
|
1430
1429
|
if (requested.size !== captions.length) throw new Error("Caption Clip ids must be unique within a voiceover take");
|
|
1431
1430
|
const existing = directAnchorChildren(draft, voiceoverClipEntityId).filter((clipId) => clipRole(draft, clipId) === "caption");
|
|
@@ -1434,6 +1433,8 @@ var EntityTimelineEditor = class {
|
|
|
1434
1433
|
for (const caption of captions) {
|
|
1435
1434
|
const startMs = finiteNonNegative(caption.startMs, "Caption startMs");
|
|
1436
1435
|
const durationMs = finitePositive(caption.durationMs, "Caption durationMs");
|
|
1436
|
+
const selections = captionSelections(caption.selections);
|
|
1437
|
+
assertSelectionNamesScriptSegments(draft, audioScriptEntityId, selections);
|
|
1437
1438
|
if (draft.entities.find((entity) => entity.entityId === caption.captionClipEntityId) === void 0) {
|
|
1438
1439
|
const content = {
|
|
1439
1440
|
entityId: this.mintEntityId(draft),
|
|
@@ -1446,23 +1447,15 @@ var EntityTimelineEditor = class {
|
|
|
1446
1447
|
},
|
|
1447
1448
|
sampling: "native",
|
|
1448
1449
|
coordinateSpace: "milliseconds",
|
|
1449
|
-
|
|
1450
|
+
selections,
|
|
1450
1451
|
...caption.style === void 0 ? {} : { style: cloneJsonObject(caption.style, "Caption style") }
|
|
1451
1452
|
}
|
|
1452
1453
|
};
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
entityKind: "asset",
|
|
1456
|
-
payload: { inline: {
|
|
1457
|
-
mediaType: "text/plain",
|
|
1458
|
-
text: caption.text
|
|
1459
|
-
} }
|
|
1460
|
-
};
|
|
1461
|
-
draft.entities.push(content, asset);
|
|
1462
|
-
draft.relations.push(this.createRelation(draft, "physical-asset", content.entityId, asset.entityId), this.createRelation(draft, "caption-alignment", content.entityId, voiceEntityId, { alignment: {
|
|
1454
|
+
draft.entities.push(content);
|
|
1455
|
+
draft.relations.push(this.createRelation(draft, "caption-composition", content.entityId, audioScriptEntityId, { segmentAlignment: [] }), this.createRelation(draft, "caption-alignment", content.entityId, voiceEntityId, { alignment: {
|
|
1463
1456
|
start: startMs,
|
|
1464
1457
|
end: startMs + durationMs
|
|
1465
|
-
} })
|
|
1458
|
+
} }));
|
|
1466
1459
|
this.insertPlacedClipIntoDraft(draft, {
|
|
1467
1460
|
clipEntityId: caption.captionClipEntityId,
|
|
1468
1461
|
trackEntityId: captionTrack.entityId,
|
|
@@ -1494,27 +1487,10 @@ var EntityTimelineEditor = class {
|
|
|
1494
1487
|
...content,
|
|
1495
1488
|
payload: {
|
|
1496
1489
|
...content.payload,
|
|
1497
|
-
|
|
1498
|
-
kind: "bounded",
|
|
1499
|
-
start: 0,
|
|
1500
|
-
end: durationMs
|
|
1501
|
-
},
|
|
1502
|
-
text: caption.text,
|
|
1490
|
+
selections,
|
|
1503
1491
|
...Object.keys(style).length === 0 ? {} : { style }
|
|
1504
1492
|
}
|
|
1505
1493
|
});
|
|
1506
|
-
const asset = requireEntityKind(draft, otherEndpoint(requireOneRelation(draft, content.entityId, "physical-asset"), content.entityId), "asset");
|
|
1507
|
-
if (asset.payload.inline === void 0) throw new Error(`Caption "${caption.captionClipEntityId}" is not inline`);
|
|
1508
|
-
replaceEntity(draft, asset.entityId, {
|
|
1509
|
-
...asset,
|
|
1510
|
-
payload: {
|
|
1511
|
-
...asset.payload,
|
|
1512
|
-
inline: {
|
|
1513
|
-
mediaType: "text/plain",
|
|
1514
|
-
text: caption.text
|
|
1515
|
-
}
|
|
1516
|
-
}
|
|
1517
|
-
});
|
|
1518
1494
|
this.applyClipPlacement(draft, topology.clip.entityId, {
|
|
1519
1495
|
kind: "anchored",
|
|
1520
1496
|
hostClipEntityId: voiceoverClipEntityId,
|
|
@@ -1525,17 +1501,13 @@ var EntityTimelineEditor = class {
|
|
|
1525
1501
|
...placed.marker,
|
|
1526
1502
|
payload: {
|
|
1527
1503
|
...placed.marker.payload,
|
|
1528
|
-
sourceRange: {
|
|
1529
|
-
start: 0,
|
|
1530
|
-
end: durationMs
|
|
1531
|
-
},
|
|
1532
1504
|
duration: {
|
|
1533
1505
|
mode: "fixed",
|
|
1534
1506
|
value: durationMs
|
|
1535
1507
|
}
|
|
1536
1508
|
}
|
|
1537
1509
|
});
|
|
1538
|
-
this.replaceCaptionSemanticRelations(draft, content.entityId, voiceEntityId,
|
|
1510
|
+
this.replaceCaptionSemanticRelations(draft, content.entityId, voiceEntityId, audioScriptEntityId, startMs, durationMs);
|
|
1539
1511
|
}
|
|
1540
1512
|
}
|
|
1541
1513
|
ensureRoleTrackForClip(draft, clipEntityId, role) {
|
|
@@ -1545,22 +1517,24 @@ var EntityTimelineEditor = class {
|
|
|
1545
1517
|
return this.ensureRoleTrack(draft, timeline.entityId, role);
|
|
1546
1518
|
}
|
|
1547
1519
|
replaceCaptionSemanticRelations(draft, captionEntityId, voiceEntityId, scriptEntityId, startMs, durationMs) {
|
|
1548
|
-
const removed = new Set(incidentRelations(draft, captionEntityId).filter((relation) => relation.relationKind === "caption-alignment" || relation.relationKind === "caption-
|
|
1520
|
+
const removed = new Set(incidentRelations(draft, captionEntityId).filter((relation) => relation.relationKind === "caption-alignment" || relation.relationKind === "caption-composition").map((relation) => relation.relationId));
|
|
1549
1521
|
draft.relations = draft.relations.filter((relation) => !removed.has(relation.relationId));
|
|
1550
1522
|
draft.relations.push(this.createRelation(draft, "caption-alignment", captionEntityId, voiceEntityId, { alignment: {
|
|
1551
1523
|
start: startMs,
|
|
1552
1524
|
end: startMs + durationMs
|
|
1553
|
-
} }), this.createRelation(draft, "caption-
|
|
1525
|
+
} }), this.createRelation(draft, "caption-composition", captionEntityId, scriptEntityId, { segmentAlignment: [] }));
|
|
1554
1526
|
}
|
|
1527
|
+
/**
|
|
1528
|
+
* Remove one placed Caption use. The composed AudioScript outlives the
|
|
1529
|
+
* caption: it may anchor further captions and remains the text owner.
|
|
1530
|
+
*/
|
|
1555
1531
|
removeCaptionClipGraph(draft, clipEntityId) {
|
|
1556
1532
|
const topology = requireClipOnRole(draft, clipEntityId, "caption");
|
|
1557
1533
|
const caption = requireEntityKind(draft, otherEndpoint(topology.markerContentRelation, topology.marker.entityId), "caption");
|
|
1558
|
-
const asset = requireEntityKind(draft, otherEndpoint(requireOneRelation(draft, caption.entityId, "physical-asset"), caption.entityId), "asset");
|
|
1559
1534
|
const contentRelations = incidentRelations(draft, caption.entityId);
|
|
1560
1535
|
const allowed = new Set([
|
|
1561
|
-
"
|
|
1536
|
+
"caption-composition",
|
|
1562
1537
|
"caption-alignment",
|
|
1563
|
-
"caption-provenance",
|
|
1564
1538
|
"marker-content"
|
|
1565
1539
|
]);
|
|
1566
1540
|
const unsupported = contentRelations.filter((relation) => !allowed.has(relation.relationKind));
|
|
@@ -1568,10 +1542,8 @@ var EntityTimelineEditor = class {
|
|
|
1568
1542
|
this.removeClipGraph(draft, clipEntityId);
|
|
1569
1543
|
if (incidentRelations(draft, caption.entityId).some((relation) => relation.relationKind === "marker-content")) return;
|
|
1570
1544
|
const removed = new Set(incidentRelations(draft, caption.entityId).map((relation) => relation.relationId));
|
|
1571
|
-
const assetIncidents = incidentRelations(draft, asset.entityId);
|
|
1572
|
-
const deleteAsset = asset.payload.inline !== void 0 && assetIncidents.every((relation) => removed.has(relation.relationId));
|
|
1573
1545
|
draft.relations = draft.relations.filter((relation) => !removed.has(relation.relationId));
|
|
1574
|
-
draft.entities = draft.entities.filter((entity) => entity.entityId !== caption.entityId
|
|
1546
|
+
draft.entities = draft.entities.filter((entity) => entity.entityId !== caption.entityId);
|
|
1575
1547
|
}
|
|
1576
1548
|
replaceAnchorHost(draft, childClipEntityId, hostClipEntityId) {
|
|
1577
1549
|
const anchors = draft.relations.filter((relation) => relation.relationKind === "clip-anchor" && relation.endpoint0EntityId === childClipEntityId);
|
|
@@ -1992,7 +1964,6 @@ function migrateLegacyTimelineToEntities(legacy, assetFacts, initial = {
|
|
|
1992
1964
|
facts.set(fact.assetId, fact);
|
|
1993
1965
|
}
|
|
1994
1966
|
const contentByPartId = /* @__PURE__ */ new Map();
|
|
1995
|
-
const scriptBySpeechClipId = /* @__PURE__ */ new Map();
|
|
1996
1967
|
for (const track of legacy.tracks ?? []) for (const item of track.items ?? []) {
|
|
1997
1968
|
const part = requirePart(legacy, item.part_id);
|
|
1998
1969
|
if (part.video_clip !== void 0) {
|
|
@@ -2026,7 +1997,8 @@ function migrateLegacyTimelineToEntities(legacy, assetFacts, initial = {
|
|
|
2026
1997
|
entities = [...imported.rows.entities];
|
|
2027
1998
|
relations = [...imported.rows.relations];
|
|
2028
1999
|
contentByPartId.set(item.part_id, imported.contentEntityId);
|
|
2029
|
-
|
|
2000
|
+
const phonemeScript = speech.phoneme_script;
|
|
2001
|
+
ensureSpeechPhoneticChain(imported.contentEntityId, speech.audio_script, typeof phonemeScript === "string" ? phonemeScript : void 0, entities, relations, addEntity, link);
|
|
2030
2002
|
} else if (part.bgm !== void 0) {
|
|
2031
2003
|
const bgm = part.bgm;
|
|
2032
2004
|
const fact = facts.get(bgm.origin_media_id);
|
|
@@ -2101,6 +2073,22 @@ function migrateLegacyTimelineToEntities(legacy, assetFacts, initial = {
|
|
|
2101
2073
|
} else if (part.caption !== void 0) {
|
|
2102
2074
|
const caption = part.caption;
|
|
2103
2075
|
duration = caption.initial_duration_ms;
|
|
2076
|
+
const voice = contentByPartId.get(caption.speech_part_id);
|
|
2077
|
+
const render = relations.find((relation) => relation.relationKind === "phonetic-script-render" && relation.endpoint0EntityId === voice);
|
|
2078
|
+
const phonetic = entities.find((entity) => entity.entityId === render?.endpoint1EntityId);
|
|
2079
|
+
const script = phonetic === void 0 ? void 0 : composedAudioScript(phonetic, entities, relations);
|
|
2080
|
+
if (script === void 0) fail("Legacy Caption has no composed AudioScript");
|
|
2081
|
+
const sourceText = scriptText(script);
|
|
2082
|
+
const captionText = caption.text;
|
|
2083
|
+
const offset = sourceText.indexOf(captionText);
|
|
2084
|
+
if (!captionText.trim() || offset < 0 || sourceText.indexOf(captionText, offset + 1) >= 0) fail("Legacy Caption needs explicit unambiguous AudioScript selections before cutover");
|
|
2085
|
+
const selections = [{
|
|
2086
|
+
segmentId: "segment-0",
|
|
2087
|
+
...sourceText === captionText ? {} : { textRange: {
|
|
2088
|
+
start: Array.from(sourceText.slice(0, offset)).length,
|
|
2089
|
+
end: Array.from(sourceText.slice(0, offset + captionText.length)).length
|
|
2090
|
+
} }
|
|
2091
|
+
}];
|
|
2104
2092
|
content = addEntity("caption", {
|
|
2105
2093
|
extent: {
|
|
2106
2094
|
kind: "bounded",
|
|
@@ -2109,21 +2097,14 @@ function migrateLegacyTimelineToEntities(legacy, assetFacts, initial = {
|
|
|
2109
2097
|
},
|
|
2110
2098
|
sampling: "native",
|
|
2111
2099
|
coordinateSpace: "milliseconds",
|
|
2112
|
-
|
|
2100
|
+
selections,
|
|
2113
2101
|
...caption.style === void 0 ? {} : { style: toEntityCaptionStyle(caption.style) }
|
|
2114
2102
|
});
|
|
2115
|
-
|
|
2116
|
-
mediaType: "text/plain",
|
|
2117
|
-
text: caption.text
|
|
2118
|
-
} });
|
|
2119
|
-
link("physical-asset", content, asset);
|
|
2120
|
-
const voice = contentByPartId.get(caption.speech_part_id);
|
|
2121
|
-
const script = scriptBySpeechClipId.get(caption.speech_part_id);
|
|
2103
|
+
link("caption-composition", content, script.entityId, { segmentAlignment: [] });
|
|
2122
2104
|
link("caption-alignment", content, voice, { alignment: {
|
|
2123
2105
|
start: caption.start_ms,
|
|
2124
2106
|
end: caption.start_ms + duration
|
|
2125
2107
|
} });
|
|
2126
|
-
link("caption-provenance", content, script, { segmentAlignment: [] });
|
|
2127
2108
|
markerPayload = {
|
|
2128
2109
|
sourceRange: {
|
|
2129
2110
|
start: 0,
|
|
@@ -2339,7 +2320,7 @@ function assertPartSupported(id, part, role) {
|
|
|
2339
2320
|
if (speech.voice?.name !== void 0 && typeof speech.voice.name !== "string") fail("Migration requires a string voice name when present");
|
|
2340
2321
|
if (!Array.isArray(speech.caption_ids) || speech.caption_ids.some((captionId) => !trimmed(captionId))) fail("Migration requires explicit Speech caption identities");
|
|
2341
2322
|
if (new Set(speech.caption_ids).size !== speech.caption_ids.length) fail("Migration requires unique Speech caption identities");
|
|
2342
|
-
if (phonemeScript !== void 0 && phonemeScript !== null) fail("
|
|
2323
|
+
if (phonemeScript !== void 0 && phonemeScript !== null && typeof phonemeScript !== "string") fail("Migration requires a string phoneme_script when present");
|
|
2343
2324
|
assertKnownFields(speech.voice, ["id", "name"], "voice");
|
|
2344
2325
|
assertKnownFields(speech, [
|
|
2345
2326
|
"id",
|
|
@@ -2463,20 +2444,31 @@ function requirePart(document, partId) {
|
|
|
2463
2444
|
if (part === void 0) fail(`Placed Clip ${partId} has no part payload`);
|
|
2464
2445
|
return part;
|
|
2465
2446
|
}
|
|
2466
|
-
function
|
|
2467
|
-
const renders = relations.filter((relation) => relation.relationKind === "
|
|
2468
|
-
if (renders.length > 1) fail(`Voice ${voiceEntityId} has ambiguous
|
|
2447
|
+
function ensureSpeechPhoneticChain(voiceEntityId, audioScriptText, phonemeScript, entities, relations, addEntity, link) {
|
|
2448
|
+
const renders = relations.filter((relation) => relation.relationKind === "phonetic-script-render" && relation.endpoint0EntityId === voiceEntityId);
|
|
2449
|
+
if (renders.length > 1) fail(`Voice ${voiceEntityId} has ambiguous PhoneticScript provenance`);
|
|
2469
2450
|
if (renders.length === 1) {
|
|
2470
|
-
const
|
|
2471
|
-
if (
|
|
2472
|
-
|
|
2451
|
+
const phonetic = entities.find((entity) => entity.entityId === renders[0].endpoint1EntityId && entity.entityKind === "phonetic-script");
|
|
2452
|
+
if (phonetic === void 0) fail(`Voice ${voiceEntityId} has a dangling PhoneticScript render`);
|
|
2453
|
+
const script = composedAudioScript(phonetic, entities, relations);
|
|
2454
|
+
if (script === void 0 || scriptText(script) !== audioScriptText) fail(`Voice ${voiceEntityId} conflicts with the legacy Speech script`);
|
|
2455
|
+
return phonetic.entityId;
|
|
2473
2456
|
}
|
|
2474
2457
|
const script = addEntity("audio-script", { segments: [{
|
|
2475
2458
|
segmentId: "segment-0",
|
|
2476
|
-
text
|
|
2459
|
+
text: audioScriptText
|
|
2477
2460
|
}] });
|
|
2478
|
-
|
|
2479
|
-
|
|
2461
|
+
const phonetic = addEntity("phonetic-script", phonemeScript === void 0 ? {} : { phonemeScript });
|
|
2462
|
+
link("phonetic-script-composition", phonetic, script, { segmentAlignment: [] });
|
|
2463
|
+
link("phonetic-script-render", voiceEntityId, phonetic);
|
|
2464
|
+
return phonetic;
|
|
2465
|
+
}
|
|
2466
|
+
function composedAudioScript(phonetic, entities, relations) {
|
|
2467
|
+
const edges = relations.filter((relation) => relation.relationKind === "phonetic-script-composition" && (relation.endpoint0EntityId === phonetic.entityId || relation.endpoint1EntityId === phonetic.entityId));
|
|
2468
|
+
if (edges.length !== 1) return void 0;
|
|
2469
|
+
const edge = edges[0];
|
|
2470
|
+
const otherId = edge.endpoint0EntityId === phonetic.entityId ? edge.endpoint1EntityId : edge.endpoint0EntityId;
|
|
2471
|
+
return entities.find((entity) => entity.entityId === otherId);
|
|
2480
2472
|
}
|
|
2481
2473
|
function scriptText(script) {
|
|
2482
2474
|
const segments = script.payload.segments;
|
|
@@ -4704,4 +4696,4 @@ function serverCovers(serverVV, target) {
|
|
|
4704
4696
|
return covers(server, target);
|
|
4705
4697
|
}
|
|
4706
4698
|
//#endregion
|
|
4707
|
-
export { DEFAULT_UNIT_TIME_MS, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, EntityGraphHttpClient, EntityTimelineEditor, EntityTimelineProjectionError, IMPLEMENTED_SEMANTIC_OP_KINDS, LANE_KINDS_IN_STACK_ORDER, ManualSyncDoc, MedeoHttpDocStorage, MemoryDocStorage, MengineAckFailedError, MengineDocSession, MengineHttpClient, MengineHttpRequestError, MenginePushRejectedError, MirrorVideoDocumentAdapter, PlainMemoryAdapter, SchemaValidator, SemanticEditor, TIMELINE_SKELETON_DURATION_MS, VIDEO_DOCUMENT_SCHEMA_VERSION, ValidationError, VideoDocumentValidationError, applyEntityTimelineProjection, arrangeMainTrackSeamlessly, assertCanonicalEditorResources, assertEntityProjectionPreservesLegacy, assertMediaAssetWritePolicy, assertValidVideoDocument, base64ToBytes, buildInitialVideoDocument, buildSpeechHostMap, bytesToBase64, cascadeAfterVideoClipChanges, createEditSandbox, createMirrorVideoDocument, createMirrorVideoDocumentAdapter, createPlainMemoryAdapter, decodeDocVersionMark, derivePositionFromAbs, effectiveVideoClipDurationMs, encodeDocVersionMark, ensureEditorFoundation, ensureLaneTrack, fillMainTrackTimeGaps, findLaneTrack, fromVideoDocument, generatePartId, getAt, hostForAbsMs, importMediaAsset, isEmptyVideoClip, isImplementedSemanticOpKind, isMap, laneTrackId, mainTrackRanges, migrateLegacyTimelineToEntities, partDurationMs, partUnionSchema, projectEntityTimeline, readMainTrackItems, readMengineEventStream, readPart, readPartDurationMs, readVideoDocumentFromDraft, reassignSpeechesToVideoClipsByTime, recalculateTimelineDuration, relativePositionForAbs, replayJournal, resolveAllSpeechOverlaps, resolveEntityTimelineLayout, resolveSpeechOverlapByShiftingVideos, safeDurationMs, schemas_exports as schemas, snapshotToPlain, solveVideoDocument, speedOf, syncAggregatedClipsTimePosition, toVideoDocument, validateVideoDocument, videoDocumentMirrorSchema, videoDocumentSchema, writeVideoDocumentToDraft };
|
|
4699
|
+
export { DEFAULT_UNIT_TIME_MS, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, EntityGraphHttpClient, EntityTimelineEditor, EntityTimelineProjectionError, IMPLEMENTED_SEMANTIC_OP_KINDS, LANE_KINDS_IN_STACK_ORDER, ManualSyncDoc, MedeoHttpDocStorage, MemoryDocStorage, MengineAckFailedError, MengineDocSession, MengineHttpClient, MengineHttpRequestError, MenginePushRejectedError, MirrorVideoDocumentAdapter, PlainMemoryAdapter, SchemaValidator, ScriptCompositionError, SemanticEditor, TIMELINE_SKELETON_DURATION_MS, VIDEO_DOCUMENT_SCHEMA_VERSION, ValidationError, VideoDocumentValidationError, applyEntityTimelineProjection, arrangeMainTrackSeamlessly, assembleCaptionContent, assemblePhoneticScriptContent, assembleScriptText, assertCanonicalEditorResources, assertEntityProjectionPreservesLegacy, assertMediaAssetWritePolicy, assertValidVideoDocument, base64ToBytes, buildInitialVideoDocument, buildSpeechHostMap, bytesToBase64, cascadeAfterVideoClipChanges, createEditSandbox, createMirrorVideoDocument, createMirrorVideoDocumentAdapter, createPlainMemoryAdapter, decodeDocVersionMark, derivePositionFromAbs, effectiveVideoClipDurationMs, encodeDocVersionMark, ensureEditorFoundation, ensureLaneTrack, fillMainTrackTimeGaps, findComposedAudioScript, findLaneTrack, fromVideoDocument, generatePartId, getAt, hostForAbsMs, importMediaAsset, isEmptyVideoClip, isImplementedSemanticOpKind, isMap, laneTrackId, mainTrackRanges, migrateLegacyTimelineToEntities, partDurationMs, partUnionSchema, projectEntityTimeline, readMainTrackItems, readMengineEventStream, readPart, readPartDurationMs, readVideoDocumentFromDraft, reassignSpeechesToVideoClipsByTime, recalculateTimelineDuration, relativePositionForAbs, replayJournal, resolveAllSpeechOverlaps, resolveEntityTimelineLayout, resolveSpeechOverlapByShiftingVideos, safeDurationMs, schemas_exports as schemas, selectAudioScriptSegments, snapshotToPlain, solveVideoDocument, speedOf, syncAggregatedClipsTimePosition, toVideoDocument, validateVideoDocument, videoDocumentMirrorSchema, videoDocumentSchema, writeVideoDocumentToDraft };
|
package/dist/testing.d.ts
CHANGED
package/dist/testing.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { et as VIDEO_DOCUMENT_SCHEMA_VERSION, ot as base64ToBytes, s as createMirrorVideoDocumentAdapter, st as bytesToBase64 } from "./document-Bf200CmD.js";
|
|
2
2
|
import { t as classifyUpdate } from "./loro-relay-doc-ssdYpuef.js";
|
|
3
3
|
import { LoroDoc, VersionVector, encodeFrontiers } from "loro-crdt";
|
|
4
4
|
//#region src/testing/in-memory-mengine-server.ts
|