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 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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dasha",
3
- "version": "4.0.0-alpha.14",
3
+ "version": "4.0.0-alpha.15",
4
4
  "description": "Streaming manifest parser",
5
5
  "files": [
6
6
  "dist"