function extractAdaptiveFormatsInfo(in_formats) { function getStreamType(f) { const mimeType = f.mimeType || ''; if (mimeType.startsWith('audio/')) return 'audio'; if (mimeType.startsWith('video/')) { if (f.audioChannels && f.audioChannels > 0) { return 'video+audio'; } return 'video'; } return '-'; } function getFormat(mimeType) { if (!mimeType) return '-'; return mimeType.split(';')[0].split('/')[1] || '-'; } function getCodec(mimeType) { if (!mimeType) return '-'; const match = mimeType.match(/codecs="(.+?)"/); return match ? match[1] : '-'; } function prettyBitrate(bps) { if (bps == null || bps === '-') return '-'; if (bps >= 1_000_000) return (bps / 1_000_000).toFixed(2) + ' Mb'; if (bps >= 1_000) return (bps / 1_000).toFixed(1) + ' kb'; return bps + ' bps'; } function prettySize(size) { if (!size || isNaN(size)) return '-'; size = Number(size); if (size >= 1024 * 1024 * 1024) return (size / (1024 * 1024 * 1024)).toFixed(2) + ' GB'; if (size >= 1024 * 1024) return (size / (1024 * 1024)).toFixed(2) + ' MB'; if (size >= 1024) return (size / 1024).toFixed(1) + ' KB'; return size + ' B'; } function cleanQualityStr(q) { if (!q) return '-'; return String(q).replace(/^AUDIO_QUALITY_/, ''); } function pad(str, len) { str = String(str ?? '-'); return str.length >= len ? str.slice(0, len) : str + ' '.repeat(len - str.length); } function getVideoAudioBitrate(f) { let videoBitrate = '-'; let audioBitrate = '-'; if (f.approximateAudioBitrate || f.audioBitrate) { audioBitrate = prettyBitrate(f.approximateAudioBitrate || f.audioBitrate); if (f.bitrate) { videoBitrate = prettyBitrate(f.bitrate - (f.approximateAudioBitrate || f.audioBitrate)); } } else if (getStreamType(f).startsWith('audio')) { audioBitrate = prettyBitrate(f.bitrate); } else if (getStreamType(f).startsWith('video')) { videoBitrate = prettyBitrate(f.bitrate); } return { videoBitrate, audioBitrate }; } let rows = in_formats.map(f => { const type = getStreamType(f); const bitrate = prettyBitrate(f.bitrate); const res = (f.width && f.height) ? `${f.width}x${f.height}` : '-'; const fps = f.fps ?? '-'; const format = getFormat(f.mimeType); const codec = getCodec(f.mimeType); let quality = f.qualityLabel || f.audioQuality || f.quality || '-'; quality = cleanQualityStr(quality); const size = prettySize(f.contentLength || f.approximateContentLength); const { videoBitrate, audioBitrate } = getVideoAudioBitrate(f); let audioSampleRate = f.audioSampleRate ? f.audioSampleRate + ' Hz' : '-'; let itagStr = f.itag; if (f.isDrc) itagStr = itagStr + '-drc'; let resSort = 0; if (f.width && f.height) resSort = f.width * f.height; let qualitySort = 0; if (f.qualityLabel) { const m = f.qualityLabel.match(/^(\d+)/); if (m) qualitySort = parseInt(m[1]); } else if (f.audioQuality) { if (/LOW/i.test(f.audioQuality)) qualitySort = 1; else if (/MEDIUM/i.test(f.audioQuality)) qualitySort = 2; else if (/HIGH/i.test(f.audioQuality)) qualitySort = 3; } else if (f.quality) { const m = String(f.quality).match(/^(\d+)/); if (m) qualitySort = parseInt(m[1]); } return { itag: itagStr, format, type, res, bitrate, videoBitrate, audioBitrate, audioSampleRate, fps, codec, quality, size, resSort, qualitySort }; }); rows.sort((a, b) => { if (a.resSort && b.resSort) return b.resSort - a.resSort; if (a.resSort) return -1; if (b.resSort) return 1; return b.qualitySort - a.qualitySort; }); let out = [ pad('itag', 10) + pad('format', 8) + pad('type', 12) + pad('resolution', 13) + pad('total br', 12) + pad('video br', 12) + pad('audio br', 12) + pad('audio rate', 12) + pad('fps', 5) + pad('codec', 18) + pad('quality', 12) + pad('size', 12) ]; out.push('-'.repeat(138)); rows.forEach(r => { out.push( pad(r.itag, 10) + pad(r.format, 8) + pad(r.type, 12) + pad(r.res, 13) + pad(r.bitrate, 12) + pad(r.videoBitrate, 12) + pad(r.audioBitrate, 12) + pad(r.audioSampleRate, 12) + pad(r.fps, 5) + pad(r.codec, 18) + pad(r.quality, 12) + pad(r.size, 12) ); }); return out.join('\n'); } // Usage example: var plyRes = document.getElementsByTagName("ytd-app")[0].data.playerResponse; var streamingData = plyRes.streamingData; var arr_formats = (streamingData.adaptiveFormats || []) .concat(streamingData.formats || []); console.log(extractAdaptiveFormatsInfo(arr_formats));