Yamibo 漫画阅读器

漫区卡片式预览封面,一键进入漫画阅读器,支持自动生成系列目录,智能匹配章节标题。

安装此脚本
作者推荐脚本

您可能也喜欢Yamibo漫区封面卡片

安装此脚本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Yamibo 漫画阅读器
// @namespace    https://bbs.yamibo.com/
// @version      3.5.6
// @author       hitori酱
// @description  漫区卡片式预览封面,一键进入漫画阅读器,支持自动生成系列目录,智能匹配章节标题。
// @match        https://bbs.yamibo.com/thread-*
// @match        https://bbs.yamibo.com/forum.php?mod=viewthread&*
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM_listValues
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/cn2t.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/t2cn.js
// @run-at       document-end
// @noframes
// @license      MIT License
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAB2AAAAdgB+lymcgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAr3SURBVHic7Zt7cNTVFcc/v32H7Ca72c2LhEcS5JFIgUB5JSioQCvKWOVRqSMjxAeoVaYKdapFaccq0OfUOlrKjLUUR1HGUstDMSIJRAyEAAnQvNk8NgnJPvLYTbK7v/6xyYbFZMluNgaK35nfzO7v3HvOud/fueeee3+70D9UwO8AEyDeoJcJ+C2g7G+Qgh8CtgM/Cw+TExsdToXRglSQMDpS56fL9QVTa4vY3tUpANuAjX218UdATZhKFl+R84QQawhHMW4bMWEaqjf8akicHQqYWm0k/+kV7M6uWiChrzYSP/1jDboRQqwhfGi8+xYQp47AMEINENtfG38E3BT4joDhdmC48R0Bw+3AcOM7AobbgeHGTU+ALFSKutwudpw6zq6z+Zy/bEIqSEiNjuPhKTNZPWUmUsHDtUt0c6SylANl5/m69hIV5ibMjnYANAol4/UxPHjrdB5Nn+uj3yW6eafwBH8vPEFxowmX6GaSIY6fTJ5BVvoc5BJpUH6HhIC6Vhv37n6Lk3VGj1KpR+2RqlKOVJWysyCP3Q+s5r1zp/h9XjZ1rTaf/nKZHIlEQmtbCzUtVkrarNw2dxa3dEhxuVw029u5//0dHDNW+OjPNZaTayznbwXH2ffg48SrIwL2fdAEdLld3sEbIvWkJqehVUcCYLaZOVdeRK6xnLF/fBm3KCIIAjG6GGKjYoiLjic+Jg6pzPP03KKb1rZWVEoVr+cXoteqOfT5J5ytrERERKfRcWtKGjqNZ0NmabVSVF7EyTojS997m2NrNgQcCYPOATsL8jhZZ0QfqWf25NnewQPoInRERUZ1D04kITqB+em3M/vWWSQlJDEytnfwABJBQoQ6AoVcAUCTpRWUGkREr76ewQNo1ZHMmTwbfaSe/NpL7CzIC9j/QROw62w+AGnJqUgEX3UF/z1NWXUZcpmc70+awfSJ6WhGaABQKBRIpNd+WtPT0lmUsRCVUkV5TTkFFwt8ByBISEtO9fElEAyagPOXTcikMrRqre/9ygsY642oFCpumzqPeEO8j1yp6veM4htIiE3gnvlLUI9QY2yo5nzlBR+5Vq1FJpVR1FgXsP+DJkAplSGKbm+YAjSYGygxlqCQK5gzeQ7hYb5bakEQkMvlAdnRhGtYnLkIlVJFibGEBnODVyYiIooiKllgOiEEBEyKjsPldtNsNQPgcrkoLDkDwJRx30Pj2Y9TWFLIsbPHAZDKpAhC71nMl19/SfZX2X3qP3z8MLmncgGIUEeQOT3To6/0DC6XC4BmqxmX20VqdFzA/g+agDVTZwNQVF6Ey+2iylSFvcPOyOiR3rDvcnZxqd5Im70NANlVT8poqqa2oe/wNdvMlFSV0tnVCcCouESSEpOwO+xUmqpwuV0UlRcBkDVtTsD+D5qA5anTWDD2FiytFnJO51BaUwbAhFHjvW2arE2IoohBawBAJhu42ThDHKIoYrps8t5LT52GIAiU1ZSRczoHS6uFO5PGsyx1asD+D5oAmUTCRyuyuCt5AtY2G44OB9HaaDThGm+bZptnehgi9R6jA8j+PYg1eMK6oal3zkeoIxgZE4+jw4G1zcbC5InsWb7WW20GgpDsBbSqMA49tJ6Vaekep6NifOTtDk/oq7vzgUQycLNajaeuaGlr8bk/ZuQYAFampXPwoXVoVWFB+R6yzZCAgLXDDoC++0n3oK271g9XeVaDQAjQqD2RdDUBMXoPyRaHHcHv4bZ/hGwzBHCuO5H1ZPseOJ1OAA7nfw7gswIA3gS3a98/+9XdbDX3KT/bUBu8w4SQgPauTmpsVgRBQB1+VZEjqPz2De//xY1fudPmpLbFSmtnB2rFwAurKxEyAsrNTYiIhCkVNOb7PilppCFUZnygHnsHbe0OKixNTI4ZGZSOkOWAcvNlAOyOTiy2Nl+h2x0qM16YLS20tTu6bTcFrSd0BFh6nTDWNvrIPj1ygi3bd+Lo6AxYb0dnF1u27+Q/n/nmleq63mWxrJv8YBDyCAD47NhpH9k/PtjP5q07WLT8GQqLSr336xubudxs8X5vMlsxNfQSeaa4lIXLfsrmrTvY/dEhH52Hsk94P1cMIgJCmgN68K/PvmLDmvu833+z8REKz1dwNK+QqQseJiE+GplUSlW1ibQJSZw7uguAjCWPc7H0EmMS43C6XNTUeSJpSto4tr38lI+9jw982Wvbch1FQLwmgtyTxZy7WOWVxeo05H3yFtteforUCUnUNzZTVW0iZWwCjz3cS9STax5gXFIiVdUm6hubSZ2QxNbNT5J3YAdxMb21xdnzZeSeOOM9AitrDp6AkESAiEilpZnoEWp+nrGQZw58yAvb32HfX3/pbaHAxXPrV/Hc+lU4nS5cbjdKhe+m6Oms5TydtZyOzi6kEgkyWd8l88ZX3sDtFnkhcxG/PnqQSkszblFEIgReEIUkAmpbbNidXSTp9DyaPpcx2ij2f5HPRwePeduITgeiy1MQyWTSbwz+SigV8n4Hv2dfNgc+z2NMZBRZ6XNI1unpcDmpabH02f5aCAkBPeGfojMQJpOz895VCILAmo1/4OyFSk8jEdztNhDF/hVdA8UXK1j77KsIgsDb9/yYMJmc5O4dZrCJMEQEeIwnaT3z9I6k8bw4bzGt7Q7ufXQLZy54jrNxu3G3twCBk1BYVMoPVm7A1tLGS/MWsyhlIgDJOo/NYJfCkEZAjzMAW+bfzePTM6g2Xea2lZu800F0duJuawkoEvbsyyZjyWMYaxt4Ynomr8y/2yvrsRlsMRTSCEjR+Za8by5ZwWt3LqXd3sGKp15j8eqXOF1cjujsxNVqQXR1+dVbfLGCFVkvsnztL2i3d7Ap4y7euHu5T5vkbpsVluAICMkq0LMOJ+l8t8ECApsy7mJaXCJP7v+Aw8cKmfmjDcxJn8TSO2exMHMqiaNGYoiLRZDIaDJbqa5t5NMjJ/h4/1GOfX0Gt1tkXFQ0f/7hMhanTPqG7cFOgZAQUGFuQiGVkhih7VO+KGUi59a9wJv5ObyZn0NufjG5+cVset0jVyk9L0KuLpXH62NYNyOTdTMyUUr7djVBo0UplQWdBENCQOboFEbI5X6PpJRSGc/Oms8zs24n51I52ZUl5Fwqp9pmpsnuOTBJ0ugYFakjY1QyC8beQubo5GsedkgEgVWTZ9Bkb/Pbrj+EhID3lz0y4LYCAvNGpzBvdEooTAOwc+mqoPve9L8PuOkJGPAUWLJgHNFNQ3OyM5wYMAF7/3I/vBvcsdP1jJt+CgyYgNUb/83T+/cMpS/DggETsHtfMXsvFA6lL8OC/+spUNNipbG9VQT6rZP9lVlOlVImnTROj7Wl44b8x0iNzUqH5xBmO/B8oP2dDP9/fgZ7uYGt+Fnt/EaAUiGXnjnyLuNTRl+LrOsOo6beR3VtgxPw+7sZvzkgJjrqhhx8IBhwIbT22Vf5IvfUUPoSUlz5gsUfBkxAfWMz5VWDexV9PcJvDhiVECu9VLD3GwJV4u1EaSTU7p3ncz98UTZqdQT1xZ+E2M3AEYocUH+5yUJdffDv3W4E+JsCu+yOjudTZi4T42P0PpHS2eUEFNdUvn7jdg5mB/773VCgOwdIgR1AVjA6lHj+clpDH2tsvF4plr2XId4z1yAumx8jGj+cJ45QSkVBEBpEy1GdaDmqUyrln/bV91u+9gcz+GvBoZRLxPAwqbvHUKRa5pZKBBGoHwqD1xscgChAF7AZeJ3eyvGmIOAL4AQw5Yp7s4BC4OPhcChY/A/fkn/A85DrtAAAAABJRU5ErkJggg==
// ==/UserScript==

(function() {
  'use strict';
  let isReading = false;
  let images = [];
  let bgIsBlack = true;
  let zoomLevel = 35; // 默认缩放比例35%
  let autoReaderEnabled = false; // 全局阅读器开关

  // 目录识别相关变量
  let seriesDirectory = [];
  let currentSeriesKey = '';
  let isDirectoryMode = false;
  let savedThreadTitle = '';
  let originalSeriesTitle = '';
  let searchCache = new Map();
  let directoryMemoryCache = new Map();

  // 保存原始页面HTML
  let originalPageHTML = '';
  let originalPageTitle = '';

  // 事件处理与状态
  let readerEventHandlers = {};
  let readerEventsBound = false;
  let readerToolsTimer = null;
  let unbindReaderEvents = null;

  // 缓存前缀与过期时长
  const CACHE_PREFIX = 'yamibo-directory-cache-';
  const CACHE_EXPIRY = 24 * 60 * 60 * 1000;

  // 持久化缓存索引键(用于 GM_* 环境)
  const GM_INDEX_KEY = CACHE_PREFIX + 'gm-index';

  // 通用存储封装:优先使用 GM_getValue/GM_setValue/GM_deleteValue(若环境支持),否则降级到 sessionStorage
  function storageGet(key, defaultVal = null) {
    try {
      if (typeof GM_getValue === 'function') {
        let val;
        try {
          val = GM_getValue(key, undefined);
        } catch (e) {
          val = undefined;
        }
        if (val === undefined) {
        } else if (val === null) {
          return defaultVal;
        } else if (typeof val === 'string') {
          try { return JSON.parse(val); } catch (e) { return val; }
        } else {
          return val;
        }
      }
    } catch (e) {
    }

    try {
      const raw = sessionStorage.getItem(key);
      return raw ? JSON.parse(raw) : defaultVal;
    } catch (e) {
      return defaultVal;
    }
  }

  function storageSet(key, value) {
    try {
      if (typeof GM_setValue === 'function') {
        try {
          GM_setValue(key, value);
        } catch (e) {
          try { GM_setValue(key, JSON.stringify(value)); } catch (ee) { throw ee; }
        }

        try {
          let idx = GM_getValue(GM_INDEX_KEY, undefined);
          if (idx === undefined || idx === null) idx = [];
          if (typeof idx === 'string') {
            try { idx = JSON.parse(idx); } catch (e) { idx = []; }
          }
          if (!Array.isArray(idx)) idx = [];
          if (!idx.includes(key)) { idx.push(key); GM_setValue(GM_INDEX_KEY, idx); }
        } catch (e) {
        }
        return true;
      }
    } catch (e) {
    }

    try {
      sessionStorage.setItem(key, JSON.stringify(value));
      return true;
    } catch (e) {
      console.warn('⚠️ storageSet 失败:', e);
      return false;
    }
  }

  function storageRemove(key) {
    try {
      if (typeof GM_deleteValue === 'function') {
        try { GM_deleteValue(key); } catch (e) {
          try { GM_setValue(key, null); } catch (ee) {}
        }

        try {
          let idx = GM_getValue(GM_INDEX_KEY, undefined);
          if (typeof idx === 'string') {
            try { idx = JSON.parse(idx); } catch (e) { idx = []; }
          }
          if (!Array.isArray(idx)) idx = [];
          const newIdx = idx.filter(k => k !== key);
          GM_setValue(GM_INDEX_KEY, newIdx);
        } catch (e) {
        }

        return true;
      }
    } catch (e) {
    }

    try {
      sessionStorage.removeItem(key);
      return true;
    } catch (e) {
      return false;
    }
  }

  // 清理过期缓存:同时支持 sessionStorage 前缀与 GM 索引
  function cleanExpiredCache() {
    let cleanedCount = 0;

    // 1) 清理 sessionStorage 前缀缓存
    try {
      const sKeys = Object.keys(sessionStorage).filter(k => k.startsWith(CACHE_PREFIX));
      sKeys.forEach(key => {
        try {
          const raw = sessionStorage.getItem(key);
          if (!raw) return;
          const obj = JSON.parse(raw);
          const ts = obj.ts || obj.timestamp || 0;
          if (Date.now() - ts > CACHE_EXPIRY) {
            sessionStorage.removeItem(key);
            cleanedCount++;
          }
        } catch (e) {
          try { sessionStorage.removeItem(key); cleanedCount++; } catch (ee) {}
        }
      });
    } catch (e) {
    }

    // 2) 清理 GM_* 存储(使用索引枚举)
    try {
      if (typeof GM_getValue === 'function' && typeof GM_setValue === 'function') {
        let idx = GM_getValue(GM_INDEX_KEY, undefined);
        if (typeof idx === 'string') {
          try { idx = JSON.parse(idx); } catch (e) { idx = []; }
        }
        if (!Array.isArray(idx)) idx = [];

        const remaining = [];
        for (const key of idx) {
          try {
            const stored = storageGet(key, null);
            if (!stored) continue;
            const ts = stored.ts || stored.timestamp || 0;
            if (Date.now() - ts > CACHE_EXPIRY) {
              storageRemove(key);
              cleanedCount++;
            } else {
              remaining.push(key);
            }
          } catch (e) {
            try { storageRemove(key); cleanedCount++; } catch (ee) {}
          }
        }

        // 更新索引为剩余项
        try { GM_setValue(GM_INDEX_KEY, remaining); } catch (e) {}
      }
    } catch (e) {
    }

    if (cleanedCount > 0) console.log('🧹 清理了', cleanedCount, '个过期缓存 (session+GM)');
    return cleanedCount;
  }

  // 在配额不足或需要收缩时清理最旧的缓存(同时支持 sessionStorage 与 GM)
  function cleanOldestCache() {
    try {
      const entries = [];

      // 收集 sessionStorage 条目
      try {
        Object.keys(sessionStorage).forEach(key => {
          if (!key.startsWith(CACHE_PREFIX)) return;
          try {
            const obj = JSON.parse(sessionStorage.getItem(key));
            const ts = obj.ts || obj.timestamp || 0;
            entries.push({ key, ts, source: 'session' });
          } catch (e) {
            entries.push({ key, ts: 0, source: 'session' });
          }
        });
      } catch (e) {}

      // 收集 GM_* 条目 via index
      try {
        if (typeof GM_getValue === 'function') {
          let idx = GM_getValue(GM_INDEX_KEY, undefined);
          if (typeof idx === 'string') {
            try { idx = JSON.parse(idx); } catch (e) { idx = []; }
          }
          if (!Array.isArray(idx)) idx = [];

          for (const key of idx) {
            try {
              const stored = storageGet(key, null);
              const ts = stored ? (stored.ts || stored.timestamp || 0) : 0;
              entries.push({ key, ts, source: 'gm' });
            } catch (e) {
              entries.push({ key, ts: 0, source: 'gm' });
            }
          }
        }
      } catch (e) {}

      if (entries.length === 0) return 0;

      // 按时间戳排序,最旧的在前
      entries.sort((a, b) => (a.ts || 0) - (b.ts || 0));

      const toDelete = Math.ceil(entries.length / 2);
      for (let i = 0; i < toDelete; i++) {
        const e = entries[i];
        try {
          if (e.source === 'session') sessionStorage.removeItem(e.key);
          else storageRemove(e.key);
        } catch (err) {}
      }

      return toDelete;
    } catch (e) {
      console.warn('cleanOldestCache failed', e);
      return 0;
    }
  }

  // 检查是否启用了全局阅读器模式
  function checkAutoReaderStatus() {
    const stored = localStorage.getItem('yamibo-auto-reader');
    return stored === 'true';
  }

  // 设置全局阅读器模式
  function setAutoReaderStatus(enabled) {
    autoReaderEnabled = enabled;
    localStorage.setItem('yamibo-auto-reader', enabled.toString());
    console.log('🔧 全局阅读器模式:', enabled ? '开启' : '关闭');
  }

  /*** 标题标准化函数  ***/
  function normalizeSeriesTitle(rawTitle) {
    if (!rawTitle) return '';

    // 首先清理页面title的后缀
    let title = rawTitle;
    if (title.includes(' - ')) {
      title = title.split(' - ')[0].trim();
    }

    // 移除页数标注
    title = title.replace(/[((]\s*\d+\s*p\s*[))]\s*$/i, '');

    // 移除章节标识 - 参考脚本的模式
    title = title.replace(/第[\d一二三四五六七八九十百千万〇零兩两1234567890\.]+[话話章节節回卷篇]/gi, ' ');
    title = title.replace(/\d+(?:\.\d+)?\s*[话話章节節回卷篇]/gi, ' ');
    title = title.replace(/\d+(?:\.\d+)?\s*[上下前后前後左右中篇部卷期全完]+(?:\s*[++&和及與并並,,/]\s*[上下前后前後左右中篇部卷期全完]+)+/gi, ' ');
    title = title.replace(/[((][上下前后前後中全完]+(?:\s*[,,++&和及與并並/]\s*[上下前后前後中全完]+)*[))]/g, ' ');
    title = title.replace(/\d+(?:\.\d+)?\s*[上下前后前後左右中篇部卷期全完]+/gi, ' ');
    title = title.replace(/(?:\s+|[-‐‑‒–—―-~~·•_、::])?\d+(?:\.\d+)*(?:\s*[上下前后前後左右中篇部卷期話话节節全完])?\s*$/g, ' ');
    title = title.replace(/[--—–~~\u2013\u2014\s]+$/g, ' ');
    title = title.replace(/[\[\]【】()()]/g, ' ');
    title = title.replace(/\s+/g, ' ').trim();

    if (!title) {
      return rawTitle.trim();
    }
    return title;
  }

  function buildSeriesKey(title) {
    const normalized = normalizeSeriesTitle(title || '');
    const base = normalized || (title || '').trim();
    return base.toLowerCase();
  }

  function generateSeriesKey(title) {
    try {
      const k = buildSeriesKey(title || '');
      // 限制长度并移除特殊字符,避免存储键过长或包含非法字符
      return k.replace(/[\s\/:\\#\?&=\+%\*\|<>"'`]/g, '-').substring(0, 120);
    } catch (e) {
      return String(title || '').toLowerCase().substring(0, 120);
    }
  }

// 统一的排除词汇列表,避免重复定义
const EXCLUDE_WORDS = [
  '个人汉化', '汉化组', '汉化', '个人翻译', '個人翻譯', '个汉',
  '翻译', '生肉', '未翻译', '填坑组', '粮食组', '保护协会','創作百合', '创作百合',
  '熟肉', '字幕', '工作室', '提灯喵', '社团', '官方中字', '出版',
  '汉化工房', '猫岛汉化组', '和菓子漫画屋', '大友同好會', '透明声彩汉化组',
  '翻译组', '汉化委员会', '渣翻渣嵌', '合作汉化', '完结','连载','短篇',
  '合集','同人','raw','韩漫','杂志','英译','单行本','插画','特典','番外','外传','彩页','合订本'
].map(s => s.toLowerCase());

// 统一的文本过滤函数:检查是否为噪音词汇
function isNoiseText(text) {
  if (!text || typeof text !== 'string') return true;
  const t = text.toLowerCase();

  // 检查是否包含排除词汇
  for (const word of EXCLUDE_WORDS) {
    if (t.includes(word)) return true;
  }

  // 常见格式判断:纯数字视为噪音
  if (/^\d+$/.test(t)) return true;

  // 智能长度检查:CJK字符2个即有效,其他字符3个以上有效
  const hasCJK = /[\u4e00-\u9fa5\u3040-\u309F\u30A0-\u30FF\uAC00-\uD7AF]/.test(text);
  const minLength = hasCJK ? 2 : 3;
  if (t.length < minLength) return true;

  return false;
}

// 保持向后兼容的 isGenericTag 函数
function isGenericTag(text) {
  return isNoiseText(text);
}

  function getCachedDirectory(seriesKey) {
    // 🚫 临时禁用缓存读取,强制测试双语解析逻辑
    console.log('🔄 缓存读取已禁用,将执行新的双语解析逻辑');
    return null;

    if (!seriesKey) return null;

    // 1) 先检查内存缓存
    try {
      if (directoryMemoryCache && directoryMemoryCache.has(seriesKey)) {
        const cached = directoryMemoryCache.get(seriesKey);
        if (cached && cached.ts && (Date.now() - cached.ts) < CACHE_EXPIRY) {
          return cached.data || cached.d || null;
        } else {
          directoryMemoryCache.delete(seriesKey);
        }
      }
    } catch (e) {
    }

    const key = CACHE_PREFIX + seriesKey;

    // 2) 尝试 GM_getValue
    try {
      if (typeof GM_getValue === 'function') {
        let stored = GM_getValue(key, undefined);
        if (typeof stored === 'string') {
          try { stored = JSON.parse(stored); } catch (e) { /* leave as-is */ }
        }
        if (stored && (stored.d || stored.data)) {
          const ts = stored.ts || stored.timestamp || 0;
          if (Date.now() - ts < CACHE_EXPIRY) {
            try { directoryMemoryCache.set(seriesKey, { d: stored.d || stored.data, data: stored.d || stored.data, ts: ts || Date.now() }); } catch (e) {}
            return stored.d || stored.data;
          } else {
            try { storageRemove(key); } catch (e) {}
            return null;
          }
        }
      }
    } catch (e) {
    }

    // 3) 尝试 sessionStorage
    try {
      const raw = sessionStorage.getItem(key);
      if (raw) {
        let obj = raw;
        try { obj = JSON.parse(raw); } catch (e) { obj = raw; }
        if (obj && (obj.d || obj.data)) {
          const ts = obj.ts || obj.timestamp || 0;
          if (Date.now() - ts < CACHE_EXPIRY) {
            try { directoryMemoryCache.set(seriesKey, { d: obj.d || obj.data, data: obj.d || obj.data, ts: ts || Date.now() }); } catch (e) {}
            return obj.d || obj.data;
          } else {
            try { sessionStorage.removeItem(key); } catch (e) {}
            return null;
          }
        }
      }
    } catch (e) {
    }

    return null;
  }

  function setCachedDirectory(seriesKey, directory) {
    if (!seriesKey || !directory) return false;
    const key = CACHE_PREFIX + seriesKey;
    const payload = { ts: Date.now(), data: directory, d: directory };

    try { directoryMemoryCache.set(seriesKey, { d: directory, data: directory, ts: payload.ts }); } catch (e) {}

    try {
      if (typeof GM_setValue === 'function') {
        try { GM_setValue(key, payload); }
        catch (e) {
          try { GM_setValue(key, JSON.stringify(payload)); } catch (ee) { /* ignore */ }
        }
        return true;
      }
    } catch (e) {
    }

    try {
      sessionStorage.setItem(key, JSON.stringify(payload));
      return true;
    } catch (e) {
      console.warn('⚠️ setCachedDirectory 写入失败:', e);
      return false;
    }
  }

  /*** 相似度计算辅助函数  ***/

  // 简繁体标准化函数 - 使用 OpenCC 库
  let converter = null;

  function normalizeChineseVariants(text) {
    try {
      // 初始化转换器(繁体转简体)
      if (!converter && typeof OpenCC !== 'undefined') {
        converter = OpenCC.Converter({ from: 'tw', to: 'cn' });
      }

      if (converter) {
        return converter(text);
      }

      return text;
    } catch (error) {
      console.warn('简繁转换失败,使用原文本:', error);
      return text;
    }
  }

  // 提取有意义的关键词(排除常见无关词汇)
function extractMeaningfulKeywords(title) {
  const keywords = [];

  // 1. 检查明显的中外对照分隔符
  const dualMatch = title.match(/^(.+?)[\s/||/()()]+(.+?)$/);
  if (dualMatch) {
    const part1 = dualMatch[1].trim();
    const part2 = dualMatch[2].trim();
    if (part1 && part2 && part1 !== part2) {
      keywords.push(part1, part2);
      return [...new Set(keywords)];
    }
  }

  // 2. 没有分隔符的中外混合,允许拆分
  const enZhMix = title.match(/([A-Za-z][A-Za-z0-9\.\*\s]*[A-Za-z])([\u4e00-\u9fa5]{2,})/);
  if (enZhMix) {
    const en = enZhMix[1].trim();
    const zh = enZhMix[2].trim();
    if (!isNoiseText(en)) keywords.push(en);
    if (!isNoiseText(zh)) keywords.push(zh);
  }

  // 3. 继续原有的中文、日文、韩文、英文多词短语等提取
  const chineseMatches = title.match(/[\u4e00-\u9fa5]{2,8}/g);
  if (chineseMatches) {
    chineseMatches.forEach(match => {
      if (!isNoiseText(match)) keywords.push(match);
    });
  }
  const japaneseMatches = title.match(/[\u3040-\u309F\u30A0-\u30FF]{2,}/g);
  if (japaneseMatches) {
    japaneseMatches.forEach(match => {
      if (!isNoiseText(match)) keywords.push(match);
    });
  }
  const koreanMatches = title.match(/[\uAC00-\uD7AF]{2,}/g);
  if (koreanMatches) {
    koreanMatches.forEach(match => {
      if (!isNoiseText(match)) keywords.push(match);
    });
  }
  const englishMatches = title.match(/[A-Za-z]{3,}(?:\s+[A-Za-z]{2,})+/g);
  if (englishMatches) {
    englishMatches.forEach(match => {
      const cleanMatch = match.trim();
      if (cleanMatch.length >= 5 && !isNoiseText(cleanMatch)) {
        keywords.push(cleanMatch);
      }
    });
  }
  const singleEnglishMatches = title.match(/\b[A-Za-z]{5,}\b/g);
  if (singleEnglishMatches) {
    singleEnglishMatches.forEach(match => {
      if (keywords.some(k => k !== match && k.includes(match))) return;
      if (!isNoiseText(match)) {
        keywords.push(match);
      }
    });
  }


  // 去重,且如果有整体词则不保留其子词
  const finalKeywords = [];
  for (const kw of keywords) {
    if (finalKeywords.some(k => k.length > kw.length && k.includes(kw))) continue;
    finalKeywords.push(kw);
  }

  return [...new Set(finalKeywords)];
}

  // 计算核心作品名相似度
  function calculateCoreWorkSimilarity(core1, core2) {
    // 🔧 特殊处理:对于英文为主的标题,使用更严格的匹配
    const isEnglishDominant1 = /[A-Za-z]/.test(core1) && !/[\u4e00-\u9fa5\u3040-\u309F\u30A0-\u30FF]/.test(core1);
    const isEnglishDominant2 = /[A-Za-z]/.test(core2) && !/[\u4e00-\u9fa5\u3040-\u309F\u30A0-\u30FF]/.test(core2);

    if (isEnglishDominant1 && isEnglishDominant2) {
      // 对于英文为主的标题,进行词级别的严格匹配
      const words1 = core1.toLowerCase().replace(/[^\w\s]/g, ' ').split(/\s+/).filter(w => w.length > 0 && /[a-z]/.test(w));
      const words2 = core2.toLowerCase().replace(/[^\w\s]/g, ' ').split(/\s+/).filter(w => w.length > 0 && /[a-z]/.test(w));

      console.log(`   🔤 英文词汇对比: [${words1.join(', ')}] vs [${words2.join(', ')}]`);

      // 计算词汇重叠度 - 更严格的匹配逻辑
      const uniqueWords1 = [...new Set(words1)];
      const uniqueWords2 = [...new Set(words2)];
      const commonUniqueWords = uniqueWords1.filter(w => uniqueWords2.includes(w));

      if (commonUniqueWords.length === 0) {
        console.log(`   ❌ 英文标题无共同词汇,相似度为0`);
        return 0;
      }

      // 🎯 严格匹配:要求绝大部分唯一词汇都匹配
      const overlapRatio1 = commonUniqueWords.length / uniqueWords1.length;
      const overlapRatio2 = commonUniqueWords.length / uniqueWords2.length;
      const minOverlapRatio = Math.min(overlapRatio1, overlapRatio2);

      console.log(`   📊 唯一词汇: [${uniqueWords1.join(', ')}] vs [${uniqueWords2.join(', ')}]`);
      console.log(`   📊 共同词汇: [${commonUniqueWords.join(', ')}]`);
      console.log(`   📊 重叠率: ${(overlapRatio1 * 100).toFixed(1)}% & ${(overlapRatio2 * 100).toFixed(1)}% (最小: ${(minOverlapRatio * 100).toFixed(1)}%)`);

      // 🎯 更严格的匹配标准
      if (minOverlapRatio >= 0.8) {
        return 0.95; // 高匹配度:两边80%以上词汇重叠
      } else if (minOverlapRatio >= 0.6) {
        return 0.7; // 中等匹配度:两边60%以上词汇重叠
      } else {
        console.log(`   ❌ 英文词汇重叠度不足 (${(minOverlapRatio * 100).toFixed(1)}% < 60%),认为不相似`);
        return 0; // 重叠度不足
      }
    }

    // 标准化处理(包括简繁体转换)
    const clean1 = normalizeChineseVariants(core1.replace(/[^\u4e00-\u9fa5\u3040-\u309F\u30A0-\u30FFa-zA-Z0-9]/g, '')).toLowerCase();
    const clean2 = normalizeChineseVariants(core2.replace(/[^\u4e00-\u9fa5\u3040-\u309F\u30A0-\u30FFa-zA-Z0-9]/g, '')).toLowerCase();

    if (!clean1 || !clean2) return 0;

    console.log(`   🔤 简繁体标准化: "${clean1}" vs "${clean2}"`);

    // 1. 完全匹配
    if (clean1 === clean2) return 1.0;

    // 2. 包含关系
    if (clean1.includes(clean2) || clean2.includes(clean1)) {
      const longer = clean1.length > clean2.length ? clean1 : clean2;
      const shorter = clean1.length <= clean2.length ? clean1 : clean2;
      return shorter.length / longer.length * 0.95; // 包含关系给0.95分
    }

    // 3. 计算最长公共子串
    let maxCommonLength = 0;
    for (let i = 0; i < clean1.length; i++) {
      for (let j = 0; j < clean2.length; j++) {
        let commonLength = 0;
        while (i + commonLength < clean1.length &&
               j + commonLength < clean2.length &&
               clean1[i + commonLength] === clean2[j + commonLength]) {
          commonLength++;
        }
        maxCommonLength = Math.max(maxCommonLength, commonLength);
      }
    }

    // 4. 基于最长公共子串计算相似度
    const minLength = Math.min(clean1.length, clean2.length);
    if (maxCommonLength >= 4) { // 至少4个字符相同才认为有相似性
      const similarity = (maxCommonLength / minLength) * 0.9; // 最高0.9分
      return similarity;
    }

    return 0;
  }

  // 检查关键词匹配(排除翻译组等无关信息)
  function checkKeywordMatch(core1, core2) {
    // 提取有意义的关键词片段(4字符以上)
    const keywords1 = extractMeaningfulKeywords(core1);
    const keywords2 = extractMeaningfulKeywords(core2);

    console.log(`   🔍 关键词提取: "${keywords1.join('", "')}" vs "${keywords2.join('", "')}"`);

    let bestMatch = 0;

    // 检查直接关键词匹配
    for (const kw1 of keywords1) {
      for (const kw2 of keywords2) {
        if (kw1.length >= 2 && kw2.length >= 2) {
if (kw1 === kw2) {
  console.log(`   🎯 完全匹配: "${kw1}"`);
  return 0.95; // 完全匹配给高分
} else if (kw1.includes(kw2) || kw2.includes(kw1)) {
  const longer = kw1.length > kw2.length ? kw1 : kw2;
  const shorter = kw1.length <= kw2.length ? kw1 : kw2;
  const match = shorter.length / longer.length;
  bestMatch = Math.max(bestMatch, match * 0.9);
  console.log(`   🎯 包含匹配: "${kw1}" ⟷ "${kw2}" (${(match * 90).toFixed(1)}%)`);
}
        }
      }
    }

    // 如果核心1和核心2都是字符串对象且包含双语信息,进行交叉匹配
    if (typeof core1 === 'object' && core1._dualLanguage && typeof core2 === 'object' && core2._dualLanguage) {
      // 双语对双语:交叉匹配所有组合
      const pairs = [
        [core1._dualLanguage.chinese, core2._dualLanguage.chinese],
        [core1._dualLanguage.foreign, core2._dualLanguage.foreign],
        [core1._dualLanguage.chinese, core2._dualLanguage.foreign],
        [core1._dualLanguage.foreign, core2._dualLanguage.chinese]
      ];

      for (const [term1, term2] of pairs) {
        if (term1 && term2) {
          const kw1Set = extractMeaningfulKeywords(term1);
          const kw2Set = extractMeaningfulKeywords(term2);

          for (const kw1 of kw1Set) {
            for (const kw2 of kw2Set) {
              if (kw1.length >= 2 && kw2.length >= 2) {
                if (kw1 === kw2 || kw1.includes(kw2) || kw2.includes(kw1)) {
                  console.log(`   🌐 双语交叉匹配: "${kw1}" ⟷ "${kw2}"`);
                  return 0.92; // 双语匹配给高分
                }
              }
            }
          }
        }
      }
    } else if (typeof core1 === 'object' && core1._dualLanguage) {
      // 双语对单语:用双语的两个部分分别匹配单语
      const singleTerms = extractMeaningfulKeywords(core2.toString());
      const dualTerms = [
        ...extractMeaningfulKeywords(core1._dualLanguage.chinese || ''),
        ...extractMeaningfulKeywords(core1._dualLanguage.foreign || '')
      ];
      for (const dTerm of dualTerms) {
        for (const sTerm of singleTerms) {
          if (dTerm.length >= 2 && sTerm.length >= 2) {
            if (dTerm === sTerm) {
              console.log(`   🎯 双语单语完全匹配: "${dTerm}"`);
              return 0.95;
            } else if (dTerm.includes(sTerm) || sTerm.includes(dTerm)) {
              const longer = dTerm.length > sTerm.length ? dTerm : sTerm;
              const shorter = dTerm.length <= sTerm.length ? dTerm : sTerm;
              const match = shorter.length / longer.length;
              bestMatch = Math.max(bestMatch, match * 0.9);
              console.log(`   🎯 双语单语包含匹配: "${dTerm}" ⟷ "${sTerm}" (${(match * 90).toFixed(1)}%)`);
            }
          }
        }
      }
    } else if (typeof core2 === 'object' && core2._dualLanguage) {
      // 单语对双语:用单语匹配双语的两个部分
      const singleTerms = extractMeaningfulKeywords(core1.toString());
      const dualTerms = [
        ...extractMeaningfulKeywords(core2._dualLanguage.chinese || ''),
        ...extractMeaningfulKeywords(core2._dualLanguage.foreign || '')
      ];
      for (const sTerm of singleTerms) {
        for (const dTerm of dualTerms) {
          if (sTerm.length >= 2 && dTerm.length >= 2) {
            if (sTerm === dTerm) {
              console.log(`   🎯 单语双语完全匹配: "${sTerm}"`);
              return 0.95;
            } else if (sTerm.includes(dTerm) || dTerm.includes(sTerm)) {
              const longer = sTerm.length > dTerm.length ? sTerm : dTerm;
              const shorter = sTerm.length <= dTerm.length ? sTerm : dTerm;
              const match = shorter.length / longer.length;
              bestMatch = Math.max(bestMatch, match * 0.9);
              console.log(`   🎯 单语双语包含匹配: "${sTerm}" ⟷ "${dTerm}" (${(match * 90).toFixed(1)}%)`);
            }
          }
        }
      }
    }

    return bestMatch;
  }

  // 提取核心作品名
function extractCoreWorkName(title) {
  console.log(`   🔍 优化版标题处理: "${title}"`);
  if (!title || typeof title !== 'string') return '';

  // 1. 移除开头的【】[]标签和紧跟的()()
  let step1 = title
    .replace(/^(\s*【[^】]*】\s*)+/g, '') // 移除开头【】
    .replace(/^(\s*\[[^\]]*\]\s*)+/g, '') // 移除开头[]
    .replace(/^(\s*[\[【((][^\]】))]*[\]】))]\s*)+/g, '') // 移除开头的所有括号
    .replace(/^[\]】))]\s*/, '') // 清理可能残留的右括号
    .trim();

  // 处理《》书名号
  if (step1.includes('《') && step1.includes('》')) {
    const bookMatch = step1.match(/《([^》]+)》/);
    if (bookMatch) {
      const bookTitle = bookMatch[1].trim();
      step1 = step1.replace(/《[^》]+》/, bookTitle); // 替换《》为内容
      console.log(`   📚 提取书名号内容: "${bookTitle}"`);
    }
  }

  console.log(`   🧹 移除开头标签和括号: "${step1}"`);

  // 2. 处理|分隔的双语结构
  if (step1.includes('|')) {
    const parts = step1.split('|').map(p => p.trim());
    console.log(`   🌐 检测到|分隔双语: [${parts.map(p => `"${p}"`).join(', ')}]`);
    const validParts = parts.filter(p => p.length > 0);
    if (validParts.length > 0) {
      // 返回双语对象结构
      const result = new String(validParts[0]);
      if (validParts.length > 1) {
        result._dualLanguage = {
          chinese: validParts.find(p => /[\u4e00-\u9fa5]/.test(p)) || validParts[0],
          foreign: validParts.find(p => !/[\u4e00-\u9fa5]/.test(p)) || validParts[1]
        };
      }
      return result;
    }
  }

  // 3. 特殊处理:提取末尾的日文标题
  const endJapaneseMatch = step1.match(/【[^】]*】([ひらがなカタカナ\u3040-\u309F\u30A0-\u30FF\u4e00-\u9fa5ー~〜]+)$/);
  if (endJapaneseMatch) {
    const japaneseTitle = endJapaneseMatch[1].trim();
    console.log(`   🎌 提取末尾日文标题: "${japaneseTitle}"`);
    return japaneseTitle;
  }

  // 4. 清理尾部的汉化组信息
  step1 = step1.replace(/\s*(kakukuroi|汉化组|个人汉化|翻译组|汉化|翻译).*$/i, '').trim();

  // 5. 处理/分隔的多个关键词
  if (step1.includes('/') && !step1.includes('【') && !step1.includes('】')) {
    const slashMatch = step1.match(/^([^\/【】]+)\s*\/\s*([^\/【】]+?)(?:\s+\d+)?$/);
    if (slashMatch) {
      const part1 = slashMatch[1].trim();
      const part2 = slashMatch[2].trim();

      if (!part1.includes('同人志') && !part2.includes('【')) {
        console.log(`   🔀 检测到/分隔关键词: "${part1}" / "${part2}"`);
        const result = new String(part1);
        result._dualLanguage = {
          chinese: part1,
          foreign: part2
        };
        return result;
      }
    }
  }

  // 6. 检测章节分隔,确定主体书名范围
  let mainContent = step1;

  // 策略A: 匹配明确的章节标记
  const explicitChapterMatch = step1.match(/^(.+?)\s*(?:第?\d+(?:\.\d+)?\s*[话話章节節回卷篇期]|番外|外传|omake|extra|短篇|\d+\s*「)/i);
  if (explicitChapterMatch) {
    mainContent = explicitChapterMatch[1].trim();
    console.log(`   📖 检测到明确章节标记,主体书名: "${mainContent}"`);
  } else {
    // 策略B: 检测各种隐式章节模式
    let chapterDetected = false;

    // B1: "作品名+数字+空格+小标题"
    const spaceChapterMatch = step1.match(/^([\u4e00-\u9fa5\u3040-\u309F\u30A0-\u30FFA-Za-z\s]+?)(\d{1,3})\s+(.+)$/);
    if (spaceChapterMatch && !chapterDetected) {
      const baseName = spaceChapterMatch[1].trim();
      const chapterNum = spaceChapterMatch[2];
      const subtitle = spaceChapterMatch[3].trim();

      // 验证这确实是章节模式:基础名应该是合理的作品名(至少3字符)
      if (baseName.length >= 3 && chapterNum.length <= 3) {
        mainContent = baseName;
        chapterDetected = true;
        console.log(`   📖 检测到空格分隔章节: 作品名"${baseName}" + 章节"${chapterNum}" + 小标题"${subtitle}"`);
      }
    }

    // B2: "作品名+数字+其他内容"
    const noSpaceChapterMatch = step1.match(/^([\u4e00-\u9fa5\u3040-\u309F\u30A0-\u30FFA-Za-z]+?)(\d{1,3})([\u4e00-\u9fa5\u3040-\u309F\u30A0-\u30FFA-Za-z].+)$/);
    if (noSpaceChapterMatch && !chapterDetected) {
      const baseName = noSpaceChapterMatch[1].trim();
      const chapterNum = noSpaceChapterMatch[2];
      const subtitle = noSpaceChapterMatch[3].trim();

      // 更严格的验证:确保基础名至少4字符,且副标题不是纯数字
      if (baseName.length >= 4 && chapterNum.length <= 3 && !/^\d+$/.test(subtitle)) {
        mainContent = baseName;
        chapterDetected = true;
        console.log(`   📖 检测到紧贴章节: 作品名"${baseName}" + 章节"${chapterNum}" + 小标题"${subtitle}"`);
      }
    }

    // B3: "作品名 + 空格 + 数字 + 小标题"
    const spaceBeforeChapterMatch = step1.match(/^([\u4e00-\u9fa5\u3040-\u309F\u30A0-\u30FFA-Za-z]+)\s+(\d{1,3})\s*(.*)$/);
    if (spaceBeforeChapterMatch && !chapterDetected) {
      const baseName = spaceBeforeChapterMatch[1].trim();
      const chapterNum = spaceBeforeChapterMatch[2];
      const subtitle = spaceBeforeChapterMatch[3].trim();

      // 验证:基础名合理,章节号不超过3位
      if (baseName.length >= 3 && chapterNum.length <= 3) {
        mainContent = baseName;
        chapterDetected = true;
        console.log(`   📖 检测到前置空格章节: 作品名"${baseName}" + 章节"${chapterNum}" + 小标题"${subtitle}"`);
      }
    }
  }

  // 7. 移除版本号
  mainContent = mainContent.replace(/(\d+(?:\.\d+)+)(?=\s|$|[\((【])/g, '').trim();

  // 8. 检查中间的括号
  const middleBrackets = mainContent.match(/[\[【((]([^\]】))]+)[\]】))]/g);
  let meaningfulBrackets = [];

  if (middleBrackets) {
    console.log(`   🔍 发现括号: ${middleBrackets.join(', ')}`);

    middleBrackets.forEach(bracket => {
      const content = bracket.slice(1, -1).trim();

      // 移除括号内的版本号和感叹号
      const cleanContent = content.replace(/\d+(?:\.\d+)+/g, '').replace(/[!!]$/, '').trim();

      const hasJapanese = /[\u3040-\u309F\u30A0-\u30FF]/.test(cleanContent);
      const hasKorean = /[\uAC00-\uD7AF]/.test(cleanContent);
      const hasChinese = /[\u4e00-\u9fa5]/.test(cleanContent);
      const hasLongEnglish = /[A-Za-z]/.test(cleanContent) && cleanContent.length > 4;

      // 检查原始内容中是否包含有效的中文(去除版本号后)
      const originalChinese = /[\u4e00-\u9fa5]/.test(content);
      const chineseAfterClean = content.replace(/\d+(?:\.\d+)+/g, '').replace(/[!!]$/, '').trim();
      const hasValidChinese = originalChinese && /[\u4e00-\u9fa5]/.test(chineseAfterClean) && chineseAfterClean.length >= 2;

      // 优化:更宽松的判断条件
      const isValidContent = hasJapanese || hasKorean || hasLongEnglish || hasValidChinese;

      // 排除明显的作者标识和展会标签(但不排除有版本号的中文词汇)
      const isAuthorOrTag = /^[A-Za-z\s]+\d+$/.test(content) || // Key Island13
                           /[\u4e00-\u9fa5\u3040-\u309F\u30A0-\u30FF]+\([A-Za-z0-9]+\)/.test(content) || // 壁発狂(kao)
                           (/^[\u4e00-\u9fa5A-Za-z0-9]{1,2}$/.test(cleanContent) && !hasValidChinese) || // 短标识符如"苍莓"等,但保留带版本号的中文
                           /汉化|翻译|合同志|短篇|版本/i.test(cleanContent) ||
                           cleanContent === '';

      if (isValidContent && !isAuthorOrTag) {
        // 如果有有效中文,使用清理后的版本
        const finalContent = hasValidChinese ? chineseAfterClean : cleanContent;
        meaningfulBrackets.push(finalContent);
        console.log(`   💎 提取对照内容: "${finalContent}"`);
      } else {
        console.log(`   🚫 忽略: "${content}" (${isAuthorOrTag ? '作者/标签' : '短标识符'})`);
      }
    });
  }

  // 9. 生成最终结果
  let body = mainContent.replace(/[\[【((][^\]】))]*[\]】))]/g, '').trim();

  // 处理各种语言混合情况

  // 韩文+中文混合
  const koreanChineseMatch = body.match(/^([\uAC00-\uD7AF]+)([\u4e00-\u9fa5]+)$/);
  if (koreanChineseMatch) {
    const koreanPart = koreanChineseMatch[1].trim();
    const chinesePart = koreanChineseMatch[2].trim();
    console.log(`   🇰🇷 检测到韩中混合: 韩文"${koreanPart}" + 中文"${chinesePart}"`);
    const result = new String(koreanPart);
    result._dualLanguage = {
      chinese: chinesePart,
      foreign: koreanPart
    };
    return result;
  }

  // 中文+韩文混合
  const chineseKoreanMatch = body.match(/^([\u4e00-\u9fa5]+)\s*([\uAC00-\uD7AF\s]+)$/);
  if (chineseKoreanMatch) {
    const chinesePart = chineseKoreanMatch[1].trim();
    const koreanPart = chineseKoreanMatch[2].trim();
    console.log(`   🇰🇷 检测到中韩混合: 中文"${chinesePart}" + 韩文"${koreanPart}"`);
    const result = new String(chinesePart);
    result._dualLanguage = {
      chinese: chinesePart,
      foreign: koreanPart
    };
    return result;
  }

  // 日文+中文混合
  const japaneseChineseMatch = body.match(/^([\u3040-\u309F\u30A0-\u30FF~〜~ー]+)\s+([\u4e00-\u9fa5~〜~]+)$/);
  if (japaneseChineseMatch) {
    const japanesePart = japaneseChineseMatch[1].trim();
    const chinesePart = japaneseChineseMatch[2].trim();
    console.log(`   🇯🇵 检测到日中混合: 日文"${japanesePart}" + 中文"${chinesePart}"`);
    const result = new String(japanesePart);
    result._dualLanguage = {
      chinese: chinesePart,
      foreign: japanesePart
    };
    return result;
  }

  // 处理中文+英文混合
  const chineseEnglishMatch = body.match(/^([\u4e00-\u9fa5!!]+)\s+([A-Za-z][A-Za-z\s!]*[A-Za-z!])$/);
  if (chineseEnglishMatch) {
    const chinesePart = chineseEnglishMatch[1].replace(/[!!]$/, '').trim();
    const englishPart = chineseEnglishMatch[2].replace(/[!!]$/, '').trim();
    console.log(`   🔀 检测到中英混合: 中文"${chinesePart}" + 英文"${englishPart}"`);
    const result = new String(chinesePart);
    result._dualLanguage = {
      chinese: chinesePart,
      foreign: englishPart
    };
    return result;
  }

  // 处理英文+中文混合的情况
  const mixedMatch = body.match(/^([A-Za-z][A-Za-z0-9\.\*\s]*[A-Za-z])([\u4e00-\u9fa5].*)?$/);
  if (mixedMatch && mixedMatch[2]) {
    // 英文部分和中文部分分开
    const englishPart = mixedMatch[1].trim();
    const chinesePart = mixedMatch[2].trim();

    console.log(`   🔀 检测到英中混合: 英文"${englishPart}" + 中文"${chinesePart}"`);

    // 判断中文部分是否是章节标题
    if (/能和你在一起就好|总有一天|第\d+话/.test(chinesePart)) {
      console.log(`   � 中文部分是章节标题,只保留英文`);
      return englishPart;
    } else {
      console.log(`   📖 中文部分是作品名,创建双语结构`);
      const result = new String(englishPart);
      result._dualLanguage = {
        chinese: chinesePart,
        foreign: englishPart
      };
      return result;
    }
  }

  // 只保留核心标题(移除数字、「」等)
  const cleanBody = body
    .replace(/\s*\d+\s*「[^」]*」.*$/g, '')
    .replace(/\s*\d+\s*$/, '')
    .trim();

  if (cleanBody !== body) {
    console.log(`   ✂️ 清理章节信息: "${cleanBody}"`);
  }

  // 如果有有意义的括号内容,创建双语结构
  if (meaningfulBrackets.length > 0 && cleanBody) {
    const result = new String(cleanBody);
    const chineseBracket = meaningfulBrackets.find(b => /[\u4e00-\u9fa5]/.test(b));
    const foreignBracket = meaningfulBrackets.find(b => !/[\u4e00-\u9fa5]/.test(b));

    console.log(`   🔍 括号分析: 中文=${chineseBracket} 外文=${foreignBracket} 主体=${cleanBody}`);

    if (chineseBracket || foreignBracket) {
      result._dualLanguage = {
        chinese: chineseBracket || cleanBody,
        foreign: foreignBracket || cleanBody
      };
      console.log(`   🌐 创建双语结构: 中文="${result._dualLanguage.chinese}" 外文="${result._dualLanguage.foreign}"`);
    }
    return result;
  }

  console.log(`   🎯 最终结果: "${cleanBody || step1 || title}"`);
  return cleanBody || step1 || title || '';
    const meaningfulBracketMatch = workName.match(/^([^((]+)[((]([^))]*[\u4e00-\u9fa5\u3040-\u309F\u30A0-\u30FF]+[^))]*)[))](.*)$/);
    if (meaningfulBracketMatch) {
      const beforeBracket = meaningfulBracketMatch[1].trim();
      const insideBracket = meaningfulBracketMatch[2].trim();
      const afterBracket = meaningfulBracketMatch[3].trim();

      // 检查括号内是否包含无关描述词
      const isDescriptive = /短篇|合同志|合集|特典|番外|彩页|后记|前记|完结|连载|单行本|杂志|raw|生肉|汉化|翻译/.test(insideBracket);

      if (!isDescriptive && insideBracket.length >= 2) {
        // 保留有意义的括号对照
        workName = beforeBracket + '(' + insideBracket + ')';
        console.log(`   🌐 保留有意义的括号对照: "${workName}"`);
      } else {
        // 移除描述性括号内容
        workName = beforeBracket + (afterBracket ? ' ' + afterBracket : '');
        console.log(`   🗑️ 移除描述性括号内容: "${insideBracket}"`);
      }
    } else {
      // 移除其他尾部括号内容
      workName = workName.replace(/\s*[((][^))]*[))].*$/, '');
    }

    // 2) 移除「」『』等引号中的副标题
    workName = workName.replace(/\s*[「『〖〈《"'][^」』〗〉》"']*[」』〗〉》"'].*$/, '');

    // 3) 移除章节相关信息(包含 "第X部/话/卷" 等模式)
    workName = workName.replace(/\s+(第\d+[部卷话篇章节期回集]|第[一二三四五六七八九十]+[部卷话篇章节期回集]).*$/, '');
    workName = workName.replace(/\s+\d+(?:\.\d+)?\s*(话|篇|期|回|集|章|节|卷|部|上|下|前|后|中|完|全|特|番外|彩页|特典|后记|前记|完结).*$/, '');

  }

  // 智能相似度匹配函数 - 专注核心作品名匹配
  function calculateSimilarity(searchTitle, resultTitle) {
    console.log(`🔄 计算相似度: "${searchTitle}" vs "${resultTitle}"`);

    // 提取两个标题的核心作品名(去除翻译组、章节号等干扰信息)
    const searchCore = extractCoreWorkName(searchTitle);
    const resultCore = extractCoreWorkName(resultTitle);

    console.log(`   📝 搜索核心: "${searchCore}"`);
    console.log(`   📝 结果核心: "${resultCore}"`);

    // 调试:检查是否有双语信息
    if (typeof searchCore === 'object' && searchCore._dualLanguage) {
      console.log(`   🌐 搜索核心双语信息: 中文="${searchCore._dualLanguage.chinese}" 外文="${searchCore._dualLanguage.foreign}"`);
    }
    if (typeof resultCore === 'object' && resultCore._dualLanguage) {
      console.log(`   🌐 结果核心双语信息: 中文="${resultCore._dualLanguage.chinese}" 外文="${resultCore._dualLanguage.foreign}"`);
    }

    // 智能长度检查:CJK字符2个即有效,英文需要3个
    function isValidCore(core) {
      if (!core) return false;
      const coreStr = core.toString();
      const hasCJK = /[\u4e00-\u9fa5\u3040-\u309F\u30A0-\u30FF\uAC00-\uD7AF]/.test(coreStr);
      return hasCJK ? coreStr.length >= 2 : coreStr.length >= 3;
    }

    if (!isValidCore(searchCore) || !isValidCore(resultCore)) {
      console.log(`   ❌ 核心标题无效,跳过`);
      return 0;
    }

    // 检查是否有关键词直接匹配(排除翻译组等无关词汇)
    const keywordMatch = checkKeywordMatch(searchCore, resultCore);
    if (keywordMatch > 0) {
      console.log(`   ✅ 关键词匹配度: ${(keywordMatch * 100).toFixed(1)}%`);
      return keywordMatch;
    }

    // 计算核心作品名的相似度
    const similarity = calculateCoreWorkSimilarity(searchCore, resultCore);
    console.log(`   ✅ 核心作品相似度: ${(similarity * 100).toFixed(1)}%`);

    return similarity;
  }

  /*** 目录识别功能 ***/
  async function searchSeriesDirectory(seriesTitle) {
    if (!seriesTitle) {
      console.log('❌ 搜索失败: 标题为空');
      return [];
    }

    console.log('🔍 开始搜索系列目录:', seriesTitle);

    // 动态获取当前帖子所属版块fid(30/37等)
    const currentForumId = detectForumId();
    const forumName = getForumName(currentForumId);
    console.log(`🎯 搜索限定在: ${forumName} (fid=${currentForumId})`);

    // 第一步:智能提取搜索关键词
    function generateSmartSearchTerms(title) {
      console.log('🎯 智能分析标题:', title);
      const searchTerms = new Set();

      // 策略1: 提取【】中的完整作品名(最高优先级)
      const titleBrackets = title.match(/【([^】]*[^汉化组个人翻译Sub字幕工作室提灯喵社团][^】]*)】/g);
      if (titleBrackets) {
        titleBrackets.forEach(bracket => {
          const content = bracket.slice(1, -1).trim();
          if (content.length >= 6 && content.length <= 25) {
            // 完整作品名
            searchTerms.add(content);
            console.log(`✅ 完整作品名: "${content}"`);

            // 如果作品名超过12字,也添加前8字的版本
            if (content.length > 12) {
              const shortVersion = content.substring(0, 8);
              searchTerms.add(shortVersion);
              console.log(`✅ 短版本作品名: "${shortVersion}"`);
            }
          }
        });
      }

      // 策略2: 提取最长连续中文片段
      const chineseSegments = title.match(/[\u4e00-\u9fa5]{4,}/g);
      if (chineseSegments) {
        // 按长度排序,取最长的2个
        const sortedSegments = chineseSegments
          .filter(seg => seg.length >= 4 && seg.length <= 15)
          .filter(seg => !isNoiseText(seg))
          .sort((a, b) => b.length - a.length)
          .slice(0, 2);

        sortedSegments.forEach(seg => {
          searchTerms.add(seg);
          console.log(`✅ 中文片段: "${seg}"`);
        });
      }

      // 策略3: 如果前面没找到好的关键词,尝试日文片段
      if (searchTerms.size === 0) {
        const japaneseSegments = title.match(/[\u3040-\u309F\u30A0-\u30FF]{4,}/g);
        if (japaneseSegments) {
          const longestJapanese = japaneseSegments
            .sort((a, b) => b.length - a.length)[0];
          if (longestJapanese && longestJapanese.length >= 4) {
            searchTerms.add(longestJapanese.substring(0, 8));
            console.log(`✅ 日文片段: "${longestJapanese.substring(0, 8)}"`);
          }
        }
      }

      // 转换为数组并限制数量
      const result = Array.from(searchTerms).slice(0, 3);
      console.log('🎯 最终搜索关键词:', result);
      return result;
    }

    // 优化关键词提取:智能提取作品名
    function extractWorkName(title) {
      // 先移除未翻译标签
      let cleanTitle = title.replace(/^\[未翻译\]\s*|\[生肉\]\s*|\[RAW\]\s*/i, '');

      // 智能提取括号中的标题信息
      const bracketContents = [];

      // 提取【】中的内容,区分汉化组和标题
      const doubleBrackets = cleanTitle.match(/【([^】]+)】/g);
      if (doubleBrackets) {
        doubleBrackets.forEach(match => {
          const content = match.slice(1, -1);
          // 如果包含"汉化"、"组"、"个人"等关键词,认为是汉化组信息
          if (!/汉化|组|个人|翻译|Sub|字幕|工作室/i.test(content)) {
            bracketContents.push(content);
          }
        });
      }

      // 提取[]中的标题内容(排除明显的作者名)
      const squareBrackets = cleanTitle.match(/\[([^\]]+)\]/g);
      if (squareBrackets) {
        squareBrackets.forEach(match => {
          const content = match.slice(1, -1);
          // 排除明显的作者名(通常较短且不含中文标点)
          if (content.length > 3 && !/^[A-Za-z0-9\s]+$/.test(content)) {
            bracketContents.push(content);
          }
        });
      }

      // 去除所有括号和汉化组信息后的主体内容
      let mainTitle = cleanTitle
        .replace(/【[^】]*汉化[^】]*】/gi, '')  // 移除汉化组信息
        .replace(/【[^】]*组[^】]*】/gi, '')    // 秮除包含"组"的信息
        .replace(/【[^】]*个人[^】]*】/gi, '')  // 移除个人翻译信息
        .replace(/\[[^\]]*\]/g, '')           // 秘除所有方括号内容
        .replace(/【[^】]*】/g, '')            // 秮除剩余的双括号内容
        .trim();

      // 去除章节信息
      mainTitle = mainTitle.replace(/\d{1,3}(?:\.\d+)?\s*[话話章节節回卷篇部].*$/i, '');
      mainTitle = mainTitle.replace(/第\d+[话話章节節回卷篇部].*$/i, '');

      // 清理标点和空格
      mainTitle = mainTitle.replace(/[、,,。!?!?;;::\s]+$/, '').trim();

      // 生成候选标题列表
      const candidates = [];

      // 1. 主标题
      if (mainTitle) {
        candidates.push(mainTitle);
      }

      // 2. 括号中的标题内容
      bracketContents.forEach(content => {
        if (content.length > 3) {
          candidates.push(content);
        }
      });

      // 3. 如果主标题包含日文,尝试提取中文部分
      if (mainTitle && /[\u3040-\u309F\u30A0-\u30FF]/.test(mainTitle)) {
        const chinesePart = mainTitle.replace(/[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FAF]*[\u3040-\u309F\u30A0-\u30FF]+[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FAF]*/g, '').trim();
        if (chinesePart && chinesePart.length > 2) {
          candidates.push(chinesePart);
        }
      }

      // 返回最长的候选标题
      const bestCandidate = candidates.reduce((longest, current) =>
        current.length > longest.length ? current : longest, '');

      return bestCandidate || mainTitle || cleanTitle;
    }

    // 生成搜索关键词 - 智能分词策略,优先中文,限制长度,最多2个搜索词
    function generateSearchTerms(title) {
      console.log('🎯 分析标题:', title);

      // ✨ 优先使用 extractCoreWorkName 提取核心作品名
      const coreWorkName = extractCoreWorkName(title);
      if (coreWorkName && coreWorkName.length >= 2) {
        console.log('✅ 使用核心作品名作为搜索词:', coreWorkName);

        const searchTerms = [];

        // 🔍 检查是否从 extractCoreWorkName 返回了双语信息
        const coreWorkNameStr = coreWorkName.toString ? coreWorkName.toString() : String(coreWorkName);
        let mainTerm = coreWorkNameStr.replace(/[!!??]+$/, '').trim();
        let alternateTerm = null;

        if (coreWorkName._dualLanguage) {
          console.log('🌐 检测到核心提取的双语信息:', coreWorkName._dualLanguage);
          const chineseTerm = coreWorkName._dualLanguage.chinese.replace(/[!!??]+$/, '').trim();
          const foreignTerm = coreWorkName._dualLanguage.foreign;

          // 🎯 优先原文,再中文
          mainTerm = foreignTerm;  // 外文作主词 (优先搜索)
          alternateTerm = chineseTerm;  // 中文作备选 (次优搜索)

          // 设置双语搜索标记
          searchTerms._dualLanguageSearch = {
            chinese: chineseTerm,
            foreign: foreignTerm,
            priority: 'foreign'
          };

          console.log(`🌐 使用双语搜索 (优先外文): 外文"${foreignTerm}" / 中文"${chineseTerm}"`);
        }

        // 🔧 清理主词的标点符号
        mainTerm = mainTerm.replace(/[!!??]+$/, '').trim();

        // 🔧 特殊处理:英文开头+中文章节标题的情况
        const englishPrefixMatch = coreWorkNameStr.match(/^([A-Za-z*]+)(.*)$/);
        if (englishPrefixMatch && englishPrefixMatch[2]) {
          const englishPart = englishPrefixMatch[1];
          const chinesePart = englishPrefixMatch[2];

          // 检查中文部分是否包含章节描述词
          if (/^[\u4e00-\u9fa5]/.test(chinesePart) && /[能和你在一起就好|希望|梦想|故事|物语|生活|日常|短篇|合同志]/.test(chinesePart)) {
            console.log(`🎯 检测到英文+中文章节标题模式,优先英文: "${englishPart}"`);
            mainTerm = englishPart;
            // 不设置 alternateTerm,只使用英文部分
          }
        }

        // 如果已经有双语信息,跳过其他处理
        if (!coreWorkName._dualLanguage) {
          const parenMatch = coreWorkNameStr.match(/^([^((]+)[((]([^))]+)[))]/);
          if (parenMatch) {
          const part1 = parenMatch[1].trim();
          const part2 = parenMatch[2].trim();
          const hasChinese1 = /[\u4e00-\u9fa5]/.test(part1);
          const hasChinese2 = /[\u4e00-\u9fa5]/.test(part2);

          if (!hasChinese1 && hasChinese2) {
            // 英文(中文) - 主词用英文,备选用中文
            mainTerm = part1.replace(/[\d\.]+$/, '').trim();
            alternateTerm = part2.replace(/[\d\.]+$/, '').trim();
            console.log(`🔄 英文主词+中文备选: "${mainTerm}" / "${alternateTerm}"`);

            // 设置双语搜索标记
            searchTerms._dualLanguageSearch = {
              chinese: alternateTerm,
              foreign: mainTerm
            };
          } else if (hasChinese1 && !hasChinese2) {
            // 中文(英文) - 主词用中文,备选用英文
            mainTerm = part1;
            alternateTerm = part2;
            console.log(`🔄 中文主词+英文备选: "${mainTerm}" / "${alternateTerm}"`);

            // 设置双语搜索标记
            searchTerms._dualLanguageSearch = {
              chinese: mainTerm,
              foreign: alternateTerm
            };
          } else if (hasChinese1 && hasChinese2) {
            // 日文(中文) - 优先中文
            mainTerm = part2;
            alternateTerm = part1;
            console.log(`🔄 中文主词+日文备选: "${mainTerm}" / "${alternateTerm}"`);

            // 设置双语搜索标记
            searchTerms._dualLanguageSearch = {
              chinese: mainTerm,
              foreign: alternateTerm
            };
          }
        }

        // 处理各种分隔符的对照翻译:/ | () ()
        else {
          let parts = null;
          let separator = '';

          // 检测分隔符并拆分
          if (coreWorkNameStr.includes('/')) {
            parts = coreWorkNameStr.split('/').map(p => p.trim());
            separator = '/';
          } else if (coreWorkNameStr.includes('|')) {
            parts = coreWorkNameStr.split('|').map(p => p.trim());
            separator = '|';
          }

          if (parts && parts.length === 2) {
            const [part1, part2] = parts;
            const hasChinese1 = /[\u4e00-\u9fa5]/.test(part1);
            const hasChinese2 = /[\u4e00-\u9fa5]/.test(part2);
            const hasJapanese1 = /[\u3040-\u309F\u30A0-\u30FF]/.test(part1);
            const hasJapanese2 = /[\u3040-\u309F\u30A0-\u30FF]/.test(part2);
            const hasEnglish1 = /[A-Za-z]/.test(part1);
            const hasEnglish2 = /[A-Za-z]/.test(part2);

            // 判断语言类型 - 修复语言检测逻辑
            // 主要看字符比例,而不是严格排他性
            const chineseRatio1 = (part1.match(/[\u4e00-\u9fa5]/g) || []).length / part1.length;
            const chineseRatio2 = (part2.match(/[\u4e00-\u9fa5]/g) || []).length / part2.length;
            const japaneseRatio1 = (part1.match(/[\u3040-\u309F\u30A0-\u30FF]/g) || []).length / part1.length;
            const japaneseRatio2 = (part2.match(/[\u3040-\u309F\u30A0-\u30FF]/g) || []).length / part2.length;

            const isChinese1 = chineseRatio1 > 0.6 && japaneseRatio1 < 0.3;
            const isChinese2 = chineseRatio2 > 0.6 && japaneseRatio2 < 0.3;
            const isJapanese1 = japaneseRatio1 > 0.3 || (hasJapanese1 && chineseRatio1 < 0.6);
            const isJapanese2 = japaneseRatio2 > 0.3 || (hasJapanese2 && chineseRatio2 < 0.6);
            const isEnglish1 = hasEnglish1 && !hasChinese1 && !hasJapanese1;
            const isEnglish2 = hasEnglish2 && !hasChinese2 && !hasJapanese2;
            const isForeign1 = isJapanese1 || isEnglish1;
            const isForeign2 = isJapanese2 || isEnglish2;

            console.log(`🔍 语言检测结果: part1="${part1}" (中文:${chineseRatio1.toFixed(2)} 日文:${japaneseRatio1.toFixed(2)}) part2="${part2}" (中文:${chineseRatio2.toFixed(2)} 日文:${japaneseRatio2.toFixed(2)})`);
            console.log(`🔍 判定结果: part1=${isChinese1?'中文':isForeign1?'外文':'混合'} part2=${isChinese2?'中文':isForeign2?'外文':'混合'}`);

            // 策略1:中外文对照 → 分别提取作为双语搜索 (优先原文)
            if ((isChinese1 && isForeign2) || (isForeign1 && isChinese2)) {
              const chineseTerm = isChinese1 ? part1 : part2;
              const foreignTerm = isForeign1 ? part1 : part2;
              console.log(`🌐 ${separator}分隔-中外对照: 外文"${foreignTerm}" / 中文"${chineseTerm}"`);

              // 🎯 优先原文,再中文 - 按用户要求调整搜索顺序
              mainTerm = foreignTerm;  // 外文作主词 (优先搜索)
              alternateTerm = chineseTerm;  // 中文作备选 (次优搜索)

              // 标记为需要双语搜索策略
              searchTerms._dualLanguageSearch = {
                chinese: chineseTerm,
                foreign: foreignTerm,
                priority: 'foreign'  // 标记优先搜索外文
              };
            }
            // 策略2:日中对照 → 优先日文原文
            else if ((isJapanese1 && isChinese2) || (isChinese1 && isJapanese2)) {
              const chineseTerm = isChinese1 ? part1 : part2;
              const japaneseTerm = isJapanese1 ? part1 : part2;
              console.log(`🌐 ${separator}分隔-日中对照: 日文"${japaneseTerm}" / 中文"${chineseTerm}"`);

              // 🎯 优先日文原文,再中文
              mainTerm = japaneseTerm;  // 日文作主词 (优先搜索)
              alternateTerm = chineseTerm;  // 中文作备选 (次优搜索)

              // 标记为需要双语搜索策略
              searchTerms._dualLanguageSearch = {
                chinese: chineseTerm,
                foreign: japaneseTerm,
                priority: 'foreign'  // 标记优先搜索外文
              };
            }
            // 策略3:两组都是中文 → 优先取前面的词
            else if (isChinese1 && isChinese2) {
              mainTerm = part1;
              alternateTerm = part2;
              console.log(`🀄 ${separator}分隔-双中文,优先前词: "${mainTerm}" / "${alternateTerm}"`);
            }
            // 策略4:其他情况 → 选择较长的
            else {
              mainTerm = part1.length >= part2.length ? part1 : part2;
              alternateTerm = part1.length >= part2.length ? part2 : part1;
              console.log(`🔧 ${separator}分隔-选长词: "${mainTerm}" / "${alternateTerm}"`);
            }
          }
        }
        } // 关闭 if (!coreWorkName._dualLanguage)

        // 🎯 添加主搜索词 - 支持2字中文
        if (mainTerm && (mainTerm.length >= 2)) {
          // 对中文降低长度要求到2字,其他语言保持3字符
          const hasChinese = /[\u4e00-\u9fa5]/.test(mainTerm);
          if (hasChinese && mainTerm.length >= 2) {
            searchTerms.push(mainTerm);
          } else if (!hasChinese && mainTerm.length >= 3) {
            searchTerms.push(mainTerm);
          }
        }

        // 🎯 添加备选搜索词 - 支持2字中文
        if (alternateTerm && (alternateTerm.length >= 2)) {
          // 对中文降低长度要求到2字,其他语言保持3字符
          const hasChinese = /[\u4e00-\u9fa5]/.test(alternateTerm);
          if (hasChinese && alternateTerm.length >= 2) {
            searchTerms.push(alternateTerm);
          } else if (!hasChinese && alternateTerm.length >= 3) {
            searchTerms.push(alternateTerm);
          }
        }

        // 检查是否为纯英文作品名
        const isPureEnglish = /^[A-Za-z\s]+$/.test(coreWorkNameStr);

        if (isPureEnglish) {
          // 英文作品名:检查是否包含多个单词
          const words = coreWorkNameStr.trim().split(/\s+/);

          if (words.length > 1) {
            // ✨ 策略改变:直接使用带空格的原始版本搜索
            // 论坛搜索会把空格当作"AND"条件,能找到包含所有词的结果
            console.log(`✅ 英文多词(保持空格): "${coreWorkNameStr}"`);

            // ✨ 移除备选首词逻辑,避免过度分割
            // 保持完整的英文标题,不添加单词片段
            console.log(`🚫 跳过首词分割,保持完整标题`);
          } else {
            // 单个英文单词
            console.log(`✅ 单个英文词: "${coreWorkNameStr}"`);
          }

          // 纯英文标题不启用双语搜索
          searchTerms._pureEnglish = true;
        } else {
          // 中文/日文/混合作品名
          if (!coreWorkName._dualLanguage) {
            // 只有在没有双语信息时才添加原始作品名
            searchTerms.push(coreWorkNameStr);
          }

          // ✨ 如果原标题包含括号中的英文,也添加为双语搜索
          const bracketEnglish = title.match(/[((]([A-Za-z\s!?]+)[))]/);
          if (bracketEnglish) {
            const englishName = bracketEnglish[1].trim().replace(/[!?]+$/, '');
            if (englishName.length >= 3) {
              // 🎯 优先英文,再中文
              searchTerms.length = 0; // 清空原有的
              searchTerms.push(englishName);  // 英文优先
              searchTerms.push(coreWorkNameStr);  // 中文其次

              // 设置双语搜索标记
              searchTerms._dualLanguageSearch = {
                chinese: coreWorkNameStr,
                foreign: englishName,
                priority: 'foreign'
              };

              console.log(`🌐 括号中英对照 (优先英文): 英文"${englishName}" / 中文"${coreWorkNameStr}"`);
            }
          }

          // 优化长度控制:主词过长(>12字符)自动生成6字符短版本
          if (coreWorkNameStr.length > 12 && searchTerms.length === 1) {
            const shortVersion = coreWorkNameStr.substring(0, 6);
            // 确保短版本不会太短造成搜索泛化(至少4个有效字符)
            if (shortVersion.length >= 4 && shortVersion.replace(/\s+/g, '').length >= 3) {
              searchTerms.push(shortVersion);
              console.log('✅ 主词过长,添加6字符短版本作为备选:', shortVersion);
            }
          }
        }

        // 去重处理并保留元信息
        const uniqueTerms = Array.from(new Set(searchTerms.filter(Boolean)));
        if (searchTerms._dualLanguageSearch) uniqueTerms._dualLanguageSearch = searchTerms._dualLanguageSearch;
        if (searchTerms._pureEnglish) uniqueTerms._pureEnglish = searchTerms._pureEnglish;

        console.log('🎯 最终搜索关键词:', uniqueTerms);
        return uniqueTerms.slice(0, 2);
      }

      // 如果核心提取失败,使用原有的备用逻辑
      console.log('⚠️ 核心作品名提取失败,使用备用逻辑');

      // 移除常见的噪音标签
      let cleanTitle = title
        .replace(/^\[未翻译\]\s*|\[生肉\]\s*|\[RAW\]\s*/i, '')
        .replace(/【[^】]*】/g, (match) => {
          const content = match.slice(1, -1);
          return isNoiseText(content) ? '' : match;
        });

      const candidates = {
        chinese: [], // 中文标题候选
        japanese: [], // 日文标题候选
        mixed: [] // 混合标题候选
      };

      // 策略1: 提取【】中的核心作品名
      const doubleBrackets = cleanTitle.match(/【([^】]+)】/g);
      if (doubleBrackets) {
        doubleBrackets.forEach(match => {
          const content = match.slice(1, -1).trim();
          // 统一使用 isNoiseText 过滤
          if (content.length >= 3 && content.length <= 20 && !isNoiseText(content)) {

            // 判断内容类型
            const hasChinese = /[\u4e00-\u9fa5]/.test(content);
            const hasJapanese = /[\u3040-\u309F\u30A0-\u30FF]/.test(content);

            if (hasChinese && hasJapanese) {
              candidates.mixed.push(content);
            } else if (hasChinese) {
              candidates.chinese.push(content);
            } else if (hasJapanese) {
              candidates.japanese.push(content);
            }

            console.log(`✅ 找到【】中的标题: "${content}" (类型: ${hasChinese ? '中' : ''}${hasJapanese ? '日' : ''})`);
          }
        });
      }

      // 策略2: 提取最长的纯中文片段(统一使用 isNoiseText 过滤)
      const chineseMatches = cleanTitle.match(/[\u4e00-\u9fa5]{3,}/g);
      if (chineseMatches) {
        chineseMatches
          .filter(match => match.length >= 3)
          .filter(match => !isNoiseText(match))
          .forEach(match => {
            candidates.chinese.push(match);
          });
      }

      // 策略3: 提取最长的日文片段
      const japaneseMatches = cleanTitle.match(/[\u3040-\u309F\u30A0-\u30FF]{3,}/g);
      if (japaneseMatches) {
        japaneseMatches
          .filter(match => match.length >= 3)
          .forEach(match => {
            candidates.japanese.push(match);
          });
      }

      // 智能选择搜索词
      const finalTerms = [];

      // 优先级1: 中文标题
      if (candidates.chinese.length > 0) {
        const bestChinese = candidates.chinese
          .sort((a, b) => b.length - a.length)[0];

        // 如果中文标题超过12字,截取前6字
        let searchTerm = bestChinese;
        if (searchTerm.length > 12) {
          searchTerm = searchTerm.substring(0, 6);
          console.log(`🔤 中文标题过长,截取前6字: "${bestChinese}" -> "${searchTerm}"`);
        }
        finalTerms.push(searchTerm);
        console.log('✅ 优先使用中文标题:', searchTerm);
      }

      // 优先级2: 如果没有中文标题,使用日文标题
      if (finalTerms.length === 0 && candidates.japanese.length > 0) {
        const bestJapanese = candidates.japanese
          .sort((a, b) => b.length - a.length)[0];

        // 如果日文标题超过12字,截取前6字
        let searchTerm = bestJapanese;
        if (searchTerm.length > 12) {
          searchTerm = searchTerm.substring(0, 6);
          console.log(`🔤 日文标题过长,截取前6字: "${bestJapanese}" -> "${searchTerm}"`);
        }
        finalTerms.push(searchTerm);
        console.log('✅ 使用日文标题:', searchTerm);
      }

      // 优先级3: 混合标
      if (finalTerms.length === 0 && candidates.mixed.length > 0) {
        const bestMixed = candidates.mixed
          .sort((a, b) => b.length - a.length)[0];

        // 尝试提取中文部分
        const chinesePart = bestMixed.match(/[\u4e00-\u9fa5]+/g);
        if (chinesePart && chinesePart.length > 0) {
          let searchTerm = chinesePart.join('');
          if (searchTerm.length > 12) {
            searchTerm = searchTerm.substring(0, 6);
          }
          finalTerms.push(searchTerm);
          console.log('✅ 从混合标题提取中文部分:', searchTerm);
        } else {
          let searchTerm = bestMixed;
          if (searchTerm.length > 12) {
            searchTerm = searchTerm.substring(0, 6);
          }
          finalTerms.push(searchTerm);
          console.log('✅ 使用混合标题:', searchTerm);
        }
      }

      // 兜底策略:如果都没找到,使用清理后的标题
      if (finalTerms.length === 0) {
        let baseTitle = cleanTitle
          .replace(/第?\d+(?:\.\d+)?\s*[话話章节節回卷篇期].*$/i, '')
          .replace(/\d+(?:\.\d+)?\s*$/, '')
          .replace(/[【】\[\]()()]/g, ' ')
          .replace(/[、,,。!?!?;;::\s]+/g, ' ')
          .trim();

        if (baseTitle && baseTitle.length >= 3) {
          // 截取处理
          if (baseTitle.length > 10) {
            baseTitle = baseTitle.substring(0, 6);
            console.log(`🔤 兜底标题过长,截取前6字: "${baseTitle}"`);
          }
          finalTerms.push(baseTitle);
          console.log('✅ 使用清理后的标题:', baseTitle);
        }
      }

      // 可选的第二个搜索词:如果第一个词是从长标题截取的,可以尝试更短的核心词
      if (finalTerms.length === 1 && finalTerms[0].length >= 5) {
        const firstTerm = finalTerms[0];
        // 尝试提取更短的核心词(3-4字)
        if (firstTerm.length > 4) {
          const shorterTerm = firstTerm.substring(0, 4);
          // 避免重复添加
          if (shorterTerm !== firstTerm) {
            finalTerms.push(shorterTerm);
            console.log('✅ 添加更短的核心词作为备选:', shorterTerm);
          }
        }
      }

      // 去重处理
      const uniqueTerms = Array.from(new Set(finalTerms.filter(Boolean)));

      console.log('🎯 最终搜索关键词:', uniqueTerms);
      return uniqueTerms.slice(0, 2); // 最多返回2个搜索词
    }

    // 🌐 双语搜索辅助函数:执行单次搜索并返回结果数量
    async function performSingleSearch(keyword, forumId) {
      if (!keyword) return [];

      try {
        console.log(`🔎 单次搜索测试: "${keyword}"`);

        // 获取搜索页面和FormHash
        const searchPageResponse = await fetch('https://bbs.yamibo.com/search.php', {
          method: 'GET',
          credentials: 'include',
          headers: {
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
            'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
            'Referer': window.location.href,
            'User-Agent': navigator.userAgent
          }
        });

        let formHash = '';
        if (searchPageResponse.ok) {
          const searchPageHtml = await searchPageResponse.text();
          const formHashMatch = searchPageHtml.match(/name="formhash"\s+value="([^"]+)"/);
          if (formHashMatch) formHash = formHashMatch[1];
        }

        await new Promise(resolve => setTimeout(resolve, 1500)); // 防止过快请求

        // 执行搜索
        const formData = new FormData();
        formData.append('formhash', formHash);
        formData.append('srchtxt', keyword);
        if (forumId) formData.append('srchfid[]', forumId);
        formData.append('orderby', 'dateline');
        formData.append('ascdesc', 'desc');
        formData.append('searchsubmit', 'yes');

        const response = await fetch('https://bbs.yamibo.com/search.php?mod=forum', {
          method: 'POST',
          credentials: 'include',
          headers: {
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
            'Origin': 'https://bbs.yamibo.com',
            'Referer': 'https://bbs.yamibo.com/search.php',
            'User-Agent': navigator.userAgent
          },
          body: formData
        });

        if (response.ok) {
          const html = await response.text();
          const parser = new DOMParser();
          const doc = parser.parseFromString(html, 'text/html');

          // 提取搜索结果
          const results = [];
          const threadElements = doc.querySelectorAll('#threadlisttableid tbody[id^="normalthread_"]');

          threadElements.forEach(thread => {
            const titleElement = thread.querySelector('th a[href*="thread-"]');
            if (titleElement) {
              results.push({
                title: titleElement.textContent.trim(),
                url: titleElement.href
              });
            }
          });

          console.log(`📊 "${keyword}" 搜索到 ${results.length} 个结果`);
          return results;
        }

        return [];
      } catch (error) {
        console.warn(`⚠️ 单次搜索"${keyword}"失败:`, error);
        return [];
      }
    }

    // 生成搜索关键词
    let searchTerms = generateSearchTerms(seriesTitle);

    // 检查是否有双语搜索标记(仅在真正的双语对照时启用)
    if (searchTerms && searchTerms._dualLanguageSearch && !searchTerms._pureEnglish) {
      const { chinese, foreign } = searchTerms._dualLanguageSearch;
      console.log(`🌐 检测到中外文对照,启用双语搜索: 中文"${chinese}" vs 外文"${foreign}"`);

      try {
        // 分别搜索中文和外文,比较结果数量
        const chineseResults = await performSingleSearch(chinese, currentForumId);
        const foreignResults = await performSingleSearch(foreign, currentForumId);

        console.log(`📊 搜索结果对比: 中文"${chinese}"=${chineseResults.length}个 / 外文"${foreign}"=${foreignResults.length}个`);

        // 根据搜索结果优化搜索词顺序
        if (foreignResults.length > chineseResults.length) {
          console.log(`✅ 外文搜索结果更多,优先使用外文关键词: "${foreign}"`);
          searchTerms = [foreign, chinese];
        } else {
          console.log(`✅ 中文搜索结果更优,优先使用中文关键词: "${chinese}"`);
          searchTerms = [chinese, foreign];
        }

        delete searchTerms._dualLanguageSearch;
        console.log('🎯 双语搜索优化后关键词:', searchTerms);
      } catch (error) {
        console.warn('⚠️ 双语搜索比较失败,使用默认策略:', error);
        delete searchTerms._dualLanguageSearch;
      }
    }

    if (!searchTerms || searchTerms.length === 0) {
      searchTerms = generateSmartSearchTerms(seriesTitle);
      console.log('📝 使用传统搜索逻辑生成关键词:', searchTerms);
    }

    console.log('📝 使用搜索方式获取完整系列目录...');

    const searchResults = new Map();

    try {
      const cacheKey = seriesTitle;
      if (searchCache.has(cacheKey)) {
        console.log('📦 使用内存缓存结果:', searchCache.get(cacheKey).length, '个章节');
        return searchCache.get(cacheKey);
      }

      // 检查持久化缓存
      const seriesKey = generateSeriesKey(seriesTitle);
      const cachedDirectory = getCachedDirectory(seriesKey);
      if (cachedDirectory && cachedDirectory.length > 0) {
        console.log('📦 使用持久化缓存结果:', cachedDirectory.length, '个章节');
        searchCache.set(cacheKey, cachedDirectory);
        return cachedDirectory;
      }



      // 检测503错误频率,如果连续失败则停止搜索
      console.log('⚠️ 注意:论坛有搜索频率限制,将串行搜索以避免503错误');

      let consecutiveFailures = 0;
      const maxFailures = 1; // 减少到1次失败后就切换策略
      let searchBlocked = false;

      for (let i = 0; i < Math.min(searchTerms.length, 2); i++) { // 限制最多2次搜索
        const searchTerm = searchTerms[i];

        // 如果连续失败次数过多,停止搜索
        if (consecutiveFailures >= maxFailures) {
          console.log(`❌ 连续失败 ${maxFailures} 次,停止搜索以避免被论坛限制`);
          break;
        }

        // ✅ 如果已经找到足够的结果,跳过后续搜索
        if (searchResults.size > 0) {
          console.log(`✅ 已找到 ${searchResults.size} 个结果,跳过后续搜索`);
          break;
        }

        // 如果不是第一个搜索,等待12秒避免频率限制
        if (i > 0) {
          console.log(`⏱️ 等待12秒后进行下一个搜索 (${i+1}/${Math.min(searchTerms.length, 2)})...`);
          await new Promise(resolve => setTimeout(resolve, 12000));
        }

        try {
          console.log('🔎 当前搜索关键词:', searchTerm);

          console.log('📝 获取搜索页面...');
          const searchPageResponse = await fetch('https://bbs.yamibo.com/search.php', {
            method: 'GET',
            credentials: 'include',
            headers: {
              'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
              'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
              'Cache-Control': 'no-cache',
              'Pragma': 'no-cache',
              'Referer': window.location.href,
              'User-Agent': navigator.userAgent || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
            }
          });

          let formHash = '';
          if (searchPageResponse.ok) {
            const searchPageHtml = await searchPageResponse.text();
            const formHashMatch = searchPageHtml.match(/name="formhash"\s+value="([^"]+)"/);
            if (formHashMatch) {
              formHash = formHashMatch[1];
              console.log('✅ 获取到新的FormHash:', formHash);
            }
          }

          // 等待一小段时间模拟人工操作
          await new Promise(resolve => setTimeout(resolve, Math.random() * 2000 + 1000));

          // 使用动态获取的fid
          const formData = new FormData();
          formData.append('formhash', formHash);
          formData.append('srchtxt', searchTerm);
          formData.append('srchfid[]', currentForumId); // 动态版块ID
          formData.append('orderby', 'dateline');
          formData.append('ascdesc', 'desc');
          formData.append('searchsubmit', 'yes');

          console.log('🔍 发送搜索请求...');
          console.log('📝 搜索参数详情:', {
            formhash: formHash,
            srchtxt: searchTerm,
            srchfid: currentForumId,
            orderby: 'dateline',
            ascdesc: 'desc'
          });

          // 先尝试GET搜索(模拟手动搜索)
          const encodedSearchTerm = encodeURIComponent(searchTerm);
          const getUrl = `https://bbs.yamibo.com/search.php?mod=forum&srchtxt=${encodedSearchTerm}&formhash=${formHash}&srchfid=${currentForumId}&orderby=dateline&ascdesc=desc&searchsubmit=yes`;
          console.log('🌐 尝试GET搜索URL:', getUrl);

          let response = await fetch(getUrl, {
            method: 'GET',
            credentials: 'include',
            headers: {
              'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
              'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
              'Cache-Control': 'no-cache',
              'Referer': 'https://bbs.yamibo.com/search.php',
              'User-Agent': navigator.userAgent || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
            }
          });

          // 如果GET失败,回退到POST
          if (!response.ok) {
            console.log('❌ GET搜索失败,尝试POST搜索...');
            response = await fetch('https://bbs.yamibo.com/search.php?mod=forum', {
              method: 'POST',
              credentials: 'include',
              headers: {
                'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
                'Origin': 'https://bbs.yamibo.com',
                'Referer': 'https://bbs.yamibo.com/search.php',
                'Sec-Fetch-Dest': 'document',
                'Sec-Fetch-Mode': 'navigate',
                'Sec-Fetch-Site': 'same-origin',
                'Sec-Fetch-User': '?1',
                'Upgrade-Insecure-Requests': '1',
                'User-Agent': navigator.userAgent || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
              },
              body: formData
            });
          } else {
            console.log('✅ GET搜索请求成功');
          }

          if (!response.ok) {
            console.log(`❌ 搜索请求失败: ${response.status} - ${response.statusText}`);
            consecutiveFailures++;

            if (response.status === 503) {
              console.log('⚠️ 搜索服务暂时不可用,可能是论坛维护中');
            }
            continue;
          }

          const html = await response.text();
          if (html.includes('需要登录')) {
            console.log('❌ 需要登录');
            continue;
          }

          const parser = new DOMParser();
          const doc = parser.parseFromString(html, 'text/html');

          // 调试:检查页面标题和主要内容
          const pageTitle = doc.querySelector('title')?.textContent || '无标题';
          console.log('📄 搜索结果页面标题:', pageTitle);

          // 检查是否有搜索结果统计信息
          const resultStats = doc.querySelector('.pg .xi2, .ptm .xi2, .pages .xi2');
          if (resultStats) {
            console.log('📊 搜索统计信息:', resultStats.textContent.trim());
          }

          // 改进的搜索结果提取 - 支持多页和多种选择器
          const pageSearchResults = [];

          // 尝试多种可能的选择器(累积式)
          const selectors = [
            '#threadlist li.pbw h3.xs3 a',                    // 原有主选择器
            '#threadlist ul li.pbw h3.xs3 a',                // 百合会搜索结果的实际结构!
            '#threadlist .slst ul li.pbw h3 a',              // 搜索结果页面的完整路径
            '#threadlist li h3.xs3 a',                       // 简化版本的搜索结果
            '#threadlist .xst',                               // 标准搜索结果
            'a.xst',                                         // 通用搜索结果链接
            '.xst',                                          // 搜索结果标题类
            'a[href*="thread-"]',                            // 包含thread的链接
            'a[href*="tid="]',                               // 包含tid的链接
            '.s.xst',                                        // 另一种搜索结果格式
            '#threadlist tbody .subject a',                  // 表格形式的搜索结果
            '.threadlist .title a',                          // 标题链接
            'h3 a[href*="thread"]',                         // h3中的帖子链接
            'tbody[id^="normalthread"] .xst',                // 论坛标准列表格式
            'tbody[id^="normalthread"] a[href*="thread"]',   // 标准帖子列表中的链接
            '.ptm .xst',                                     // 搜索结果页面格式
            '#threadlisttableid .xst',                       // 帖子列表表格中的标题
            '#threadlisttableid a[href*="thread"]',          // 帖子列表表格中的链接
            '.bl .xst',                                      // 搜索结果中的标题
            'table .subject a',                              // 表格中的主题链接
            '.ptm a[href*="thread"]'                         // 搜索结果中的所有帖子链接
          ];

          let foundResults = false;
          selectors.forEach(selector => {
            const elements = doc.querySelectorAll(selector);
            if (elements.length > 0) {
              console.log(`✅ 选择器 "${selector}" 找到 ${elements.length} 个结果`);
              pageSearchResults.push(...Array.from(elements));
              foundResults = true;
            }
          });

          if (!foundResults) {
            console.log('❌ 所有选择器都未找到结果,打印页面结构用于调试...');

            // 调试信息:检查页面是否包含搜索词
            const bodyText = doc.body?.textContent || '';
            const searchTermLower = searchTerm.toLowerCase();
            const containsSearchTerm = bodyText.toLowerCase().includes(searchTermLower);
            console.log(`🔍 页面是否包含搜索词"${searchTerm}": ${containsSearchTerm}`);

            // 检查页面是否有错误信息
            const errorMsg = doc.querySelector('.error, .alert, .notice');
            if (errorMsg) {
              console.log('⚠️ 页面错误信息:', errorMsg.textContent.trim());
            }

            // 打印页面的主要结构
            const allLinks = doc.querySelectorAll('a[href*="thread"], a[href*="tid="]');
            console.log(`📋 页面中所有thread链接数量: ${allLinks.length}`);
            if (allLinks.length > 0) {
              console.log('📋 前5个thread链接:');
              Array.from(allLinks).slice(0, 5).forEach((link, idx) => {
                console.log(`   ${idx + 1}. "${link.textContent.trim()}" (${link.href})`);
              });
            }

            // 检查是否有特殊的搜索结果结构
            const searchResultContainer = doc.querySelector('#threadlist, #threadlisttableid, .searchresult, .ptm');
            if (searchResultContainer) {
              console.log('📋 找到搜索结果容器:', searchResultContainer.tagName + (searchResultContainer.id ? '#' + searchResultContainer.id : '') + (searchResultContainer.className ? '.' + searchResultContainer.className.replace(/\s+/g, '.') : ''));

              // 检查容器内的链接
              const containerLinks = searchResultContainer.querySelectorAll('a');
              console.log(`📋 容器内链接数量: ${containerLinks.length}`);
            }
          }

          // 去重处理
          const uniqueResults = [];
          const seenUrls = new Set();
          pageSearchResults.forEach(link => {
            const href = link.href;
            if (href && !seenUrls.has(href)) {
              seenUrls.add(href);
              uniqueResults.push(link);
            }
          });

          console.log(`📊 搜索结果汇总: 原始 ${pageSearchResults.length} 个,去重后 ${uniqueResults.length} 个`);

          // 检查是否有下一页,并获取前2页的结果
          const hasNextPage = doc.querySelector('.nxt, .next, a[href*="page=2"]');
          if (hasNextPage && uniqueResults.length > 0) {
            console.log('📄 检测到搜索结果有多页,尝试获取第2页...');

            try {
              await new Promise(resolve => setTimeout(resolve, 2000));

              const currentUrl = new URL(response.url);
              currentUrl.searchParams.set('page', '2');

              const page2Response = await fetch(currentUrl.toString(), {
                method: 'GET',
                credentials: 'include',
                headers: {
                  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                  'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
                  'Referer': response.url,
                  'User-Agent': navigator.userAgent || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
                }
              });

              if (page2Response.ok) {
                const page2Html = await page2Response.text();
                const page2Doc = new DOMParser().parseFromString(page2Html, 'text/html');

                // 提取第2页结果
                const page2Results = [];
                selectors.forEach(selector => {
                  const elements = page2Doc.querySelectorAll(selector);
                  if (elements.length > 0) {
                    page2Results.push(...Array.from(elements));
                  }
                });

                // 去重并合并第2页结果
                page2Results.forEach(link => {
                  const href = link.href;
                  if (href && !seenUrls.has(href)) {
                    seenUrls.add(href);
                    uniqueResults.push(link);
                  }
                });

                console.log(`✅ 第2页找到额外 ${page2Results.length} 个结果,总计 ${uniqueResults.length} 个`);
              } else {
                console.log('❌ 获取第2页失败:', page2Response.status);
              }
            } catch (error) {
              console.warn('⚠️ 获取第2页时出错:', error.message);
            }
          }

          // 使用去重后的结果
          const finalResults = uniqueResults;

          const currentResults = finalResults.map(link => {
            const originalTitle = link.textContent.trim();
            let url = link.href;

            if (!originalTitle || originalTitle === '快速') return null;

            if (url.startsWith('/')) {
              url = `https://bbs.yamibo.com${url}`;
            } else if (url.startsWith('forum.php')) {
              url = `https://bbs.yamibo.com/${url}`;
            }

            const threadId = url.match(/tid=(\d+)/)?.[1] || url.match(/thread-(\d+)-/)?.[1];
            if (!threadId) return null;

            // ✨ 智能匹配过滤(针对多单词英文搜索优化)
            const hasEnglish = /[A-Za-z]/.test(searchTerm);
            if (hasEnglish && searchTerm.length >= 4) {
              const titleLower = originalTitle.toLowerCase();
              const searchLower = searchTerm.toLowerCase();

              // 对于多单词英文搜索,检查是否包含所有关键单词
              if (searchTerm.includes(' ')) {
                const searchWords = searchTerm.toLowerCase().split(/\s+/).filter(word => word.length > 2);
                const allWordsFound = searchWords.every(word => titleLower.includes(word));

                if (!allWordsFound) {
                  console.log(`   ❌ 多词过滤: "${originalTitle}" 不包含所有关键词 [${searchWords.join(', ')}]`);
                  return null;
                } else {
                  console.log(`   ✅ 多词匹配: "${originalTitle}" 包含所有关键词 [${searchWords.join(', ')}]`);
                }
              } else {
                // 单词搜索,直接检查包含关系
                if (!titleLower.includes(searchLower)) {
                  console.log(`   ❌ 单词过滤: "${originalTitle}" 不包含 "${searchTerm}"`);
                  return null;
                } else {
                  console.log(`   ✅ 单词匹配: "${originalTitle}" 包含 "${searchTerm}"`);
                }
              }
            }

            // 直接使用原始标题进行相似度计算,不要预先清理
            const similarity = calculateSimilarity(seriesTitle, originalTitle);

            return {
              threadId,
              title: originalTitle,
              originalTitle: originalTitle,
              url,
              normalizedTitle: normalizeSeriesTitle(originalTitle),
              similarity,
              searchTerm
            };
          }).filter(Boolean);

          // 合并当前搜索结果
          currentResults.forEach(item => {
            const existing = searchResults.get(item.threadId);
            if (!existing || item.similarity > existing.similarity) {
              searchResults.set(item.threadId, item);
            }
          });

          console.log(`✅ 搜索词 "${searchTerm}" 完成,找到 ${currentResults.length} 个结果`);

          // 详细显示搜索结果
          if (currentResults.length > 0) {
            console.log(`   搜索结果详情:`);
            currentResults.slice(0, 5).forEach((result, idx) => {
              console.log(`     ${idx + 1}. "${result.title}" (相似度: ${(result.similarity * 100).toFixed(1)}%)`);
            });
          } else {
            console.log(`   ⚠️ 搜索词 "${searchTerm}" 未找到任何结果`);

            // 🔄 回退策略:对于多单词英文搜索无结果,立即尝试首个单词搜索
            if (/^[A-Za-z\s]+$/.test(searchTerm) && searchTerm.includes(' ')) {
              const firstWord = searchTerm.split(/\s+/)[0];
              if (firstWord.length >= 4 && !searchTerms.includes(firstWord)) {
                console.log(`🔄 多词英文搜索无结果,立即尝试首词: "${firstWord}"`);

                try {
                  // 等待短暂间隔后搜索首词
                  await new Promise(resolve => setTimeout(resolve, 3000));

                  // 递归调用相同的搜索逻辑(复用现有的表单构建和请求逻辑)
                  const backupFormData = new FormData();
                  backupFormData.append('formhash', formHash);
                  backupFormData.append('srchtxt', firstWord);
                  backupFormData.append('srchfid[]', currentForumId);
                  backupFormData.append('orderby', 'dateline');
                  backupFormData.append('ascdesc', 'desc');
                  backupFormData.append('searchsubmit', 'yes');

                  const backupResponse = await fetch('https://bbs.yamibo.com/search.php?mod=forum', {
                    method: 'POST',
                    credentials: 'include',
                    headers: {
                      'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                      'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
                      'Origin': 'https://bbs.yamibo.com',
                      'Referer': 'https://bbs.yamibo.com/search.php',
                      'User-Agent': navigator.userAgent
                    },
                    body: backupFormData
                  });

                  if (backupResponse.ok) {
                    const backupHtml = await backupResponse.text();
                    const backupDoc = new DOMParser().parseFromString(backupHtml, 'text/html');

                    const backupResults = [];
                    const selectors = [
                      '#threadlist li.pbw h3.xs3 a',
                      '#threadlist .xst',
                      'a.xst',
                      'a[href*="thread-"]'
                    ];

                    selectors.forEach(selector => {
                      const elements = backupDoc.querySelectorAll(selector);
                      if (elements.length > 0) {
                        backupResults.push(...Array.from(elements));
                      }
                    });

                    const processedBackupResults = backupResults.map(link => {
                      const originalTitle = link.textContent.trim();
                      let url = link.href;
                      if (!originalTitle || originalTitle === '快速') return null;
                      if (url.startsWith('/')) url = `https://bbs.yamibo.com${url}`;

                      const threadId = url.match(/tid=(\d+)/)?.[1] || url.match(/thread-(\d+)-/)?.[1];
                      if (!threadId) return null;

                      // 对回退结果进行更严格的过滤:必须包含原搜索词的多个关键词
                      const titleLower = originalTitle.toLowerCase();
                      const originalWords = searchTerm.toLowerCase().split(/\s+/).filter(w => w.length > 2);
                      const matchCount = originalWords.filter(word => titleLower.includes(word)).length;

                      // 只保留包含原搜索词至少一半关键词的结果
                      if (matchCount < Math.ceil(originalWords.length / 2)) {
                        return null;
                      }

                      const similarity = calculateSimilarity(seriesTitle, originalTitle);
                      return {
                        threadId,
                        title: originalTitle,
                        originalTitle: originalTitle,
                        url,
                        normalizedTitle: normalizeSeriesTitle(originalTitle),
                        similarity,
                        searchTerm: `${firstWord}(回退)`
                      };
                    }).filter(Boolean);

                    if (processedBackupResults.length > 0) {
                      console.log(`🎯 首词回退搜索找到 ${processedBackupResults.length} 个相关结果`);
                      processedBackupResults.forEach(item => {
                        const existing = searchResults.get(item.threadId);
                        if (!existing || item.similarity > existing.similarity) {
                          searchResults.set(item.threadId, item);
                        }
                      });
                    }
                  }
                } catch (backupError) {
                  console.warn('⚠️ 首词回退搜索失败:', backupError.message);
                }
              }
            }
          }

          consecutiveFailures = 0;

        } catch (error) {
          console.warn(`❌ 搜索词 "${searchTerm}" 失败:`, error.message);
          consecutiveFailures++;
          // 继续下一个搜索词
        }
      }

      // 智能筛选和排序
      let directory = Array.from(searchResults.values())
        .filter(item => item.similarity > 0.7);

      // 简单按发帖时间排序(threadId小的是老帖子,排在前面)
      directory.sort((a, b) => {
        const threadIdA = parseInt(a.threadId);
        const threadIdB = parseInt(b.threadId);
        console.log(`🔄 排序比较: "${a.title}" (ID:${threadIdA}) vs "${b.title}" (ID:${threadIdB})`);
        console.log(`   按threadId排序: ${threadIdA} - ${threadIdB} = ${threadIdA - threadIdB}`);
        return threadIdA - threadIdB;
      });

      console.log(`📊 智能筛选后: 找到 ${directory.length} 个相关章节`);
      directory.forEach(item => {
        const chapterNum = extractChapterNumber(item.title);
        console.log(`   "${item.title}" (章节号: ${chapterNum}, 相似度: ${(item.similarity *  100).toFixed(1)}%)`);
      });

      if (directory.length > 0) {
        // 缓存成功的搜索结果
        searchCache.set(cacheKey, directory);

        // 同时保存到持久化缓存
        const seriesKey = generateSeriesKey(seriesTitle);
        setCachedDirectory(seriesKey, directory);

        return directory;
      }

      console.log('❌ 所有搜索词都未找到相关章节');

      // 只有在第一轮搜索完全失败时才尝试备用策略
      if (directory.length === 0 && consecutiveFailures < maxFailures) {
        console.log('🔄 第一轮搜索无结果,尝试简单备用搜索...');

        // 生成一个简单的备用搜索词
        let backupTerm = '';

        // 优先提取最长的中文片段(过滤噪音词)
        const chineseMatches = seriesTitle.match(/[\u4e00-\u9fa5]{4,}/g);
        if (chineseMatches && chineseMatches.length > 0) {
          // 找到第一个不是噪音的中文片段
          const validChinese = chineseMatches
            .sort((a, b) => b.length - a.length)
            .find(match => !isNoiseText(match));

          if (validChinese) {
            backupTerm = validChinese.substring(0, 5);
            console.log('🔤 备用搜索使用中文片段:', backupTerm);
          } else {
            console.log('❌ 所有中文片段都被判定为噪音,跳过备用搜索');
          }
        } else {
          // 如果没有中文,提取日文片段
          const japaneseMatches = seriesTitle.match(/[\u3040-\u309F\u30A0-\u30FF]{3,}/g);
          if (japaneseMatches && japaneseMatches.length > 0) {
            const validJapanese = japaneseMatches.find(match => !isNoiseText(match));
            if (validJapanese) {
              backupTerm = validJapanese.substring(0, 5);
              console.log('🔤 备用搜索使用日文片段:', backupTerm);
            } else {
              console.log('❌ 所有日文片段都被判定为噪音,跳过备用搜索');
            }
          }
        }

        if (backupTerm) {
          try {
            console.log('🔍 执行备用搜索:', backupTerm);

            // 等待10秒
            await new Promise(resolve => setTimeout(resolve, 10000));

            const formData = new FormData();
            formData.append('formhash', getFormHash() || '');
            formData.append('srchtxt', backupTerm);
            formData.append('srchfid[]', '30');
            formData.append('orderby', 'dateline');
            formData.append('ascdesc', 'desc');
            formData.append('searchsubmit', 'yes');

            const response = await fetch('https://bbs.yamibo.com/search.php?mod=forum', {
              method: 'POST',
              credentials: 'include',
              headers: {
                'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
                'Referer': 'https://bbs.yamibo.com/search.php',
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
              },
              body: formData
            });

            if (response.ok) {
              const html = await response.text();
              const parser = new DOMParser();
              const doc = parser.parseFromString(html, 'text/html');

              const backupPageResults = [];
              const threadList = doc.querySelectorAll('#threadlist li.pbw h3.xs3 a');
              if (threadList.length > 0) {
                backupPageResults.push(...Array.from(threadList));
              } else {
                backupPageResults.push(...Array.from(doc.querySelectorAll('a.xst, a[href*="thread-"]')));
              }

              const backupResults = backupPageResults.map(link => {
                const title = link.textContent.trim();
                let url = link.href;

                if (!title || title === '快速') return null;

                if (url.startsWith('/')) {
                  url = `https://bbs.yamibo.com${url}`;
                } else if (url.startsWith('forum.php')) {
                  url = `https://bbs.yamibo.com/${url}`;
                }

                const threadId = url.match(/tid=(\d+)/)?.[1] || url.match(/thread-(\d+)-/)?.[1];
                if (!threadId) return null;

                const similarity = calculateSimilarity(seriesTitle, title);

                return {
                  threadId,
                  title,
                  originalTitle: title,
                  url,
                  normalizedTitle: normalizeSeriesTitle(title),
                  similarity,
                  searchTerm: `backup:${backupTerm}`
                };
              }).filter(Boolean);

              backupResults.forEach(item => {
                const existing = searchResults.get(item.threadId);
                if (!existing || item.similarity > existing.similarity) {
                  searchResults.set(item.threadId, item);
                }
              });

              console.log(`✅ 备用搜索找到 ${backupResults.length} 个结果`);

              directory = Array.from(searchResults.values())
                .filter(item => item.similarity > 0.05);

            } else {
              console.log(`❌ 备用搜索失败: ${response.status}`);
            }

          } catch (error) {
            console.warn('❌ 备用搜索失败:', error.message);
          }
        }
      }

      // 如果搜索完全失败
      if (directory.length === 0) {
        console.log('❌ 所有搜索词都未找到相关章节');
      }

      // 最后兜底:提供当前章节作为基础目录
      const currentThreadId = getCurrentThreadId();
      if (directory.length === 0 && currentThreadId) {
        console.log('🔧 提供当前章节作为基础目录');
        return [{
          threadId: currentThreadId,
          title: seriesTitle,
          originalTitle: seriesTitle,
          url: window.location.href,
          normalizedTitle: normalizeSeriesTitle(seriesTitle),
          similarity: 1.0,
          searchTerm: 'current'
        }];
      }

      return directory;

    } catch (error) {
      console.error('❌ 搜索目录失败:', error);
      console.error('错误堆栈:', error.stack);
      return [];
    }
  }



  // 提取章节号(支持小数格式和复杂排序)
function extractChapterNumber(title) {
  if (!title || typeof title !== 'string') return 0;
  // 特殊章节(番外/彩页等)放到最后
  const specialPatterns = [
    /番外|外传|特别篇|SP|特典|彩页|后记|前记|预告|PV|CM/i,
    /extra|special|omake|bonus/i
  ];
  for (const p of specialPatterns) {
    if (p.test(title)) return 99999;
  }

  const patterns = [
    { regex: /(?:第\s*)?(\d+\.\d+)\s*[话話章节節回卷篇期]?/i, priority: 1, type: 'decimal' },
    { regex: /第\s*(\d+)\s*[话話章节節回卷篇]/i, priority: 2, type: 'standard' },
    { regex: /(\d+)\s*[话話章节節]/i, priority: 3, type: 'numbered' },
    { regex: /[\[\((](\d+(?:\.\d+)?)[\]\))]/, priority: 4, type: 'bracketed' },
    { regex: /(?:第\s*)?(\d+)\s*卷/i, priority: 5, type: 'volume' },
    { regex: /\s(\d+(?:\.\d+)?)$/, priority: 6, type: 'trailing' },
    { regex: /^(\d+(?:\.\d+)?)\s/, priority: 7, type: 'leading' },
    { regex: /(\d+(?:\.\d+)?)/, priority: 8, type: 'any' }
  ];

  let bestMatch = null;
  let bestPriority = Infinity;
  for (const p of patterns) {
    const m = title.match(p.regex);
    if (m && p.priority < bestPriority) {
      bestMatch = m[1];
      bestPriority = p.priority;
    }
  }

  if (bestMatch != null) {
    if (bestMatch.includes('.')) {
      // 小数章如 9.5 -> 9500(保持整数比较)
      const v = parseFloat(bestMatch);
      if (!isNaN(v)) return Math.round(v * 1000);
    } else {
      const v = parseInt(bestMatch, 10);
      if (!isNaN(v)) return v;
    }
  }

  // 简单中文数字映射(可扩展)
  const chineseNumbers = {
    '零': 0, '一': 1, '二': 2, '三': 3, '四': 4, '五': 5,
    '六': 6, '七': 7, '八': 8, '九': 9, '十': 10,
    '十一': 11, '十二': 12, '十三': 13, '十四': 14, '十五': 15,
    '十六': 16, '十七': 17, '十八': 18, '十九': 19, '二十': 20
  };
  for (const [ch, num] of Object.entries(chineseNumbers)) {
    if (title.includes(`第${ch}`) || title.includes(`${ch}话`) || title.includes(`${ch}章`)) {
      return num;
    }
  }

  return 0;
}

function getFormHash() {
  if (isReading) {
    console.log('🔑 FormHash: 阅读模式下跳过FormHash');
    return '';
  }
  const formHashInput = document.querySelector('input[name="formhash"]');
  return formHashInput ? formHashInput.value : '';
}

  // 从URL识别帖子所属版块
  function detectForumId(url = window.location.href) {
    // 方式1: 从URL参数中提取 fid
    const fidMatch = url.match(/[?&]fid=(\d+)/);
    if (fidMatch) {
      const fid = fidMatch[1];
      console.log(`📍 从URL参数识别版块: fid=${fid}`);
      return fid;
    }

    // 方式2: 从forum.php路径中提取
    const forumMatch = url.match(/forum-(\d+)-/);
    if (forumMatch) {
      const fid = forumMatch[1];
      console.log(`📍 从forum路径识别版块: fid=${fid}`);
      return fid;
    }

    // 方式3: 从thread URL中推断(访问页面时检查页面元素)
    try {
      const breadcrumbs = document.querySelectorAll('.z a[href*="forum"]');
      const forumIds = [];

      for (const breadcrumb of breadcrumbs) {
        // 尝试从 forum-数字- 格式提取
        const breadcrumbMatch1 = breadcrumb.href.match(/forum-(\d+)-/);
        if (breadcrumbMatch1) {
          const fid = breadcrumbMatch1[1];
          const name = breadcrumb.textContent.trim();
          forumIds.push({ fid, name, element: breadcrumb });
          continue;
        }
        // 尝试从 fid= 参数提取
        const breadcrumbMatch2 = breadcrumb.href.match(/fid=(\d+)/);
        if (breadcrumbMatch2) {
          const fid = breadcrumbMatch2[1];
          const name = breadcrumb.textContent.trim();
          forumIds.push({ fid, name, element: breadcrumb });
        }
      }

      // ✨ 选择最后一个版块(最精确的子版块)
      if (forumIds.length > 0) {
        const lastForum = forumIds[forumIds.length - 1];
        console.log(`📍 从面包屑导航识别版块: fid=${lastForum.fid} (${lastForum.name})`);
        if (forumIds.length > 1) {
          console.log(`   💡 跳过了 ${forumIds.length - 1} 个父级版块,选择最精确的子版块`);
        }
        return lastForum.fid;
      }
    } catch (e) {
      console.log('⚠️ 无法从面包屑导航识别版块:', e.message);
    }

    // 方式4: 从当前页面的返回链接中提取
    try {
      const backLinks = document.querySelectorAll('a[href*="forum"]');
      for (const backLink of backLinks) {
        const linkMatch = backLink.href.match(/fid=(\d+)/);
        if (linkMatch) {
          const fid = linkMatch[1];
          console.log(`📍 从返回链接识别版块: fid=${fid}`);
          return fid;
        }
      }
    } catch (e) {
      // ignore
    }

    // 默认返回中文百合漫画区 (fid=30)
    console.log('📍 无法识别版块,默认使用中文百合漫画区 (fid=30)');
    return '30';
  }

  // 获取版块名称(用于日志显示)
  function getForumName(fid) {
    const forumNames = {
      '30': '中文百合漫画区',
      '37': '百合漫画图源区'
    };
    return forumNames[fid] || `版块${fid}`;
  }

  // 检查两个标题是否包含相似词汇
  function containsSimilarWords(title1, title2) {
    const words1 = title1.toLowerCase().split(/[\s\-_]+/).filter(w => w.length > 1);
    const words2 = title2.toLowerCase().split(/[\s\-_]+/).filter(w => w.length > 1);

    console.log(`🔍 词汇比较: "${title1}" vs "${title2}"`);
    console.log(`   词汇1: [${words1.join(', ')}]`);
    console.log(`   词汇2: [${words2.join(', ')}]`);

    let commonWords = 0;
    const matchedPairs = [];

    for (const word1 of words1) {
      for (const word2 of words2) {
        if (word1.includes(word2) || word2.includes(word1)) {
          commonWords++;
          matchedPairs.push(`"${word1}" ⟷ "${word2}"`);
          break;
        }
      }
    }

    const threshold = Math.min(2, Math.min(words1.length, words2.length));
    const isMatch = commonWords >= threshold;

    console.log(`   匹配词汇: ${matchedPairs.join(', ')}`);
    console.log(`   匹配数量: ${commonWords}/${threshold} (需要: ${threshold})`);
    console.log(`   结果: ${isMatch ? '✅ 匹配' : '❌ 不匹配'}`);

    return isMatch;
  }

  /*** 悬浮按钮 ***/
  const ioniconsModule = document.createElement('script');
  ioniconsModule.type = 'module';
  ioniconsModule.src = 'https://unpkg.com/[email protected]/dist/ionicons/ionicons.esm.js';
  document.head.appendChild(ioniconsModule);

  const ioniconsNomodule = document.createElement('script');
  ioniconsNomodule.noModule = true;
  ioniconsNomodule.src = 'https://unpkg.com/[email protected]/dist/ionicons/ionicons.js';
  document.head.appendChild(ioniconsNomodule);

  const fontLink = document.createElement('link');
  fontLink.href = 'https://fonts.googleapis.com/css2?family=Poppins&display=swap';
  fontLink.rel = 'stylesheet';
  document.head.appendChild(fontLink);

  const button = document.createElement('button');
  button.id = 'reader-toggle';
  button.innerHTML = `
    <span class="icon"><ion-icon name="book-outline"></ion-icon></span>
    <span class="title">进入阅读模式</span>
  `;

  document.body.appendChild(button);

  GM_addStyle(`
    #reader-toggle {
      position: fixed;
      top: 20%;
      right: 0px;
      transform: translateY(-50%);
      z-index: 99999;
      list-style: none;
      width: 60px;
      height: 60px;
      background: white;
      border-radius: 60px;
      box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
      cursor: pointer;
      display: flex;
      justify-content: center;
      align-items: center;
      transition: 0.5s;
      border: none;
      font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", "Source Han Sans SC", sans-serif;
    }

    #reader-toggle::before {
      content: "";
      position: absolute;
      inset: 0;
      border-radius: 40px;
      background: linear-gradient(45deg, #56CCF2, #2F80ED);
      opacity: 0;
      transition: 0.5s;
    }

    #reader-toggle::after {
      content: "";
      position: absolute;
      top: 10px;
      width: 100%;
      height: 100%;
      border-radius: 40px;
      background: linear-gradient(45deg, #56CCF2, #2F80ED);
      filter: blur(15px);
      z-index: -1;
      opacity: 0;
      transition: 0.5s;
    }

    #reader-toggle:hover {
      width: 180px;
      box-shadow: 0 10px 25px rgba(0, 0, 0, 0);
    }

    #reader-toggle:hover::before {
      opacity: 1;
    }

    #reader-toggle:hover::after {
      opacity: 0.5;
    }

    #reader-toggle .icon {
      position: absolute;
      left: 0;
      top: 0;
      width: 60px;
      height: 60px;
      color: #777;
      font-size: 2em;
      transition: 0.5s;
      transition-delay: 0.25s;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    #reader-toggle .icon ion-icon {
      width: 24px;
      height: 24px;
    }

    #reader-toggle:hover .icon {
      transform: scale(0);
      color: #fff;
      transition-delay: 0s;
    }

    #reader-toggle .title {
      position: absolute;
      color: #fff;
      font-size: 1.4em;
      text-transform: uppercase;
      letter-spacing: 0.1em;
      transform: scale(0);
      transition: 0.5s;
      transition-delay: 0s;
    }

    #reader-toggle:hover .title {
      transform: scale(1);
      transition-delay: 0.25s;
    }

    #directory-sidebar {
      position: fixed;
      top: 0;
      right: -400px;
      width: 400px;
      height: 100%;
      background: linear-gradient(145deg, #1e2837 0%, #2a3441 25%, #1f2937 50%, #374151 75%, #1e293b 100%);
      z-index: 2147483647;
      transition: right 0.3s cubic-bezier(0.4, 0, 0.2, 1);
      box-shadow: -15px 0 40px rgba(0, 0, 0, 0.4);
      display: flex;
      flex-direction: column;
      color: white;
      backdrop-filter: blur(20px);
      border: none;
    }

    #directory-sidebar.open {
      right: 0;
    }

    /* 遮罩层 */
    #directory-overlay {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: rgba(0, 0, 0, 0.6);
      z-index: 2147483646;
      opacity: 0;
      visibility: hidden;
      transition: opacity 0.3s ease, visibility 0.3s ease;
      backdrop-filter: blur(2px);
    }

    #directory-overlay.show {
      opacity: 1;
      visibility: visible;
    }

    #directory-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 10px 20px;
      background: linear-gradient(135deg, rgba(59, 130, 246, 0.15) 0%, rgba(99, 102, 241, 0.1) 100%);
      backdrop-filter: blur(15px);
      border: none;
      position: relative;
    }

    #directory-header::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      height: 1px;
      background: linear-gradient(90deg, transparent 0%, rgba(59, 130, 246, 0.4) 50%, transparent 100%);
    }

    #directory-title {
      font-size: 16px;
      font-weight: 600;
      color: white;
      letter-spacing: 0.5px;
    }

    #directory-close {
      background: rgba(255, 255, 255, 0.1);
      border: none;
      font-size: 18px;
      cursor: pointer;
      color: white;
      padding: 8px;
      border-radius: 8px;
      transition: all 0.2s ease;
      width: 36px;
      height: 36px;
      display: flex;
      align-items: center;
      justify-content: center;
      backdrop-filter: blur(10px);
    }

    #directory-close:hover {
      background: rgba(255, 255, 255, 0.2);
      transform: scale(1.05);
    }

    #directory-close:active {
      transform: scale(0.95);
    }

    #directory-content {
      flex: 1;
      overflow-y: auto;
      padding: 16px 0;
      scrollbar-width: thin;
      scrollbar-color: rgba(255, 255, 255, 0.3) transparent;
    }

    #directory-content::-webkit-scrollbar {
      width: 6px;
    }

    #directory-content::-webkit-scrollbar-track {
      background: transparent;
    }

    #directory-content::-webkit-scrollbar-thumb {
      background: rgba(255, 255, 255, 0.3);
      border-radius: 3px;
    }

    #directory-content::-webkit-scrollbar-thumb:hover {
      background: rgba(255, 255, 255, 0.5);
    }

    #directory-list {
      list-style: none;
      padding: 0 16px;
      margin: 0;
    }

    .directory-item {
      display: block;
      padding: 14px 16px;
      margin: 0 0 8px 0;
      background: linear-gradient(135deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.04) 100%);
      border: none;
      border-radius: 12px;
      text-decoration: none !important;
      color: rgba(255, 255, 255, 0.9);
      transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
      cursor: pointer;
      font-size: 14px;
      font-weight: 500;
      backdrop-filter: blur(10px);
      position: relative;
      overflow: hidden;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    }

    .directory-item::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.1), transparent);
      transform: translateX(-100%);
      transition: transform 0.6s;
    }

    .directory-item:hover::before {
      transform: translateX(100%);
    }

    .directory-item:hover {
      background: rgba(255, 255, 255, 0.15);
      transform: translateX(6px);
      color: white;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
    }

    .directory-item.current {
      background: linear-gradient(135deg, #FF6B6B, #FF8E53);
      color: white;
      box-shadow: 0 4px 15px rgba(255, 107, 107, 0.3);
      font-weight: 600;
    }

    .directory-item.current:hover {
      transform: translateX(6px) scale(1.02);
      box-shadow: 0 6px 20px rgba(255, 107, 107, 0.4);
    }

    .directory-item.mainpost {
      background: linear-gradient(135deg, #4CAF50, #45a049);
      color: white;
    }

    .directory-item.mainpost:hover {
      background: linear-gradient(135deg, #45a049, #3d8b40);
    }

    #directory-loading {
      text-align: center;
      padding: 60px 20px;
      color: rgba(255, 255, 255, 0.7);
      font-size: 16px;
      font-weight: 500;
    }

    #directory-loading::before {
      content: '📚';
      display: block;
      font-size: 32px;
      margin-bottom: 16px;
      animation: pulse 2s infinite;
    }

    @keyframes pulse {
      0%, 100% { opacity: 0.7; }
      50% { opacity: 1; }
    }

    #directory-empty {
      text-align: center;
      padding: 60px 20px;
      color: rgba(255, 255, 255, 0.6);
      font-size: 16px;
    }

    #directory-empty::before {
      content: '📖';
      display: block;
      font-size: 32px;
      margin-bottom: 16px;
      opacity: 0.6;
    }

    /* 目录侧边栏的tooltip样式 */
    #directory-sidebar [data-tooltip]:hover::after {
      content: attr(data-tooltip);
      position: absolute;
      bottom: 100%;
      left: 50%;
      transform: translateX(-50%);
      background: rgba(0, 0, 0, 0.6);
      color: white;
      padding: 8px 12px;
      border-radius: 6px;
      font-size: 12px;
      white-space: nowrap;
      z-index: 2147483650;
      pointer-events: none;
      margin-bottom: 8px;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
      opacity: 0;
      animation: tooltipFadeIn 0.2s ease forwards;
    }

    #directory-sidebar [data-tooltip]:hover::before {
      content: '';
      position: absolute;
      bottom: 100%;
      left: 50%;
      transform: translateX(-50%);
      border: 6px solid transparent;
      border-top-color: rgba(0, 0, 0, 0.6);
      z-index: 2147483650;
      pointer-events: none;
      margin-bottom: 2px;
      opacity: 0;
      animation: tooltipFadeIn 0.2s ease forwards;
    }
  `);

  // 添加快捷键:Ctrl+Shift+R 切换阅读模式
  document.addEventListener('keydown', e => {
    if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() === 'r') {
      e.preventDefault();
      if (!isReading) enterReader();
      else exitReader();
    }
  });

  button.addEventListener('click', () => {
    if (!isReading) {
      enterReader();
      setAutoReaderStatus(true); // 开启全局阅读器模式
    } else {
      exitReader();
    }
  });





  /*** 目录功能 ***/
  async function showDirectoryModal() {
    // 创建遮罩层
    const overlay = document.createElement('div');
    overlay.id = 'directory-overlay';

    // 创建侧边栏
    const sidebar = document.createElement('div');
    sidebar.id = 'directory-sidebar';
    sidebar.innerHTML = `
      <div id="directory-header">
        <div id="directory-title">目录</div>
        <button id="directory-close">×</button>
      </div>
      <div id="directory-content">
        <div id="directory-loading">正在搜索相关章节...</div>
        <ul id="directory-list" style="display: none;"></ul>
        <div id="directory-empty" style="display: none;">未找到相关章节</div>
      </div>
    `;

    document.body.appendChild(overlay);
    document.body.appendChild(sidebar);

    // 显示遮罩和侧边栏
    setTimeout(() => {
      overlay.classList.add('show');
      sidebar.classList.add('open');
    }, 10);

    // 关闭按钮事件
    const closeBtn = sidebar.querySelector('#directory-close');
    closeBtn.addEventListener('click', closeSidebar);

    // 点击遮罩关闭
    overlay.addEventListener('click', closeSidebar);

    function closeSidebar() {
      overlay.classList.remove('show');
      sidebar.classList.remove('open');

      setTimeout(() => {
        overlay.remove();
        sidebar.remove();
      }, 300);
    }

    // 开始搜索目录
    loadSeriesDirectory(sidebar);
  }

  async function loadSeriesDirectory(modal) {
    console.log('📖 开始加载系列目录...');

    // 如果已有预加载的目录,直接使用
    if (seriesDirectory.length > 0) {
      console.log('✅ 使用预加载的目录:', seriesDirectory.length, '个章节');
      displayDirectory(modal, seriesDirectory);
      return;
    }

    // 如果预加载目录为空,先检查持久化缓存
    if (originalSeriesTitle || savedThreadTitle) {
      const titleToCheck = originalSeriesTitle || savedThreadTitle;
      const seriesKey = generateSeriesKey(titleToCheck);
      const cachedDirectory = getCachedDirectory(seriesKey);
      if (cachedDirectory && cachedDirectory.length > 0) {
        console.log('✅ 从持久化缓存加载目录:', cachedDirectory.length, '个章节');
        seriesDirectory = cachedDirectory;
        displayDirectory(modal, seriesDirectory);
        return;
      }
    }

    // 尝试多种方式获取页面标题
    let titleElement = null;
    let threadTitle = '';

    console.log('🔍 尝试查找页面标题...');

    // 简化标题提取逻辑
    const h1Element = document.querySelector('h1.ts');
    if (h1Element) {
      const subjectSpan = h1Element.querySelector('#thread_subject, span[id^="thread_subject"]');
      if (subjectSpan) {
        threadTitle = subjectSpan.textContent.trim();
        console.log(`✅ 找到标题: "${threadTitle}"`);
      } else {
        threadTitle = h1Element.textContent.trim();
        console.log(`✅ 找到h1文本: "${threadTitle}"`);
      }
    } else {
      // 兜底:使用原有逻辑
      const titleSelectors = [
        '#thread_subject',
        'span[id^="thread_subject"]',
        '.ts a',
        'h1.ts',
        '.ntn a',
        '.ntn',
        '.bm .mbm h1',
        '.ts'
      ];

      for (const selector of titleSelectors) {
        titleElement = document.querySelector(selector);
        if (titleElement) {
          threadTitle = titleElement.textContent.trim();
          console.log(`✅ 找到标题元素: "${selector}" -> "${threadTitle}"`);
          break;
        } else {
          console.log(`❌ 未找到: "${selector}"`);
        }
      }
    }

    // 在阅读模式下,优先使用原始系列标题进行目录搜索(避免使用错误的标题)
    if (isReading) {
      if (originalSeriesTitle) {
        threadTitle = originalSeriesTitle;
        console.log('🎯 阅读模式下使用原始系列标题:', threadTitle);
      } else if (savedThreadTitle) {
        threadTitle = savedThreadTitle;
        console.log('📦 阅读模式下使用预存标题:', threadTitle);
      }
    } else if (!threadTitle && originalSeriesTitle) {
      threadTitle = originalSeriesTitle;
      console.log('🎯 使用原始系列标题:', threadTitle);
    } else if (!threadTitle && savedThreadTitle) {
      threadTitle = savedThreadTitle;
      console.log('📦 使用预存标题:', threadTitle);
    }
    // 如果还是没找到,尝试从页面title获取
    if (!threadTitle) {
      const pageTitle = document.title;
      console.log('🔍 尝试从页面title获取:', pageTitle);

      // 移除论坛名称等后缀,只保留漫画标题部分
      if (pageTitle.includes(' - ')) {
        threadTitle = pageTitle.split(' - ')[0].trim();
        console.log('📝 从页面title提取:', threadTitle);
      } else {
        threadTitle = pageTitle.replace(/\s*-\s*百合会.*$/, '').trim();
        console.log('📝 清理后的标题:', threadTitle);
      }
    }

    const currentThreadId = getCurrentThreadId();

    console.log('📋 当前页面信息:');
    console.log('   标题元素:', titleElement ? '✅ 找到' : '❌ 未找到');
    console.log('   页面标题:', threadTitle);
    console.log('   线程ID:', currentThreadId);

    // 调试:打印页面中所有可能的标题元素
    if (!titleElement) {
      console.log('🔍 调试:查找所有可能的标题元素...');

      const allH1 = document.querySelectorAll('h1');
      const allSpans = document.querySelectorAll('span[id*="thread"], span[id*="subject"]');
      const allTs = document.querySelectorAll('.ts, .ntn');

      console.log('  - h1元素数量:', allH1.length);
      allH1.forEach((h1, index) => {
        if (index < 5) {
          console.log(`    h1[${index}]: "${h1.textContent.trim().substring(0, 50)}" (class: ${h1.className})`);
        }
      });

      console.log('  - 包含thread/subject的span数量:', allSpans.length);
      allSpans.forEach((span, index) => {
        if (index < 5) {
          console.log(`    span[${index}]: id="${span.id}", text="${span.textContent.trim().substring(0, 50)}"`);
        }
      });

      console.log('  - .ts/.ntn元素数量:', allTs.length);
      allTs.forEach((ts, index) => {
        if (index < 5) {
          console.log(`    ts[${index}]: class="${ts.className}", text="${ts.textContent.trim().substring(0, 50)}"`);
        }
      });
    }

    if (!threadTitle) {
      console.log('❌ 页面标题为空,显示空状态');
      showDirectoryEmpty(modal);
      return;
    }

    try {
      console.log('🔍 开始搜索目录...');
      const directory = await searchSeriesDirectory(threadTitle);

      console.log('📊 搜索结果:', directory.length, '个章节');

      if (directory.length === 0) {
        console.log('❌ 未找到章节,显示空状态');
        showDirectoryEmpty(modal);
        return;
      }

      console.log('✅ 找到章节,开始显示目录界面');
      displayDirectory(modal, directory, threadTitle);

    } catch (error) {
      console.error('❌ 加载目录失败:', error);
      console.error('错误详情:', error.message);
      console.error('错误堆栈:', error.stack);
      showDirectoryEmpty(modal, '加载失败,请稍后重试');
    }
  }

  function displayDirectory(modal, directory, threadTitle = '') {
    // 显示目录
    const loading = modal.querySelector('#directory-loading');
    const list = modal.querySelector('#directory-list');
    const title = modal.querySelector('#directory-title');

    loading.style.display = 'none';
    list.style.display = 'block';

    // 获取页面标题(如果没有提供)
    if (!threadTitle) {
     if (savedThreadTitle) {
       threadTitle = savedThreadTitle;
     } else {
        threadTitle = document.title.split(' - ')[0] || '漫画目录';
     }
    }

    // 简化标题,只显示"目录"
    title.textContent = '目录';

    console.log('📝 目录标题: 目录');

    list.innerHTML = '';

    const currentThreadId = getCurrentThreadId();

    directory.forEach((item, index) => {
      const li = document.createElement('li');
      const link = document.createElement('a');
      link.className = 'directory-item';
      if (item.source === 'mainpost') {
        link.classList.add('mainpost');
      }

      link.href = item.url;

      // 为主楼提取的目录优化显示格式
      if (item.source === 'mainpost') {
        let displayText = item.title;

        // 识别不同的章节格式并优化显示
        if (item.title.match(/^\d{1,2}$/)) {
          displayText = `第${String(item.title).padStart(2, '0')}话`;
        } else if (item.title.match(/^\d+\.\d+$/)) {
          displayText = `第${item.title}话`;
        } else if (item.title.match(/^\d+[话話章节節回卷篇]/i)) {
          displayText = item.title;
        } else if (item.title.match(/卷|番外|彩页|特典/i)) {
          displayText = item.title;
        } else if (item.title.match(/^0\d+$/)) {
          displayText = `第${item.title}话`;
        }

        link.textContent = displayText;
      } else {
        link.textContent = item.title;
      }

      // 添加点击事件处理,无缝加载新章节内容
      link.addEventListener('click', async (e) => {
        e.preventDefault();
        console.log('🔄 正在加载章节:', item.title);

        // 关闭侧边栏
        const overlay = document.getElementById('directory-overlay');
        const sidebar = document.getElementById('directory-sidebar');
        if (overlay && sidebar) {
          overlay.classList.remove('show');
          sidebar.classList.remove('open');
          setTimeout(() => {
            overlay.remove();
            sidebar.remove();
          }, 300);
        }

        // 无缝加载新章节内容
        await loadNewChapter(item.url, item.title);
      });

      // 高亮当前章节
      if (item.threadId === currentThreadId) {
        link.classList.add('current');
        console.log(`⭐ 当前章节: ${item.title}`);
      }

      li.appendChild(link);
      list.appendChild(li);

      console.log(`📄 章节 ${index + 1}: ${item.title}`);
    });

    console.log('✅ 目录界面显示完成');
  }

  function showDirectoryEmpty(modal, message = '未找到相关章节') {
    const loading = modal.querySelector('#directory-loading');
    const empty = modal.querySelector('#directory-empty');

    loading.style.display = 'none';
    empty.style.display = 'block';
    empty.textContent = message;
  }

  function getCurrentThreadId() {
    const href = window.location.href;
    let match = href.match(/thread-(\d+)-/);
    if (match) {
      return match[1];
    }

    try {
      const url = new URL(href);
      const tidParam = url.searchParams.get('tid');
      if (tidParam) {
        return tidParam;
      }
    } catch (e) {
      // ignore
    }

    match = href.match(/[?&]tid=(\d+)/);
    return match ? match[1] : null;
  }

  // 清理所有缓存,并清空内存缓存
  function clearAllCache() {
    console.log('🧹 清理所有目录缓存 (session + GM) ...');
    let cleanedCount = 0;

    // 1) 清理 sessionStorage 前缀条目
    try {
      const sKeys = Object.keys(sessionStorage).filter(k => k.startsWith(CACHE_PREFIX));
      sKeys.forEach(k => {
        try { sessionStorage.removeItem(k); cleanedCount++; } catch (e) {}
      });
    } catch (e) {
    }

    // 2) 清理 GM_* 条目(通过索引枚举)
    try {
      if (typeof GM_getValue === 'function' && typeof GM_setValue === 'function') {
        let idx = GM_getValue(GM_INDEX_KEY, undefined);
        if (typeof idx === 'string') {
          try { idx = JSON.parse(idx); } catch (e) { idx = []; }
        }
        if (!Array.isArray(idx)) idx = [];

        for (const key of idx) {
          try { storageRemove(key); cleanedCount++; } catch (e) {}
        }

        try { GM_setValue(GM_INDEX_KEY, []); } catch (e) {}
      }
    } catch (e) {
    }

    // 3) 清理内存缓存
    try { if (searchCache && searchCache.clear) searchCache.clear(); } catch (e) {}
    try { if (directoryMemoryCache && directoryMemoryCache.clear) directoryMemoryCache.clear(); } catch (e) {}

    console.log(`✅ 已清理 ${cleanedCount} 个持久化缓存条目,且已清空内存缓存`);
    return cleanedCount;
  }

  // 查看缓存状态(session + GM 索引 + 内存统计)
  function viewCacheStatus() {
    console.log('📊 缓存状态统计:');

    // sessionStorage 条目
    let sessionList = [];
    try {
      sessionList = Object.keys(sessionStorage).filter(k => k.startsWith(CACHE_PREFIX));
    } catch (e) { sessionList = []; }

    // GM 索引条目
    let gmList = [];
    try {
      if (typeof GM_getValue === 'function') {
        let idx = GM_getValue(GM_INDEX_KEY, undefined);
        if (typeof idx === 'string') {
          try { idx = JSON.parse(idx); } catch (e) { idx = []; }
        }
        if (Array.isArray(idx)) gmList = idx.slice();
      }
    } catch (e) { gmList = []; }

    console.log(`📦 sessionStorage 缓存数量: ${sessionList.length}`);
    console.log(`📦 GM_* 缓存数量 (index): ${gmList.length}`);
    console.log(`🧠 内存缓存 (searchCache): ${typeof searchCache !== 'undefined' && searchCache.size !== undefined ? searchCache.size : '未知'}`);
    console.log(`🧠 内存目录缓存 (directoryMemoryCache): ${typeof directoryMemoryCache !== 'undefined' && directoryMemoryCache.size !== undefined ? directoryMemoryCache.size : '未知'}`);

    if (sessionList.length > 0) {
      console.log('\n📋 sessionStorage 详情:');
      sessionList.forEach((k, i) => {
        try {
          const obj = JSON.parse(sessionStorage.getItem(k));
          const age = Math.round((Date.now() - (obj.ts || obj.timestamp || 0)) / (1000*60*60));
          const count = (obj.d || obj.data) ? (obj.d || obj.data).length : '未知';
          console.log(`   ${i+1}. ${k.replace(CACHE_PREFIX+'session-','')}: ${count}章, ${age}小时前`);
        } catch (e) {
          console.log(`   ${i+1}. ${k} (无法解析)`);
        }
      });
    }

    if (gmList.length > 0) {
      console.log('\n📋 GM_* 详情 (由索引列出):');
      gmList.forEach((k, i) => {
        try {
          const obj = storageGet(k, null);
          const age = obj ? Math.round((Date.now() - (obj.ts || obj.timestamp || 0)) / (1000*60*60)) : '未知';
          const count = obj ? ((obj.d || obj.data) ? (obj.d || obj.data).length : '未知') : '未知';
          console.log(`   ${i+1}. ${k.replace(CACHE_PREFIX,'')}: ${count}章, ${age}小时前`);
        } catch (e) {
          console.log(`   ${i+1}. ${k} (无法读取)`);
        }
      });
    }

    return {
      sessionCount: sessionList.length,
      gmCount: gmList.length,
      memorySearchCount: typeof searchCache !== 'undefined' && searchCache.size !== undefined ? searchCache.size : null,
      memoryDirCount: typeof directoryMemoryCache !== 'undefined' && directoryMemoryCache.size !== undefined ? directoryMemoryCache.size : null
    };
  }

// 必须识别作者 UID,按楼层顺序收集该作者的图片;识别失败直接返回空数组,避免全页搜索
function collectImagesFromDocument(doc = document) {
  try {
    const normalizeUrl = u => {
      if (!u) return null;
      u = String(u).trim();
      if (!u) return null;
      if (u.startsWith('//')) u = (location.protocol || 'https:') + u;
      if (!/^https?:\/\//i.test(u)) u = 'https://bbs.yamibo.com/' + u.replace(/^\/+/, '');
      u = u.replace(/^https?:\/\/https?:\/\//, 'https://');
      return u;
    };

    const isPlaceholder = (img, src) => {
      if (!src) return true;
      if (src.includes('static/image/common/none.gif')) {
        if (img.getAttribute('file') || img.getAttribute('zoomfile') || img.getAttribute('aid')) return false;
        return true;
      }
      return false;
    };

    // 识别并忽略头像/评分用户小图等噪音图片
    const isIgnoredImage = (img, src) => {
      try {
        if (!src && !img) return true;
        const s = String(src || '').toLowerCase();

        // 明确的头像路径(示例:/uc_server/data/avatar/...)
        if (/\/uc_server\/data\/avatar\//i.test(s)) return true;

        // 常见 avatar 文件名 / avatar_small
        if (/avatar(?:_small|_middle)?\.(jpg|jpeg|png|gif|webp)$/i.test(s)) return true;
        if (s.includes('/avatar/') || s.includes('/avatars/')) return true;

        // class 名称包含 avatar 或 user_avatar 等
        const cls = (img && img.className) ? String(img.className).toLowerCase() : '';
        if (cls.includes('user_avatar') || cls.includes('avatar') || cls.includes('userpic') || cls.includes('authoravatar')) return true;

        // 如果图片位于明显的评分/头像容器,忽略
        if (img && (img.closest('.postrate') || img.closest('.post-ratings') || img.closest('.postratedby') || img.closest('.poster') || img.closest('.author') || img.closest('.avatar') || img.closest('.user')) ) {
          return true;
        }

        // 若图片尺寸非常小(通常为头像),忽略阈值可调整
        const wAttr = img && (img.getAttribute('width') || img.width);
        const hAttr = img && (img.getAttribute('height') || img.height);
        const w = wAttr ? parseInt(wAttr, 10) : 0;
        const h = hAttr ? parseInt(hAttr, 10) : 0;
        if ((w > 0 && w < 80) || (h > 0 && h < 80)) return true;

        // 若 src 含有明显的评分/头像关键词
        if (s.includes('rating') || s.includes('score') || s.includes('grade') || s.includes('usericon')) return true;

        return false;
      } catch (e) {
        return false;
      }
    };

    const preferredSelectors = [
      'ignore_js_op img',
      '.savephotop img',
      'div.t_f img',
      'td.t_f img',
      '.pcb img',
      'img[zoomfile]',
      'img[file]',
      'img[aid]',
      'img.zoom',
      'img'
    ];

    // 定位主楼容器,尝试从中识别作者 UID
    let mainPost = null;
    try {
      const posts = doc.querySelectorAll('[id^="post_"], .post');
      if (posts && posts.length) {
        for (const p of posts) {
          if (p.id && /^post_\d+/.test(p.id)) { mainPost = p; break; }
        }
        if (!mainPost) mainPost = posts[0];
      }
    } catch (e) { mainPost = null; }

    // 必须识别作者 UID,否则直接返回空数组(避免全页抓取)
    let authorUid = null;
    if (mainPost) {
      try {
        const a = mainPost.querySelector('a[href*="space-uid-"], a[href*="uid="], a[href*="space.php?uid="]');
        if (a && a.getAttribute('href')) {
          const href = a.getAttribute('href');
          const m1 = href.match(/space-uid-(\d+)\.html/);
          const m2 = href.match(/uid=(\d+)/);
          if (m1) authorUid = m1[1];
          else if (m2) authorUid = m2[1];
        }
      } catch (e) { authorUid = null; }
    }

    if (!authorUid) {
      console.log('⚠️ collectImagesFromDocument: 无法识别作者 UID,跳过图片收集');
      return [];
    }

    const seen = new Set();
    const results = [];

    // 遍历所有 post_* 楼层,按文档顺序只收集该作者的图片
    const postsAll = Array.from(doc.querySelectorAll('[id^="post_"]'));
    for (const p of postsAll) {
      try {
        const authorLink = p.querySelector(`a[href*="space-uid-${authorUid}"], a[href*="uid=${authorUid}"], a[href*="space.php?uid=${authorUid}"]`);
        if (!authorLink) continue; // 非楼主发言,跳过

for (const sel of preferredSelectors) {
  const imgs = p.querySelectorAll(sel);
  for (const img of imgs) {
    const u = normalizeUrl(
      img.getAttribute('zoomfile') ||
      img.getAttribute('file') ||
      img.getAttribute('src') ||
      img.getAttribute('data-src')
    );
    if (!u) continue;
    if (isIgnoredImage(img, u)) continue;
    if (!seen.has(u)) { seen.add(u); results.push(u); }
  }
}
      } catch (e) {
        continue;
      }
    }

    return results;
  } catch (e) {
    console.warn('collectImagesFromDocument error', e);
    return [];
  }
}


  // 初始化时检查全局阅读器状态
  function initAutoReader() {
    autoReaderEnabled = checkAutoReaderStatus();
    console.log('🚀 初始化全局阅读器状态:', autoReaderEnabled);

    // 清理过期缓存
    cleanExpiredCache();

    // 检查是否有漫画内容,优先检测主楼
    const comicImages = collectImagesFromDocument(document);
    if (comicImages && comicImages.length > 0) {
      console.log('🎯 检测到漫画内容,立即开始预取目录...');

      // 立即开始预取目录信息,不管是否进入阅读模式
      preloadDirectoryInfo();

      // 如果全局阅读器开启,自动进入阅读模式
      if (autoReaderEnabled && !isReading) {
        console.log('🎯 自动进入阅读模式');
        setTimeout(() => {
          if (button && button.parentNode) {
            button.remove();
          }
          enterReader();
        }, 1000);
      }
    } else {
      console.log('🔍 尝试预取目录信息...');
      preloadDirectoryInfo();
    }
  }
  // 预加载目录信息
  async function preloadDirectoryInfo() {
    if (seriesDirectory.length > 0) {
      console.log('� 目录已预加载,跳过重复加载');
      return;
    }

    try {
      console.log('�📚 开始预加载目录信息...');

      // 获取当前页面标题
      let threadTitle = '';
      const h1Element = document.querySelector('h1.ts');
      if (h1Element) {
        const subjectSpan = h1Element.querySelector('#thread_subject, span[id^="thread_subject"]');
        if (subjectSpan) {
          threadTitle = subjectSpan.textContent.trim();
        } else {
          threadTitle = h1Element.textContent.trim();
        }
      } else {
        const titleElement = document.querySelector('#thread_subject, span[id^="thread_subject"]');
        if (titleElement) {
          threadTitle = titleElement.textContent.trim();
        } else {
          const pageTitle = document.title;
          threadTitle = pageTitle.includes(' - ') ? pageTitle.split(' - ')[0].trim() : pageTitle.replace(/\s*-\s*百合会.*$/, '').trim();
        }
      }

      if (threadTitle) {
        // 保存标题信息
        savedThreadTitle = threadTitle;
        originalSeriesTitle = threadTitle;

        console.log('📖 开始预取目录,使用标题:', threadTitle);

        // 先检查持久化缓存
        const seriesKey = generateSeriesKey(threadTitle);
        const cachedDirectory = getCachedDirectory(seriesKey);
        if (cachedDirectory && cachedDirectory.length > 0) {
          console.log('✅ 从持久化缓存预加载完成:', cachedDirectory.length, '个章节');
          seriesDirectory = cachedDirectory;
          return;
        }

        // 如果没有缓存,立即开始异步搜索目录
        searchSeriesDirectory(threadTitle).then(directory => {
          if (directory && directory.length > 0) {
            seriesDirectory = directory;
            console.log('✅ 预加载完成,获得', directory.length, '个章节');
          } else {
            console.log('⚠️ 预加载未找到目录');
          }
        }).catch(error => {
          console.warn('⚠️ 预加载目录失败:', error.message);
        });

        console.log('🚀 预加载任务已启动,后台进行中...');
      } else {
        console.log('⚠️ 无法获取页面标题,跳过预加载');
      }
    } catch (error) {
      console.warn('⚠️ 预加载目录失败:', error.message);
    }
  }

  // 页面加载完成后初始化
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', () => {
      setTimeout(initAutoReader, 1000); // 确保页面元素完全加载
    });
  } else {
    setTimeout(initAutoReader, 1000); // 给页面充足时间渲染
  }

  /*** 进入阅读模式 ***/
  function enterReader() {
    isReading = true;

    // 保存原始页面HTML和标题
    originalPageHTML = document.body.innerHTML;
    originalPageTitle = document.title;
    console.log('💾 已保存原始页面内容');

    button.remove();

    // 在替换页面内容之前,先提取并保存标题
    console.log('🔍 进入阅读模式,保存页面标题...');

    // 简化标题提取逻辑
    const h1Element = document.querySelector('h1.ts');
    if (h1Element) {
      const subjectSpan = h1Element.querySelector('#thread_subject, span[id^="thread_subject"]');
      if (subjectSpan) {
        savedThreadTitle = subjectSpan.textContent.trim();
        console.log('💾 保存标题:', savedThreadTitle);
      } else {
        savedThreadTitle = h1Element.textContent.trim();
        console.log('💾 保存h1文本:', savedThreadTitle);
      }
    } else {
      // 兜底:尝试其他方式
      const threadTitleElement = document.querySelector('#thread_subject, span[id^="thread_subject"]');
      if (threadTitleElement) {
        savedThreadTitle = threadTitleElement.textContent.trim();
        console.log('💾 保存标题元素:', savedThreadTitle);
      } else {
        // 最后兜底用<title>
        const pageTitle = document.title;
        savedThreadTitle = pageTitle.includes(' - ')
          ? pageTitle.split(' - ')[0].trim()
          : pageTitle.replace(/\s*-\s*百合会.*$/, '').trim();
        console.log('💾 从页面title保存:', savedThreadTitle);
      }
    }

    // 保存原始系列标题,用于后续目录搜索
    originalSeriesTitle = savedThreadTitle;
    console.log('🎯 保存原始系列标题:', originalSeriesTitle);

    // 检查是否已有预加载的目录数据
    if (seriesDirectory.length > 0) {
      console.log('✅ 使用预加载的目录数据:', seriesDirectory.length, '个章节');
    } else {
      // 检查持久化缓存
      const seriesKey = generateSeriesKey(savedThreadTitle);
      const cachedDirectory = getCachedDirectory(seriesKey);
      if (cachedDirectory && cachedDirectory.length > 0) {
        console.log('📦 从持久化缓存加载目录:', cachedDirectory.length, '个章节');
        seriesDirectory = cachedDirectory;
      } else {
        // 缓存也没有,异步搜索
        console.log('🔍 开始异步搜索目录...');
        searchSeriesDirectory(savedThreadTitle).then(directory => {
          seriesDirectory = directory;
          console.log('📋 异步获取到目录:', seriesDirectory.length, '个章节');
        }).catch(error => {
          console.error('❌ 异步获取目录失败:', error);
        });
      }
    }

    // 提取漫画图片
    images = collectImagesFromDocument(document)
      .map(u => {
        if (!u) return null;
        let url = String(u);
        if (url.startsWith('//')) url = 'https:' + url;
        if (!/^https?:\/\//i.test(url)) url = 'https://bbs.yamibo.com/' + url.replace(/^\/+/, '');
        if (url.startsWith('http://')) url = url.replace(/^http:\/\//, 'https://');
        url = url.replace(/^https?:\/\/https?:\/\//, 'https://');
        return url;
      })
      .filter(Boolean);

    console.log('📸 提取到', images.length, '张图片,URL已处理为HTTPS');

    document.body.innerHTML = `
      <button id="cw-exit" data-tooltip="退出阅读模式">⏻</button>
      <div id="cw-toolbar">
        <button id="cw-directory" data-tooltip="查看目录 (M)">☰</button>
        <button id="cw-full" data-tooltip="全屏模式 (F)">⛶</button>
        <button id="cw-bg" data-tooltip="切换背景色 (B)">◐</button>
        <div id="cw-zoom">
          <button id="cw-zoom-in" data-tooltip="放大图片 (+)">﹢</button>
          <button id="cw-zoom-out" data-tooltip="缩小图片 (-)">﹣</button>
        </div>
      </div>
      <div id="cw-container"></div>
      <div id="cw-bottom-bar">
        <span id="cw-page-info">1/${images.length}</span>
        <button id="cw-to-top" data-tooltip="返回顶部 (T)">⬆</button>
      </div>
    `;

    GM_addStyle(`
      html, body {
        margin: 0;
        padding: 0;
        background: #616161;
        overflow-y: auto;
        color: #fff;
        font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", "Source Han Sans SC", sans-serif !important;
      }

      /* 容器样式:负责整体布局 */
      #cw-container {
        display: flex !important;
        flex-direction: column !important;
        align-items: center !important;
        justify-content: flex-start !important;
        padding: 70px 0 60px !important;
        gap: 20px !important;
        margin: 0 auto !important;
      }

      /* 图片基础样式 */
      #cw-container img {
        display: block !important;
        width: var(--img-width, 35vw) !important; /* 使用CSS变量控制宽度 */
        height: auto !important;
        border-radius: 0 !important;
        user-select: none !important;
        transition: all 0.3s ease !important;
        margin: 0 auto !important;
      }

      /* 小图保持原始大小 */
      #cw-container img[data-original-size="small"] {
        width: auto !important;
        max-width: var(--img-width, 35vw) !important;
      }

      #cw-exit {
        position: fixed;
        top: 15px;
        left: 20px;
        z-index: 2147483647;
        background: rgba(0,0,0,0.6);
        color: #fff;
        border: none;
        padding: 6px 10px;
        border-radius: 5px;
        cursor: pointer;
        font-size: 14px;
      }

      #cw-toolbar {
        position: fixed;
        top: 15px;
        right: 20px;
        display: flex;
        flex-direction: column;
        gap: 10px;
        z-index: 2147483647;
        pointer-events: auto;
      }

      #cw-toolbar button {
        background: rgba(0,0,0,0.6);
        color: #fff;
        border: none;
        padding: 6px;
        width: 32px;
        height: 32px;
        border-radius: 5px;
        cursor: pointer;
        font-size: 14px;
        transition: background-color 0.2s;
        display: flex;
        align-items: center;
        justify-content: center;
      }

      #cw-toolbar button:hover {
        background: rgba(0,0,0,0.8);
        transform: scale(1.05);
      }

      #cw-toolbar button:active {
        transform: scale(0.95);
      }

      /* 放大缩小按钮的特殊样式 */
      #cw-zoom {
        display: flex;
        flex-direction: column;
        gap: 5px;
      }

      #cw-zoom-in,
      #cw-zoom-out {
        color: white !important;
        font-size: 20px !important;
        font-weight: bold !important;
      }

      /* ESC按钮的特殊样式 */
      #cw-full[data-fullscreen="true"] {
        font-size: 24px !important;
        line-height: 16px !important;
        padding: 6px 10px !important;
      }

      /* 底部工具栏 */
      #cw-bottom-bar {
        position: fixed;
        bottom: 15px;
        right: 20px;
        display: flex;
        align-items: center;
        gap: 15px;
        z-index: 2147483647;
        pointer-events: auto;
        background: rgba(0,0,0,0.6);
        padding: 8px 12px;
        border-radius: 5px;
        font-size: 14px;
      }

      #cw-bottom-bar button {
        background: rgba(255,255,255,0.2);
        color: #fff;
        border: none;
        padding: 4px 8px;
        border-radius: 3px;
        cursor: pointer;
        font-size: 12px;
      }
      #cw-bottom-bar button:hover {
        background: rgba(255,255,255,0.3);
      }

      #cw-page-info {
        color: #fff;
        font-weight: bold;
      }

      /* 全屏状态下的基础样式 */
      :fullscreen #cw-toolbar,
      :-webkit-full-screen #cw-toolbar,
      :fullscreen #cw-bottom-bar,
      :-webkit-full-screen #cw-bottom-bar,
      :fullscreen #cw-exit,
      :-webkit-full-screen #cw-exit {
        display: flex !important;
        position: fixed !important;
        z-index: 2147483647 !important;
        transition: all 0.3s ease !important;
        opacity: 0 !important;
        pointer-events: none !important;
      }

      /* 鼠标移动时显示工具栏 */
      :fullscreen.tools-visible #cw-toolbar,
      :-webkit-full-screen.tools-visible #cw-toolbar,
      :fullscreen.tools-visible #cw-bottom-bar,
      :-webkit-full-screen.tools-visible #cw-bottom-bar,
      :fullscreen.tools-visible #cw-exit,
      :-webkit-full-screen.tools-visible #cw-exit {
        opacity: 1 !important;
        pointer-events: auto !important;
      }

      :fullscreen #cw-toolbar,
      :-webkit-full-screen #cw-toolbar {
        top: 15px !important;
        right: 20px !important;
      }

      :fullscreen #cw-bottom-bar,
      :-webkit-full-screen #cw-bottom-bar {
        bottom: 15px !important;
        right: 20px !important;
      }

      /* 确保全屏状态下按钮样式保持一致 */
      :fullscreen #cw-toolbar button:not(#cw-zoom-in):not(#cw-zoom-out),
      :-webkit-full-screen #cw-toolbar button:not(#cw-zoom-in):not(#cw-zoom-out) {
        padding: 6px !important;
        width: 32px !important;
        height: 32px !important;
        font-size: 14px !important;
        line-height: 16px !important;
        display: flex !important;
        align-items: center !important;
        justify-content: center !important;
      }

      /* 全屏状态下的缩放按钮样式 */
      :fullscreen #cw-zoom-in,
      :fullscreen #cw-zoom-out,
      :-webkit-full-screen #cw-zoom-in,
      :-webkit-full-screen #cw-zoom-out {
        padding: 6px !important;
        width: 32px !important;
        height: 32px !important;
        font-size: 18px !important;
        line-height: 16px !important;
        color: #ffffff !important;
      }

      /* ESC 符号单独设置大小 */
      :fullscreen #cw-full[data-fullscreen="true"],
      :-webkit-full-screen #cw-full[data-fullscreen="true"] {
        font-size: 24px !important;
      }

      /* 自定义tooltip样式,禁用原生tooltip */
      [data-tooltip] {
        position: relative;
      }

      [data-tooltip]:hover::after {
        content: attr(data-tooltip);
        position: absolute;
        left: 50%;
        transform: translateX(-50%);
        background: rgba(0, 0, 0, 0.9);
        color: white;
        padding: 8px 12px;
        border-radius: 6px;
        font-size: 12px;
        white-space: nowrap;
        z-index: 2147483648;
        pointer-events: none;
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
        opacity: 0;
        animation: tooltipFadeIn 0.2s ease forwards;
      }

      [data-tooltip]:hover::before {
        content: '';
        position: absolute;
        left: 50%;
        transform: translateX(-50%);
        border: 6px solid transparent;
        border-top-color: rgba(0, 0, 0, 0.9);
        z-index: 2147483648;
        pointer-events: none;
        opacity: 0;
        animation: tooltipFadeIn 0.2s ease forwards;
      }

      /* 顶部工具栏按钮 - tooltip显示在下方 */
      #cw-toolbar [data-tooltip]:hover::after,
      #cw-exit[data-tooltip]:hover::after {
        top: 100%;
        margin-top: 8px;
      }

      #cw-toolbar [data-tooltip]:hover::before,
      #cw-exit[data-tooltip]:hover::before {
        top: 100%;
        border-bottom-color: rgba(0, 0, 0, 0.9);
        margin-top: 2px;
      }

      /* 底部按钮 - tooltip显示在上方 */
      #cw-bottom-bar [data-tooltip]:hover::after {
        bottom: 100%;
        margin-bottom: 8px;
      }

      #cw-bottom-bar [data-tooltip]:hover::before {
        bottom: 100%;
        border-top-color: rgba(0, 0, 0, 0.9);
        margin-bottom: 2px;
      }

      /* 右侧按钮tooltip防止超出屏幕 */
      #cw-toolbar [data-tooltip]:hover::after {
        right: 0;
        left: auto;
        transform: translateX(-20px);
      }

      #cw-toolbar [data-tooltip]:hover::before {
        right: 20px;
        left: auto;
        transform: none;
      }

      /* 左侧退出按钮tooltip */
      #cw-exit[data-tooltip]:hover::after {
        left: 0;
        transform: translateX(20px);
      }

      #cw-exit[data-tooltip]:hover::before {
        left: 20px;
        transform: none;
      }

      /* 确保tooltip在全屏状态下也能正常显示 */
      :fullscreen [data-tooltip]:hover::after,
      :-webkit-full-screen [data-tooltip]:hover::after,
      :fullscreen [data-tooltip]:hover::before,
      :-webkit-full-screen [data-tooltip]:hover::before {
        z-index: 2147483649 !important;
      }
    `);

    // ====== 初始化阅读器UI(渲染图片并绑定按钮) ======
    function initReaderUI() {
      const container = document.getElementById('cw-container');
      if (!container) {
        console.warn('⚠️ cw-container 未找到,无法渲染图片');
        return;
      }

      // 设置初始缩放(使用 CSS 变量控制宽度)
      const applyZoom = () => {
        const vw = Math.max(10, Math.min(90, zoomLevel));
        document.documentElement.style.setProperty('--img-width', `${vw}vw`);
      };
      applyZoom();

      // 渲染图片列表
      container.innerHTML = '';
      images.forEach((url, idx) => {
        const img = document.createElement('img');
        img.src = url;
        img.loading = 'lazy';
        img.alt = `page-${idx + 1}`;
        img.dataset.index = String(idx + 1);
        container.appendChild(img);
      });

      // 更新页码显示(靠近视口中心的图片)
      const pageInfo = document.getElementById('cw-page-info');
      function updateCurrentPageInfo() {
        const imgs = container.querySelectorAll('img');
        if (!imgs.length) return;
        const viewportMid = window.scrollY + window.innerHeight / 2;
        let current = 1;
        let minDist = Infinity;
        imgs.forEach((img, i) => {
          const rect = img.getBoundingClientRect();
          const imgMid = window.scrollY + rect.top + rect.height / 2;
          const dist = Math.abs(imgMid - viewportMid);
          if (dist < minDist) { minDist = dist; current = i + 1; }
        });
        if (pageInfo) pageInfo.textContent = `${current}/${imgs.length}`;
      }

      // 退出、目录、全屏、背景、缩放、回顶部
      readerEventHandlers.onExitClick = () => exitReader();
      readerEventHandlers.onDirectoryClick = () => showDirectoryModal();
      readerEventHandlers.onFullClick = async () => {
        try {
          if (!document.fullscreenElement) await document.documentElement.requestFullscreen();
          else await document.exitFullscreen();
        } catch (e) { console.warn('全屏切换失败:', e); }
      };
      readerEventHandlers.onBgClick = () => {
        bgIsBlack = !bgIsBlack;
        document.body.style.background = bgIsBlack ? '#616161' : '#f5f5f5';
        document.body.style.color = bgIsBlack ? '#fff' : '#000';
      };
      readerEventHandlers.onZoomIn = () => { zoomLevel = Math.min(90, zoomLevel + 5); applyZoom(); };
      readerEventHandlers.onZoomOut = () => { zoomLevel = Math.max(10, zoomLevel - 5); applyZoom(); };
      readerEventHandlers.onToTop = () => window.scrollTo({ top: 0, behavior: 'smooth' });

      const throttle = (fn, wait = 100) => {
        let t = null;
        return (...args) => {
          if (t) return;
          t = setTimeout(() => { fn(...args); t = null; }, wait);
        };
      };

      readerEventHandlers.updateCurrentPageInfo = throttle(updateCurrentPageInfo, 120);

      // 工具栏显示控制
      readerEventHandlers.showTools = function() {
        try {
          document.documentElement.classList.add('tools-visible');
          if (readerToolsTimer) clearTimeout(readerToolsTimer);
          readerToolsTimer = setTimeout(() => {
            document.documentElement.classList.remove('tools-visible');
            readerToolsTimer = null;
          }, 3000);
        } catch (e) {
          // ignore
        }
      };

      readerEventHandlers.onMousemove = readerEventHandlers.showTools;
      readerEventHandlers.onKeydown = readerEventHandlers.showTools;

      readerEventHandlers.onFullscreen = function() {
        if (document.fullscreenElement) {
          readerEventHandlers.showTools();
        } else {
          document.documentElement.classList.remove('tools-visible');
          if (readerToolsTimer) { clearTimeout(readerToolsTimer); readerToolsTimer = null; }
        }
      };

      // 绑定 DOM 事件
      const exitBtn = document.getElementById('cw-exit');
      if (exitBtn) exitBtn.addEventListener('click', readerEventHandlers.onExitClick);

      const dirBtn = document.getElementById('cw-directory');
      if (dirBtn) dirBtn.addEventListener('click', readerEventHandlers.onDirectoryClick);

      const fullBtn = document.getElementById('cw-full');
      if (fullBtn) fullBtn.addEventListener('click', readerEventHandlers.onFullClick);

      const bgBtn = document.getElementById('cw-bg');
      if (bgBtn) bgBtn.addEventListener('click', readerEventHandlers.onBgClick);

      const zoomIn = document.getElementById('cw-zoom-in');
      const zoomOut = document.getElementById('cw-zoom-out');
      if (zoomIn) zoomIn.addEventListener('click', readerEventHandlers.onZoomIn);
      if (zoomOut) zoomOut.addEventListener('click', readerEventHandlers.onZoomOut);

      const toTop = document.getElementById('cw-to-top');
      if (toTop) toTop.addEventListener('click', readerEventHandlers.onToTop);

      // 全局事件绑定
      if (!readerEventsBound) {
        window.addEventListener('scroll', readerEventHandlers.updateCurrentPageInfo, { passive: true });
        window.addEventListener('mousemove', readerEventHandlers.onMousemove, { passive: true });
        window.addEventListener('keydown', readerEventHandlers.onKeydown, { passive: true });
        document.addEventListener('fullscreenchange', readerEventHandlers.onFullscreen);
        readerEventsBound = true;
      }

      // 立即更新一次页码并短暂显示工具栏
      setTimeout(updateCurrentPageInfo, 200);
      readerEventHandlers.showTools();

      // 提供解绑函数,供 exitReader 调用
      unbindReaderEvents = function() {
        try {
          if (!readerEventsBound) return;

          // 移除 DOM 绑定
          try { if (exitBtn) exitBtn.removeEventListener('click', readerEventHandlers.onExitClick); } catch (e) {}
          try { if (dirBtn) dirBtn.removeEventListener('click', readerEventHandlers.onDirectoryClick); } catch (e) {}
          try { if (fullBtn) fullBtn.removeEventListener('click', readerEventHandlers.onFullClick); } catch (e) {}
          try { if (bgBtn) bgBtn.removeEventListener('click', readerEventHandlers.onBgClick); } catch (e) {}
          try { if (zoomIn) zoomIn.removeEventListener('click', readerEventHandlers.onZoomIn); } catch (e) {}
          try { if (zoomOut) zoomOut.removeEventListener('click', readerEventHandlers.onZoomOut); } catch (e) {}
          try { if (toTop) toTop.removeEventListener('click', readerEventHandlers.onToTop); } catch (e) {}



          // 移除全局事件
          try { window.removeEventListener('scroll', readerEventHandlers.updateCurrentPageInfo, { passive: true }); } catch (e) {}
          try { window.removeEventListener('mousemove', readerEventHandlers.onMousemove, { passive: true }); } catch (e) {}
          try { window.removeEventListener('keydown', readerEventHandlers.onKeydown, { passive: true }); } catch (e) {}
          try { document.removeEventListener('fullscreenchange', readerEventHandlers.onFullscreen); } catch (e) {}
        } catch (e) {
          // ignore
        }
        // 清理定时器与状态
        if (readerToolsTimer) { clearTimeout(readerToolsTimer); readerToolsTimer = null; }
        readerEventHandlers = {};
               readerEventsBound = false;
        unbindReaderEvents = null;
      };
    }

    // 立即初始化阅读器 UI
    initReaderUI();
  }

  /*** 退出阅读模式 ***/
  function exitReader() {
    isReading = false;
    setAutoReaderStatus(false); // 关闭全局阅读器模式

    // 解绑阅读器事件,避免残留监听
    try {
      if (typeof unbindReaderEvents === 'function') unbindReaderEvents();
    } catch (e) {
      // ignore
    }

    // 先退出全屏
    if (document.fullscreenElement) {
      document.exitFullscreen().catch(err => {
        console.warn('退出全屏失败:', err);
      });
    }

    // 如果有保存的原始页面内容,直接恢复
    if (originalPageHTML) {
      console.log('🔄 恢复原始页面内容...');

      // 移除阅读模式添加的样式
      const readerStyles = document.querySelectorAll('style');
      readerStyles.forEach(style => {
        // 移除包含阅读模式特定选择器的样式
        if (style.textContent.includes('#cw-container') ||
            style.textContent.includes('#cw-toolbar') ||
            style.textContent.includes('#chapter-loader')) {
          style.remove();
          console.log('🧹 移除阅读模式样式');
        }
      });

      document.body.innerHTML = originalPageHTML;
      document.title = originalPageTitle;

      // 重新绑定按钮事件
      const restoredButton = document.getElementById('reader-toggle');
      if (restoredButton) {
        restoredButton.addEventListener('click', () => {
          if (!isReading) {
            enterReader();
            setAutoReaderStatus(true);
          } else {
            exitReader();
          }
        });
      }

      console.log('✅ 页面内容已恢复,目录缓存保留');
    } else {
      // 如果没有保存的内容,刷新页面
      console.log('⚠️ 没有保存的页面内容,刷新页面');
      location.reload();
    }
  }

  // 无缝章节加载:加载提示与错误显示
  function showLoadingIndicator(message = '正在加载章节...') {
    try {
      // 移除已存在的加载提示
      const existing = document.getElementById('chapter-loader');
      if (existing) existing.remove();

      const loader = document.createElement('div');
      loader.id = 'chapter-loader';
      loader.innerHTML = `
        <div class="loader-content">
          <div class="loader-spinner"></div>
          <div class="loader-text">${message}</div>
        </div>
      `;

      const style = document.createElement('style');
      style.id = 'chapter-loader-style';
      style.textContent = `
        #chapter-loader { position: fixed; top:0; left:0; width:100%; height:100%; background: rgba(0,0,0,0.6); display:flex; align-items:center; justify-content:center; z-index:2147483648; }
        #chapter-loader .loader-content { color:#fff; padding:18px 24px; border-radius:10px; background: rgba(0,0,0,0.45); text-align:center; }
        #chapter-loader .loader-spinner { width:30px; height:30px; border:3px solid rgba(255,255,255,0.25); border-top:3px solid #fff; border-radius:50%; animation: yamibo-spin 1s linear infinite; margin:0 auto 8px }
        @keyframes yamibo-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
        #chapter-loader .loader-text { font-size:14px; }
      `;

      document.head.appendChild(style);
      document.body.appendChild(loader);
    } catch (e) {
      console.warn('showLoadingIndicator error', e);
    }
  }

  function hideLoadingIndicator() {
    try {
      const loader = document.getElementById('chapter-loader');
      if (loader) {
        loader.remove();
      }
      const style = document.getElementById('chapter-loader-style');
      if (style) style.remove();
    } catch (e) {
      // ignore
    }
  }

  function showErrorMessage(message) {
    try {
      const id = 'chapter-error-msg';
      const existing = document.getElementById(id);
      if (existing) existing.remove();

      const el = document.createElement('div');
      el.id = id;
      el.style.cssText = 'position:fixed;left:50%;top:40%;transform:translate(-50%,-50%);background:#ff6b6b;color:#fff;padding:12px  18px;border-radius:8px;z-index:2147483649;font-size:14px;box-shadow:0 8px 30px rgba(0,0,0,0.4)';
      el.textContent = message;
      document.body.appendChild(el);
      setTimeout(() => { try { el.style.opacity = '0'; setTimeout(() => el.remove(), 250); } catch (e) {} }, 2500);
    } catch (e) {
      console.warn('showErrorMessage error', e);
    }
  }

  // 无缝章节切换
  async function loadNewChapter(chapterUrl, chapterTitle) {
    try {
      console.log('📖 开始无缝加载章节:', chapterTitle);
      showLoadingIndicator('正在加载章节...');

      const response = await fetch(chapterUrl, {
        method: 'GET',
        credentials: 'include',
        headers: {
          'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
          'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
          'Referer': window.location.href,
          'User-Agent': navigator.userAgent
        }
      });

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }

      const html = await response.text();
      const parser = new DOMParser();
      const doc = parser.parseFromString(html, 'text/html');

      // 提取图片 URL
      const newImages = collectImagesFromDocument(doc)
        .map(u => {
          if (!u) return null;
          let url = String(u);
          if (url.startsWith('//')) url = 'https:' + url;
          if (!/^https?:\/\//i.test(url)) url = 'https://bbs.yamibo.com/' + url.replace(/^\/+/, '');
          if (url.startsWith('http://')) url = url.replace(/^http:\/\//, 'https://');
          url = url.replace(/^https?:\/\/https?:\/\//, 'https://');
          return url;
        })
        .filter(Boolean);

      if (!newImages || newImages.length === 0) {
        hideLoadingIndicator();
        showErrorMessage('未找到漫画图片,已跳转到原帖');
        location.href = chapterUrl;
        return;
      }

      // 更新全局图片数组
      images = newImages;

      // 尝试提取并保存新章节标题
      const newH1 = doc.querySelector('h1.ts');
      if (newH1) {
        const subjectSpan = newH1.querySelector('#thread_subject, span[id^="thread_subject"]');
        savedThreadTitle = subjectSpan ? subjectSpan.textContent.trim() : newH1.textContent.trim();
      } else {
        const newTitleEl = doc.querySelector('#thread_subject, span[id^="thread_subject"]');
        if (newTitleEl) savedThreadTitle = newTitleEl.textContent.trim();
      }

      // 更新浏览器地址栏(不刷新页面)
      try { window.history.pushState({}, '', chapterUrl); } catch (e) { /* ignore */ }

      // 只更新图片容器与页码
      const container = document.getElementById('cw-container');
      if (container) {
        container.innerHTML = '';
        images.forEach((url, idx) => {
          const img = document.createElement('img');
          img.src = url;
          img.loading = 'lazy';
          img.alt = `page-${idx + 1}`;
          img.dataset.index = String(idx + 1);

          img.onload = function() {
            try {
              const naturalWidth = this.naturalWidth || 0;
              const viewportWidth = window.innerWidth || 1024;
              const oneThirdViewport = viewportWidth / 3;
              if (naturalWidth > 0 && naturalWidth < oneThirdViewport) this.setAttribute('data-original-size', 'small');
              else this.removeAttribute('data-original-size');
            } catch (e) {
              // ignore
            }
          };

          container.appendChild(img);
        });

        const pageInfo = document.getElementById('cw-page-info');
        if (pageInfo) pageInfo.textContent = `1/${images.length}`;
      }

      // 滚动到顶部
      window.scrollTo({ top: 0, behavior: 'smooth' });

      hideLoadingIndicator();
      console.log('🎉 章节加载完成:', chapterTitle);

    } catch (error) {
      console.error('❌ 加载章节失败:', error);
      hideLoadingIndicator();
      showErrorMessage('加载章节失败: ' + (error && error.message ? error.message : String(error)));
      // 若失败,1s 后回退到原帖(避免卡死在阅读器)
      setTimeout(() => { try { location.href = chapterUrl; } catch (e) {} }, 1000);
    }
  }
})();