DCInside 자짤 차단기

빠른 실행 + 차단 목록 기반 CSS + 편집 UI 포함

Tính đến 08-07-2025. Xem phiên bản mới nhất.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(Tôi đã có Trình quản lý tập lệnh người dùng, hãy cài đặt nó!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         DCInside 자짤 차단기
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  빠른 실행 + 차단 목록 기반 CSS + 편집 UI 포함
// @match        *://*.dcinside.com/*
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @license MIT
// @run-at       document-start
// ==/UserScript==

(function () {
    'use strict';

    const STORAGE_KEY = 'dc_blocked_urls';

    // 현재 차단 목록 가져오기
    function getBlockedList() {
        return JSON.parse(GM_getValue(STORAGE_KEY, '[]'));
    }

    // 차단 목록 저장
    function saveBlockedList(list) {
        GM_setValue(STORAGE_KEY, JSON.stringify(list));
    }

    // CSS로 직접 차단
    function applyCSSBlocking() {
        const list = getBlockedList();
        if (list.length === 0) return;

        const style = document.createElement('style');
        style.id = 'dc-block-style';
        style.textContent = list.map(part => `
            img[src*="${part}"],
            video[data-src*="${part}"],
            video[src*="${part}"]
            { display: none !important; }
        `).join('\n');
        document.documentElement.appendChild(style);
    }

    // DOM 요소 숨기기 (Fallback)
    function hideBlockedElements() {
        const blocked = getBlockedList();
        document.querySelectorAll('img, video').forEach(el => {
            const src = el.src || el.getAttribute('data-src') || '';
            if (blocked.some(part => src.includes(part))) {
                el.style.display = 'none';
            }
        });
    }

    // 팝업 기반 편집 UI
    function openBlockEditorPopup() {
        const old = document.getElementById('blockEditorPopup');
        if (old) old.remove();

        const wrapper = document.createElement('div');
        wrapper.id = 'blockEditorPopup';
        wrapper.innerHTML = `
            <div class="popup-box">
                <h3>차단된 URL 목록 편집</h3>
                <textarea id="blockEditorTextarea">${getBlockedList().join('\n')}</textarea>
                <div class="popup-actions">
                    <button id="saveBlockedUrls">저장</button>
                    <button id="cancelBlockedUrls">취소</button>
                </div>
            </div>
        `;
        document.body.appendChild(wrapper);

        GM_addStyle(`
    #blockEditorPopup {
        position: fixed;
        top: 50%; left: 50%;
        transform: translate(-50%, -50%);
        background: #2a2a2a;  /* 다크모드 대비용 진회색 */
        color: #f0f0f0;       /* 밝은 텍스트 */
        border: 2px solid #555;
        padding: 16px;
        z-index: 99999;
        width: 400px;
        box-shadow: 0 0 10px rgba(0,0,0,0.5);
        font-family: sans-serif;
        border-radius: 6px;
    }
    #blockEditorPopup h3 {
        margin-top: 0;
        font-size: 1.1em;
    }
    #blockEditorPopup textarea {
        width: 100%;
        height: 200px;
        margin-top: 8px;
        resize: vertical;
        font-family: monospace;
        background: #1e1e1e;
        color: #f0f0f0;
        border: 1px solid #777;
        padding: 8px;
    }
    #blockEditorPopup .popup-actions {
        margin-top: 10px;
        text-align: right;
    }
    #blockEditorPopup button {
        margin-left: 8px;
        padding: 6px 12px;
        background: #444;
        color: #f0f0f0;
        border: 1px solid #888;
        border-radius: 4px;
        cursor: pointer;
    }
    #blockEditorPopup button:hover {
        background: #666;
        border-color: #aaa;
    }
`);


        document.getElementById('saveBlockedUrls').onclick = () => {
            const value = document.getElementById('blockEditorTextarea').value;
            const list = value.split('\n').map(s => s.trim()).filter(s => s.length > 0);
            saveBlockedList(list);
            document.getElementById('dc-block-style')?.remove();
            applyCSSBlocking();
            hideBlockedElements();
            alert('저장되었습니다!');
            wrapper.remove();
        };

        document.getElementById('cancelBlockedUrls').onclick = () => {
            wrapper.remove();
        };
    }

    // 메뉴 등록
    GM_registerMenuCommand('차단 목록 보기/편집 (팝업)', openBlockEditorPopup);
    GM_registerMenuCommand('마지막 우클릭한 URL 차단하기', function () {
        const url = GM_getValue('__temp_block_candidate', '');
        if (!url) {
            alert('이미지나 영상을 먼저 우클릭하세요.');
            return;
        }

        const short = prompt('차단할 URL 일부를 입력하세요 (기본값: 전체 URL)', url);
        if (short !== null) {
            const list = getBlockedList();
            const trimmed = short.trim();
            if (!list.includes(trimmed)) {
                list.push(trimmed);
                saveBlockedList(list);
                document.getElementById('dc-block-style')?.remove();
                applyCSSBlocking();
                hideBlockedElements();
                alert('차단되었습니다: ' + trimmed);
            }
        }
    });

    // 우클릭한 URL 저장
    document.addEventListener('contextmenu', function (e) {
        const target = e.target;
        let url = '';
        if (target.tagName === 'IMG') {
            url = target.src;
        } else if (target.tagName === 'VIDEO') {
            url = target.getAttribute('data-src') || target.src;
        }

        if (url) {
            GM_setValue('__temp_block_candidate', url);
        }
    });

    // 초기 실행
    applyCSSBlocking();

    // 동적 이미지 대응
    const observer = new MutationObserver(() => hideBlockedElements());
    observer.observe(document.documentElement, { childList: true, subtree: true });

    // 로딩 후 한번 더 (혹시 누락된 경우)
    window.addEventListener('load', hideBlockedElements);
})();