Watch9 Reconstruct

Restores the old watch layout from before 2019

目前为 2022-09-14 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Watch9 Reconstruct
  3. // @version 2.0.0
  4. // @description Restores the old watch layout from before 2019
  5. // @author Aubrey P.
  6. // @icon https://www.youtube.com/favicon.ico
  7. // @namespace aubymori
  8. // @license Unlicense
  9. // @match www.youtube.com/*
  10. // @grant none
  11. // @run-at document-start
  12. // ==/UserScript==
  13.  
  14. const w9rOptions = {
  15. oldAutoplay: true,
  16. removeBloatButtons: true
  17. }
  18.  
  19. /**
  20. * Internationalization strings.
  21. */
  22. const w9ri18n = {
  23. en: {
  24. subSuffixMatch: /( subscribers)|( subscriber)/, // Regex for isolating subscriber count
  25. subCntZero: "No", // When the author has 0 subscribers
  26. nonPublishMatch: /(Premier)|(Stream)|(Start)/, // Match to determine if a video was normally uploaded
  27. publishedOn: "Published on %s", // Self explanatory
  28. upNext: "Up next",
  29. autoplay: "Autoplay",
  30. autoplayTip: "When autoplay is enabled, a suggested video will automatically play next."
  31. }
  32. };
  33.  
  34. /**
  35. * Stub for autoplay renderer.
  36. * (CURRENTLY UNUSED)
  37. */
  38. const autoplayStub = `
  39. <ytd-compact-autoplay-renderer class="style-scope ytd-watch-next-secondary-results-renderer">
  40. <div id="head" class="style-scope ytd-compact-autoplay-renderer">
  41. <div id="upnext" class="style-scope ytd-compact-autoplay-renderer"></div>
  42. <div id="autoplay" class="style-scope ytd-compact-autoplay-renderer"></div>
  43. <tp-yt-paper-toggle-button id="toggle" noink="" class="style-scope ytd-compact-autoplay-renderer" role="button" aria-pressed="" tabindex="0" style="touch-action: pan-y;" toggles="" aria-disabled="false" aria-label=""></tp-yt-paper-toggle-button>
  44. <tp-yt-paper-tooltip id="tooltip for="toggle" class="style-scope ytd-compact-autoplay-renderer" role="tooltip" tabindex="-1"></tp-yt-paper-tooltip>
  45. </div>
  46. <div id="contents" class="style-scope ytd-compact-autoplay-renderer"></div>
  47. </ytd-compact-autoplay-renderer>
  48. `;
  49.  
  50. /**
  51. * Get a string from the internationalization strings.
  52. *
  53. * @param {string} string Name of string to get
  54. * @param {string} hl Language to use.
  55. * @returns {string}
  56. */
  57. function getString(string, hl = "en") {
  58. if (string == null) return "ERROR";
  59. return w9ri18n[hl][string];
  60. }
  61.  
  62. /**
  63. * Format upload date string to include "Published on" if applicable.
  64. *
  65. * @param {string} dateStr dateText from InnerTube ("Sep 13, 2022", "Premiered 2 hours ago", etc.)
  66. * @param {string} hl Language to use.
  67. * @returns
  68. */
  69. function formatUploadDate(dateStr, hl = "en") {
  70. var nonPublishMatch = getString("nonPublishMatch", hl);
  71. var publishedOn = getString("publishedOn", hl);
  72. if (nonPublishMatch.test(dateStr)) {
  73. return dateStr;
  74. } else {
  75. return publishedOn.replace("%s", dateStr);
  76. }
  77. }
  78.  
  79. /**
  80. * Format subscriber count string to only include count.
  81. *
  82. * @param {string} count Subscriber count string from InnerTube ("374K subscribers", "No subscribers", etc.)
  83. * @param {string} hl Language to use.
  84. * @returns
  85. */
  86. function formatSubCount(count, hl = "en") {
  87. if (count == null) return "";
  88. var tmp = count.replace(getString("subSuffixMatch", hl), "");
  89. tmp = tmp.replace(getString("subCntZero", hl), "0");
  90. return tmp;
  91. }
  92.  
  93. /**
  94. * Toggle autoplay.
  95. *
  96. * @returns {void}
  97. */
  98. function clickAutoplay() {
  99. var player = document.querySelector("#movie_player");
  100. var autoplay;
  101. if (autoplay = player.querySelector(".ytp-autonav-toggle-button-container")) {
  102. autoplay.parentNode.click();
  103. } else {
  104. var settings = player.querySelector('.ytp-settings-button');
  105. settings.click();settings.click();
  106. var item = player.querySelector('.ytp-menuitem[role="menuitemcheckbox"]');
  107. item.click();
  108. }
  109. }
  110.  
  111. /**
  112. * Should the Autoplay renderer be inserted?
  113. * (Basically, if there's a playlist active)
  114. *
  115. * @returns {boolean}
  116. */
  117. function shouldHaveAutoplay() {
  118. var playlist;
  119. if (playlist = document.querySelector("#playlist.ytd-watch-flexy")) {
  120. if (playlist.hidden && playlist.hidden == true) {
  121. return true;
  122. } else {
  123. return false;
  124. }
  125. } else {
  126. return true;
  127. }
  128. }
  129.  
  130. function removeBloatButtons() {
  131. var watchFlexy = document.querySelector("ytd-watch-flexy");
  132. var primaryInfo = watchFlexy.querySelector("ytd-video-primary-info-renderer");
  133. var actionBtns = primaryInfo.querySelector("ytd-menu-renderer.ytd-video-primary-info-renderer .top-level-buttons");
  134. // I have no idea why they made this a seperate element
  135. // type but go off I guess, Google
  136. var dlBtn;
  137. if (dlBtn = actionBtns.querySelector("ytd-download-button-renderer")) {
  138. dlBtn.remove();
  139. }
  140.  
  141. var abList = actionBtns.querySelectorAll("ytd-button-renderer");
  142. for (var i = 0; i < abList.length; i++) {
  143. var iconType;
  144. if (iconType = abList[i].data.icon.iconType) {
  145. console.log(iconType);
  146. if (iconType == "MONEY_HEART" || iconType == "CONTENT_CUT") {
  147. abList[i].remove();
  148. }
  149. }
  150. }
  151. }
  152.  
  153. /**
  154. * Build new Watch9 elements and tweak currently existing elements accordingly.
  155. *
  156. * @return {void}
  157. */
  158. function buildWatch9() {
  159. const watchFlexy = document.querySelector("ytd-watch-flexy");
  160. const primaryInfo = watchFlexy.querySelector("ytd-video-primary-info-renderer");
  161. const secondaryInfo = watchFlexy.querySelector("ytd-video-secondary-info-renderer");
  162. const viewCount = primaryInfo.querySelector("ytd-video-view-count-renderer");
  163. const subBtn = secondaryInfo.querySelector("#subscribe-button tp-yt-paper-button");
  164. const uploadDate = secondaryInfo.querySelector(".date.ytd-video-secondary-info-renderer"); // Old unused element that we inject the date into
  165. const language = yt.config_.HL;
  166.  
  167. // Let script know we've done this initial build
  168. watchFlexy.setAttribute("watch9-built", "");
  169.  
  170. // Make view count large like in Watch9
  171. viewCount.removeAttribute("small");
  172.  
  173. // Publish date
  174. var newUploadDate = formatUploadDate(primaryInfo.data.dateText.simpleText, language);
  175. uploadDate.innerText = newUploadDate;
  176.  
  177. // Sub count
  178. var newSubCount = formatSubCount(secondaryInfo.data.owner.videoOwnerRenderer.subscriberCountText.simpleText);
  179. var w9rSubCount = document.createElement("yt-formatted-string");
  180. w9rSubCount.classList.add("style-scope", "deemphasize");
  181. w9rSubCount.text = {
  182. simpleText: newSubCount
  183. };
  184. subBtn.insertAdjacentElement("beforeend", w9rSubCount);
  185.  
  186. // Bloat buttons
  187. removeBloatButtons();
  188. }
  189.  
  190. /**
  191. * Update currently existing Watch9 elements.
  192. *
  193. * @return {void}
  194. */
  195. function updateWatch9() {
  196. const watchFlexy = document.querySelector("ytd-watch-flexy");
  197. const primaryInfo = watchFlexy.querySelector("ytd-video-primary-info-renderer");
  198. const secondaryInfo = watchFlexy.querySelector("ytd-video-secondary-info-renderer");
  199. const subCnt = secondaryInfo.querySelector("yt-formatted-string.deemphasize");
  200. const uploadDate = secondaryInfo.querySelector(".date.ytd-video-secondary-info-renderer");
  201. const language = yt.config_.HL;
  202.  
  203. // Publish date
  204. var newUploadDate = formatUploadDate(primaryInfo.data.dateText.simpleText, language);
  205. uploadDate.innerText = newUploadDate;
  206.  
  207. // Sub count
  208. var newSubCount = formatSubCount(secondaryInfo.data.owner.videoOwnerRenderer.subscriberCountText.simpleText, language);
  209. subCnt.text = {
  210. simpleText: newSubCount
  211. };
  212.  
  213. // Bloat buttons
  214. removeBloatButtons();
  215. }
  216.  
  217. /**
  218. * Run the Watch9 build/update functions.
  219. */
  220. document.addEventListener("yt-page-data-updated", (e) => {
  221. if (e.detail.pageType == "watch") {
  222. if (document.querySelector("ytd-watch-flexy").getAttribute("watch9-built") != null) {
  223. updateWatch9();
  224. } else {
  225. buildWatch9();
  226. }
  227. }
  228. });
  229.  
  230. /**
  231. * Inject styles.
  232. */
  233. document.addEventListener("DOMContentLoaded", function tmp() {
  234. document.head.insertAdjacentHTML("beforeend", `
  235. <style>
  236. /* Hide Watch11 */
  237. ytd-watch-metadata {
  238. display: none !important;
  239. }
  240.  
  241. /* Force Watch10 to display */
  242. #meta-contents[hidden],
  243. #info-contents[hidden] {
  244. display: block !important;
  245. }
  246.  
  247. yt-formatted-string.deemphasize {
  248. opacity: .85;
  249. margin-left: 6px;
  250. }
  251.  
  252. yt-formatted-string.deemphasize:empty {
  253. margin-left: 0;
  254. }
  255.  
  256. /**
  257. * Prevent sub count from appearing on the "Edit video" button since
  258. * it uses the same element as subscribe button
  259. */
  260. ytd-button-renderer.style-primary yt-formatted-string.deemphasize {
  261. display: none;
  262. }
  263.  
  264. #info-strings.ytd-video-primary-info-renderer,
  265. #owner-sub-count.ytd-video-owner-renderer {
  266. display: none !important;
  267. }
  268. </style>
  269. `);
  270. document.removeEventListener("DOMContentLoaded", tmp);
  271. });