Greasy Fork

来自缓存

Greasy Fork is available in English.

Tabview Youtube

Make comments and lists into tabs

当前为 2021-06-30 提交的版本,查看 最新版本

// ==UserScript==
// @name         Tabview Youtube
// @namespace    http://tampermonkey.net/
// @version      0.3
// @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?v20210701a
// @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
// ==/UserScript==
function main($){
    // MIT License
    // https://github.com/cyfung1031/Tabview-Youtube/raw/main/js/content.js





/**
 * SVG resources:
 * <div>Icons made by <a href="https://www.flaticon.com/authors/smashicons" title="Smashicons">Smashicons</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a></div>
 */
 const svgComments = `
 <path d="M40.068,13.465L5.93,13.535c-3.27,0-5.93,2.66-5.93,5.93v21.141c0,3.27,2.66,5.929,5.93,5.929H12v10
 c0,0.413,0.254,0.784,0.64,0.933c0.117,0.045,0.239,0.067,0.36,0.067c0.276,0,0.547-0.115,0.74-0.327l9.704-10.675l16.626-0.068
 c3.27,0,5.93-2.66,5.93-5.929V19.395C46,16.125,43.34,13.465,40.068,13.465z M10,23.465h13c0.553,0,1,0.448,1,1s-0.447,1-1,1H10
 c-0.553,0-1-0.448-1-1S9.447,23.465,10,23.465z M36,37.465H10c-0.553,0-1-0.448-1-1s0.447-1,1-1h26c0.553,0,1,0.448,1,1
 S36.553,37.465,36,37.465z M36,31.465H10c-0.553,0-1-0.448-1-1s0.447-1,1-1h26c0.553,0,1,0.448,1,1S36.553,31.465,36,31.465z"/>
 <path d="M54.072,2.535L19.93,2.465c-3.27,0-5.93,2.66-5.93,5.93v3.124l26.064-0.054c4.377,0,7.936,3.557,7.936,7.93v21.07v0.071
 v2.087l3.26,3.586c0.193,0.212,0.464,0.327,0.74,0.327c0.121,0,0.243-0.022,0.36-0.067c0.386-0.149,0.64-0.52,0.64-0.933v-10h1.07
 c3.27,0,5.93-2.66,5.93-5.929V8.465C60,5.195,57.34,2.535,54.072,2.535z"/>
 `

const svgVideos = `<path d="M298,33c0-13.255-10.745-24-24-24H24C10.745,9,0,19.745,0,33v232c0,13.255,10.745,24,24,24h250c13.255,0,24-10.745,24-24V33
 z M91,39h43v34H91V39z M61,259H30v-34h31V259z M61,73H30V39h31V73z M134,259H91v-34h43V259z M123,176.708v-55.417
 c0-8.25,5.868-11.302,12.77-6.783l40.237,26.272c6.902,4.519,6.958,11.914,0.056,16.434l-40.321,26.277
 C128.84,188.011,123,184.958,123,176.708z M207,259h-43v-34h43V259z M207,73h-43V39h43V73z M268,259h-31v-34h31V259z M268,73h-31V39
 h31V73z"/>`

const svgInfo = `<path d="M11.812,0C5.289,0,0,5.289,0,11.812s5.289,11.813,11.812,11.813s11.813-5.29,11.813-11.813
 S18.335,0,11.812,0z M14.271,18.307c-0.608,0.24-1.092,0.422-1.455,0.548c-0.362,0.126-0.783,0.189-1.262,0.189
 c-0.736,0-1.309-0.18-1.717-0.539s-0.611-0.814-0.611-1.367c0-0.215,0.015-0.435,0.045-0.659c0.031-0.224,0.08-0.476,0.147-0.759
 l0.761-2.688c0.067-0.258,0.125-0.503,0.171-0.731c0.046-0.23,0.068-0.441,0.068-0.633c0-0.342-0.071-0.582-0.212-0.717
 c-0.143-0.135-0.412-0.201-0.813-0.201c-0.196,0-0.398,0.029-0.605,0.09c-0.205,0.063-0.383,0.12-0.529,0.176l0.201-0.828
 c0.498-0.203,0.975-0.377,1.43-0.521c0.455-0.146,0.885-0.218,1.29-0.218c0.731,0,1.295,0.178,1.692,0.53
 c0.395,0.353,0.594,0.812,0.594,1.376c0,0.117-0.014,0.323-0.041,0.617c-0.027,0.295-0.078,0.564-0.152,0.811l-0.757,2.68
 c-0.062,0.215-0.117,0.461-0.167,0.736c-0.049,0.275-0.073,0.485-0.073,0.626c0,0.356,0.079,0.599,0.239,0.728
 c0.158,0.129,0.435,0.194,0.827,0.194c0.185,0,0.392-0.033,0.626-0.097c0.232-0.064,0.4-0.121,0.506-0.17L14.271,18.307z
  M14.137,7.429c-0.353,0.328-0.778,0.492-1.275,0.492c-0.496,0-0.924-0.164-1.28-0.492c-0.354-0.328-0.533-0.727-0.533-1.193
 c0-0.465,0.18-0.865,0.533-1.196c0.356-0.332,0.784-0.497,1.28-0.497c0.497,0,0.923,0.165,1.275,0.497
 c0.353,0.331,0.53,0.731,0.53,1.196C14.667,6.703,14.49,7.101,14.137,7.429z"/>`

const svgPlayList = `
 <rect x="0" y="64" width="256" height="42.667"/>
 <rect x="0" y="149.333" width="256" height="42.667"/>
 <rect x="0" y="234.667" width="170.667" height="42.667"/>
 <polygon points="341.333,234.667 341.333,149.333 298.667,149.333 298.667,234.667 213.333,234.667 213.333,277.333 
     298.667,277.333 298.667,362.667 341.333,362.667 341.333,277.333 426.667,277.333 426.667,234.667"/>
     `



const svgElm = (w, h, vw, vh, p) => `<svg width="${w}" height="${h}" viewBox="0 0 ${vw} ${vh}" preserveAspectRatio="xMidYMid meet">${p}</svg>`

let settings = {
    toggleSettings: {
        tabs: 1,
        tInfo: 1,
        tComments: 1,
        tVideos: 1,
    },
    defaultTab: "videos"
};

function isVideoPlaying(video) {
    return video.currentTime > 0 && !video.paused && !video.ended && video.readyState > video.HAVE_CURRENT_DATA;
}




const Q={}

function chatFrameElement(cssSelector){
    let iframe = document.querySelector('iframe#chatframe');
    if(!iframe) return null;
    let elm = null;
    try{
        elm = iframe.contentDocument.querySelector(cssSelector)
    }catch(e){
        console.log('iframe error', e)
    }
    return elm;
}



function mtf_ChatExist(){

    //iframe can be not mutation triggering
    //collaseped might help
    
    const elmChat = document.querySelector('ytd-live-chat-frame#chat')
    let elmCont = null;
    if(elmChat){
        elmCont=chatFrameElement('yt-live-chat-renderer #continuations')
    }
    
    const chatBlockR = (elmChat?1:0)+(elmCont?2:0)
    if(Q.mtf_chatBlockQ!==chatBlockR){

        //console.log(897, Q.mtf_chatBlockQ, chatBlockR)
        Q.mtf_chatBlockQ=chatBlockR

        
        const cssElm = document.querySelector('ytd-watch-flexy')
        if(elmChat){

            let s=0;
            if(elmCont){
                //not found if it is collasped.
                s |= elmCont.querySelector('yt-timed-continuation')?1:0;
                s |= elmCont.querySelector('yt-live-chat-replay-continuation, yt-player-seek-continuation')?2:0;
                //s |= elmCont.querySelector('yt-live-chat-restricted-participation-renderer')?4:0;
                if(s==1) cssElm.setAttribute('userscript-chatblock', 'chat-live')
                if(s==2) cssElm.setAttribute('userscript-chatblock', 'chat-playback')
                //if(s==5) cssElm.setAttribute('userscript-chatblock', 'chat-live-paid')


                if(s==1){
                    $("span#tab3-txt-loader").text('')
                }

            }
            //keep unknown as original
            if( !cssElm.hasAttribute) cssElm.setAttribute('userscript-chatblock', '')
           
            

        }else{
            cssElm.removeAttribute('userscript-chatblock')
            cssElm.removeAttribute('userscript-chat-collapsed')

        }
        

    }
}




let lastScrollAt = 0;

function makeBodyScroll() {

    // avoid over triggering scroll event
    if (+new Date - lastScrollAt < 30) return;
    lastScrollAt = +new Date;

    //required for youtube content display

    requestAnimationFrame(()=>{

        window.dispatchEvent(new Event("scroll"));

    })

}


let mtoIgnoreTo = 0
let mtoNav = 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)}<span>Videos</span>`
    const sTabBtnInfo = `${svgElm(16,16,23.625,23.625,svgInfo)}<span>Info</span>`
    const sTabBtnPlayList = `${svgElm(16,16,426.667,426.667,svgPlayList)}<span>Playlist</span>`

    const str1 = `
     <paper-ripple class="style-scope yt-icon-button">
         <div id="background" class="style-scope paper-ripple" style="opacity:0;"></div>
         <div id="waves" class="style-scope paper-ripple"></div>
     </paper-ripple>
     `;



    const str_tabs = [
        ts.tInfo ? `<a id="tab-btn1" data-name="info" userscript-tab-content="#tab-info" class="tab-btn">${sTabBtnInfo}${str1}</a>` : '',
        `<a id="tab-btn2" userscript-tab-content="#tab-live" class="tab-btn hide">Chat${str1}</a>`,
        ts.tComments ? `<a id="tab-btn3" userscript-tab-content="#tab-comments" data-name="comments" class="tab-btn">${svgElm(16,16,60,60,svgComments)}<span id="tab3-txt-loader"></span>${str1}</a>` : '',
        ts.tVideos ? `<a id="tab-btn4" userscript-tab-content="#tab-videos" data-name="videos" class="active tab-btn">${sTabBtnVideos}${str1}</a>` : '',
        `<a id="tab-btn5" userscript-tab-content="#tab-list">${sTabBtnPlayList}${str1}</a>`
    ].join('')

    var addHTML = `
     <div id="right-tabs">
         <header>
             <div id="material-tabs">
                 ${str_tabs}
             </div>
         </header>
         <div class="tab-content">
             <div id="tab-info" class="tab-content-cld" userscript-scrollbar-render></div>
             <div id="tab-live" class="tab-content-cld hideOnRight" userscript-scrollbar-render></div>
             <div id="tab-comments" class="tab-content-cld" userscript-scrollbar-render></div>
             <div id="tab-videos" class="tab-content-cld" userscript-scrollbar-render></div>
             <div id="tab-list" class="tab-content-cld" userscript-scrollbar-render></div>
         </div>
     </div>
     `;


    $("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)

    }
*/



    mtf_liveChatBtnQ = null

    if (mtoNav) {
        mtoNav.takeRecords();
        mtoNav.disconnect();
        mtoNav = null;
        Q.mtf_checkDescriptionLoaded = null
        Q.mtf_related = null;
        Q.mtf_checkPlayList = null;
        Q.mtf_checkCommentsLoaded = null;
        mtf_playerListQ = null
        stComments_last = null
        mtoIgnoreTo = 0;
        Q.mtf_checkTabStatus_playlist=null;
        Q.mtf_checkTabStatus_comments=null;
        Q.mtf_checkStatus_chatroom=null;
        Q.mtf_chatBlockQ=null;
    }
    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')
                    
                    $(elm2).appendTo('#tab-comments')
                    
                    //insertBefore(elm2, elm1)

                    elm1 = null;
                    elm2 = null;
                })

            }
        }
    }

    let mtf_commentRenderingLast=0;
    function mtf_commentRendering() {

        //var elmHeader = document.querySelector("ytd-comments#comments.userscript-hide-comments ytd-comments-header-renderer");
        var elmHeader = document.querySelector("ytd-comments#comments ytd-comments-header-renderer");
        if (elmHeader) {
            if(new Date - mtf_commentRenderingLast<800) return;
            mtf_commentRenderingLast=+new Date;
            window.requestAnimationFrame(() => {
                const comments = $("ytd-comments#comments")[0];
                const tabComments = $("#tab-comments")[0];
                if(!comments|| !tabComments) return;
                if(!tabComments.contains(comments)) $(comments).appendTo(tabComments);
                checkCommentsLoaded();
                $(comments).removeClass('userscript-hide-comments')
            })
        }
    }


    function mtf_liveChatBtnF() {

        let button = document.querySelector('ytd-live-chat-frame#chat>.ytd-live-chat-frame#show-hide-button:nth-child(n+2)')

        if(button){
            requestAnimationFrame(()=> button.parentNode.insertBefore(button, button.parentNode.firstChild) )
            }


    }

    function mtf_fixInfo() {

        const content = document.querySelector('#meta-contents ytd-expander>#content, #tab-info ytd-expander>#content')
        if (content) {
        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', '');

        }



        const playlist = document.querySelector('#tab-list ytd-playlist-panel-renderer#playlist')

        if(playlist){


            if(playlist.hasAttribute('collapsed')) playlist.removeAttribute('collapsed');

            if(playlist.hasAttribute('collapsible')) playlist.removeAttribute('collapsible');
        }
         


    }

    function mtf_appendPlayList(){
        
        let ple1 = document.querySelector("#secondary>ytd-playlist-panel-renderer#playlist, #secondary-inner>ytd-playlist-panel-renderer#playlist");
        if(ple1){

            let $wrapper = $('#ytd-userscript-playlist');
            if(!$wrapper[0]) $wrapper=$('<div id="ytd-userscript-playlist"></div>')
            $wrapper.append(ple1).appendTo("#tab-list");
        }

    }

    let mtfaa=0;
    function mtf_advancedComments(){



        if(mtfaa)return;
        

        if(!$('ytd-comments#comments #continuations')[0]) return;

        mtfaa=1;

        $('ytd-comments#comments')[0].dispatchEvent(new Event("yt-retrieve-location"))



    }



    let mtoNav_delayedC = 0;


    let mtoNav_delayedF = () => {
        mtoNav_delayedC = 0;

        let addP=Q.addP;
        let removeP=Q.removeP;

        Q.addP=0;Q.removeP=0;

        if(!addP||!removeP) return;


        //console.log(999,++wwx)

        (async()=>{
        mtf_fixInfo();
        })();
        (async()=>{

        mtf_ChatExist();
    })();

        if(addP>0){

            (async()=>{
                mtf_commentRelocate();
            })();
            
            (async()=>{
            mtf_liveChatBtnF();
            })();
            
            (async()=>{
                mtf_commentRendering();
            })();

            (async()=>{
            mtf_appendPlayList();
            })();

            (async()=>{
                mtf_advancedComments();
            })();

            (async()=>{
                if (Q.mtf_checkDescriptionLoaded && Q.mtf_checkDescriptionLoaded() === false) Q.mtf_checkDescriptionLoaded = null
            })();

            (async()=>{
                
            if (Q.mtf_related && Q.mtf_related() === false) Q.mtf_related = null;
            })();
            (async()=>{
                
            if (Q.mtf_checkPlayList && Q.mtf_checkPlayList() === false) Q.mtf_checkPlayList = null;
            })();
            (async()=>{
                
            if (Q.mtf_checkCommentsLoaded && Q.mtf_checkCommentsLoaded() === false) Q.mtf_checkCommentsLoaded = null;
            })();
            (async()=>{
                
            if(Q.mtf_checkTabStatus_comments&&Q.mtf_checkTabStatus_comments()===false)Q.mtf_checkTabStatus_comments=null;
            })();
            (async()=>{
                
            if(Q.mtf_checkTabStatus_playlist&&Q.mtf_checkTabStatus_playlist()===false)Q.mtf_checkTabStatus_playlist=null;
            })();
            
            (async()=>{
                
            if(Q.mtf_checkStatus_chatroom&&Q.mtf_checkStatus_chatroom()===false)Q.mtf_checkStatus_chatroom=null;
            })();
      

            (async()=>{
                if(Q.mtf_forceCheckLiveVideo&&Q.mtf_forceCheckLiveVideo()===false)Q.mtf_forceCheckLiveVideo=null;
            
        })();

        }
       

    }

    Q.addP=0;
    Q.removeP=0;
    let mtoI=0;
    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) {
                    Q.addP++
                    ch = true;
                }
            for (const removedNode of mutation.removedNodes)
                if (removedNode.nodeType === 1) {
                    Q.removeP++;
                    ch = true;
                }
        }
        if (!ch) return;

        if (mtoNav_delayedC) return;
        
        mtoNav_delayedC=setTimeout(mtoNav_delayedF,30+((+new Date)%300)>>1)

    });
    mtoNav.observe(document.querySelector('ytd-watch-flexy'), {
        subtree: true,
        childList: true
    })



    if (document.querySelector("#right-tabs")) {
        runAfterTabAppended();
    } else {
        let watchAt = +new Date;

        Q.mtf_related = () => {
            const related = document.querySelector("#related")
            if (!related) return true;
            $(addHTML).prependTo(related);
            runAfterTabAppended();
            return false;
        }
        if (Q.mtf_related && Q.mtf_related() === false) Q.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() {

    $('<userscript-control-element></userscript-control-element>').prependTo('ytd-comments#comments')
}

let loadComments_cid1 = 0;


function runAfterTabAppended() {

    $('#tab-comments').attr('lazy-loading','')

    $('span#tab3-txt-loader').text('')

    setDefaultActiveTab();
    if (settings.toggleSettings.tVideos) {
        let $wrapper = $('#ytd-userscript-watch-next-videos');
        if(!$wrapper[0]) $wrapper=$('<div id="ytd-userscript-watch-next-videos"></div>')
        $wrapper.append($("ytd-watch-next-secondary-results-renderer")).appendTo("#tab-videos");
    }
    if (settings.toggleSettings.tInfo) {
        checkDescriptionLoaded();
    }
    tabsUiScript();
    checkPlayList();
    // chatToggleToTop()


    checkTabStatus();
    checkChatStatus();
    forceCheckLiveVideo();


    $("#right-tabs [userscript-scrollbar-render]").scroll(makeBodyScroll);

}


function forceCheckLiveVideo(){




    function timeCheck(){


        setTimeout(function(){

            const cssElm = document.querySelector('ytd-watch-flexy')
            if(!cssElm) return;

            if($('#ytd-player .ytp-time-display').is('.ytp-live')) cssElm.setAttribute('userscript-chatblock', 'chat-live')

        },170)

        

    }


    Q.mtf_forceCheckLiveVideo = () => {
        const playerLabel = document.querySelector('#ytd-player .ytp-time-display') && document.querySelector('ytd-live-chat-frame#chat')
        if (!playerLabel) return true;
        timeCheck();
        return false;
    }

    if (Q.mtf_forceCheckLiveVideo && Q.mtf_forceCheckLiveVideo() === false) Q.mtf_forceCheckLiveVideo = null

}


function forceCheckLiveVideo__(){

    // this is possible to detect the live video when chat area is collaseped 
    //meta might not update... 

function timeCheck(){

    setTimeout(()=>{

        const spanMeta = document.querySelector('[itemprop="publication"][itemscope][itemtype]')
        if(!spanMeta)return;
        let meta_isLiveBroadcast = spanMeta.querySelector('meta[itemprop="isLiveBroadcast"]')
        meta_isLiveBroadcast=meta_isLiveBroadcast?meta_isLiveBroadcast.getAttribute('content').toLowerCase()=='true':null
        let meta_startDate = spanMeta.querySelector('meta[itemprop="isLiveBroadcast"]')
        meta_startDate=((meta_startDate?meta_startDate.getAttribute('content'):null)||"").length>0
        let meta_endDate = spanMeta.querySelector('meta[itemprop="endDate"]')
        meta_endDate=((meta_endDate?meta_endDate.getAttribute('content'):null)||"").length>0



        const cssElm = document.querySelector('ytd-watch-flexy')
        

        if(meta_isLiveBroadcast&&meta_startDate&&!meta_endDate){

            cssElm.setAttribute('userscript-chatblock', 'chat-live')


        }else if(meta_isLiveBroadcast&&meta_startDate&&meta_endDate){

            cssElm.setAttribute('userscript-chatblock', 'chat-playback')

        }



    },170)
    


}

    Q.mtf_forceCheckLiveVideo = () => {
        const spanMeta = document.querySelector('[itemprop="publication"][itemscope][itemtype]')
        if (!spanMeta) return true;
        timeCheck();
        return false;
    }

    if (Q.mtf_forceCheckLiveVideo && Q.mtf_forceCheckLiveVideo() === false) Q.mtf_forceCheckLiveVideo = null


}



function checkDescriptionLoaded() {
    let watchAt = +new Date;
    //console.log(113);
    Q.mtf_checkDescriptionLoaded = () => {
        const expander = document.querySelector("#meta-contents ytd-expander");
        if (!expander) return true;
        $(expander).appendTo("#tab-info")
        return false;
    }

    if (Q.mtf_checkDescriptionLoaded && Q.mtf_checkDescriptionLoaded() === false) Q.mtf_checkDescriptionLoaded = null
}

function checkCommentsLoaded() {
    let $span = $("span#tab3-txt-loader")
    if (!$span[0]) return;

    Q.mtf_checkCommentsLoaded = () => {
        const commentRenderer = document.querySelector("#count.ytd-comments-header-renderer");
        if (!commentRenderer) return true;
        let r = '0';
        let txt = commentRenderer.textContent
        if (typeof txt == 'string') {
            let m = txt.match(/[\d\,\s]+/)
            if (m) r = m[0].trim()
        }      
        remove_DisablePauseVideo();
        $span[0].innerHTML = `${r}`;
        makeBodyScroll(); // force display content
        $('#tab-comments[lazy-loading]').removeAttr('lazy-loading')
        return false
    }
    if (Q.mtf_checkCommentsLoaded && Q.mtf_checkCommentsLoaded() === false) Q.mtf_checkCommentsLoaded = null;
}

const mtoVs={}

function checkTabStatus() {


    if(mtoVs.mtoVisibility_Playlist) {
        mtoVs.mtoVisibility_Playlist.takeRecords();
        mtoVs.mtoVisibility_Playlist.disconnect();
        mtoVs.mtoVisibility_Playlist=null;
    }


    let mtf_attrPlaylist=(mutations, observer)=>{


        var playlist=document.querySelector('ytd-playlist-panel-renderer#playlist')
        const $tabBtn = $('[userscript-tab-content="#tab-list"]');

        //console.log('attr playlist changed')

        if( $tabBtn.is('.hide') && !playlist.hasAttribute('hidden') ){

            //console.log('attr playlist changed - no hide')
            $tabBtn.removeClass("hide");

        }else if( !$tabBtn.is('.hide') && playlist.hasAttribute('hidden') ){


            //console.log('attr playlist changed - add hide')

            var isActiveBefore = $tabBtn.is('.active')

            $tabBtn.addClass("hide");
            if (isActiveBefore) {
                setDefaultActiveTab();
            }


        }

        
    }

    Q.mtf_checkTabStatus_playlist=()=>{


        var playlist=document.querySelector('ytd-playlist-panel-renderer#playlist')

        if(!playlist) return true;


        mtoVs.mtoVisibility_Playlist=new MutationObserver(mtf_attrPlaylist)
        mtoVs.mtoVisibility_Playlist.observe(playlist, {          
            attributes: true,
            attributeFilter: ['hidden'],
            attributeOldValue: true
        })
        mtf_attrPlaylist()


        return false;


    }

    if(Q.mtf_checkTabStatus_playlist&&Q.mtf_checkTabStatus_playlist()===false)Q.mtf_checkTabStatus_playlist=null;










    if(mtoVs.mtoVisibility_Comments) {
        mtoVs.mtoVisibility_Comments.takeRecords();
        mtoVs.mtoVisibility_Comments.disconnect();
        mtoVs.mtoVisibility_Comments=null;
    }


    let mtf_attrComments=(mutations, observer)=>{


        var comments=document.querySelector('ytd-comments#comments')
        const $tabBtn = $('[userscript-tab-content="#tab-comments"]');

        if(!comments || !$tabBtn[0])return;

        //console.log('attr comments changed')

        if( $tabBtn.is('.hide') && !comments.hasAttribute('hidden') ){

            //console.log('attr comments changed - no hide')
            $tabBtn.removeClass("hide");

        }else if( !$tabBtn.is('.hide') && comments.hasAttribute('hidden') ){


            //console.log('attr comments changed - add hide')

            $('span#tab3-txt-loader').text('');

            var isActiveBefore = $tabBtn.is('.active')

            $tabBtn.addClass("hide");
            if (isActiveBefore) {
                setDefaultActiveTab();
            }

            $('span#tab3-txt-loader').text('');


        }

        
    }

    Q.mtf_checkTabStatus_comments=()=>{


        var comments=document.querySelector('ytd-comments#comments')

        if(!comments) return true;


        mtoVs.mtoVisibility_Comments=new MutationObserver(mtf_attrComments)
        mtoVs.mtoVisibility_Comments.observe(comments, {          
            attributes: true,
            attributeFilter: ['hidden'],
            attributeOldValue: true
        })
        mtf_attrComments()


        return false;


    }

    if(Q.mtf_checkTabStatus_comments&&Q.mtf_checkTabStatus_comments()===false)Q.mtf_checkTabStatus_comments=null;



}


function checkChatStatus(){


    
    if(mtoVs.mtoVisibility_Chatroom) {
        mtoVs.mtoVisibility_Chatroom.takeRecords();
        mtoVs.mtoVisibility_Chatroom.disconnect();
        mtoVs.mtoVisibility_Chatroom=null;
    }


    let cid_chatFrameCheck=0;

    let mtf_attrChatroom=(mutations, observer)=>{

        const chatBlock = document.querySelector('ytd-live-chat-frame#chat')
        const cssElm = document.querySelector('ytd-watch-flexy')

        
        if(!cssElm.hasAttribute('userscript-chatblock')) cssElm.setAttribute('userscript-chatblock', '');
        if (chatBlock.hasAttribute('collapsed')) {
            cssElm.setAttribute('userscript-chat-collapsed', '');
        } else {
            cssElm.removeAttribute('userscript-chat-collapsed');
        }


        if(!cid_chatFrameCheck){
            let dd=+new Date;
            cid_chatFrameCheck=setInterval(()=>{
                if(+new Date - dd>2750) {
                    return (cid_chatFrameCheck=clearInterval(cid_chatFrameCheck));
                }
                var chatFrameChecking=!!chatFrameElement('yt-live-chat-renderer #continuations')
                if(chatFrameChecking) {
                    mtf_ChatExist();
                    return (cid_chatFrameCheck=clearInterval(cid_chatFrameCheck));
                }
            },30)
        }

    }

    Q.mtf_checkStatus_chatroom=()=>{


        var chatroom=document.querySelector('ytd-live-chat-frame#chat')

        if(!chatroom) return true;


        mtoVs.mtoVisibility_Chatroom=new MutationObserver(mtf_attrChatroom)
        mtoVs.mtoVisibility_Chatroom.observe(chatroom, {          
            attributes: true,
            attributeFilter: ['collapsed'],
            attributeOldValue: true
        })
        mtf_attrChatroom()


        return false;


    }

    if(Q.mtf_checkStatus_chatroom&&Q.mtf_checkStatus_chatroom()===false)Q.mtf_checkStatus_chatroom=null;





    if(mtoVs.mtoFlexyAttr) {
        mtoVs.mtoFlexyAttr.takeRecords();
        mtoVs.mtoFlexyAttr.disconnect();
        mtoVs.mtoFlexyAttr=null;
    }


    let checkQ = null;
    let mtf_attrFlexy=(mutations, observer)=>{
        
        
        const cssElm = document.querySelector('ytd-watch-flexy')
        let checkR =  !cssElm.hasAttribute('userscript-chat-collapsed') && cssElm.hasAttribute('userscript-chatblock')
        
        if(checkQ!==checkR){

            checkQ=checkR;
            window.requestAnimationFrame(()=>{

                if (checkQ) {
                    switchTabActivity(null)
                } else {
                    setDefaultActiveTab();
                }      


            })

        }


    }


    Q.mtf_checkFlexy=()=>{


        var flexy=document.querySelector('ytd-watch-flexy')

        if(!flexy) return true;


        mtoVs.mtoFlexyAttr=new MutationObserver(mtf_attrFlexy)
        mtoVs.mtoFlexyAttr.observe(flexy, {          
            attributes: true,
            attributeFilter: ['userscript-chat-collapsed','userscript-chatblock'],
            attributeOldValue: true
        })
        mtf_attrFlexy()


        return false;


    }

    if(Q.mtf_checkFlexy&&Q.mtf_checkFlexy()===false)Q.mtf_checkFlexy=null;



}



function checkPlayList() {

    Q.mtf_checkPlayList = () => {

        const items= document.querySelector('ytd-playlist-panel-renderer>#container>#items');
        if(!items) return true;

        $(items).scroll(makeBodyScroll);

        return false;

    }

    if (Q.mtf_checkPlayList && Q.mtf_checkPlayList() === false) Q.mtf_checkPlayList = null;



}

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:not(.hide)')
    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;

            switchTabActivity_lastTab = this.getAttribute('userscript-tab-content');

            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(this)

                        setTimeout(() => {

                            makeBodyScroll();

                        },20);


                    }, 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...
})();