// ==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:
*
*/
const svgComments = `
`
const svgVideos = ``
const svgInfo = ``
const svgPlayList = `
`
const svgElm = (w, h, vw, vh, 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 = `
`;
$("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...
})();