fix trailers: update user agents and innertube api key depreciation

This commit is contained in:
chrisk325 2026-03-05 01:07:15 +05:30 committed by GitHub
parent 905c59d23d
commit ed5bb26a59
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -70,17 +70,17 @@ export interface YouTubeExtractionResult {
// Innertube client configs — we use Android (no cipher, direct URLs) // Innertube client configs — we use Android (no cipher, direct URLs)
// and web as fallback (may need cipher decode) // and web as fallback (may need cipher decode)
const INNERTUBE_API_KEY = 'AIzaSyA8ggJvXiQHQFN-YMEoM30s0s3RlxEYJuA'; // Note: ?key= param was deprecated by YouTube in mid-2023 and is no longer sent.
const INNERTUBE_URL = 'https://www.youtube.com/youtubei/v1/player'; const INNERTUBE_URL = 'https://www.youtube.com/youtubei/v1/player';
// Android client gives direct URLs without cipher obfuscation // Android client gives direct URLs without cipher obfuscation
const ANDROID_CLIENT_CONTEXT = { const ANDROID_CLIENT_CONTEXT = {
client: { client: {
clientName: 'ANDROID', clientName: 'ANDROID',
clientVersion: '19.09.37', clientVersion: '19.44.41',
androidSdkVersion: 30, androidSdkVersion: 30,
userAgent: userAgent:
'com.google.android.youtube/19.09.37 (Linux; U; Android 11) gzip', 'com.google.android.youtube/19.44.41 (Linux; U; Android 11) gzip',
hl: 'en', hl: 'en',
gl: 'US', gl: 'US',
}, },
@ -90,10 +90,10 @@ const ANDROID_CLIENT_CONTEXT = {
const IOS_CLIENT_CONTEXT = { const IOS_CLIENT_CONTEXT = {
client: { client: {
clientName: 'IOS', clientName: 'IOS',
clientVersion: '19.09.3', clientVersion: '19.45.4',
deviceModel: 'iPhone14,3', deviceModel: 'iPhone16,2',
userAgent: userAgent:
'com.google.ios.youtube/19.09.3 (iPhone14,3; U; CPU iPhone OS 15_6 like Mac OS X)', 'com.google.ios.youtube/19.45.4 (iPhone16,2; U; CPU iOS 17_5_1 like Mac OS X)',
hl: 'en', hl: 'en',
gl: 'US', gl: 'US',
}, },
@ -359,7 +359,8 @@ async function writeDashManifestToFile(
async function fetchPlayerResponse( async function fetchPlayerResponse(
videoId: string, videoId: string,
context: object, context: object,
userAgent: string userAgent: string,
clientNameId: string = '3'
): Promise<InnertubePlayerResponse | null> { ): Promise<InnertubePlayerResponse | null> {
const controller = new AbortController(); const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS); const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
@ -373,13 +374,13 @@ async function fetchPlayerResponse(
}; };
const response = await fetch( const response = await fetch(
`${INNERTUBE_URL}?key=${INNERTUBE_API_KEY}&prettyPrint=false`, `${INNERTUBE_URL}?prettyPrint=false`,
{ {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'User-Agent': userAgent, 'User-Agent': userAgent,
'X-YouTube-Client-Name': '3', 'X-YouTube-Client-Name': clientNameId,
'Origin': 'https://www.youtube.com', 'Origin': 'https://www.youtube.com',
'Referer': `https://www.youtube.com/watch?v=${videoId}`, 'Referer': `https://www.youtube.com/watch?v=${videoId}`,
}, },
@ -500,24 +501,28 @@ export class YouTubeExtractor {
logger.info('YouTubeExtractor', `Extracting for videoId=${videoId} platform=${platform ?? 'unknown'}`); logger.info('YouTubeExtractor', `Extracting for videoId=${videoId} platform=${platform ?? 'unknown'}`);
const clients: Array<{ context: object; userAgent: string; name: string }> = [ const clients: Array<{ context: object; userAgent: string; name: string; clientNameId: string }> = [
{ {
name: 'ANDROID', name: 'ANDROID',
clientNameId: '3',
context: ANDROID_CLIENT_CONTEXT, context: ANDROID_CLIENT_CONTEXT,
userAgent: 'com.google.android.youtube/19.09.37 (Linux; U; Android 11) gzip', userAgent: 'com.google.android.youtube/19.44.41 (Linux; U; Android 11) gzip',
}, },
{ {
name: 'IOS', name: 'IOS',
clientNameId: '5',
context: IOS_CLIENT_CONTEXT, context: IOS_CLIENT_CONTEXT,
userAgent: 'com.google.ios.youtube/19.09.3 (iPhone14,3; U; CPU iPhone OS 15_6 like Mac OS X)', userAgent: 'com.google.ios.youtube/19.45.4 (iPhone16,2; U; CPU iOS 17_5_1 like Mac OS X)',
}, },
{ {
name: 'TVHTML5_EMBEDDED', name: 'TVHTML5_EMBEDDED',
clientNameId: '85',
context: TVHTML5_EMBEDDED_CONTEXT, context: TVHTML5_EMBEDDED_CONTEXT,
userAgent: 'Mozilla/5.0 (SMART-TV; Linux; Tizen 6.0)', userAgent: 'Mozilla/5.0 (SMART-TV; Linux; Tizen 6.0)',
}, },
{ {
name: 'WEB_EMBEDDED', name: 'WEB_EMBEDDED',
clientNameId: '56',
context: WEB_EMBEDDED_CONTEXT, context: WEB_EMBEDDED_CONTEXT,
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36', userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36',
}, },
@ -529,7 +534,7 @@ export class YouTubeExtractor {
for (const client of clients) { for (const client of clients) {
logger.info('YouTubeExtractor', `Trying ${client.name} client...`); logger.info('YouTubeExtractor', `Trying ${client.name} client...`);
const resp = await fetchPlayerResponse(videoId, client.context, client.userAgent); const resp = await fetchPlayerResponse(videoId, client.context, client.userAgent, client.clientNameId);
if (!resp) continue; if (!resp) continue;
const status = resp.playabilityStatus?.status; const status = resp.playabilityStatus?.status;