// ==UserScript== // @name Tabview Youtube // @namespace http://tampermonkey.net/ // @version 0.2 // @description Make comments and lists into tabs // @author CY Fung // @match https://www.youtube.com/watch?v=* // @resource contentCSS https://github.com/cyfung1031/Tabview-Youtube/raw/main/css/style_content.css?v20210630b // @icon https://github.com/cyfung1031/Tabview-Youtube/raw/main/images/icon128p.png // @require https://code.jquery.com/jquery-3.6.0.slim.min.js // @grant GM_getResourceText // @run-at document-start // @license MIT https://github.com/cyfung1031/Tabview-Youtube/blob/main/LICENSE // @downloadURL none // ==/UserScript== function main($){ // MIT License // https://github.com/cyfung1031/Tabview-Youtube/raw/main/js/content.js /** * SVG resources: *
Icons made by Smashicons from www.flaticon.com
*/ const svgComments = ` ` const svgVideos = `` const svgInfo = `` const svgPlayList = ` ` const svgElm = (w, h, vw, vh, p) => `${p}` let settings = { toggleSettings: { lightsOff: 1, tabs: 1, tInfo: 1, tComments: 1, tVideos: 1, volumeControl: 1 }, defaultTab: "videos" }; function isVideoPlaying(video) { return video.currentTime > 0 && !video.paused && !video.ended && video.readyState > video.HAVE_CURRENT_DATA; } let lastScrollAt = 0; function makeBodyScroll() { // avoid over triggering scroll event if (+new Date - lastScrollAt < 10) return; lastScrollAt = +new Date; //required for youtube content display window.dispatchEvent(new Event("scroll")); } let mtoIgnoreTo = 0 let mtoNav = null; let mtf_checkDescriptionLoaded = null let mtf_related = null; let mtf_checkPlayList = null; let mtf_checkCommentsLoaded = null; let mtf_playerListQ = null var stComments_last = null let mtf_liveChatBtnQ = null; function AddTabPanel() { if (window.location.href.indexOf("www.youtube.com/watch?v=") < 0) return; let ts = settings.toggleSettings; if (!ts.tabs) return; const sTabBtnVideos = `${svgElm(16,16,298,298,svgVideos)}Videos` const sTabBtnInfo = `${svgElm(16,16,23.625,23.625,svgInfo)}Info` const sTabBtnPlayList = `${svgElm(16,16,426.667,426.667,svgPlayList)}Playlist` const str1 = `
`; const str_tabs = [ ts.tInfo ? `${sTabBtnInfo}${str1}` : '', `Chat${str1}`, ts.tComments ? `Loading..${str1}` : '', ts.tVideos ? `${sTabBtnVideos}${str1}` : '', `${sTabBtnPlayList}${str1}` ].join('') var addHTML = `
${str_tabs}
`; $("span#tab3-txt-loader").text("Loading.."); $("ytd-watch-flexy").removeAttr("userscript-chatblock").removeAttr("userscript-chat-collapsed") remove_DisablePauseVideo(); let elm1 = document.querySelector("ytd-watch-metadata ~ #info") let elm2 = document.querySelector('ytd-comments#comments') if (elm1 && elm2) { add_DisablePauseVideo(); $(elm2).addClass('userscript-hide-comments') insertBefore(elm2, elm1) } function stChatButton() { let button = mtf_liveChatBtnQ if (!button || !button.parentNode) return; button.parentNode.insertBefore(button, button.parentNode.firstChild) const collapsedObserver = new MutationObserver((mutations, observer) => { for (const mutation of mutations) { console.log('ytd-live-chat-frame#chat: attribute[collapsed] changed', mutation) } sVisiblity() }) collapsedObserver.observe(document.querySelector('ytd-live-chat-frame#chat'), { attributes: true, attributeFilter: ['collapsed'], attributeOldValue: true }) //console.log(1213, document.querySelector('ytd-live-chat-frame#chat')) function sVisiblity() { const chatBlock = document.querySelector('ytd-live-chat-frame#chat') const cssElm = document.querySelector('ytd-watch-flexy') if (chatBlock) { cssElm.setAttribute('userscript-chatblock', '') if (chatBlock.hasAttribute('collapsed')) { cssElm.setAttribute('userscript-chat-collapsed', ''); } else { cssElm.removeAttribute('userscript-chat-collapsed'); } } else { cssElm.removeAttribute('userscript-chatblock') } //console.log(1218, cssElm.hasAttribute('userscript-chatblock'), cssElm.hasAttribute('userscript-chat-collapsed')) if (!cssElm.hasAttribute('userscript-chat-collapsed') && cssElm.hasAttribute('userscript-chatblock')) { switchTabActivity(null) } else { let z; z = document.querySelector(`a[userscript-tab-content="${switchTabActivity_lastTab}}"]`) || document.querySelector(`a[userscript-tab-content="#tab-${settings.defaultTab}"]`) if (z) { switchTabActivity_lastTab = z.getAttribute('userscript-tab-content') switchTabActivity(z) } } } sVisiblity() } mtf_liveChatBtnQ = null if (mtoNav) { mtoNav.takeRecords(); mtoNav.disconnect(); mtoNav = null; mtf_checkDescriptionLoaded = null mtf_related = null; mtf_checkPlayList = null; mtf_checkCommentsLoaded = null; mtf_playerListQ = null stComments_last = null mtoIgnoreTo = 0; } var wwx = 0; var lastRelocate = 0 function mtf_commentRelocate() { let elm1, elm2; if (+new Date - lastRelocate > 350) { if ((elm1 = document.querySelector("ytd-watch-metadata ~ #info")) && (elm2 = document.querySelector('ytd-watch-metadata ~ #info ~ ytd-comments#comments'))) { lastRelocate = +new Date; window.requestAnimationFrame(() => { add_DisablePauseVideo(); $(elm2).addClass('userscript-hide-comments') insertBefore(elm2, elm1) elm1 = null; elm2 = null; }) } } } function mtf_commentRendering() { var elmComments = document.querySelector('ytd-comments#comments'); var elmHeader = document.querySelector("ytd-comments#comments ytd-comments-header-renderer"); var stComments_current = (elmComments ? 1 : 0) + (elmHeader ? 2 : 0) + (document.querySelectorAll('#tab-comments, [userscript-tab-content="#tab-comments"]').length == 2 ? 4 : 0) if (stComments_current !== stComments_last) { stComments_last = stComments_current; window.requestAnimationFrame(() => { if (stComments_current == 1 + 4) { var isActiveBefore = $('[userscript-tab-content="#tab-comments"]').is('.active') $('[userscript-tab-content="#tab-comments"]').addClass("hide"); if (isActiveBefore) { setDefaultActiveTab(); } } else if (stComments_current == 1 + 2 + 4) { $('[userscript-tab-content="#tab-comments"]').removeClass("hide"); if ($("ytd-comments#comments").is('.userscript-hide-comments')) { $("ytd-comments#comments").appendTo("#tab-comments"); checkCommentsLoaded(); $("ytd-comments#comments").removeClass('userscript-hide-comments') } } }) } } function mtf_liveChatBtnF() { let button = document.querySelector('ytd-live-chat-frame#chat>.ytd-live-chat-frame#show-hide-button') if (button && mtf_liveChatBtnQ !== button) { mtf_liveChatBtnQ = button requestAnimationFrame(stChatButton) } } function mtf_fixInfo() { const content = document.querySelector('#meta-contents ytd-expander>#content, #tab-info ytd-expander>#content') if (!content) return; const expander = content.parentNode; if (expander.hasAttribute('collapsed')) { expander.removeAttribute('collapsed') } let btn1 = expander.querySelector('tp-yt-paper-button#less:not([hidden])'); let btn2 = expander.querySelector('tp-yt-paper-button#more:not([hidden])'); if (btn1) btn1.setAttribute('hidden', '') if (btn2) btn2.setAttribute('hidden', '') } let mtoNav_delayedC = 0; let mtoNav_delayedF = () => { mtoNav_delayedC = 0; //console.log(999,++wwx) mtf_commentRelocate(); mtf_liveChatBtnF(); mtf_commentRendering(); mtf_fixInfo(); if (mtf_checkDescriptionLoaded && mtf_checkDescriptionLoaded() === false) mtf_checkDescriptionLoaded = null if (mtf_related && mtf_related() === false) mtf_related = null; mtf_checkPlayList() if (mtf_checkCommentsLoaded && mtf_checkCommentsLoaded() === false) mtf_checkCommentsLoaded = null; } mtoNav = new MutationObserver((mutations, observer) => { if (mtoIgnoreTo > +new Date) return; let ch = false; for (const mutation of mutations) { for (const addedNode of mutation.addedNodes) if (addedNode.nodeType === 1) ch = true; for (const removedNode of mutation.removedNodes) if (removedNode.nodeType === 1) ch = true; } if (!ch) return; if (mtoNav_delayedC) return; mtoNav_delayedC = window.requestAnimationFrame(mtoNav_delayedF) }); mtoNav.observe(document.querySelector('ytd-watch-flexy'), { subtree: true, childList: true }) if (document.querySelector("#right-tabs")) { runAfterTabAppended(); } else { let watchAt = +new Date; mtf_related = () => { let keepTrace = true; if ($("#related").length && !$("#right-tabs").length) { $(addHTML).prependTo("#related"); runAfterTabAppended(); keepTrace = false; } else if (new Date - watchAt > 1000) { keepTrace = false; } return keepTrace; } if (mtf_related && mtf_related() === false) mtf_related = null; } } function setDefaultActiveTab() { const jElm = document.querySelector(`a[userscript-tab-content="${switchTabActivity_lastTab}"]:not(.hide)`) || document.querySelector(`a[userscript-tab-content="#tab-${settings.defaultTab}"]:not(.hide)`) || document.querySelector("a[userscript-tab-content]:not(.hide)") || null; switchTabActivity(jElm) } function insertBefore(elm, p) { if (elm && p && p.parentNode) p.parentNode.insertBefore(elm, p) } function hDisablePauseVideo(evt) { //evt.preventDefault(); //evt.stopPropagation(); //evt.stopImmediatePropagation() this.play(); } function add_DisablePauseVideo() { const video = document.querySelector('.ytd-player video') if (video && isVideoPlaying(video)) video.addEventListener('pause', hDisablePauseVideo, { once: true, capture: true, passive: false }) } function remove_DisablePauseVideo() { const video = document.querySelector('.ytd-player video') if (video) video.removeEventListener('pause', hDisablePauseVideo, { once: true, capture: true, passive: false }) } function addControlElement() { $('').prependTo('ytd-comments#comments') } let loadComments_cid1 = 0; function loadComments() { } function runAfterTabAppended() { $('.tab-content').attr('standardized-themed-scrollbar', '').attr('scrollbar-rework', '').attr('scrollbar-color', '') //$("#tab-comments").addClass('hideOnRight'); //$('[userscript-tab-content="#tab-comments"]').addClass("hide"); setDefaultActiveTab(); if (settings.toggleSettings.tVideos) { $("ytd-watch-next-secondary-results-renderer").appendTo("#tab-videos"); } if (settings.toggleSettings.tComments) { loadComments(); } if (settings.toggleSettings.tInfo) { checkDescriptionLoaded(); } tabsUiScript(); checkPlayList(); // chatToggleToTop() $(".tab-content").scroll(makeBodyScroll); } function checkDescriptionLoaded() { let watchAt = +new Date; //console.log(113); mtf_checkDescriptionLoaded = () => { //console.log(114); let keepTrace = true; const expander = document.querySelector("#meta-contents ytd-expander"); //console.log(117,expander?expander.textContent:null) if (expander && (expander.textContent || new Date - watchAt > 11270)) { //console.log(115, expander?expander.textContent:null); keepTrace = false; if (expander) { $(expander).appendTo("#tab-info") } } return keepTrace; } if (mtf_checkDescriptionLoaded() === false) mtf_checkDescriptionLoaded = null } function checkCommentsLoaded() { //console.log(3434) let $span = $("span#tab3-txt-loader") if (!$span[0]) return; //$span[0].textContent = ("Loading.."); function updateCommentCount(s) { remove_DisablePauseVideo() $span[0].innerHTML = `${svgElm(16,16,60,60,svgComments)}${s}`; makeBodyScroll(); // force display content } let watchAt = +new Date; mtf_checkCommentsLoaded = () => { let keepTrace = true; const commentRenderer = document.querySelector("#count.ytd-comments-header-renderer"); if (commentRenderer) { //console.log('k060', +new Date) let r = '0'; let txt = commentRenderer.textContent if (typeof txt == 'string') { let m = txt.match(/[\d\,\s]+/) if (m) r = m[0].trim() } if (updateCommentCount) { updateCommentCount(r) updateCommentCount = null } keepTrace = false; } else if (new Date - watchAt > 4000) { if (updateCommentCount) { updateCommentCount('0') updateCommentCount = null } keepTrace = false; } return keepTrace } if (mtf_checkCommentsLoaded && mtf_checkCommentsLoaded() === false) mtf_checkCommentsLoaded = null; } function checkPlayList() { var elmSelector = "#secondary #playlist"; var isActiveBefore = $('[userscript-tab-content="#tab-list"]').is('.active') //$('[userscript-tab-content="#tab-list"]').addClass("hide"); // if(isActiveBefore){ // setDefaultActiveTab(); //} let watchAt = +new Date; //console.log(177) mtf_checkPlayList = () => { let ple1 = document.querySelector("#secondary>ytd-playlist-panel-renderer#playlist, #secondary-inner>ytd-playlist-panel-renderer#playlist"); let ple2 = document.querySelector("#tab-list ytd-playlist-panel-renderer#playlist"); let ple3 = document.querySelector('ytd-playlist-panel-renderer>#container>#items>ytd-playlist-panel-video-renderer') let mtf_playerListR = (ple1 ? 1 : 0) + (ple2 ? 2 : 0) + (ple3 ? 4 : 0); if (mtf_playerListR !== mtf_playerListQ) { mtf_playerListQ = mtf_playerListR window.requestAnimationFrame(() => { if (mtf_playerListQ & 4) { //if(!$(elmSelector).is(":hidden")){ if (mtf_playerListQ & 1) $(ple1).appendTo("#tab-list"); const tab5 = document.querySelector('[userscript-tab-content="#tab-list"]'); if (tab5) { $(tab5).removeClass("hide"); //tab5.click(); } $('ytd-playlist-panel-renderer>#container>#items').scroll(makeBodyScroll); //} } else { var isActiveBefore = $('[userscript-tab-content="#tab-list"]').is('.active') $('[userscript-tab-content="#tab-list"]').addClass("hide"); if (isActiveBefore) { setDefaultActiveTab(); } } }) } } mtf_checkPlayList() } let switchTabActivity_lastTab = null function switchTabActivity(activeLink) { if (activeLink && activeLink.hasAttribute('hide')) return; //console.log(1219,'hello', activeLink?activeLink.getAttribute('userscript-tab-content'):null) const links = document.querySelectorAll('#material-tabs a[userscript-tab-content]'); for (const link of links) { let content = document.querySelector(link.getAttribute('userscript-tab-content')); if (link && content) { if (link !== activeLink) { $(link).removeClass("active"); $(content).addClass("hideOnRight"); } else { $(link).addClass("active"); $(content).removeClass("hideOnRight"); window.requestAnimationFrame(() => content.focus()) } } } } let tabsUiScript_setclick = false; function tabsUiScript() { const materialTab = document.querySelector("#material-tabs") if (!materialTab) return; let noActiveTab = !!document.querySelector('ytd-watch-flexy[userscript-chatblock]:not([userscript-chat-collapsed])') const activeLink = materialTab.querySelector('a[userscript-tab-content].active') || document.querySelector(`a[userscript-tab-content="#tab-${settings.defaultTab}"]`); if (activeLink) switchTabActivity(noActiveTab ? null : activeLink) if (!tabsUiScript_setclick) { tabsUiScript_setclick = true; $(materialTab).on("click", "a", function(evt) { if (!this.hasAttribute('userscript-tab-content')) return; window.requestAnimationFrame(() => { Promise.resolve().then(() => { let button = document.querySelector('ytd-live-chat-frame#chat:not([collapsed])>.ytd-live-chat-frame#show-hide-button') return button }).then(button => { mtoIgnoreTo = +new Date + 300; if (button) { button.querySelector('ytd-toggle-button-renderer').click(); } }).then(() => { setTimeout(() => { switchTabActivity_lastTab = this.getAttribute('userscript-tab-content'); switchTabActivity(this) }, 100); mtoIgnoreTo = 0; }) }) evt.preventDefault(); }); } } // --------------------------------------------------------------------------------------------- window.addEventListener("yt-navigate-finish", AddTabPanel) // https://github.com/cyfung1031/Tabview-Youtube/raw/main/js/content.js } ;!(function $$() { 'use strict'; if(document.documentElement==null) return window.requestAnimationFrame($$) var cssTxt = GM_getResourceText("contentCSS"); function addStyle (styleText) { const styleNode = document.createElement('style'); styleNode.type = 'text/css'; styleNode.textContent = styleText; document.documentElement.appendChild(styleNode); return styleNode; } addStyle (cssTxt); main(window.$); // Your code here... })();