return-youtube-dislike.script.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. const LIKED_STATE = "LIKED_STATE";
  2. const DISLIKED_STATE = "DISLIKED_STATE";
  3. const NEUTRAL_STATE = "NEUTRAL_STATE";
  4. if (!storedData) {
  5. var storedData = {
  6. likes: 0,
  7. dislikes: 0,
  8. previousState: NEUTRAL_STATE
  9. };
  10. }
  11. function cLog(message, writer) {
  12. message = `[return youtube dislike]: ${message}`;
  13. if (writer) {
  14. writer(message);
  15. } else {
  16. console.log(message);
  17. }
  18. }
  19. function getButtons() {
  20. //--- If Menu Element Is Displayed: ---//
  21. if (document.getElementById("menu-container")?.offsetParent === null) {
  22. return document.querySelector("ytd-menu-renderer.ytd-watch-metadata > div");
  23. //--- If Menu Element Isnt Displayed: ---//
  24. } else {
  25. return document
  26. .getElementById("menu-container")
  27. ?.querySelector("#top-level-buttons-computed");
  28. }
  29. }
  30. function getLikeButton() {
  31. return getButtons().children[0];
  32. }
  33. function getDislikeButton() {
  34. return getButtons().children[1];
  35. }
  36. function isVideoLiked() {
  37. return getLikeButton().classList.contains("style-default-active");
  38. }
  39. function isVideoDisliked() {
  40. return getDislikeButton().classList.contains("style-default-active");
  41. }
  42. function isVideoNotLiked() {
  43. return getLikeButton().classList.contains("style-text");
  44. }
  45. function isVideoNotDisliked() {
  46. return getDislikeButton().classList.contains("style-text");
  47. }
  48. function checkForSignInButton() {
  49. if (document.querySelector('[aria-label="Sign in"]')) {
  50. return true
  51. } else {
  52. return false
  53. }
  54. }
  55. function getState() {
  56. if (isVideoLiked()) {
  57. return { current: LIKED_STATE, previous: storedData.previousState };
  58. }
  59. if (isVideoDisliked()) {
  60. return { current: DISLIKED_STATE, previous: storedData.previousState };
  61. }
  62. return { current: NEUTRAL_STATE, previous: storedData.previousState };
  63. }
  64. //--- Sets The Likes And Dislikes Values ---//
  65. function setLikes(likesCount) {
  66. getButtons().children[0].querySelector("#text").innerText = likesCount;
  67. }
  68. function setDislikes(dislikesCount) {
  69. getButtons().children[1].querySelector("#text").innerText = dislikesCount;
  70. }
  71. function setState() {
  72. let statsSet = false;
  73. browser.runtime.sendMessage(
  74. {
  75. message: "fetch_from_youtube",
  76. videoId: getVideoId(window.location.href),
  77. },
  78. function (response) {
  79. if (response != undefined) {
  80. cLog("response from youtube:");
  81. cLog(JSON.stringify(response));
  82. try {
  83. if ("likes" in response && "dislikes" in response) {
  84. const formattedDislike = numberFormat(response.dislikes);
  85. setDislikes(formattedDislike);
  86. storedData.dislikes = parseInt(response.dislikes);
  87. storedData.likes = parseInt(response.likes)
  88. createRateBar(response.likes, response.dislikes);
  89. statsSet = true;
  90. }
  91. } catch (e) {
  92. statsSet = false;
  93. }
  94. }
  95. }
  96. );
  97. browser.runtime.sendMessage(
  98. {
  99. message: "set_state",
  100. videoId: getVideoId(window.location.href),
  101. state: getState().current,
  102. },
  103. function (response) {
  104. cLog("response from api:");
  105. cLog(JSON.stringify(response));
  106. if (response != undefined && !("traceId" in response) && !statsSet) {
  107. const formattedDislike = numberFormat(response.dislikes);
  108. storedData.dislikes = response.dislikes;
  109. // setLikes(response.likes);
  110. console.log(response);
  111. setDislikes(formattedDislike);
  112. createRateBar(response.likes, response.dislikes);
  113. } else {
  114. }
  115. }
  116. );
  117. }
  118. function likeClicked() {
  119. if (checkForSignInButton() == false) {
  120. if (storedData.previousState == DISLIKED_STATE) {
  121. storedData.dislikes--;
  122. storedData.likes++;
  123. createRateBar(storedData.likes, storedData.dislikes);
  124. setDislikes(numberFormat(storedData.dislikes));
  125. storedData.previousState = LIKED_STATE;
  126. } else if (storedData.previousState == NEUTRAL_STATE) {
  127. storedData.likes++;
  128. createRateBar(storedData.likes, storedData.dislikes);
  129. storedData.previousState = LIKED_STATE;
  130. } else if (storedData.previousState = LIKED_STATE) {
  131. storedData.likes--;
  132. createRateBar(storedData.likes, storedData.dislikes)
  133. storedData.previousState = NEUTRAL_STATE;
  134. }
  135. }
  136. }
  137. function dislikeClicked() {
  138. if (checkForSignInButton() == false) {
  139. if (storedData.previousState == NEUTRAL_STATE) {
  140. storedData.dislikes++;
  141. setDislikes(numberFormat(storedData.dislikes));
  142. createRateBar(storedData.likes, storedData.dislikes);
  143. storedData.previousState = DISLIKED_STATE;
  144. } else if (storedData.previousState == DISLIKED_STATE) {
  145. storedData.dislikes--;
  146. setDislikes(numberFormat(storedData.dislikes));
  147. createRateBar(storedData.likes, storedData.dislikes);
  148. storedData.previousState = NEUTRAL_STATE;
  149. } else if (storedData.previousState == LIKED_STATE) {
  150. storedData.likes--;
  151. storedData.dislikes++;
  152. setDislikes(numberFormat(storedData.dislikes));
  153. createRateBar(storedData.likes, storedData.dislikes);
  154. storedData.previousState = DISLIKED_STATE;
  155. }
  156. }
  157. }
  158. function setInitialState() {
  159. setState();
  160. // setTimeout(() => sendVideoIds(), 1500);
  161. }
  162. function getVideoId(url) {
  163. const urlObject = new URL(url);
  164. const pathname = urlObject.pathname;
  165. if (pathname.startsWith('/clips')) {
  166. return document.querySelector("meta[itemprop='videoId']").content;
  167. } else {
  168. return urlObject.searchParams.get("v");
  169. }
  170. }
  171. function isVideoLoaded() {
  172. const videoId = getVideoId(window.location.href);
  173. return (
  174. document.querySelector(`ytd-watch-flexy[video-id='${videoId}']`) !== null
  175. );
  176. }
  177. function roundDown(num) {
  178. if (num < 1000) return num;
  179. const int = Math.floor(Math.log10(num) - 2);
  180. const decimal = int + (int % 3 ? 1 : 0);
  181. const value = Math.floor(num / 10 ** decimal);
  182. return value * 10 ** decimal;
  183. }
  184. function numberFormat(numberState) {
  185. const userLocales = navigator.language;
  186. const formatter = Intl.NumberFormat(userLocales, {
  187. notation: "compact"
  188. });
  189. return formatter.format(roundDown(numberState));
  190. }
  191. function setEventListeners(evt) {
  192. function checkForJS_Finish() {
  193. if (getButtons()?.offsetParent && isVideoLoaded()) {
  194. clearInterval(jsInitChecktimer);
  195. const buttons = getButtons();
  196. if (!window.returnDislikeButtonlistenersSet) {
  197. buttons.children[0].addEventListener("click", likeClicked);
  198. buttons.children[1].addEventListener("click", dislikeClicked);
  199. let lastKnownScrollPosition = 0;
  200. let ticking = false;
  201. // document.addEventListener('scroll', function(e) {
  202. // lastKnownScrollPosition = window.scrollY;
  203. //
  204. // if (!ticking) {
  205. // window.requestAnimationFrame(function() {
  206. // // sendVideoIds();
  207. // ticking = false;
  208. // });
  209. //
  210. // ticking = true;
  211. // }
  212. // });
  213. window.returnDislikeButtonlistenersSet = true;
  214. }
  215. setInitialState();
  216. }
  217. }
  218. if (window.location.href.indexOf("watch?") >= 0) {
  219. var jsInitChecktimer = setInterval(checkForJS_Finish, 111);
  220. }
  221. }
  222. function createRateBar(likes, dislikes) {
  223. var rateBar = document.getElementById("return-youtube-dislike-bar-container");
  224. const widthPx =
  225. getButtons().children[0].clientWidth +
  226. getButtons().children[1].clientWidth +
  227. 8;
  228. const widthPercent =
  229. likes + dislikes > 0 ? (likes / (likes + dislikes)) * 100 : 50;
  230. if (!rateBar) {
  231. (
  232. document.querySelector("#actions-inner") ||
  233. document.getElementById("menu-container")
  234. ).insertAdjacentHTML(
  235. "beforeend",
  236. `
  237. <div class="ryd-tooltip" style="width: ${widthPx}px">
  238. <div class="ryd-tooltip-bar-container">
  239. <div
  240. id="return-youtube-dislike-bar-container"
  241. style="width: 100%; height: 2px;"
  242. >
  243. <div
  244. id="return-youtube-dislike-bar"
  245. style="width: ${widthPercent}%; height: 100%"
  246. ></div>
  247. </div>
  248. </div>
  249. <tp-yt-paper-tooltip position="top" id="ryd-dislike-tooltip" class="style-scope ytd-sentiment-bar-renderer" role="tooltip" tabindex="-1">
  250. <div>
  251. <!--css-build:shady-->${likes.toLocaleString()}&nbsp;/&nbsp;${dislikes.toLocaleString()}
  252. </tp-yt-paper-tooltip>
  253. </div>
  254. `
  255. );
  256. } else {
  257. document.getElementById(
  258. "return-youtube-dislike-bar-container"
  259. ).style.width = widthPx + "px";
  260. document.getElementById("return-youtube-dislike-bar").style.width =
  261. widthPercent + "%";
  262. document.querySelector(
  263. "#ryd-dislike-tooltip > #tooltip"
  264. ).innerHTML = `${likes.toLocaleString()}&nbsp;/&nbsp;${dislikes.toLocaleString()}`;
  265. }
  266. }
  267. function sendVideoIds() {
  268. const ids = Array.from(
  269. document.getElementsByClassName(
  270. "yt-simple-endpoint ytd-compact-video-renderer"
  271. )
  272. )
  273. .concat(
  274. Array.from(
  275. document.getElementsByClassName("yt-simple-endpoint ytd-thumbnail")
  276. )
  277. )
  278. .filter((x) => x.href && x.href.indexOf("/watch?v=") > 0)
  279. .map((x) => getVideoId(x.href));
  280. browser.runtime.sendMessage({
  281. message: "send_links",
  282. videoIds: ids,
  283. });
  284. }
  285. setEventListeners();
  286. setTimeout(() => sendVideoIds(), 1500);