Update youtubeExtractor.ts

This commit is contained in:
CK 2026-03-05 21:39:26 +05:30 committed by GitHub
parent 5fa02d7c53
commit a2a801d68a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -416,35 +416,69 @@ async function collectAllFormats(
const adaptiveAudio: StreamCandidate[] = []; const adaptiveAudio: StreamCandidate[] = [];
const hlsManifests: Array<{ clientKey: string; priority: number; url: string }> = []; const hlsManifests: Array<{ clientKey: string; priority: number; url: string }> = [];
for (const client of CLIENTS) { // Fire all client requests in parallel — same approach as Kotlin coroutines
try { const results = await Promise.allSettled(
const resp = await fetchPlayerResponse(videoId, client, apiKey, visitorData); CLIENTS.map(client => fetchPlayerResponse(videoId, client, apiKey, visitorData)
if (!resp) continue; .then(resp => ({ client, resp }))
)
);
const status = resp.playabilityStatus?.status; for (const result of results) {
if (status && status !== 'OK' && status !== 'CONTENT_CHECK_REQUIRED') { if (result.status === 'rejected') {
logger.warn('YouTubeExtractor', `[${client.key}] status=${status} reason=${resp.playabilityStatus?.reason ?? ''}`); logger.warn('YouTubeExtractor', `Client request rejected:`, result.reason);
continue; continue;
} }
const sd = resp.streamingData; const { client, resp } = result.value;
if (!sd) continue; if (!resp) continue;
if (sd.hlsManifestUrl) { const status = resp.playabilityStatus?.status;
hlsManifests.push({ clientKey: client.key, priority: client.priority, url: sd.hlsManifestUrl }); if (status && status !== 'OK' && status !== 'CONTENT_CHECK_REQUIRED') {
} logger.warn('YouTubeExtractor', `[${client.key}] status=${status} reason=${resp.playabilityStatus?.reason ?? ''}`);
continue;
}
let nProg = 0, nVid = 0, nAud = 0; const sd = resp.streamingData;
if (!sd) continue;
// Progressive (muxed) formats — matching Kotlin: skip non-video mimeTypes if (sd.hlsManifestUrl) {
for (const f of (sd.formats ?? [])) { hlsManifests.push({ clientKey: client.key, priority: client.priority, url: sd.hlsManifestUrl });
if (!f.url) continue; }
const mimeBase = getMimeBase(f.mimeType);
if (f.mimeType && !mimeBase.startsWith('video/')) continue; let nProg = 0, nVid = 0, nAud = 0;
// Progressive (muxed) formats — matching Kotlin: skip non-video mimeTypes
for (const f of (sd.formats ?? [])) {
if (!f.url) continue;
const mimeBase = getMimeBase(f.mimeType);
if (f.mimeType && !mimeBase.startsWith('video/')) continue;
const height = f.height ?? parseQualityLabel(f.qualityLabel);
const fps = f.fps ?? 0;
const bitrate = f.bitrate ?? f.averageBitrate ?? 0;
progressive.push({
client: client.key,
priority: client.priority,
url: f.url,
score: videoScore(height, fps, bitrate),
height,
fps,
ext: getExt(f.mimeType),
bitrate,
mimeType: f.mimeType ?? '',
});
nProg++;
}
// Adaptive formats
for (const f of (sd.adaptiveFormats ?? [])) {
if (!f.url) continue;
const mimeBase = getMimeBase(f.mimeType);
if (mimeBase.startsWith('video/')) {
const height = f.height ?? parseQualityLabel(f.qualityLabel); const height = f.height ?? parseQualityLabel(f.qualityLabel);
const fps = f.fps ?? 0; const fps = f.fps ?? 0;
const bitrate = f.bitrate ?? f.averageBitrate ?? 0; const bitrate = f.bitrate ?? f.averageBitrate ?? 0;
progressive.push({ adaptiveVideo.push({
client: client.key, client: client.key,
priority: client.priority, priority: client.priority,
url: f.url, url: f.url,
@ -455,53 +489,27 @@ async function collectAllFormats(
bitrate, bitrate,
mimeType: f.mimeType ?? '', mimeType: f.mimeType ?? '',
}); });
nProg++; nVid++;
} else if (mimeBase.startsWith('audio/')) {
const bitrate = f.bitrate ?? f.averageBitrate ?? 0;
const sampleRate = parseFloat(f.audioSampleRate ?? '0') || 0;
adaptiveAudio.push({
client: client.key,
priority: client.priority,
url: f.url,
score: audioScore(bitrate, sampleRate),
height: 0,
fps: 0,
ext: getExt(f.mimeType),
bitrate,
audioSampleRate: f.audioSampleRate,
mimeType: f.mimeType ?? '',
});
nAud++;
} }
// Adaptive formats
for (const f of (sd.adaptiveFormats ?? [])) {
if (!f.url) continue;
const mimeBase = getMimeBase(f.mimeType);
if (mimeBase.startsWith('video/')) {
const height = f.height ?? parseQualityLabel(f.qualityLabel);
const fps = f.fps ?? 0;
const bitrate = f.bitrate ?? f.averageBitrate ?? 0;
adaptiveVideo.push({
client: client.key,
priority: client.priority,
url: f.url,
score: videoScore(height, fps, bitrate),
height,
fps,
ext: getExt(f.mimeType),
bitrate,
mimeType: f.mimeType ?? '',
});
nVid++;
} else if (mimeBase.startsWith('audio/')) {
const bitrate = f.bitrate ?? f.averageBitrate ?? 0;
const sampleRate = parseFloat(f.audioSampleRate ?? '0') || 0;
adaptiveAudio.push({
client: client.key,
priority: client.priority,
url: f.url,
score: audioScore(bitrate, sampleRate),
height: 0,
fps: 0,
ext: getExt(f.mimeType),
bitrate,
audioSampleRate: f.audioSampleRate,
mimeType: f.mimeType ?? '',
});
nAud++;
}
}
logger.info('YouTubeExtractor', `[${client.key}] progressive=${nProg} video=${nVid} audio=${nAud} hls=${sd.hlsManifestUrl ? 1 : 0}`);
} catch (err) {
logger.warn('YouTubeExtractor', `[${client.key}] Failed:`, err);
} }
logger.info('YouTubeExtractor', `[${client.key}] progressive=${nProg} video=${nVid} audio=${nAud} hls=${sd.hlsManifestUrl ? 1 : 0}`);
} }
return { progressive, adaptiveVideo, adaptiveAudio, hlsManifests }; return { progressive, adaptiveVideo, adaptiveAudio, hlsManifests };