// ==UserScript==
// @name         종합 웹 크롤러 UI
// @namespace    http://tampermonkey.net/
// @version      4.2
// @description  다양한 검색 엔진의 여러 페이지를 자동으로 크롤링하고, 결과를 한국어 UI로 표시합니다. 추가 기능 포함.
// @match        *://www.google.com/search*
// @match        *://www.bing.com/search*
// @match        *://duckduckgo.com/*
// @match        *://search.naver.com/search*
// @match        *://search.yahoo.com/search*
// @match        *://www.baidu.com/s*
// @match        *://www.yandex.com/search*
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// @grant        GM_download
// @grant        GM_notification
// @connect      *
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // 크롤링 상태 저장을 위한 키
    const STORAGE_KEY = 'comprehensiveWebCrawlerData_v4_2';

    // 크롤링 상태
    let crawlerData = {
        isRunning: false,
        progress: 0,
        results: [],
        currentPage: 1,
        totalPages: 1, // 임의 큰 수으로 설정
        searchEngine: '',
        query: '',
        visitedUrls: [],
        logs: [],
        startTime: null
    };

    // 광고 제외 패턴 정의
    const adPatterns = [
        /google\.com\/ads/,
        /bing\.com\/ads/,
        /yahoo\.com\/ads/,
        /doubleclick\.net/,
        /adservice\.google\.com/,
        /ads\.yandex\.net/,
        /safeframe/,
        /banner/,
        /promo/,
        /advertisement/,
        /adsbygoogle/,
        /googletagmanager/,
        /ads\.bing\.com/,
        /googleadservices\.com/
    ];

    // 지원하는 검색 엔진 정의
    const searchEngines = {
        'google.com': {
            name: 'Google',
            parseResults: function(doc, results) {
                const items = doc.querySelectorAll('div.g');
                items.forEach(item => {
                    const titleElement = item.querySelector('h3');
                    const linkElement = item.querySelector('a');
                    const descElement = item.querySelector('.IsZvec, .VwiC3b, .aCOpRe');
                    const title = titleElement ? titleElement.innerText.trim() : '제목 없음';
                    const url = linkElement ? linkElement.href.trim() : '링크 없음';
                    const description = descElement ? descElement.innerText.trim() : '설명 없음';
                    if (!crawlerData.visitedUrls.includes(url) && !isAd(url)) {
                        results.push({name: title, url: url, description: description});
                        crawlerData.visitedUrls.push(url);
                        addLog(`수집됨: ${url}`);
                    }
                });
            },
            getNextPageURL: function(doc) {
                const next = doc.querySelector('#pnnext');
                return next ? next.href : null;
            }
        },
        'bing.com': {
            name: 'Bing',
            parseResults: function(doc, results) {
                const items = doc.querySelectorAll('li.b_algo');
                items.forEach(item => {
                    const titleElement = item.querySelector('h2');
                    const linkElement = item.querySelector('a');
                    const descElement = item.querySelector('.b_caption p');
                    const title = titleElement ? titleElement.innerText.trim() : '제목 없음';
                    const url = linkElement ? linkElement.href.trim() : '링크 없음';
                    const description = descElement ? descElement.innerText.trim() : '설명 없음';
                    if (!crawlerData.visitedUrls.includes(url) && !isAd(url)) {
                        results.push({name: title, url: url, description: description});
                        crawlerData.visitedUrls.push(url);
                        addLog(`수집됨: ${url}`);
                    }
                });
            },
            getNextPageURL: function(doc) {
                const next = doc.querySelector('a.sb_pagN');
                return next ? next.href : null;
            }
        },
        'duckduckgo.com': {
            name: 'DuckDuckGo',
            parseResults: function(doc, results) {
                const items = doc.querySelectorAll('div.result');
                items.forEach(item => {
                    const titleElement = item.querySelector('h2');
                    const linkElement = item.querySelector('a.result__a');
                    const descElement = item.querySelector('.result__snippet');
                    const title = titleElement ? titleElement.innerText.trim() : '제목 없음';
                    const url = linkElement ? linkElement.href.trim() : '링크 없음';
                    const description = descElement ? descElement.innerText.trim() : '설명 없음';
                    if (!crawlerData.visitedUrls.includes(url) && !isAd(url)) {
                        results.push({name: title, url: url, description: description});
                        crawlerData.visitedUrls.push(url);
                        addLog(`수집됨: ${url}`);
                    }
                });
            },
            getNextPageURL: function(doc) {
                const next = doc.querySelector('.result--more__btn');
                return next ? next.href : null;
            }
        },
        'search.naver.com': {
            name: 'Naver',
            parseResults: function(doc, results) {
                const items = doc.querySelectorAll('li.sh_blog_top');
                items.forEach(item => {
                    const titleElement = item.querySelector('a.sh_blog_title');
                    const linkElement = item.querySelector('a.sh_blog_title');
                    const descElement = item.querySelector('dd.sh_blog_passage');
                    const title = titleElement ? titleElement.innerText.trim() : '제목 없음';
                    const url = linkElement ? linkElement.href.trim() : '링크 없음';
                    const description = descElement ? descElement.innerText.trim() : '설명 없음';
                    if (!crawlerData.visitedUrls.includes(url) && !isAd(url)) {
                        results.push({name: title, url: url, description: description});
                        crawlerData.visitedUrls.push(url);
                        addLog(`수집됨: ${url}`);
                    }
                });
            },
            getNextPageURL: function(doc) {
                const next = doc.querySelector('a.btn_next');
                return next ? next.href : null;
            }
        },
        'search.yahoo.com': {
            name: 'Yahoo',
            parseResults: function(doc, results) {
                const items = doc.querySelectorAll('div.dd.algo');
                items.forEach(item => {
                    const titleElement = item.querySelector('h3.title');
                    const linkElement = item.querySelector('a');
                    const descElement = item.querySelector('div.compText.aAbs');
                    const title = titleElement ? titleElement.innerText.trim() : '제목 없음';
                    const url = linkElement ? linkElement.href.trim() : '링크 없음';
                    const description = descElement ? descElement.innerText.trim() : '설명 없음';
                    if (!crawlerData.visitedUrls.includes(url) && !isAd(url)) {
                        results.push({name: title, url: url, description: description});
                        crawlerData.visitedUrls.push(url);
                        addLog(`수집됨: ${url}`);
                    }
                });
            },
            getNextPageURL: function(doc) {
                const next = doc.querySelector('a.next');
                return next ? next.href : null;
            }
        },
        'baidu.com': {
            name: 'Baidu',
            parseResults: function(doc, results) {
                const items = doc.querySelectorAll('div.result');
                items.forEach(item => {
                    const titleElement = item.querySelector('h3.t');
                    const linkElement = item.querySelector('a');
                    const descElement = item.querySelector('div.c-abstract');
                    const title = titleElement ? titleElement.innerText.trim() : '제목 없음';
                    const url = linkElement ? linkElement.href.trim() : '링크 없음';
                    const description = descElement ? descElement.innerText.trim() : '설명 없음';
                    if (!crawlerData.visitedUrls.includes(url) && !isAd(url)) {
                        results.push({name: title, url: url, description: description});
                        crawlerData.visitedUrls.push(url);
                        addLog(`수집됨: ${url}`);
                    }
                });
            },
            getNextPageURL: function(doc) {
                const next = doc.querySelector('a.n');
                return next ? next.href : null;
            }
        },
        'yandex.com': {
            name: 'Yandex',
            parseResults: function(doc, results) {
                const items = doc.querySelectorAll('li.serp-item');
                items.forEach(item => {
                    const titleElement = item.querySelector('h2 a');
                    const linkElement = item.querySelector('h2 a');
                    const descElement = item.querySelector('div.Text span');
                    const title = titleElement ? titleElement.innerText.trim() : '제목 없음';
                    const url = linkElement ? linkElement.href.trim() : '링크 없음';
                    const description = descElement ? descElement.innerText.trim() : '설명 없음';
                    if (!crawlerData.visitedUrls.includes(url) && !isAd(url)) {
                        results.push({name: title, url: url, description: description});
                        crawlerData.visitedUrls.push(url);
                        addLog(`수집됨: ${url}`);
                    }
                });
            },
            getNextPageURL: function(doc) {
                const next = doc.querySelector('a.link_theme_next');
                return next ? next.href : null;
            }
        }
        // 추가적인 검색 엔진을 여기에 정의할 수 있습니다.
    };

    // 현재 페이지의 호스트명으로 검색 엔진 결정
    const hostname = window.location.hostname;
    let currentEngine = null;
    for (let key in searchEngines) {
        if (hostname.includes(key)) {
            currentEngine = searchEngines[key];
            break;
        }
    }

    if (!currentEngine) {
        console.log('지원하지 않는 검색 엔진입니다.');
        return;
    }

    // UI 생성 함수
    function createUI() {
        const ui = document.createElement('div');
        ui.id = 'crawler-ui';
        ui.innerHTML = `
            <div id="crawler-header">🕸️ 웹 크롤러</div>
            <div id="crawler-controls">
                <button id="start-btn" title="크롤링 시작">시작</button>
                <button id="stop-btn" title="크롤링 중지">중지</button>
                <button id="reset-btn" title="크롤링 초기화">초기화</button>
                <button id="toggle-log-btn" title="로그 표시/숨기기">로그 토글</button>
            </div>
            <div id="crawler-progress">진행률: 0.00% | 예상 시간: 계산 중...</div>
            <div id="crawler-status">상태: 중지됨</div>
            <div id="crawler-results">
                <table id="results-table">
                    <thead>
                        <tr>
                            <th>사이트 이름</th>
                            <th>주소</th>
                            <th>설명</th>
                            <th>HTML 보기</th>
                        </tr>
                    </thead>
                    <tbody></tbody>
                </table>
            </div>
            <div id="crawler-logs" style="display:none;">
                <h3>로그</h3>
                <div id="logs-container" style="max-height: 150px; overflow-y: scroll; border: 1px solid #ccc; padding: 5px;"></div>
                <button id="download-log-btn" title="로그 다운로드">로그 다운로드</button>
            </div>
            <div id="html-viewer" style="display:none;">
                <h3>사이트 HTML</h3>
                <pre id="html-content"></pre>
                <button id="close-html-viewer-btn">닫기</button>
            </div>
        `;
        document.body.appendChild(ui);

        // UI 스타일링
        GM_addStyle(`
            #crawler-ui {
                position: fixed;
                top: 20px;
                right: 20px;
                width: 400px;
                max-height: 80vh;
                overflow: auto;
                background: rgba(255, 255, 255, 0.95);
                border: 2px solid #333;
                border-radius: 10px;
                padding: 15px;
                box-shadow: 0 4px 12px rgba(0,0,0,0.3);
                z-index: 10000;
                font-family: '맑은 고딕', 'Malgun Gothic', Arial, sans-serif;
                font-size: 14px;
                resize: both;
                overflow: auto;
            }
            #crawler-header {
                font-size: 20px;
                font-weight: bold;
                margin-bottom: 15px;
                text-align: center;
                color: #333;
                cursor: move;
                user-select: none;
            }
            #crawler-controls {
                display: flex;
                justify-content: space-between;
                margin-bottom: 15px;
                flex-wrap: wrap;
            }
            #crawler-controls button {
                padding: 8px 12px;
                cursor: pointer;
                border: none;
                border-radius: 5px;
                background-color: #007BFF;
                color: white;
                font-size: 14px;
                transition: background-color 0.3s;
                flex: 1;
                margin: 5px;
            }
            #crawler-controls button:hover {
                background-color: #0056b3;
            }
            #crawler-progress, #crawler-status {
                margin-bottom: 10px;
                font-weight: bold;
                color: #555;
                text-align: left;
            }
            #results-table {
                width: 100%;
                border-collapse: collapse;
                margin-bottom: 15px;
            }
            #results-table th, #results-table td {
                border: 1px solid #ddd;
                padding: 8px;
                text-align: left;
                word-break: break-word;
            }
            #results-table th {
                background-color: #f2f2f2;
                font-size: 14px;
            }
            #results-table tr:nth-child(even){background-color: #f9f9f9;}
            #results-table tr:hover {background-color: #ddd;}
            #results-table button {
                padding: 5px 10px;
                cursor: pointer;
                border: none;
                border-radius: 3px;
                background-color: #17a2b8;
                color: white;
                transition: background-color 0.3s;
            }
            #results-table button:hover {
                background-color: #117a8b;
            }
            #crawler-logs h3 {
                margin-bottom: 10px;
            }
            #logs-container p {
                margin: 5px 0;
                font-size: 12px;
            }
            #download-log-btn {
                background-color: #28a745;
                margin-top: 10px;
            }
            #download-log-btn:hover {
                background-color: #218838;
            }
            #html-viewer {
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                width: 80%;
                height: 80%;
                background: rgba(255, 255, 255, 0.98);
                border: 2px solid #333;
                border-radius: 10px;
                padding: 20px;
                box-shadow: 0 4px 12px rgba(0,0,0,0.5);
                z-index: 10001;
                overflow: auto;
                font-family: '맑은 고딕', 'Malgun Gothic', Arial, sans-serif;
            }
            #html-viewer h3 {
                margin-bottom: 10px;
                text-align: center;
                color: #333;
            }
            #html-viewer pre {
                white-space: pre-wrap;
                word-wrap: break-word;
                background-color: #f9f9f9;
                padding: 10px;
                border: 1px solid #ccc;
                border-radius: 5px;
                max-height: 70vh;
                overflow-y: scroll;
            }
            #close-html-viewer-btn {
                display: block;
                margin: 20px auto 0;
                padding: 8px 16px;
                cursor: pointer;
                border: none;
                border-radius: 5px;
                background-color: #dc3545;
                color: white;
                font-size: 14px;
                transition: background-color 0.3s;
            }
            #close-html-viewer-btn:hover {
                background-color: #c82333;
            }
        `);
    }

    // UI 업데이트 함수
    function updateUI() {
        document.getElementById('crawler-progress').innerText = `진행률: ${crawlerData.progress.toFixed(2)}% | 예상 시간: ${estimateTime()}`;
        document.getElementById('crawler-status').innerText = `상태: ${crawlerData.isRunning ? '실행 중' : '중지됨'}`;

        const tbody = document.querySelector('#results-table tbody');
        tbody.innerHTML = '';
        crawlerData.results.forEach(item => {
            const row = document.createElement('tr');
            row.innerHTML = `
                <td>${item.name}</td>
                <td><a href="${item.url}" target="_blank">${item.url}</a></td>
                <td>${item.description}</td>
                <td><button class="view-html-btn" data-url="${item.url}">HTML 보기</button></td>
            `;
            tbody.appendChild(row);
        });

        // HTML 보기 버튼 이벤트 추가
        document.querySelectorAll('.view-html-btn').forEach(button => {
            button.onclick = () => {
                const url = button.getAttribute('data-url');
                showHTML(url);
            };
        });

        // 로그 업데이트
        const logsContainer = document.getElementById('logs-container');
        logsContainer.innerHTML = '';
        crawlerData.logs.forEach(log => {
            const logEntry = document.createElement('p');
            logEntry.textContent = log;
            logsContainer.appendChild(logEntry);
        });
    }

    // 로그 추가 함수
    function addLog(message) {
        const timestamp = new Date().toLocaleString();
        const logMessage = `[${timestamp}] ${message}`;
        crawlerData.logs.push(logMessage);
        if (crawlerData.logs.length > 100) {
            crawlerData.logs.shift(); // 로그 100개 제한
        }
        updateUI();
        console.log(logMessage);
    }

    // HTML 보기 함수
    function showHTML(url) {
        fetchHTML(url).then(htmlContent => {
            if (htmlContent) {
                const viewer = document.getElementById('html-viewer');
                const content = document.getElementById('html-content');
                content.textContent = htmlContent;
                viewer.style.display = 'block';
            } else {
                addLog(`HTML을 가져오는 데 실패했습니다: ${url}`);
                alert('HTML을 가져오는 데 실패했습니다.');
            }
        });
    }

    // HTML 가져오기 함수
    async function fetchHTML(url) {
        addLog(`HTML을 가져오는 중: ${url}`);
        try {
            const response = await fetch(url);
            if (response.ok) {
                const text = await response.text();
                addLog(`HTML을 성공적으로 가져왔습니다: ${url}`);
                return text;
            } else {
                addLog(`HTML 가져오기 실패: ${url} (Status: ${response.status})`);
                return null;
            }
        } catch (error) {
            addLog(`HTML 가져오기 오류: ${url} (${error})`);
            return null;
        }
    }

    // 사이트 정보 가져오기 함수
    function getSiteInfo(url) {
        addLog(`사이트 정보를 가져오는 중: ${url}`);
        GM_xmlhttpRequest({
            method: "GET",
            url: url,
            onload: function(response) {
                if (response.status === 200) {
                    const parser = new DOMParser();
                    const doc = parser.parseFromString(response.responseText, 'text/html');
                    const title = doc.querySelector('title') ? doc.querySelector('title').innerText.trim() : '제목 없음';
                    const metaDesc = doc.querySelector('meta[name="description"]') ? doc.querySelector('meta[name="description"]').getAttribute('content').trim() : '설명 없음';
                    addLog(`사이트 정보 - 제목: ${title}, 설명: ${metaDesc}`);
                } else {
                    addLog(`사이트 정보 가져오기 실패: ${url} (Status: ${response.status})`);
                }
            },
            onerror: function(err) {
                addLog(`사이트 정보 가져오기 오류: ${url}`);
            }
        });
    }

    // 광고 제외 함수
    function isAd(url) {
        return adPatterns.some(pattern => pattern.test(url));
    }

    // 크롤링 시작 함수
    function startCrawling() {
        if (crawlerData.isRunning) return;

        // 현재 검색어 추출
        let searchBox = document.querySelector('input[name="q"], input[name="p"], input[name="query"]');
        const query = searchBox ? searchBox.value.trim() : '';
        if (!query) {
            alert('검색어를 입력해주세요.');
            return;
        }

        crawlerData = {
            isRunning: true,
            progress: 0,
            results: [],
            currentPage: 1,
            totalPages: 1, // 임의 큰 수으로 설정
            searchEngine: currentEngine.name,
            query: query,
            visitedUrls: [],
            logs: [],
            startTime: new Date()
        };

        // 상태 저장
        GM_setValue(STORAGE_KEY, JSON.stringify(crawlerData));

        addLog(`크롤링 시작: "${query}" (${currentEngine.name})`);
        updateUI();

        // 현재 페이지 크롤링
        crawlCurrentPage();
    }

    // 크롤링 중지 함수
    function stopCrawling() {
        if (!crawlerData.isRunning) return;
        crawlerData.isRunning = false;
        GM_setValue(STORAGE_KEY, JSON.stringify(crawlerData));
        addLog('크롤링 중지');
        updateUI();
    }

    // 크롤링 초기화 함수
    function resetCrawling() {
        logResetTopics(crawlerData.query);
        crawlerData = {
            isRunning: false,
            progress: 0,
            results: [],
            currentPage: 1,
            totalPages: 1, // 임의 큰 수으로 설정
            searchEngine: '',
            query: '',
            visitedUrls: [],
            logs: [],
            startTime: null
        };
        GM_setValue(STORAGE_KEY, JSON.stringify(crawlerData));
        addLog('크롤링 초기화됨');
        updateUI();
    }

    // 크롤링 초기화 시 주제 기록
    function logResetTopics(query) {
        const resetTopicsKey = 'crawlerResetTopics_v4_2';
        let topics = GM_getValue(resetTopicsKey, []);
        topics.push({query: query, timestamp: new Date().toLocaleString()});
        GM_setValue(resetTopicsKey, topics);
    }

    // 크롤링 함수
    function crawlCurrentPage() {
        if (!crawlerData.isRunning) return;

        addLog(`현재 페이지 크롤링: ${crawlerData.currentPage}`);

        // 현재 페이지의 검색 결과를 파싱
        currentEngine.parseResults(document, crawlerData.results);

        // 진행률 업데이트
        crawlerData.progress = (crawlerData.currentPage / crawlerData.totalPages) * 100;
        if (crawlerData.progress > 100) crawlerData.progress = 100;

        // 예상 시간 업데이트
        const estimatedTime = estimateTime();
        addLog(`진행률 업데이트: ${crawlerData.progress.toFixed(2)}% | 예상 시간: ${estimatedTime}`);

        updateUI();

        // 사이트 정보 가져오기
        crawlerData.results.forEach(item => {
            getSiteInfo(item.url);
        });

        // 다음 페이지 URL 가져오기
        const nextPageURL = currentEngine.getNextPageURL(document);

        if (nextPageURL && crawlerData.isRunning) {
            crawlerData.currentPage += 1;
            GM_setValue(STORAGE_KEY, JSON.stringify(crawlerData));
            addLog(`다음 페이지로 이동: ${nextPageURL}`);
            setTimeout(() => {
                window.location.href = nextPageURL;
            }, 100); // 100ms 후 다음 페이지로 이동
        } else {
            // 크롤링 완료
            crawlerData.isRunning = false;
            crawlerData.progress = 100;
            GM_setValue(STORAGE_KEY, JSON.stringify(crawlerData));
            addLog('크롤링 완료되었습니다.');
            updateUI();
            alert('크롤링이 완료되었습니다.');
        }
    }

    // 예상 시간 계산 함수
    function estimateTime() {
        if (!crawlerData.startTime) return '계산 중...';
        const elapsed = (new Date() - new Date(crawlerData.startTime)) / 1000; // 초
        const progress = crawlerData.progress / 100;
        if (progress === 0) return '계산 중...';
        const estimatedTotal = elapsed / progress;
        const remaining = estimatedTotal - elapsed;
        return remaining > 0 ? `${remaining.toFixed(2)}초 남음` : '예상 시간 계산 불가';
    }

    // 창을 드래그하여 위치 변경할 수 있게 하는 함수
    function makeDraggable() {
        const ui = document.getElementById('crawler-ui');
        let isDragging = false;
        let startX, startY, initialLeft, initialTop;

        const header = document.getElementById('crawler-header');
        header.addEventListener('mousedown', (e) => {
            isDragging = true;
            startX = e.clientX;
            startY = e.clientY;
            const rect = ui.getBoundingClientRect();
            initialLeft = rect.left;
            initialTop = rect.top;
            document.body.style.userSelect = 'none';
        });

        document.addEventListener('mousemove', (e) => {
            if (isDragging) {
                const dx = e.clientX - startX;
                const dy = e.clientY - startY;
                ui.style.left = `${initialLeft + dx}px`;
                ui.style.top = `${initialTop + dy}px`;
            }
        });

        document.addEventListener('mouseup', () => {
            isDragging = false;
            document.body.style.userSelect = 'auto';
        });
    }

    // 로그 토글 함수
    function toggleLogs() {
        const logsDiv = document.getElementById('crawler-logs');
        if (logsDiv.style.display === 'none') {
            logsDiv.style.display = 'block';
        } else {
            logsDiv.style.display = 'none';
        }
    }

    // 로그 다운로드 함수
    function downloadLogs() {
        const logs = crawlerData.logs.join('\n');
        GM_download({
            url: 'data:text/plain;charset=utf-8,' + encodeURIComponent(logs),
            name: 'crawler_logs.txt',
            saveAs: true
        });
    }

    // HTML 보기 닫기 버튼 이벤트
    function setupHTMLViewer() {
        const closeBtn = document.getElementById('close-html-viewer-btn');
        closeBtn.addEventListener('click', () => {
            const viewer = document.getElementById('html-viewer');
            viewer.style.display = 'none';
            document.getElementById('html-content').textContent = '';
        });
    }

    // 광고 제외 필터링
    function filterAds() {
        crawlerData.results = crawlerData.results.filter(item => !isAd(item.url));
    }

    // UI 생성
    createUI();
    makeDraggable();
    setupHTMLViewer();

    // 이벤트 리스너 등록
    document.getElementById('start-btn').addEventListener('click', () => {
        if (!crawlerData.isRunning) {
            crawlerData.startTime = new Date();
        }
        startCrawling();
    });
    document.getElementById('stop-btn').addEventListener('click', stopCrawling);
    document.getElementById('reset-btn').addEventListener('click', resetCrawling);
    document.getElementById('toggle-log-btn').addEventListener('click', toggleLogs);
    document.getElementById('download-log-btn').addEventListener('click', downloadLogs);

    // 페이지 새로고침 시 크롤링 초기화
    window.addEventListener('beforeunload', () => {
        if (crawlerData.isRunning) {
            crawlerData.isRunning = false;
            GM_setValue(STORAGE_KEY, JSON.stringify(crawlerData));
        }
    });

    // 크롤링 상태 복원 및 진행
    function restoreState() {
        const savedData = GM_getValue(STORAGE_KEY);
        if (savedData) {
            crawlerData = JSON.parse(savedData);
            if (crawlerData.isRunning) {
                addLog('이전 크롤링 상태가 감지되어 재개합니다.');
                updateUI();
                setTimeout(() => {
                    crawlCurrentPage();
                }, 100); // 100ms 후 크롤링 재개
            } else {
                updateUI();
            }
        } else {
            updateUI();
        }
    }

    restoreState();

})();html 가져오는데 실패했다고 뜨네? 빨리 수정해야지? 너랑 대체 몇 분 이러고 있는거냐?