Block Youtube Users

Hide videos of blacklisted users/channels and comments

  1. // ==UserScript==
  2. // @name Block Youtube Users
  3. // @namespace https://codeberg.org/schegge
  4. // @description Hide videos of blacklisted users/channels and comments
  5. // @version 2.5.3.3
  6. // @author Schegge
  7. // @match https://www.youtube.com/*
  8. // @exclude *://*.youtube.com/embed/*
  9. // @exclude *://*.youtube.com/live_chat*
  10. // @run-at document-end
  11. // @grant GM_getValue
  12. // @grant GM_setValue
  13. // @grant GM.getValue
  14. // @grant GM.setValue
  15. // @require https://code.jquery.com/jquery-4.0.0-beta.js
  16. // ==/UserScript==
  17.  
  18. // fix trusted-types https://github.com/Tampermonkey/tampermonkey/issues/1334#issuecomment-2556498540
  19. window.testTrusted = function() {
  20. if (typeof window != "undefined" &&
  21. ('trustedTypes' in window) &&
  22. ('createPolicy' in window.trustedTypes) &&
  23. (typeof window.trustedTypes.createPolicy == "function")) {
  24. window.trustedTypes.createPolicy('default', {createScriptURL: s => s, createScript: s => s, createHTML: s => s})
  25. } else {
  26. setTimeout(window.testTrusted, 1000);
  27. }
  28. }
  29. window.testTrusted();
  30.  
  31. // gm4 polyfill https://github.com/greasemonkey/gm4-polyfill
  32. if (typeof GM == 'undefined') {
  33. this.GM = {};
  34. Object.entries({
  35. 'GM_getValue': 'getValue',
  36. 'GM_setValue': 'setValue'
  37. }).forEach(([oldKey, newKey]) => {
  38. let old = this[oldKey];
  39. if (old && (typeof GM[newKey] == 'undefined')) {
  40. GM[newKey] = function(...args) {
  41. return new Promise((resolve, reject) => { try { resolve(old.apply(this, args)); } catch (e) { reject(e); } });
  42. };
  43. }
  44. });
  45. }
  46.  
  47. (async function($) {
  48. /* VALUES */
  49.  
  50. const DEBUGGING = false;
  51.  
  52. const Values = {
  53. storageVer: '1',
  54. storageSep: ',',
  55. storageTimer: 1000,
  56. storageComment: '',
  57. storageVideo: '',
  58. storageAdd: '',
  59. storageBlacklist: [],
  60. storageWhitelist: [],
  61. menuOpen: false,
  62. menuPause: false
  63. };
  64.  
  65. // get saved values
  66. Values.storageVer = await GM.getValue('byuver', '1');
  67. Values.storageSep = await GM.getValue('sep', ',');
  68. Values.storageTimer = await GM.getValue('timer', 1000);
  69. Values.storageComment = await GM.getValue('hidecomments', '');
  70. Values.storageVideo = await GM.getValue('enablepause', '');
  71. Values.storageAdd = await GM.getValue('enableadd', '');
  72. Values.storageBlacklist = getArray(await GM.getValue('savedblocks', ''));
  73. Values.storageWhitelist = getArray(await GM.getValue('savedwhites', ''));
  74.  
  75. if (DEBUGGING) {
  76. console.log('BYU- current blacklist:', Values.storageBlacklist);
  77. console.log('BYU- current whitelist:', Values.storageWhitelist);
  78. }
  79.  
  80. // get array from string
  81. function getArray(string) {
  82. if (!string) return [];
  83. return string.split(Values.storageSep).map(v => v.trim()).filter(v => v.length);
  84. }
  85.  
  86. const Where = {
  87. // home, related and page playlist: #metadata #text.ytd-channel-name
  88. // search video: #channel-info #text.ytd-channel-name
  89. // search channel: #channel-title.ytd-channel-renderer span.ytd-channel-renderer, #info #text.ytd-channel-name, #metadata #subscribers.ytd-channel-renderer
  90. // video playlist: #byline.ytd-playlist-panel-video-renderer
  91. // user video: #meta #upload-info #channel-name #text.ytd-channel-name, #owner #upload-info #channel-name #text.ytd-channel-name
  92. // comment: #author-text span.ytd-comment-view-model, #name #text.ytd-channel-name
  93. user: `#metadata #text.ytd-channel-name,
  94. #channel-info #text.ytd-channel-name,
  95. #channel-title.ytd-channel-renderer span.ytd-channel-renderer,
  96. #info #text.ytd-channel-name,
  97. #metadata #subscribers.ytd-channel-renderer,
  98. #byline.ytd-playlist-panel-video-renderer,
  99. #meta #upload-info #channel-name #text.ytd-channel-name,
  100. #owner #upload-info #channel-name #text.ytd-channel-name
  101. ${Values.storageComment ? ', #author-text span.ytd-comment-view-model, #name #text.ytd-channel-name' : ''}`,
  102.  
  103. renderer: `ytd-rich-item-renderer,
  104. ytd-video-renderer,
  105. ytd-channel-renderer,
  106. ytd-playlist-renderer,
  107. ytd-playlist-video-renderer,
  108. ytd-playlist-panel-video-renderer,
  109. ytd-movie-renderer,
  110. ytd-compact-video-renderer,
  111. ytd-compact-movie-renderer,
  112. ytd-compact-radio-renderer,
  113. ytd-compact-autoplay-renderer,
  114. ytd-compact-playlist-renderer,
  115. ytd-grid-video-renderer,
  116. ytd-grid-playlist-renderer,
  117. ytd-secondary-search-container-renderer
  118. ${Values.storageComment ? ', ytd-comment-view-model.ytd-comment-replies-renderer, ytd-comment-view-model.ytd-comment-thread-renderer' : ''}`,
  119.  
  120. userVideo: '#owner #upload-info #channel-name #text.ytd-channel-name'
  121. };
  122.  
  123. /* INTERVAL FOR BLACKLISTING */
  124.  
  125. search();
  126. setInterval(search, Values.storageTimer);
  127.  
  128. /* CSS */
  129.  
  130. $('head').append(`<style>
  131. #byu-is-black { display: none!important; }
  132. .byu-add { font-size: .8em; margin-right: .5em; cursor: pointer; color: var(--yt-brand-youtube-red, red); font-family: consolas, monospace; float: left; }
  133. #byu-icon { display: inline-block; position: relative; text-align: center; width: 40px; height: 24px; margin: 0 8px; font-weight: 100; }
  134. #byu-icon span { color: var(--yt-spec-icon-active-other); cursor: pointer; font-size: 20px; vertical-align: middle; }
  135. #byu-options { width: 30%; max-width: 250px; display: flex; flex-flow: row wrap; align-items: baseline; position: fixed; right: 10px; padding: 15px; text-align: center; color: var(--yt-spec-text-primary); background-color: var(--yt-spec-base-background); border: 1px solid var(--yt-spec-10-percent-layer); z-index: 99999; }
  136. #byu-options div { width: 50%; flex-grow: 1; box-sizing: border-box; padding: 5px; }
  137. #byu-save { font-size: 1.5em!important; font-weight: bold; cursor: pointer; color: var(--yt-brand-youtube-red, red); }
  138. #byu-pause { cursor: pointer; }
  139. #byu-options .byu-textarea { width: 100%; }
  140. #byu-options .byu-textarea span { font-size: 1.2em; width: 100%; text-align: center; font-weight: bold; }
  141. #byu-options .byu-textarea textarea { font-size: 1em; line-height: 1em; resize: vertical; width: 100%; padding: 4px; color: var(--yt-spec-text-primary); background-color: var(--yt-spec-badge-chip-background); box-sizing: border-box; border: 0; border-radius: 1em; }
  142. #byu-options .byu-textarea textarea#byu-blacklist { min-height: 6em; }
  143. #byu-options .byu-textarea textarea#byu-whiteklist { min-height: 4em; }
  144. #byu-options .byu-opt { text-align: right; padding-right: 2em; }
  145. #byu-options .byu-opt input { color: var(--yt-spec-text-primary); background-color: var(--yt-spec-badge-chip-background); border: 0; padding: 0 2px; height: 1.6em; line-height: 1em; vertical-align: middle; box-sizing: border-box; margin: 0; border-radius: .5em; }
  146. #byu-sep { width: 1em; }
  147. #byu-timer { width: 5em; }
  148. #byu-video-page-black { position: fixed; z-index: 99999; bottom: 2em; left: 2em; width: 20%; min-width: 10em; font-size: 1.5em; padding: 1em; background: var(--yt-brand-youtube-red, red); color: #fff; border-radius: .5em; }
  149. #byu-notice { position: fixed; z-index: 99999; bottom: 2em; right: 2em; width: 30%; min-width: 10em; font-size: 1.2em; padding: 1.5em; color: var(--yt-brand-youtube-red, red); background: #fff; border-radius: .5em; border: 1px solid var(--yt-brand-youtube-red, red); }
  150. #byu-notice-close { cursor: pointer; background: var(--yt-brand-youtube-red, red); color: #fff; border-radius: .5em; padding: 0 .5em; }
  151. </style>`);
  152.  
  153. /* VIDEO FIRST PAGE */
  154.  
  155. if (Values.storageVideo && /\/watch/.test(window.location.href)) {
  156. let waitUserVideo = setInterval(() => {
  157. if ($(Where.userVideo).length) {
  158. clearInterval(waitUserVideo);
  159.  
  160. let username = $(Where.userVideo).text().trim();
  161. if (ifMatch(username.toLowerCase())) {
  162. let video = $('#player video.video-stream.html5-main-video');
  163. video.get(0).pause();
  164. video.get(0).currentTime = 0;
  165. let pausing = setInterval(() => {
  166. if (!video.get(0).paused) {
  167. video.get(0).pause();
  168. video.get(0).currentTime = 0;
  169. }
  170. }, 500);
  171. $('body').append($(`<div id="byu-video-page-black">${username} is blacklisted</div>`));
  172. $('body').on('click', '.html5-main-video, .html5-video-player, .ytp-play-button, #secondary',
  173. () => clearInterval(pausing));
  174. setTimeout(() => {
  175. $('#byu-video-page-black').remove();
  176. clearInterval(pausing);
  177. }, 10000);
  178. }
  179. }
  180. }, 1000);
  181. }
  182.  
  183. /* BLACKLIST MENU */
  184.  
  185. $('body').append(`<div id="byu-options" style="display: none;">
  186. <div><span id="byu-save">save</span></div>
  187. <div><span id="byu-pause">pause</span></div>
  188. <div class="byu-textarea"><span>blacklist</span>
  189. <textarea spellcheck="false" id="byu-blacklist">${
  190. Values.storageBlacklist.join(`${Values.storageSep} `)
  191. }</textarea></div>
  192. <div class="byu-textarea"><span>whitelist</span>
  193. <textarea spellcheck="false" id="byu-whitelist">${
  194. Values.storageWhitelist.join(`${Values.storageSep} `)
  195. }</textarea></div>
  196. <div class="byu-opt" title="between usernames">separator <input id="byu-sep" type="text" maxlength="1" value="${
  197. Values.storageSep
  198. }"></div>
  199. <div class="byu-opt" title="hide comments">comments
  200. <input id="byu-hidecomments" type="checkbox" value="comments" ${
  201. Values.storageComment ? 'checked' : ''
  202. }></div>
  203. <div class="byu-opt" title="interval between new checks">timer
  204. <input id="byu-timer" type="number" min="500" max="5000" step="500" title="in milliseconds" value="${
  205. Values.storageTimer
  206. }"></div>
  207. <div class="byu-opt" title="if user blacklisted">pause video
  208. <input id="byu-enablepause" type="checkbox" value="pausevideo" ${
  209. Values.storageVideo ? 'checked' : ''
  210. }></div>
  211. <div class="byu-opt" title="always show [x]">right click add
  212. <input id="byu-enableadd" type="checkbox" value="clickadd" ${
  213. Values.storageAdd ? 'checked' : ''
  214. }></div>
  215. </div>`);
  216.  
  217. // for the B wait till the masthead buttons are added
  218. let buttonB = $('<div id="byu-icon"><span>B</span></div>');
  219.  
  220. let waitButton = setInterval(() => {
  221. if ($('#buttons').length) {
  222. clearInterval(waitButton);
  223. $('#buttons').before(buttonB);
  224. $('head').append(`<style>#byu-options { top:${
  225. $('#container.ytd-masthead').height()
  226. }px; }</style>`);
  227. }
  228. }, 1000);
  229.  
  230. /* NEW VERSION NOTIFICATION */
  231.  
  232. if (Values.storageVer !== '2.5.3.3') {
  233. Values.storageVer = '2.5.3.3';
  234. GM.setValue('byuver', Values.storageVer);
  235. /* $('body').append(`<div id="byu-notice">BLOCK YOUTUBE USERS [${Values.storageVer}]<br><br>--
  236. <br><br><span id="byu-notice-close">close</span></div>`);
  237. $('#byu-notice-close').on('click', () => $('#byu-notice').remove()); */
  238. }
  239.  
  240. /* BLACKLISTING FUNCTIONS */
  241.  
  242. // global search
  243. function search(newAdd = false) {
  244. $(Where.user).each(function() {
  245. findMatch($(this), newAdd);
  246. });
  247. }
  248.  
  249. // do the thing
  250. function findMatch(user, newAdd) {
  251. // retrieve current username
  252. let username = user.text().trim().toLowerCase();
  253. if (!username) return;
  254.  
  255. // add [x] when menu is open or always add selected
  256. if ((Values.menuOpen || Values.storageAdd) && !user.siblings('.byu-add').length) {
  257. $('<div class="byu-add">[x]</div>').insertBefore(user);
  258. }
  259.  
  260. // if blacklist is paused do nothing
  261. if (Values.menuPause) return;
  262.  
  263. // if content or blacklist are changed
  264. if (user.data('username') !== username || newAdd) {
  265. user.data('username', username);
  266.  
  267. // hide if match
  268. if (ifMatch(username)) {
  269. user.closest(Where.renderer).attr('id', 'byu-is-black');
  270.  
  271. if (DEBUGGING) {
  272. console.log('BYU- MATCHED USER', user, user.closest(Where.renderer));
  273. }
  274.  
  275. user.data('black', 'yes');
  276. // show if it was hidden with another username or deleted username from blacklist
  277. } else if (user.data('black')) {
  278. user.closest(Where.renderer).removeAttr('id');
  279. user.data('black', '');
  280. }
  281. }
  282. }
  283.  
  284. // check if it needs to be blacklisted
  285. function ifMatch(u) {
  286. return (
  287. !Values.storageWhitelist.some(w => u === w.toLowerCase()) &&
  288. Values.storageBlacklist.some(b => {
  289. b = b.toLowerCase();
  290. if (b.startsWith('*')) {
  291. b = b.replace('*', '');
  292. return b && u.includes(b);
  293. } else {
  294. return u === b;
  295. }
  296. })
  297. );
  298. }
  299.  
  300. /* EVENT LISTENERS */
  301.  
  302. // open/close options
  303. $(buttonB).on('click', openMenu);
  304. $(document).bind('keydown', function(e) {
  305. if (e.ctrlKey && e.altKey && e.key == 'b') {
  306. openMenu();
  307. }
  308. });
  309.  
  310. function openMenu() {
  311. $('#byu-options').slideToggle();
  312. $(buttonB).css('font-weight', $(buttonB).css('font-weight') === '500' ? '' : '500');
  313.  
  314. Values.menuOpen = !Values.menuOpen;
  315. if (Values.storageAdd) return;
  316.  
  317. if (Values.menuOpen) {
  318. search();
  319. } else {
  320. $('.byu-add').remove();
  321. }
  322. }
  323.  
  324. // save changes
  325. $('#byu-save').on('click', function() {
  326. if (/[*"]|^$/.test($('#byu-sep').val())) {
  327. $(this).text('ERROR! separator');
  328. } else {
  329. Values.storageSep = $('#byu-sep').val();
  330. Values.storageTimer = Math.max(parseInt($('#byu-timer').val(), 10), 500) || 1000;
  331. Values.storageComment = $('#byu-hidecomments').is(':checked') ? 'yes' : '';
  332. Values.storageVideo = $('#byu-enablepause').is(':checked') ? 'yes' : '';
  333. Values.storageAdd = $('#byu-enableadd').is(':checked') ? 'yes' : '';
  334. Values.storageBlacklist = getArray($('#byu-blacklist').val().trim());
  335. Values.storageWhitelist = getArray($('#byu-whitelist').val().trim());
  336. GM.setValue('sep', Values.storageSep);
  337. GM.setValue('timer', Values.storageTimer);
  338. GM.setValue('hidecomments', Values.storageComment);
  339. GM.setValue('enablepause', Values.storageVideo);
  340. GM.setValue('enableadd', Values.storageAdd);
  341. GM.setValue('savedblocks', Values.storageBlacklist.join(`${Values.storageSep} `));
  342. GM.setValue('savedwhites', Values.storageWhitelist.join(`${Values.storageSep} `));
  343. $(this).text('saved');
  344. search(true);
  345. }
  346. setTimeout(() => $(this).text('save'), 2000);
  347. });
  348.  
  349. // pause
  350. $('#byu-pause').on('click', function() {
  351. Values.menuPause = !Values.menuPause;
  352. if (Values.menuPause) {
  353. $('[id="byu-is-black"]').removeAttr('id');
  354. $(this).text('paused');
  355. } else {
  356. search(true);
  357. $(this).text('pause');
  358. }
  359. });
  360.  
  361. // add usernames to blacklist
  362. $(document).on('click contextmenu', '.byu-add', function(e) {
  363. e.preventDefault();
  364. e.stopPropagation();
  365.  
  366. let username = $(this).next().text().trim().toLowerCase();
  367.  
  368. if (DEBUGGING) {
  369. console.log('BYU- YOU HAVE RIGHT-CLICKED ON [X]');
  370. console.log('BYU- current # blacklist:', Values.storageBlacklist.length);
  371. console.log('BYU- element:', $(this));
  372. console.log('BYU- username:', username);
  373. console.log('BYU- username already in the blacklist?', Values.storageBlacklist.includes(username));
  374. }
  375.  
  376. if (!Values.storageBlacklist.includes(username)) {
  377. Values.storageBlacklist.push(username);
  378. let blacks = Values.storageBlacklist.join(`${Values.storageSep} `);
  379. $('#byu-blacklist').val(blacks);
  380. GM.setValue('savedblocks', blacks);
  381. search(true);
  382. }
  383. });
  384.  
  385. })(jQuery);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址