mirror of
https://github.com/imputnet/cobalt.git
synced 2024-12-28 18:46:09 +00:00
api/youtube: use poToken, visitorData, and web client with cookies
and also decipher media whenever needed, but only if cookies are used
This commit is contained in:
parent
9da3ba60a9
commit
c6d0e0bdd5
|
@ -48,7 +48,7 @@ const transformSessionData = (cookie) => {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const values = { ...cookie.values() };
|
const values = { ...cookie.values() };
|
||||||
const REQUIRED_VALUES = [ 'access_token', 'refresh_token' ];
|
const REQUIRED_VALUES = ['access_token', 'refresh_token'];
|
||||||
|
|
||||||
if (REQUIRED_VALUES.some(x => typeof values[x] !== 'string')) {
|
if (REQUIRED_VALUES.some(x => typeof values[x] !== 'string')) {
|
||||||
return;
|
return;
|
||||||
|
@ -66,12 +66,18 @@ const transformSessionData = (cookie) => {
|
||||||
|
|
||||||
const cloneInnertube = async (customFetch) => {
|
const cloneInnertube = async (customFetch) => {
|
||||||
const shouldRefreshPlayer = lastRefreshedAt + PLAYER_REFRESH_PERIOD < new Date();
|
const shouldRefreshPlayer = lastRefreshedAt + PLAYER_REFRESH_PERIOD < new Date();
|
||||||
const cookie = getCookie('youtube')?.toString();
|
|
||||||
|
const rawCookie = getCookie('youtube');
|
||||||
|
const cookieValues = rawCookie?.values();
|
||||||
|
const cookie = rawCookie?.toString();
|
||||||
|
|
||||||
if (!innertube || shouldRefreshPlayer) {
|
if (!innertube || shouldRefreshPlayer) {
|
||||||
innertube = await Innertube.create({
|
innertube = await Innertube.create({
|
||||||
fetch: customFetch,
|
fetch: customFetch,
|
||||||
retrieve_player: false,
|
retrieve_player: !!cookie,
|
||||||
cookie
|
cookie,
|
||||||
|
po_token: cookieValues?.po_token,
|
||||||
|
visitor_data: cookieValues?.visitor_data,
|
||||||
});
|
});
|
||||||
lastRefreshedAt = +new Date();
|
lastRefreshedAt = +new Date();
|
||||||
}
|
}
|
||||||
|
@ -117,7 +123,7 @@ const cloneInnertube = async (customFetch) => {
|
||||||
return yt;
|
return yt;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function(o) {
|
export default async function (o) {
|
||||||
let yt;
|
let yt;
|
||||||
try {
|
try {
|
||||||
yt = await cloneInnertube(
|
yt = await cloneInnertube(
|
||||||
|
@ -134,6 +140,8 @@ export default async function(o) {
|
||||||
} else throw e;
|
} else throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cookie = getCookie('youtube')?.toString();
|
||||||
|
|
||||||
let useHLS = o.youtubeHLS;
|
let useHLS = o.youtubeHLS;
|
||||||
|
|
||||||
// HLS playlists don't contain the av1 video format, at least with the iOS client
|
// HLS playlists don't contain the av1 video format, at least with the iOS client
|
||||||
|
@ -141,9 +149,20 @@ export default async function(o) {
|
||||||
useHLS = false;
|
useHLS = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let innertubeClient = "ANDROID";
|
||||||
|
|
||||||
|
if (cookie) {
|
||||||
|
useHLS = false;
|
||||||
|
innertubeClient = "WEB";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useHLS) {
|
||||||
|
innertubeClient = "IOS";
|
||||||
|
}
|
||||||
|
|
||||||
let info;
|
let info;
|
||||||
try {
|
try {
|
||||||
info = await yt.getBasicInfo(o.id, useHLS ? 'IOS' : 'ANDROID');
|
info = await yt.getBasicInfo(o.id, innertubeClient);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e?.info) {
|
if (e?.info) {
|
||||||
const errorInfo = JSON.parse(e?.info);
|
const errorInfo = JSON.parse(e?.info);
|
||||||
|
@ -168,7 +187,7 @@ export default async function(o) {
|
||||||
const playability = info.playability_status;
|
const playability = info.playability_status;
|
||||||
const basicInfo = info.basic_info;
|
const basicInfo = info.basic_info;
|
||||||
|
|
||||||
switch(playability.status) {
|
switch (playability.status) {
|
||||||
case "LOGIN_REQUIRED":
|
case "LOGIN_REQUIRED":
|
||||||
if (playability.reason.endsWith("bot")) {
|
if (playability.reason.endsWith("bot")) {
|
||||||
return { error: "youtube.login" }
|
return { error: "youtube.login" }
|
||||||
|
@ -243,7 +262,7 @@ export default async function(o) {
|
||||||
} else {
|
} else {
|
||||||
throw new Error("couldn't fetch the HLS playlist");
|
throw new Error("couldn't fetch the HLS playlist");
|
||||||
}
|
}
|
||||||
}).catch(() => {});
|
}).catch(() => { });
|
||||||
|
|
||||||
if (!fetchedHlsManifest) {
|
if (!fetchedHlsManifest) {
|
||||||
return { error: "youtube.no_hls_streams" };
|
return { error: "youtube.no_hls_streams" };
|
||||||
|
@ -324,7 +343,7 @@ export default async function(o) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkFormat = (format, pCodec) => format.content_length &&
|
const checkFormat = (format, pCodec) => format.content_length &&
|
||||||
(format.mime_type.includes(codecList[pCodec].videoCodec)
|
(format.mime_type.includes(codecList[pCodec].videoCodec)
|
||||||
|| format.mime_type.includes(codecList[pCodec].audioCodec));
|
|| format.mime_type.includes(codecList[pCodec].audioCodec));
|
||||||
|
|
||||||
// sort formats & weed out bad ones
|
// sort formats & weed out bad ones
|
||||||
|
@ -438,6 +457,10 @@ export default async function(o) {
|
||||||
urls = audio.uri;
|
urls = audio.uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (innertubeClient === "WEB" && innertube) {
|
||||||
|
urls = audio.decipher(innertube.session.player);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: "audio",
|
type: "audio",
|
||||||
isAudioOnly: true,
|
isAudioOnly: true,
|
||||||
|
@ -464,11 +487,17 @@ export default async function(o) {
|
||||||
width: video.width,
|
width: video.width,
|
||||||
height: video.height,
|
height: video.height,
|
||||||
});
|
});
|
||||||
|
|
||||||
filenameAttributes.resolution = `${video.width}x${video.height}`;
|
filenameAttributes.resolution = `${video.width}x${video.height}`;
|
||||||
filenameAttributes.extension = codecList[codec].container;
|
filenameAttributes.extension = codecList[codec].container;
|
||||||
|
|
||||||
video = video.url;
|
video = video.url;
|
||||||
audio = audio.url;
|
audio = audio.url;
|
||||||
|
|
||||||
|
if (innertubeClient === "WEB" && innertube) {
|
||||||
|
video = video.decipher(innertube.session.player);
|
||||||
|
audio = audio.decipher(innertube.session.player);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filenameAttributes.qualityLabel = `${resolution}p`;
|
filenameAttributes.qualityLabel = `${resolution}p`;
|
||||||
|
|
Loading…
Reference in a new issue