ryd.content-script.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. import {
  2. getButtons,
  3. getLikeButton,
  4. getDislikeButton,
  5. checkForSignInButton,
  6. } from "./src/buttons";
  7. import {
  8. isMobile,
  9. isVideoDisliked,
  10. isVideoLiked,
  11. getState,
  12. setLikes,
  13. setDislikes,
  14. getLikeCountFromButton,
  15. LIKED_STATE,
  16. DISLIKED_STATE,
  17. NEUTRAL_STATE,
  18. } from "./src/state";
  19. import { numberFormat, getBrowser, cLog } from "./src/utils";
  20. let storedData = {
  21. likes: 0,
  22. dislikes: 0,
  23. previousState: NEUTRAL_STATE,
  24. };
  25. function processResponse(response) {
  26. const formattedDislike = numberFormat(response.dislikes);
  27. setDislikes(formattedDislike);
  28. storedData.dislikes = parseInt(response.dislikes);
  29. storedData.likes = getLikeCountFromButton() || parseInt(response.likes);
  30. createRateBar(storedData.likes, storedData.dislikes);
  31. }
  32. function setState() {
  33. storedData.previousState = isVideoDisliked()
  34. ? DISLIKED_STATE
  35. : isVideoLiked()
  36. ? LIKED_STATE
  37. : NEUTRAL_STATE;
  38. let statsSet = false;
  39. getBrowser().runtime.sendMessage(
  40. {
  41. message: "set_state",
  42. videoId: getVideoId(window.location.href),
  43. state: getState(storedData).current,
  44. likeCount: getLikeCountFromButton() || null,
  45. },
  46. function (response) {
  47. cLog("response from api:");
  48. cLog(JSON.stringify(response));
  49. if (response !== undefined && !("traceId" in response) && !statsSet) {
  50. processResponse(response);
  51. } else {
  52. }
  53. }
  54. );
  55. }
  56. function sendVote(vote) {
  57. getBrowser().runtime.sendMessage({
  58. message: "send_vote",
  59. vote: vote,
  60. videoId: getVideoId(window.location.href),
  61. });
  62. }
  63. function likeClicked() {
  64. if (checkForSignInButton() === false) {
  65. if (storedData.previousState === DISLIKED_STATE) {
  66. sendVote(1);
  67. storedData.dislikes--;
  68. storedData.likes++;
  69. createRateBar(storedData.likes, storedData.dislikes);
  70. setDislikes(numberFormat(storedData.dislikes));
  71. storedData.previousState = LIKED_STATE;
  72. } else if (storedData.previousState === NEUTRAL_STATE) {
  73. sendVote(1);
  74. storedData.likes++;
  75. createRateBar(storedData.likes, storedData.dislikes);
  76. storedData.previousState = LIKED_STATE;
  77. } else if ((storedData.previousState = LIKED_STATE)) {
  78. sendVote(0);
  79. storedData.likes--;
  80. createRateBar(storedData.likes, storedData.dislikes);
  81. storedData.previousState = NEUTRAL_STATE;
  82. }
  83. }
  84. }
  85. function dislikeClicked() {
  86. if (checkForSignInButton() == false) {
  87. if (storedData.previousState === NEUTRAL_STATE) {
  88. sendVote(-1);
  89. storedData.dislikes++;
  90. setDislikes(numberFormat(storedData.dislikes));
  91. createRateBar(storedData.likes, storedData.dislikes);
  92. storedData.previousState = DISLIKED_STATE;
  93. } else if (storedData.previousState === DISLIKED_STATE) {
  94. sendVote(0);
  95. storedData.dislikes--;
  96. setDislikes(numberFormat(storedData.dislikes));
  97. createRateBar(storedData.likes, storedData.dislikes);
  98. storedData.previousState = NEUTRAL_STATE;
  99. } else if (storedData.previousState === LIKED_STATE) {
  100. sendVote(-1);
  101. storedData.likes--;
  102. storedData.dislikes++;
  103. setDislikes(numberFormat(storedData.dislikes));
  104. createRateBar(storedData.likes, storedData.dislikes);
  105. storedData.previousState = DISLIKED_STATE;
  106. }
  107. }
  108. }
  109. function setInitialState() {
  110. setState();
  111. setTimeout(() => {
  112. sendVideoIds();
  113. }, 1500);
  114. }
  115. function getVideoId(url) {
  116. const urlObject = new URL(url);
  117. const pathname = urlObject.pathname;
  118. if (pathname.startsWith("/clip")) {
  119. return document.querySelector("meta[itemprop='videoId']").content;
  120. } else {
  121. return urlObject.searchParams.get("v");
  122. }
  123. }
  124. function isVideoLoaded() {
  125. const videoId = getVideoId(window.location.href);
  126. return (
  127. document.querySelector(`ytd-watch-flexy[video-id='${videoId}']`) !== null ||
  128. // mobile: no video-id attribute
  129. document.querySelector('#player[loading="false"]:not([hidden])') !== null
  130. );
  131. }
  132. let jsInitChecktimer = null;
  133. function setEventListeners(evt) {
  134. function checkForJS_Finish() {
  135. if (getButtons()?.offsetParent && isVideoLoaded()) {
  136. clearInterval(jsInitChecktimer);
  137. jsInitChecktimer = null;
  138. const buttons = getButtons();
  139. if (!window.returnDislikeButtonlistenersSet) {
  140. buttons.children[0].addEventListener("click", likeClicked);
  141. buttons.children[1].addEventListener("click", dislikeClicked);
  142. window.returnDislikeButtonlistenersSet = true;
  143. }
  144. setInitialState();
  145. }
  146. }
  147. if (window.location.href.indexOf("watch?") >= 0) {
  148. jsInitChecktimer = setInterval(checkForJS_Finish, 111);
  149. }
  150. }
  151. function createRateBar(likes, dislikes) {
  152. let rateBar = document.getElementById("ryd-bar-container");
  153. const widthPx =
  154. getButtons().children[0].clientWidth +
  155. getButtons().children[1].clientWidth +
  156. 8;
  157. const widthPercent =
  158. likes + dislikes > 0 ? (likes / (likes + dislikes)) * 100 : 50;
  159. if (!rateBar) {
  160. (
  161. document.getElementById("menu-container") ||
  162. document.querySelector("ytm-slim-video-action-bar-renderer")
  163. ).insertAdjacentHTML(
  164. "beforeend",
  165. `
  166. <div class="ryd-tooltip" style="width: ${widthPx}px">
  167. <div class="ryd-tooltip-bar-container">
  168. <div
  169. id="ryd-bar-container"
  170. style="width: 100%; height: 2px;"
  171. >
  172. <div
  173. id="ryd-bar"
  174. style="width: ${widthPercent}%; height: 100%"
  175. ></div>
  176. </div>
  177. </div>
  178. <tp-yt-paper-tooltip position="top" id="ryd-dislike-tooltip" class="style-scope ytd-sentiment-bar-renderer" role="tooltip" tabindex="-1">
  179. <!--css-build:shady-->${likes.toLocaleString()}&nbsp;/&nbsp;${dislikes.toLocaleString()}
  180. </tp-yt-paper-tooltip>
  181. </div>
  182. `
  183. );
  184. } else {
  185. document.getElementById("ryd-bar-container").style.width = widthPx + "px";
  186. document.getElementById("ryd-bar").style.width = widthPercent + "%";
  187. document.querySelector(
  188. "#ryd-dislike-tooltip > #tooltip"
  189. ).innerHTML = `${likes.toLocaleString()}&nbsp;/&nbsp;${dislikes.toLocaleString()}`;
  190. }
  191. }
  192. function sendVideoIds() {
  193. let links = Array.from(
  194. document.getElementsByClassName(
  195. "yt-simple-endpoint ytd-compact-video-renderer"
  196. )
  197. ).concat(
  198. Array.from(
  199. document.getElementsByClassName("yt-simple-endpoint ytd-thumbnail")
  200. )
  201. );
  202. // Also try mobile
  203. if (links.length < 1)
  204. links = Array.from(
  205. document.querySelectorAll(
  206. ".large-media-item-metadata > a, a.large-media-item-thumbnail-container"
  207. )
  208. );
  209. const ids = links
  210. .filter((x) => x.href && x.href.indexOf("/watch?v=") > 0)
  211. .map((x) => getVideoId(x.href));
  212. getBrowser().runtime.sendMessage({
  213. message: "send_links",
  214. videoIds: ids,
  215. });
  216. }
  217. setEventListeners();
  218. document.addEventListener("yt-navigate-finish", function (event) {
  219. if (jsInitChecktimer !== null) clearInterval(jsInitChecktimer);
  220. window.returnDislikeButtonlistenersSet = false;
  221. setEventListeners();
  222. });
  223. setTimeout(() => sendVideoIds(), 2500);