Last active
May 27, 2025 06:54
-
-
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.1.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.1.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 { | |
#blockedCache = null; | |
get #values() { | |
return GM_listValues().filter((key) => { | |
return key.startsWith('/channel/') || key === 'blocked'; | |
}); | |
} | |
get blockedList() { | |
if (this.#blockedCache == null) { | |
this.#blockedCache = GM_getValues(this.#values); | |
} | |
return this.#blockedCache; | |
} | |
get #requireMigrate() { | |
return this.#values.includes("blocked"); | |
} | |
migrate() { | |
if (this.#requireMigrate) { | |
for (const blocked of GM_getValue('blocked', [])) { | |
GM_setValue(blocked.channelUrl, blocked.handle); | |
} | |
GM_deleteValue('blocked'); | |
} | |
} | |
block({channelUrl, handle}) { | |
this.#blockedCache[channelUrl] = handle; | |
GM_setValue(channelUrl, handle); | |
GM_addStyle(` | |
ytd-comment-thread-renderer:has(> 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; | |
} | |
`); | |
} | |
}; | |
config.migrate(); | |
Promise.all(Object.entries(config.blockedList).map(([channelUrl, handle]) => { | |
return GM.addStyle(` | |
ytd-comment-thread-renderer:has(> 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; | |
} | |
`); | |
})).then(console.debug); | |
const blockUserFn = (handle, channelUrl) => ((ev) => { | |
config.block({handle, channelUrl}); | |
}); | |
const watchMultiPageMenu = new MutationObserver((records, observer) => { | |
for (const record of records) { | |
if (record.type !== "childList" || record.addedNodes.length === 0) { | |
continue; | |
} | |
const profileIdentityInfoView = Array.from(record.addedNodes).find(node => node.nodeName.toLowerCase() === 'yt-profile-identity-info-view-model'); | |
if (profileIdentityInfoView == null) { | |
continue; | |
} | |
const profileIdentityInfo = profileIdentityInfoView.__instance.props.data; | |
const channelBannerContainer = profileIdentityInfoView.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); | |
} | |
}); | |
new MutationObserver((records, observer) => { | |
const ytdMultiPageMenu = document.querySelector('#sections.ytd-multi-page-menu-renderer'); | |
if (ytdMultiPageMenu == null) { | |
return; | |
} | |
observer.disconnect(); | |
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