Humoruniv Simple Blind

간편한 블라인드 강화 기능

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         Humoruniv Simple Blind
// @namespace    http://tampermonkey.net/
// @author       십갈
// @version      2.9
// @description  간편한 블라인드 강화 기능
// @match        https://web.humoruniv.com/*
// @exclude      https://web.humoruniv.com/board/humor/list.html?table=face*
// @exclude      https://web.humoruniv.com/board/humor/list.html?table=fashion*
// @exclude      https://web.humoruniv.com/cr/cr_list.html*
// @exclude      https://web.humoruniv.com/board/humor/report_ok.html?*
// @exclude      https://web.humoruniv.com/board/humor/cash_info.html?*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addValueChangeListener
// ==/UserScript==

(function () {
    'use strict';

    // Prevent the script from running in iframes
    if (window.self !== window.top) {
        return;
    }

    const memosKey = 'userMemos';
    const memoVisibilityKey = 'memoVisibility';
    let memos = GM_getValue(memosKey, []);
    let memoVisible = GM_getValue(memoVisibilityKey, true);
    let currentPage = 0;
    const memosPerPage = 5;

    // Create memo container
    const memoContainer = document.createElement('div');
    memoContainer.style.position = 'fixed';
    memoContainer.style.top = '10px';
    memoContainer.style.right = '10px';
    memoContainer.style.width = '200px';
    memoContainer.style.border = '1px solid #ccc';
    memoContainer.style.backgroundColor = '#f9f9f9';
    memoContainer.style.zIndex = '10000';
    memoContainer.style.padding = '10px';
    memoContainer.style.boxShadow = '0px 0px 10px rgba(0, 0, 0, 0.1)';
    memoContainer.style.maxHeight = '300px';
    memoContainer.style.overflow = 'auto';
    memoContainer.style.display = memoVisible ? 'block' : 'none';
    memoContainer.style.borderRadius = '8px';

    // Create memo input
    const memoInput = document.createElement('input');
    memoInput.type = 'text';
    memoInput.style.width = 'calc(100% - 22px)';
    memoInput.style.marginBottom = '10px';
    memoInput.style.border = '2px solid #007BFF'; // Blue border
    memoInput.style.backgroundColor = '#E9F7FF';  // Light blue background
    memoInput.style.padding = '5px';              // Add padding for better visibility
    memoInput.style.borderRadius = '4px';         // Rounded corners
    memoContainer.appendChild(memoInput);

    // Create add button
    const addButton = document.createElement('button');
    addButton.textContent = '추가';
    addButton.style.marginRight = '10px';
    addButton.style.padding = '5px 10px';
    addButton.style.backgroundColor = '#007BFF';
    addButton.style.color = 'white';
    addButton.style.border = 'none';
    addButton.style.borderRadius = '4px';
    addButton.style.cursor = 'pointer';
    addButton.style.fontSize = '14px';
    memoContainer.appendChild(addButton);

    // Create save button
    const saveButton = document.createElement('button');
    saveButton.textContent = '삭제 저장';
    saveButton.style.padding = '5px 10px';
    saveButton.style.backgroundColor = '#28a745';
    saveButton.style.color = 'white';
    saveButton.style.border = 'none';
    saveButton.style.borderRadius = '4px';
    saveButton.style.cursor = 'pointer';
    saveButton.style.fontSize = '14px';
    memoContainer.appendChild(saveButton);

    // Create hide button
    const hideButton = document.createElement('button');
    hideButton.textContent = '숨기기';
    hideButton.style.padding = '5px 10px';
    hideButton.style.backgroundColor = '#6c757d';
    hideButton.style.color = 'white';
    hideButton.style.border = 'none';
    hideButton.style.borderRadius = '4px';
    hideButton.style.cursor = 'pointer';
    hideButton.style.fontSize = '14px';
    memoContainer.appendChild(hideButton);

    // Create message display
    const messageDisplay = document.createElement('div');
    messageDisplay.style.color = 'red';
    messageDisplay.style.marginBottom = '10px';
    memoContainer.appendChild(messageDisplay);

    // Create memo list container
    const memoListContainer = document.createElement('div');
    memoContainer.appendChild(memoListContainer);

    // Create pagination controls
    const paginationControls = document.createElement('div');
    paginationControls.style.display = 'flex';
    paginationControls.style.justifyContent = 'space-between';
    paginationControls.style.alignItems = 'center'; // Align items vertically
    paginationControls.style.marginTop = '10px';

    const prevButton = document.createElement('button');
    prevButton.textContent = '<<<';
    prevButton.style.padding = '5px 10px';
    prevButton.style.backgroundColor = '#007BFF';
    prevButton.style.color = 'white';
    prevButton.style.border = 'none';
    prevButton.style.borderRadius = '4px';
    prevButton.style.cursor = 'pointer';
    prevButton.style.fontSize = '14px';
    prevButton.disabled = true;
    paginationControls.appendChild(prevButton);

    const pageIndicator = document.createElement('span');
    pageIndicator.style.fontSize = '14px';
    paginationControls.appendChild(pageIndicator);

    const nextButton = document.createElement('button');
    nextButton.textContent = '>>>';
    nextButton.style.padding = '5px 10px';
    nextButton.style.backgroundColor = '#007BFF';
    nextButton.style.color = 'white';
    nextButton.style.border = 'none';
    nextButton.style.borderRadius = '4px';
    nextButton.style.cursor = 'pointer';
    nextButton.style.fontSize = '14px';
    nextButton.disabled = true;
    paginationControls.appendChild(nextButton);

    memoContainer.appendChild(paginationControls);

    // Create show button
    const showButton = document.createElement('button');
    showButton.textContent = '블라인드';
    showButton.style.position = 'fixed';
    showButton.style.top = '10px';
    showButton.style.right = '10px';
    showButton.style.padding = '10px 20px';
    showButton.style.backgroundColor = '#28a745';
    showButton.style.color = 'white';
    showButton.style.border = 'none';
    showButton.style.borderRadius = '4px';
    showButton.style.cursor = 'pointer';
    showButton.style.fontSize = '14px';
    showButton.style.display = memoVisible ? 'none' : 'block';

    // Create memo count display
    const memoCountDisplay = document.createElement('span');
    memoCountDisplay.style.position = 'fixed';
    memoCountDisplay.style.top = '40px';
    memoCountDisplay.style.right = '10px';
    memoCountDisplay.style.padding = '2px 5px';
    memoCountDisplay.style.backgroundColor = '#dc3545';
    memoCountDisplay.style.color = 'white';
    memoCountDisplay.style.borderRadius = '4px';
    memoCountDisplay.style.fontSize = '12px';
    memoCountDisplay.style.display = memoVisible ? 'none' : 'block';
    memoCountDisplay.textContent = memos.length;

    document.body.appendChild(showButton);
    document.body.appendChild(memoContainer);
    document.body.appendChild(memoCountDisplay);

    const commentBlindContainer = document.createElement('div');
    commentBlindContainer.style.position = 'fixed';
    commentBlindContainer.style.bottom = '10px';
    commentBlindContainer.style.right = '10px';
    commentBlindContainer.style.width = '200px';
    commentBlindContainer.style.border = '1px solid #ccc';
    commentBlindContainer.style.backgroundColor = '#f9f9f9';
    commentBlindContainer.style.zIndex = '10000';
    commentBlindContainer.style.padding = '10px';
    commentBlindContainer.style.boxShadow = '0px 0px 10px rgba(0, 0, 0, 0.1)';
    commentBlindContainer.style.borderRadius = '8px';
    commentBlindContainer.innerHTML = `
            <button id="showAllButton" style="padding: 5px 10px; background-color: #28a745; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px;">모두 보기</button>
            <button id="hideAllButton" style="padding: 5px 10px; background-color: #dc3545; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px;">모두 가리기</button>
        `;
    document.body.appendChild(commentBlindContainer);

    document.getElementById('showAllButton').addEventListener('click', showAll);
    document.getElementById('hideAllButton').addEventListener('click', hideAll);

    function updateMemoList() {
        memoListContainer.innerHTML = '';
        const start = currentPage * memosPerPage;
        const end = Math.min(start + memosPerPage, memos.length);
        const currentMemos = memos.slice(start, end);

        currentMemos.forEach((memo, index) => {
            const memoItem = document.createElement('div');
            memoItem.style.display = 'flex';
            memoItem.style.alignItems = 'center';
            memoItem.style.marginBottom = '5px';

            const memoCheckbox = document.createElement('input');
            memoCheckbox.type = 'checkbox';
            memoCheckbox.style.marginRight = '10px';
            memoCheckbox.style.zoom = 1.5;
            memoCheckbox.checked = true;
            memoCheckbox.addEventListener('change', () => {
                if (memoCheckbox.checked) {
                    memos[start + index] = memo;
                } else {
                    memos[start + index] = null;
                }
            });

            const memoText = document.createElement('span');
            memoText.textContent = memo;

            memoItem.appendChild(memoCheckbox);
            memoItem.appendChild(memoText);
            memoListContainer.appendChild(memoItem);
        });
    }

    function updatePaginationControls() {
        prevButton.disabled = currentPage === 0;
        nextButton.disabled = (currentPage + 1) * memosPerPage >= memos.length;
        const totalPages = Math.max(1, Math.ceil(memos.length / memosPerPage));
        pageIndicator.textContent = `${currentPage + 1} / ${totalPages}`;
    }

    function addMemo() {
        const newMemo = memoInput.value.trim(); // Use value instead of textContent
        if (newMemo === '') return;
        if (memos.includes(newMemo)) {
            if (checkboxClicked === true) {
                messageDisplay.textContent = '';
            } else {
                messageDisplay.textContent = '이미 등록된 사용자입니다.';
            }
        } else {
            messageDisplay.textContent = '';
            memos.unshift(newMemo);
            GM_setValue(memosKey, memos);
            updateMemoList();
            updatePaginationControls();
            applyFilter(); // Reapply filter to ensure new memos have the checkboxes
        }
        memoInput.value = '';
    }

    addButton.addEventListener('click', addMemo); // Pass function reference instead of calling it
    memoInput.addEventListener('keydown', (e) => {
        if (e.key === 'Enter') {
            addMemo();
        }
    });

    prevButton.addEventListener('click', () => {
        if (currentPage > 0) {
            currentPage--;
            updateMemoList();
            updatePaginationControls();
        }
    });

    nextButton.addEventListener('click', () => {
        if ((currentPage + 1) * memosPerPage < memos.length) {
            currentPage++;
            updateMemoList();
            updatePaginationControls();
        }
    });

    saveButton.addEventListener('click', () => {
        memos = memos.filter(memo => memo !== null);
        GM_setValue(memosKey, memos);
        updateMemoList();
        updatePaginationControls();
        applyFilter();
        memoCountDisplay.textContent = memos.length;
    });

    hideButton.addEventListener('click', () => {
        memoContainer.style.display = 'none';
        showButton.style.display = 'block';
        memoCountDisplay.style.display = 'block';
        GM_setValue(memoVisibilityKey, false);
    });

    showButton.addEventListener('click', () => {
        memoContainer.style.display = 'block';
        showButton.style.display = 'none';
        memoCountDisplay.style.display = 'none';
        GM_setValue(memoVisibilityKey, true);
    });

    var checkboxClicked
    function applyFilter() {
        if (window.location.href.includes('https://web.humoruniv.com/user/blind_list.html')
            || ((window.location.href.includes('st=name') || window.location.href.includes('st=subject')) && !window.location.href.includes('read.html'))) {
            return;
        }
        checkboxClicked = false;
        document.querySelectorAll('span.hu_nick_txt').forEach(span => {
            let spanText = span.textContent.trim();
            if (spanText.length === 0) {
                spanText = [...span.querySelectorAll('span')].find(child => child.textContent.length > 0).textContent.trim();
            }
            if (!span.closest('#profile_table > tbody > tr') && !span.closest('span.nick > span > span') && !span.closest('#login_box_mem > dl > dd.a > span > span > span')) {
                var toggleCheckboxHTML;
                let closestTr = span.closest('tr');
                if (closestTr) {
                    if (window.location.href.includes('list.html')) {
                        closestTr = closestTr.closest('tbody').closest('tr');
                    }
                    if (memos.includes(spanText)) {
                        const listBestBox = closestTr.querySelector('td > div#list_best_box');
                        const tdsToHide = listBestBox ? Array.from(closestTr.querySelectorAll('td')).slice(1, 3) : Array.from(closestTr.querySelectorAll('td')).slice(0, 3);
                        tdsToHide.forEach(td => {
                            if (!td.querySelector('.blind-overlay')) {
                                const overlay = document.createElement('div');
                                overlay.className = 'blind-overlay';
                                overlay.style.position = 'absolute';
                                overlay.style.top = '0';
                                overlay.style.left = '0';
                                overlay.style.width = '100%';
                                overlay.style.height = '100%';
                                overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.97)'; // Set opacity to 97%
                                overlay.style.pointerEvents = 'none';
                                td.style.position = 'relative';
                                td.appendChild(overlay);
                            }
                        });
                        // Check if checkboxes already exist
                        if (!closestTr.querySelector('.toggle-hide-checkbox')) {
                            toggleCheckboxHTML = `
                             <tz><br><input type="checkbox" class="toggle-hide-checkbox"><label>보기</label></tz>
                            `
                            if (!closestTr.querySelector('.toggle-blind-checkbox')) {
                                toggleCheckboxHTML = `
                                <tz><br><input type="checkbox" class="toggle-blind-checkbox" checked><label>블라</label></tz>
                            ` + toggleCheckboxHTML;
                            } else {
                                closestTr.querySelector('.toggle-blind-checkbox').checked = true;
                            }
                            closestTr.children[3].children[1].insertAdjacentHTML('beforeend', toggleCheckboxHTML);

                            const toggleHideCheckbox = closestTr.querySelector('.toggle-hide-checkbox');
                            if (toggleHideCheckbox && toggleHideCheckbox.getAttribute('listener') !== 'true') {
                                toggleHideCheckbox.addEventListener('change', (e) => {
                                    const elementChanged = e.target;
                                    elementChanged.setAttribute('listener', 'true')
                                    const isChecked = toggleHideCheckbox.checked;
                                    tdsToHide.forEach(td => {
                                        const overlay = td.querySelector('.blind-overlay');
                                        if (overlay) {
                                            overlay.style.display = isChecked ? 'none' : 'block';
                                        }
                                    });
                                });
                            }
                        }
                    } else if (closestTr.querySelector('.toggle-hide-checkbox')) {
                        closestTr.querySelector('tz:nth-child(2)').remove()
                        const tdsToHide = Array.from(closestTr.querySelectorAll('td')).slice(0, 3);
                        tdsToHide.forEach(td => {
                            if (td.querySelector('.blind-overlay')) {
                                td.querySelector('.blind-overlay').remove()
                            }
                        });
                        closestTr.querySelector('.toggle-blind-checkbox').checked = false;
                    } else if (!closestTr.querySelector('.toggle-blind-checkbox')) {
                        toggleCheckboxHTML = `
                                <tz><br><input type="checkbox" class="toggle-blind-checkbox"><label>블라</label></tz>
                            `;
                        closestTr.children[3].children[1].insertAdjacentHTML('beforeend', toggleCheckboxHTML);
                        closestTr.querySelector('.toggle-blind-checkbox').checked = false;

                    } else {
                        closestTr.querySelector('.toggle-blind-checkbox').checked = false;
                    }
                    const toggleBlindCheckbox = closestTr.querySelector('.toggle-blind-checkbox');
                    if (toggleBlindCheckbox && toggleBlindCheckbox.getAttribute('listener') !== 'true') {
                        toggleBlindCheckbox.addEventListener('change', (e) => {
                            checkboxClicked = true;
                            const elementChanged = e.target;
                            elementChanged.setAttribute('listener', 'true')
                            const isChecked = toggleBlindCheckbox.checked;
                            if (isChecked) {
                                const span = toggleBlindCheckbox.closest('tr').querySelector('span.hu_nick_txt');
                                let spanText = span.textContent.trim();
                                if (spanText.length === 0) {
                                    spanText = [...span.querySelectorAll('span')].find(child => child.textContent.length > 0).textContent.trim();
                                }
                                console.log(spanText);
                                memoInput.value = spanText;
                                addMemo();
                            } else {
                                memos = memos.filter(memo => memo !== spanText);
                                GM_setValue(memosKey, memos);
                                updateMemoList();
                                updatePaginationControls();
                                applyFilter();
                            }
                        });

                    }
                }
            }
        });
    }

    function showAll() {
        document.querySelectorAll('.blind-overlay').forEach(overlay => {
            overlay.style.display = 'none';
        });
        document.querySelectorAll('.toggle-hide-checkbox').forEach(checkbox => {
            checkbox.checked = true;
        });
    }

    function hideAll() {
        document.querySelectorAll('.toggle-hide-checkbox').forEach(checkbox => {
            checkbox.checked = false;
            checkbox.dispatchEvent(new Event('change'));
        });
    }

    // Initialize the memo list, pagination controls, and apply filter
    updateMemoList();
    updatePaginationControls();
    applyFilter();

    // Listen for changes to memos and re-apply filter if necessary
    GM_addValueChangeListener(memosKey, () => {
        memos = GM_getValue(memosKey, []);
        updateMemoList();
        applyFilter();
        memoCountDisplay.textContent = memos.length;
    });
})();