아카라이브 만화 뷰어 모드

아카라이브의 이미지를 만화처럼 볼 수 있는 뷰어 모드를 추가합니다

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         아카라이브 만화 뷰어 모드
// @namespace    https://arca.live/
// @version      1.0
// @description  아카라이브의 이미지를 만화처럼 볼 수 있는 뷰어 모드를 추가합니다
// @author       ㅇㅇ
// @match        https://arca.live/b/*
// @grant        GM_setValue
// @grant        GM_getValue
// @run-at       document-end
// ==/UserScript==

(function () {
    'use strict';

    // 중복 실행 방지 변수
    let isInitialized = false;    // 스타일 추가 - 아카라이브 디자인에 맞춘 개선된 GUI
    const style = document.createElement('style');
    style.textContent = `        #manga-viewer-container {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: #1a1a1a;
            z-index: 10000;
            display: none;
            flex-direction: column;
            color: #ffffff;
            font-family: -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Pretendard Variable", Pretendard, Roboto, "Noto Sans", "Segoe UI", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", sans-serif;
        }
        
        #manga-viewer-header {
            height: 60px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 0 20px;
            background: rgba(26, 26, 26, 0.95);
            backdrop-filter: blur(15px);
            border-bottom: 1px solid rgba(255, 255, 255, 0.08);
            box-shadow: 0 1px 8px rgba(0, 0, 0, 0.2);
            z-index: 10001;
            position: relative;
        }
          #manga-viewer-title {
            font-size: 14px;
            font-weight: 500;
            max-width: 40%;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            cursor: default;
            transition: color 0.2s;
            display: flex;
            align-items: center;
            color: #f8f9fa;
        }
        
        #manga-viewer-title.has-series {
            cursor: pointer;
        }
        
        #manga-viewer-title.has-series:hover {
            color: #4facfe;
        }
        
        #manga-viewer-title.has-series:after {
            content: "";
            display: inline-block;
            margin-left: 8px;
            border: solid #f8f9fa;
            border-width: 0 2px 2px 0;
            padding: 2px;
            transform: rotate(45deg);
            -webkit-transform: rotate(45deg);
            transition: transform 0.2s, border-color 0.2s;
        }
        
        #manga-viewer-title.has-series:hover:after {
            border-color: #4facfe;
        }
        
        #manga-viewer-title.has-series.open:after {
            transform: rotate(-135deg);
            -webkit-transform: rotate(-135deg);
            margin-top: 2px;
        }
        
        #manga-viewer-counter {
            font-size: 14px;
            font-weight: 500;
            position: absolute;
            left: 50%;
            transform: translateX(-50%);
            color: #f8f9fa;
            background: rgba(0, 0, 0, 0.4);
            padding: 4px 12px;
            border-radius: 12px;
            backdrop-filter: blur(8px);
        }
        
        #manga-viewer-close {
            cursor: pointer;
            padding: 8px 16px;
            background: rgba(248, 249, 250, 0.1);
            border: 1px solid rgba(248, 249, 250, 0.2);
            border-radius: 8px;
            font-size: 12px;
            font-weight: 500;
            color: #f8f9fa;
            transition: all 0.2s ease;
            backdrop-filter: blur(8px);
        }
        
        #manga-viewer-close:hover {
            background: rgba(248, 249, 250, 0.15);
            border-color: rgba(248, 249, 250, 0.3);
            transform: translateY(-1px);
        }
          #manga-viewer-content {
            flex: 1;
            display: flex;
            justify-content: center;
            align-items: center;
            overflow: hidden;
            position: relative;
        }
        
        #manga-viewer-image {
            max-width: 100%;
            max-height: 100%;
            object-fit: contain;
            transition: transform 0.2s ease-out;
        }
          .manga-viewer-nav {
            position: absolute;
            top: 0;
            height: 100%;
            width: 50%;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            opacity: 0;
            transition: opacity 0.3s, background 0.3s;
            color: rgba(255, 255, 255, 0.8);
            font-size: 2rem;
            font-weight: bold;
        }
        
        .manga-viewer-nav:hover {
            opacity: 0.15;
            background: radial-gradient(circle at center, rgba(79, 172, 254, 0.1) 0%, transparent 70%);
        }
        
        #manga-viewer-prev {
            left: 0;
            background: linear-gradient(to right, rgba(79, 172, 254, 0.05), transparent);
        }
        
        #manga-viewer-next {
            right: 0;
            background: linear-gradient(to left, rgba(79, 172, 254, 0.05), transparent);
        }
        
        .manga-nav-hint {
            opacity: 0;
            transition: opacity 0.5s;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
        }        #manga-drawer-toggle {
            position: absolute;
            bottom: 20px;
            right: 20px;
            width: 50px;
            height: 50px;
            background: linear-gradient(135deg, rgba(79, 172, 254, 0.9) 0%, rgba(0, 242, 254, 0.9) 100%);
            border-radius: 50%;
            cursor: pointer;
            z-index: 10002;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 20px;
            color: white;
            box-shadow: 0 4px 20px rgba(79, 172, 254, 0.4);
            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            border: 2px solid rgba(255, 255, 255, 0.1);
            backdrop-filter: blur(10px);
        }
        
        #manga-drawer-toggle:hover {
            background: linear-gradient(135deg, rgba(67, 163, 245, 0.95) 0%, rgba(0, 212, 230, 0.95) 100%);
            transform: scale(1.1);
            box-shadow: 0 6px 25px rgba(79, 172, 254, 0.6);
            border-color: rgba(255, 255, 255, 0.2);
        }
        
        #manga-drawer-toggle.active {
            transform: rotate(180deg) scale(1.05);
            background: linear-gradient(135deg, rgba(255, 100, 100, 0.9) 0%, rgba(255, 50, 150, 0.9) 100%);
            box-shadow: 0 4px 20px rgba(255, 100, 100, 0.4);
        }
          #manga-drawer {
            position: fixed;
            bottom: 0;
            left: 0;
            width: 100%;
            height: 0;
            background: linear-gradient(135deg, rgba(30, 30, 50, 0.95) 0%, rgba(40, 40, 60, 0.95) 100%);
            backdrop-filter: blur(15px);
            border-top: 2px solid rgba(79, 172, 254, 0.3);
            z-index: 10001;
            overflow-y: hidden;
            transition: height 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            display: flex;
            flex-direction: row;
            flex-wrap: nowrap;
            padding: 0;
            overflow-x: auto;
            scrollbar-width: thin;
            scrollbar-color: rgba(79, 172, 254, 0.5) rgba(30, 30, 50, 0.3);
            justify-content: flex-start;
            align-items: center;
            box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.3);
        }
            scrollbar-width: thin;
            scrollbar-color: rgba(79, 172, 254, 0.5) rgba(30, 30, 50, 0.3);
            justify-content: flex-start;
            align-items: center;
            box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.3);
        }
        
        #manga-drawer.active {
            height: 120px;
            padding: 10px;
        }
        
        .manga-drawer-item {
            height: calc(100% - 20px);
            min-width: auto;
            max-height: 100px;
            margin-right: 10px;
            cursor: pointer;
            border: 2px solid transparent;
            transition: border-color 0.3s;
            position: relative;
            display: flex;
            align-items: center;
        }
        
        .manga-drawer-item.active {
            border-color: #f5f5f5;
        }
        
        .manga-drawer-item:hover {
            border-color: #666;
        }
        
        .manga-drawer-img {
            height: 100%;
            width: auto;
            object-fit: contain;
            max-height: 100%;
        }
        
        .manga-drawer-number {
            position: absolute;
            bottom: 0;
            left: 0;
            background-color: rgba(0, 0, 0, 0.7);
            padding: 2px 5px;
            font-size: 10px;
        }
        
        /* 스크롤바 스타일 */
        #manga-drawer::-webkit-scrollbar {
            height: 6px;
        }
        
        #manga-drawer::-webkit-scrollbar-thumb {
            background-color: #666;
            border-radius: 3px;
        }
        
        #manga-drawer::-webkit-scrollbar-track {
            background-color: #333;
        }
        
        /* 뷰어 모드에서 불필요한 텍스트 제거 */
        body.manga-viewer-active .notification-text,
        body.manga-viewer-active #removeAllBtn,
        body.manga-viewer-active .noti-text,
        body.manga-viewer-active .article-info,
        body.manga-viewer-active .btn-text {
            display: none !important;
            visibility: hidden !important;
        }
        
        /* 뷰어 모드 안에서 보여줄 요소만 남기기 */
        body.manga-viewer-active * {
            visibility: hidden;
        }
        
        body.manga-viewer-active #manga-viewer-container,
        body.manga-viewer-active #manga-viewer-container * {
            visibility: visible;
        }
        
        /* 모바일 대응 */
        @media (max-width: 768px) {
            #manga-drawer.active {
                height: 90px;
                padding-top: 18px;
            }
            
            .manga-drawer-item {
                height: calc(100% - 20px);
                max-height: 70px;
                min-width: auto;
            }
            
            #manga-viewer-counter {
                font-size: 12px;
            }
            
            #manga-drawer-toggle {
                width: 36px;
                height: 36px;
                font-size: 16px;
                bottom: 15px;
                right: 15px;
            }
        }
          /* 시리즈 목록 스타일 */
        #manga-series-popup {
            position: absolute;
            top: 45px;
            left: 20px;
            background-color: rgba(30, 30, 30, 0.95);
            border-radius: 6px;
            padding: 15px;
            z-index: 10004;
            max-width: 85%;
            max-height: 80vh;
            overflow-y: auto;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
            display: none;
            min-width: 300px;
        }
        
        #manga-series-popup.active {
            display: block;
        }
        
        #manga-series-title {
            font-size: 16px;
            font-weight: bold;
            margin-bottom: 10px;
            padding-bottom: 5px;
            border-bottom: 1px solid #555;
            color: #fff;
        }
        
        .manga-series-item {
            padding: 10px;
            margin-bottom: 8px;
            border-radius: 4px;
            cursor: pointer;
            transition: background-color 0.2s;
            color: #ddd;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            font-size: 14px;
        }
        
        .manga-series-item:hover {
            background-color: rgba(80, 80, 80, 0.6);
        }
        
        .manga-series-item.current {
            background-color: rgba(90, 90, 150, 0.4);
            color: #fff;
            font-weight: bold;
        }
        
        #manga-viewer-title {
            cursor: default;
            transition: color 0.2s;
            display: flex;
            align-items: center;
        }
        
        #manga-viewer-title.has-series {
            cursor: pointer;
        }
        
        #manga-viewer-title.has-series:hover {
            color: #a9d7ff;
        }
        
        #manga-viewer-title.has-series:after {
            content: "";
            display: inline-block;
            margin-left: 5px;
            border: solid #fff;
            border-width: 0 2px 2px 0;
            padding: 3px;
            transform: rotate(45deg);
            -webkit-transform: rotate(45deg);
            transition: transform 0.2s, border-color 0.2s;
        }
        
        #manga-viewer-title.has-series:hover:after {
            border-color: #a9d7ff;
        }
        
        #manga-viewer-title.has-series.open:after {
            transform: rotate(-135deg);
            -webkit-transform: rotate(-135deg);
            margin-top: 5px;
        }
        }
        
        #manga-viewer-title.has-series:after {
            content: "";
            display: inline-block;
            margin-left: 5px;
            border: solid #fff;
            border-width: 0 2px 2px 0;
            padding: 3px;
            transform: rotate(45deg);
            -webkit-transform: rotate(45deg);
            transition: transform 0.2s, border-color 0.2s;
        }
        
        #manga-viewer-title.has-series:hover:after {
            border-color: #a9d7ff;
        }
        
        #manga-viewer-title.has-series.open:after {
            transform: rotate(-135deg);
            -webkit-transform: rotate(-135deg);
            margin-top: 5px;
        }
        
        /* 모바일 대응 추가 */
        @media (max-width: 768px) {
            #manga-series-popup {
                max-width: 90%;
                max-height: 70vh;
            }
            
            .manga-series-item {
                padding: 10px 8px;
                font-size: 13px;
            }
            
            #manga-series-title {
                font-size: 14px;
            }
        }

        /* 키보드 이벤트 감지용 투명 입력 요소 */
        #manga-keyboard-catcher {
            position: fixed;
            top: -1000px;
            left: -1000px;
            width: 0;
            height: 0;
            opacity: 0;
            pointer-events: none;
        }

        /* 네비게이션 피드백 스타일 */
        #manga-nav-feedback {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            font-size: 3rem;
            color: rgba(255, 255, 255, 0.8);
            z-index: 10005;
            pointer-events: none;
            animation: navFeedbackAnim 0.3s ease-out;
        }

        @keyframes navFeedbackAnim {
            0% { opacity: 0; transform: translate(-50%, -50%) scale(0.5); }
            50% { opacity: 1; transform: translate(-50%, -50%) scale(1.2); }
            100% { opacity: 0; transform: translate(-50%, -50%) scale(1); }
        }

        /* 키보드 단축키 도움말 스타일 */
        #manga-help-popup {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: rgba(26, 26, 26, 0.98);
            border: 1px solid rgba(255, 255, 255, 0.1);
            border-radius: 12px;
            padding: 20px 30px;
            z-index: 10006;
            max-width: 400px;
            backdrop-filter: blur(15px);
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
            display: none;
            color: #f8f9fa;
        }
        
        #manga-help-popup.active {
            display: block;
            animation: helpFadeIn 0.3s ease-out;
        }
        
        @keyframes helpFadeIn {
            from { opacity: 0; transform: translate(-50%, -50%) scale(0.9); }
            to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
        }
        
        #manga-help-title {
            font-size: 18px;
            font-weight: 600;
            margin-bottom: 15px;
            text-align: center;
            color: #4facfe;
            border-bottom: 1px solid rgba(255, 255, 255, 0.1);
            padding-bottom: 10px;
        }
        
        .manga-help-section {
            margin-bottom: 15px;
        }
        
        .manga-help-section h4 {
            font-size: 14px;
            font-weight: 600;
            margin-bottom: 8px;
            color: #a9d7ff;
        }
          .manga-help-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 5px;
            font-size: 13px;
            gap: 10px;
        }
        
        .manga-help-keys {
            display: flex;
            gap: 5px;
            flex-shrink: 0;
        }
        
        .manga-help-key {
            background: rgba(79, 172, 254, 0.2);
            border: 1px solid rgba(79, 172, 254, 0.3);
            border-radius: 4px;
            padding: 2px 8px;
            font-family: 'Courier New', monospace;
            font-size: 12px;
            color: #4facfe;
            min-width: 24px;
            text-align: center;
            flex-shrink: 0;
        }
        
        .manga-help-desc {
            color: #d0d0d0;
            margin-left: 15px;
            flex: 1;
        }
        
        #manga-help-close {
            position: absolute;
            top: 10px;
            right: 15px;
            background: none;
            border: none;
            color: #999;
            font-size: 20px;
            cursor: pointer;
            padding: 5px;
            transition: color 0.2s;
        }
        
        #manga-help-close:hover {
            color: #f8f9fa;
        }

        // ...existing code...
    `;
    document.head.appendChild(style);

    // 현재 보고 있는 이미지 인덱스와 이미지 배열
    let currentImageIndex = 0;
    let images = [];
    let viewerActive = false;
    let drawerActive = false;
    let drawerHeight = 120; // 기본 서랍 높이
    let articleTitle = ''; // 글 제목 저장용 변수
    let seriesItems = []; // 시리즈 아이템 저장용
    let seriesPopupOpen = false; // 시리즈 팝업 상태
    let hasSeries = false; // 시리즈 존재 여부 확인 변수
    let autoOpenFromSeries = false; // 시리즈 링크를 통해 진입했는지 확인하는 플래그
    let isDrawerLoading = false; // 서랍 로딩 상태
    let drawerImagesLoaded = {}; // 이미지 로딩 상태 추적

    // 마지막으로 본 페이지 정보 저장용 키 생성
    function getStorageKey() {
        const path = window.location.pathname;
        return `arcalive_manga_viewer_${path}`;
    }

    // 뷰어 상태 저장
    function saveViewerState() {
        // 유효성 검사 추가
        const validIndex = typeof currentImageIndex === 'number' && !isNaN(currentImageIndex) &&
            currentImageIndex >= 0 && currentImageIndex < images.length ?
            currentImageIndex : 0;

        GM_setValue(getStorageKey(), {
            index: validIndex,
            drawerHeight: drawerHeight,
            title: articleTitle
        });
    }

    // 뷰어 상태 로드 - 안정성 추가
    function loadViewerState() {
        try {
            const savedState = GM_getValue(getStorageKey());
            return savedState && typeof savedState === 'object' ?
                savedState : { index: 0, drawerHeight: 120, title: '' };
        } catch (e) {
            console.log("상태 로드 오류:", e);
            return { index: 0, drawerHeight: 120, title: '' };
        }
    }

    // 아카라이브 게시물인지 확인
    function isArticlePage() {
        return location.pathname.includes('/b/') && location.pathname.split('/').length >= 4;
    }

    // 뷰어 요소 생성
    function createViewerElements() {
        // 이미 존재하는 뷰어 컨테이너 확인
        if (document.getElementById('manga-viewer-container')) {
            return;
        }

        const container = document.createElement('div');
        container.id = 'manga-viewer-container';

        container.innerHTML = `
            <div id="manga-viewer-header">
                <div id="manga-viewer-title"></div>
                <div id="manga-viewer-counter"></div>
                <div id="manga-viewer-close">닫기 (ESC)</div>
                <div id="manga-series-popup">
                    <div id="manga-series-title">시리즈</div>
                    <div id="manga-series-list"></div>
                </div>
            </div>
            <div id="manga-viewer-content">
                <img id="manga-viewer-image" src="" alt="만화 이미지">
                <div id="manga-viewer-prev" class="manga-viewer-nav">
                    <div id="manga-nav-prev-hint" class="manga-nav-hint">&lt;</div>
                </div>
                <div id="manga-viewer-next" class="manga-viewer-nav">
                    <div id="manga-nav-next-hint" class="manga-nav-hint">&gt;</div>
                </div>
                <div id="manga-drawer-toggle">≡</div>
                <div id="manga-drawer"></div>
                <input type="text" id="manga-keyboard-catcher" autocomplete="off">
            </div>
        `;

        document.body.appendChild(container);

        // 이벤트 리스너 추가
        document.getElementById('manga-viewer-close').addEventListener('click', closeViewer);
        document.getElementById('manga-viewer-prev').addEventListener('click', prevImage);
        document.getElementById('manga-viewer-next').addEventListener('click', nextImage);
        document.getElementById('manga-viewer-image').addEventListener('wheel', handleZoom);
        document.getElementById('manga-drawer-toggle').addEventListener('click', toggleDrawer);

        // 시리즈 팝업 기능 이벤트 추가 - 시리즈가 있을 때만 활성화됨
        document.getElementById('manga-viewer-title').addEventListener('click', toggleSeriesPopup);        // 키보드 이벤트용 숨겨진 입력 요소 설정
        const keyboardCatcher = document.getElementById('manga-keyboard-catcher');
        keyboardCatcher.addEventListener('keydown', handleKeyDown);

        // 전역 키보드 이벤트 캡처 (뷰어 활성화 시 모든 키보드 입력을 우선 처리)
        document.addEventListener('keydown', handleGlobalKeyDown, true); // capture phase
        document.addEventListener('keyup', handleGlobalKeyUp, true); // capture phase

        // 시리즈 팝업 외부 클릭시 닫기
        document.addEventListener('click', function (event) {
            const seriesPopup = document.getElementById('manga-series-popup');
            const viewerTitle = document.getElementById('manga-viewer-title');

            if (seriesPopupOpen &&
                !seriesPopup.contains(event.target) &&
                event.target !== viewerTitle) {
                closeSeriesPopup();
            }
        });
    }

    // 키보드 포커스 강제 적용 함수
    function focusKeyboardCatcher() {
        const keyboardCatcher = document.getElementById('manga-keyboard-catcher');
        if (keyboardCatcher) {
            keyboardCatcher.focus();

            // 포커스가 제대로 적용되도록 쓰레드 분리
            setTimeout(() => {
                keyboardCatcher.focus();
            }, 100);
        }
    }

    // 시리즈 목록 토글
    function toggleSeriesPopup(event) {
        // 시리즈가 없으면 동작하지 않음
        if (!hasSeries) return;

        event.stopPropagation();

        const seriesPopup = document.getElementById('manga-series-popup');
        const viewerTitle = document.getElementById('manga-viewer-title');

        if (seriesPopupOpen) {
            closeSeriesPopup();
        } else {
            // 시리즈 목록이 없으면 가져오기 시도
            if (seriesItems.length === 0) {
                fetchSeriesItems();
            }

            seriesPopupOpen = true;
            seriesPopup.classList.add('active');
            viewerTitle.classList.add('open');
        }
    }

    // 시리즈 팝업 닫기
    function closeSeriesPopup() {
        const seriesPopup = document.getElementById('manga-series-popup');
        const viewerTitle = document.getElementById('manga-viewer-title');

        seriesPopupOpen = false;
        seriesPopup.classList.remove('active');
        viewerTitle.classList.remove('open');

        // 팝업 닫을 때 키보드 캐처에 포커스
        focusKeyboardCatcher();
    }

    // 시리즈 목록 가져오기 - HTML 구조에 맞게 완전히 개선된 버전
    function fetchSeriesItems() {
        // 현재 페이지에서 시리즈 정보 추출 - 두 가지 구조 모두 확인
        const seriesElement = document.querySelector('.article-series') || document.querySelector('.article-series.extend');
        if (!seriesElement) {
            hasSeries = false;
            document.getElementById('manga-viewer-title').classList.remove('has-series');
            return;
        }

        hasSeries = true;
        document.getElementById('manga-viewer-title').classList.add('has-series');

        // 시리즈 제목 설정
        const seriesNameElement = seriesElement.querySelector('.series-name');
        let seriesTitle = '시리즈';

        if (seriesNameElement) {
            seriesTitle = seriesNameElement.textContent.trim();
        } else {
            // 시리즈 이름 요소가 없는 경우, 첫 번째 항목의 공통 부분을 추출
            const firstSeriesItem = seriesElement.querySelector('.series-link a');
            if (firstSeriesItem) {
                const text = firstSeriesItem.textContent.trim();
                const match = text.match(/^(\d+)\.\s+(.+?)\s+Chapter/i);
                if (match && match[2]) {
                    seriesTitle = match[2].trim();
                }
            }
        }

        document.getElementById('manga-series-title').textContent = seriesTitle;

        // 시리즈 항목들 가져오기 - 두 가지 가능한 선택자를 모두 검사
        let seriesLinks = Array.from(seriesElement.querySelectorAll('.series-link a'));

        if (!seriesLinks || seriesLinks.length === 0) {
            seriesLinks = Array.from(seriesElement.querySelectorAll('.vrow'));
        }

        if (!seriesLinks || seriesLinks.length === 0) return;

        // 현재 경로를 가져와서 현재 페이지를 찾기 위해 사용
        const currentPath = window.location.pathname;

        // 시리즈 정보 정리
        seriesItems = seriesLinks.map(item => {
            let link, title, isCurrent;

            if (item.tagName.toLowerCase() === 'a') {
                // series-link > a 타입인 경우
                link = item.getAttribute('href');
                title = item.textContent.trim().replace(/^\s*\d+\.\s*/, ''); // 앞의 번호와 점 제거
                isCurrent = link === currentPath || link === window.location.href;
            } else {
                // vrow 타입인 경우
                link = item.getAttribute('href');
                title = item.textContent.trim().replace(/^\s*\d+\s*/, ''); // 앞의 번호 제거
                isCurrent = item.classList.contains('active');
            }

            // 현재 URL과 비교해서 현재 페이지 여부 추가 확인
            if (!isCurrent && link) {
                isCurrent = currentPath === link || currentPath.endsWith(link);
            }

            return { link, title, isCurrent };
        });

        // 시리즈 목록 UI 생성
        createSeriesList();

        // 로그로 확인
        console.log("시리즈 항목 추출 완료:", seriesItems);
    }

    // 시리즈 목록 UI 생성
    function createSeriesList() {
        const seriesList = document.getElementById('manga-series-list');
        seriesList.innerHTML = '';

        seriesItems.forEach(item => {
            const itemElement = document.createElement('div');
            itemElement.className = 'manga-series-item';
            if (item.isCurrent) {
                itemElement.classList.add('current');
            }

            itemElement.textContent = item.title;

            // 클릭 이벤트 - 새로운 시리즈 아이템으로 이동 시 자동 열기 파라미터 추가
            // 단, 첫 페이지부터 보기 위한 파라미터로 수정
            itemElement.addEventListener('click', function () {
                // 첫 페이지부터 보기 위한 파라미터로 수정 (이어서보기가 아닌 첫페이지부터)
                const url = new URL(item.link, window.location.origin);
                url.searchParams.set('manga_viewer_open', '1');
                window.location.href = url.toString();
            });

            seriesList.appendChild(itemElement);
        });
    }    // 이미지 서랍 토글 - 지연 로딩 최적화 버전
    function toggleDrawer() {
        const drawer = document.getElementById('manga-drawer');
        const drawerToggle = document.getElementById('manga-drawer-toggle');

        // 로딩 중이면 중복 실행 방지
        if (isDrawerLoading) return;

        drawerActive = !drawerActive;

        // 성능 통계 업데이트
        updatePerformanceStats('drawer');

        if (drawerActive) {
            // 로딩 상태로 설정
            isDrawerLoading = true;

            drawer.classList.add('active');
            drawerToggle.classList.add('active');
            drawer.style.height = `${drawerHeight}px`;

            // 서랍이 활성화될 때만 이미지 미리보기 로드 (최적화)
            loadDrawerPreviews();

            // 로딩 완료 후 액션
            setTimeout(() => {
                // 현재 이미지가 서랍의 중앙에 오도록 스크롤
                scrollToCurrentPage(true);
                isDrawerLoading = false; // 로딩 상태 해제
            }, 100);
        } else {
            drawer.classList.remove('active');
            drawerToggle.classList.remove('active');
            drawer.style.height = '0';

            // 로딩 상태 해제
            isDrawerLoading = false;
        }

        // 서랍이 활성화되면 토글 버튼 위치 조정
        updateDrawerTogglePosition();

        // 서랍 토글 시 키보드 포커스 복원
        focusKeyboardCatcher();
    }// 서랍 미리보기 이미지 로드 최적화 함수
    function loadDrawerPreviews() {
        const drawer = document.getElementById('manga-drawer');
        const drawerItems = drawer.querySelectorAll('.manga-drawer-item');

        // 현재 표시되는 아이템만 이미지 로드
        drawerItems.forEach((item, index) => {
            const img = item.querySelector('img');
            if (img && !drawerImagesLoaded[index]) {
                // 현재 이미지 주변의 이미지만 로드 (±10)
                if (Math.abs(index - currentImageIndex) < 10) {
                    img.src = images[index];
                    drawerImagesLoaded[index] = true;
                }
            }
        });

        // 현재 스크롤 위치 주변 이미지 지연 로드
        setTimeout(() => {
            const visibleStart = Math.max(0, currentImageIndex - 20);
            const visibleEnd = Math.min(images.length - 1, currentImageIndex + 20);

            for (let i = visibleStart; i <= visibleEnd; i++) {
                if (!drawerImagesLoaded[i]) {
                    const img = drawerItems[i]?.querySelector('img');
                    if (img) {
                        img.src = images[i];
                        drawerImagesLoaded[i] = true;
                    }
                }
            }
        }, 500);
    }    // 서랍 토글 버튼 위치 업데이트
    function updateDrawerTogglePosition() {
        const drawerToggle = document.getElementById('manga-drawer-toggle');
        const drawer = document.getElementById('manga-drawer');

        if (drawerActive) {
            // 서랍이 열렸을 때는 서랍 위에 위치 (간격 유지)
            const drawerHeight = parseInt(drawer.style.height) || 120;
            drawerToggle.style.bottom = `${drawerHeight + 20}px`;
        } else {
            // 서랍이 닫혔을 때는 기본 위치
            drawerToggle.style.bottom = '20px';
        }
    }// 서랍 아이템 높이 업데이트
    function updateDrawerItemsHeight() {
        const items = document.querySelectorAll('.manga-drawer-item');
        const drawer = document.getElementById('manga-drawer');
        const drawerHeight = drawer.clientHeight;

        // 패딩 고려
        const itemHeight = Math.min(100, drawerHeight - 30);

        items.forEach(item => {
            item.style.height = `${itemHeight}px`;
        });
    }// 현재 페이지가 가운데 오도록 스크롤 - 개선된 버전
    function scrollToCurrentPage(smooth = false) {
        const activeItem = document.querySelector('.manga-drawer-item.active');
        const drawer = document.getElementById('manga-drawer');

        if (!activeItem || !drawer || !drawer.classList.contains('active')) return;

        // requestAnimationFrame을 이용한 더 부드러운 스크롤
        requestAnimationFrame(() => {
            // 서랍의 너비와 스크롤 위치 계산
            const drawerWidth = drawer.clientWidth;
            const itemRect = activeItem.getBoundingClientRect();

            // 아이템 위치 계산 (중앙에 오도록) - 성능 최적화
            const itemLeft = activeItem.offsetLeft;
            const scrollLeft = itemLeft - (drawerWidth / 2) + (itemRect.width / 2);

            // 스크롤 적용
            drawer.scrollTo({
                left: scrollLeft,
                behavior: smooth ? 'smooth' : 'auto'
            });
        });
    }

    // 뷰어 버튼 추가
    function addViewerButton() {
        // article-link 요소 내부에 버튼 추가
        const articleLinkContainer = document.querySelector('.article-link');
        if (!articleLinkContainer) return;

        // 이미 버튼이 추가되었는지 확인
        if (document.getElementById('manga-viewer-button') || document.getElementById('manga-viewer-continue')) {
            return;
        }

        // 만화모드 버튼 생성
        const viewerButton = document.createElement('button');
        viewerButton.id = 'manga-viewer-button';
        viewerButton.className = 'btn btn-arca btn-sm';
        viewerButton.textContent = '만화모드';
        viewerButton.addEventListener('click', openViewer);

        // 이어서보기 버튼 생성
        const continueButton = document.createElement('button');
        continueButton.id = 'manga-viewer-continue';
        continueButton.className = 'btn btn-arca btn-sm';
        continueButton.textContent = '이어서보기';
        continueButton.addEventListener('click', continueViewing);

        // 마지막으로 본 페이지가 없으면 이어서보기 버튼 비활성화
        const savedState = loadViewerState();
        if (!savedState || savedState.index === undefined) {
            continueButton.disabled = true;
            continueButton.style.opacity = '0.5';
            continueButton.title = '이전에 본 기록이 없습니다';
        } else {
            continueButton.title = `마지막으로 본 페이지: ${savedState.index + 1}`;
        }

        // 버튼들을 article-link 요소 내부의 첫 번째 위치에 삽입
        articleLinkContainer.insertBefore(continueButton, articleLinkContainer.firstChild);
        articleLinkContainer.insertBefore(viewerButton, articleLinkContainer.firstChild);        // 기존 아카라이브 스타일로 버튼 스타일 조정
        const additionalStyle = document.createElement('style');
        additionalStyle.textContent = `
            #manga-viewer-button, #manga-viewer-continue {
                margin-right: 8px;
                margin-left: 0;
            }
            
            #manga-viewer-continue:disabled {
                opacity: 0.5;
                cursor: not-allowed;
            }
            
            .article-link {
                display: flex;
                align-items: center;
            }
            .article-link a {
                margin-left: auto;
            }
        `;
        document.head.appendChild(additionalStyle);
    }

    // 이미지 수집
    function collectImages() {
        const articleContent = document.querySelector('.article-content');
        if (!articleContent) return [];

        // 본문의 모든 이미지 수집
        return Array.from(articleContent.querySelectorAll('img:not(.emoticon)'))
            .filter(img => {
                // 이모티콘 등의 작은 이미지 제외
                const rect = img.getBoundingClientRect();
                return rect.width > 100 || rect.height > 100;
            })
            .map(img => img.src);
    }

    // 게시물 제목 가져오기
    function getArticleTitle() {
        // 게시물 제목 요소 선택
        const titleElement = document.querySelector('.article-head .title');

        // 제목 요소가 있으면 내용을 반환, 없으면 기본값 반환
        return titleElement ? titleElement.textContent.trim() : '만화 뷰어';
    }    // 이미지 서랍 생성 (성능 최적화 버전)
    function createImageDrawer() {
        const startTime = performance.now();
        const drawer = document.getElementById('manga-drawer');

        // 기존 항목 모두 제거
        while (drawer.firstChild) {
            drawer.removeChild(drawer.firstChild);
        }

        // IntersectionObserver 초기화
        initLazyLoading();

        // 각 이미지에 대한 미리보기 추가 (지연 로딩 적용)
        images.forEach((src, index) => {
            const item = document.createElement('div');
            item.className = 'manga-drawer-item';
            if (index === currentImageIndex) {
                item.classList.add('active');
            }

            const img = document.createElement('img');
            img.className = 'manga-drawer-img';
            img.alt = `Image ${index + 1}`;

            // 현재 이미지와 주변 5개 이미지만 즉시 로드, 나머지는 지연 로딩
            if (Math.abs(index - currentImageIndex) <= 5) {
                img.src = src;
                loadedImages.add(src);
            } else {
                img.dataset.src = src;
                img.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB2aWV3Qm94PSIwIDAgMSAxIiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9IiMzMzMiLz48L3N2Zz4=';
                if (drawerObserver) {
                    drawerObserver.observe(img);
                }
            }

            const number = document.createElement('div');
            number.className = 'manga-drawer-number';
            number.textContent = index + 1;

            item.appendChild(img);
            item.appendChild(number);

            // 클릭 시 해당 이미지로 이동
            item.addEventListener('click', () => {
                currentImageIndex = index;
                updateViewer();
            });

            drawer.appendChild(item);
        });

        // 열린 상태에서는 아이템 높이 조정
        if (drawerActive) {
            updateDrawerItemsHeight();
        }

        // 성능 로그
        performanceLog('서랍 생성', startTime);

        // 메모리 정리
        cleanupImageCache();
    }

    // 이어서보기 기능
    function continueViewing() {
        const savedState = loadViewerState();
        if (!savedState || savedState.index === undefined) {
            alert('이전에 본 기록이 없습니다.');
            return;
        }

        images = collectImages();
        if (images.length === 0) {
            alert('표시할 이미지가 없습니다.');
            return;
        }

        // 저장된 인덱스 또는 첫 페이지로 설정
        currentImageIndex = (savedState.index >= 0 && savedState.index < images.length) ?
            savedState.index : 0;

        // 저장된 서랍 높이 복원
        if (savedState.drawerHeight) {
            drawerHeight = savedState.drawerHeight;
        }

        // 저장된 제목 복원 또는 현재 제목 가져오기
        articleTitle = savedState.title || getArticleTitle();

        const container = document.getElementById('manga-viewer-container');
        container.style.display = 'flex';
        document.body.style.overflow = 'hidden'; // 스크롤 방지

        // 제목 설정
        document.getElementById('manga-viewer-title').textContent = articleTitle;

        // 이미지 서랍 생성
        createImageDrawer();

        // 네비게이션 힌트 표시
        showNavigationHints();

        updateViewer();

        viewerActive = true;

        // 전역 키보드 이벤트를 추가하는 방식을 변경
        window.addEventListener('keydown', handleKeyDown);

        // 뷰어 활성화 시 body에 클래스 추가
        document.body.classList.add('manga-viewer-active');

        // 서랍 핸들 위치 업데이트
        const drawerHandle = document.getElementById('manga-drawer-handle');
        if (drawerHandle) {
            if (drawerActive) {
                drawerHandle.style.bottom = `${drawerHeight}px`;
            } else {
                drawerHandle.style.bottom = "0px";
            }
        }

        // 제목 요소 초기 상태 설정
        const viewerTitle = document.getElementById('manga-viewer-title');
        if (viewerTitle) {
            viewerTitle.classList.remove('has-series');
            viewerTitle.classList.remove('open');
        }

        // 시리즈 정보 확인 - DOM에서 직접 검색
        setTimeout(() => {
            fetchSeriesItems();
        }, 200); // DOM이 완전히 준비된 후 실행하기 위해 약간의 지연 추가
    }

    // 뷰어 열기
    function openViewer() {
        images = collectImages();
        if (images.length === 0) {
            alert('표시할 이미지가 없습니다.');
            return;
        }

        // 시리즈 정보 초기화
        seriesItems = [];
        seriesPopupOpen = false;
        hasSeries = false;

        // 제목 요소 초기 상태 설정
        const viewerTitle = document.getElementById('manga-viewer-title');
        if (viewerTitle) {
            viewerTitle.classList.remove('has-series');
            viewerTitle.classList.remove('open');
        }

        // 저장된 상태 불러오기
        const savedState = loadViewerState();

        // 이전에 저장된 서랍 높이 복원
        if (savedState && savedState.drawerHeight) {
            drawerHeight = savedState.drawerHeight;
        }

        currentImageIndex = 0;

        // 현재 게시물 제목 가져오기
        articleTitle = getArticleTitle();

        const container = document.getElementById('manga-viewer-container');
        container.style.display = 'flex';
        document.body.style.overflow = 'hidden'; // 스크롤 방지

        // 제목 설정
        document.getElementById('manga-viewer-title').textContent = articleTitle;

        // 이미지 서랍 생성
        createImageDrawer();

        // 네비게이션 힌트 요소 보였다가 숨기기
        showNavigationHints();

        updateViewer();

        viewerActive = true;

        // 전역 키보드 이벤트를 추가하는 방식을 변경
        window.addEventListener('keydown', handleKeyDown);

        // 뷰어 활성화 시 body에 클래스 추가
        document.body.classList.add('manga-viewer-active');

        // 서랍 핸들 위치 업데이트
        const drawerHandle = document.getElementById('manga-drawer-handle');
        if (drawerHandle) {
            if (drawerActive) {
                drawerHandle.style.bottom = `${drawerHeight}px`;
            } else {
                drawerHandle.style.bottom = "0px";
            }
        }

        // 시리즈 정보 확인 - DOM에서 직접 검색
        setTimeout(() => {
            fetchSeriesItems();
        }, 200); // DOM이 완전히 준비된 후 실행하기 위해 약간의 지연 추가
    }

    // 네비게이션 힌트 표시 후 숨기기
    function showNavigationHints() {
        const prevHint = document.getElementById('manga-nav-prev-hint');
        const nextHint = document.getElementById('manga-nav-next-hint');

        prevHint.style.opacity = '1';
        nextHint.style.opacity = '1';

        setTimeout(() => {
            prevHint.style.opacity = '0';
            nextHint.style.opacity = '0';

            // 트랜지션 추가
            prevHint.style.transition = 'opacity 0.5s';
            nextHint.style.transition = 'opacity 0.5s';
        }, 1500);
    }

    // 네비게이션 피드백 표시
    function showNavigationFeedback(direction) {
        const existingFeedback = document.getElementById('manga-nav-feedback');
        if (existingFeedback) {
            existingFeedback.remove();
        }

        const feedback = document.createElement('div');
        feedback.id = 'manga-nav-feedback';
        feedback.textContent = direction === 'prev' ? '◀' : '▶';
        feedback.style.cssText = `
            position: fixed;
            top: 50%;
            left: ${direction === 'prev' ? '20%' : '80%'};
            transform: translate(-50%, -50%);
            font-size: 3rem;
            color: rgba(255, 255, 255, 0.8);
            z-index: 10005;
            pointer-events: none;
            animation: navFeedbackAnim 0.3s ease-out;
        `;

        // 애니메이션 CSS 추가 (한 번만)
        if (!document.getElementById('nav-feedback-style')) {
            const style = document.createElement('style');
            style.id = 'nav-feedback-style';
            style.textContent = `
                @keyframes navFeedbackAnim {
                    0% { opacity: 0; transform: translate(-50%, -50%) scale(0.5); }
                    50% { opacity: 1; transform: translate(-50%, -50%) scale(1.2); }
                    100% { opacity: 0; transform: translate(-50%, -50%) scale(1); }
                }
            `;
            document.head.appendChild(style);
        }

        document.body.appendChild(feedback);

        // 300ms 후 제거
        setTimeout(() => {
            if (feedback.parentNode) {
                feedback.remove();
            }
        }, 300);
    }    // 뷰어 닫기
    function closeViewer() {
        // 현재 상태 저장
        saveViewerState();

        // 이어서보기 버튼 업데이트
        const continueButton = document.getElementById('manga-viewer-continue');
        if (continueButton) {
            continueButton.disabled = false;
            continueButton.style.opacity = '1';
            continueButton.title = `마지막으로 본 페이지: ${currentImageIndex + 1}`;
        }

        const container = document.getElementById('manga-viewer-container');
        container.style.display = 'none';
        document.body.style.overflow = ''; // 스크롤 복원
        viewerActive = false;
        drawerActive = false;

        // 서랍 토글 버튼 위치 초기화
        const drawerToggle = document.getElementById('manga-drawer-toggle');
        if (drawerToggle) {
            drawerToggle.style.bottom = '20px';
        }

        // 전역 키보드 이벤트 제거
        document.removeEventListener('keydown', handleGlobalKeyDown, true);
        document.removeEventListener('keyup', handleGlobalKeyUp, true);
        window.removeEventListener('keydown', handleKeyDown);

        // 도움말 팝업이 열려있으면 닫기
        hideHelpPopup();

        // body에서 뷰어 활성화 클래스 제거
        document.body.classList.remove('manga-viewer-active');

        // 서랍 핸들 위치 초기화
        const drawerHandle = document.getElementById('manga-drawer-handle');
        if (drawerHandle) {
            drawerHandle.style.bottom = "0px";
        }
    }

    // 이전 이미지로 이동
    function prevImage() {
        if (currentImageIndex > 0) {
            currentImageIndex--;
            updateViewer();
        }
    }

    // 다음 이미지로 이동
    function nextImage() {
        if (currentImageIndex < images.length - 1) {
            currentImageIndex++;
            updateViewer();
        }
    }    // 이미지 프리로딩 및 캐싱 시스템
    let imageCache = new Map();
    let preloadQueue = [];
    let isPreloading = false;

    // 이미지 프리로드 함수
    function preloadImage(src) {
        return new Promise((resolve, reject) => {
            if (imageCache.has(src)) {
                resolve(imageCache.get(src));
                return;
            }

            const img = new Image();
            img.onload = () => {
                imageCache.set(src, img);
                resolve(img);
            };
            img.onerror = reject;
            img.src = src;
        });
    }

    // 주변 이미지들을 백그라운드에서 프리로드
    function preloadAdjacentImages(centerIndex, radius = 3) {
        if (isPreloading) return;
        isPreloading = true;

        const startIndex = Math.max(0, centerIndex - radius);
        const endIndex = Math.min(images.length - 1, centerIndex + radius);

        // 프리로드 큐 생성 (현재 이미지 제외)
        preloadQueue = [];
        for (let i = startIndex; i <= endIndex; i++) {
            if (i !== centerIndex && !imageCache.has(images[i])) {
                preloadQueue.push(images[i]);
            }
        }

        // 순차적으로 프리로드 (브라우저 부담 최소화)
        processPreloadQueue();
    }

    function processPreloadQueue() {
        if (preloadQueue.length === 0) {
            isPreloading = false;
            return;
        }

        const imageSrc = preloadQueue.shift();
        preloadImage(imageSrc)
            .then(() => {
                // 100ms 간격으로 다음 이미지 프리로드
                setTimeout(() => processPreloadQueue(), 100);
            })
            .catch(() => {
                // 에러 시 다음 이미지로 진행
                setTimeout(() => processPreloadQueue(), 100);
            });
    }

    // 뷰어 업데이트 (성능 최적화 버전)
    function updateViewer() {
        const img = document.getElementById('manga-viewer-image');
        const currentImageSrc = images[currentImageIndex];

        // 캐시된 이미지가 있으면 즉시 표시, 없으면 로드
        if (imageCache.has(currentImageSrc)) {
            img.src = currentImageSrc;
        } else {
            // 로딩 인디케이터 표시
            showLoadingIndicator();

            preloadImage(currentImageSrc)
                .then(() => {
                    img.src = currentImageSrc;
                    hideLoadingIndicator();
                })
                .catch(() => {
                    hideLoadingIndicator();
                    console.error('이미지 로드 실패:', currentImageSrc);
                });
        }

        img.style.transform = 'scale(1)'; // 이미지 변경 시 줌 리셋
        currentScale = 1;

        // 카운터 업데이트
        document.getElementById('manga-viewer-counter').textContent =
            `${currentImageIndex + 1} / ${images.length}`;

        // 주변 이미지 프리로드 시작
        preloadAdjacentImages(currentImageIndex);

        // 이미지 서랍 활성 항목 업데이트
        updateDrawerActiveItem();

        // 상태 저장 (디바운싱)
        clearTimeout(saveStateTimeout);
        saveStateTimeout = setTimeout(saveViewerState, 1000);
    }

    let saveStateTimeout = null;

    // 로딩 인디케이터 관련 함수들
    function showLoadingIndicator() {
        let indicator = document.getElementById('manga-loading-indicator');
        if (!indicator) {
            indicator = document.createElement('div');
            indicator.id = 'manga-loading-indicator';
            indicator.innerHTML = '로딩 중...';
            indicator.style.cssText = `
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                background: rgba(0, 0, 0, 0.8);
                color: white;
                padding: 10px 20px;
                border-radius: 5px;
                z-index: 10003;
                font-size: 14px;
            `;
            document.getElementById('manga-viewer-content').appendChild(indicator);
        }
        indicator.style.display = 'block';
    }

    function hideLoadingIndicator() {
        const indicator = document.getElementById('manga-loading-indicator');
        if (indicator) {
            indicator.style.display = 'none';
        }
    }

    // 서랍 활성 항목 업데이트 (별도 함수로 분리하여 성능 최적화)
    function updateDrawerActiveItem() {
        const drawerItems = document.querySelectorAll('.manga-drawer-item');

        // 서랍에 아이템이 없으면 작업 건너뛰기
        if (drawerItems.length === 0) return;

        drawerItems.forEach((item, index) => {
            if (index === currentImageIndex) {
                item.classList.add('active');

                // 서랍이 활성화된 경우에만 스크롤
                if (drawerActive) {
                    // 페이지 변경 시 현재 이미지가 중앙에 오도록 스크롤
                    scrollToCurrentPage(true);
                }
            } else {
                item.classList.remove('active');
            }
        });
    }    // 전역 키보드 이벤트 핸들러 - 뷰어 활성화 시 사이트 기본 키보드 동작 차단
    function handleGlobalKeyDown(e) {
        // 뷰어가 비활성화되어 있으면 기본 동작 허용
        if (!viewerActive) return;

        // 입력 필드나 편집 가능한 요소에서는 뷰어 키보드 처리 건너뛰기
        const activeElement = document.activeElement;
        const isEditableElement = activeElement && (
            activeElement.tagName === 'INPUT' ||
            activeElement.tagName === 'TEXTAREA' ||
            activeElement.contentEditable === 'true' ||
            activeElement.isContentEditable
        );

        if (isEditableElement) return;

        // 뷰어에서 처리하는 키들 정의
        const viewerKeys = [
            'arrowleft', 'arrowright', 'arrowup', 'arrowdown',
            'a', 'd', 'w', 's', 'q', 'f', 'r', 'h',
            'home', 'end', 'pageup', 'pagedown',
            'escape', 'tab', ' '
        ];

        const keyLower = e.key.toLowerCase();

        // 뷰어가 처리하는 키인 경우 기본 동작과 전파를 차단
        if (viewerKeys.includes(keyLower)) {
            e.preventDefault();
            e.stopPropagation();
            e.stopImmediatePropagation();

            // 뷰어 키보드 핸들러로 이벤트 전달
            handleKeyDown(e);
            return false;
        }

        // Ctrl 조합키 차단 (F11 제외)
        if (e.ctrlKey && e.key !== 'F11') {
            const ctrlKeys = ['a', 'c', 'v', 'x', 'z', 'y', 'f', 's'];
            if (ctrlKeys.includes(keyLower)) {
                e.preventDefault();
                e.stopPropagation();
                e.stopImmediatePropagation();
                return false;
            }
        }
    }

    // 전역 키업 이벤트 핸들러
    function handleGlobalKeyUp(e) {
        if (!viewerActive) return;

        const activeElement = document.activeElement;
        const isEditableElement = activeElement && (
            activeElement.tagName === 'INPUT' ||
            activeElement.tagName === 'TEXTAREA' ||
            activeElement.contentEditable === 'true' ||
            activeElement.isContentEditable
        );

        if (isEditableElement) return;

        // 뷰어 키들에 대해서는 keyup도 차단
        const viewerKeys = [
            'arrowleft', 'arrowright', 'arrowup', 'arrowdown',
            'a', 'd', 'w', 's', 'q', 'f', 'r', 'h',
            'home', 'end', 'pageup', 'pagedown',
            'escape', 'tab', ' '
        ];

        const keyLower = e.key.toLowerCase();

        if (viewerKeys.includes(keyLower)) {
            e.preventDefault();
            e.stopPropagation();
            e.stopImmediatePropagation();
            return false;
        }
    }

    // 키보드 이벤트 처리 최적화
    let keyPressTimeout = null;
    let lastKeyPressTime = 0;
    const KEY_DEBOUNCE_DELAY = 30; // 30ms 디바운싱으로 더 반응성 개선
    let keyRepeatInterval = null; function handleKeyDown(e) {
        // 뷰어가 활성화되어 있을 때만 처리
        if (!viewerActive) return;

        const currentTime = Date.now();

        // 키 입력이 너무 빠르게 연속으로 들어오는 것을 방지 (단, 화살표 키는 예외)
        const isNavigationKey = ['arrowleft', 'arrowright', 'a', 'd'].includes(e.key.toLowerCase());
        if (!isNavigationKey && currentTime - lastKeyPressTime < KEY_DEBOUNCE_DELAY) {
            return;
        }

        lastKeyPressTime = currentTime;

        // 입력 필드에서 키를 누른 경우 무시 (보안 강화)
        const activeElement = document.activeElement;
        const isEditableElement = activeElement && (
            activeElement.tagName === 'INPUT' ||
            activeElement.tagName === 'TEXTAREA' ||
            activeElement.contentEditable === 'true' ||
            activeElement.isContentEditable
        );

        if (isEditableElement) return;

        // 모든 뷰어 키에 대해 기본 동작 차단
        const viewerKeys = [
            'arrowleft', 'arrowright', 'arrowup', 'arrowdown',
            'a', 'd', 'w', 's', 'q', 'f', 'r', 'h',
            'home', 'end', 'pageup', 'pagedown',
            'escape', 'tab', ' '
        ];

        const keyLower = e.key.toLowerCase();

        if (viewerKeys.includes(keyLower)) {
            e.preventDefault();
            e.stopPropagation();
            e.stopImmediatePropagation();
        }

        // 시리즈 팝업이 열려있으면 특정 키만 처리
        if (seriesPopupOpen) {
            if (e.key === 'Escape') {
                closeSeriesPopup();
                e.preventDefault();
            }
            return;
        }

        switch (keyLower) {
            case 'arrowleft':
            case 'a':
                // 이전 페이지로 이동 (향상된 반응성)
                if (currentImageIndex > 0) {
                    prevImage();
                    showNavigationFeedback('prev');
                }
                break;
            case 'arrowright':
            case 'd':
                // 다음 페이지로 이동 (향상된 반응성)
                if (currentImageIndex < images.length - 1) {
                    nextImage();
                    showNavigationFeedback('next');
                }
                break;
            case 'w':
            case 'pageup':
                prevImage();
                break;
            case 's':
            case 'pagedown':
            case ' ': // 스페이스바로도 다음 이미지
                nextImage();
                break;
            case 'arrowup':
                // 위쪽 화살표로 첫 번째 이미지로 이동
                if (currentImageIndex > 0) {
                    currentImageIndex = 0;
                    updateViewer();
                }
                break;
            case 'arrowdown':
                // 아래쪽 화살표로 마지막 이미지로 이동
                if (currentImageIndex < images.length - 1) {
                    currentImageIndex = images.length - 1;
                    updateViewer();
                }
                break;
            case 'home':
                // Home 키로 첫 번째 이미지
                if (currentImageIndex > 0) {
                    currentImageIndex = 0;
                    updateViewer();
                }
                break;
            case 'end':
                // End 키로 마지막 이미지
                if (currentImageIndex < images.length - 1) {
                    currentImageIndex = images.length - 1;
                    updateViewer();
                }
                break;
            case 'escape':
                // 시리즈 팝업이 열려있으면 팝업만 닫기
                if (seriesPopupOpen) {
                    closeSeriesPopup();
                } else {
                    closeViewer();
                }
                break;
            case 'q':
            case 'tab':
                toggleDrawer();
                break;
            case 'f':
                // F키로 전체화면 토글
                toggleFullscreen();
                break;
            case 'r':
                // R키로 이미지 새로고침
                refreshCurrentImage();
                break;
            case 'h':
                // H키로 도움말 표시
                showHelpPopup();
                break;
        }

        // 성능 통계 업데이트
        updatePerformanceStats('keypress');
    }

    // 전체화면 토글 기능
    function toggleFullscreen() {
        if (!document.fullscreenElement) {
            document.documentElement.requestFullscreen().catch(err => {
                console.log(`전체화면 전환 실패: ${err.message}`);
            });
        } else {
            if (document.exitFullscreen) {
                document.exitFullscreen();
            }
        }
    }    // 현재 이미지 새로고침
    function refreshCurrentImage() {
        if (images.length > 0 && currentImageIndex >= 0 && currentImageIndex < images.length) {
            const img = document.getElementById('manga-viewer-image');
            const currentSrc = img.src;
            img.src = '';
            setTimeout(() => {
                img.src = currentSrc + '?refresh=' + Date.now();
            }, 100);
        }
    }

    // 도움말 팝업 표시/숨기기
    function showHelpPopup() {
        // 기존 도움말 팝업이 있으면 제거
        const existingPopup = document.getElementById('manga-help-popup');
        if (existingPopup) {
            hideHelpPopup();
            return;
        }

        // 도움말 팝업 HTML 생성
        const helpPopup = document.createElement('div');
        helpPopup.id = 'manga-help-popup';
        helpPopup.className = 'active';
        helpPopup.innerHTML = `
            <button id="manga-help-close">×</button>
            <div id="manga-help-title">⌨️ 키보드 단축키 도움말</div>
            
            <div class="manga-help-section">
                <h4>📖 페이지 네비게이션</h4>
                <div class="manga-help-item">
                    <span class="manga-help-desc">이전 페이지</span>
                    <div class="manga-help-keys">
                        <span class="manga-help-key">A</span>
                        <span class="manga-help-key">←</span>
                    </div>
                </div>
                <div class="manga-help-item">
                    <span class="manga-help-desc">다음 페이지</span>
                    <div class="manga-help-keys">
                        <span class="manga-help-key">D</span>
                        <span class="manga-help-key">→</span>
                    </div>
                </div>
                <div class="manga-help-item">
                    <span class="manga-help-desc">이전 페이지 (대안)</span>
                    <div class="manga-help-keys">
                        <span class="manga-help-key">W</span>
                        <span class="manga-help-key">PgUp</span>
                    </div>
                </div>
                <div class="manga-help-item">
                    <span class="manga-help-desc">다음 페이지 (대안)</span>
                    <div class="manga-help-keys">
                        <span class="manga-help-key">S</span>
                        <span class="manga-help-key">PgDn</span>
                        <span class="manga-help-key">Space</span>
                    </div>
                </div>
            </div>

            <div class="manga-help-section">
                <h4>🎯 빠른 이동</h4>
                <div class="manga-help-item">
                    <span class="manga-help-desc">첫 번째 페이지</span>
                    <div class="manga-help-keys">
                        <span class="manga-help-key">↑</span>
                        <span class="manga-help-key">Home</span>
                    </div>
                </div>
                <div class="manga-help-item">
                    <span class="manga-help-desc">마지막 페이지</span>
                    <div class="manga-help-keys">
                        <span class="manga-help-key">↓</span>
                        <span class="manga-help-key">End</span>
                    </div>
                </div>
            </div>

            <div class="manga-help-section">
                <h4>🔧 뷰어 기능</h4>
                <div class="manga-help-item">
                    <span class="manga-help-desc">서랍 토글</span>
                    <div class="manga-help-keys">
                        <span class="manga-help-key">Q</span>
                        <span class="manga-help-key">Tab</span>
                    </div>
                </div>
                <div class="manga-help-item">
                    <span class="manga-help-desc">전체화면</span>
                    <div class="manga-help-keys">
                        <span class="manga-help-key">F</span>
                    </div>
                </div>
                <div class="manga-help-item">
                    <span class="manga-help-desc">이미지 새로고침</span>
                    <div class="manga-help-keys">
                        <span class="manga-help-key">R</span>
                    </div>
                </div>
                <div class="manga-help-item">
                    <span class="manga-help-desc">뷰어 닫기</span>
                    <div class="manga-help-keys">
                        <span class="manga-help-key">ESC</span>
                    </div>
                </div>
                <div class="manga-help-item">
                    <span class="manga-help-desc">도움말 토글</span>
                    <div class="manga-help-keys">
                        <span class="manga-help-key">H</span>
                    </div>
                </div>
            </div>

            <div class="manga-help-section">
                <h4>🖱️ 마우스 기능</h4>
                <div class="manga-help-item">
                    <span class="manga-help-desc">페이지 네비게이션</span>
                    <div class="manga-help-keys">
                        <span class="manga-help-key">휠 스크롤</span>
                    </div>
                </div>
                <div class="manga-help-item">
                    <span class="manga-help-desc">확대/축소</span>
                    <div class="manga-help-keys">
                        <span class="manga-help-key">Ctrl + 휠</span>
                    </div>
                </div>
            </div>
        `;

        // 뷰어 컨테이너에 추가
        document.getElementById('manga-viewer-container').appendChild(helpPopup);

        // 닫기 버튼 이벤트
        document.getElementById('manga-help-close').addEventListener('click', hideHelpPopup);

        // 전역 키보드 이벤트 - ESC나 H로 도움말 닫기
        document.addEventListener('keydown', handleHelpKeyDown);
    }

    // 도움말 팝업 숨기기
    function hideHelpPopup() {
        const helpPopup = document.getElementById('manga-help-popup');
        if (helpPopup) {
            helpPopup.remove();
            document.removeEventListener('keydown', handleHelpKeyDown);
            // 키보드 캐처에 포커스 복원
            focusKeyboardCatcher();
        }
    }

    // 도움말 팝업이 열려있을 때의 키보드 이벤트 처리
    function handleHelpKeyDown(e) {
        if (e.key === 'Escape' || e.key.toLowerCase() === 'h') {
            hideHelpPopup();
            e.preventDefault();
            e.stopPropagation();
        }
    }

    // 확대/축소 기능
    let currentScale = 1;
    const scaleStep = 0.1;
    const minScale = 0.5;
    const maxScale = 3;    // 마우스 휠 이벤트 처리 (페이지 네비게이션 + 줌) - 개선된 버전
    let wheelTimeouts = new Map();
    let wheelSensitivity = 100; // 휠 감도 임계값

    function handleZoom(e) {
        e.preventDefault();

        // Ctrl 키를 누른 상태에서는 줌 기능
        if (e.ctrlKey) {
            const zoomIn = e.deltaY < 0;

            if (zoomIn && currentScale < maxScale) {
                currentScale = Math.min(currentScale + scaleStep, maxScale);
            } else if (!zoomIn && currentScale > minScale) {
                currentScale = Math.max(currentScale - scaleStep, minScale);
            }

            document.getElementById('manga-viewer-image').style.transform = `scale(${currentScale})`;
        } else {
            // 일반 휠 스크롤은 페이지 네비게이션 (디바운싱 적용)
            const direction = e.deltaY < 0 ? 'up' : 'down';

            // 이전 타임아웃 제거
            if (wheelTimeouts.has(direction)) {
                clearTimeout(wheelTimeouts.get(direction));
            }

            // 짧은 지연 후 네비게이션 실행 (빠른 연속 스크롤 방지)
            const timeout = setTimeout(() => {
                if (Math.abs(e.deltaY) > wheelSensitivity) {
                    if (direction === 'up') {
                        // 위로 스크롤 -> 이전 페이지
                        if (currentImageIndex > 0) {
                            prevImage();
                            showNavigationFeedback('prev');
                        }
                    } else {
                        // 아래로 스크롤 -> 다음 페이지
                        if (currentImageIndex < images.length - 1) {
                            nextImage();
                            showNavigationFeedback('next');
                        }
                    }
                }
                wheelTimeouts.delete(direction);
            }, 50);

            wheelTimeouts.set(direction, timeout);
        }
    }

    // 로컬 스토리지에서 시리즈 자동 전환 상태 관리
    function getSeriesAutoOpenKey() {
        return 'arcalive_manga_viewer_series_auto_open';
    }

    function checkAndAutoOpenFromSeries() {
        // URL 파라미터에서 시리즈 이동 여부 확인
        const urlParams = new URLSearchParams(window.location.search);
        if (urlParams.has('manga_from_series')) {
            autoOpenFromSeries = true;

            // 페이지 로드 후 약간 지연시켜서 만화 뷰어 모드를 실행
            setTimeout(() => {
                // 페이지가 완전히 로드된 후 이어서보기 실행
                continueViewing();
            }, 500);

            // URL에서 파라미터 제거 (히스토리는 유지)
            window.history.replaceState({}, document.title,
                window.location.pathname + window.location.hash);
        }
    }    // 스크립트 초기화
    function init() {
        // 이미 초기화되었으면 중복 실행 방지
        if (isInitialized) return;

        if (!isArticlePage()) return;

        isInitialized = true;
        console.log('아카라이브 만화 뷰어 초기화');

        // 시리즈 링크를 통한 자동 열기 기능 확인
        checkAndAutoOpenFromSeries();

        // DOM이 완전히 로드된 후에 실행
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', function () {
                createViewerElements();
                addViewerButton();
            });
        } else {
            createViewerElements();
            addViewerButton();
        }

        // 모바일 환경 감지 및 터치 이벤트 추가
        if ('ontouchstart' in window) {
            console.log('모바일 환경 감지: 터치 이벤트 추가');
            // 뷰어가 생성된 후에 터치 이벤트 추가
            setTimeout(() => {
                const viewerContent = document.getElementById('manga-viewer-content');
                if (viewerContent) {
                    viewerContent.addEventListener('touchstart', handleTouchStart, { passive: false });
                    viewerContent.addEventListener('touchmove', handleTouchMove, { passive: false });
                    viewerContent.addEventListener('touchend', handleTouchEnd, { passive: false });
                }
            }, 100);
        }
    }// 터치 이벤트 처리 (모바일용) - 개선된 버전
    let touchStartX = 0;
    let touchStartY = 0;
    let touchStartTime = 0;
    let touchMoved = false;
    let isDoubleTap = false;
    let lastTouchTime = 0;

    function handleTouchStart(e) {
        const touch = e.changedTouches[0];
        touchStartX = touch.screenX;
        touchStartY = touch.screenY;
        touchStartTime = Date.now();
        touchMoved = false;

        // 더블탭 감지
        const currentTime = Date.now();
        if (currentTime - lastTouchTime < 300) {
            isDoubleTap = true;
            e.preventDefault(); // 더블탭 시 줌 방지
        } else {
            isDoubleTap = false;
        }
        lastTouchTime = currentTime;
    }

    function handleTouchMove(e) {
        const touch = e.changedTouches[0];
        const moveX = Math.abs(touch.screenX - touchStartX);
        const moveY = Math.abs(touch.screenY - touchStartY);

        // 5px 이상 움직였다면 스와이프로 간주
        if (moveX > 5 || moveY > 5) {
            touchMoved = true;
        }
    }

    function handleTouchEnd(e) {
        if (!touchMoved && isDoubleTap) {
            // 더블탭으로 서랍 토글
            toggleDrawer();
            return;
        }

        if (!touchMoved || Date.now() - touchStartTime > 800) {
            // 탭이나 너무 긴 터치는 무시
            return;
        }

        const touch = e.changedTouches[0];
        const touchEndX = touch.screenX;
        const touchEndY = touch.screenY;
        const diffX = touchEndX - touchStartX;
        const diffY = touchEndY - touchStartY;

        // 세로 스와이프가 더 크면 무시 (세로 스크롤)
        if (Math.abs(diffY) > Math.abs(diffX)) {
            return;
        }

        const minSwipeDistance = 80;
        const fastSwipeTime = 300;
        const isFastSwipe = Date.now() - touchStartTime < fastSwipeTime;

        // 빠른 스와이프는 더 짧은 거리로도 인정
        const effectiveMinDistance = isFastSwipe ? minSwipeDistance * 0.6 : minSwipeDistance;

        if (Math.abs(diffX) > effectiveMinDistance) {
            if (diffX > 0) {
                prevImage(); // 오른쪽으로 스와이프 -> 이전 이미지
            } else {
                nextImage(); // 왼쪽으로 스와이프 -> 다음 이미지
            }
        }
    }

    // 페이지 변경을 감지하여 스크립트 재초기화 (SPA 대응)
    let lastUrl = location.href;
    new MutationObserver(() => {
        if (location.href !== lastUrl) {
            lastUrl = location.href;
            isInitialized = false;
            setTimeout(init, 1000); // 페이지 전환 후 1초 뒤에 다시 초기화
        }
    }).observe(document, { subtree: true, childList: true });

    init();

    // IntersectionObserver를 이용한 지연 로딩 최적화
    let drawerObserver = null;
    let loadedImages = new Set();

    // 이미지 지연 로딩 초기화
    function initLazyLoading() {
        if ('IntersectionObserver' in window) {
            drawerObserver = new IntersectionObserver((entries) => {
                entries.forEach(entry => {
                    if (entry.isIntersecting) {
                        const img = entry.target;
                        const realSrc = img.dataset.src;
                        if (realSrc && !loadedImages.has(realSrc)) {
                            img.src = realSrc;
                            loadedImages.add(realSrc);
                            drawerObserver.unobserve(img);
                        }
                    }
                });
            }, {
                rootMargin: '100px' // 100px 전에 미리 로드
            });
        }
    }

    // 메모리 관리 - 사용하지 않는 이미지 캐시 정리
    function cleanupImageCache() {
        if (imageCache.size > 50) { // 50개 이상 캐시되면 정리
            const entries = Array.from(imageCache.entries());
            // 오래된 순서로 절반 정리 (LRU 방식)
            const toDelete = entries.slice(0, entries.length / 2);
            toDelete.forEach(([key]) => {
                imageCache.delete(key);
            });
        }
    }

    // 성능 모니터링
    function performanceLog(action, startTime) {
        if (console.time && performance.now) {
            const duration = performance.now() - startTime;
            console.log(`[만화뷰어] ${action}: ${duration.toFixed(2)}ms`);
        }
    }

    // 성능 모니터링 시스템 추가
    let performanceStats = {
        keyPressCount: 0,
        imageLoadCount: 0,
        drawerToggleCount: 0,
        startTime: Date.now()
    };

    // 성능 통계 업데이트
    function updatePerformanceStats(action) {
        switch (action) {
            case 'keypress':
                performanceStats.keyPressCount++;
                break;
            case 'imageload':
                performanceStats.imageLoadCount++;
                break;
            case 'drawer':
                performanceStats.drawerToggleCount++;
                break;
        }
    }

    // 성능 통계 출력 (디버그용)
    function logPerformanceStats() {
        const runTime = Date.now() - performanceStats.startTime;
        console.log(`[만화뷰어 성능 통계] 실행시간: ${Math.floor(runTime / 1000)}초`);
        console.log(`키 입력: ${performanceStats.keyPressCount}회`);
        console.log(`이미지 로드: ${performanceStats.imageLoadCount}회`);
        console.log(`서랍 토글: ${performanceStats.drawerToggleCount}회`);
    }
})();