Sleazy Fork is available in English.

LOLICON Wide Hentai

Full width E-Hentai and Exhentai, dynamically adjusting the page width, also allows you to adjust the size and margins of the thumbnails, infinite scroll to automatically load the next page

// ==UserScript==
// @name                LOLICON Wide Hentai
// @name:zh-CN          LOLICON 宽屏E绅士
// @name:zh-TW          LOLICON 寬屏E紳士
// @name:ja             LOLICON ワイド Hentai
// @name:ko             LOLICON 와이드 Hentai
// @name:ru             LOLICON Широкий Hentai
// @namespace           https://greasyfork.org/scripts/516145
// @version             2024.12.24
// @description         Full width E-Hentai and Exhentai, dynamically adjusting the page width, also allows you to adjust the size and margins of the thumbnails, infinite scroll to automatically load the next page
// @description:zh-CN   全屏宽度 E 绅士,动态调整页面宽度,同时支持调整缩略图大小和边距,无限滚动自动加载下一页
// @description:zh-TW   全螢幕寬度 E 紳士,動態調整頁面寬度,並支援調整縮圖大小及邊距,無限滾動自動加載下一頁
// @description:ja      フルスクリーン幅 E-Hentai と Exhentai、ページ幅を動的に調整し、サムネイルのサイズと余白も調整可能、スクロール時に自動的に次のページを読み込み
// @description:ko      전체 화면 너비 E-Hentai와 Exhentai, 페이지 너비를 동적으로 조정하고 썸네일 크기와 여백도 조정 가능, 스크롤 시 자동으로 다음 페이지를 로드
// @description:ru      Полная ширина E-Hentai и Exhentai, динамически регулирующая ширину страницы, а также позволяющая изменять размер миниатюр и поля, автоматическая загрузка следующей страницы при прокрутке
// @icon                https://e-hentai.org/favicon.ico
// @match               https://e-hentai.org/*
// @match               https://exhentai.org/*
// @exclude             https://e-hentai.org/s/*
// @exclude             https://exhentai.org/s/*
// @run-at              document-end
// @grant               GM_setValue
// @grant               GM_getValue
// @grant               GM_registerMenuCommand
// @noframes
// ==/UserScript==

(function () {
    'use strict';

    function $(id) { return document.getElementById(id); }

    function c(id) { return document.getElementsByClassName(id); }

    // 获取当前设备的设备像素比(DPR)
    const devicePixelRatio = window.devicePixelRatio || 1;

    // 获取用户语言
    const userLang = navigator.language || navigator.userLanguage;

    let columnWidthS,
        columnWidthSb,
        columnWidthG,
        marginAdjustmentS,
        marginAdjustmentG,
        paddingAdjustmentS,
        columnsS,
        OLDcolumnsS;

    // 搜索类别行
    let initialTableRows = null;

    // 缩略图信息
    let thumbnailData = [];

    // gl1t序号
    let gl1tIndex = 0;

    // 配置项
    const config = {
        zoomFactor: { step: 0.01, min: 0.5, max: 10 },
        margin: { step: 1, min: 0, max: 100 },
        pageMargin: { step: 1, min: 0, max: 1000 },
        pagePadding: { step: 1, min: 0, max: 100 },
    };

    // 设置默认值
    const defaults = {
        zoomFactor: 1,
        margin: 10,
        pageMargin: 10,
        pagePadding: 10,
        fullScreenMode: false,
        squareMode: false,
        infiniteScroll: false,
        showIndex: false,
        liveURLUpdate: false
    };

    let zoomFactor = GM_getValue('zoomFactor', defaults.zoomFactor);
    let margin = GM_getValue('margin', defaults.margin);
    let pageMargin = GM_getValue('pageMargin', defaults.pageMargin);
    let pagePadding = GM_getValue('pagePadding', defaults.pagePadding);
    let fullScreenMode = GM_getValue('fullScreenMode', defaults.fullScreenMode);
    let squareMode = GM_getValue('squareMode', defaults.squareMode);
    let infiniteScroll = GM_getValue('infiniteScroll', defaults.infiniteScroll);
    let showIndex = GM_getValue('showIndex', defaults.showIndex);
    let liveURLUpdate = GM_getValue('liveURLUpdate', defaults.liveURLUpdate);

    const originalUrl = window.location.href;

    const isThumbnailMode = !!c('itg gld')[0]; // 缩略图模式
    const isGalleryPage = window.location.pathname.indexOf('/g/') == 0; // /g/ 画廊页面
    const isWatchedPage = window.location.pathname.indexOf('/watched') == 0; // /watched 订阅页面
    const isPopularPage = window.location.pathname.indexOf('/popular') == 0; // /popular 热门页面
    const isFavoritesPage = window.location.pathname.indexOf('/favorites.php') == 0; // /favorites 收藏夹页面

    /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */

    /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */

    // 定义语言包
    const translations = {
        'zoomFactor': {
            'en': 'Thumbnail Zoom',
            'zh-CN': '缩略图缩放',
            'zh-TW': '縮圖縮放',
            'ja': 'サムネイルズーム',
            'ko': '썸네일 확대 비율',
            'ru': 'Масштаб миниатюры :'
        },
        'zoomFactorRange': {
            'en': `Invalid Thumbnail zoom factor! Please enter a value between ${config.zoomFactor.min} and ${config.zoomFactor.max}. Default ${defaults.zoomFactor}`,
            'zh-CN': `缩略图缩放比例无效!请输入 ${config.zoomFactor.min} 至 ${config.zoomFactor.max} 之间的值。 默认 ${defaults.zoomFactor}`,
            'zh-TW': `縮圖縮放比例無效!請輸入 ${config.zoomFactor.min} 至 ${config.zoomFactor.max} 之間的值。 預設為 ${defaults.zoomFactor}`,
            'ja': `無効なサムネイルズーム比率! ${config.zoomFactor.min} から ${config.zoomFactor.max} の間の値を入力してください。 デフォルトは ${defaults.zoomFactor}`,
            'ko': `잘못된 썸네일 확대 비율! ${config.zoomFactor.min} 에서 ${config.zoomFactor.max} 사이의 값을 입력하세요. 기본값 ${defaults.zoomFactor}`,
            'ru': `Неверный масштаб миниатюры! Пожалуйста, введите значение от ${config.zoomFactor.min} до ${config.zoomFactor.max}. По умолчанию ${defaults.zoomFactor}`
        },
        'margin': {
            'en': 'Thumbnail Margin',
            'zh-CN': '缩略图边距',
            'zh-TW': '縮圖邊距',
            'ja': 'サムネイルマージン',
            'ko': '썸네일 여백',
            'ru': 'Отступы миниатюры :'
        },
        'marginRange': {
            'en': `Invalid Thumbnail margin! Please enter a value between ${config.margin.min} and ${config.margin.max}. Default ${defaults.margin}`,
            'zh-CN': `缩略图边距无效!请输入 ${config.margin.min} 至 ${config.margin.max} 之间的值。 默认 ${defaults.margin}`,
            'zh-TW': `縮圖邊距無效!請輸入 ${config.margin.min} 至 ${config.margin.max} 之間的值。 預設為 ${defaults.margin}`,
            'ja': `無効なサムネイルマージン! ${config.margin.min} から ${config.margin.max} の間の値を入力してください。 デフォルトは ${defaults.margin}`,
            'ko': `잘못된 썸네일 여백! ${config.margin.min} 에서 ${config.margin.max} 사이의 값을 입력하세요. 기본값 ${defaults.margin}`,
            'ru': `Неверный Отступы миниатюры! Пожалуйста, введите значение от ${config.margin.min} до ${config.margin.max}. По умолчанию ${defaults.margin}`
        },
        'pageMargin': {
            'en': 'Page Margin',
            'zh-CN': '页面外边距',
            'zh-TW': '頁面外邊距',
            'ja': 'ページマージン',
            'ko': '페이지 외부 여백',
            'ru': 'Внешний отступ страницы :'
        },
        'pageMarginRange': {
            'en': `Invalid page margin! Please enter a value between ${config.pageMargin.min} and ${config.pageMargin.max}. Default ${defaults.pageMargin}`,
            'zh-CN': `页面外边距无效!请输入 ${config.pageMargin.min} 至 ${config.pageMargin.max} 之间的值。 默认 ${defaults.pageMargin}`,
            'zh-TW': `頁面外邊距無效!請輸入 ${config.pageMargin.min} 至 ${config.pageMargin.max} 之間的值。 預設為 ${defaults.pageMargin}`,
            'ja': `無効なページマージン! ${config.pageMargin.min} から ${config.pageMargin.max} の間の値を入力してください。 デフォルトは ${defaults.pageMargin}`,
            'ko': `잘못된 페이지 외부 여백! ${config.pageMargin.min} 에서 ${config.pageMargin.max} 사이의 값을 입력하세요. 기본값 ${defaults.pageMargin}`,
            'ru': `Неверный Внешний отступ страницы! Пожалуйста, введите значение от ${config.pageMargin.min} до ${config.pageMargin.max}. По умолчанию ${defaults.pageMargin}`
        },
        'pagePadding': {
            'en': 'Page Padding',
            'zh-CN': '页面内边距',
            'zh-TW': '頁面內邊距',
            'ja': 'ページパディング',
            'ko': '페이지 내부 여백',
            'ru': 'Внутренний отступ страницы :'
        },
        'pagePaddingRange': {
            'en': `Invalid page padding! Please enter a value between ${config.pagePadding.min} and ${config.pagePadding.max}. Default ${defaults.pagePadding}`,
            'zh-CN': `页面内边距无效!请输入 ${config.pagePadding.min} 至 ${config.pagePadding.max} 之间的值。 默认 ${defaults.pagePadding}`,
            'zh-TW': `頁面內邊距無效!請輸入 ${config.pagePadding.min} 至 ${config.pagePadding.max} 之間的值。 預設為 ${defaults.pagePadding}`,
            'ja': `無効なページパディング! ${config.pagePadding.min} から ${config.pagePadding.max} の間の値を入力してください。 デフォルトは ${defaults.pagePadding}`,
            'ko': `잘못된 페이지 내부 여백! ${config.pagePadding.min} 에서 ${config.pagePadding.max} 사이의 값을 입력하세요. 기본값 ${defaults.pagePadding}`,
            'ru': `Неверный Внутренний отступ страницы! Пожалуйста, введите значение от ${config.pagePadding.min} до ${config.pagePadding.max}. По умолчанию ${defaults.pagePadding}`
        },
        'fullScreenMode': {
            'en': 'Full Screen Mode',
            'zh-CN': '全屏模式',
            'zh-TW': '全螢幕模式',
            'ja': 'フルスクリーンモード',
            'ko': '전체 화면 모드',
            'ru': 'Режим полного экрана :'
        },
        'squareMode': {
            'en': 'Square Thumbnail',
            'zh-CN': '方形缩略图',
            'zh-TW': '方形縮圖',
            'ja': 'スクエアサムネイル',
            'ko': '정사각형 썸네일',
            'ru': 'Квадратная миниатюра :'
        },
        'infiniteScroll': {
            'en': 'Infinite Scroll',
            'zh-CN': '无限滚动',
            'zh-TW': '無限滾動',
            'ja': '無限スクロール',
            'ko': '무한 스크롤',
            'ru': 'Бесконечная прокрутка',
        },
        'showIndex': {
            'en': 'Show Index',
            'zh-CN': '显示序号',
            'zh-TW': '顯示序號',
            'ja': 'インデックスを表示',
            'ko': '인덱스 표시',
            'ru': 'Показать индекс',
        },
        'liveURLUpdate': {
            'en': 'Live URL Update',
            'zh-CN': '实时更新网址',
            'zh-TW': '實時更新網址',
            'ja': 'URLのライブ更新',
            'ko': '실시간 URL 업데이트',
            'ru': 'Живое обновление URL',
        },
        'settings': {
            'en': 'Settings',
            'zh-CN': '设置',
            'zh-TW': '設置',
            'ja': '設定',
            'ko': '설정',
            'ru': 'Настройки'
        },
        'settingsPanel': {
            'en': 'Settings Panel',
            'zh-CN': '设置面板',
            'zh-TW': '設置面板',
            'ja': '設定パネル',
            'ko': '설정 패널',
            'ru': 'Панель настроек'
        },
        'save': {
            'en': 'Save',
            'zh-CN': '保存',
            'zh-TW': '儲存',
            'ja': '保存',
            'ko': '저장',
            'ru': 'Сохранить'
        },
        'cancel': {
            'en': 'Cancel',
            'zh-CN': '取消',
            'zh-TW': '取消',
            'ja': 'キャンセル',
            'ko': '취소',
            'ru': 'Отменить'
        },
        'InvalidPage': {
            'en': 'only effective in thumbnail mode or gallery page.',
            'zh-CN': '仅在缩略图模式或画廊页面有效',
            'zh-TW': '僅在縮圖模式或畫廊頁面有效',
            'ja': 'サムネイルモードまたはギャラリーページでのみ有効です。',
            'ko': '썸네일 모드 또는 갤러리 페이지에서만 유효합니다.',
            'ru': 'это возможно только в режиме миниатюр или на странице галереи.'
        },
    };

    // 根据用户语言选择对应的文本
    const translate = (key) => {
        const lang = userLang.substring(0, 2);

        switch (lang) {
            case 'zh':
                return translations[key][userLang.startsWith('zh-TW') ? 'zh-TW' : 'zh-CN'];
            case 'ja':
                return translations[key].ja;
            case 'ko':
                return translations[key].ko;
            case 'ru':
                return translations[key].ru;
            default:
                return translations[key].en;
        }
    };

    // 创建和显示设置面板
    function showSettingsPanel() {
        if (document.getElementById('settings-panel')) return;

        const panel = document.createElement('div');
        panel.id = 'settings-panel';
        panel.style.position = 'fixed';
        panel.style.top = '24px';
        panel.style.right = '24px';
        panel.style.padding = '12px 12px';
        panel.style.backgroundColor = 'rgba(255, 255, 255, 0.9)';
        panel.style.border = '2px solid #00AAFF';
        panel.style.borderRadius = '9px';
        panel.style.boxShadow = '0 0 12px rgba(0,0,0,0.24)';
        panel.style.zIndex = '999999';
        panel.style.fontFamily = '"Segoe UI", Tahoma, Geneva, Verdana, sans-serif';
        panel.style.fontSize = '12px';
        panel.style.color = '#222';

        if (isThumbnailMode) {
            panel.innerHTML = `
            <h3 style='margin: 0; margin-bottom: 10px; font-size: 16px; color: #00AAFF; text-align: center;'>${translate('settingsPanel')}</h3>
            ${createInputHTML('zoomFactor', zoomFactor, config.zoomFactor.step, config.zoomFactor.min, config.zoomFactor.max)}
            ${createInputHTML('margin', margin, config.margin.step, config.margin.min, config.margin.max)}
            ${createInputHTML('pageMargin', pageMargin, config.pageMargin.step, config.pageMargin.min, config.pageMargin.max)}
            ${createInputHTML('pagePadding', pagePadding, config.pagePadding.step, config.pagePadding.min, config.pagePadding.max)}
            ${createCheckboxHTML('fullScreenMode', fullScreenMode == true)}
            ${createCheckboxHTML('squareMode', squareMode == true)}
            ${createCheckboxHTML('infiniteScroll', infiniteScroll == true)}
            ${createCheckboxHTML('showIndex', showIndex == true)}
            ${createCheckboxHTML('liveURLUpdate', liveURLUpdate == true)}
            ${createButtonsHTML()}
        `;
        } else if (isGalleryPage) {
            panel.innerHTML = `
            <h3 style='margin: 0; margin-bottom: 10px; font-size: 16px; color: #00AAFF; text-align: center;'>${translate('settingsPanel')}</h3>
            ${createInputHTML('pageMargin', pageMargin, config.pageMargin.step, config.pageMargin.min, config.pageMargin.max)}
            ${createCheckboxHTML('fullScreenMode', fullScreenMode == true)}
            ${createButtonsHTML()}
        `;
        } else {
            panel.innerHTML = `
            <h3 style='margin: 0; margin-bottom: 10px; font-size: 16px; color: #00AAFF; text-align: center;'>${translate('settingsPanel')}</h3>
            <div style='margin-top: 20px; margin-bottom: 20px; font-size: 14px; line-height: 2; font-weight: bold; text-align: center;'>${translate('InvalidPage')}</div>
            ${createButtonsHTML()}
        `;
        }

        document.body.appendChild(panel);

        panel.addEventListener('wheel', (event) => {
            event.preventDefault();
            event.stopPropagation();
        }, { passive: false });

        bindInputEvents(panel);
        bindButtons(panel);
    }

    // 动态生成输入框HTML
    function createInputHTML(name, value, step, min, max) {
        return `
        <div style='margin-bottom: 10px; display: flex; align-items: center;'>
            <label for='${name}Input' style='font-weight: bold; margin-right: 10px;'>${translate(name)} </label>
            <input type='number' id='${name}Input' value='${value}' step='${step}' min='${min}' max='${max}' style='width: 60px; padding: 5px; border: 1px solid #ccc; border-radius: 5px; box-sizing: border-box; margin-left: auto;'>
        </div>
    `;
    }

    // 动态生成复选框HTML
    function createCheckboxHTML(name, checked) {
        return `
        <div style='margin-bottom: 10px; display: flex; align-items: center;'>
            <label for='${name}Input' style='font-weight: bold; margin-right: 10px;'>${translate(name)} </label>
            <input type='checkbox' id='${name}Input' style='width: 30px; height: 20px; cursor: pointer; margin-left: auto;' ${checked ? 'checked' : ''}>
        </div>
    `;
    }

    // 动态生成按钮HTML
    function createButtonsHTML() {
        return `
        <div style='display: flex; justify-content: space-between;'>
            <button id='saveSettingsBtn' style='padding: 8px 12px; background-color: #00AAFF; color: white; border: none; border-radius: 5px; cursor: pointer; font-weight: bold;'>${translate('save')}</button>
            <button id='cancelSettingsBtn' style='padding: 8px 12px; background-color: #FF2222; color: white; border: none; border-radius: 5px; cursor: pointer; font-weight: bold;'>${translate('cancel')}</button>
        </div>
    `;
    }

    // 绑定事件
    function bindInputEvents(panel) {
        panel.querySelectorAll('input[type="number"]').forEach(input => {
            input.addEventListener('input', handleInputChange);
            input.addEventListener('wheel', handleWheelChange);
        });

        ['#fullScreenModeInput', '#squareModeInput', '#infiniteScrollInput', '#showIndexInput', '#liveURLUpdateInput'].forEach(selector => {
            const input = panel.querySelector(selector);
            if (input) {
                input.addEventListener('change', handleCheckboxChange);
            }
        });
    }

    function bindButtons(panel) {
        panel.querySelectorAll('button').forEach(btn => {
            btn.addEventListener('mouseover', function () { this.style.opacity = '0.8'; });
            btn.addEventListener('mouseout', function () { this.style.opacity = '1'; });
        });

        if (isThumbnailMode || isGalleryPage) {
            panel.querySelector('#saveSettingsBtn').addEventListener('click', () => saveSettings(panel));
            panel.querySelector('#cancelSettingsBtn').addEventListener('click', () => cancelSettings(panel));
        } else {
            panel.querySelector('#saveSettingsBtn').addEventListener('click', () => panel.remove());
            panel.querySelector('#cancelSettingsBtn').addEventListener('click', () => panel.remove());
        }
    }

    // 输入框变化事件
    function handleInputChange(event) {
        const { id, value } = event.target;
        const numValue = parseFloat(value);

        if (id.includes('zoomFactor') && numValue >= config.zoomFactor.min && numValue <= config.zoomFactor.max) {
            zoomFactor = numValue;
        } else if (id.includes('margin') && numValue >= config.margin.min && numValue <= config.margin.max) {
            margin = numValue;
        } else if (id.includes('pageMargin') && numValue >= config.pageMargin.min && numValue <= config.pageMargin.max) {
            pageMargin = numValue;
        } else if (id.includes('pagePadding') && numValue >= config.pagePadding.min && numValue <= config.pagePadding.max) {
            pagePadding = numValue;
        }

        applyChanges();
    }

    // 滚轮事件处理
    function handleWheelChange(event) {
        event.preventDefault();
        const input = event.target;
        let value = parseFloat(input.value);
        const step = parseFloat(input.step);
        const delta = event.deltaY < 0 ? step : -step;

        value = Math.min(parseFloat(input.max), Math.max(parseFloat(input.min), value + delta));

        if (step < 1) {
            input.value = value.toFixed(2);
        } else {
            input.value = value;
        }

        input.dispatchEvent(new Event('input'));
    }

    // 复选框变化事件
    function handleCheckboxChange(event) {
        if (event.target.id === 'fullScreenModeInput') {
            fullScreenMode = event.target.checked ? true : false;
        } else if (event.target.id === 'squareModeInput') {
            squareMode = event.target.checked ? true : false;
        } else if (event.target.id === 'infiniteScrollInput') {
            infiniteScroll = event.target.checked ? true : false;
        } else if (event.target.id === 'showIndexInput') {
            showIndex = event.target.checked ? true : false;
        } else if (event.target.id === 'liveURLUpdateInput') {
            liveURLUpdate = event.target.checked ? true : false;
        }

        applyChanges();
    }

    // 保存设置
    function saveSettings(panel) {
        GM_setValue('fullScreenMode', fullScreenMode);
        GM_setValue('squareMode', squareMode);
        GM_setValue('infiniteScroll', infiniteScroll);
        GM_setValue('showIndex', showIndex);
        GM_setValue('liveURLUpdate', liveURLUpdate);

        let errors = [];
        Object.entries(config).forEach(([settingKey, { min, max }]) => {
            const input = panel.querySelector('#' + settingKey + 'Input');
            if (input) {
                const value = parseFloat(input.value);
                if (isNaN(value) || value < min || value > max) {
                    errors.push(translate(settingKey + 'Range'));
                    return;
                }
                GM_setValue(settingKey, value);
            }
        });

        if (errors.length > 0) {
            alert(errors.join('\n\n'));
            return;
        }
        panel.remove();
    }

    // 取消设置
    function cancelSettings(panel) {
        zoomFactor = GM_getValue('zoomFactor');
        margin = GM_getValue('margin');
        pageMargin = GM_getValue('pageMargin');
        pagePadding = GM_getValue('pagePadding');
        fullScreenMode = GM_getValue('fullScreenMode');
        squareMode = GM_getValue('squareMode');
        infiniteScroll = GM_getValue('infiniteScroll');
        showIndex = GM_getValue('showIndex');
        liveURLUpdate = GM_getValue('liveURLUpdate');

        applyChanges();
        panel.remove();
    }

    // 应用更改
    function applyChanges() {
        calculateDimensions();

        if (isThumbnailMode) {
            adjustColumnsS();
            modifyThumbnailSize();
        } else if (isGalleryPage) {
            adjustColumnsG();
        }
    }

    // 初始化设置 如果为空 先保存初始值
    function initialize() {
        for (const [key, defaultValue] of Object.entries(defaults)) {
            window[key] = GM_getValue(key, defaultValue);

            if (GM_getValue(key) === undefined) {
                GM_setValue(key, defaultValue);
            }
        }
    }

    /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */

    /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */

    // 计算尺寸
    function calculateDimensions() {
        columnWidthS = 250 * zoomFactor + margin * 2; // 每列的宽度 250-400 270
        columnWidthSb = columnWidthS + (2 / devicePixelRatio); // 加上缩略图边框,边框宽度受设备像素比影响
        columnWidthG = 240; // 画廊每列的宽度
        marginAdjustmentS = 14 + pageMargin * 2; // 页面边距调整值 body-padding:2 ido-padding:5
        marginAdjustmentG = 34 + pageMargin * 2; // 画廊页面边距调整值 body-padding:2 gdt-padding:15
        paddingAdjustmentS = pagePadding * 2; // 页面内边距调整值
    }

    // 根据页面宽度动态调整列数 非画廊页面 且 缩略图模式
    function adjustColumnsS() {
        console.log('LOLICON 缩略图页面调整');

        const width = document.documentElement.clientWidth; // window.innerWidth
        const minWidthNumber = parseFloat(getComputedStyle(c('ido')[0]).minWidth);

        let clientWidthS_itg = Math.max(width - marginAdjustmentS - paddingAdjustmentS, minWidthNumber); // 计算宽度
        columnsS = Math.max(Math.floor(clientWidthS_itg / columnWidthSb), 1); // 计算列数

        clientWidthS_itg = Math.max(columnsS * columnWidthSb, fullScreenMode ? clientWidthS_itg : minWidthNumber); // 根据全屏模式调整

        let clientWidthS_ido = Math.min(clientWidthS_itg + paddingAdjustmentS, width);
        c('ido')[0].style.maxWidth = clientWidthS_ido + 'px'; // 设置最大宽度 1370
        c('itg gld')[0].style.gridTemplateColumns = 'repeat(' + columnsS + ', 1fr)'; // 设置列数
        c('itg gld')[0].style.width = clientWidthS_itg + 'px'; // 设置边距 '99%'

        const searchbox = $('searchbox'); // 搜索盒子
        if (searchbox) {
            const tbody = searchbox.querySelector('tbody');
            if (tbody) {
                // 保存搜索类别行
                if (!initialTableRows) {
                    initialTableRows = tbody.innerHTML;
                }
                if (clientWidthS_ido >= 1460) {
                    // 合并搜索类别行
                    const rows = tbody.querySelectorAll('tr');
                    if (rows.length >= 2) {
                        const firstRow = rows[0];
                        const secondRow = rows[1];

                        Array.from(secondRow.children).forEach(td => {
                            firstRow.appendChild(td);
                        });
                        secondRow.remove();
                    }
                } else {
                    // 恢复为初始状态
                    tbody.innerHTML = initialTableRows;
                }
            }

            // 调整搜索盒子大小
            const isLargerWidth = clientWidthS_ido >= 1460;
            if (c('idi')[0]) { c('idi')[0].style.width = (isLargerWidth ? 720 + 670 : 720) + 'px'; }
            if (c('idi')[1]) { c('idi')[1].style.width = (isLargerWidth ? 720 + 670 : 720) + 'px'; }
            if ($('f_search')) { $('f_search').style.width = (isLargerWidth ? 560 + 670 : 560) + 'px'; }
        }

        if (columnsS != OLDcolumnsS && liveURLUpdate && !isPopularPage && !isFavoritesPage) {
            throttledGetTheLeftmostGl1t();
            OLDcolumnsS = columnsS;
        }
    }

    // 根据页面宽度动态调整列数 画廊页面
    function adjustColumnsG() {
        console.log('LOLICON 画廊页面调整');
        const width = window.innerWidth;

        let columnsG = Math.floor((width - marginAdjustmentG) / columnWidthG); // 减去边距,并计算列数
        columnsG = Math.max(columnsG, 3);

        let clientWidthG_gdt = 700 + (columnsG - 3) * columnWidthG;

        if (fullScreenMode && columnsG >= 6) {
            clientWidthG_gdt = width - marginAdjustmentG;
        }

        const isMulticolumn = columnsG >= 6;
        if (c('gm')[0]) { c('gm')[0].style.maxWidth = isMulticolumn ? (clientWidthG_gdt + 20) + 'px' : ''; } // 设置最详情大宽度 720 960 1200
        if (c('gm')[1]) { c('gm')[1].style.maxWidth = isMulticolumn ? (clientWidthG_gdt + 20) + 'px' : ''; } // 设置最评论区大宽度 720 960 1200
        if ($('gd2')) { $('gd2').style.width = isMulticolumn ? (clientWidthG_gdt - 255) + 'px' : ''; } // 设置标题栏宽度 710 925
        if ($('gmid')) { $('gmid').style.width = isMulticolumn ? (clientWidthG_gdt - 250) + 'px' : ''; } // 设置标签栏宽度 710 930
        if ($('gd4')) { $('gd4').style.width = isMulticolumn ? (clientWidthG_gdt - 600) + 'px' : ''; } // 设置标签栏宽度 360 580
        if ($('gdo')) { $('gdo').style.maxWidth = isMulticolumn ? (clientWidthG_gdt + 20) + 'px' : ''; } // 设置缩略图设置栏最大宽度 720 960 1200

        const gdt = $('gdt');
        if (gdt) {
            if (columnsG < 6) {
                const minWidthNumber = parseFloat(getComputedStyle(c('gm')[0]).maxWidth);
                clientWidthG_gdt = minWidthNumber - 20;
                columnsG = Math.floor(minWidthNumber / columnWidthG);
            }

            gdt.style.maxWidth = clientWidthG_gdt + 'px'; // 设置最大宽度 700 940 1180

            if (gdt.classList.contains('gt100')) {
                gdt.style.gridTemplateColumns = 'repeat(' + columnsG * 2 + ', 1fr)';
            } else if (gdt.classList.contains('gt200')) {
                gdt.style.gridTemplateColumns = 'repeat(' + columnsG + ', 1fr)';
            }
        }
    }

    // 收集缩略图信息
    function collectThumbnailData() {
        const gl1tElements = document.querySelectorAll('.gl1t');

        gl1tElements.forEach((gl1t, index) => {
            if (index == gl1tIndex) {
                gl1tIndex++;

                const gl3t = gl1t.querySelector('.gl3t');
                const gl4t = gl1t.querySelector('.gl4t');
                const gl5t = gl1t.querySelector('.gl5t');
                const gl6t = gl1t.querySelector('.gl6t');
                const glink = gl1t.querySelector('.glink');
                const gl5tFirstChildDiv = gl5t?.querySelector('div:nth-child(1)');
                const img = gl3t?.querySelector('img');

                thumbnailData.push({
                    gl1t,
                    gl3t,
                    gl4t,
                    gl5t,
                    gl6t,
                    glink,
                    gl5tFirstChildDiv,
                    img,
                    originalWidth: gl3t?.clientWidth,
                    originalHeight: gl3t?.clientHeight,
                    originalImgWidth: img?.clientWidth,
                    originalImgHeight: img?.clientHeight,
                });
            }
        });
        // console.log('LOLICON thumbnailData', thumbnailData);
    }

    // 修改缩略图大小
    function modifyThumbnailSize() {
        console.log('LOLICON 修改缩略图大小');

        const minWidthNumber = parseFloat(getComputedStyle(c('ido')[0]).minWidth);
        let columnWidthSbm = Math.max(columnWidthSb, minWidthNumber / Math.floor(Math.max(minWidthNumber / columnWidthSb, 1)));

        if (fullScreenMode) {
            columnWidthSbm = columnWidthS * 2;
        }

        thumbnailData.forEach((data, index) => {
            const {
                gl1t,
                gl3t,
                gl4t,
                gl5t,
                gl6t,
                glink,
                gl5tFirstChildDiv,
                img,
                originalWidth,
                originalHeight,
                originalImgWidth,
                originalImgHeight
            } = data;

            let zoomFactorL = zoomFactor;

            if (squareMode && originalWidth < 250) {
                zoomFactorL = zoomFactor * 250 / originalWidth;
            }

            // 设置 gl1t 的宽度
            gl1t.style.minWidth = columnWidthS + 'px';
            gl1t.style.maxWidth = columnWidthSbm + 'px';

            // 调整 gl3t 的宽高
            if (gl3t) {
                const newWidth = originalWidth * zoomFactorL;
                const newHeight = originalHeight * zoomFactorL;
                gl3t.style.width = newWidth + 'px';
                gl3t.style.height = (squareMode ? newWidth : newHeight) + 'px';
            }

            // 小列宽时处理 gl5t 换行逻辑
            if (gl5t) {
                const isSmallWidth = columnWidthS <= 199;
                gl5t.style.flexWrap = isSmallWidth ? 'wrap' : '';
                gl5t.style.height = isSmallWidth ? '92px' : '';

                if (gl5tFirstChildDiv) { gl5tFirstChildDiv.style.left = isSmallWidth ? '4.5px' : ''; }
            }

            // 调整 glink 的标题序号
            if (glink) {
                const glinkSpan = glink.querySelector('span[data-LOLICON-index="true"]');

                if (showIndex) {
                    if (!glinkSpan) {
                        const span = document.createElement('span');
                        span.setAttribute('data-LOLICON-index', 'true');
                        span.textContent = `【${index + 1}】 `;
                        glink.insertBefore(span, glink.firstChild);
                    }
                } else if (glinkSpan) {
                    glinkSpan.remove();
                }
            }

            // 调整图片的宽高
            if (img) {
                const newImgWidth = originalImgWidth * zoomFactorL;
                const newImgHeight = originalImgHeight * zoomFactorL;
                let width = newImgWidth;
                let height = newImgHeight;
                let top = '';
                let left = '';

                if (squareMode) {
                    if (newImgWidth <= newImgHeight) {
                        top = ((originalWidth * zoomFactorL) - newImgHeight) / 2 + 'px';
                    } else {
                        left = ((originalWidth * zoomFactorL) - (newImgWidth * newImgWidth / newImgHeight)) / 2 + 'px';
                        width = newImgWidth * newImgWidth / newImgHeight;
                        height = newImgWidth;
                    }
                } else {
                    top = ((originalHeight * zoomFactorL) - newImgHeight) / 2 + 'px';
                }

                img.style.width = width + 'px';
                img.style.height = height + 'px';
                img.style.top = top;
                img.style.left = left;
            }
        });
    }

    /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */

    /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */

    let isLoading = false; // 防止重复加载
    let nextPageLink = document.querySelector('#dnext')?.href; // 初始化下一页链接
    let hasMorePages = !!nextPageLink; // 检查是否还有更多页面

    // 无限滚动加载下一页
    async function loadNextPage() {
        if (isLoading || !hasMorePages) return;

        isLoading = true;
        try {
            console.log('LOLICON 加载下一页:', nextPageLink);
            const response = await fetch(nextPageLink);
            const html = await response.text();
            const parser = new DOMParser();
            const doc = parser.parseFromString(html, 'text/html');
            const nextContent = doc.querySelectorAll('.gl1t');

            if (nextContent.length > 0) {
                const fragment = document.createDocumentFragment();
                nextContent.forEach(item => fragment.appendChild(item));
                c('itg gld')[0].appendChild(fragment);
                console.log('LOLICON 下一页内容已成功加载。');
                collectThumbnailData();
                modifyThumbnailSize();

                if (liveURLUpdate && !isPopularPage && !isFavoritesPage) {
                    getTheLeftmostGl1t();
                }
            } else {
                console.log('LOLICON 未找到下一页的内容,停止加载。');
                hasMorePages = false;
            }

            nextPageLink = doc.querySelector('#dnext')?.href;
            hasMorePages = !!nextPageLink;

            if (hasMorePages) {
                console.log('LOLICON 下一页链接已更新为:', nextPageLink);
            } else {
                console.log('LOLICON 已是最后一页');
            }
        } catch (error) {
            console.error('LOLICON 加载下一页时发生错误:', error);
        } finally {
            isLoading = false;
        }

        if (document.body.offsetHeight <= window.innerHeight) {
            loadNextPage();
        }
    }

    let elementPositions = [];

    // 获取最左侧的 gl1t 位置和URL
    function getTheLeftmostGl1t() {
        elementPositions = [];
        const gl1tElements = document.querySelectorAll('.gl1t');
        const scrollY = window.scrollY;

        for (let i = 0; i < gl1tIndex; i++) {
            if (i % columnsS === 0) {
                const gl1t = gl1tElements[i];
                if (gl1t) {
                    const rect = gl1t.getBoundingClientRect();
                    const urlElement = gl1t.querySelector('a:nth-child(1)');
                    const match = urlElement.href.match(/\/g\/(\d+)\//);

                    elementPositions.push({
                        bottom: rect.bottom + scrollY,
                        url: Number(match[1]) + 1,
                    });
                }
            }
        }

        updateURLOnScroll();
        // console.log('LOLICON elementPositions:', elementPositions);
    }

    let topMostElementURL;

    // 更新地址栏
    function updateURLOnScroll() {
        let newTopMostElementURL;
        const scrollY = window.scrollY;

        for (let i = 0; i < elementPositions.length; i++) {
            const { bottom, url } = elementPositions[i];
            if (bottom >= scrollY) {
                newTopMostElementURL = url;
                break;
            }
        }

        if (newTopMostElementURL != topMostElementURL) {
            let urlObj = new URL(originalUrl);
            urlObj.searchParams.delete('jump');
            urlObj.searchParams.delete('seek');
            urlObj.searchParams.set('next', newTopMostElementURL);
            window.history.replaceState(null, '', urlObj.toString());
            topMostElementURL = newTopMostElementURL;
            // console.log('LOLICON 更新地址栏:',decodedUrl);
        }
    }

    /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */

    /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */

    // 防抖函数
    function debounce(func, wait) {
        let timeout;

        return function (...args) {
            clearTimeout(timeout);
            timeout = setTimeout(() => func(...args), wait);
        };
    }

    // 节流函数
    function throttle(func, wait) {
        let lastTime = 0;
        let timeout = null;

        return function (...args) {
            const now = Date.now();
            const remaining = wait - (now - lastTime);

            if (remaining <= 0) {
                lastTime = now;
                func(...args);
            } else if (!timeout) {
                timeout = setTimeout(() => {
                    lastTime = Date.now();
                    timeout = null;
                    func(...args);
                }, remaining);
            }
        };
    }

    const throttledUpdateURLOnScroll = throttle(updateURLOnScroll, 240);
    const throttledGetTheLeftmostGl1t = throttle(getTheLeftmostGl1t, 600);

    // 设置菜单
    GM_registerMenuCommand(translate('settings'), showSettingsPanel);

    // 监控无限滚动
    function monitorInfiniteScroll() {
        const observer = new IntersectionObserver(([entry]) => {
            if (entry.isIntersecting && infiniteScroll) {
                loadNextPage();
            }
        });

        const bottomElement = document.createElement('div');
        bottomElement.classList.add('LOLICON-infinite-scroll-trigger');
        document.body.appendChild(bottomElement);

        observer.observe(bottomElement);
    }

    console.log('LOLICON 开始');

    // 初始化
    initialize();
    calculateDimensions();

    if (isThumbnailMode) {
        collectThumbnailData();
        modifyThumbnailSize();
        adjustColumnsS();
        monitorInfiniteScroll();

        window.addEventListener('resize', adjustColumnsS);
        window.addEventListener('scroll', () => {
            if (liveURLUpdate && !isPopularPage && !isFavoritesPage) {
                throttledUpdateURLOnScroll();
            }
        });
    } else if (isGalleryPage) {
        adjustColumnsG();
        window.addEventListener('resize', adjustColumnsG);
    }

})();