dasha 4.4.2 → 4.4.4

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
@@ -183,6 +183,7 @@ type Segment = {
183
183
  };
184
184
  type DashSegmentLocation = {
185
185
  path: string;
186
+ sourcePath: string;
186
187
  offset: number;
187
188
  length: number | null;
188
189
  };
@@ -360,7 +361,10 @@ declare class DashDemuxer {
360
361
  }): void;
361
362
  findMatchingTrack(nextTracks: DashParsedTrack[], currentTrack: DashParsedTrack): DashParsedTrack | undefined;
362
363
  refreshTracks(tracks: DashParsedTrack[]): Promise<void>;
363
- fetchManifest(url: string): Promise<Response>;
364
+ fetchManifestText(url: string): Promise<{
365
+ text: string;
366
+ url: string;
367
+ }>;
364
368
  resetManifestUrls(): void;
365
369
  }
366
370
  declare abstract class DashTrackBackingBase {
package/dist/index.mjs CHANGED
@@ -316,6 +316,21 @@ const getDashTrackMatchKey = (track) => JSON.stringify({
316
316
  const getSourcePath = (source) => {
317
317
  if ("rootPath" in source && typeof source.rootPath === "string") return source.rootPath;
318
318
  };
319
+ const resolvePathedSourceRequest = async (source, request) => {
320
+ const pathedSource = source;
321
+ if (typeof pathedSource._resolveRequest !== "function") throw new Error("DASH input currently requires a pathed source such as UrlSource.");
322
+ return await pathedSource._resolveRequest(request);
323
+ };
324
+ const resolvePathedSourcePath = async (source, request) => {
325
+ const ref = await resolvePathedSourceRequest(source, request);
326
+ try {
327
+ const path = getSourcePath(ref.source);
328
+ if (!path) throw new Error("DASH segment requests must resolve to a pathed source.");
329
+ return path;
330
+ } finally {
331
+ ref.free();
332
+ }
333
+ };
319
334
  const normalizeHeaders$1 = (headers) => {
320
335
  if (!headers) return {};
321
336
  if (headers instanceof Headers) return Object.fromEntries(headers.entries());
@@ -330,30 +345,48 @@ const getSourceHeaders$1 = (source) => {
330
345
  ...optionHeaders
331
346
  };
332
347
  };
348
+ const getSourceFetch = (source) => {
349
+ return ("_options" in source && source._options && typeof source._options === "object" ? source._options : void 0)?.fetchFn ?? fetch;
350
+ };
351
+ const fetchDashManifest = async (source, url) => {
352
+ const response = await getSourceFetch(source)(url, { headers: getSourceHeaders$1(source) });
353
+ if (!response.ok) throw new Error(`Failed to fetch DASH manifest: ${response.status} ${response.statusText} (${response.url})`);
354
+ return response;
355
+ };
333
356
  const parseOriginalUrlFromManifest = (text) => text.match(/<!--\s*URL:\s*([^\n]+?)\s*-->/)?.[1]?.trim();
334
357
  const loadDashManifest = async (source) => {
335
358
  const manifestPath = getSourcePath(source);
336
359
  if (!manifestPath) throw new Error("DASH input currently requires a pathed source such as UrlSource.");
337
- if (manifestPath.startsWith("http://") || manifestPath.startsWith("https://")) {
338
- const response = await fetch(manifestPath, { headers: getSourceHeaders$1(source) });
339
- if (!response.ok) throw new Error(`Failed to fetch DASH manifest: ${response.status} ${response.statusText} (${response.url})`);
340
- return {
341
- text: await response.text(),
342
- url: response.url
343
- };
344
- }
345
- if (manifestPath.startsWith("file:")) {
346
- const text = await readFile(new URL(manifestPath), "utf8");
360
+ const manifestRef = await resolvePathedSourceRequest(source, {
361
+ path: manifestPath,
362
+ isRoot: true
363
+ });
364
+ const manifestSource = manifestRef.source;
365
+ const resolvedManifestPath = getSourcePath(manifestSource);
366
+ try {
367
+ if (!resolvedManifestPath) throw new Error("DASH manifest requests must resolve to a pathed source.");
368
+ if (resolvedManifestPath.startsWith("http://") || resolvedManifestPath.startsWith("https://")) {
369
+ const response = await fetchDashManifest(manifestSource, resolvedManifestPath);
370
+ return {
371
+ text: await response.text(),
372
+ url: response.url || resolvedManifestPath
373
+ };
374
+ }
375
+ if (resolvedManifestPath.startsWith("file:")) {
376
+ const text = await readFile(new URL(resolvedManifestPath), "utf8");
377
+ return {
378
+ text,
379
+ url: parseOriginalUrlFromManifest(text) ?? resolvedManifestPath
380
+ };
381
+ }
382
+ const text = await readFile(resolvedManifestPath, "utf8");
347
383
  return {
348
384
  text,
349
- url: parseOriginalUrlFromManifest(text) ?? manifestPath
385
+ url: parseOriginalUrlFromManifest(text) ?? resolvedManifestPath
350
386
  };
387
+ } finally {
388
+ manifestRef.free();
351
389
  }
352
- const text = await readFile(manifestPath, "utf8");
353
- return {
354
- text,
355
- url: parseOriginalUrlFromManifest(text) ?? manifestPath
356
- };
357
390
  };
358
391
  const isLikelyDashPath = (source) => {
359
392
  const path = getSourcePath(source);
@@ -1828,23 +1861,27 @@ const getLeastRecentlyUsedIndex = (entries) => {
1828
1861
  }
1829
1862
  return bestIndex;
1830
1863
  };
1831
- const getSegmentLocation = (segment) => ({
1832
- path: segment.url,
1864
+ const getSegmentLocation = async (input, segment) => ({
1865
+ path: await resolvePathedSourcePath(input.source, {
1866
+ path: segment.url,
1867
+ isRoot: false
1868
+ }),
1869
+ sourcePath: segment.url,
1833
1870
  offset: segment.startRange ?? 0,
1834
1871
  length: segment.expectLength ?? null
1835
1872
  });
1836
- const createInitSegment = (segment) => ({
1873
+ const createInitSegment = async (input, segment) => ({
1837
1874
  timestamp: 0,
1838
1875
  duration: 0,
1839
1876
  relativeToUnixEpoch: false,
1840
1877
  firstSegment: null,
1841
1878
  sequenceNumber: segment.sequenceNumber,
1842
- location: getSegmentLocation(segment),
1879
+ location: await getSegmentLocation(input, segment),
1843
1880
  encryption: segment.encryption,
1844
1881
  initSegment: null,
1845
1882
  lastProgramDateTimeSeconds: null
1846
1883
  });
1847
- const trackToDashSegments = (internalTrack) => {
1884
+ const trackToDashSegments = async (input, internalTrack) => {
1848
1885
  const mediaSegments = internalTrack.track.mediaSegments;
1849
1886
  if (mediaSegments.length === 0) return [];
1850
1887
  let nextTimestamp = 0;
@@ -1857,7 +1894,7 @@ const trackToDashSegments = (internalTrack) => {
1857
1894
  relativeToUnixEpoch: false,
1858
1895
  firstSegment: null,
1859
1896
  sequenceNumber: mediaSegment.sequenceNumber,
1860
- location: getSegmentLocation(mediaSegment),
1897
+ location: await getSegmentLocation(input, mediaSegment),
1861
1898
  encryption: mediaSegment.encryption,
1862
1899
  initSegment: null,
1863
1900
  lastProgramDateTimeSeconds: null
@@ -1866,7 +1903,7 @@ const trackToDashSegments = (internalTrack) => {
1866
1903
  nextTimestamp = timestamp + mediaSegment.duration;
1867
1904
  }
1868
1905
  const firstSegment = segments[0] ?? null;
1869
- const initSegment = internalTrack.track.initSegment ? createInitSegment(internalTrack.track.initSegment) : null;
1906
+ const initSegment = internalTrack.track.initSegment ? await createInitSegment(input, internalTrack.track.initSegment) : null;
1870
1907
  for (const segment of segments) {
1871
1908
  segment.firstSegment = firstSegment;
1872
1909
  segment.initSegment = initSegment;
@@ -1902,8 +1939,9 @@ var DashSegmentedInput = class {
1902
1939
  })();
1903
1940
  }
1904
1941
  async updateSegments() {
1942
+ const input = this.demuxer.input;
1905
1943
  await this.demuxer.refreshTrackSegments(this.internalTrack);
1906
- this.segments = trackToDashSegments(this.internalTrack);
1944
+ this.segments = await trackToDashSegments(input, this.internalTrack);
1907
1945
  }
1908
1946
  getRemainingWaitTimeMs() {
1909
1947
  if (!this.internalTrack.track.isLive) return 0;
@@ -1967,7 +2005,7 @@ var DashSegmentedInput = class {
1967
2005
  if (segment.initSegment && segment.initSegment !== segment) initInput = this.getInputForSegment(segment.initSegment);
1968
2006
  const formatOptions = { ...input._formatOptions };
1969
2007
  const segmentInput = preserveSubtitleBackingsOnInput(new Input$1({
1970
- source: new CustomPathedSource(segment.location.path, async (request) => {
2008
+ source: new CustomPathedSource(segment.location.sourcePath, async (request) => {
1971
2009
  if (!request.isRoot) throw new Error("Nested requests are not supported for DASH segments.");
1972
2010
  const proxiedRequest = {
1973
2011
  ...request,
@@ -2761,11 +2799,10 @@ var DashDemuxer = class {
2761
2799
  }
2762
2800
  async refreshTracks(tracks) {
2763
2801
  if (!tracks.length) return;
2764
- const response = await this.fetchManifest(this.manifestUrl).catch(() => this.fetchManifest(this.originalUrl));
2765
- const rawText = await response.text();
2802
+ const response = await this.fetchManifestText(this.manifestUrl).catch(() => this.fetchManifestText(this.originalUrl));
2766
2803
  this.manifestUrl = response.url;
2767
2804
  this.resetManifestUrls();
2768
- const nextTracks = this.extractTracks(rawText);
2805
+ const nextTracks = this.extractTracks(response.text);
2769
2806
  for (const track of tracks) {
2770
2807
  const nextTrack = this.findMatchingTrack(nextTracks, track);
2771
2808
  if (!nextTrack) continue;
@@ -2778,10 +2815,23 @@ var DashDemuxer = class {
2778
2815
  track.subtitleGroupId = nextTrack.subtitleGroupId;
2779
2816
  }
2780
2817
  }
2781
- async fetchManifest(url) {
2782
- const response = await fetch(url, { headers: this.headers });
2783
- if (!response.ok) throw new Error(`Failed to fetch DASH manifest: ${response.status} ${response.statusText} (${response.url})`);
2784
- return response;
2818
+ async fetchManifestText(url) {
2819
+ const manifestRef = await resolvePathedSourceRequest(this.input.source, {
2820
+ path: url,
2821
+ isRoot: true
2822
+ });
2823
+ const manifestSource = manifestRef.source;
2824
+ try {
2825
+ const resolvedUrl = getSourcePath(manifestSource);
2826
+ if (!resolvedUrl) throw new Error("DASH manifest requests must resolve to a pathed source.");
2827
+ const response = await fetchDashManifest(manifestSource, resolvedUrl);
2828
+ return {
2829
+ text: await response.text(),
2830
+ url: response.url || resolvedUrl
2831
+ };
2832
+ } finally {
2833
+ manifestRef.free();
2834
+ }
2785
2835
  }
2786
2836
  resetManifestUrls() {
2787
2837
  this.mpdUrl = this.manifestUrl;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dasha",
3
- "version": "4.4.2",
3
+ "version": "4.4.4",
4
4
  "description": "Streaming manifest parser",
5
5
  "files": [
6
6
  "dist"