Shows file size for each quality in YouTube
目前為
// ==UserScript==
// @name YouTube Qualities Size
// @namespace ytqz.smz.k
// @version 1.1.2
// @description Shows file size for each quality in YouTube
// @author Abdelrahman Khalil
// @match https://www.youtube.com/*
// @grant none
// ==/UserScript==
const API = 'https://www.youtube.com/get_video_info?video_id='
const cache = {}
let videoId, settingsMenuEl, observer
// Fetching Info
const fetchInfo = () => {
return fetch(API + videoId)
}
const parseResponse = data => {
// Youtube sends data as url queries.
// we parse it then get value of player_response which is stringified JSON.
let playerResponse = JSON.parse(getQuery(data, 'player_response'))
return playerResponse.streamingData.adaptiveFormats
}
// ---------
const findFormats = (formats, quality) => {
let allCodecs = [],
audioCL = 0,
vp9 = ''
let audioFormat = formats.find(
format =>
format.audioQuality === 'AUDIO_QUALITY_MEDIUM' &&
format.mimeType.includes('opus')
)
if (audioFormat) audioCL = audioFormat.contentLength
formats.forEach(format => {
if (format.qualityLabel === quality) {
let codec = format.mimeType.replace(REGEX.codec, '')
let sizeMB = toMB(format.contentLength, audioCL)
allCodecs.push(`${codec}: ${sizeMB} MB`)
if (codec === 'vp9') vp9 = sizeMB
}
})
let allCodecsStr = allCodecs.join('\n')
return { allCodecsStr, vp9 }
}
// Injection
const addSizesToChildren = menu => {
let qualityElements = menu.querySelectorAll('span')
let formats = cache[videoId]
if (!formats) return
qualityElements.forEach(el => {
let qualityLabel = el.textContent.replace(REGEX.qlabel, '')
if (qualityLabel === 'Auto') return
let { allCodecsStr, vp9 } = findFormats(formats, qualityLabel)
el.innerHTML += `<yt-qualities-size style="float: right; text-align: right" title="${allCodecsStr}">${vp9} MB</yt-qualities-size>`
})
}
// Making sure it's /watch
addEventListener('yt-page-data-updated', () => {
settingsMenuEl = document.querySelector('.ytp-settings-menu')
videoId = getQuery(location.search, 'v')
if (location.pathname === '/watch' && !observer) {
observer = new MutationObserver(async ([{ addedNodes }]) => {
let node = addedNodes[0]
if (
node &&
node.classList.contains('ytp-quality-menu') &&
!document.querySelector('yt-qualities-size')
) {
if (!cache[videoId]) {
let info = await (await fetchInfo()).text()
cache[videoId] = parseResponse(info)
}
addSizesToChildren(node)
}
})
observer.observe(settingsMenuEl, {
childList: true
})
}
})
// Utils/Helpers/Stuff
const getQuery = (string, query) => new URLSearchParams(string).get(query)
const toMB = (vbytes, abytes) =>
Math.round((parseInt(vbytes) + parseInt(abytes)) / 1048576)
const REGEX = {
qlabel: /\s(hd|4k|8k|16k)/i,
codec: /(?!=").+="|\..+|"/g
}