Chrunos commited on
Commit
f1a9af0
·
verified ·
1 Parent(s): 35cd637

Update api/src/processing/services/youtube.js

Browse files
api/src/processing/services/youtube.js CHANGED
@@ -48,7 +48,7 @@ const transformSessionData = (cookie) => {
48
  return;
49
 
50
  const values = { ...cookie.values() };
51
- const REQUIRED_VALUES = [ 'access_token', 'refresh_token' ];
52
 
53
  if (REQUIRED_VALUES.some(x => typeof values[x] !== 'string')) {
54
  return;
@@ -66,10 +66,18 @@ const transformSessionData = (cookie) => {
66
 
67
  const cloneInnertube = async (customFetch) => {
68
  const shouldRefreshPlayer = lastRefreshedAt + PLAYER_REFRESH_PERIOD < new Date();
 
 
 
 
 
69
  if (!innertube || shouldRefreshPlayer) {
70
  innertube = await Innertube.create({
71
  fetch: customFetch,
72
- retrieve_player: false,
 
 
 
73
  });
74
  lastRefreshedAt = +new Date();
75
  }
@@ -80,30 +88,30 @@ const cloneInnertube = async (customFetch) => {
80
  innertube.session.api_version,
81
  innertube.session.account_index,
82
  innertube.session.player,
83
- undefined,
84
  customFetch ?? innertube.session.http.fetch,
85
  innertube.session.cache
86
  );
87
 
88
- const cookie = getCookie('youtube_oauth');
89
- const oauthData = transformSessionData(cookie);
90
 
91
  if (!session.logged_in && oauthData) {
92
  await session.oauth.init(oauthData);
93
  session.logged_in = true;
94
  }
95
 
96
- if (session.logged_in) {
97
  if (session.oauth.shouldRefreshToken()) {
98
  await session.oauth.refreshAccessToken();
99
  }
100
 
101
- const cookieValues = cookie.values();
102
  const oldExpiry = new Date(cookieValues.expiry_date);
103
  const newExpiry = new Date(session.oauth.oauth2_tokens.expiry_date);
104
 
105
  if (oldExpiry.getTime() !== newExpiry.getTime()) {
106
- updateCookieValues(cookie, {
107
  ...session.oauth.client_id,
108
  ...session.oauth.oauth2_tokens,
109
  expiry_date: newExpiry.toISOString()
@@ -115,7 +123,7 @@ const cloneInnertube = async (customFetch) => {
115
  return yt;
116
  }
117
 
118
- export default async function(o) {
119
  let yt;
120
  try {
121
  yt = await cloneInnertube(
@@ -132,6 +140,8 @@ export default async function(o) {
132
  } else throw e;
133
  }
134
 
 
 
135
  let useHLS = o.youtubeHLS;
136
 
137
  // HLS playlists don't contain the av1 video format, at least with the iOS client
@@ -139,9 +149,20 @@ export default async function(o) {
139
  useHLS = false;
140
  }
141
 
 
 
 
 
 
 
 
 
 
 
 
142
  let info;
143
  try {
144
- info = await yt.getBasicInfo(o.id, useHLS ? 'IOS' : 'ANDROID');
145
  } catch (e) {
146
  if (e?.info) {
147
  const errorInfo = JSON.parse(e?.info);
@@ -166,7 +187,7 @@ export default async function(o) {
166
  const playability = info.playability_status;
167
  const basicInfo = info.basic_info;
168
 
169
- switch(playability.status) {
170
  case "LOGIN_REQUIRED":
171
  if (playability.reason.endsWith("bot")) {
172
  return { error: "youtube.login" }
@@ -241,7 +262,7 @@ export default async function(o) {
241
  } else {
242
  throw new Error("couldn't fetch the HLS playlist");
243
  }
244
- }).catch(() => {});
245
 
246
  if (!fetchedHlsManifest) {
247
  return { error: "youtube.no_hls_streams" };
@@ -322,7 +343,7 @@ export default async function(o) {
322
  }
323
 
324
  const checkFormat = (format, pCodec) => format.content_length &&
325
- (format.mime_type.includes(codecList[pCodec].videoCodec)
326
  || format.mime_type.includes(codecList[pCodec].audioCodec));
327
 
328
  // sort formats & weed out bad ones
@@ -436,6 +457,10 @@ export default async function(o) {
436
  urls = audio.uri;
437
  }
438
 
 
 
 
 
439
  return {
440
  type: "audio",
441
  isAudioOnly: true,
@@ -462,11 +487,17 @@ export default async function(o) {
462
  width: video.width,
463
  height: video.height,
464
  });
 
465
  filenameAttributes.resolution = `${video.width}x${video.height}`;
466
  filenameAttributes.extension = codecList[codec].container;
467
 
468
  video = video.url;
469
  audio = audio.url;
 
 
 
 
 
470
  }
471
 
472
  filenameAttributes.qualityLabel = `${resolution}p`;
@@ -485,4 +516,4 @@ export default async function(o) {
485
  }
486
 
487
  return { error: "youtube.no_matching_format" };
488
- }
 
48
  return;
49
 
50
  const values = { ...cookie.values() };
51
+ const REQUIRED_VALUES = ['access_token', 'refresh_token'];
52
 
53
  if (REQUIRED_VALUES.some(x => typeof values[x] !== 'string')) {
54
  return;
 
66
 
67
  const cloneInnertube = async (customFetch) => {
68
  const shouldRefreshPlayer = lastRefreshedAt + PLAYER_REFRESH_PERIOD < new Date();
69
+
70
+ const rawCookie = getCookie('youtube');
71
+ const rawCookieValues = rawCookie?.values();
72
+ const cookie = rawCookie?.toString();
73
+
74
  if (!innertube || shouldRefreshPlayer) {
75
  innertube = await Innertube.create({
76
  fetch: customFetch,
77
+ retrieve_player: !!cookie,
78
+ cookie,
79
+ po_token: rawCookieValues?.po_token,
80
+ visitor_data: rawCookieValues?.visitor_data,
81
  });
82
  lastRefreshedAt = +new Date();
83
  }
 
88
  innertube.session.api_version,
89
  innertube.session.account_index,
90
  innertube.session.player,
91
+ cookie,
92
  customFetch ?? innertube.session.http.fetch,
93
  innertube.session.cache
94
  );
95
 
96
+ const oauthCookie = getCookie('youtube_oauth');
97
+ const oauthData = transformSessionData(oauthCookie);
98
 
99
  if (!session.logged_in && oauthData) {
100
  await session.oauth.init(oauthData);
101
  session.logged_in = true;
102
  }
103
 
104
+ if (session.logged_in && oauthData) {
105
  if (session.oauth.shouldRefreshToken()) {
106
  await session.oauth.refreshAccessToken();
107
  }
108
 
109
+ const cookieValues = oauthCookie.values();
110
  const oldExpiry = new Date(cookieValues.expiry_date);
111
  const newExpiry = new Date(session.oauth.oauth2_tokens.expiry_date);
112
 
113
  if (oldExpiry.getTime() !== newExpiry.getTime()) {
114
+ updateCookieValues(oauthCookie, {
115
  ...session.oauth.client_id,
116
  ...session.oauth.oauth2_tokens,
117
  expiry_date: newExpiry.toISOString()
 
123
  return yt;
124
  }
125
 
126
+ export default async function (o) {
127
  let yt;
128
  try {
129
  yt = await cloneInnertube(
 
140
  } else throw e;
141
  }
142
 
143
+ const cookie = getCookie('youtube')?.toString();
144
+
145
  let useHLS = o.youtubeHLS;
146
 
147
  // HLS playlists don't contain the av1 video format, at least with the iOS client
 
149
  useHLS = false;
150
  }
151
 
152
+ let innertubeClient = "ANDROID";
153
+
154
+ if (cookie) {
155
+ useHLS = false;
156
+ innertubeClient = "WEB";
157
+ }
158
+
159
+ if (useHLS) {
160
+ innertubeClient = "IOS";
161
+ }
162
+
163
  let info;
164
  try {
165
+ info = await yt.getBasicInfo(o.id, innertubeClient);
166
  } catch (e) {
167
  if (e?.info) {
168
  const errorInfo = JSON.parse(e?.info);
 
187
  const playability = info.playability_status;
188
  const basicInfo = info.basic_info;
189
 
190
+ switch (playability.status) {
191
  case "LOGIN_REQUIRED":
192
  if (playability.reason.endsWith("bot")) {
193
  return { error: "youtube.login" }
 
262
  } else {
263
  throw new Error("couldn't fetch the HLS playlist");
264
  }
265
+ }).catch(() => { });
266
 
267
  if (!fetchedHlsManifest) {
268
  return { error: "youtube.no_hls_streams" };
 
343
  }
344
 
345
  const checkFormat = (format, pCodec) => format.content_length &&
346
+ (format.mime_type.includes(codecList[pCodec].videoCodec)
347
  || format.mime_type.includes(codecList[pCodec].audioCodec));
348
 
349
  // sort formats & weed out bad ones
 
457
  urls = audio.uri;
458
  }
459
 
460
+ if (innertubeClient === "WEB" && innertube) {
461
+ urls = audio.decipher(innertube.session.player);
462
+ }
463
+
464
  return {
465
  type: "audio",
466
  isAudioOnly: true,
 
487
  width: video.width,
488
  height: video.height,
489
  });
490
+
491
  filenameAttributes.resolution = `${video.width}x${video.height}`;
492
  filenameAttributes.extension = codecList[codec].container;
493
 
494
  video = video.url;
495
  audio = audio.url;
496
+
497
+ if (innertubeClient === "WEB" && innertube) {
498
+ video = video.decipher(innertube.session.player);
499
+ audio = audio.decipher(innertube.session.player);
500
+ }
501
  }
502
 
503
  filenameAttributes.qualityLabel = `${resolution}p`;
 
516
  }
517
 
518
  return { error: "youtube.no_matching_format" };
519
+ }