Auto somi

자동 복호화/국룰입력/다운(Kiosk, Mega, GoogleDrive, goFile)

// ==UserScript==
// @name          Auto somi
// @name:ko       자동 소미
// @namespace     http://tampermonkey.net/
// @description   자동 복호화/국룰입력/다운(Kiosk, Mega, GoogleDrive, goFile)
// @version       new 5.0
// @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], 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
};

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();
}

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 decodeContent(target, reg) {
    try {
        if (!target || !target.innerHTML) return;
        const original = target.innerHTML;
        const matches = [...original.matchAll(reg)];
        if (matches.length === 0) return;

        let result = original;
        for (const match of matches) {
            let encoded = match[0];
            let decoded = encoded;
            try {
                while (decoded && typeof decoded === 'string' && !decoded.startsWith('http') && decoded.length > 10 && decoded.length < 1000) {
                    let tempDecoded = atob(decoded);
                    if (tempDecoded === decoded) break;
                    decoded = tempDecoded;
                }
                if (decoded && typeof decoded === 'string' && decoded.startsWith('http')) {
                    const linkHTML = `<a href="${decoded}" target="_blank" rel="noreferrer" style="color:#007bff; text-decoration:underline; word-break:break-all;">${decoded}</a>`;
                    result = result.replace(encoded, linkHTML);
                }
            } catch (e) {
            }
        }
        if (target.innerHTML !== result) {
            target.innerHTML = result;
        }
    } 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.max-w-xl.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);
    }
}

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) {
    const link = event.target;
    const productUrl = link.href;

    if (dlsitePreview.element) {
        document.body.removeChild(dlsitePreview.element);
        dlsitePreview.element = null;
        if (dlsitePreview.globalKeydownListener) {
            document.removeEventListener('keydown', dlsitePreview.globalKeydownListener);
            dlsitePreview.globalKeydownListener = null;
        }
    }

    dlsitePreview.element = document.createElement('div');
    dlsitePreview.element.style.cssText = `
        position: fixed;
        top: ${event.clientY + 15}px;
        left: ${event.clientX + 15}px;
        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: none;
        display: flex;
        justify-content: center;
        align-items: center;
    `;
    document.body.appendChild(dlsitePreview.element);
    dlsitePreview.isShowing = true;

    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.includes('/resize/')) {
                    if (!dlsitePreview.images.includes(imageUrl)) {
                        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(error) {
            dlsitePreview.element.textContent = '미리보기 로드 실패';
            dlsitePreview.element.style.color = '#fff';
        }
    });

    document.addEventListener('mousemove', moveDlsitePreview);
    link.addEventListener('mouseleave', hideDlsitePreview, { once: true });
}

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 tempElement = document.createElement('div');
    tempElement.innerHTML = 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 link = `https://www.dlsite.com/maniax/work/=/product_id/${fullCode}.html`;

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

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

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

    const dlsiteLinks = element.querySelectorAll('a[href*="dlsite.com"]');
    dlsiteLinks.forEach(link => {
        if (!link.dataset._dlsite_preview_hooked) {
            link.addEventListener('mouseenter', showDlsitePreview);
            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);
    updateDown();
    updateTab();

    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, 2000));
            }

            const continueDownloadButton = document.querySelector('.mega-button.large.positive.download.continue-download');
            if (continueDownloadButton) {
                continueDownloadButton.click();
            }
        } catch(e) {
        }
    } else {
        try {
            let btns = document.querySelectorAll(chkp[2]);
            let delayMultiplier = (PageLoading[0] || 1000) + 600;
            if(btns.length > 0){
                for(let i = 0; i < btns.length; i++){
                    await new Promise(res => setTimeout(res, i * delayMultiplier));
                    btns[i].click();
                }
            }
        } catch(e){}
    }

    if(isT[1]==true && isT[2]==true){
        let btnsForDelay = document.querySelectorAll(chkp[2]);
        let totalDelay = (btnsForDelay.length > 0) ? (btnsForDelay.length * ((PageLoading[0] || 1000) + 600) + 700) : 1300;
        if(host=='kiosk.ac'){
            new Promise(res => setTimeout(res, totalDelay)).then(kioskdone);
        } else {
            new Promise(res => setTimeout(res, totalDelay + 1000)).then(() => window.close());
        }
    }
}

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.max-h-full.flex-grow.p-1 input:nth-of-type(1)', '.flex.flex-col-reverse button:nth-of-type(1)', '.p-2.align-middle .flex.align-middle button:nth-of-type(1)'],
            isT2: true,
            pageLoadDelay: 3500,
            inputPwDelay: 2000
        },
        '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: 4000,
            inputPwDelay: 1800
        },
        'kiosk.ac': {
            chkpSelectors: ['.input.shadow-xl.flex-grow', '.btn.btn-ghost.w-full.mt-2.rounded-md', Down_Option == 2 ? '.flex.justify-between.w-full .flex.gap-2 .btn.btn-ghost' : '#vexplorer-body .hover\\:bg-neutral .dropdown button, #vexplorer-body > div > div > div.flex.justify-between.w-full > div.flex.gap-2 > button:not(.btn-disabled)'],
            isT2: Down_Option == 0,
            pageLoadDelay: 3000,
            inputPwDelay: 0
        },
        'workupload.com': {
            chkpSelectors: ['#passwordprotected_file_password', '#passwordprotected_file_submit', 'a.btn.btn-prio[href*="/file/"]'],
            isT2: Down_Option == 0,
            pageLoadDelay: 2000,
            inputPwDelay: 0
        },
        'drive.google.com': {
            chkpSelectors: [],
            isT2: true,
            pageLoadDelay: 1,
            inputPwDelay: 0
        },
        '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: 3000,
            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.max-w-xl.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();
    })();
})();