dasha 4.0.0-alpha.14 → 4.0.0-alpha.15
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.d.mts +3 -1
- package/dist/index.mjs +150 -91
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -449,6 +449,7 @@ declare const DASH_FORMATS: InputFormat[];
|
|
|
449
449
|
//#region src/mediabunny-input.d.ts
|
|
450
450
|
declare module 'mediabunny' {
|
|
451
451
|
interface Input<S extends Source = Source> {
|
|
452
|
+
_getTrackBackings(): Promise<unknown[]>;
|
|
452
453
|
_wrapBackingAsTrack(backing: unknown): InputTrack$2;
|
|
453
454
|
}
|
|
454
455
|
}
|
|
@@ -460,6 +461,7 @@ type MediabunnyTrackWithSegments = InputTrack$2 & SegmentAccessMethods;
|
|
|
460
461
|
type MediabunnyVideoTrackWithSegments = InputVideoTrack$1 & SegmentAccessMethods;
|
|
461
462
|
type MediabunnyAudioTrackWithSegments = InputAudioTrack$1 & SegmentAccessMethods;
|
|
462
463
|
type TrackBacking = Parameters<Input$1<Source>['_wrapBackingAsTrack']>[0];
|
|
464
|
+
declare const preserveSubtitleBackingsOnInput: (input: Input$1) => Input$1<Source>;
|
|
463
465
|
declare class SegmentedMediabunnyInput<S extends Source = Source> extends Input$1<S> {
|
|
464
466
|
#private;
|
|
465
467
|
_wrapBackingAsTrack(backing: TrackBacking): MediabunnyTrackWithSegments;
|
|
@@ -486,4 +488,4 @@ declare const isInput: (value: unknown) => value is Input;
|
|
|
486
488
|
declare const getSegmentedInput: (track: InputTrack$1) => InputSegmentedInput;
|
|
487
489
|
declare const getSegments: (track: InputTrack$1) => Promise<InputSegment[]>;
|
|
488
490
|
//#endregion
|
|
489
|
-
export { DASH, DASH_FORMATS, type DashSegment, type DashSegmentedInput, FilePathSource, HLS_FORMATS, type HlsSegment, type HlsSegmentedInput, Input, InputAudioTrack, InputSegment, InputSegmentedInput, InputTrack$1 as InputTrack, type InputTrackQuery, type InputTrackWithBacking, InputVideoTrack, UrlSource, asc, desc, getSegmentedInput, getSegments, isInput, prefer };
|
|
491
|
+
export { DASH, DASH_FORMATS, type DashSegment, type DashSegmentedInput, FilePathSource, HLS_FORMATS, type HlsSegment, type HlsSegmentedInput, Input, InputAudioTrack, InputSegment, InputSegmentedInput, InputTrack$1 as InputTrack, type InputTrackQuery, type InputTrackWithBacking, InputVideoTrack, UrlSource, asc, desc, getSegmentedInput, getSegments, isInput, prefer, preserveSubtitleBackingsOnInput };
|
package/dist/index.mjs
CHANGED
|
@@ -414,6 +414,153 @@ const parseDashRange = (range) => {
|
|
|
414
414
|
return [startRange, end - startRange + 1];
|
|
415
415
|
};
|
|
416
416
|
//#endregion
|
|
417
|
+
//#region src/mediabunny-input.ts
|
|
418
|
+
const requireSync = (value, getterName, asyncName) => {
|
|
419
|
+
if (value instanceof Promise) throw new Error(`'${getterName}' is not available synchronously for this track. Use '${asyncName}()' instead.`);
|
|
420
|
+
return value;
|
|
421
|
+
};
|
|
422
|
+
const queryTracks = async (tracks, query) => {
|
|
423
|
+
let matched = tracks;
|
|
424
|
+
if (query?.filter) {
|
|
425
|
+
const filterMatches = tracks.map((track) => query.filter(track));
|
|
426
|
+
const resolvedFilterMatches = await Promise.all(filterMatches);
|
|
427
|
+
matched = tracks.filter((_, index) => resolvedFilterMatches[index]);
|
|
428
|
+
}
|
|
429
|
+
if (!query?.sortBy) return matched;
|
|
430
|
+
const resolvedSortValues = await Promise.all(matched.map((track) => query.sortBy(track)));
|
|
431
|
+
return matched.map((track, index) => ({
|
|
432
|
+
track,
|
|
433
|
+
sortValue: resolvedSortValues[index]
|
|
434
|
+
})).sort((left, right) => {
|
|
435
|
+
const leftValues = Array.isArray(left.sortValue) ? left.sortValue : [left.sortValue];
|
|
436
|
+
const rightValues = Array.isArray(right.sortValue) ? right.sortValue : [right.sortValue];
|
|
437
|
+
const maxLength = Math.max(leftValues.length, rightValues.length);
|
|
438
|
+
for (let index = 0; index < maxLength; index++) {
|
|
439
|
+
const leftValue = leftValues[index] ?? 0;
|
|
440
|
+
const rightValue = rightValues[index] ?? 0;
|
|
441
|
+
if (leftValue === rightValue) continue;
|
|
442
|
+
return leftValue - rightValue;
|
|
443
|
+
}
|
|
444
|
+
return 0;
|
|
445
|
+
}).map(({ track }) => track);
|
|
446
|
+
};
|
|
447
|
+
const BACKING_TYPE_SUBTITLE = "subtitle";
|
|
448
|
+
const BACKING_TYPE_AUDIO = "audio";
|
|
449
|
+
const BACKING_TYPE_VIDEO = "video";
|
|
450
|
+
const BASE_INPUT_PATCHED = Symbol.for("dasha.base-mediabunny-input-patched");
|
|
451
|
+
const PRESERVE_SUBTITLE_BACKINGS = Symbol.for("dasha.preserve-subtitle-backings");
|
|
452
|
+
const getBackingType = (backing) => backing.getType?.();
|
|
453
|
+
const queryWrappedTracks = (input, backings, query) => {
|
|
454
|
+
return queryTracks(backings.map((backing) => input._wrapBackingAsTrack(backing)), query);
|
|
455
|
+
};
|
|
456
|
+
const getTrackBackingsByType = async (input, type) => {
|
|
457
|
+
const backings = await input._getTrackBackings();
|
|
458
|
+
if (!type) return backings;
|
|
459
|
+
return backings.filter((backing) => getBackingType(backing) === type);
|
|
460
|
+
};
|
|
461
|
+
const patchBaseMediabunnyInput = () => {
|
|
462
|
+
const prototype = Input$1.prototype;
|
|
463
|
+
if (prototype[BASE_INPUT_PATCHED]) return;
|
|
464
|
+
prototype.getTracks = function(query) {
|
|
465
|
+
return getTrackBackingsByType(this).then((backings) => queryWrappedTracks(this, this[PRESERVE_SUBTITLE_BACKINGS] ? backings : backings.filter((backing) => getBackingType(backing) !== BACKING_TYPE_SUBTITLE), query));
|
|
466
|
+
};
|
|
467
|
+
prototype.getAudioTracks = function(query) {
|
|
468
|
+
return getTrackBackingsByType(this, BACKING_TYPE_AUDIO).then((backings) => queryWrappedTracks(this, backings, query));
|
|
469
|
+
};
|
|
470
|
+
prototype[BASE_INPUT_PATCHED] = true;
|
|
471
|
+
};
|
|
472
|
+
const getSegmentedInputForTrack = (track) => {
|
|
473
|
+
const backing = track._backing;
|
|
474
|
+
if ("getSegmentedInput" in backing && typeof backing.getSegmentedInput === "function") return backing.getSegmentedInput();
|
|
475
|
+
const internalTrack = backing.internalTrack;
|
|
476
|
+
return internalTrack.demuxer.getSegmentedInputForPath(internalTrack.fullPath);
|
|
477
|
+
};
|
|
478
|
+
const addSegmentAccess = (track) => new Proxy(track, { get(target, prop) {
|
|
479
|
+
if (prop === "getSegmentedInput") return () => getSegmentedInputForTrack(target);
|
|
480
|
+
if (prop === "getSegments") return async () => {
|
|
481
|
+
const segmentedInput = getSegmentedInputForTrack(target);
|
|
482
|
+
await segmentedInput.runUpdateSegments();
|
|
483
|
+
return segmentedInput.segments;
|
|
484
|
+
};
|
|
485
|
+
const value = Reflect.get(target, prop, target);
|
|
486
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
487
|
+
} });
|
|
488
|
+
var MediabunnyInputSubtitleTrack = class extends InputTrack {
|
|
489
|
+
#backing;
|
|
490
|
+
constructor(input, backing) {
|
|
491
|
+
super();
|
|
492
|
+
Object.assign(this, {
|
|
493
|
+
input,
|
|
494
|
+
_backing: backing
|
|
495
|
+
});
|
|
496
|
+
this.#backing = backing;
|
|
497
|
+
}
|
|
498
|
+
get type() {
|
|
499
|
+
return "subtitle";
|
|
500
|
+
}
|
|
501
|
+
async getCodec() {
|
|
502
|
+
return this.#backing.getCodec();
|
|
503
|
+
}
|
|
504
|
+
get codec() {
|
|
505
|
+
return requireSync(this.#backing.getCodec(), "codec", "getCodec");
|
|
506
|
+
}
|
|
507
|
+
async getCodecParameterString() {
|
|
508
|
+
return await this.#backing.getMetadataCodecParameterString?.() ?? null;
|
|
509
|
+
}
|
|
510
|
+
async canDecode() {
|
|
511
|
+
return true;
|
|
512
|
+
}
|
|
513
|
+
async determinePacketType(_packet) {
|
|
514
|
+
return null;
|
|
515
|
+
}
|
|
516
|
+
async hasOnlyKeyPackets() {
|
|
517
|
+
return true;
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
patchBaseMediabunnyInput();
|
|
521
|
+
const preserveSubtitleBackingsOnInput = (input) => {
|
|
522
|
+
Object.assign(input, { [PRESERVE_SUBTITLE_BACKINGS]: true });
|
|
523
|
+
return input;
|
|
524
|
+
};
|
|
525
|
+
var SegmentedMediabunnyInput = class extends Input$1 {
|
|
526
|
+
#trackCache = /* @__PURE__ */ new WeakMap();
|
|
527
|
+
#subtitleTrackCache = /* @__PURE__ */ new WeakMap();
|
|
528
|
+
async #queryTracks(query, type) {
|
|
529
|
+
const backings = await getTrackBackingsByType(this, type);
|
|
530
|
+
return queryWrappedTracks(this, backings, query);
|
|
531
|
+
}
|
|
532
|
+
_wrapBackingAsTrack(backing) {
|
|
533
|
+
const track = backing.getType?.() === "subtitle" ? this.#wrapSubtitleBacking(backing) : super._wrapBackingAsTrack(backing);
|
|
534
|
+
const existing = this.#trackCache.get(track);
|
|
535
|
+
if (existing) return existing;
|
|
536
|
+
const wrapped = addSegmentAccess(track);
|
|
537
|
+
this.#trackCache.set(track, wrapped);
|
|
538
|
+
return wrapped;
|
|
539
|
+
}
|
|
540
|
+
#wrapSubtitleBacking(backing) {
|
|
541
|
+
const existing = this.#subtitleTrackCache.get(backing);
|
|
542
|
+
if (existing) return existing;
|
|
543
|
+
const track = new MediabunnyInputSubtitleTrack(this, backing);
|
|
544
|
+
this.#subtitleTrackCache.set(backing, track);
|
|
545
|
+
return track;
|
|
546
|
+
}
|
|
547
|
+
async getTracks(query) {
|
|
548
|
+
return await this.#queryTracks(query);
|
|
549
|
+
}
|
|
550
|
+
async getVideoTracks(query) {
|
|
551
|
+
return await this.#queryTracks(query, BACKING_TYPE_VIDEO);
|
|
552
|
+
}
|
|
553
|
+
async getAudioTracks(query) {
|
|
554
|
+
return await this.#queryTracks(query, BACKING_TYPE_AUDIO);
|
|
555
|
+
}
|
|
556
|
+
async getPrimaryVideoTrack(query) {
|
|
557
|
+
return await super.getPrimaryVideoTrack(query);
|
|
558
|
+
}
|
|
559
|
+
async getPrimaryAudioTrack(query) {
|
|
560
|
+
return await super.getPrimaryAudioTrack(query);
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
//#endregion
|
|
417
564
|
//#region src/dash/dash-segmented-input.ts
|
|
418
565
|
const roundToDivisor = (value, multiple) => Math.round(value * multiple) / multiple;
|
|
419
566
|
const binarySearchLessOrEqual = (array, value, getValue) => {
|
|
@@ -576,7 +723,7 @@ var DashSegmentedInput = class {
|
|
|
576
723
|
let initInput = null;
|
|
577
724
|
if (segment.initSegment && segment.initSegment !== segment) initInput = this.getInputForSegment(segment.initSegment);
|
|
578
725
|
const formatOptions = { ...input._formatOptions };
|
|
579
|
-
const segmentInput = new Input$1({
|
|
726
|
+
const segmentInput = preserveSubtitleBackingsOnInput(new Input$1({
|
|
580
727
|
source: new CustomPathedSource(segment.location.path, async (request) => {
|
|
581
728
|
if (!request.isRoot) throw new Error("Nested requests are not supported for DASH segments.");
|
|
582
729
|
const proxiedRequest = {
|
|
@@ -594,7 +741,7 @@ var DashSegmentedInput = class {
|
|
|
594
741
|
formats: input._formats.filter((format) => format.mimeType !== DASH_MIME_TYPE),
|
|
595
742
|
initInput: initInput ?? void 0,
|
|
596
743
|
formatOptions
|
|
597
|
-
});
|
|
744
|
+
}));
|
|
598
745
|
this.inputCache.push({
|
|
599
746
|
age: this.nextInputCacheAge++,
|
|
600
747
|
input: segmentInput,
|
|
@@ -1591,94 +1738,6 @@ const DASH_FORMATS = [
|
|
|
1591
1738
|
ADTS
|
|
1592
1739
|
];
|
|
1593
1740
|
//#endregion
|
|
1594
|
-
//#region src/mediabunny-input.ts
|
|
1595
|
-
const requireSync = (value, getterName, asyncName) => {
|
|
1596
|
-
if (value instanceof Promise) throw new Error(`'${getterName}' is not available synchronously for this track. Use '${asyncName}()' instead.`);
|
|
1597
|
-
return value;
|
|
1598
|
-
};
|
|
1599
|
-
const getSegmentedInputForTrack = (track) => {
|
|
1600
|
-
const backing = track._backing;
|
|
1601
|
-
if ("getSegmentedInput" in backing && typeof backing.getSegmentedInput === "function") return backing.getSegmentedInput();
|
|
1602
|
-
const internalTrack = backing.internalTrack;
|
|
1603
|
-
return internalTrack.demuxer.getSegmentedInputForPath(internalTrack.fullPath);
|
|
1604
|
-
};
|
|
1605
|
-
const addSegmentAccess = (track) => new Proxy(track, { get(target, prop) {
|
|
1606
|
-
if (prop === "getSegmentedInput") return () => getSegmentedInputForTrack(target);
|
|
1607
|
-
if (prop === "getSegments") return async () => {
|
|
1608
|
-
const segmentedInput = getSegmentedInputForTrack(target);
|
|
1609
|
-
await segmentedInput.runUpdateSegments();
|
|
1610
|
-
return segmentedInput.segments;
|
|
1611
|
-
};
|
|
1612
|
-
const value = Reflect.get(target, prop, target);
|
|
1613
|
-
return typeof value === "function" ? value.bind(target) : value;
|
|
1614
|
-
} });
|
|
1615
|
-
var MediabunnyInputSubtitleTrack = class extends InputTrack {
|
|
1616
|
-
#backing;
|
|
1617
|
-
constructor(input, backing) {
|
|
1618
|
-
super();
|
|
1619
|
-
Object.assign(this, {
|
|
1620
|
-
input,
|
|
1621
|
-
_backing: backing
|
|
1622
|
-
});
|
|
1623
|
-
this.#backing = backing;
|
|
1624
|
-
}
|
|
1625
|
-
get type() {
|
|
1626
|
-
return "subtitle";
|
|
1627
|
-
}
|
|
1628
|
-
async getCodec() {
|
|
1629
|
-
return this.#backing.getCodec();
|
|
1630
|
-
}
|
|
1631
|
-
get codec() {
|
|
1632
|
-
return requireSync(this.#backing.getCodec(), "codec", "getCodec");
|
|
1633
|
-
}
|
|
1634
|
-
async getCodecParameterString() {
|
|
1635
|
-
return await this.#backing.getMetadataCodecParameterString?.() ?? null;
|
|
1636
|
-
}
|
|
1637
|
-
async canDecode() {
|
|
1638
|
-
return true;
|
|
1639
|
-
}
|
|
1640
|
-
async determinePacketType(_packet) {
|
|
1641
|
-
return null;
|
|
1642
|
-
}
|
|
1643
|
-
async hasOnlyKeyPackets() {
|
|
1644
|
-
return true;
|
|
1645
|
-
}
|
|
1646
|
-
};
|
|
1647
|
-
var SegmentedMediabunnyInput = class extends Input$1 {
|
|
1648
|
-
#trackCache = /* @__PURE__ */ new WeakMap();
|
|
1649
|
-
#subtitleTrackCache = /* @__PURE__ */ new WeakMap();
|
|
1650
|
-
_wrapBackingAsTrack(backing) {
|
|
1651
|
-
const track = backing.getType?.() === "subtitle" ? this.#wrapSubtitleBacking(backing) : super._wrapBackingAsTrack(backing);
|
|
1652
|
-
const existing = this.#trackCache.get(track);
|
|
1653
|
-
if (existing) return existing;
|
|
1654
|
-
const wrapped = addSegmentAccess(track);
|
|
1655
|
-
this.#trackCache.set(track, wrapped);
|
|
1656
|
-
return wrapped;
|
|
1657
|
-
}
|
|
1658
|
-
#wrapSubtitleBacking(backing) {
|
|
1659
|
-
const existing = this.#subtitleTrackCache.get(backing);
|
|
1660
|
-
if (existing) return existing;
|
|
1661
|
-
const track = new MediabunnyInputSubtitleTrack(this, backing);
|
|
1662
|
-
this.#subtitleTrackCache.set(backing, track);
|
|
1663
|
-
return track;
|
|
1664
|
-
}
|
|
1665
|
-
async getTracks(query) {
|
|
1666
|
-
return await super.getTracks(query);
|
|
1667
|
-
}
|
|
1668
|
-
async getVideoTracks(query) {
|
|
1669
|
-
return await super.getVideoTracks(query);
|
|
1670
|
-
}
|
|
1671
|
-
async getAudioTracks(query) {
|
|
1672
|
-
return await super.getAudioTracks(query);
|
|
1673
|
-
}
|
|
1674
|
-
async getPrimaryVideoTrack(query) {
|
|
1675
|
-
return await super.getPrimaryVideoTrack(query);
|
|
1676
|
-
}
|
|
1677
|
-
async getPrimaryAudioTrack(query) {
|
|
1678
|
-
return await super.getPrimaryAudioTrack(query);
|
|
1679
|
-
}
|
|
1680
|
-
};
|
|
1681
|
-
//#endregion
|
|
1682
1741
|
//#region src/index.ts
|
|
1683
1742
|
var Input = class extends SegmentedMediabunnyInput {
|
|
1684
1743
|
constructor(options) {
|
|
@@ -1689,4 +1748,4 @@ const isInput = (value) => value instanceof Input;
|
|
|
1689
1748
|
const getSegmentedInput = (track) => track.getSegmentedInput();
|
|
1690
1749
|
const getSegments = async (track) => track.getSegments();
|
|
1691
1750
|
//#endregion
|
|
1692
|
-
export { DASH, DASH_FORMATS, FilePathSource, HLS_FORMATS, Input, UrlSource, asc, desc, getSegmentedInput, getSegments, isInput, prefer };
|
|
1751
|
+
export { DASH, DASH_FORMATS, FilePathSource, HLS_FORMATS, Input, UrlSource, asc, desc, getSegmentedInput, getSegments, isInput, prefer, preserveSubtitleBackingsOnInput };
|