@postfetch/core 0.12.2 → 0.12.3

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/hls.d.ts CHANGED
@@ -12,5 +12,7 @@ export type HlsMaster = {
12
12
  audio: Record<string, string>;
13
13
  };
14
14
  export declare function isMasterPlaylist(text: string): boolean;
15
- export declare function parseMaster(text: string, baseUrl: string): HlsMaster;
15
+ export declare function parseMaster(text: string, baseUrl: string, options?: {
16
+ preferOriginalAudio?: boolean;
17
+ }): HlsMaster;
16
18
  export declare function assembleHls(net: Net, playlistUrl: string, headers: HeadersInit): Promise<Uint8Array>;
package/dist/index.js CHANGED
@@ -1218,11 +1218,11 @@ function mediaFragment(fragment, sequence) {
1218
1218
  function isMasterPlaylist(text) {
1219
1219
  return text.includes("#EXT-X-STREAM-INF");
1220
1220
  }
1221
- function parseMaster(text, baseUrl) {
1221
+ function parseMaster(text, baseUrl, options = {}) {
1222
1222
  const lines = text.split(`
1223
1223
  `).map((line) => line.trim());
1224
1224
  const audio = {};
1225
- const defaultAudio = new Set;
1225
+ const audioPreference = {};
1226
1226
  const variants = [];
1227
1227
  for (let index = 0;index < lines.length; index += 1) {
1228
1228
  const line = lines[index];
@@ -1230,10 +1230,12 @@ function parseMaster(text, baseUrl) {
1230
1230
  const group = line.match(/GROUP-ID="([^"]+)"/)?.[1];
1231
1231
  const uri = line.match(/URI="([^"]+)"/)?.[1];
1232
1232
  const isDefault = /(?:^|,)DEFAULT=YES(?:,|$)/.test(line);
1233
- if (group && uri && (!audio[group] || isDefault && !defaultAudio.has(group))) {
1233
+ const name = line.match(/(?:^|,)NAME="([^"]+)"/)?.[1] ?? "";
1234
+ const isOriginal = options.preferOriginalAudio && /\boriginal\b/i.test(name);
1235
+ const preference = isOriginal ? 2 : isDefault ? 1 : 0;
1236
+ if (group && uri && (!audio[group] || preference > audioPreference[group])) {
1234
1237
  audio[group] = new URL(uri, baseUrl).href;
1235
- if (isDefault)
1236
- defaultAudio.add(group);
1238
+ audioPreference[group] = preference;
1237
1239
  }
1238
1240
  } else if (line.startsWith("#EXT-X-STREAM-INF:")) {
1239
1241
  const target = lines[index + 1];
@@ -2711,7 +2713,7 @@ async function resolveVisionOs(input, id, visitorData) {
2711
2713
  if (!response.ok) {
2712
2714
  throw new Error(`YouTube HLS manifest failed: ${response.status}`);
2713
2715
  }
2714
- const master = parseMaster(await response.text(), manifestUrl);
2716
+ const master = parseMaster(await response.text(), manifestUrl, { preferOriginalAudio: true });
2715
2717
  const variants = master.variants.filter((variant2) => /(?:^|,)(?:vp09|av01)\./i.test(variant2.codecs ?? "") && /(?:^|,)mp4a\.40\.2(?:,|$)/i.test(variant2.codecs ?? "") && variant2.audioGroup && master.audio[variant2.audioGroup]).sort((left, right) => Math.abs(left.width - input.preferredWidth) - Math.abs(right.width - input.preferredWidth) || right.bandwidth - left.bandwidth);
2716
2718
  const variant = variants[0];
2717
2719
  if (!variant?.audioGroup) {
@@ -2780,10 +2782,21 @@ function bestAudio(formats) {
2780
2782
  if (!current) {
2781
2783
  return format;
2782
2784
  }
2785
+ const preference = audioPreference(format) - audioPreference(current);
2786
+ if (preference !== 0) {
2787
+ return preference > 0 ? format : current;
2788
+ }
2783
2789
  return (number(format.bitrate) ?? 0) > (number(current.bitrate) ?? 0) ? format : current;
2784
2790
  }, null);
2785
2791
  return best ? string(best.url) : null;
2786
2792
  }
2793
+ function audioPreference(format) {
2794
+ const track = object(format.audioTrack) ? format.audioTrack : null;
2795
+ if (track && /\boriginal\b/i.test(string(track.displayName) ?? "")) {
2796
+ return 2;
2797
+ }
2798
+ return track?.audioIsDefault === true ? 1 : 0;
2799
+ }
2787
2800
  function playerBody(id, session) {
2788
2801
  return {
2789
2802
  contentCheckOk: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postfetch/core",
3
- "version": "0.12.2",
3
+ "version": "0.12.3",
4
4
  "description": "Zero-dependency typed core that turns Facebook, Instagram, LinkedIn, Pinterest, Reddit, SoundCloud, TikTok, X and YouTube post URLs into media files.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/hls.ts CHANGED
@@ -16,10 +16,10 @@ export function isMasterPlaylist(text: string): boolean {
16
16
  return text.includes("#EXT-X-STREAM-INF");
17
17
  }
18
18
 
19
- export function parseMaster(text: string, baseUrl: string): HlsMaster {
19
+ export function parseMaster(text: string, baseUrl: string, options: { preferOriginalAudio?: boolean } = {}): HlsMaster {
20
20
  const lines = text.split("\n").map((line) => line.trim());
21
21
  const audio: Record<string, string> = {};
22
- const defaultAudio = new Set<string>();
22
+ const audioPreference: Record<string, number> = {};
23
23
  const variants: HlsVariant[] = [];
24
24
  for (let index = 0; index < lines.length; index += 1) {
25
25
  const line = lines[index];
@@ -27,9 +27,12 @@ export function parseMaster(text: string, baseUrl: string): HlsMaster {
27
27
  const group = line.match(/GROUP-ID="([^"]+)"/)?.[1];
28
28
  const uri = line.match(/URI="([^"]+)"/)?.[1];
29
29
  const isDefault = /(?:^|,)DEFAULT=YES(?:,|$)/.test(line);
30
- if (group && uri && (!audio[group] || (isDefault && !defaultAudio.has(group)))) {
30
+ const name = line.match(/(?:^|,)NAME="([^"]+)"/)?.[1] ?? "";
31
+ const isOriginal = options.preferOriginalAudio && /\boriginal\b/i.test(name);
32
+ const preference = isOriginal ? 2 : isDefault ? 1 : 0;
33
+ if (group && uri && (!audio[group] || preference > audioPreference[group])) {
31
34
  audio[group] = new URL(uri, baseUrl).href;
32
- if (isDefault) defaultAudio.add(group);
35
+ audioPreference[group] = preference;
33
36
  }
34
37
  } else if (line.startsWith("#EXT-X-STREAM-INF:")) {
35
38
  const target = lines[index + 1];
package/src/youtube.ts CHANGED
@@ -139,7 +139,7 @@ async function resolveVisionOs(input: ResolveContext, id: string, visitorData?:
139
139
  if (!response.ok) {
140
140
  throw new Error(`YouTube HLS manifest failed: ${response.status}`);
141
141
  }
142
- const master = parseMaster(await response.text(), manifestUrl);
142
+ const master = parseMaster(await response.text(), manifestUrl, { preferOriginalAudio: true });
143
143
  // YouTube's AVC HLS variants use MPEG-TS. VP9/AV1 variants use fMP4 and
144
144
  // work with the bundled box-level merger. Require the paired AAC-LC track.
145
145
  const variants = master.variants.filter((variant) =>
@@ -230,11 +230,25 @@ function bestAudio(formats: Json[]): string | null {
230
230
  if (!current) {
231
231
  return format;
232
232
  }
233
+ // YouTube's default can be a dub, and bitrate varies between languages.
234
+ // Select the original track before comparing audio quality.
235
+ const preference = audioPreference(format) - audioPreference(current);
236
+ if (preference !== 0) {
237
+ return preference > 0 ? format : current;
238
+ }
233
239
  return (number(format.bitrate) ?? 0) > (number(current.bitrate) ?? 0) ? format : current;
234
240
  }, null);
235
241
  return best ? string(best.url) : null;
236
242
  }
237
243
 
244
+ function audioPreference(format: Json): number {
245
+ const track = object(format.audioTrack) ? format.audioTrack : null;
246
+ if (track && /\boriginal\b/i.test(string(track.displayName) ?? "")) {
247
+ return 2;
248
+ }
249
+ return track?.audioIsDefault === true ? 1 : 0;
250
+ }
251
+
238
252
  function playerBody(id: string, session: YoutubeSession): Json {
239
253
  return {
240
254
  contentCheckOk: true,