// ==UserScript== // @name 显示YouTube好评/差评比例(好评占比) // @name:en yet another simple YouTube video likes/dislikes ratio display // @namespace http://tampermonkey.net/ // @version 0.5.3 // @description 治好了我每次看到好评和差评时都忍不住心算一下好评占比的强迫症 // @description:en Show likes/dislikes ratio of YouTube video. // @author SSmJaE // @match https://www.youtube.com/* // @license MIT // @downloadURL none // ==/UserScript== const USER_SETTINGS = { checkInterval: 5000,//多久检查一次是否有新的视频|determine how often to check if there are any new videos showAllRatios: true,//是否显示所有视频的好评率,如果关闭,只显示主视频(也就是正在播放的视频)的好评率|whether show all videos' ratios sleepInterval: 500,//间隔多久查询下一个视频,避免请求过快被ban ip|determine to wait how much time to check next video, for avoiding being banned IP for checking too fast } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function calculate_ratio(upCount, downCount) { upCount = parseInt(upCount.replace(/[^0-9]/ig, "")); downCount = parseInt(downCount.replace(/[^0-9]/ig, "")); let ratio = Math.round(upCount * 1000 / (upCount + downCount)) / 10; if (upCount > 0 && !downCount) ratio = 100; if (isNaN(ratio)) ratio = 0; //只有0/0会为NaN return ratio + "%" } async function handle_all() { let videos = document.querySelectorAll('#thumbnail[href]'); for (let video of videos) { if (video.parentElement.parentElement.parentElement.parentElement.parentElement.hasAttribute('hidden')) continue; //跳过被隐藏的视频 if (video.classList.contains('ratio')) continue; await sleep(USER_SETTINGS.sleepInterval); try { fetch(video.getAttribute('href')).then(response => response.text()).then(text => { if (!video.classList.contains('ratio')) { //跳过已添加ratio的视频 let tooltip = /\"INDIFFERENT\",\"tooltip\":\"(.*?)\"}/.exec(text)[1]; let ratio = calculate_ratio(tooltip.split('/')[0], tooltip.split('/')[1]); let ratioDiv = document.createElement('ratioDiv'); ratioDiv.classList.add('style-scope', 'ytd-video-meta-block', 'ratio') ratioDiv.textContent = ratio; let color = ''; if (parseInt(ratio, 10) >= 90) { color = 'rgb(98,198,70)'; } else if (parseInt(ratio, 10) >= 80) { color = 'rgb(255,192,0)'; } else { color = 'rgb(207,32,0)'; } ratioDiv.style.color = color; let dot = document.createElement('ratioDiv'); dot.textContent = "•"; dot.style.margin = "0 4px"; video.parentElement.nextElementSibling.querySelector('#metadata-line').appendChild(dot); video.parentElement.nextElementSibling.querySelector('#metadata-line').appendChild(ratioDiv); video.classList.add('ratio'); } }); } catch (error) { }; }; } function handle_main() { try { let menuBar = document.querySelector('div#info div#menu div#top-level-buttons'); let up = menuBar.childNodes[0].querySelector('[id="text"]'); let down = menuBar.childNodes[1].querySelector('[id="text"]'); let shareButton = menuBar.childNodes[2].querySelector('[id="text"]'); shareButton.textContent = calculate_ratio(up.getAttribute('aria-label'), down.getAttribute('aria-label')); } catch (e) { }; } setInterval(() => { handle_main(); if (USER_SETTINGS.showAllRatios) handle_all(); }, USER_SETTINGS.checkInterval);