Auto somi

자동 복호화/국룰입력/다운

当前为 2025-05-27 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name          Auto somi
// @name:ko       자동 소미
// @namespace     http://tampermonkey.net/
// @description   자동 복호화/국룰입력/다운
// @version       new 6.1
// @author        김머시기
// @match         https://kiosk.ac/c/*
// @match         https://kio.ac/c/*
// @match         https://kone.gg/*
// @match         https://arca.live/b/*
// @match         https://mega.nz/*
// @match         https://gofile.io/d/*
// @match         https://workupload.com/*
// @match         https://drive.google.com/file/d/*
// @match         https://drive.google.com/drive/folders/*
// @match         https://drive.usercontent.google.com/download?id*
// @icon          https://lh3.google.com/u/0/d/18OVO7VmnwIuHK6Ke-z7035wKFmMKZ28W=w1854-h959-iv1
// @grant         GM.setValue
// @grant         GM.getValue
// @require       https://openuserjs.org/src/libs/sizzle/GM_config.js
// @grant         GM.registerMenuCommand
// @grant         GM_registerMenuCommand
// @grant         GM_unregisterMenuCommand
// @grant         GM_getValue
// @grant         GM_setValue
// @grant         GM.xmlHttpRequest
// @license       MIT
// @run-at        document-end
// ==/UserScript==
'use strict';
let chkp = [,,,, atob('c29taXNvZnQ='), null], Down_Option, PageLoading = [], isT = [,,], MenuID = [null, null, null], host = document.URL.split('/')[2], npw = [], pw = [atob('c29taXNvZnQ='),atob('MjAyNXNvbWlzb2Z0'),
// ================================== Settings ==========================================
// 추가하길 원하는 비밀번호 따옴표 - 쉼표로 구분해서 바로 아래줄에 넣으면 됨 ex) '1234', '2024국룰', '!국룰!'

];
PageLoading[0] = 1000;
Down_Option = 0;
// ======================================================================================

const dlsitePreview = {
    element: null,
    images: [],
    currentIndex: 0,
    isShowing: false,
    activeListener: null,
    globalKeydownListener: null,
    isEnabled: true
};

function getKoneGGContentElement() {
    if (host !== 'kone.gg') return null;
    const proseContainer = document.querySelector('div.prose-container');
    if (!proseContainer || !proseContainer.shadowRoot) return null;
    const contentDiv = proseContainer.shadowRoot.querySelector('div.dark');
    return contentDiv;
}

async function handleBlockingModals(currentHost) {
    function hideElement(selector) {
        try {
            const elements = document.querySelectorAll(selector);
            if (elements.length > 0) {
                elements.forEach(el => {
                    if (el.offsetParent !== null) {
                        el.style.setProperty('display', 'none', 'important');
                    }
                });
            }
        } catch (e) {
        }
    }

    if (currentHost === 'kone.gg') {
        const nsfwOverlayContainer = document.querySelector('div.relative.min-h-60 > div.absolute.w-full.h-full.backdrop-blur-2xl');
        if (nsfwOverlayContainer && nsfwOverlayContainer.offsetParent !== null) {
            const viewContentButton = nsfwOverlayContainer.querySelector('div.flex.gap-4 button:nth-child(2)');
            if (viewContentButton && viewContentButton.textContent?.includes('콘텐츠 보기')) {
                viewContentButton.click();
                await new Promise(resolve => setTimeout(resolve, 500));
            } else {
                const modalSelectorsKone = [
                    '.age-verification-popup',
                    '.content-overlay.block',
                ];
                modalSelectorsKone.forEach(selector => hideElement(selector));
            }
        }
    } else if (currentHost === 'arca.live') {
        const modalSelectorsArca = [
            { selector: '.adult-confirm-modal', action: 'hide' },
            { selector: '.fc-dialog', action: 'hide' },
            { selector: '#preview-block-layer', action: 'hide' },
            { selector: 'div[class*="adult-channel-confirm"]', action: 'hide' },
            { selector: 'div.modal[data-id="confirmAdult"] div.modal-footer button.btn-primary', action: 'click'},
            { selector: 'button.btn-primary.btn.text-light[data-bs-dismiss="modal"]', action: 'click' }
        ];
        modalSelectorsArca.forEach(item => {
            const elements = document.querySelectorAll(item.selector);
            elements.forEach(element => {
                if (element && element.offsetParent !== null) {
                    if (item.action === 'click') {
                        element.click();
                    } else {
                        hideElement(item.selector);
                    }
                }
            });
        });
    }
}

async function toggleDown(){
    isT[0]=!isT[0];
    if(!isT[0] && isT[1]){
        isT[1]=false;
        await GM.setValue('isT[1]', isT[1]);
    }
    await GM.setValue('isT[0]', isT[0]);
    updateDown();
    updateTab();
}

async function toggleTab(){
    isT[1]=!isT[1];
    if(!isT[0] && isT[1]){
        isT[0]=true;
        await GM.setValue('isT[0]', isT[0]);
    }
    await GM.setValue('isT[1]', isT[1]);
    updateDown();
    updateTab();
}

async function toggleDlsitePreview() {
    dlsitePreview.isEnabled = !dlsitePreview.isEnabled;
    await GM.setValue('dlsitePreviewEnabled', dlsitePreview.isEnabled);
    updateDlsitePreviewMenu();
    if (!dlsitePreview.isEnabled && dlsitePreview.isShowing) {
        hideDlsitePreview();
    }
    const allDlsiteLinks = document.querySelectorAll('a[href*="dlsite.com"]');
    allDlsiteLinks.forEach(link => {
        link.removeEventListener('mouseenter', showDlsitePreview);
        link.removeEventListener('mouseleave', hideDlsitePreview);
        delete link.dataset._dlsite_preview_hooked;
        if (dlsitePreview.isEnabled) {
            link.addEventListener('mouseenter', showDlsitePreview);
            link.dataset._dlsite_preview_hooked = '1';
        }
    });
}

function updateDown(){
    if(MenuID[0] !==null)GM_unregisterMenuCommand(MenuID[0]);
    MenuID[0]=GM_registerMenuCommand(`자동 다운로드  ${isT[0] ? 'ON' : 'OFF'}`, toggleDown, { autoClose: false, title: `자동 다운로드 ${isT[0] ? '켜짐' : '꺼짐'}`});
}

function updateTab(){
    if(MenuID[1] !==null)GM_unregisterMenuCommand(MenuID[1]);
    MenuID[1]=GM_registerMenuCommand(`자동 탭 닫기    ${isT[1] ? 'ON' : 'OFF'}`, toggleTab, { autoClose: false, title: `자동 탭 닫기 ${isT[1] ? '켜짐' : '꺼짐'}`});
}

function updateDlsitePreviewMenu(){
    if(MenuID[2] !==null)GM_unregisterMenuCommand(MenuID[2]);
    MenuID[2]=GM_registerMenuCommand(`DLsite 미리보기 ${dlsitePreview.isEnabled ? 'ON' : 'OFF'}`, toggleDlsitePreview, { autoClose: false, title: `DLsite 미리보기 ${dlsitePreview.isEnabled ? '켜짐' : '꺼짐'}`});
}

function decodeContent(target, reg) {
    try {
        if (!target || !target.innerHTML) return;
        const originalHTML = target.innerHTML;
        let newHTML = originalHTML;

        const matches = [...originalHTML.matchAll(reg)];
        if (matches.length === 0) return;

        for (const match of matches) {
            let encodedString = match[0];
            let decodedUri = encodedString;
            try {
                let previousDecodedUri = "";
                while (decodedUri && typeof decodedUri === 'string' &&
                       !decodedUri.toLowerCase().startsWith('http://') &&
                       !decodedUri.toLowerCase().startsWith('https://') &&
                       decodedUri.length > 10 && decodedUri.length < 1000) {
                    if (previousDecodedUri === decodedUri) break;
                    previousDecodedUri = decodedUri;
                    try {
                        decodedUri = atob(decodedUri);
                    } catch (e) {
                        decodedUri = previousDecodedUri;
                        break;
                    }
                }

                if (decodedUri && typeof decodedUri === 'string' &&
                    (decodedUri.toLowerCase().startsWith('http://') || decodedUri.toLowerCase().startsWith('https://'))) {
                    try {
                        const parsedUrl = new URL(decodedUri);
                        if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
                            continue;
                        }

                        const textSpan = document.createElement('span');
                        textSpan.textContent = decodedUri;
                        const safeLinkText = textSpan.innerHTML;

                        const safeHref = decodedUri.replace(/"/g, '&quot;');

                        const linkHTML = `<a href="${safeHref}" target="_blank" rel="noreferrer" style="color:#007bff; text-decoration:underline; word-break:break-all;">${safeLinkText}</a>`;
                        newHTML = newHTML.replace(encodedString, linkHTML);

                    } catch (urlError) {
                    }
                }
            } catch (e) {
            }
        }

        if (target.innerHTML !== newHTML) {
            target.innerHTML = newHTML;
        }
    } catch (e) {
    }
}

function doDec() {
    if (chkp[3] !== chkp[4]) return;

    let targets = [];

    if (host === 'arca.live') {
        targets = [
            document.querySelector('body div.article-body > div.fr-view.article-content'),
            ...document.querySelectorAll('div.article-comment#comment div.comment-content, div.article-comment div.comment-content')
        ].filter(el => el !== null);
    } else if (host === 'kone.gg') {
        const koneContentElement = getKoneGGContentElement();
        const comments = document.querySelectorAll('p.text-sm.whitespace-pre-wrap');
        const listItems = document.querySelectorAll('ol.list-decimal li p');
        targets = [koneContentElement, ...comments, ...listItems].filter(el => el !== null);
    }

    if (targets.length === 0 || (targets.length === 1 && !targets[0])) return;

    for (const target of targets) {
        if (!target) continue;
        const links = target.querySelectorAll('a');
        links.forEach(a => {
            a.setAttribute('rel', 'noreferrer');
        });

        decodeContent(target, /aHR0c[0-9A-Za-z+/=]{8,}/g);
        decodeContent(target, /YUhSMG[0-9A-Za-z+/=]{8,}/g);
        decodeContent(target, /WVVoU[0-9A-Za-z+/=]{8,}/g);
        decodeContent(target, /V1ZWb[0-9A-Za-z+/=]{8,}/g);

        doDlsiteContextAwareForElement(target);
    }

    if (host === 'kone.gg') {
        const koneContentElement = getKoneGGContentElement();
        if (!koneContentElement || koneContentElement.querySelector('.dlsite-link-appended')) return;

        const titleText = document.querySelector('h1.flex, h1.text-xl')?.textContent || '';
        const commentTexts = [...document.querySelectorAll('p.text-sm.whitespace-pre-wrap')]
            .map(el => el.textContent || '')
            .join(' ');
        const bodyText = koneContentElement?.textContent || '';

        const allText = `${titleText} ${bodyText} ${commentTexts}`;
        const rjMatches = [...allText.matchAll(/\b(RJ|rj|Rj|rJ)([0-9]{5,10})\b/g)];
        const rjSet = new Set(rjMatches.map(m => m[1].toUpperCase() + m[2]));

        if (rjSet.size === 1) {
            const onlyCode = [...rjSet][0];
            const linkUrl = `https://www.dlsite.com/maniax/work/=/product_id/${onlyCode}.html`;

            const finalLine = document.createElement('div');
            finalLine.className = 'dlsite-link-appended';
            finalLine.style.marginTop = '1em';
            finalLine.innerHTML = `<a href="${linkUrl}" target="_blank" rel="noreferrer" style="color:#1e90ff; font-weight:bold;">▶ ${onlyCode} DLsite 링크</a>`;
            koneContentElement.appendChild(finalLine);

            const appendedLink = finalLine.querySelector('a[href*="dlsite.com"]');
            if (appendedLink && !appendedLink.dataset._dlsite_preview_hooked) {
                if (dlsitePreview.isEnabled) {
                    appendedLink.addEventListener('mouseenter', showDlsitePreview);
                    appendedLink.addEventListener('mouseleave', hideDlsitePreview, { once: true });
                }
                appendedLink.dataset._dlsite_preview_hooked = '1';
            }
        }
    }
}



function updateDlsitePreviewImage() {
    if (!dlsitePreview.element || dlsitePreview.images.length === 0) {
        return;
    }

    dlsitePreview.element.innerHTML = '';
    const img = document.createElement('img');
    img.src = dlsitePreview.images[dlsitePreview.currentIndex];
    img.style.maxWidth = '100%';
    img.style.maxHeight = '100%';
    dlsitePreview.element.appendChild(img);
}

function handleDlsiteKeydown(event) {
    if (!dlsitePreview.element || !dlsitePreview.isShowing) {
        return;
    }

    if (dlsitePreview.images.length <= 1) {
    }

    if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
        event.stopPropagation();
        event.preventDefault();

        if (event.key === 'ArrowLeft') {
            dlsitePreview.currentIndex = (dlsitePreview.currentIndex - 1 + dlsitePreview.images.length) % dlsitePreview.images.length;
        } else if (event.key === 'ArrowRight') {
            dlsitePreview.currentIndex = (dlsitePreview.currentIndex + 1) % dlsitePreview.images.length;
        }
        updateDlsitePreviewImage();
    }
}


function showDlsitePreview(event) {
    if (!dlsitePreview.isEnabled) return;

    const link = event.target;
    const productUrl = link.href;

    if (dlsitePreview.isShowing) return;
    dlsitePreview.isShowing = true;

    dlsitePreview.element = document.createElement('div');
    dlsitePreview.element.style.cssText = `
        position: fixed;
        z-index: 9999;
        background-color: rgba(0, 0, 0, 0.8);
        border: 1px solid #333;
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
        max-width: 480px;
        max-height: 480px;
        overflow: hidden;
        pointer-events: auto;
        display: flex;
        justify-content: center;
        align-items: center;
    `;
    document.body.appendChild(dlsitePreview.element);

    moveDlsitePreview(event);
    document.addEventListener('mousemove', moveDlsitePreview);

    GM.xmlHttpRequest({
        method: "GET",
        url: productUrl,
        onload: function(response) {
            const parser = new DOMParser();
            const doc = parser.parseFromString(response.responseText, "text/html");
            const imgContainer = doc.querySelector('.product-slider');

            if (!imgContainer) {
                dlsitePreview.element.textContent = '미리보기를 불러올 수 없습니다.';
                dlsitePreview.element.style.color = '#fff';
                return;
            }

            dlsitePreview.images = [];
            dlsitePreview.currentIndex = 0;

            const imageDataElements = imgContainer.querySelectorAll('.product-slider-data > div[data-src]');
            imageDataElements.forEach(dataEl => {
                const imageUrl = dataEl.dataset.src;
                if (
                    imageUrl &&
                    !imageUrl.includes('data:image') &&
                    !imageUrl.toLowerCase().startsWith('javascript:') &&
                    !imageUrl.includes('/resize/')
                ) {
                    dlsitePreview.images.push(imageUrl);
                }
            });

            if (dlsitePreview.images.length > 0) {
                updateDlsitePreviewImage();
                if (dlsitePreview.globalKeydownListener) {
                    document.removeEventListener('keydown', dlsitePreview.globalKeydownListener);
                }
                dlsitePreview.globalKeydownListener = handleDlsiteKeydown;
                document.addEventListener('keydown', dlsitePreview.globalKeydownListener);
            } else {
                dlsitePreview.element.textContent = '이미지를 찾을 수 없습니다.';
                dlsitePreview.element.style.color = '#fff';
            }
        },
        onerror: function() {
            dlsitePreview.element.textContent = '미리보기 로드 실패';
            dlsitePreview.element.style.color = '#fff';
        }
    });

    link.addEventListener('mouseleave', hideDlsitePreview);
}


function moveDlsitePreview(event) {
    if (dlsitePreview.element) {
        dlsitePreview.element.style.top = `${event.clientY + 15}px`;
        dlsitePreview.element.style.left = `${event.clientX + 15}px`;
    }
}

function hideDlsitePreview() {
    if (dlsitePreview.element) {
        document.body.removeChild(dlsitePreview.element);
        dlsitePreview.element = null;
        dlsitePreview.isShowing = false;
        dlsitePreview.images = [];
        dlsitePreview.currentIndex = 0;
    }
    document.removeEventListener('mousemove', moveDlsitePreview);
    if (dlsitePreview.globalKeydownListener) {
        document.removeEventListener('keydown', dlsitePreview.globalKeydownListener);
        dlsitePreview.globalKeydownListener = null;
    }
}

function doDlsiteContextAwareForElement(element) {
    if (!element) return;

    const existingAppendedLink = element.querySelector('.dlsite-link-appended');
    if (existingAppendedLink) {
        existingAppendedLink.remove();
    }

    const keywordPattern = /(꺼|거|퍼|RJ|rj|Rj|rJ|VJ|vj|Vj|vJ|DL|dl|Dl|dL)[\s:()\[\]#-]*([0-9]{5,10})/g;
    const fullRJPattern = /\b(RJ|rj|Rj|rJ|VJ|vj|Vj|vJ|퍼|꺼|거|DL|dl|Dl|dL)([0-9]{5,10})\b/g;

    const textContent = element.textContent || '';

    const allFoundCodes = new Map();
    let match;

    const combinedRegex = new RegExp(`${keywordPattern.source}|${fullRJPattern.source}`, 'gi');
    while ((match = combinedRegex.exec(textContent)) !== null) {
        const prefix = (match[1] || match[3] || '').toLowerCase();
        const code = match[2] || match[4];
        if (code && !allFoundCodes.has(code)) {
            allFoundCodes.set(code, { prefix: prefix, originalText: match[0] });
        }
    }

    let tempHTML = element.innerHTML;

    allFoundCodes.forEach(({ prefix, originalText }, code) => {
        const mappedPrefix = ['vj', 'vJ', 'Vj', 'VJ', '퍼'].includes(prefix) ? 'VJ'
                           : ['rj', 'rJ', 'Rj', 'RJ', '꺼', '거', 'dl', 'dL', 'Dl', 'DL'].includes(prefix) ? 'RJ'
                           : prefix.toUpperCase();
        const fullCode = `${mappedPrefix}${code}`;
        const linkUrl = `https://www.dlsite.com/maniax/work/=/product_id/${fullCode}.html`;

        const textSpan = document.createElement('span');
        textSpan.textContent = originalText;
        const safeLinkText = textSpan.innerHTML;

        const escapedOriginalText = originalText.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
        const replaceRegex = new RegExp(`(${escapedOriginalText})(?![^<]*>|[^<>]*<\/a>)`, 'g');

        const safeHref = linkUrl.replace(/"/g, '&quot;');

        tempHTML = tempHTML.replace(
            replaceRegex,
            `<a href="${safeHref}" target="_blank" rel="noreferrer" style="color:#1e90ff;">${safeLinkText}</a>`
        );
    });

    if (element.innerHTML !== tempHTML) {
        element.innerHTML = tempHTML;
    }

    const dlsiteLinks = element.querySelectorAll('a[href*="dlsite.com"]');
    dlsiteLinks.forEach(link => {
        if (!link.dataset._dlsite_preview_hooked) {
            if (dlsitePreview.isEnabled) {
                link.addEventListener('mouseenter', showDlsitePreview);
                link.addEventListener('mouseleave', hideDlsitePreview, { once: true });
            }
            link.dataset._dlsite_preview_hooked = '1';
        }
    });
}

async function chkPW(){
    chkp[3]=await GM.getValue('chkp[3]');
    isT[0]=await GM.getValue('isT[0]', true);
    isT[1]=await GM.getValue('isT[1]', false);
    dlsitePreview.isEnabled = await GM.getValue('dlsitePreviewEnabled', true);
    updateDown();
    updateTab();
    updateDlsitePreviewMenu();

    if(host=='arca.live' || host=='kone.gg'){
        if(chkp[3] !=chkp[4]){
            const chk=prompt('국룰을 입력해주세요');
            if(chk?.toLowerCase()==chkp[4]) {
                await GM.setValue('chkp[3]', chkp[4]);
            } else {
                GM.setValue('chkp[3]', false);
                alert('국룰이 틀렸습니다');
            }
        }
    }
}

async function inputPW() {
    let inputElem = document.querySelector(chkp[0]), btnElem = document.querySelector(chkp[1]);
    if (!inputElem ) {
        if (isT[0] === true && !document.querySelector('.files-list, #download-section')) {
            await new Promise(res => setTimeout(res, PageLoading[1] || 1000)).then(DBtn);
        }
        return;
    }

    const combinedPw = [...new Set([...pw, ...npw])];

    if (chkp[3] == chkp[4]) {
        try {
            for (let i = 0; i < combinedPw.length; i++) {
                if (!combinedPw[i]) continue;
                if (!inputElem) break;

                inputElem.value = combinedPw[i];

                if (host == 'kio.ac') {
                    inputElem.dispatchEvent(new Event('input', { bubbles: true }));
                    inputElem.dispatchEvent(new Event('change', { bubbles: true }));
                    await new Promise(res => setTimeout(res, 50));
                    if(btnElem) btnElem.click();
                } else {
                    if(btnElem) btnElem.click();
                    else {
                        const enterEvent = new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', keyCode: 13, which: 13, bubbles: true });
                        inputElem.dispatchEvent(enterEvent);
                    }
                }

                await new Promise(res => setTimeout(res, 800));

                const successIndicator = document.querySelector('.files-list, #download-section, .download-link, .btn-download, .main-button-download');
                const errorIndicator = document.querySelector('.text-error, .text-red-500, .error-message, .incorrect-password, [class*="error"], [id*="error"]');

                if (successIndicator && successIndicator.offsetParent !== null) {
                    break;
                } else if (errorIndicator && errorIndicator.offsetParent !== null) {
                    if (inputElem) inputElem.value = '';
                }
            }
            if (isT[0] == true) {
                await new Promise(res => setTimeout(res, PageLoading[1] || 1000)).then(DBtn);
            }

        } catch (e) {
            if (isT[0] == true) {
                await new Promise(res => setTimeout(res, PageLoading[1] || 1000)).then(DBtn);
            }
        }
    }
}

async function kioskdone(){
    try {
        await new Promise(res=> setTimeout(res, 3000));
        for(let i=0, jj=0; jj!=1; i++){
            await new Promise(res=> setTimeout(res, 1000));
            if(document.querySelector('.flex.flex-row.text-xs.justify-between div:nth-child(2)').innerText=='done'){
                await new Promise(res=> setTimeout(res, 2000)).then(() => window.close());
                jj++;
            }
        }
    } catch(e){
        if(isT[1]==true && isT[2]==true) window.close();
    }
}

async function DBtn(){
    if(isT[0] !== true) return;

    if(host === 'mega.nz') {
        try {
            const resumeButton = document.querySelector('.mega-button.positive.resume.js-resume-download');
            if (resumeButton) {
                resumeButton.click();
                await new Promise(res => setTimeout(res, 500));
            }

            const standardDownloadButton = document.querySelector('.mega-button.positive.js-default-download.js-standard-download');
            if (standardDownloadButton) {
                standardDownloadButton.click();
                await new Promise(res => setTimeout(res, 1000));
            }

            const continueDownloadButton = document.querySelector('.mega-button.large.positive.download.continue-download');
            if (continueDownloadButton) {
                continueDownloadButton.click();
            }
        } catch(e) {}
    } else {
        try {
            const allBtns = document.querySelectorAll(chkp[2]);
            const clickedSet = new Set();
            const validBtns = [];

            for (const btn of allBtns) {
                if (!btn || btn.offsetParent === null || btn.classList.contains('btn-disabled')) continue;

                // 중복 방지를 위한 고유 키 (예: 버튼 텍스트, 상위 td 내용, 부모 innerHTML 일부 등)
                const uniqueKey = btn.innerText.trim() + btn.closest('tr')?.innerText?.trim();
                if (!clickedSet.has(uniqueKey)) {
                    clickedSet.add(uniqueKey);
                    validBtns.push(btn);
                }
            }

            for (const btn of validBtns) {
                btn.click();
                await new Promise(res => setTimeout(res, 200));
            }
        } catch(e){}
    }

    if (isT[1] === true && isT[2] === true) {
        const delay = 1500;
        if (host === 'kiosk.ac') {
            setTimeout(kioskdone, delay);
        } else {
            setTimeout(() => window.close(), delay + 1000);
        }
    }
}


async function FindPW(){
    let atc;
    if (host === 'arca.live') {
        atc = document.querySelector('body div.article-body > div.fr-view.article-content');
    } else if (host === 'kone.gg') {
        atc = getKoneGGContentElement();
    }

    if (!atc || !atc.innerHTML) return;

    let tempContent = atc.innerHTML;
    tempContent=tempContent.replace(/ /g, ' ').replace(/( ){2,}/g, ' ');
    tempContent=tempContent.replace(/국룰/g, 'ㄱㄹ');

    let regexx=/(대문자)/;

    if(regexx.test(tempContent)) {
        const smpeopleUpper = atob('U01QRU9QTEU=');
        if (npw.indexOf(smpeopleUpper) === -1) {
            npw.push(smpeopleUpper);
        }
    }

    function processPasswordRegex(reg){
        let currentLoopContent = tempContent;
        const processedTexts = new Set();

        while(true){
            const matchResult = reg.exec(currentLoopContent);
            if (!matchResult) break;

            let matchedText = matchResult[0];
            if (processedTexts.has(matchedText)) {
                currentLoopContent = currentLoopContent.replace(matchedText, `__SKIPPED_${Math.random().toString(36).substring(2, 10)}__`);
                continue;
            }

            let DECed = matchedText.replace(/(ㄱㄹ)/g, '국룰');
            let DECedd = DECed.replace(/\s|[+]|(은|는|이|가)|(전부)|(대문자로)|(대문자)|(비밀번호)|(패스워드)|(비번)|(ㅂㅂ)|(암호)|(ㅇㅎ)|(키오스크맘)|(키오스크)|(입니다)|(이고)|(이며)|(임다)|(같다)|(처럼)|(틀리다)|(입니다요)/g, '');
            DECedd = DECedd.split(/[(입)(임)(이)(이)(이)(입)(임)(같)(처)(틀)]/g)[0];
            DECedd = DECedd.replace(/[<>]/g, '');

            let dat;
            if (host === 'arca.live') {
                const dateEl = document.querySelector('.article-info .date .body');
                if (dateEl && typeof dateEl.innerText === 'string' && dateEl.innerText.trim() !== '') {
                    dat = dateEl.innerText.split(' ')[0];
                } else {
                    dat = undefined;
                }
            }

            let regexa=/(오늘)|(날짜)|(날자)/g;
            if(dat && regexa.test(DECedd)){
                DECedd=DECedd.replace(regexa, '');
                const dateParts = dat.split(/\-/g);
                if (dateParts.length === 3) {
                    const year = dateParts[0].slice(2);
                    const month = dateParts[1];
                    const day = dateParts[2];
                    let dateFormats=[month + day, month + '-' + day, year + month + day, dat.replace(/-/g,'')];
                    for(let k=0;k<dateFormats.length;k++){
                        const finalPw = DECedd.replace(/국룰/g,chkp[4]) + dateFormats[k];
                        if(finalPw.length > 2 && npw.indexOf(finalPw)=='-1') {
                            npw.push(finalPw);
                        }
                    }
                }
            } else {
                const finalPw = DECedd.replace(/국룰/g,chkp[4]);
                if(finalPw && finalPw.length > 2 && npw.indexOf(finalPw)=='-1') {
                    npw.push(finalPw);
                }
            }
            processedTexts.add(matchedText);
            currentLoopContent = currentLoopContent.replace(matchedText, `__PROCESSED_${Math.random().toString(36).substring(2, 15)}__`);
        }
    }
    processPasswordRegex(/[(<p>\s*)*]{0,}[ㄱ-ㅣ가-힣0-9A-Za-z\s~`!^\_+@\#$%&=]{0,}(ㄱㄹ){1,1}[ㄱ-ㅣ가-힣0-9A-Za-z\s~`!^\_+@\#$%&=]{0,}[(\s*</p>)*]{0,}/);
    await GM.setValue('npw', npw);
}

function waitForKoneContentAndProcess() {
    let attempts = 0;
    const maxAttempts = 20;
    const checkInterval = setInterval(async () => {
        attempts++;
        await handleBlockingModals(host);

        const atc = getKoneGGContentElement();
        const titleEl = [...document.querySelectorAll('h1.flex, h1.text-xl')].find(el =>
            el.textContent?.match(/RJ[0-9]{6,10}|VJ[0-9]{6,10}/i)
        );

        const hasBase64 = atc && /aHR0c|YUhSMG|WVVoU|V1ZWb/.test(atc.textContent || '');

        if (atc && (titleEl || hasBase64) && (atc.textContent || '').length > 10) {
            clearInterval(checkInterval);
            await FindPW();
            setTimeout(doDec, 200);
        } else if (attempts >= maxAttempts) {
            clearInterval(checkInterval);
        }
    }, 200);
}

async function loadNpw() {
    const saved = await GM.getValue('npw');
    if (Array.isArray(saved)) {
        npw = [...new Set([...npw, ...saved])];
    }
}

async function initHostSpecificSettings() {
    await loadNpw();

    const hostConfigs = {
        'kio.ac': {
            chkpSelectors: [
                '.overflow-auto.max-w-full.flex-grow.p-1 input:nth-of-type(1)',
                '.flex.flex-col-reverse button:nth-of-type(1)',
                'td.align-middle > div.flex > button[type="button"].inline-flex'
            ],
            isT2: true,
            pageLoadDelay: 2000,
            inputPwDelay: 1000
        },
        'kiosk.ac': {
            chkpSelectors: [
                '.input.shadow-xl.flex-grow',
                '.btn.btn-ghost.w-full.mt-2.rounded-md',
                '.dropdown.group > button'
            ],
            isT2: Down_Option === 0,
            pageLoadDelay: 200,
            inputPwDelay: 1000
        },
        'mega.nz': {
            chkpSelectors: [
                '#password-decrypt-input',
                '.mega-button.positive.fm-dialog-new-folder-button.decrypt-link-button',
                '.mega-button.positive.js-default-download.js-standard-download'
            ],
            isT2: false,
            pageLoadDelay: 2500,
            inputPwDelay: 1500
        },
        'workupload.com': {
            chkpSelectors: [
                '#passwordprotected_file_password',
                '#passwordprotected_file_submit',
                'a.btn.btn-prio[href*="/file/"]'
            ],
            isT2: Down_Option === 0,
            pageLoadDelay: 2000,
            inputPwDelay: 500
        },
        'drive.google.com': {
            chkpSelectors: [],
            isT2: true,
            pageLoadDelay: 1000,
            inputPwDelay: 500
        },
        'drive.usercontent.google.com': {
            chkpSelectors: [
                null,
                null,
                'form[method="POST"] button[type="submit"], input[type="submit"][value="다운로드"], button.jfk-button-action'
            ],
            isT2: true,
            pageLoadDelay: 0,
            inputPwDelay: 0
        },
        'gofile.io': {
            chkpSelectors: [
                '#filesErrorPasswordInput',
                '#filesErrorPasswordButton',
                'button.btn-download, a.btn-download, #rowFolderCenter button[data-bs-target="#filesList"] + div .btn-outline-secondary'
            ],
            isT2: true,
            pageLoadDelay: 1500,
            inputPwDelay: 0
        }
    };

    const config = hostConfigs[host];
    if (config) {
        chkp[0] = config.chkpSelectors[0];
        chkp[1] = config.chkpSelectors[1];
        chkp[2] = config.chkpSelectors[2];
        isT[2] = config.isT2;
        PageLoading[1] = config.pageLoadDelay;

        if (host === 'drive.google.com') {
            if(document.URL.includes('/file/d/')){
                const fileId = document.URL.split('/d/')[1].split('/')[0];
                if (fileId) {
                    window.location.href=`https://drive.usercontent.google.com/download?id=${fileId}&export=download&authuser=0`;
                }
            } else if(document.URL.includes('/drive/folders/')){
                await new Promise(res => setTimeout(res, (PageLoading[0] || 1000) + 1500));
                if(isT[0] === true) {
                    const downloadAllButton = document.querySelector('div[aria-label="모두 다운로드"], div[data-tooltip="모두 다운로드"]');
                    if (downloadAllButton) {
                        downloadAllButton.click();
                    } else {
                        const firstItemDownloadButton = document.querySelector('div[role="gridcell"][data-is-shared="false"] div[aria-label*="다운로드"]');
                        if(firstItemDownloadButton) {
                            firstItemDownloadButton.click();
                        }
                    }
                }
                await new Promise(res => setTimeout(res, (PageLoading[0] || 1000) + 3500)).then(() => {
                    if(isT[0] === true) DBtn();
                });
            }
        } else if (host === 'drive.usercontent.google.com') {
            await new Promise(res => setTimeout(res, 100)).then(() => {
                if(isT[0] === true) DBtn();
            });
        } else {
            await new Promise(res => setTimeout(res, (PageLoading[0] || 1000) + config.inputPwDelay)).then(inputPW);
        }
    }
}


(async () => {
    await chkPW();
    await handleBlockingModals(host);

    if (host === 'arca.live') {
        await FindPW();
        setTimeout(doDec, 200);
    } else if (host === 'kone.gg') {
        waitForKoneContentAndProcess();
    }

    await initHostSpecificSettings();
})();

(function () {
    if (location.host !== 'kone.gg') return;

    function hookDecodeTriggerOnButton() {
        const buttonsToHook = [
            document.querySelector('div.flex.items-center.justify-between.p-4 button[data-slot="button"]'),
            [...document.querySelectorAll('button.flex.cursor-pointer.items-center')]
                .find(button => button.textContent?.trim() === '댓글 더 불러오기'),
        ].filter(b => b instanceof Element && b.dataset._somi_hooked !== '1');

        buttonsToHook.forEach(button => {
            button.dataset._somi_hooked = '1';
            button.addEventListener('click', async () => {
                await handleBlockingModals(host);
                setTimeout(async () => {
                    await FindPW();
                    setTimeout(doDec, 200);
                }, 500);
            });
        });
    }

    hookDecodeTriggerOnButton();

    const observer = new MutationObserver(async (mutationsList) => {
        for (const mutation of mutationsList) {
            if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                hookDecodeTriggerOnButton();
                await handleBlockingModals(host);
                setTimeout(async () => {
                    await FindPW();
                    setTimeout(doDec, 200);
                }, 100);
            } else if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                await handleBlockingModals(host);
                setTimeout(async () => {
                    await FindPW();
                    setTimeout(doDec, 200);
                }, 100);
            }
        }
        await handleBlockingModals(host);
    });
    observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['class', 'style'] });
})();


(function () {
    if (location.host !== 'kone.gg') return;

    let lastUrl = location.href;
    let mainProcessingIntervalId = null;

    const observer = new MutationObserver(async () => {
        const currentUrl = location.href;
        if (currentUrl !== lastUrl) {
            lastUrl = currentUrl;
            if (mainProcessingIntervalId) {
                clearInterval(mainProcessingIntervalId);
            }
            await handleBlockingModals(host);
            observeAndRunKoneFunctions();
        }
    });

    observer.observe(document.body, { childList: true, subtree: true });

    async function observeAndRunKoneFunctions() {
        const start = Date.now();
        const timeout = 8000;

        if (mainProcessingIntervalId) {
            clearInterval(mainProcessingIntervalId);
        }

        mainProcessingIntervalId = setInterval(async () => {
            await handleBlockingModals(host);
            const atc = getKoneGGContentElement();
            const hasText = atc && (atc.textContent || '').length > 20;
            const hasEncoded = atc && /aHR0c|YUhSMG|WVVoU|V1ZWb/.test(atc.textContent || '');
            const hasDlsiteLink = atc && atc.querySelector('a[href*="dlsite.com"]');
            const comments = document.querySelectorAll('p.text-sm.whitespace-pre-wrap');
            let hasEncodedComments = false;
            for(const comment of comments) {
                if (/aHR0c|YUhSMG|WVVoU|V1ZWb/.test(comment.textContent || '')) {
                    hasEncodedComments = true;
                    break;
                }
            }


            if (atc && (hasText && (hasEncoded || hasDlsiteLink)) || hasEncodedComments) {
                clearInterval(mainProcessingIntervalId);
                mainProcessingIntervalId = null;
                await FindPW();
                setTimeout(doDec, 200);
            }

            if (Date.now() - start > timeout) {
                clearInterval(mainProcessingIntervalId);
                mainProcessingIntervalId = null;
            }
        }, 200);
    }

    (async () => {
        await handleBlockingModals(host);
        observeAndRunKoneFunctions();
    })();
})();