显示YouTube好评/差评比例(好评占比)

治好了我每次看到好评和差评时都忍不住心算一下好评占比的强迫症

  1. // ==UserScript==
  2. // @name 显示YouTube好评/差评比例(好评占比)
  3. // @name:en yet another simple YouTube video likes/dislikes ratio display
  4. // @namespace http://tampermonkey.net/
  5. // @version 0.6.1
  6. // @description 治好了我每次看到好评和差评时都忍不住心算一下好评占比的强迫症
  7. // @description:en Show likes/dislikes ratio of YouTube video.
  8. // @author SSmJaE
  9. // @match https://www.youtube.com/*
  10. // @license GPL-3.0
  11. // @compatible chrome
  12. // ==/UserScript==
  13.  
  14. const USER_SETTINGS = {
  15. //多久检查一次是否有新的视频
  16. //determine how often to check if there are any new videos
  17. checkInterval: 5000,
  18. //是否显示所有视频的好评率,如果关闭,只显示主视频(也就是正在播放的视频)的好评率
  19. //whether show all videos' ratios
  20. showAllRatios: true,
  21. //间隔多久查询下一个视频,避免请求过快被ban ip
  22. //determine to wait how much time to check next video, for avoiding being banned IP for checking too fast
  23. sleepInterval: 500,
  24. //是否显示彩色好评率,默认开启,关闭的话,显示灰色
  25. //whether to show different colors for the ratio, or just grey
  26. /**
  27. * >=99% , blue
  28. * 90~99%, green
  29. * 80~90%, yellow
  30. * <80% , red
  31. */
  32. colorfulRatio: true,
  33. //是否显示喜欢按钮上方的统计数字
  34. //whether to show the total count above like button
  35. showLikeCount: true,
  36. //是否显示不喜欢按钮上方的统计数字
  37. //whether to show the total count above dislike button
  38. showDislikeCount: true,
  39. };
  40.  
  41. function sleep(ms) {
  42. return new Promise((resolve) => setTimeout(resolve, ms));
  43. }
  44.  
  45. function calculate_ratio([upCount, downCount]) {
  46. upCount = parseInt(upCount.replace(/[^0-9]/gi, ""), 10);
  47. downCount = parseInt(downCount.replace(/[^0-9]/gi, ""), 10);
  48. let ratio = Math.round((upCount * 1000) / (upCount + downCount)) / 10;
  49.  
  50. if (upCount > 0 && !downCount) ratio = 100; //正无穷
  51. if (isNaN(ratio)) ratio = 0; //只有0/0会为NaN
  52. return ratio + "%";
  53. }
  54.  
  55. async function handle_all() {
  56. for (let video of document.querySelectorAll("#thumbnail[href]")) {
  57. if (
  58. video.parentElement.parentElement.parentElement.parentElement.parentElement.hasAttribute(
  59. "hidden",
  60. )
  61. )
  62. continue; //跳过被隐藏的视频
  63. if (video.classList.contains("ratio")) continue;
  64.  
  65. await sleep(USER_SETTINGS.sleepInterval);
  66. try {
  67. fetch(video.getAttribute("href"), { credentials: "omit" })
  68. .then((response) => response.text())
  69. .then((text) => {
  70. if (!video.classList.contains("ratio")) {
  71. //跳过已添加ratio的视频
  72. let tooltip = /"INDIFFERENT","tooltip":"(.*?)"/.exec(text)[1];
  73. let ratio = calculate_ratio(tooltip.split("/"));
  74.  
  75. let ratioDiv = document.createElement("div");
  76. ratioDiv.classList.add("style-scope", "ytd-video-meta-block", "ratio");
  77. ratioDiv.textContent = ratio;
  78. let color = "";
  79. if (USER_SETTINGS.colorfulRatio) {
  80. if (parseInt(ratio, 10) >= 99) {
  81. color = "rgb(30,144,255)";
  82. } else if (parseInt(ratio, 10) >= 90) {
  83. color = "rgb(98,198,70)";
  84. } else if (parseInt(ratio, 10) >= 80) {
  85. color = "rgb(255,192,0)";
  86. } else {
  87. color = "rgb(207,32,0)";
  88. }
  89. }
  90. ratioDiv.style.color = color;
  91.  
  92. const dot = document.createElement("div");
  93. dot.textContent = "•";
  94. dot.style.margin = "0 4px";
  95.  
  96. video.parentElement.nextElementSibling
  97. .querySelector("#metadata-line")
  98. .appendChild(dot);
  99. video.parentElement.nextElementSibling
  100. .querySelector("#metadata-line")
  101. .appendChild(ratioDiv);
  102. video.classList.add("ratio");
  103. }
  104. });
  105. } catch (error) {}
  106. }
  107. setTimeout(handle_all, USER_SETTINGS.checkInterval);
  108. }
  109.  
  110. function handle_main() {
  111. try {
  112. let menuBar = document.querySelector("div#info div#menu div#top-level-buttons");
  113. let up = menuBar.childNodes[0].querySelector('[id="text"]');
  114. let down = menuBar.childNodes[1].querySelector('[id="text"]');
  115. let shareButton = menuBar.childNodes[2].querySelector('[id="text"]');
  116. shareButton.textContent = calculate_ratio([
  117. up.getAttribute("aria-label"),
  118. down.getAttribute("aria-label"),
  119. ]);
  120.  
  121. if (!USER_SETTINGS.showLikeCount) up.textContent = "";
  122. if (!USER_SETTINGS.showDislikeCount) down.textContent = "";
  123. } catch (e) {}
  124. }
  125.  
  126. /*------------------------------------------------------------------------- */
  127. setInterval(handle_main, USER_SETTINGS.checkInterval);
  128.  
  129. if (USER_SETTINGS.showAllRatios) setTimeout(handle_all, USER_SETTINGS.checkInterval);