Greasy Fork 支持简体中文。

Youtube Hide Tool

快捷隱藏 YouTube 留言區、相關推薦、影片結尾推薦和設置選單

目前為 2023-08-23 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Youtube Hide Tool
  3. // @name:zh-TW Youtube 隱藏工具
  4. // @name:zh-CN Youtube 隐藏工具
  5. // @name:ja Youtube 非表示ツール
  6. // @name:ko 유튜브 숨기기 도구
  7. // @name:en Youtube Hide Tool
  8. // @name:de Youtube Versteckwerkzeug
  9. // @name:pt Ferramenta de Ocultação do Youtube
  10. // @name:es Herramienta de Ocultación de Youtube
  11. // @name:fr Outil de Masquage de Youtube
  12. // @name:hi यूट्यूब छुपाने का उपकरण
  13. // @name:id Alat Sembunyikan Youtube
  14. // @version 0.0.17
  15. // @author HentaiSaru
  16. // @description 快捷隱藏 YouTube 留言區、相關推薦、影片結尾推薦和設置選單
  17. // @description:zh-TW 快捷隱藏 YouTube 留言區、相關推薦、影片結尾推薦和設置選單
  18. // @description:zh-CN 快捷隐藏 YouTube 评论区、相关推荐、视频结尾推荐和设置菜单
  19. // @description:ja YouTubeのコメント欄、関連おすすめ、動画の最後のおすすめ、設定メニューを素早く非表示にする
  20. // @description:ko 빠른 YouTube 댓글 영역, 관련 추천, 비디오 끝 추천 및 설정 메뉴 숨기기
  21. // @description:en Quickly hide YouTube comments, related recommendations, video end recommendations, and settings menu
  22. // @description:de Schnell verstecken YouTube Kommentare, verwandte Empfehlungen, Video-Ende-Empfehlungen und Einstellungsmenü
  23. // @description:pt Ocultar rapidamente comentários do YouTube, recomendações relacionadas, recomendações de final de vídeo e menu de configurações
  24. // @description:es Ocultar rápidamente comentarios de YouTube, recomendaciones relacionadas, recomendaciones de final de video y menú de configuración
  25. // @description:fr Masquer rapidement les commentaires de YouTube, les recommandations connexes, les recommandations de fin de vidéo et le menu des paramètres
  26. // @description:hi यूट्यूब टिप्पणियाँ, संबंधित सिफारिशें, वीडियो के अंत की सिफारिशें और सेटिंग्स मेनू को त्वरित रूप से छुपाएं
  27. // @description:id Sembunyikan cepat komentar YouTube, rekomendasi terkait, rekomendasi akhir video, dan menu pengaturan
  28.  
  29. // @match *://www.youtube.com/*
  30. // @icon https://cdn-icons-png.flaticon.com/512/1383/1383260.png
  31.  
  32. // @license MIT
  33. // @namespace https://greasyfork.org/users/989635
  34.  
  35. // @run-at document-end
  36. // @grant GM_setValue
  37. // @grant GM_getValue
  38. // @grant GM_addStyle
  39. // @grant GM_registerMenuCommand
  40. // ==/UserScript==
  41.  
  42. (function() {
  43. const pattern = /^https:\/\/www\.youtube\.com\/.+$/;
  44. const observer = new MutationObserver(() => {
  45. var currentUrl = window.location.href;
  46. if (pattern.test(currentUrl) && !document.body.hasAttribute("data-hide")) {
  47. document.body.setAttribute("data-hide", true);
  48. let transform = false, set; RunMaim();
  49. async function RunMaim() {
  50. const VVP_Pattern = /^https:\/\/www\.youtube\.com\/watch\?v=.+$/, // 判斷在播放頁面運行
  51. Playlist_Pattern = /^https:\/\/www\.youtube\.com\/playlist\?list=.+$/, // 判斷在播放清單運行
  52. language = display_language(navigator.language),
  53. Lookup_Delay = 300;
  54. GM_addStyle(`
  55. .ytp-ce-element{opacity: 0.1!important;}
  56. .ytp-ce-element:hover{opacity: 1!important;}
  57. `);
  58. GM_registerMenuCommand(language[0], function() {alert(language[1])});
  59. async function HideJudgment(element, gm="") {
  60. if (element.style.display === "none" || transform) {
  61. element.style.display = "block";
  62. if (gm !== "") {GM_setValue(gm, false)}
  63. } else {
  64. element.style.display = "none";
  65. if (gm !== "") {GM_setValue(gm, true)}
  66. }
  67. }
  68. async function SetTrigger(element) {
  69. element.style.display = "none";
  70. return new Promise(resolve => {
  71. setTimeout(function() {
  72. if (element.style.display === "none") {resolve(true)}
  73. else {resolve(false)}
  74. }, Lookup_Delay);
  75. });
  76. }
  77. setTimeout(()=>{
  78. const [
  79. end,
  80. below,
  81. secondary,
  82. related,
  83. inner,
  84. chat,
  85. comments,
  86. menu,
  87. actions
  88. ] = [
  89. "end",
  90. "below",
  91. "secondary",
  92. "related",
  93. "secondary-inner",
  94. "chat-container",
  95. "comments",
  96. "menu-container",
  97. "actions"
  98. ].map(selector => document.getElementById(selector));
  99. document.addEventListener("keydown", function(event) {
  100. if (event.shiftKey) {
  101. event.preventDefault();
  102. let elements = document.querySelectorAll(".ytp-ce-element, .ytp-ce-covering");
  103. elements.forEach(function(element) {
  104. HideJudgment(element);
  105. });
  106. } else if (event.ctrlKey && event.key === "z") {
  107. event.preventDefault();
  108. set = GM_getValue("Minimalist", null);
  109. if (set && set != null) {
  110. end.style.display = "block";
  111. below.style.display = "block";
  112. secondary.style.display = "block";
  113. related.style.display = "block";
  114. GM_setValue("Minimalist", false);
  115. } else {
  116. end.style.display = "none";
  117. below.style.display = "none";
  118. secondary.style.display = "none";
  119. related.style.display = "none";
  120. GM_setValue("Minimalist", true);
  121. }
  122. } else if (event.altKey && event.key === "1") {
  123. event.preventDefault();
  124. let child = inner.childElementCount;
  125. if (child > 1) {// 子元素數量
  126. HideJudgment(chat, "Trigger_1");
  127. HideJudgment(secondary);
  128. HideJudgment(related);
  129. transform = false;
  130. } else {
  131. HideJudgment(chat, "Trigger_1");
  132. HideJudgment(related);
  133. transform = true;
  134. }
  135. } else if (event.altKey && event.key === "2") {
  136. event.preventDefault();
  137. HideJudgment(comments, "Trigger_2");
  138. } else if (event.altKey && event.key === "3") {
  139. event.preventDefault();
  140. HideJudgment(menu, "Trigger_3");
  141. HideJudgment(actions);
  142. } else if (event.altKey && event.key === "4") {
  143. event.preventDefault();
  144. let playlist = document.querySelector("#page-manager > ytd-browse > ytd-playlist-header-renderer > div");
  145. HideJudgment(playlist, "Trigger_4");
  146. }
  147. });
  148. }, 1500);
  149. if (VVP_Pattern.test(currentUrl)) {
  150. set = GM_getValue("Minimalist", null);
  151. if (set && set !== null) {
  152. let interval;
  153. interval = setInterval(() => {
  154. const [end, below, secondary, related] = ["end", "below", "secondary", "related"].map(selector => document.getElementById(selector));
  155. if (end && below && secondary && related) {
  156. Promise.all([SetTrigger(end), SetTrigger(below), SetTrigger(secondary), SetTrigger(related)]).then(results => {
  157. if (results[0] && results[1] && results[2] && results[3]) {
  158. clearInterval(interval); return;
  159. }
  160. });
  161. }
  162. }, Lookup_Delay);
  163. }
  164. set = GM_getValue("Trigger_1", null);
  165. if (set && set !== null){
  166. let interval;
  167. interval = setInterval(() => {
  168. const [chat, secondary, related] = ["chat-container", "secondary", "related"].map(selector => document.getElementById(selector));
  169. if (chat && secondary && related) {
  170. Promise.all([SetTrigger(chat), SetTrigger(secondary), SetTrigger(related)]).then(results => {
  171. if (results[0] && results[1]) {clearInterval(interval)}
  172. });
  173. }
  174. }, Lookup_Delay);
  175. }
  176. set = GM_getValue("Trigger_2", null);
  177. if (set && set !== null){
  178. let interval;
  179. interval = setInterval(() => {
  180. let comments = document.getElementById("comments");
  181. if (comments) {
  182. SetTrigger(comments).then(() => {clearInterval(interval)});
  183. }
  184. }, Lookup_Delay);
  185. }
  186. set = GM_getValue("Trigger_3", null);
  187. if (set && set !== null){
  188. let interval;
  189. interval = setInterval(() => {
  190. const [menu, actions] = ["menu-container", "actions"].map(selector => document.getElementById(selector));
  191. if (menu && actions) {
  192. Promise.all([SetTrigger(menu), SetTrigger(actions)]).then(results => {
  193. if (results[0] && results[1]) {clearInterval(interval)}
  194. });
  195. }
  196. }, Lookup_Delay);
  197. }
  198. } else if (Playlist_Pattern.test(currentUrl)) {
  199. set = GM_getValue("Trigger_4", null);
  200. if (set && set !== null){
  201. let interval;
  202. interval = setInterval(function() {
  203. let playlist = document.querySelector("#page-manager > ytd-browse > ytd-playlist-header-renderer > div");
  204. if (playlist) {
  205. SetTrigger(playlist).then(() => {clearInterval(interval)});
  206. }
  207. }, Lookup_Delay);
  208. }
  209. }
  210. }
  211. }
  212. });
  213. observer.observe(document.head, {childList: true, subtree: true});
  214. })();
  215.  
  216. function display_language(language) {
  217. let display = {
  218. "zh-TW": ["📜 設置快捷", `@ 功能失效時 [請重新整理] =>
  219.  
  220. (Shift) : 完全隱藏影片尾部推薦
  221. (Alt + 1) : 隱藏右側影片推薦
  222. (Alt + 2) : 隱藏留言區
  223. (Alt + 3) : 隱藏功能選項
  224. (Alt + 4) : 隱藏播放清單資訊
  225. (Ctrl + Z) : 使用極簡化`],
  226. "zh-CN": ["📜 设置快捷", `@ 功能失效时 [请重新刷新] =>
  227.  
  228. (Shift) : 全部隐藏视频尾部推荐
  229. (Alt + 1) : 隐藏右侧视频推荐
  230. (Alt + 2) : 隐藏评论区
  231. (Alt + 3) : 隐藏功能选项
  232. (Alt + 4) : 隐藏播放列表信息
  233. (Ctrl + Z) : 使用极简化`],
  234. "ja": ["📜 設定ショートカット", `@ 機能が無効になった場合 [再読み込みしてください] =>
  235.  
  236. (Shift) : 動画の最後のおすすめを完全に非表示にする
  237. (Alt + 1) : 右側の動画おすすめを非表示にする
  238. (Alt + 2) : コメント欄を非表示にする
  239. (Alt + 3) : 機能オプションを非表示にする
  240. (Alt + 4) : プレイリスト情報を非表示にする
  241. (Ctrl + Z) : 簡素化を使用する`],
  242. "en": ["📜 Settings Shortcut", `@ When function fails [Please refresh] =>
  243.  
  244. (Shift) : Fully hide video end recommendations
  245. (Alt + 1) : Hide right side video recommendations
  246. (Alt + 2) : Hide comments section
  247. (Alt + 3) : Hide function options
  248. (Alt + 4) : Hide playlist information
  249. (Ctrl + Z) : Use minimalism`],
  250. "ko": ["📜 설정 바로 가기", `@ 기능이 실패하면 [새로 고침하세요] =>
  251.  
  252. (Shift) : 비디오 추천을 완전히 숨기기
  253. (Alt + 1) : 오른쪽 비디오 추천 숨기기
  254. (Alt + 2) : 댓글 섹션 숨기기
  255. (Alt + 3) : 기능 옵션 숨기기
  256. (Alt + 4) : 재생 목록 정보 숨기기
  257. (Ctrl + Z) : 미니멀리즘 사용하기`]};
  258. return display[language] || display["en"];
  259. }