Return Youtube Dislike On Mobile

Return dislikes on youtube mobile page. Uses returnyoutubedislike.com API

当前为 2024-04-18 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Return Youtube Dislike On Mobile
  3. // @namespace https://gitlab.com/Dwyriel
  4. // @version 1.3.2
  5. // @description Return dislikes on youtube mobile page. Uses returnyoutubedislike.com API
  6. // @author Dwyriel
  7. // @license MIT
  8. // @match *://*.youtube.com/*
  9. // @grant none
  10. // @homepageURL https://gitlab.com/Dwyriel/Greasyfork-Scripts
  11. // ==/UserScript==
  12.  
  13. (function () {
  14. 'use strict';
  15. const scriptName = "[Return Youtube Dislike On Mobile]";
  16. const API_URL = "https://returnyoutubedislikeapi.com/votes?videoId=";
  17. const buttonSegmentClass = "YtSegmentedLikeDislikeButtonViewModelSegmentedButtonsWrapper";
  18. const dislikeButtonID = "dislikeButtonID_198wa16df78ms1d";
  19.  
  20. let dislikeCache = {};
  21. let oldURL = "";
  22. let videoID;
  23. let fetching = false;
  24.  
  25. const config = { attributes: true, childList: true, subtree: true };
  26. let mutationObserver = new MutationObserver(() => { });
  27.  
  28. const getVideoID = () => {
  29. return (new Proxy(new URLSearchParams(window.location.search), { get: (UrlSearchParams, key) => UrlSearchParams.get(key) })).v;
  30. }
  31.  
  32. const formatedDislikeNumber = () => {
  33. let dislikes = dislikeCache[videoID];
  34. let formattedNum = "";
  35. if (dislikes / 10E8 >= 1)
  36. formattedNum = `${Math.round(dislikes / 10E8)}B`;
  37. else if (dislikes / 10E5 >= 1)
  38. formattedNum = `${Math.round(dislikes / 10E5)}M`;
  39. else if (dislikes / 1000 >= 1) {
  40. if (dislikes < 10E3)
  41. formattedNum += `${Math.floor(dislikes / 1000)}.${Math.floor((dislikes % 1000) / 100)}K`;
  42. else
  43. formattedNum = `${Math.round(dislikes / 1000)}K`;
  44. }
  45. else
  46. formattedNum = `${dislikes}`;
  47. return formattedNum;
  48. }
  49.  
  50. const modifyDislikeButton = () => { //check explanation at the end of the file
  51. let buttons = document.getElementsByClassName(buttonSegmentClass)[0].children;
  52. if (buttons.length == 0)
  53. return;
  54. document.getElementById(dislikeButtonID)?.remove();
  55. let dislikeButton = buttons[1].children[0].children[0].children[0];
  56. dislikeButton.children[0].style = "margin: 0 6px 0 -6px";
  57. let dislikes = buttons[0].children[0].children[0].children[0].children[1].cloneNode(true);
  58. dislikes.id = dislikeButtonID;
  59. dislikeButton.appendChild(dislikes);
  60. dislikeButton.appendChild(dislikeButton.children[1]);
  61. let dislikeString = formatedDislikeNumber();
  62. dislikes.innerHTML = dislikeString;
  63. dislikeButton.style = `width: ${62 + (8 * dislikeString.length)}px !important; padding-left: 14px`;
  64. }
  65.  
  66. let hookObserver = async () => {
  67. let buttons = document.getElementsByClassName(buttonSegmentClass);
  68. if (buttons.length > 0 && buttons[0].children != undefined) {
  69. mutationObserver.disconnect();
  70. modifyDislikeButton();
  71. mutationObserver.observe(buttons[0].children[0].parentNode, config);
  72. }
  73. else
  74. await new Promise(() => setTimeout(hookObserver, 100));
  75. }
  76.  
  77. const callback = () => {
  78. let currURL = window.location.href;
  79. if (window.location.pathname != "/watch") {
  80. oldURL = currURL;
  81. return;
  82. }
  83. if (fetching || (oldURL == currURL))
  84. return;
  85. fetching = true;
  86. oldURL = currURL;
  87.  
  88. videoID = getVideoID();
  89. if (typeof videoID != 'string') {
  90. fetching = false;
  91. return;
  92. }
  93.  
  94. if (dislikeCache[videoID] != undefined) {
  95. fetching = false;
  96. hookObserver();
  97. return;
  98. }
  99.  
  100. let request = new Request(API_URL + videoID);
  101. fetch(request).then(response => response.json(), (reason) => { fetching = false; console.error("Couldn't fetch dislikes", reason) }).then(response => {
  102. console.log(`${scriptName} response from api: \n${JSON.stringify(response)}`);
  103. dislikeCache[videoID] = response.dislikes;
  104. fetching = false;
  105. hookObserver();
  106. }, (reason) => { fetching = false; console.error("Couldn't fetch dislikes", reason) });
  107. };
  108.  
  109. mutationObserver = new MutationObserver(() => {
  110. hookObserver();
  111. });
  112.  
  113. const old_pushState = history.pushState;
  114. history.pushState = function pushState() {
  115. let origFuncReturn = old_pushState.apply(this, arguments);
  116. window.dispatchEvent(new Event('historyChanged'));
  117. return origFuncReturn;
  118. };
  119.  
  120. window.addEventListener('popstate', () => window.dispatchEvent(new Event('historyChanged')));
  121. window.addEventListener('load', () => callback());
  122. window.addEventListener('historyChanged', () => {
  123. mutationObserver.disconnect();
  124. callback();
  125. });
  126. })();
  127.  
  128. /* modifyDislikeButton function explanation
  129.  
  130. let buttons = document.getElementsByClassName(buttonSegmentClass)[0].children; //get both like and dislike buttons if they exist
  131. if (buttons.length == 0)
  132. return;
  133.  
  134. document.getElementById(dislikeButtonID)?.remove(); //remove if it was already created before
  135.  
  136. let dislikeButton = buttons[1].children[0].children[0].children[0]; //the dislike "button" tag
  137. dislikeButton.children[0].style = "margin: 0 6px 0 -6px"; //fix margin to accomodate changes
  138.  
  139. let dislikes = buttons[0].children[0].children[0].children[0].children[1].cloneNode(true); //clone the text tag of the like button to be added to the dislike
  140.  
  141. dislikes.id = dislikeButtonID; //set custom ID
  142.  
  143. dislikeButton.appendChild(dislikes); //append cloned node to dislike button
  144.  
  145. dislikeButton.appendChild(dislikeButton.children[1]); //move nodes around to be in the same order as the like button
  146.  
  147. let dislikeString = formatedDislikeNumber(); //formats and adds the formated string to the cloned node's inner HTML
  148. dislikes.innerHTML = dislikeString;
  149.  
  150. dislikeButton.style = `width: ${56 + (8 * dislikeString.length)}px`; //adjust button width based on formated string
  151. */