@mebius-io/web 0.5.3 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +29 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.global.js +29 -10
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +29 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -149,6 +149,13 @@ interface CaptionSegment {
|
|
|
149
149
|
durationMs: number;
|
|
150
150
|
/** Original transcript, in the source language. */
|
|
151
151
|
text: string;
|
|
152
|
+
/**
|
|
153
|
+
* Language `text` is actually in, as the recogniser identified it. With an
|
|
154
|
+
* "auto" source this varies per sentence, so a client showing `text` as a
|
|
155
|
+
* subtitle must check this rather than assume it matches what the viewer
|
|
156
|
+
* asked for.
|
|
157
|
+
*/
|
|
158
|
+
srcLang?: string;
|
|
152
159
|
/** The requested {@link CaptionsOptions.lang} translation, if produced yet. */
|
|
153
160
|
translation?: string;
|
|
154
161
|
/** Always `true`. Render a machine-generated indicator — never as a direct quote. */
|
|
@@ -417,6 +424,12 @@ declare class MebiusCaptions extends TypedEmitter<CaptionsEventMap> {
|
|
|
417
424
|
private es;
|
|
418
425
|
private timer;
|
|
419
426
|
private readonly pending;
|
|
427
|
+
/**
|
|
428
|
+
* segmentId -> the rev already handed to listeners. Not a Set: with interim
|
|
429
|
+
* revisions on, a segment stays pending while it is being corrected, and a
|
|
430
|
+
* plain "have I shown this id" check re-emits the same unchanged text on
|
|
431
|
+
* every 100ms tick. Comparing revs emits exactly once per actual revision.
|
|
432
|
+
*/
|
|
420
433
|
private readonly shown;
|
|
421
434
|
/** @internal */
|
|
422
435
|
constructor(signaling: SignalingClient, player: MebiusPlayer, opts: CaptionsOptions);
|
package/dist/index.d.ts
CHANGED
|
@@ -149,6 +149,13 @@ interface CaptionSegment {
|
|
|
149
149
|
durationMs: number;
|
|
150
150
|
/** Original transcript, in the source language. */
|
|
151
151
|
text: string;
|
|
152
|
+
/**
|
|
153
|
+
* Language `text` is actually in, as the recogniser identified it. With an
|
|
154
|
+
* "auto" source this varies per sentence, so a client showing `text` as a
|
|
155
|
+
* subtitle must check this rather than assume it matches what the viewer
|
|
156
|
+
* asked for.
|
|
157
|
+
*/
|
|
158
|
+
srcLang?: string;
|
|
152
159
|
/** The requested {@link CaptionsOptions.lang} translation, if produced yet. */
|
|
153
160
|
translation?: string;
|
|
154
161
|
/** Always `true`. Render a machine-generated indicator — never as a direct quote. */
|
|
@@ -417,6 +424,12 @@ declare class MebiusCaptions extends TypedEmitter<CaptionsEventMap> {
|
|
|
417
424
|
private es;
|
|
418
425
|
private timer;
|
|
419
426
|
private readonly pending;
|
|
427
|
+
/**
|
|
428
|
+
* segmentId -> the rev already handed to listeners. Not a Set: with interim
|
|
429
|
+
* revisions on, a segment stays pending while it is being corrected, and a
|
|
430
|
+
* plain "have I shown this id" check re-emits the same unchanged text on
|
|
431
|
+
* every 100ms tick. Comparing revs emits exactly once per actual revision.
|
|
432
|
+
*/
|
|
420
433
|
private readonly shown;
|
|
421
434
|
/** @internal */
|
|
422
435
|
constructor(signaling: SignalingClient, player: MebiusPlayer, opts: CaptionsOptions);
|
package/dist/index.global.js
CHANGED
|
@@ -43047,7 +43047,7 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
|
|
|
43047
43047
|
var MAX_DRIFT_S = 2;
|
|
43048
43048
|
var EDGE_MARGIN_S = 0.4;
|
|
43049
43049
|
var AUDIO_RETRY_MS = 2500;
|
|
43050
|
-
var
|
|
43050
|
+
var UPSTREAM_LATENCY_MS = 800;
|
|
43051
43051
|
function stalledWithData(video, ms) {
|
|
43052
43052
|
if (video.currentTime > 0) return Promise.resolve(false);
|
|
43053
43053
|
return new Promise((resolve) => {
|
|
@@ -43177,13 +43177,24 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
|
|
|
43177
43177
|
return { bitrateKbps, framesPerSecond, latencyMs: void 0 };
|
|
43178
43178
|
}
|
|
43179
43179
|
/**
|
|
43180
|
-
* Estimate
|
|
43181
|
-
*
|
|
43182
|
-
*
|
|
43183
|
-
*
|
|
43180
|
+
* Estimate — FLV carries no wall clock, so this is measured where possible
|
|
43181
|
+
* and assumed where not (see {@link UPSTREAM_LATENCY_MS}).
|
|
43182
|
+
*
|
|
43183
|
+
* The measurable half is the decoded media queued ahead of the playhead:
|
|
43184
|
+
* whatever is buffered but not yet shown is, by definition, how far behind
|
|
43185
|
+
* the newest received frame this viewer is watching. A flat guess for the
|
|
43186
|
+
* whole delay was previously used, and being too generous costs real time —
|
|
43187
|
+
* every millisecond of over-estimate is a caption withheld for no reason,
|
|
43188
|
+
* on top of the STT latency the viewer already pays.
|
|
43184
43189
|
*/
|
|
43185
43190
|
playheadEpochMs() {
|
|
43186
|
-
|
|
43191
|
+
let bufferedAheadMs = 0;
|
|
43192
|
+
const ranges = this.video?.buffered;
|
|
43193
|
+
if (ranges && ranges.length > 0 && this.video) {
|
|
43194
|
+
const ahead = ranges.end(ranges.length - 1) - this.video.currentTime;
|
|
43195
|
+
if (Number.isFinite(ahead) && ahead > 0) bufferedAheadMs = ahead * 1e3;
|
|
43196
|
+
}
|
|
43197
|
+
return Date.now() - UPSTREAM_LATENCY_MS - bufferedAheadMs;
|
|
43187
43198
|
}
|
|
43188
43199
|
};
|
|
43189
43200
|
|
|
@@ -43416,7 +43427,7 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
|
|
|
43416
43427
|
// src/captions.ts
|
|
43417
43428
|
var TICK_MS = 100;
|
|
43418
43429
|
var STALE_MS = 5e3;
|
|
43419
|
-
var MAX_QUEUE_MS =
|
|
43430
|
+
var MAX_QUEUE_MS = 1500;
|
|
43420
43431
|
var MebiusCaptions = class extends TypedEmitter {
|
|
43421
43432
|
/** @internal */
|
|
43422
43433
|
constructor(signaling, player, opts) {
|
|
@@ -43427,7 +43438,13 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
|
|
|
43427
43438
|
this.es = null;
|
|
43428
43439
|
this.timer = null;
|
|
43429
43440
|
this.pending = /* @__PURE__ */ new Map();
|
|
43430
|
-
|
|
43441
|
+
/**
|
|
43442
|
+
* segmentId -> the rev already handed to listeners. Not a Set: with interim
|
|
43443
|
+
* revisions on, a segment stays pending while it is being corrected, and a
|
|
43444
|
+
* plain "have I shown this id" check re-emits the same unchanged text on
|
|
43445
|
+
* every 100ms tick. Comparing revs emits exactly once per actual revision.
|
|
43446
|
+
*/
|
|
43447
|
+
this.shown = /* @__PURE__ */ new Map();
|
|
43431
43448
|
}
|
|
43432
43449
|
/** Open the SSE connection and begin emitting segments for `streamId`. */
|
|
43433
43450
|
start(streamId) {
|
|
@@ -43476,8 +43493,9 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
|
|
|
43476
43493
|
this.emit("cleared", { segmentId: id });
|
|
43477
43494
|
continue;
|
|
43478
43495
|
}
|
|
43479
|
-
|
|
43480
|
-
this.shown.
|
|
43496
|
+
const rev = frame.rev ?? 0;
|
|
43497
|
+
if (this.shown.get(id) === rev) continue;
|
|
43498
|
+
this.shown.set(id, rev);
|
|
43481
43499
|
this.emit("segment", toSegment(id, frame, this.opts.lang));
|
|
43482
43500
|
}
|
|
43483
43501
|
}
|
|
@@ -43490,6 +43508,7 @@ Schedule: ${scheduleItems.map((seg) => segmentToString(seg))} pos: ${this.timeli
|
|
|
43490
43508
|
epochMs: frame.epochMs ?? 0,
|
|
43491
43509
|
durationMs: frame.durationMs ?? 0,
|
|
43492
43510
|
text: frame.text ?? "",
|
|
43511
|
+
srcLang: frame.srcLang,
|
|
43493
43512
|
translation: frame.translations?.[lang],
|
|
43494
43513
|
machineGenerated: true
|
|
43495
43514
|
};
|