Return YouTube Dislike

Return of the YouTube Dislike, Based off https://www.returnyoutubedislike.com/

当前为 2021-11-27 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Return YouTube Dislike
  3. // @namespace https://www.returnyoutubedislike.com/
  4. // @version 0.5
  5. // @description Return of the YouTube Dislike, Based off https://www.returnyoutubedislike.com/
  6. // @author Anarios & JRWR
  7. // @match *://*.youtube.com/watch*
  8. // @compatible chrome
  9. // @compatible firefox
  10. // @compatible opera
  11. // @compatible safari
  12. // @compatible edge
  13. // @grant GM.xmlHttpRequest
  14. // ==/UserScript==
  15. function cLog(text, subtext = '') {
  16. subtext = subtext.trim() === '' ? '' : `(${subtext})`;
  17. console.log(`[Return Youtube Dislikes] ${text} ${subtext}`);
  18. }
  19.  
  20. function doXHR(opts) {
  21. if (typeof GM_xmlhttpRequest === 'function') {
  22. return GM_xmlhttpRequest(opts);
  23. }
  24. if (typeof GM.xmlHttpRequest === 'function') {
  25. return GM.xmlHttpRequest(opts);
  26. }
  27.  
  28. console.warn('Unable to detect UserScript plugin, falling back to native XHR.');
  29.  
  30. const xhr = new XMLHttpRequest();
  31.  
  32. xhr.open(opts.method, opts.url, true);
  33. xhr.onload = () => opts.onload({
  34. response: JSON.parse(xhr.responseText),
  35. });
  36. xhr.onerror = err => console.error('XHR Failed', err);
  37. xhr.send();
  38. }
  39.  
  40. function getButtons() {
  41. return document
  42. .getElementById("menu-container")
  43. ?.querySelector("#top-level-buttons-computed");
  44. }
  45.  
  46. function getLikeButton() {
  47. return getButtons().children[0];
  48. }
  49.  
  50. function getDislikeButton() {
  51. return getButtons().children[1];
  52. }
  53.  
  54. function isVideoLiked() {
  55. return getLikeButton().classList.contains("style-default-active");
  56. }
  57.  
  58. function isVideoDisliked() {
  59. return getDislikeButton().classList.contains("style-default-active");
  60. }
  61.  
  62. function isVideoNotLiked() {
  63. return getLikeButton().classList.contains("style-text");
  64. }
  65.  
  66. function isVideoNotDisliked() {
  67. return getDislikeButton().classList.contains("style-text");
  68. }
  69.  
  70. function getState() {
  71. if (isVideoLiked()) {
  72. return "liked";
  73. }
  74. if (isVideoDisliked()) {
  75. return "disliked";
  76. }
  77.  
  78. return "neutral";
  79. }
  80.  
  81. function setLikes(likesCount) {
  82. getButtons().children[0].querySelector("#text").innerText = likesCount;
  83. }
  84.  
  85. function setDislikes(dislikesCount) {
  86. getButtons().children[1].querySelector("#text").innerText = dislikesCount;
  87. }
  88.  
  89. function setState() {
  90. cLog('Fetching votes...');
  91.  
  92. doXHR({
  93. method: "GET",
  94. responseType: "json",
  95. url:
  96. "https://return-youtube-dislike-api.azurewebsites.net/votes?videoId=" +
  97. getVideoId(),
  98. onload: function (xhr) {
  99. if (xhr != undefined) {
  100. const { dislikes } = xhr.response;
  101.  
  102. cLog(`Received count: ${dislikes}`);
  103. setDislikes(numberFormat(dislikes));
  104. }
  105. },
  106. });
  107. }
  108.  
  109. function likeClicked() {
  110. cLog('Like clicked', getState());
  111. setState();
  112. }
  113.  
  114. function dislikeClicked() {
  115. cLog('Dislike clicked', getState());
  116. setState();
  117. }
  118.  
  119. function setInitalState() {
  120. setState();
  121. }
  122.  
  123. function getVideoId() {
  124. const urlParams = new URLSearchParams(window.location.search);
  125. const videoId = urlParams.get("v");
  126.  
  127. return videoId;
  128. }
  129.  
  130. function isVideoLoaded() {
  131. const videoId = getVideoId();
  132.  
  133. return (
  134. document.querySelector(`ytd-watch-flexy[video-id='${videoId}']`) !== null
  135. );
  136. }
  137.  
  138. function numberFormat(numberState) {
  139. const userLocales = navigator.language;
  140. const formatter = Intl.NumberFormat(userLocales, { notation: "compact" });
  141.  
  142. return formatter.format(numberState);
  143. }
  144.  
  145. function setEventListeners(evt) {
  146. function checkForJS_Finish() {
  147. if (getButtons()?.offsetParent && isVideoLoaded()) {
  148. clearInterval(jsInitChecktimer);
  149. const buttons = getButtons();
  150.  
  151. if (!window.returnDislikeButtonlistenersSet) {
  152. cLog('Registering button listeners...');
  153. buttons.children[0].addEventListener("click", likeClicked);
  154. buttons.children[1].addEventListener("click", dislikeClicked);
  155. window.returnDislikeButtonlistenersSet = true;
  156. }
  157. setInitalState();
  158. }
  159. }
  160.  
  161. if (window.location.href.indexOf("watch?") >= 0) {
  162. cLog('Setting up...');
  163. var jsInitChecktimer = setInterval(checkForJS_Finish, 111);
  164. }
  165. }
  166.  
  167. (function () {
  168. "use strict";
  169. window.addEventListener("yt-navigate-finish", setEventListeners, true);
  170. setEventListeners();
  171. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址