Last active
August 16, 2025 13:37
-
-
Save kphrx/eb4290150bc7556af95eac2c89965cbe to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name YouTube block user comment | |
| // @namespace https://kpherox.dev | |
| // @version 1.2.1 | |
| // @downloadURL https://gist.github.com/kphrx/eb4290150bc7556af95eac2c89965cbe/raw/youtube-comment-block.user.js | |
| // @updateURL https://gist.github.com/kphrx/eb4290150bc7556af95eac2c89965cbe/raw/youtube-comment-block.meta.js | |
| // @author kPherox | |
| // @description block user comment | |
| // @noframes | |
| // ==/UserScript== |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name YouTube block user comment | |
| // @namespace https://kpherox.dev | |
| // @match https://www.youtube.com/* | |
| // @grant GM.addStyle | |
| // @grant GM_addStyle | |
| // @grant GM_getValue | |
| // @grant GM_getValues | |
| // @grant GM_setValue | |
| // @grant GM_listValues | |
| // @grant GM_deleteValue | |
| // @version 1.2.1 | |
| // @downloadURL https://gist.github.com/kphrx/eb4290150bc7556af95eac2c89965cbe/raw/youtube-comment-block.user.js | |
| // @updateURL https://gist.github.com/kphrx/eb4290150bc7556af95eac2c89965cbe/raw/youtube-comment-block.meta.js | |
| // @author kPherox | |
| // @description block user comment | |
| // @noframes | |
| // ==/UserScript== | |
| const config = new class { | |
| #values; | |
| blockedList; | |
| constructor() { | |
| this.#values = GM_listValues().filter((key) => { | |
| return key.startsWith('/channel/') || key === 'blocked'; | |
| }); | |
| this.blockedList = GM_getValues(this.#values); | |
| this.#migrate(); | |
| Promise.all(Object.entries(this.blockedList).map(([channelUrl, handle]) => { | |
| return this.#addStyle({channelUrl, handle}) | |
| })).then(console.debug); | |
| } | |
| get #requireMigrate() { | |
| return this.#values.includes("blocked"); | |
| } | |
| #migrate() { | |
| if (this.#requireMigrate) { | |
| for (const blocked of (this.blockedList['blocked'] ?? [])) { | |
| this.blockedList[blocked.channelUrl] = blocked.handle; | |
| GM_setValue(blocked.channelUrl, blocked.handle); | |
| } | |
| delete this.blockedList['blocked']; | |
| GM_deleteValue('blocked'); | |
| } | |
| } | |
| #addStyle({channelUrl, handle}) { | |
| return GM.addStyle(`ytd-comment-thread-renderer:has(> #comment-container > ytd-comment-view-model > #body > div#author-thumbnail > button#author-thumbnail-button[aria-label="${handle}"]), | |
| ytd-comment-replies-renderer ytd-comment-view-model:has( | |
| > #body > #author-thumbnail > #author-thumbnail-button[aria-label="${handle}"], | |
| > #body > #main > #expander > #content > #content-text a.yt-core-attributed-string__link[href="${channelUrl}"] | |
| ) { | |
| display: none; | |
| }`); | |
| } | |
| block({channelUrl, handle}) { | |
| this.blockedList[channelUrl] = handle; | |
| GM_setValue(channelUrl, handle); | |
| return this.#addStyle({channelUrl, handle}); | |
| } | |
| }; | |
| const blockUserFn = (handle, channelUrl) => ((ev) => { | |
| config.block({handle, channelUrl}); | |
| }); | |
| const addBlockButton = (profileCardView) => { | |
| if (profileCardView == null) { | |
| return; | |
| } | |
| const profileIdentityInfo = profileCardView.rawProps.data().profileIdentityInfo.profileIdentityInfoViewModel; | |
| const channelBannerContainer = profileCardView.querySelector('.yt-profile-identity-info-view-model-wiz__channel-banner-container'); | |
| const wrapButton = channelBannerContainer.appendChild(document.createElement('div')); | |
| wrapButton.classList.add('yt-profile-identity-info-view-model-wiz__wrap-button'); | |
| wrapButton.style.paddingLeft = '16px'; | |
| const button = wrapButton.appendChild(document.createElement('div')); | |
| button.classList.add('yt-profile-identity-info-view-model-wiz__button'); | |
| const buttonViewModel = button.appendChild(document.createElement('div')); | |
| buttonViewModel.classList.add('yt-spec-button-view-model'); | |
| const buttonShape = buttonViewModel.appendChild(document.createElement('a')); | |
| buttonShape.classList.add('yt-spec-button-shape-next', 'yt-spec-button-shape-next--tonal', 'yt-spec-button-shape-next--mono', 'yt-spec-button-shape-next--size-m'); | |
| const buttonText = buttonShape.appendChild(document.createElement('div')); | |
| buttonText.classList.add('yt-spec-button-shape-next__button-text-content'); | |
| buttonText.textContent = 'Block'; | |
| const listener = blockUserFn(profileIdentityInfo.channelHandle, profileIdentityInfo.channelAccess.buttonViewModel.onTap.innertubeCommand.commandMetadata.webCommandMetadata.url); | |
| buttonShape.addEventListener('click', listener); | |
| }; | |
| const watchMultiPageMenu = new MutationObserver((records, observer) => { | |
| for (const record of records) { | |
| if (record.type !== "childList" || record.addedNodes.length === 0) { | |
| continue; | |
| } | |
| addBlockButton(Array.from(record.addedNodes).find(node => node.nodeName.toLowerCase() === 'yt-profile-card-view-model')); | |
| } | |
| }); | |
| new MutationObserver((records, observer) => { | |
| const ytdMultiPageMenu = document.querySelector('#sections.ytd-multi-page-menu-renderer'); | |
| if (ytdMultiPageMenu == null) { | |
| return; | |
| } | |
| observer.disconnect(); | |
| addBlockButton(document.querySelector('yt-profile-card-view-model')); | |
| watchMultiPageMenu.observe(ytdMultiPageMenu, {childList: true, subtree: true}); | |
| }).observe(document.body, {childList: true}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment