Skip to content

Commit

Permalink
feat(getInfo): use android player to get more stream itags
Browse files Browse the repository at this point in the history
  • Loading branch information
skick1234 committed Aug 5, 2024
1 parent 06ad10b commit 9fd6390
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 19 deletions.
42 changes: 42 additions & 0 deletions lib/formats.js
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,20 @@ module.exports = {
audioBitrate: 192,
},

231: {
mimeType: 'video/ts; codecs="H.264, aac"',
qualityLabel: '480p',
bitrate: 500000,
audioBitrate: null,
},

232: {
mimeType: 'video/ts; codecs="H.264, aac"',
qualityLabel: '720p',
bitrate: 800000,
audioBitrate: null,
},

242: {
mimeType: 'video/webm; codecs="VP9"',
qualityLabel: '240p',
Expand Down Expand Up @@ -388,6 +402,13 @@ module.exports = {
audioBitrate: null,
},

270: {
mimeType: 'video/webm; codecs="VP9"',
qualityLabel: '1080p',
bitrate: 5000000,
audioBitrate: null,
},

271: {
mimeType: 'video/webm; codecs="VP9"',
qualityLabel: '1440p',
Expand Down Expand Up @@ -430,6 +451,13 @@ module.exports = {
audioBitrate: 48,
},

301: {
mimeType: 'video/ts; codecs="H.264, aac"',
qualityLabel: '1080p',
bitrate: 3000000,
audioBitrate: 128,
},

302: {
mimeType: 'video/webm; codecs="VP9"',
qualityLabel: '720p HFR',
Expand All @@ -451,6 +479,20 @@ module.exports = {
audioBitrate: null,
},

311: {
mimeType: 'video/webm; codecs="VP9"',
qualityLabel: '720p',
bitrate: 1250000,
audioBitrate: null,
},

312: {
mimeType: 'video/webm; codecs="VP9"',
qualityLabel: '1080p',
bitrate: 2500000,
audioBitrate: null,
},

313: {
mimeType: 'video/webm; codecs="VP9"',
qualityLabel: '2160p',
Expand Down
105 changes: 86 additions & 19 deletions lib/info.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ const parseFormats = player_response => {
return formats;
};


// TODO: Clean up this function for readability and support more clients
/**
* Gets info from a video additional formats and deciphered URLs.
*
Expand All @@ -218,27 +218,30 @@ const parseFormats = player_response => {
*/
exports.getInfo = async(id, options) => {
const info = await exports.getBasicInfo(id, options);
const iosPlayerResponse = await fetchIosJsonPlayer(id, options);
const playErr = utils.playError(iosPlayerResponse);
if (playErr) throw playErr;

info.formats = parseFormats(iosPlayerResponse);
const hasManifest =
iosPlayerResponse && iosPlayerResponse.streamingData && (
iosPlayerResponse.streamingData.dashManifestUrl ||
iosPlayerResponse.streamingData.hlsManifestUrl
);
const [iosPlayerResponse, androidPlayerResponse] = await Promise.all([
fetchIosJsonPlayer(id, options),
fetchAndroidJsonPlayer(id, options),
]);
info.formats = parseFormats(androidPlayerResponse).concat(parseFormats(iosPlayerResponse));
let funcs = [];
if (info.formats.length) {
funcs.push(info.formats);
}
if (hasManifest && iosPlayerResponse.streamingData.dashManifestUrl) {
let url = iosPlayerResponse.streamingData.dashManifestUrl;
funcs.push(getDashManifest(url, options));
if (androidPlayerResponse && androidPlayerResponse.streamingData) {
if (androidPlayerResponse.streamingData.dashManifestUrl) {
funcs.push(getDashManifest(androidPlayerResponse.streamingData.dashManifestUrl, options));
}
if (androidPlayerResponse.streamingData.hlsManifestUrl) {
funcs.push(getM3U8(androidPlayerResponse.streamingData.hlsManifestUrl, options));
}
}
if (hasManifest && iosPlayerResponse.streamingData.hlsManifestUrl) {
let url = iosPlayerResponse.streamingData.hlsManifestUrl;
funcs.push(getM3U8(url, options));
if (iosPlayerResponse && iosPlayerResponse.streamingData) {
if (iosPlayerResponse.streamingData.dashManifestUrl) {
funcs.push(getDashManifest(iosPlayerResponse.streamingData.dashManifestUrl, options));
}
if (iosPlayerResponse.streamingData.hlsManifestUrl) {
funcs.push(getM3U8(iosPlayerResponse.streamingData.hlsManifestUrl, options));
}
}

let results = await Promise.all(funcs);
Expand All @@ -251,8 +254,6 @@ exports.getInfo = async(id, options) => {
return info;
};


// TODO: Clean up this code to impliment Android player.
const IOS_CLIENT_VERSION = '19.28.1',
IOS_DEVICE_MODEL = 'iPhone16,2',
IOS_USER_AGENT_VERSION = '17_5_1',
Expand Down Expand Up @@ -309,6 +310,72 @@ const fetchIosJsonPlayer = async(videoId, options) => {
},
};
const response = await utils.request('https://youtubei.googleapis.com/youtubei/v1/player', opts);
const playErr = utils.playError(response);
if (playErr) throw playErr;
if (!response.videoDetails || videoId !== response.videoDetails.videoId) {
const err = new Error('Malformed response from YouTube');
err.response = response;
throw err;
}
return response;
};

const ANDROID_CLIENT_VERSION = '19.30.36',
ANDROID_OS_VERSION = '14',
ANDROID_SDK_VERSION = '34';


const fetchAndroidJsonPlayer = async(videoId, options) => {
const payload = {
videoId,
cpn: utils.generateClientPlaybackNonce(16),
contentCheckOk: true,
racyCheckOk: true,
context: {
client: {
clientName: 'ANDROID',
clientVersion: ANDROID_CLIENT_VERSION,
platform: 'MOBILE',
osName: 'Android',
osVersion: ANDROID_OS_VERSION,
androidSdkVersion: ANDROID_SDK_VERSION,
hl: 'en',
gl: 'US',
utcOffsetMinutes: -240,
},
request: {
internalExperimentFlags: [],
useSsl: true,
},
user: {
lockedSafetyMode: false,
},
},
};

const { jar, dispatcher } = options.agent || defaultAgent;
const opts = {
requestOptions: {
method: 'POST',
dispatcher,
query: {
prettyPrint: false,
t: utils.generateClientPlaybackNonce(12),
id: videoId,
},
headers: {
'Content-Type': 'application/json',
cookie: jar.getCookieStringSync('https://www.youtube.com'),
'User-Agent': `com.google.android.youtube/${ANDROID_CLIENT_VERSION
} (Linux; U; Android ${ANDROID_OS_VERSION}; en_US) gzip`,
'X-Goog-Api-Format-Version': '2',
},
body: JSON.stringify(payload),
},
};
const response = await utils.request('https://youtubei.googleapis.com/youtubei/v1/player', opts);
const playErr = utils.playError(response);
if (playErr) throw playErr;
if (!response.videoDetails || videoId !== response.videoDetails.videoId) {
const err = new Error('Malformed response from YouTube');
err.response = response;
Expand Down

0 comments on commit 9fd6390

Please sign in to comment.