dasha 4.2.1 → 4.3.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/README.md CHANGED
@@ -131,6 +131,30 @@ async function getEnglishSubtitles() {
131
131
  }
132
132
  ```
133
133
 
134
+ ### Overriding track metadata
135
+
136
+ Some services expose track metadata outside the manifest. You can override the parsed language code on any dasha track, and the updated value will be visible through the regular query/filter APIs.
137
+
138
+ ```ts
139
+ import { DASH_FORMATS, Input, UrlSource } from 'dasha';
140
+
141
+ async function getFrenchAudioTrack() {
142
+ const input = new Input({
143
+ source: new UrlSource('https://example.com/manifest.mpd'),
144
+ formats: DASH_FORMATS,
145
+ });
146
+
147
+ const audioTracks = await input.getAudioTracks();
148
+ const apiLanguageCode = 'fr';
149
+
150
+ audioTracks[0]?.setLanguageCode(apiLanguageCode);
151
+
152
+ return await input.getAudioTracks({
153
+ filter: async (track) => (await track.getLanguageCode()) === apiLanguageCode,
154
+ });
155
+ }
156
+ ```
157
+
134
158
  ### Mediabunny with DASH support
135
159
 
136
160
  > Only reading is supported
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _$mediabunny from "mediabunny";
2
2
  import { AudioCodec as AudioCodec$1, DurationMetadataRequestOptions, EncodedPacket, FilePathSource, HLS, HLS_FORMATS, Input as Input$1, InputAudioTrack as InputAudioTrack$1, InputFormat, InputOptions, InputTrack as InputTrack$2, InputTrackQuery, InputTrackQuery as InputTrackQuery$1, InputVideoTrack as InputVideoTrack$1, MP3, MP4, MaybePromise, MediaCodec as MediaCodec$1, MetadataTags, PacketRetrievalOptions, PathedSource, Source, SourceRef, SubtitleCodec as SubtitleCodec$1, TrackDisposition, UrlSource, VideoCodec as VideoCodec$1, asc, desc, prefer } from "mediabunny";
3
- import { Element } from "@xmldom/xmldom";
3
+ import * as _$_xmldom_xmldom0 from "@xmldom/xmldom";
4
4
 
5
5
  //#region src/mediabunny.d.ts
6
6
  type Segment$1 = {
@@ -104,6 +104,7 @@ declare const ROLE_TYPE: {
104
104
  type RoleType = (typeof ROLE_TYPE)[keyof typeof ROLE_TYPE];
105
105
  //#endregion
106
106
  //#region src/dash/dash-misc.d.ts
107
+ type Element = _$_xmldom_xmldom0.Element;
107
108
  type DashTrackType = 'video' | 'audio' | 'subtitle';
108
109
  type DashEncryptionData = {
109
110
  method: string;
@@ -557,16 +558,19 @@ type SegmentAccessMethods = {
557
558
  getSegmentedInput(): HlsSegmentedInput | DashSegmentedInput;
558
559
  getSegments(): Promise<(HlsSegment | DashSegment)[]>;
559
560
  };
561
+ type TrackMetadataOverrideMethods = {
562
+ setLanguageCode(value: string): void;
563
+ };
560
564
  type VideoDynamicRangeMethods = {
561
565
  getDynamicRange(): Promise<VideoDynamicRange>;
562
566
  };
563
567
  type MediabunnySubtitleTrackLike = InputTrack$2 & {
564
568
  type: 'subtitle';
565
569
  };
566
- type InputTrack$1 = InputTrack$2 & SegmentAccessMethods;
567
- type InputVideoTrack = InputVideoTrack$1 & SegmentAccessMethods & VideoDynamicRangeMethods;
568
- type InputAudioTrack = InputAudioTrack$1 & SegmentAccessMethods;
569
- type InputSubtitleTrack = MediabunnySubtitleTrackLike & SegmentAccessMethods;
570
+ type InputTrack$1 = InputTrack$2 & SegmentAccessMethods & TrackMetadataOverrideMethods;
571
+ type InputVideoTrack = InputVideoTrack$1 & SegmentAccessMethods & VideoDynamicRangeMethods & TrackMetadataOverrideMethods;
572
+ type InputAudioTrack = InputAudioTrack$1 & SegmentAccessMethods & TrackMetadataOverrideMethods;
573
+ type InputSubtitleTrack = MediabunnySubtitleTrackLike & SegmentAccessMethods & TrackMetadataOverrideMethods;
570
574
  type InputSubtitleSource = PathedSource | SourceRef<PathedSource>;
571
575
  type InputSubtitleTrackMetadata = {
572
576
  codec?: SubtitleCodec | null;
package/dist/index.mjs CHANGED
@@ -1240,6 +1240,8 @@ const CUSTOM_SUBTITLE_TRACK_ID_OFFSET = 1e9;
1240
1240
  const CUSTOM_PAIRING_BIT_START = 1024n;
1241
1241
  const EXTRA_PAIRING_MASK = Symbol.for("dasha.extra-pairing-mask");
1242
1242
  const ORIGINAL_GET_PAIRING_MASK = Symbol.for("dasha.original-get-pairing-mask");
1243
+ const TRACK_METADATA_OVERRIDES = Symbol.for("dasha.track-metadata-overrides");
1244
+ const ORIGINAL_GET_LANGUAGE_CODE = Symbol.for("dasha.original-get-language-code");
1243
1245
  const HLS_VARIANT_INF_LINE = "#EXT-X-STREAM-INF:";
1244
1246
  const HLS_DEMUXER_PATCHED = Symbol.for("dasha.hls-demuxer-patched");
1245
1247
  const HLS_DEMUXER_METADATA_PATCH = Symbol.for("dasha.hls-demuxer-metadata-patch");
@@ -1406,13 +1408,26 @@ const patchBaseMediabunnyInput = () => {
1406
1408
  prototype[BASE_INPUT_PATCHED] = true;
1407
1409
  };
1408
1410
  const getSegmentedInputForTrack = (track) => {
1409
- const backing = track._backing;
1411
+ const backing = getTrackBacking(track);
1410
1412
  if ("getSegmentedInput" in backing && typeof backing.getSegmentedInput === "function") return backing.getSegmentedInput();
1411
1413
  const internalTrack = backing.internalTrack;
1412
1414
  return internalTrack.demuxer.getSegmentedInputForPath(internalTrack.fullPath);
1413
1415
  };
1416
+ const getTrackBacking = (track) => track._backing;
1417
+ const getTrackMetadataOverrides = (backing) => backing[TRACK_METADATA_OVERRIDES] ??= {};
1418
+ const ensureLanguageCodeOverridePatch = (backing) => {
1419
+ const patchedBacking = backing;
1420
+ if (patchedBacking[ORIGINAL_GET_LANGUAGE_CODE]) return patchedBacking;
1421
+ patchedBacking[ORIGINAL_GET_LANGUAGE_CODE] = backing.getLanguageCode?.bind(backing) ?? (() => "und");
1422
+ Object.assign(backing, { getLanguageCode: () => getTrackMetadataOverrides(patchedBacking).languageCode ?? patchedBacking[ORIGINAL_GET_LANGUAGE_CODE]?.() ?? "und" });
1423
+ return patchedBacking;
1424
+ };
1425
+ const setTrackLanguageCode = (track, value) => {
1426
+ getTrackMetadataOverrides(ensureLanguageCodeOverridePatch(getTrackBacking(track))).languageCode = value;
1427
+ };
1414
1428
  const addSegmentAccess = (track) => new Proxy(track, { get(target, prop) {
1415
1429
  if (prop === "getDynamicRange" && target instanceof InputVideoTrack) return () => getDynamicRangeForTrack(target);
1430
+ if (prop === "setLanguageCode") return (value) => setTrackLanguageCode(target, value);
1416
1431
  if (prop === "getSegmentedInput") return () => getSegmentedInputForTrack(target);
1417
1432
  if (prop === "getSegments") return async () => {
1418
1433
  const segmentedInput = getSegmentedInputForTrack(target);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dasha",
3
- "version": "4.2.1",
3
+ "version": "4.3.0",
4
4
  "description": "Streaming manifest parser",
5
5
  "files": [
6
6
  "dist"
@@ -52,15 +52,15 @@
52
52
  "temporal-polyfill": "^0.3.2"
53
53
  },
54
54
  "peerDependencies": {
55
- "mediabunny": "^1.44.2"
55
+ "mediabunny": "^1.45.2"
56
56
  },
57
57
  "devDependencies": {
58
- "@types/node": "^25.6.2",
59
- "oxfmt": "^0.48.0",
60
- "oxlint": "^1.63.0",
58
+ "@types/node": "^25.8.0",
59
+ "oxfmt": "^0.50.0",
60
+ "oxlint": "^1.65.0",
61
61
  "tsdown": "^0.22.0",
62
62
  "typescript": "^6.0.3",
63
- "vitest": "^4.1.5"
63
+ "vitest": "^4.1.6"
64
64
  },
65
65
  "scripts": {
66
66
  "test": "vitest",