Chzzk Util: Auto Click View more

치지적 팔로잉 채널의 더보기 버튼을 자동으로 클릭

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Chzzk Util: Auto Click View more
// @name:ko      Chzzk Util: 더보기 버튼 자동화
// @namespace    Chzzk Util: Auto Click View more
// @version      1.1
// @description  치지적 팔로잉 채널의 더보기 버튼을 자동으로 클릭
// @author       DOGJIP
// @match        https://chzzk.naver.com/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    let lastUrl = location.href;
    let isProcessing = false;
    let checkTimeout = null;
    let retryCount = 0;
    const MAX_RETRIES = 10;
    let theaterModeTimeout = null; // 극장 모드 디바운스용

    // 더보기 버튼 클릭 함수
    function clickMoreButton() {
        if (isProcessing || retryCount >= MAX_RETRIES) {
            if (retryCount >= MAX_RETRIES) {
                //console.log('[CHZZK Auto Expand] 최대 재시도 횟수 도달');
                retryCount = 0;
            }
            return;
        }

        const moreButton = document.querySelector('.navigation_bar_box__5WNl4 button.navigation_bar_more_button__7DoyA');

        if (!moreButton) {
            isProcessing = false;
            retryCount = 0;
            return;
        }

        const ariaLabel = moreButton.getAttribute('aria-label');
        const ariaExpanded = moreButton.getAttribute('aria-expanded');

        if (ariaLabel === '더보기' && ariaExpanded === 'false') {
            //console.log('[CHZZK Auto Expand] 더보기 버튼 클릭 (시도:', ++retryCount, ')');
            isProcessing = true;
            moreButton.click();

            checkTimeout = setTimeout(() => {
                isProcessing = false;
                clickMoreButton();
            }, 300);
        } else if (ariaLabel === '접기') {
            //console.log('[CHZZK Auto Expand] 모든 채널 확장 완료');
            isProcessing = false;
            retryCount = 0;
        } else {
            isProcessing = false;
            retryCount = 0;
        }
    }

    // 극장 모드 전환 처리 (디바운스 적용)
    function handleTheaterModeToggle(source) {
        // 중복 호출 방지
        if (theaterModeTimeout) {
            clearTimeout(theaterModeTimeout);
        }

        //console.log(`[CHZZK Theater Mode] ${source} 감지 - 극장 모드 토글`);

        theaterModeTimeout = setTimeout(() => {
            isProcessing = false;
            retryCount = 0;
            clickMoreButton();
            theaterModeTimeout = null;
        }, 600);
    }

    // 전체화면 변경 감지
    document.addEventListener('fullscreenchange', () => {
        //console.log('[CHZZK Fullscreen] 전체화면 상태 변경');
        handleTheaterModeToggle('전체화면 변경');
    });

    // T키 입력 감지 (극장 모드 토글)
    document.addEventListener('keydown', (e) => {
        // input, textarea 등에서 입력 중일 때는 무시
        if (e.target.tagName === 'INPUT' ||
            e.target.tagName === 'TEXTAREA' ||
            e.target.isContentEditable) {
            return;
        }

        if (e.key === 't' || e.key === 'T') {
            handleTheaterModeToggle('T키');
        }

        if (e.key === 'Escape') {
            handleTheaterModeToggle('Esc키');
        }
    }, { passive: true }); // passive 옵션으로 성능 개선

    // 극장 모드 버튼 클릭 감지 & 메뉴 확장 시
    document.addEventListener('click', (e) => {
        const target = e.target.closest('button');
        if (!target) return;

        const ariaLabel = target.getAttribute('aria-label');

        // 극장 모드 버튼 클릭 감지
        if (ariaLabel?.includes('좁은')) {
            handleTheaterModeToggle('극장 모드 버튼');
        }

        // 메뉴 확장 버튼 클릭 감지 (엄밀히 극장 모드는 아님)
        if (ariaLabel?.includes('메뉴 확장')) {
            handleTheaterModeToggle ('메뉴 확장 버튼');
        }
    }, { capture: true, passive: true }); // passive 옵션 추가


    // History API 감지
    const originalPushState = history.pushState;
    const originalReplaceState = history.replaceState;

    history.pushState = function(...args) {
        originalPushState.apply(this, args);
        handleUrlChange();
    };

    history.replaceState = function(...args) {
        originalReplaceState.apply(this, args);
        handleUrlChange();
    };

    window.addEventListener('popstate', handleUrlChange);

    // URL 변경 처리 함수
    function handleUrlChange() {
        if (location.href !== lastUrl) {
            //console.log('[CHZZK Auto Expand] URL 변경:', location.href);
            lastUrl = location.href;
            isProcessing = false;
            retryCount = 0;

            if (checkTimeout) clearTimeout(checkTimeout);
            if (theaterModeTimeout) clearTimeout(theaterModeTimeout);

            setTimeout(clickMoreButton, 800);
        }
    }

    // MutationObserver - 더보기 버튼이 나타날 때만 감지
    const observerConfig = {
        childList: true,
        subtree: false
    };

    let observerTimeout = null;
    const observer = new MutationObserver((mutations) => {
        const hasRelevantChange = mutations.some(mutation => {
            return Array.from(mutation.addedNodes).some(node =>
                node.nodeType === 1 &&
                (node.classList?.contains('navigation_bar_box__5WNl4') ||
                 node.querySelector?.('.navigation_bar_box__5WNl4'))
            );
        });

        if (hasRelevantChange) {
            if (observerTimeout) clearTimeout(observerTimeout);
            observerTimeout = setTimeout(() => {
                if (!isProcessing) clickMoreButton();
            }, 100);
        }
    });

    // 네비게이션 영역만 관찰
    function startObserver() {
        const navSection = document.querySelector('nav.navigation_bar_section__hDpyD');
        if (navSection) {
            observer.observe(navSection, observerConfig);
            //console.log('[CHZZK Auto Expand] 네비게이션 영역 감시 시작');
        } else {
            setTimeout(startObserver, 500);
        }
    }

    // 초기화
    function init() {
        //console.log('[CHZZK Auto Expand] 스크립트 시작 (최적화 v3.3)');
        startObserver();
        setTimeout(clickMoreButton, 2000);
        // 초기 로딩 보강: 더보기 버튼이 늦게 생길 경우 5초간 주기적으로 재시도
        let initRetry = 0;
        const initInterval = setInterval(() => {
            const btn = document.querySelector('.navigation_bar_box__5WNl4 button.navigation_bar_more_button__7DoyA');
            if (btn) {
                //console.log('[CHZZK Auto Expand] 초기 더보기 버튼 감지됨 - 클릭');
                clickMoreButton();
                clearInterval(initInterval);
            } else if (++initRetry > 10) {
                clearInterval(initInterval);
            }
        }, 500);
    }

    // DOM이 준비되면 실행
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

})();