Greasy Fork

Chzzk_L&V: UserBlockPopup

치지직 페이지에서 닉네임 클릭 시 userId 추출 후 차단 팝업 띄우기 (토글 기능 포함)

当前为 2025-06-04 提交的版本,查看 最新版本

// ==UserScript==
// @name         Chzzk_L&V: UserBlockPopup
// @namespace    Chzzk_L&V: UserBlockPopup
// @version      1.0
// @description  치지직 페이지에서 닉네임 클릭 시 userId 추출 후 차단 팝업 띄우기 (토글 기능 포함)
// @author       DOGJIP
// @match        https://chzzk.naver.com/*
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// ==/UserScript==

(function () {
    'use strict';

    // 1) 스크립트 활성화 여부 플래그
    let enabled = true;

    // 2) 메뉴에 등록할 명령어 텍스트 업데이트 함수
    function updateMenu() {
        // 기존 메뉴 제거
        try {
            GM_unregisterMenuCommand(toggleCommandId);
        } catch (e) {
            // 첫 실행 시 GM_unregisterMenuCommand가 없을 수 있음. 무시.
        }
        // 새로운 메뉴 등록
        const title = enabled ? '스크립트 비활성화' : '스크립트 활성화';
        toggleCommandId = GM_registerMenuCommand(title, () => {
            enabled = !enabled;
            alert(enabled ? 'UserBlockPopup 스크립트가 활성화되었습니다.' : 'UserBlockPopup 스크립트가 비활성화되었습니다.');
            updateMenu();
        });
    }

    let toggleCommandId = null;
    updateMenu();

    // 3) 원본 pushState 저장
    const originalPushState = history.pushState;

    // 4) pushState 훅킹
    history.pushState = function (...args) {
        if (!enabled) {
            // 비활성화 상태면 그냥 원래 동작
            return originalPushState.apply(this, args);
        }
        const url = args[2];
        if (typeof url === 'string' && /^\/[a-z0-9]{32}$/i.test(url)) {
            const userId = url.slice(1);
            const userUrl = window.location.origin + '/' + userId;
            console.log('[Chzzk-Block] pushState 감지, userId:', userId);
            showPopup(userId, userUrl);
            // 이동 자체를 막고 싶지 않으면 아래 주석 해제
            // return originalPushState.apply(this, args);
            return;
        }
        return originalPushState.apply(this, args);
    };

    // 5) popstate 이벤트 훅
    window.addEventListener('popstate', (e) => {
        if (!enabled) return;
        const path = location.pathname;
        if (/^\/[a-z0-9]{32}$/i.test(path)) {
            const userId = path.slice(1);
            const userUrl = window.location.origin + '/' + userId;
            console.log('[Chzzk-Block] popstate 감지, userId:', userId);
            showPopup(userId, userUrl);
        }
    });

    // 6) <a> 클릭 훅
    document.body.addEventListener('click', (e) => {
        if (!enabled) return;
        const span = e.target.closest('span[class^="name_text__"]');
        if (!span) return;

        const link = span.closest('a[href^="/"]');
        if (!link) return;

        const href = link.getAttribute('href');
        const match = href.match(/^\/([a-z0-9]{32})$/i);
        if (!match) return;

        const userId = match[1];
        const userUrl = window.location.origin + '/' + userId;
        console.log('[Chzzk-Block] <a> 클릭 감지, userId:', userId);

        e.preventDefault();
        e.stopPropagation();
        showPopup(userId, userUrl);
    });

    // 7) 팝업 생성 함수
    function showPopup(userId, userUrl) {
        // 이미 팝업이 있으면 제거
        const existing = document.getElementById('chzzkBlockPopup');
        if (existing) existing.remove();

        // 팝업 DIV 생성
        const popup = document.createElement('div');
        popup.id = 'chzzkBlockPopup';
        popup.style.cssText = `
            position: fixed;
            top: 35%;
            left: 50%;
            transform: translate(-50%, -35%);
            background: #fff;
            border: 2px solid #333;
            padding: 18px 24px;
            z-index: 10000;
            font-family: Arial, sans-serif;
            border-radius: 6px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.25);
            min-width: 300px;
            text-align: center;
        `;

        popup.innerHTML = `
            <p style="margin-bottom: 14px; font-size: 15px; color: #333;">
                "${userId}" 님을 차단하시겠습니까?
            </p>
            <div style="display: flex; justify-content: center; gap: 8px;">
                <button id="chzzkBlockYes" style="padding: 6px 12px; border:none; background:#d33; color:#fff; border-radius:4px; cursor:pointer;">
                    예
                </button>
                <button id="chzzkBlockGo" style="padding: 6px 12px; border:none; background:#555; color:#fff; border-radius:4px; cursor:pointer;">
                    사용자 페이지 이동
                </button>
                <button id="chzzkBlockClose" style="padding: 6px 12px; border:none; background:#999; color:#fff; border-radius:4px; cursor:pointer;">
                    닫기
                </button>
            </div>
        `;

        document.body.appendChild(popup);

        // “예” 버튼 클릭 시 API 호출 후 팝업 제거
        popup.querySelector('#chzzkBlockYes').onclick = async () => {
            try {
                const res = await fetch(
                    `https://comm-api.game.naver.com/nng_main/v1/privateUserBlocks/${userId}?loungeId=`,
                    {
                        method: 'POST',
                        credentials: 'include',
                        headers: {
                            accept: 'application/json, text/plain, */*',
                            origin: 'https://game.naver.com',
                            referer: `https://game.naver.com/profile/${userId}`,
                        },
                    }
                );
                if (res.ok) {
                    alert(`"${userId}" 님이 차단되었습니다.`);
                } else {
                    alert(`차단 실패 (HTTP ${res.status})`);
                }
            } catch (err) {
                console.error('[Chzzk-Block] 차단 중 오류:', err);
                alert('차단 중 오류가 발생했습니다.');
            } finally {
                popup.remove();
            }
        };

        // “사용자 페이지 이동” 버튼 클릭 시 원래 페이지로 이동
        popup.querySelector('#chzzkBlockGo').onclick = () => {
            popup.remove();
            window.location.href = userUrl;
        };

        // “닫기” 버튼 클릭 시 팝업만 닫기
        popup.querySelector('#chzzkBlockClose').onclick = () => {
            popup.remove();
        };
    }
})();