return-youtube-dislike.script.js 8.9 KB

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