[ {"sourceUrl":"https://www.baidu.com/晴天番茄书荒广场","sourceName":"晴天书荒广场","sourceIcon":"http://v1.gyks.cf/favicon.ico","sourceComment":"原作者 未知\n二改:\n  世界有多大 (翻页)\n  梓澄qwq (个人推荐, js注入, 拦截跳转)\n  Folltoshe (js注入)\n  柚屿 (完善登录)\n  清词 (失效修复,修复有书籍无法点击跳转的情况,加强过滤)\n  期待完美的自己(兼容晴天完全版书源)\n  晴天(完善晴天订阅源)","enabled":true,"jsLib":"var  base_url \u003d \t\u0027http://v1.gyks.cf\u0027;\n\nfunction checkSum(s) {\n  return String(java.lang.String(s).hashCode())\n}\n\nfunction getKey(key) {\n  let parts \u003d key.split(\";\");\n  for (let part of parts) {\n    if (part.includes(\"qttoken\")) {\n      return part.split(\"\u003d\")[1];\n    }\n  }\n  return \"\";\n}\n\nfunction removeCookie() {\n    const { cookie } \u003d this;\n    let domains \u003d [base_url,\u0027fanqienovel.com\u0027];\n    domains.forEach((domain) \u003d\u003e {\n      cookie.removeCookie(domain);\n    });\n  }\n\n\n\nfunction isIPv4Address(ip) {\n  ip \u003d String(ip);\n  let parts \u003d ip.split(\".\");\n  if (parts.length !\u003d\u003d 4) return false;\n\n  for (let part of parts) {\n    if (!/^\\d+$/.test(part)) return false; // 必须是数字\n    if (part.length \u003e 1 \u0026\u0026 part[0] \u003d\u003d\u003d \"0\") return false; // 禁止前导零\n    let num \u003d parseInt(part, 10);\n    if (num \u003c 0 || num \u003e 255) return false; // 范围检查\n  }\n  return true;\n}\n\nfunction isIPv6Address(ip) {\n  ip \u003d String(ip);\n  // 处理双冒号（最多出现一次）\n  if (ip.includes(\":::\")) return false;\n  let doubleColonCount \u003d (ip.match(/::/g) || []).length;\n  if (doubleColonCount \u003e 1) return false;\n\n  // 分割成组\n  let groups \u003d ip.split(\":\");\n  let validGroupCount \u003d 8;\n  let actualGroupCount \u003d groups.filter((g) \u003d\u003e g !\u003d\u003d \"\").length;\n\n  // 验证组数\n  if (doubleColonCount \u003d\u003d\u003d 1) {\n    if (actualGroupCount \u003e validGroupCount - 1) return false;\n  } else {\n    if (groups.length !\u003d\u003d validGroupCount) return false;\n  }\n\n  // 验证每组内容\n  for (let group of groups) {\n    if (group \u003d\u003d\u003d \"\") continue; // 跳过空组（双冒号部分）\n    if (!/^[0-9a-fA-F]{1,4}$/.test(group)) return false; // 1-4位十六进制\n  }\n  return true;\n}\n\nfunction isIPAddress(input) {\n  return isIPv4Address(input) || isIPv6Address(input);\n}\n\nfunction getSessionId(cookieString) {\n    const match \u003d cookieString.match(/sessionid\u003d([^;]+)/);\n    return match ? match[1] : null;\n}\n\n\n","enabledCookieJar":true,"header":"{\"User-Agent\":\"Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1 Edg/138.0.0.0\"}","loginUrl":"const localVersion \u003d \u00274.12.30\u0027;\n\n\nfunction login(flag) {\n\tif (flag \u003d\u003d undefined) {\n\t\tresult \u003d JSON.parse(source.getLoginInfo())\n\t} else {\n\t\tjava.longToast(\"\\n\\n💞正在登录中...\")\n\t\tputLoginInfo(JSON.stringify(result))\n\t}\n\t let register_email \u003d String(result[\u0027邮箱\u0027])\n\tlet password \u003d String(result[\u0027密码\u0027])\n\tlet key \u003d String(result[\u0027密钥\u0027]||\u0027\u0027)\n\t\n\t//java.log(cookie.getCookie(base_url))\n\t\n\tif ((register_email \u0026\u0026 password || key)\u0026\u0026 !String(getKey(String(cookie.getCookie(base_url))))) {\n\t\tremoveCookie();\n\t\tlet deviceKey \u003d \u0027\u0027;\n\t\tif (String(deviceKey) \u003d\u003d \"undefined\") {\n\t\t\ttry {\n\t\t\t\tdeviceKey \u003d java.deviceID();\n\t\t\t} catch (e) {\n\t\t\t\tdeviceKey \u003d java.androidId();\n\t\t\t}\n\t\t};\n\t\t\n\tlet deviceId \u003d java.digestHex(deviceKey, \"SHA256\")\n\t\t  if (register_email \u0026\u0026 password){\n\t\t\tlet options \u003d JSON.stringify({\n\t\t\t\tmethod: \u0027POST\u0027,\n\t\t\t\theaders: {\n\t\t\t\t\t\u0027Content-Type\u0027: \u0027application/json\u0027\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tregister_email: result[\u0027邮箱\u0027],\n\t\t\t\t\tpassword: result[\u0027密码\u0027]\n\t\t\t\t})\n\t\t\t})\n\t\t\ttry {\n\t\t\t\tlet data \u003d JSON.parse(java.ajax(`${base_url}/login_api,${options}`))\n\t\t\t\tif (data.code \u003d\u003d 0) {\n\t\t\t\t\tjava.toast(\"\\n\\n✅️登录成功\")\n\t\t\t\t\tcookie.setCookie(base_url, `qttoken\u003d${data.key};deviceId\u003d${deviceId}`)\n\t\t\t\t\tresult[\u0027密钥\u0027]\u003ddata.key\n\t\t\t\t\tputLoginInfo(JSON.stringify(result))\n\t\t\t\t} else {\n\t\t\t\t\tjava.toast(\u0027\\n\\n💔\u0027+data.msg || \"登录失败，请重试！\")\n\t\t\t\t}\n\t\t\t} catch (e) {\n\t\t\t\tjava.toast(\"\\n\\n💔登录失败，请重试！\\n\" + e.message)\n\t\t\t}\n\t\t} else {\n\t\t\tcookie.setCookie(base_url, `qttoken\u003d${key};deviceId\u003d${deviceId}`)\n\t\t\tlet res\u003djava.ajax(`${base_url}/user_api,{\"method\":\"POST\",\"headers\":{\"cookie\":\"${cookie.getCookie(base_url)}\"}}`)\t\t\t\n\t\t\ttry {\n\t\t\t\tres\u003dJSON.parse(res)\n\t\t\t\tif (res.id!\u003dundefined) {\n\t\t\t\t\tjava.toast(\u0027\\n\\n密钥登录成功\u0027)\n\t\t\t\t\tresult[\u0027邮箱\u0027] \u003d res.email\n\t\t\t\t\tputLoginInfo(JSON.stringify(result))\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error()\n\t\t\t\t}\n\t\t\t} catch(e) {\n\t\t\t\tjava.log(e)\n\t\t\t\tjava.toast(\"\\n\\n💔登录失败\")\n\t\t\t}\n\t\t}\n\t} else if (flag\u0026\u0026String(getKey(String(cookie.getCookie(base_url))))) {\n\t\tjava.toast(\"\\n\\n当前✅️已登录，请🚫退出登录后重新登录\");\n\t\t//checkStatus();\n\t} else if (flag) {\n\t\tjava.toast(\"\\n\\n⛔️请先填写邮箱和密码\");\n\t\t}\n}\n\nfunction fq_login() {\n\ttry {\n\t\tjava.startBrowserAwait(\"https://fanqienovel.com/\", \"登录\")\n\t} catch (e) {\n\t\tjava.toast(e)\n\t}\n\ttry {\n\t\tcookie.removeCookie(\"snssdk.com\")\n\t} catch (e) {}\n\tvar cookies \u003d cookie.getCookie(\"fanqienovel.com\")\n\tif (!cookies || cookies \u003d\u003d \"\") {\n\t\tjava.toast(\"登录失败！\")\n\t\treturn false\n\t}\n\tjava.toast(\"登录成功！\")\n\treturn true\n}\n\nfunction checkStatus() {\n\tjava.longToast(\u0027\\n\\n♻️检测中...\u0027);\n\tlet res\u003djava.ajax(`${base_url}/user_api,{\"method\":\"POST\",\"headers\":{\"cookie\":\"${cookie.getCookie(base_url)}\"}}`)\t\n\ttry {\n\t\t\t\tres\u003dJSON.parse(res)\n\t\t\t\tif (res.id!\u003dundefined) {\n\t\t\t\t\tresult[\u0027邮箱\u0027] \u003d res.email\n\t\t\t\t\tputLoginInfo(JSON.stringify(result))\n\t\t\t\t\tlet devices\n\t\t\t\t\ttry {\n\t\t\t\t\t\tdevices \u003d JSON.parse(res.device).length;\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tdevices \u003d res.device ? 1 : 0;\n\t\t\t\t\t}\n\t\t\t\t\tlet isVip;\n\t\t\t\t\tif (res.is_vip\u003d\u003d1) {\n\t\t\t\t\t\tisVip \u003d \u0027VIP\u0027;\n\t\t\t\t\t} else if (res.is_vip\u003e\u003d2) {\n\t\t\t\t\t\tisVip \u003d \u0027SVIP\u0027;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tisVip \u003d \u0027普通会员\u0027;\n\t\t\t\t\t}\n\t\t\t\t\ttips\u003d `\n┏┅┅┅┅┅┅┱┄┄┄┄┄┄┄┄┄┄┐\n　✉️邮箱　　　　${res.email.replace(/(.{3}).*?@/,\"$1***@\").padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n　🔑密钥　　　　${(`${res.user_key.substring(0,4)}***${res.user_key.slice(-4)}`).padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n　📅注册时间　　${java.timeFormat(res.register_time*1000).padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n　🗒️今日阅读　　${(java.timeFormat(new Date()).slice(0,10)\u003d\u003djava.timeFormat(res.last_read_time * 1000).slice(0,10)?res.day_read_count:0).toString().padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n　📚累计阅读　　${res.all_read_count.toString().padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n　🕓最后阅读　　${(res.last_read_time !\u003d 0?java.timeFormat(res.last_read_time * 1000):\u0027未阅读\u0027).padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n　📱关联设备　　${devices.toString().padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n　👑会员状态　　${isVip.padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n　🚫封禁状态　　${res.is_banned?\u0027已封禁\u0027:\u0027正常　\u0027}　　　　　　　\n┗┅┅┅┅┅┅┹┄┄┄┄┄┄┄┄┄┄┘\n`\n\t\t\t\t\tjava.log(tips)\n\t\t\t\t\tjava.longToast(tips)\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(res.msg)\n\t\t\t\t}\n\t\t\t} catch(e) {\n\t\t\t\t//java.log(e)\n\t\t\t\tjava.toast(\"\\n检测登录失败\\n\"+e.message)\n\t\t\t}\n}\n\nfunction clearDevice() {\n  let res\u003djava.ajax(`${base_url}/clear,{\"method\":\"POST\",\"headers\":{\"cookie\":\"${cookie.getCookie(base_url)}\"}}`)\n\t//java.toast(res.code \u003d\u003d\u003d 0 ? \"\\n\\n📴设备清除成功\" : res.msg)\n\tPackages.java.lang.Thread.sleep(500)\n\tcheckStatus()\n}\n// 保存登录UI信息\nfunction putLoginInfo(info) {\n\ttry {\n\t\tlet key \u003d java.androidId()\n\t\tlet encodeStr \u003d Packages.android.util.Base64.encodeToString(java.createSymmetricCrypto(\"AES\", key).encrypt(info), 2)\n\t\tcache.put(`userInfo_${source.getKey()}`, encodeStr)\n\t\treturn true\n\t} catch (e) {\n\t\tjava.log(e)\n\t\treturn source.putLoginInfo(info)\n\t}\n}\n\n\n\nfunction api() {\njava.startBrowserAwait(\u0027http://vip.gyks.cf\u0027, \"首页\");\n}\n\n\n//打赏\nfunction vip() {\n\tjava.startBrowserAwait(base_url+ \u0027/coffee\u0027, \"喝咖啡\");\n\t\n}\nfunction loginqt() {\n\tjava.startBrowserAwait(base_url + \u0027/login\u0027, \u0027登录晴天小说书源\u0027);\n}\n\n function logout() {\n\tcookie.removeCookie(\"fanqienovel.com\");\n\tcookie.removeCookie(\"snssdk.com\");\n\tcookie.removeCookie(base_url);\n\tcookie.removeCookie(\"gyks.cf\");\n\tcookie.removeCookie(\"113.45.175.112\");\n\tjava.toast(\"退出登录成功\");\n}\n\n// 书源更新\nfunction renderVersionPage() {\n    let yd \u003d \u0027\u0027;\n    let html \u003d `\n\u003c!DOCTYPE html\u003e\n\u003chtml lang\u003d\"zh-CN\"\u003e\n\u003chead\u003e\n  \u003cmeta charset\u003d\"UTF-8\" /\u003e\n  \u003cmeta name\u003d\"viewport\" content\u003d\"width\u003ddevice-width, initial-scale\u003d1.0\" /\u003e\n  \u003ctitle\u003e书源更新\u003c/title\u003e\n  \u003c!-- Font Awesome 图标库 --\u003e\n  \u003clink rel\u003d\"stylesheet\" href\u003d\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css\" /\u003e\n  \u003cstyle\u003e\n    :root {\n      --primary-gradient: linear-gradient(135deg, #4e6ef2, #6b2dd8);\n      --latest-gradient: linear-gradient(135deg, #8e2de2 0%, #4a00e0 50%, #d4af37 100%);\n      --success-color: #28c76f;\n      --warning-color: #ff9f43;\n      --error-color: #ea5455;\n      --text-main: #1f2937;\n      --text-secondary: #6b7280;\n      --card-bg: #ffffff;\n      --border-color: #e5e7eb;\n      --light-bg: #f9fafb;\n      --shadow: 0 4px 12px rgba(78, 110, 242, 0.1);\n      --shadow-hover: 0 6px 18px rgba(78, 110, 242, 0.2);\n      --glow-shadow: 0 0 25px rgba(142, 45, 226, 0.5), 0 0 50px rgba(212, 175, 55, 0.3);\n      --modal-bg: rgba(31, 41, 55, 0.8);\n      --modal-content-bg: #ffffff;\n    }\n\n    * {\n      box-sizing: border-box;\n      margin: 0;\n      padding: 0;\n      font-family: \u0027Segoe UI\u0027, \u0027PingFang SC\u0027, \u0027Microsoft YaHei\u0027, sans-serif;\n    }\n\n    body {\n      background: linear-gradient(135deg, #eef2ff, #f5f7ff);\n      color: var(--text-main);\n      min-height: 100vh;\n      display: flex;\n      flex-direction: column;\n      align-items: center;\n      justify-content: center;\n      padding: 16px;\n    }\n\n    /* 加载动画 */\n    .loading-wrapper {\n      text-align: center;\n      animation: fadeIn 0.3s ease;\n    }\n\n    .loading-spinner {\n      width: 50px;\n      height: 50px;\n      border: 4px solid rgba(78, 110, 242, 0.3);\n      border-top-color: #4e6ef2;\n      border-radius: 50%;\n      margin: 0 auto 20px;\n      animation: spin 1s linear infinite;\n    }\n\n    .loading-text {\n      color: var(--text-main);\n      font-size: 16px;\n      font-weight: 500;\n    }\n\n    @keyframes spin {\n      to { transform: rotate(360deg); }\n    }\n\n    @keyframes fadeIn {\n      from { opacity: 0; transform: translateY(20px); }\n      to { opacity: 1; transform: translateY(0); }\n    }\n\n    @keyframes slideIn {\n      from { opacity: 0; transform: translateY(30px); }\n      to { opacity: 1; transform: translateY(0); }\n    }\n\n    @keyframes pulse {\n      0%, 100% { opacity: 1; }\n      50% { opacity: 0.7; }\n    }\n\n    @keyframes gradientAnimation {\n      0% { background-position: 0% 50%; }\n      50% { background-position: 100% 50%; }\n      100% { background-position: 0% 50%; }\n    }\n\n    @keyframes breathe {\n      0%, 100% { \n        transform: scale(1);\n        box-shadow: var(--glow-shadow), var(--shadow);\n      }\n      50% { \n        transform: scale(1.02);\n        box-shadow: 0 0 30px rgba(142, 45, 226, 0.6), 0 0 60px rgba(212, 175, 55, 0.4), var(--shadow);\n      }\n    }\n\n    @keyframes shimmer {\n      0% {\n        background-position: -200% center;\n      }\n      100% {\n        background-position: 200% center;\n      }\n    }\n\n    /* 主容器 */\n    .container {\n      width: 100%;\n      max-width: 420px;\n      background: var(--card-bg);\n      border-radius: 24px;\n      overflow: hidden;\n      box-shadow: var(--shadow);\n      position: relative;\n      z-index: 1;\n      animation: slideIn 0.5s ease;\n      display: none;\n    }\n\n    /* 头部 */\n    .header {\n      background: var(--primary-gradient);\n      color: #ffffff;\n      padding: 24px 16px;\n      text-align: center;\n      position: relative;\n      overflow: hidden;\n    }\n\n    .header::before {\n      content: \u0027\u0027;\n      position: absolute;\n      top: -30px;\n      left: -30px;\n      width: 80px;\n      height: 80px;\n      background: rgba(255, 255, 255, 0.15);\n      border-radius: 50%;\n    }\n\n    .header::after {\n      content: \u0027\u0027;\n      position: absolute;\n      bottom: -60px;\n      right: -60px;\n      width: 150px;\n      height: 150px;\n      background: rgba(255, 255, 255, 0.1);\n      border-radius: 50%;\n    }\n\n    .header h1 {\n      font-size: 1.4rem;\n      font-weight: 700;\n      margin-bottom: 8px;\n      position: relative;\n      z-index: 2;\n    }\n\n    .header p {\n      font-size: 0.9rem;\n      opacity: 0.9;\n      line-height: 1.4;\n      position: relative;\n      z-index: 2;\n    }\n\n    .header-icon {\n      font-size: 48px;\n      margin-bottom: 10px;\n      display: inline-block;\n      animation: bounce 2s ease infinite;\n    }\n\n    @keyframes bounce {\n      0%, 100% { transform: translateY(0); }\n      50% { transform: translateY(-10px); }\n    }\n\n    /* 版本对比 */\n    .version-comparison {\n      display: flex;\n      flex-wrap: nowrap;\n      gap: 12px;\n      padding: 16px;\n      margin-top: 8px;\n      position: relative;\n      z-index: 10;\n    }\n\n    .version-card {\n      flex: 1;\n      min-width: 45%;\n      background: var(--card-bg);\n      border-radius: 16px;\n      padding: 28px 16px 16px;\n      box-shadow: var(--shadow);\n      text-align: center;\n      position: relative;\n      transition: transform 0.3s ease, box-shadow 0.3s ease;\n      overflow: hidden;\n      border: 1px solid rgba(120, 130, 240, 0.1);\n    }\n\n    .version-card:hover {\n      transform: translateY(-4px);\n      box-shadow: var(--shadow-hover);\n    }\n\n    .version-card.current-version {\n      background: linear-gradient(135deg, #ffffff 0%, #f8f9ff 100%);\n      border: 1px solid rgba(78, 110, 242, 0.15);\n    }\n\n    .version-card.current-version:hover {\n      box-shadow: 0 6px 20px rgba(78, 110, 242, 0.15);\n    }\n\n    .version-card.current-version h3,\n    .version-card.current-version .version-number,\n    .version-card.current-version .version-date {\n      color: var(--text-main);\n    }\n\n    .version-card.latest-version {\n      background: var(--latest-gradient);\n      background-size: 300% 300%;\n      box-shadow: var(--glow-shadow), var(--shadow);\n      color: #fff;\n      z-index: 2;\n      animation: gradientAnimation 6s ease infinite, breathe 3s ease-in-out infinite;\n      position: relative;\n      overflow: hidden;\n    }\n\n    .version-card.latest-version::before {\n      content: \u0027\u0027;\n      position: absolute;\n      top: -50%;\n      left: -50%;\n      width: 200%;\n      height: 200%;\n      background: linear-gradient(\n        90deg,\n        transparent,\n        rgba(255, 255, 255, 0.3),\n        transparent\n      );\n      transform: rotate(45deg);\n      animation: shimmer 3s infinite;\n    }\n\n    .version-card.latest-version h3,\n    .version-card.latest-version .version-number,\n    .version-card.latest-version .version-date {\n      color: #fff;\n      text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);\n      position: relative;\n      z-index: 1;\n    }\n\n    .version-status {\n      position: absolute;\n      top: 6px;\n      right: 6px;\n      padding: 3px 7px;\n      font-size: 0.65rem;\n      font-weight: 600;\n      border-radius: 6px;\n      color: #fff;\n      line-height: 1.2;\n      white-space: nowrap;\n      z-index: 2;\n    }\n\n    .version-card.latest-version .version-status {\n      background: rgba(255, 255, 255, 0.25);\n      backdrop-filter: blur(5px);\n      border: 1px solid rgba(255, 255, 255, 0.3);\n      color: #fff;\n      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n    }\n\n    .status-outdated { background: var(--warning-color); }\n    .status-latest { background: var(--success-color); }\n    .status-invalid { background: var(--error-color); }\n\n    .version-card h3 {\n      font-size: 0.9rem;\n      color: var(--text-secondary);\n      margin-bottom: 8px;\n      font-weight: 500;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      gap: 6px;\n    }\n\n    .version-number {\n      font-size: 1.25rem;\n      font-weight: 700;\n      color: var(--text-main);\n      margin: 8px 0;\n      transition: all 0.3s ease;\n      font-family: \u0027Courier New\u0027, monospace;\n    }\n\n    .version-card.latest-version .version-number {\n      font-size: 1.4rem;\n      transform: scale(1.05);\n      text-shadow: \n        0 2px 4px rgba(0, 0, 0, 0.3),\n        0 0 10px rgba(212, 175, 55, 0.8),\n        0 0 20px rgba(212, 175, 55, 0.5);\n      animation: pulse-glow 2s ease-in-out infinite;\n    }\n\n    @keyframes pulse-glow {\n      0%, 100% {\n        text-shadow: \n          0 2px 4px rgba(0, 0, 0, 0.3),\n          0 0 10px rgba(212, 175, 55, 0.8),\n          0 0 20px rgba(212, 175, 55, 0.5);\n      }\n      50% {\n        text-shadow: \n          0 2px 4px rgba(0, 0, 0, 0.3),\n          0 0 15px rgba(212, 175, 55, 1),\n          0 0 30px rgba(212, 175, 55, 0.7);\n      }\n    }\n\n    .version-date {\n      font-size: 0.8rem;\n      color: var(--text-secondary);\n      margin-top: 4px;\n    }\n\n    /* 版本对比指示器 */\n    .version-indicator {\n      position: absolute;\n      left: 50%;\n      top: 50%;\n      transform: translate(-50%, -50%);\n      z-index: 5;\n      width: 32px;\n      height: 32px;\n      border-radius: 50%;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n      color: white;\n    }\n\n    .version-indicator.update-needed {\n      background: var(--error-color);\n      box-shadow: 0 2px 8px rgba(234, 84, 85, 0.4);\n      animation: pulse-indicator 1.5s infinite;\n    }\n\n    .version-indicator.is-latest {\n      background: var(--success-color);\n      box-shadow: 0 2px 8px rgba(40, 199, 111, 0.4);\n    }\n\n    @keyframes pulse-indicator {\n      0% { transform: translate(-50%, -50%) scale(1); }\n      50% { transform: translate(-50%, -50%) scale(1.1); }\n      100% { transform: translate(-50%, -50%) scale(1); }\n    }\n\n    /* 内容区 */\n    .content-container {\n      padding: 16px;\n    }\n\n    /* 状态提示 */\n    .status-alert {\n      background: var(--card-bg);\n      border-radius: 16px;\n      box-shadow: var(--shadow);\n      margin-bottom: 16px;\n      overflow: hidden;\n      border: 1px solid rgba(120, 130, 240, 0.1);\n      padding: 12px 16px;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      gap: 10px;\n      font-weight: 500;\n      font-size: 14px;\n      animation: slideIn 0.5s ease 0.3s backwards;\n    }\n\n    .status-alert i {\n      font-size: 20px;\n    }\n\n    .status-alert.update-available {\n      background: linear-gradient(135deg, #ffeaa7 0%, #fdcb6e 100%);\n      color: #d63031;\n      box-shadow: 0 4px 15px rgba(253, 203, 110, 0.4);\n    }\n\n    .status-alert.up-to-date {\n      background: linear-gradient(135deg, #55efc4 0%, #00b894 100%);\n      color: white;\n      box-shadow: 0 4px 15px rgba(0, 184, 148, 0.4);\n    }\n\n    /* 更新容器 */\n    .update-container {\n      background: var(--card-bg);\n      border-radius: 16px;\n      box-shadow: var(--shadow);\n      margin-bottom: 16px;\n      overflow: hidden;\n      border: 1px solid rgba(120, 130, 240, 0.1);\n      animation: slideIn 0.5s ease 0.4s backwards;\n    }\n\n    .update-header {\n      background: var(--light-bg);\n      padding: 12px 16px;\n      display: flex;\n      justify-content: space-between;\n      align-items: center;\n      border-bottom: 1px solid var(--border-color);\n    }\n\n    .update-header h2 {\n      font-size: 1rem;\n      font-weight: 600;\n      color: var(--text-main);\n      display: flex;\n      align-items: center;\n      gap: 8px;\n    }\n\n    .update-header h2 i {\n      color: #4e6ef2;\n    }\n\n    .update-tag {\n      background: rgba(78, 110, 242, 0.1);\n      color: #4e6ef2;\n      padding: 4px 8px;\n      border-radius: 8px;\n      font-size: 0.75rem;\n      font-weight: 600;\n    }\n\n    .update-content {\n      padding: 16px;\n    }\n\n    .update-date {\n      font-weight: 600;\n      color: #4e6ef2;\n      margin-bottom: 12px;\n      display: flex;\n      align-items: center;\n      gap: 6px;\n      padding: 8px 0;\n      border-bottom: 1px dashed #e0e0e0;\n    }\n\n    .update-text {\n      margin: 8px 0;\n      position: relative;\n      padding-left: 16px;\n      line-height: 1.5;\n      color: var(--text-main);\n      font-size: 0.95rem;\n      white-space: pre-wrap;\n      word-break: break-word;\n    }\n\n    .update-text::before {\n      content: \u0027•\u0027;\n      position: absolute;\n      left: 0;\n      font-weight: bold;\n      color: #4e6ef2;\n      font-size: 1.2rem;\n      line-height: 1;\n    }\n\n    /* 历史日志 */\n    .history-container {\n      background: var(--card-bg);\n      border-radius: 16px;\n      box-shadow: var(--shadow);\n      margin-bottom: 16px;\n      border: 1px solid rgba(120, 130, 240, 0.1);\n      animation: slideIn 0.5s ease 0.5s backwards;\n    }\n\n    .history-header {\n      background: var(--light-bg);\n      padding: 12px 16px;\n      display: flex;\n      justify-content: space-between;\n      align-items: center;\n      border-bottom: 1px solid var(--border-color);\n      cursor: pointer;\n      user-select: none;\n    }\n\n    .history-header:hover {\n      opacity: 0.8;\n    }\n\n    .history-header h2 {\n      font-size: 1rem;\n      font-weight: 600;\n      color: var(--text-main);\n      display: flex;\n      align-items: center;\n      gap: 8px;\n    }\n\n    .history-header h2 i {\n      color: #4e6ef2;\n    }\n\n    .toggle-history {\n      background: none;\n      border: none;\n      color: var(--text-secondary);\n      cursor: pointer;\n      font-weight: 500;\n      display: flex;\n      align-items: center;\n      gap: 4px;\n      font-size: 0.85rem;\n      transition: color 0.2s ease;\n    }\n\n    .toggle-history:hover {\n      color: #4e6ef2;\n    }\n\n    .history-content {\n      padding: 0 16px;\n      max-height: 0;\n      overflow: hidden;\n      transition: max-height 0.4s ease, padding 0.4s ease;\n    }\n\n    .history-content.expanded {\n      max-height: 60vh;\n      overflow-y: auto;\n      padding: 16px;\n      scrollbar-width: thin;\n      scrollbar-color: #4e6ef2 #f0f0f0;\n    }\n\n    .history-content.expanded::-webkit-scrollbar {\n      width: 6px;\n    }\n\n    .history-content.expanded::-webkit-scrollbar-track {\n      background: #f0f0f0;\n      border-radius: 4px;\n    }\n\n    .history-content.expanded::-webkit-scrollbar-thumb {\n      background: #4e6ef2;\n      border-radius: 4px;\n    }\n\n    .history-content.expanded::-webkit-scrollbar-thumb:hover {\n      background: #3a56d0;\n    }\n\n    .history-item {\n      margin-bottom: 16px;\n      padding-bottom: 16px;\n      border-bottom: 1px dashed var(--border-color);\n    }\n\n    .history-item:last-child {\n      border-bottom: none;\n      margin-bottom: 0;\n      padding-bottom: 0;\n    }\n\n    .history-date {\n      font-weight: 600;\n      color: var(--text-main);\n      margin-bottom: 8px;\n      display: flex;\n      align-items: center;\n      gap: 4px;\n      font-size: 0.9rem;\n      background: rgba(78, 110, 242, 0.05);\n      padding: 6px 10px;\n      border-radius: 6px;\n    }\n\n    .history-text {\n      margin: 8px 0;\n      padding-left: 16px;\n      line-height: 1.4;\n      color: var(--text-secondary);\n      position: relative;\n      font-size: 0.9rem;\n      white-space: pre-wrap;\n      word-break: break-word;\n    }\n\n    .history-text::before {\n      content: \u0027•\u0027;\n      position: absolute;\n      left: 0;\n      color: #4e6ef2;\n      font-weight: bold;\n      font-size: 1.2rem;\n      line-height: 1;\n    }\n\n    /* 按钮组 */\n    .button-group {\n      display: flex;\n      flex-direction: column;\n      gap: 10px;\n      margin-bottom: 16px;\n    }\n\n    .button {\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      gap: 10px;\n      padding: 14px 28px;\n      text-align: center;\n      font-size: 1rem;\n      border: none;\n      border-radius: 12px;\n      text-decoration: none;\n      background: var(--primary-gradient);\n      color: white;\n      font-weight: 600;\n      transition: all 0.3s ease;\n      box-shadow: var(--shadow);\n      position: relative;\n      overflow: hidden;\n      cursor: pointer;\n    }\n\n    .button i {\n      font-size: 1rem;\n    }\n\n    .button::after {\n      content: \u0027\u0027;\n      position: absolute;\n      top: -50%;\n      left: -50%;\n      width: 200%;\n      height: 200%;\n      background: rgba(255, 255, 255, 0.1);\n      transform: rotate(30deg);\n      transition: all 0.6s ease;\n      pointer-events: none;\n    }\n\n    .button:hover {\n      transform: translateY(-3px);\n      box-shadow: var(--shadow-hover);\n    }\n\n    .button:hover::after {\n      transform: rotate(30deg) translate(20%, 20%);\n    }\n\n    .button:active {\n      transform: scale(0.95);\n    }\n\n    /* 错误状态 */\n    .error-state {\n      text-align: center;\n      padding: 40px 20px;\n      color: var(--text-main);\n    }\n\n    .error-icon {\n      font-size: 64px;\n      margin-bottom: 20px;\n      color: var(--error-color);\n    }\n\n    .error-text {\n      font-size: 16px;\n      line-height: 1.6;\n      margin-bottom: 20px;\n    }\n\n    .retry-button {\n      background: var(--primary-gradient);\n      color: white;\n      padding: 12px 30px;\n      border-radius: 12px;\n      border: none;\n      font-weight: 600;\n      cursor: pointer;\n      transition: all 0.3s ease;\n      font-size: 14px;\n      box-shadow: var(--shadow);\n    }\n\n    .retry-button:hover {\n      transform: translateY(-2px);\n      box-shadow: var(--shadow-hover);\n    }\n\n    .retry-button:active {\n      transform: scale(0.95);\n    }\n\n    /* 装饰元素 */\n    .decoration {\n      position: absolute;\n      z-index: 0;\n      pointer-events: none;\n    }\n\n    .decoration.circle {\n      width: 120px;\n      height: 120px;\n      border-radius: 50%;\n      background: rgba(107, 45, 216, 0.05);\n      top: 10%;\n      left: 10%;\n    }\n\n    .decoration.square {\n      width: 80px;\n      height: 80px;\n      transform: rotate(45deg);\n      background: rgba(78, 110, 242, 0.05);\n      bottom: 10%;\n      right: 10%;\n    }\n\n    /* 响应式 */\n    @media (max-width: 768px) {\n      body {\n        padding: 12px;\n      }\n\n      .container {\n        max-width: 100%;\n        border-radius: 20px;\n      }\n\n      .header {\n        padding: 20px 15px;\n      }\n\n      .header h1 {\n        font-size: 1.3rem;\n      }\n\n      .header-icon {\n        font-size: 40px;\n      }\n\n      .version-comparison {\n        flex-direction: row;\n        flex-wrap: nowrap;\n        gap: 10px;\n        padding: 12px;\n        margin-top: 6px;\n        overflow-x: auto;\n      }\n\n      .version-card {\n        min-width: 45%;\n        padding: 26px 12px 12px;\n      }\n\n      /* 移动端减弱呼吸动效 */\n      .version-card.latest-version {\n        animation: gradientAnimation 6s ease infinite;\n      }\n\n      .version-status {\n        top: 5px;\n        right: 5px;\n        padding: 2px 5px;\n        font-size: 0.6rem;\n      }\n\n      .version-number {\n        font-size: 1.1rem;\n      }\n\n      .version-card.latest-version .version-number {\n        font-size: 1.2rem;\n      }\n\n      .update-header h2, .history-header h2 {\n        font-size: 0.9rem;\n      }\n\n      .button {\n        padding: 12px 24px;\n        font-size: 0.95rem;\n      }\n\n      .history-content.expanded {\n        max-height: 50vh;\n        -webkit-overflow-scrolling: touch;\n      }\n    }\n\n    @media (max-width: 380px) {\n      .header h1 {\n        font-size: 1.2rem;\n      }\n\n      .version-number {\n        font-size: 1rem;\n      }\n\n      .version-card.latest-version .version-number {\n        font-size: 1.1rem;\n      }\n\n      .button {\n        padding: 11px;\n        font-size: 0.9rem;\n      }\n    }\n  \u003c/style\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n  \u003cdiv class\u003d\"decoration circle\"\u003e\u003c/div\u003e\n  \u003cdiv class\u003d\"decoration square\"\u003e\u003c/div\u003e\n\n  \u003cdiv id\u003d\"loading\" class\u003d\"loading-wrapper\"\u003e\n    \u003cdiv class\u003d\"loading-spinner\"\u003e\u003c/div\u003e\n    \u003cdiv class\u003d\"loading-text\"\u003e\u003ci class\u003d\"fas fa-search\"\u003e\u003c/i\u003e 正在检查更新...\u003c/div\u003e\n  \u003c/div\u003e\n\n  \u003cdiv class\u003d\"container\" id\u003d\"container\"\u003e\n    \u003cdiv class\u003d\"header\"\u003e\n      \u003cdiv class\u003d\"header-icon\"\u003e\u003ci class\u003d\"fas fa-book\"\u003e\u003c/i\u003e\u003c/div\u003e\n      \u003ch1\u003e晴天订阅源更新\u003c/h1\u003e\n      \u003cp\u003e推荐使用阅读测试版\u003cbr\u003e正式版可能存在兼容性问题\u003c/p\u003e\n    \u003c/div\u003e\n\n    \u003cdiv class\u003d\"version-comparison\"\u003e\n      \u003cdiv class\u003d\"version-card current-version\"\u003e\n        \u003cdiv class\u003d\"version-status status-outdated\" id\u003d\"currentStatus\"\u003e待检查\u003c/div\u003e\n        \u003ch3\u003e\u003ci class\u003d\"fas fa-cube\"\u003e\u003c/i\u003e 当前版本\u003c/h3\u003e\n        \u003cdiv class\u003d\"version-number\" id\u003d\"currentVersion\"\u003e-\u003c/div\u003e\n        \u003cdiv class\u003d\"version-date\"\u003e您的当前版本\u003c/div\u003e\n      \u003c/div\u003e\n\n      \u003cdiv class\u003d\"version-indicator update-needed\" id\u003d\"versionIndicator\" style\u003d\"display: none;\"\u003e\n        \u003ci class\u003d\"fas fa-arrow-right\"\u003e\u003c/i\u003e\n      \u003c/div\u003e\n\n      \u003cdiv class\u003d\"version-card latest-version\"\u003e\n        \u003cdiv class\u003d\"version-status status-latest\" id\u003d\"latestStatus\"\u003e最新版本\u003c/div\u003e\n        \u003ch3\u003e\u003ci class\u003d\"fas fa-star\"\u003e\u003c/i\u003e 最新版本\u003c/h3\u003e\n        \u003cdiv class\u003d\"version-number\" id\u003d\"latestVersion\"\u003e-\u003c/div\u003e\n        \u003cdiv class\u003d\"version-date\"\u003e可用最新版本\u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n\n    \u003cdiv class\u003d\"content-container\"\u003e\n      \u003cdiv class\u003d\"status-alert\" id\u003d\"statusAlert\" style\u003d\"display: none;\"\u003e\u003c/div\u003e\n\n      \u003cdiv id\u003d\"latestLogContainer\" style\u003d\"display: none;\"\u003e\n        \u003cdiv class\u003d\"update-container\"\u003e\n          \u003cdiv class\u003d\"update-header\"\u003e\n            \u003ch2\u003e\u003ci class\u003d\"fas fa-bolt\"\u003e\u003c/i\u003e 最新更新\u003c/h2\u003e\n            \u003cdiv class\u003d\"update-tag\"\u003e最新发布\u003c/div\u003e\n          \u003c/div\u003e\n          \u003cdiv class\u003d\"update-content\"\u003e\n            \u003cdiv class\u003d\"update-date\" id\u003d\"latestLogDate\"\u003e\u003c/div\u003e\n            \u003cdiv class\u003d\"update-text\" id\u003d\"latestLogContent\"\u003e\u003c/div\u003e\n          \u003c/div\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n\n      \u003cdiv class\u003d\"button-group\" id\u003d\"buttonGroup\" style\u003d\"display: none;\"\u003e\u003c/div\u003e\n\n      \u003cdiv class\u003d\"history-container\" id\u003d\"logs\" style\u003d\"display: none;\"\u003e\n        \u003cdiv class\u003d\"history-header\" onclick\u003d\"toggleLogs()\"\u003e\n          \u003ch2\u003e\u003ci class\u003d\"fas fa-history\"\u003e\u003c/i\u003e 历史更新 \u003cspan id\u003d\"historyCount\"\u003e\u003c/span\u003e\u003c/h2\u003e\n          \u003cbutton class\u003d\"toggle-history\" id\u003d\"toggleButton\"\u003e\n            \u003cspan id\u003d\"toggleText\"\u003e展开历史\u003c/span\u003e\n            \u003ci class\u003d\"fas fa-chevron-down\" id\u003d\"toggleIcon\"\u003e\u003c/i\u003e\n          \u003c/button\u003e\n        \u003c/div\u003e\n        \u003cdiv class\u003d\"history-content\" id\u003d\"logList\"\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\n  \u003cscript\u003e\n  let logsCollapsed \u003d true;\n\n  function toggleLogs() {\n    logsCollapsed \u003d !logsCollapsed;\n    const logList \u003d document.getElementById(\u0027logList\u0027);\n    const toggleText \u003d document.getElementById(\u0027toggleText\u0027);\n    const toggleIcon \u003d document.getElementById(\u0027toggleIcon\u0027);\n    \n    if (logsCollapsed) {\n      logList.classList.remove(\u0027expanded\u0027);\n      toggleText.textContent \u003d \u0027展开历史\u0027;\n      toggleIcon.className \u003d \u0027fas fa-chevron-down\u0027;\n    } else {\n      logList.classList.add(\u0027expanded\u0027);\n      toggleText.textContent \u003d \u0027收起历史\u0027;\n      toggleIcon.className \u003d \u0027fas fa-chevron-up\u0027;\n    }\n  }\n\n  (async function() {\n    const loading \u003d document.getElementById(\u0027loading\u0027);\n    const container \u003d document.getElementById(\u0027container\u0027);\n    const currentVersion \u003d document.getElementById(\u0027currentVersion\u0027);\n    const latestVersion \u003d document.getElementById(\u0027latestVersion\u0027);\n    const currentStatus \u003d document.getElementById(\u0027currentStatus\u0027);\n    const latestStatus \u003d document.getElementById(\u0027latestStatus\u0027);\n    const versionIndicator \u003d document.getElementById(\u0027versionIndicator\u0027);\n    const statusAlert \u003d document.getElementById(\u0027statusAlert\u0027);\n    const buttonGroup \u003d document.getElementById(\u0027buttonGroup\u0027);\n    const latestLogContainer \u003d document.getElementById(\u0027latestLogContainer\u0027);\n    const latestLogDate \u003d document.getElementById(\u0027latestLogDate\u0027);\n    const latestLogContent \u003d document.getElementById(\u0027latestLogContent\u0027);\n    const logsContainer \u003d document.getElementById(\u0027logs\u0027);\n    const logList \u003d document.getElementById(\u0027logList\u0027);\n    const historyCount \u003d document.getElementById(\u0027historyCount\u0027);\n\n    const localVer \u003d \u0027${String(localVersion)}\u0027;\n\n    // 统一的服务器配置 - 方便维护\n    const serverConfig \u003d {\n      main: {\n        name: \u0027主线路\u0027,\n        icon: \u0027rocket\u0027,\n        baseUrl: \u0027https://sy.gyks.cf\u0027,\n        downloadPath: \u0027/download/晴天订阅源.json\u0027\n      },\n      backup1: {\n        name: \u0027备用线路1\u0027,\n        icon: \u0027box\u0027,\n        baseUrl: \u0027http://v1.gyks.cf\u0027,\n        downloadPath: \u0027/sy/download/晴天订阅源.json\u0027\n      },\n      backup2: {\n        name: \u0027备用线路2\u0027,\n        icon: \u0027satellite\u0027,\n        baseUrl: \u0027http://v2.gyks.cf\u0027,\n        downloadPath: \u0027/sy/download/晴天订阅源.json\u0027\n      },\n      backup3: {\n        name: \u0027备用线路3\u0027,\n        icon: \u0027link\u0027,\n        baseUrl: \u0027http://v3.gyks.cf\u0027,\n        downloadPath: \u0027/sy/download/晴天订阅源.json\u0027\n      },\n      backup4: {\n        name: \u0027备用线路4\u0027,\n        icon: \u0027bolt\u0027,\n        baseUrl: \u0027http://v4.gyks.cf\u0027,\n        downloadPath: \u0027/sy/download/晴天订阅源.json\u0027\n      },\n      backup5: {\n        name: \u0027备用线路5\u0027,\n        icon: \u0027globe\u0027,\n        baseUrl: \u0027http://v5.gyks.cf\u0027,\n        downloadPath: \u0027/sy/download/晴天订阅源.json\u0027\n      },\n      backup6: {\n        name: \u0027备用线路6\u0027,\n        icon: \u0027broadcast-tower\u0027,\n        baseUrl: \u0027http://101.35.133.34:8888\u0027,\n        downloadPath: \u0027/sy/download/晴天订阅源.json\u0027\n      }\n    };\n\n    // 版本比较函数\n    function compareVersions(vs) {\n      const normalize \u003d (v) \u003d\u003e {\n        return v.split(\u0027.\u0027).map(n \u003d\u003e {\n          const num \u003d parseInt(n, 10);\n          return isNaN(num) ? 0 : num;\n        });\n      };\n\n      const parts1 \u003d normalize(localVer);\n      const parts2 \u003d normalize(vs);\n      const maxLength \u003d Math.max(parts1.length, parts2.length);\n      \n      for (let i \u003d 0; i \u003c maxLength; i++) {\n        const num1 \u003d parts1[i] || 0;\n        const num2 \u003d parts2[i] || 0;\n        if (num1 \u003e num2) return 1;\n        if (num1 \u003c num2) return -1;\n      }\n      return 0;\n    }\n\n    async function fetchVersionData() {\n      // 使用统一配置中除主线路外的备用线路进行版本检查\n      const serversToCheck \u003d Object.values(serverConfig).filter(s \u003d\u003e s.baseUrl.includes(\u0027gyks.cf\u0027) || s.baseUrl.includes(\u0027101.35\u0027));\n      \n      for (const server of serversToCheck) {\n        try {\n          const response \u003d await fetch(server.baseUrl + \u0027/version\u0027, { timeout: 2000 });\n          if (response.ok) {\n            return await response.json();\n          }\n        } catch (e) {\n          console.warn(\\`接口失败：\\${server.baseUrl}\\`, e);\n        }\n      }\n      throw new Error(\u0027所有更新接口都请求失败\u0027);\n    }\n\n    function showError(message) {\n      loading.innerHTML \u003d \\`\n        \u003cdiv class\u003d\"error-state\"\u003e\n          \u003cdiv class\u003d\"error-icon\"\u003e\u003ci class\u003d\"fas fa-exclamation-triangle\"\u003e\u003c/i\u003e\u003c/div\u003e\n          \u003cdiv class\u003d\"error-text\"\u003e\\${message}\u003c/div\u003e\n          \u003cbutton class\u003d\"retry-button\" onclick\u003d\"location.reload()\"\u003e\u003ci class\u003d\"fas fa-redo\"\u003e\u003c/i\u003e 重试\u003c/button\u003e\n        \u003c/div\u003e\n      \\`;\n    }\n\n    try {\n      const data \u003d await fetchVersionData();\n      const cloudVersion \u003d String(data.rssVersion3);\n      const updateLog \u003d data.update_rss_log || {};\n\n      // 显示版本信息\n      currentVersion.textContent \u003d \\`v\\${localVer}\\`;\n      latestVersion.textContent \u003d \\`v\\${cloudVersion}\\`;\n\n      // 处理日志\n      const logEntries \u003d Object.entries(updateLog);\n      if (logEntries.length \u003e 0) {\n        // 显示最新日志\n        const [latestDate, latestContent] \u003d logEntries[0];\n        latestLogDate.innerHTML \u003d \\`\u003ci class\u003d\"fas fa-calendar-alt\"\u003e\u003c/i\u003e \\${latestDate}\\`;\n        latestLogContent.textContent \u003d latestContent;\n        latestLogContainer.style.display \u003d \u0027block\u0027;\n\n        // 显示历史日志\n        if (logEntries.length \u003e 1) {\n          const historyLogs \u003d logEntries.slice(1);\n          historyCount.textContent \u003d \\`(\\${historyLogs.length}条)\\`;\n          logList.innerHTML \u003d historyLogs.map(([date, content]) \u003d\u003e \\`\n            \u003cdiv class\u003d\"history-item\"\u003e\n              \u003cdiv class\u003d\"history-date\"\u003e\n                \u003ci class\u003d\"fas fa-calendar-day\"\u003e\u003c/i\u003e\n                \u003cspan\u003e\\${date}\u003c/span\u003e\n              \u003c/div\u003e\n              \u003cdiv class\u003d\"history-text\"\u003e\\${content}\u003c/div\u003e\n            \u003c/div\u003e\n          \\`).join(\u0027\u0027);\n          logsContainer.style.display \u003d \u0027block\u0027;\n        }\n      }\n\n      // 检查更新状态\n      const compareResult \u003d compareVersions(cloudVersion);\n      \n      // 显示版本指示器\n      versionIndicator.style.display \u003d \u0027flex\u0027;\n      \n      if (compareResult \u003d\u003d\u003d -1) {\n        // 需要更新\n        currentStatus.textContent \u003d \u0027待更新\u0027;\n        currentStatus.className \u003d \u0027version-status status-outdated\u0027;\n        versionIndicator.className \u003d \u0027version-indicator update-needed\u0027;\n        versionIndicator.innerHTML \u003d \u0027\u003ci class\u003d\"fas fa-arrow-right\"\u003e\u003c/i\u003e\u0027;\n\n        // 使用统一配置生成下载按钮\n        buttonGroup.innerHTML \u003d Object.values(serverConfig).map(server \u003d\u003e {\n          const fullUrl \u003d server.baseUrl + server.downloadPath;\n          return \\`\n            \u003ca href\u003d\"legado://import/auto?src\u003d\\${encodeURIComponent(fullUrl)}\" class\u003d\"button\"\u003e\n              \u003ci class\u003d\"fas fa-\\${server.icon}\"\u003e\u003c/i\u003e\n              \u003cspan\u003e\\${server.name}\u003c/span\u003e\n            \u003c/a\u003e\n          \\`;\n        }).join(\u0027\u0027);\n        buttonGroup.style.display \u003d \u0027flex\u0027;\n      } else {\n        // 已是最新版本\n        currentStatus.textContent \u003d \u0027最新\u0027;\n        currentStatus.className \u003d \u0027version-status status-latest\u0027;\n        versionIndicator.className \u003d \u0027version-indicator is-latest\u0027;\n        versionIndicator.innerHTML \u003d \u0027\u003ci class\u003d\"fas fa-check\"\u003e\u003c/i\u003e\u0027;\n        \n        statusAlert.className \u003d \u0027status-alert up-to-date\u0027;\n        statusAlert.innerHTML \u003d \u0027\u003ci class\u003d\"fas fa-check-circle\"\u003e\u003c/i\u003e \u003cdiv\u003e您已是最新版本\u003c/div\u003e\u0027;\n        statusAlert.style.display \u003d \u0027flex\u0027;\n      }\n\n      // 显示主容器，隐藏加载\n      loading.style.display \u003d \u0027none\u0027;\n      container.style.display \u003d \u0027block\u0027;\n\n    } catch (err) {\n      console.error(\u0027版本检查失败：\u0027, err);\n      showError(\u0027\u003ci class\u003d\"fas fa-exclamation-circle\"\u003e\u003c/i\u003e 检查更新失败，请稍后重试\u003cbr\u003e\u003csmall\u003e\u0027 + err.message + \u0027\u003c/small\u003e\u0027);\n    }\n  })();\n  \u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n`;\n    java.startBrowser(`data:text/html;base64,${java.base64Encode(html)}`, \u0027晴天订阅源更新\u0027);\n}","loginUi":"[{\"name\": \"邮箱\", \"type\": \"text\"},\n        {\"name\": \"密码\", \"type\": \"password\"},\n        {\n            \"name\": \"♥UI登录书源\",\n            \"type\": \"button\",\n            \"action\": \"login(true)\",\n            \"style\": {\n                \"layout_flexGrow\": 1,\n                \"layout_flexBasisPercent\": 0.4\n            }\n        },\n        {\n            \"name\": \"♥网页登录书源\",\n            \"type\": \"button\",\n            \"action\": \"loginqt()\",\n            \"style\": {\n                \"layout_flexGrow\": 1,\n                \"layout_flexBasisPercent\": 0.4\n            }\n            }, {\n            \"name\": \"🍅番茄登录\",\n            \"type\": \"button\",\n            \"action\": \"fq_login()\",\n            \"style\": {\n                \"layout_flexGrow\": 1,\n                \"layout_flexBasisPercent\": 0.4\n            }\n        }, {\n            \"name\": \"🔮 检测登录\",\n            \"type\": \"button\",\n            \"action\": \"checkStatus()\",\n            \"style\": {\n                \"layout_flexGrow\": 1,\n                \"layout_flexBasisPercent\": 0.4\n            }\n\n        },\n        {\n            \"name\": \" 🔚 退出登录\",\n            \"type\": \"button\",\n            \"action\": \"logout()\",\n            \"style\": {\n                \"layout_flexGrow\": 1,\n                \"layout_flexBasisPercent\": 0.4\n            }\n        }, {\n            \"name\": \" 🗑 清除设备\",\n            \"type\": \"button\",\n            \"action\": \"clearDevice()\",\n            \"style\": {\n                \"layout_flexGrow\": 1,\n                \"layout_flexBasisPercent\": 0.4\n            }\n\n        },{\n            \"name\": \"♻️ 订阅源更新\",\n            \"type\": \"button\",\n            \"action\": \"renderVersionPage()\",\n            \"style\": {\n                \"layout_flexGrow\": 1,\n                \"layout_flexBasisPercent\": 0.4\n            }\n        },{\n            \"name\": \"☕打赏享福利\",\n            \"type\": \"button\",\n            \"action\": \"vip()\",\n            \"style\": {\n                \"layout_flexGrow\": 1,\n                \"layout_flexBasisPercent\": 0.4\n            }\n        },\n  {\n    \ttype: \"text\",\n    \tname: \"番茄Token\"\n  }\n]","sortUrl":"晴天发现::晴天\n番茄::番茄\n塔读::https://m.tadu.com/\n书旗::https://t.shuqi.com/\n七猫::https://www.qimao.com/\n轻小说::https://www.huanmengacg.com/","singleUrl":false,"articleStyle":0,"ruleArticles":"\u003cjs\u003e\nif (baseUrl.includes(\u0027番茄\u0027)) {\nlet ck \u003d (String(cookie.getKey(\"fanqienovel.com\", \"sessionid\")) ? String(cookie.getKey(\"fanqienovel.com\", \"sessionid\")) : (source.getLoginInfoMap() || {})[\u0027番茄Token\u0027]) || \"\";\nfunction getCellId() {\n  let sInfo \u003d java.ajax(java.log(base_url + \"/book_mall_tab?ssionid\u003d\" + ck));\n  let cell_id \u003d \"cell_id%253D6914906572011339784%2526\"\n  let body \u003d JSON.parse(sInfo).data.tab_item[0].cell_data[1].cell_data\n  for (let i of body) {\n    /*java.log(JSON.stringify(i))*/\n     if (typeof i.cell_url !\u003d\u003d \u0027undefined\u0027) {\n       // java.log(i.cell_url)\n       cell_id \u003d i.cell_url\n       break\n     }\n  }\n  java.log(cell_id)\n  cell_id \u003d cell_id.split(\"cell_id%253D\")[1].split(\"%2526\")[0]\n  java.log(cell_id)\n  return cell_id\n}\nlet cell_id \u003d getCellId();\njava.ajax(java.log(base_url + \u0027/book_mall_y?cell_id\u003d\u0027 + cell_id + \u0027\u0026ssionid\u003d\u0027+ck));\n} else if (baseUrl.includes(\u0027晴天\u0027)) {\n\tlet other \u003d {\n\t\t\u0027data\u0027:{\u0027cell_view\u0027:{\u0027topic_data\u0027:\n\t\t[{\u0027topic_desc\u0027:{\n\t\t\t\u0027topic_title\u0027:\u0027晴天多来源发现平台\u0027,\n\t\t\t \u0027topic_id\u0027:\u0027http://v1.gyks.cf/online_search\u0027\n\t\t\t}},{\u0027topic_desc\u0027:{\n\t\t\t\u0027topic_title\u0027:\u0027晴天推书\u0027,\n\t\t\t \u0027topic_id\u0027:\u0027http://v1.gyks.cf/put_book\u0027\n\t\t\t}},{\u0027topic_desc\u0027:{\n\t\t\t\u0027topic_title\u0027:\u0027晴天后台\u0027,\n\t\t\t \u0027topic_id\u0027:\u0027http://v1.gyks.cf/login\u0027\n\t\t\t}},{\u0027topic_desc\u0027:{\n\t\t\t\u0027topic_title\u0027:\u0027求打赏~\u0027,\n\t\t\t \u0027topic_id\u0027:\u0027http://v1.gyks.cf/coffee\u0027\n\t\t\t}}]}\n\t\t}}\n\t\tother \u003d JSON.stringify(other);\n\n\t} else {\n\t//java.toast(baseUrl);\n\tlet other \u003d {\n\t\t\u0027data\u0027:{\u0027cell_view\u0027:{\u0027topic_data\u0027:\n\t\t[{\u0027topic_desc\u0027:{\n\t\t\t\u0027topic_title\u0027:\u0027进入官网，支持点击书籍跳转阅读书架哦～\u0027,\n\t\t\t \u0027topic_id\u0027:baseUrl\n\t\t\t}}]}\n\t\t}}\n\t\tother \u003d JSON.stringify(other);\n\t\t//java.toast(other)\n\t};\n\t\u003c/js\u003e\n$.data.cell_view.topic_data[*]","ruleTitle":"$.topic_desc.topic_title","rulePubDate":"$.topic_desc.topic_content\n@js:\nif (baseUrl.includes(\u0027番茄\u0027)) {\n\tlet data \u003d JSON.parse(result).skeleton.data.replace(/\u003c\\/?search_link\u003e/g, \" \")\nlet select \u003d Packages.org.jsoup.Jsoup.parse(data).select(\"p, span\")\nlet final \u003d Array.from(select).map(p \u003d\u003e p.text()).join(\" \")\njava.timeFormat(java.getString(\u0027topic_desc.create_time\u0027)*1000) + (!Packages.android.text.TextUtils.isEmpty(final) ? (\u0027 | \u0027 + final) : \u0027\u0027)\n}","ruleImage":"$.topic_desc.topic_cover","ruleLink":"\u003cjs\u003e\nlet ruleUrl;\nif (baseUrl.includes(\u0027番茄\u0027)) { \n\truleUrl \u003d `https://reading.snssdk.com/wap/topic-share.html?topic_id\u003d{{$.topic_desc.topic_id}}\u0026sort\u003dsmart_hot\u0026service_id\u003d6\u0026session_id\u003d0\u0026aid\u003d1967`\n\t} else {\n\t\truleUrl \u003d \u0027{{$.topic_desc.topic_id}}\u0027;\n\t\t//java.toast(ruleUrl)\n\t\t}\n\truleUrl\n\u003c/js\u003e","shouldOverrideUrlLoading":"function extractBookId(url) {\n    let match \u003d url.match(/[?\u0026]book_id\u003d([^\u0026]+)/) || url.match(/page\\/(\\d+)/) || url.match(/shuku\\/(\\d+_\\d+|\\d+)(?:-\\d+)?/) || url.match(/query\\/(\\d+)/) || url.match(/book\\/(\\d+)/) || url.match(/album\\/(\\d+)/) || url.match(/reader\\/(\\d+)/) || url.match(/book-detail\\/(\\d+)/) || url.match(/info\\/(\\d+)/);    \n   if (!match) {\n    \t     return null;\n   }\n    let bookId \u003d match[1];\n    if (url.includes(\u0027huanmengacg\u0027)) {\n    \t  let name \u003d url.split(\u0027##\u0027)[1];\n    \t   bookId \u003d `{\"name\":\"${decodeURIComponent(name)}\",\"t\":\"search\",\"url\":\"https://hm.gyks.cf/api/v1/books/${bookId}\",\"variable\":\"\"}`;\n    \t  bookId \u003d bookId.replace(\u0027\u003d\u0027,\u0027\u0027)\n    \t}\n    return bookId;\n}\n\n// java.toast(url.startsWith(\u0027legadosearch://\u0027))\nif (url.startsWith(\u0027legadosearch://\u0027)) { \n  // java.toast(\u0027ab\u0027)\n  java.searchBook(\n    decodeURIComponent(\n      url.replace(\u0027legadosearch://\u0027, \u0027\u0027)\n    )\n  )\n}\nlet needBreak \u003d false\n\n\t  if (url.match(/book_id\u003d\\d+/) || url.match(/\\/page\\/\\d+/) || url.match(/shuku\\/(\\d+_\\d+|\\d+)(?:-\\d+)?/) || url.match(/query\\/(\\d+)/) || url.match(/book\\/(\\d+)/) || url.match(/album\\/(\\d+)/) || url.match(/reader\\/(\\d+)/) || url.match(/book-detail\\/(\\d+)/) || url.includes(\u0027online_detail\u0027) || url.includes(\u0027book/info\u0027)) {\n  \t//java.toast(url);\n  \t const bookId \u003d java.encodeURI(java.base64Encode(extractBookId(url)));\n  \t //java.toast(bookId);\n  \t let url2 \u003d `${base_url}/detail?book_id\u003d${bookId}\u0026source\u003d番茄`\n  \t if (url.includes(\u0027shuku\u0027)) {\n  \t \turl2 \u003d `${base_url}/detail?book_id\u003d${bookId}\u0026source\u003d七猫`\n  \t \t}\n  \t \tif (url.includes(\u0027tadu\u0027)) {\n  \t \turl2 \u003d `${base_url}/detail?book_id\u003d${bookId}\u0026source\u003d塔读`\n  \t \t}\n  \t \tif (url.includes(\u0027shuqi\u0027)) {\n  \t \turl2 \u003d `${base_url}/detail?book_id\u003d${bookId}\u0026source\u003d书旗`\n  \t \t}\n  \t \tif (url.includes(\u0027lrts\u0027)) {\n  \t \turl2 \u003d `${base_url}/detail?book_id\u003d${bookId}\u0026source\u003d懒人听书\u0026tab\u003d听书`\n  \t \t}\n  \t \tif (url.includes(\u0027qq\u0027)) {\n  \t \turl2 \u003d `${base_url}/detail?book_id\u003d${bookId}\u0026source\u003dQQ`\n  \t \t}\n  \t \tif (url.includes(\u0027huanmengacg\u0027)) {\n  \t \turl2 \u003d `${base_url}/detail?book_id\u003d${bookId}\u0026source\u003d幻梦轻小说\u0026tab\u003d小说`\n   \t \t}\n  \t \tif (url.includes(\u0027online_detail\u0027)) {\n  \t \turl2 \u003d url.replace(\u0027online_detail\u0027,\u0027detail\u0027)\n  \t \t}\n  \t //java.toast(url2.replace(\u0027%3D\u0027,\u0027\u0027));\n  \t java.addBook(url2.replace(\u0027%3D\u0027,\u0027\u0027));\n    needBreak \u003d true;\n  }\n\n!(url.startsWith(\u0027http\u0027) || url.startsWith(\u0027legado\u0027)) || url.match(/\\/chapter-list\\/\\d+/) || needBreak","enableJs":true,"loadWithBaseUrl":false,"injectJs":"const host \u003d document.location.host;\n\n// 获取书名信息 - 优化版本\nfunction getBookName(element) {\n    // 1. 首先尝试从图片alt属性获取（最直接）\n    const img \u003d element.querySelector(\u0027img\u0027);\n    if (img \u0026\u0026 img.alt \u0026\u0026 img.alt.trim()) {\n        const altText \u003d img.alt.trim();\n        // 可以进一步清理alt文本（如有需要）\n        // 例如：移除重复的\"-\"或特殊格式\n        return altText;\n    }\n    \n    // 2. 尝试从dt元素获取\n    const dtElement \u003d element.querySelector(\u0027dt\u0027) || \n                     element.parentElement?.querySelector(\u0027dt\u0027);\n    if (dtElement \u0026\u0026 dtElement.textContent \u0026\u0026 dtElement.textContent.trim()) {\n        return dtElement.textContent.trim();\n    }\n    \n    // 3. 尝试其他选择器\n    const selectors \u003d [\n        \u0027.common-info dt\u0027,\n        \u0027.book-title\u0027,\n        \u0027h1, h2, h3, h4\u0027,\n        \u0027[class*\u003d\"title\"]\u0027,\n        \u0027[class*\u003d\"name\"]\u0027\n    ];\n    \n    for (const selector of selectors) {\n        const titleElement \u003d element.closest(selector) || \n                           element.querySelector(selector) || \n                           element.parentElement?.querySelector(selector);\n        \n        if (titleElement \u0026\u0026 titleElement.textContent \u0026\u0026 titleElement.textContent.trim()) {\n            return titleElement.textContent.trim();\n        }\n    }\n    \n    // 最后尝试从元素文本本身获取\n    return element.textContent?.trim() || \n           element.parentElement?.textContent?.trim() || \n           \u0027未知书名\u0027;\n}\n// 拦截导航\nfunction interceptNavigation(event) {\n    event.preventDefault();\n    event.stopPropagation();\n    event.stopImmediatePropagation();\n    \n    let targetUrl \u003d \u0027\u0027;\n    const element \u003d event.currentTarget;\n    \n    // 1. 处理a标签\n    if (element.tagName.toLowerCase() \u003d\u003d\u003d \u0027a\u0027 \u0026\u0026 element.href) {\n        targetUrl \u003d element.href;\n    }\n    // 2. 处理带onclick的元素\n    else if (element.onclick || element.getAttribute(\u0027onclick\u0027)) {\n        const onclickValue \u003d element.onclick?.toString() || element.getAttribute(\u0027onclick\u0027);\n        const urlMatch \u003d onclickValue.match(/window\\.location\\.href\\s*\u003d\\s*[\u0027\"]([^\u0027\"]+)[\u0027\"]/);\n        if (urlMatch) {\n            targetUrl \u003d urlMatch[1];\n        }\n    }\n    \n    if (!targetUrl) {\n        console.warn(\u0027未找到跳转URL\u0027);\n        return true;\n    }\n    \n    // 构建最终URL\n    let finalUrl \u003d targetUrl;\n    \n    // 检查是否为huanmengacg域名\n    if (host.includes(\u0027huanmengacg\u0027)) {\n        const bookName \u003d getBookName(element);\n        \n        // 添加书名查询参数和##分隔符后的书名（不进行编码）\n        const separator \u003d finalUrl.includes(\u0027?\u0027) ? \u0027\u0026\u0027 : \u0027?\u0027;\n        finalUrl \u003d `${finalUrl}${separator}book_name\u003d${bookName}##${bookName}`;\n        \n        console.log(\u0027添加书名的URL:\u0027, finalUrl);\n    }\n    \n    // 跳转到处理后的URL\n    window.location.href \u003d finalUrl;\n    \n    return false;\n}\n\n// 为现有元素添加拦截\nfunction addInterceptors() {\n    // 1. 拦截所有a标签\n    document.querySelectorAll(\u0027a[href]\u0027).forEach(link \u003d\u003e {\n        // 避免重复绑定\n        if (!link.hasAttribute(\u0027data-intercept-bound\u0027)) {\n            link.addEventListener(\u0027click\u0027, interceptNavigation, true);\n            link.setAttribute(\u0027data-intercept-bound\u0027, \u0027true\u0027);\n        }\n    });\n    \n    // 2. 拦截特定卡片类型\n    const cardSelectors \u003d [\n        \u0027.book-card[onclick]\u0027, \n        \u0027div[onclick*\u003d\"window.location.href\"]\u0027, \n        \u0027li[onclick*\u003d\"window.location.href\"]\u0027,\n        \u0027section[onclick*\u003d\"window.location.href\"]\u0027,\n        \u0027.details-part\u0027 // 添加您提供的示例中的类\n    ];\n    \n    cardSelectors.forEach(selector \u003d\u003e {\n        document.querySelectorAll(selector).forEach(card \u003d\u003e {\n            if (!card.hasAttribute(\u0027data-intercept-bound\u0027)) {\n                card.addEventListener(\u0027click\u0027, interceptNavigation, true);\n                card.setAttribute(\u0027data-intercept-bound\u0027, \u0027true\u0027);\n            }\n        });\n    });\n}\n\n// 使用MutationObserver监控DOM变化\nconst observer \u003d new MutationObserver(function(mutations) {\n    mutations.forEach(() \u003d\u003e {\n        addInterceptors(); // DOM变化时重新绑定拦截器\n    });\n});\n\n// 开始观察文档\nobserver.observe(document.body, {\n    childList: true,    // 监控子节点变化\n    subtree: true,      // 监控所有后代节点\n    attributes: true,   // 监控属性变化\n    attributeFilter: [\u0027onclick\u0027, \u0027href\u0027, \u0027class\u0027] // 只监控这些属性\n});\n\n// 初始执行一次拦截器绑定\naddInterceptors();\nshowNotification(\u0027拦截器成功启动！\u0027);\n\nfunction showNotification(message, type \u003d \u0027success\u0027, duration \u003d 2000) {\n    // 创建样式（如果不存在）\n    if (!document.getElementById(\u0027notification-styles\u0027)) {\n        const style \u003d document.createElement(\u0027style\u0027);\n        style.id \u003d \u0027notification-styles\u0027;\n        style.textContent \u003d `\n            .notification {\n                position: fixed;\n                top: 20px;\n                right: 20px;\n                padding: 15px 25px;\n                color: white;\n                border-radius: 8px;\n                box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);\n                display: flex;\n                align-items: center;\n                transform: translateX(150%);\n                opacity: 0;\n                transition: all 0.3s ease;\n                z-index: 1000;\n                font-family: \u0027Arial\u0027, sans-serif;\n            }\n            \n            .notification.show {\n                transform: translateX(0);\n                opacity: 1;\n            }\n            \n            .notification.hide {\n                transform: translateX(150%);\n                opacity: 0;\n            }\n            \n            .notification-icon {\n                margin-right: 10px;\n                font-size: 20px;\n            }\n            \n            .notification-content {\n                font-size: 16px;\n            }\n            \n            .notification.success {\n                background-color: #4CAF50;\n            }\n            \n            .notification.error {\n                background-color: #f44336;\n            }\n            \n            .notification.warning {\n                background-color: #ff9800;\n            }\n            \n            .notification.info {\n                background-color: #2196F3;\n            }\n        `;\n        document.head.appendChild(style);\n    }\n\n    // 创建通知元素\n    const notification \u003d document.createElement(\u0027div\u0027);\n    notification.className \u003d `notification ${type}`;\n    \n    // 添加图标\n    const icon \u003d document.createElement(\u0027span\u0027);\n    icon.className \u003d \u0027notification-icon\u0027;\n    \n    // 根据类型设置不同图标\n    const icons \u003d {\n        success: \u0027✓\u0027,\n        error: \u0027✕\u0027,\n        warning: \u0027⚠\u0027,\n        info: \u0027ℹ\u0027\n    };\n    icon.textContent \u003d icons[type] || \u0027✓\u0027;\n    \n    // 添加消息内容\n    const content \u003d document.createElement(\u0027span\u0027);\n    content.className \u003d \u0027notification-content\u0027;\n    content.textContent \u003d message;\n    \n    // 组装通知\n    notification.appendChild(icon);\n    notification.appendChild(content);\n    \n    // 添加到body\n    document.body.appendChild(notification);\n    \n    // 显示通知\n    setTimeout(() \u003d\u003e {\n        notification.classList.add(\u0027show\u0027);\n    }, 10);\n    \n    // 指定时间后隐藏并移除通知\n    setTimeout(() \u003d\u003e {\n        notification.classList.remove(\u0027show\u0027);\n        notification.classList.add(\u0027hide\u0027);\n        \n        // 动画结束后移除元素\n        notification.addEventListener(\u0027transitionend\u0027, () \u003d\u003e {\n            notification.remove();\n        });\n    }, duration);\n}\n\n// 初始化通知\nshowNotification(\u0027欢迎使用晴天订阅源！\u0027);\n\n\n\nconst path \u003d document.location.pathname;\nconst params \u003d new URLSearchParams(window.location.search);\nconst currentUrl \u003d window.location.href;\nconst url \u003d new URL(currentUrl);\n\n// 域名重定向\nif (host \u003d\u003d\u003d \u0027changdunovel.com\u0027 \u0026\u0026 path.endsWith(\u0027share-v2.html\u0027)) {\n  const bookid \u003d params.get(\u0027book_id\u0027);\n  if (bookid) {\n    document.location.href \u003d `https://fanqienovel.com/page/${bookid}`;\n  }\n}\n\nconst adBlockSystem \u003d setInterval(() \u003d\u003e {\n  const shouldSkip \u003d (el) \u003d\u003e {\n    return el.closest(\u0027.horizontal-slip-modal-card\u0027) || \n           el.closest(\u0027.topic-comment-item.new-card-style\u0027);\n  };\n document.querySelectorAll(\u0027.page-reader-btn.download, .download-btn, .app-download-popup, .download-app\u0027)\n    .forEach(el \u003d\u003e {\n      if (!shouldSkip(el) \u0026\u0026 el.textContent.match(/下载|APP|安装/)) {\n        el.remove();\n      }\n    });\n  document.querySelectorAll(\u0027.mask, .popup-layer, .modal-backdrop, .popup-container\u0027)\n    .forEach(el \u003d\u003e {\n      if (!shouldSkip(el)) {\n        el.remove();\n      }\n    });\n  document.querySelectorAll(\u0027.float-ad, .bottom-ad, .fixed-ad\u0027)\n    .forEach(ad \u003d\u003e {\n      if (!shouldSkip(ad)) {\n        ad.remove();\n      }\n    });\n}, 500);\n\nconst fixBookClick \u003d setInterval(() \u003d\u003e {\n  const shouldSkip \u003d (el) \u003d\u003e {\n    return el.closest(\u0027.horizontal-slip-modal-card\u0027) || \n           el.closest(\u0027.topic-comment-item.new-card-style\u0027);\n  };\n  \n  document.querySelectorAll(\u0027.horizontal-slip-books-item\u0027).forEach(item \u003d\u003e {\n    if (shouldSkip(item)) return;\n    \n    item.style.pointerEvents \u003d \u0027auto\u0027;\n    item.style.cursor \u003d \u0027pointer\u0027;\n    \n    if (item.id \u0026\u0026 !item.hasAttribute(\u0027data-click-fixed\u0027)) {\n      item.setAttribute(\u0027data-click-fixed\u0027, \u0027true\u0027);\n      item.addEventListener(\u0027click\u0027, (e) \u003d\u003e {\n        e.preventDefault();\n        window.location.href \u003d `https://fanqienovel.com/page/${item.id}`;\n      });\n    }\n  });\n  \n  document.querySelectorAll(\u0027div.books-fold-card-book-item.marrow-book-item\u0027).forEach(item \u003d\u003e {\n    if (shouldSkip(item)) return;\n    \n    item.style.pointerEvents \u003d \u0027auto\u0027;\n    item.style.cursor \u003d \u0027pointer\u0027;\n    \n    const bookId \u003d item.getAttribute(\u0027data-book-id\u0027) || item.id;\n    if (bookId \u0026\u0026 !item.hasAttribute(\u0027data-click-fixed\u0027)) {\n      item.setAttribute(\u0027data-click-fixed\u0027, \u0027true\u0027);\n      item.addEventListener(\u0027click\u0027, (e) \u003d\u003e {\n        e.preventDefault();\n        window.location.href \u003d `https://fanqienovel.com/page/${bookId}`;\n      });\n    }\n  });\n}, 1000);\n\nconst paginationSystem \u003d setInterval(() \u003d\u003e {\n  const shareBottom \u003d document.querySelector(\".share-bottom-button\");\n  const shouldSkip \u003d (el) \u003d\u003e {\n    return el \u0026\u0026 (el.closest(\u0027.horizontal-slip-modal-card\u0027) || \n                 el.closest(\u0027.topic-comment-item.new-card-style\u0027));\n  };\n  \n  if (shareBottom \u0026\u0026 !shouldSkip(shareBottom)) {\n    shareBottom.remove();\n    const shareApp \u003d document.querySelector(\".share-end-href-app\");\n    const offset \u003d Number(url.searchParams.get(\u0027offset\u0027) || \"0\");\n    \n    if (shareApp \u0026\u0026 !shouldSkip(shareApp)) {\n      shareApp.parentNode.innerHTML \u003d `\n        \u003cdiv class\u003d\"share-end-href-app\" style\u003d\"display:flex;justify-content:center;gap:20px;padding:12px 0;\"\u003e\n          ${offset \u003d\u003d\u003d 0 ? \"\" : `\u003ca style\u003d\"padding:8px 16px;border-radius:4px;background:#f0f0f0;color:#333;text-decoration:none;\" onclick\u003d\"changePage(${offset-1}, url)\"\u003e上一页\u003c/a\u003e`}\n          \u003cspan style\u003d\"padding:8px 16px;color:#666;\"\u003e${offset+1}\u003c/span\u003e\n          \u003ca style\u003d\"padding:8px 16px;border-radius:4px;background:#f0f0f0;color:#333;text-decoration:none;\" onclick\u003d\"changePage(${offset+1}, url)\"\u003e下一页\u003c/a\u003e\n        \u003c/div\u003e\n      `;\n    }\n  }\n}, 1000);\n\nfunction changePage(value, url) {\n  url.searchParams.set(\u0027offset\u0027, value);\n  location.replace(url);\n}\n\nconst style \u003d document.createElement(\u0027style\u0027);\nstyle.textContent \u003d `\n  .page-reader-btn.download:not(.horizontal-slip-modal-card *):not(.topic-comment-item.new-card-style *),\n  .download-btn:not(.horizontal-slip-modal-card *):not(.topic-comment-item.new-card-style *),\n  .app-download-popup:not(.horizontal-slip-modal-card *):not(.topic-comment-item.new-card-style *) {\n    display: none !important;\n    visibility: hidden !important;\n    pointer-events: none !important;\n    opacity: 0 !important;\n  }\n  \n  .topic-comment-item:not(.new-card-style):not(.horizontal-slip-modal-card *) {\n    pointer-events: none !important;\n    user-select: none !important;\n  }\n  \n  .horizontal-slip-books-item:not(.horizontal-slip-modal-card *):not(.topic-comment-item.new-card-style *),\n  div.books-fold-card-book-item.marrow-book-item:not(.horizontal-slip-modal-card *):not(.topic-comment-item.new-card-style *) {\n    pointer-events: auto !important;\n    cursor: pointer !important;\n  }\n`;\ndocument.head.appendChild(style);\n\nsetTimeout(() \u003d\u003e {\n  clearInterval(adBlockSystem);\n  clearInterval(fixBookClick);\n}, 30000);","lastUpdateTime":1767079245478,"customOrder":-101053,"userid":"","usertocken":"","phonehttp":false} , {"sourceUrl":"http://vip.gyks.cf","sourceName":"晴天发布页","sourceIcon":"http://v1.gyks.cf/favicon.ico","enabled":true,"enabledCookieJar":true,"singleUrl":true,"articleStyle":0,"enableJs":true,"loadWithBaseUrl":true,"lastUpdateTime":1767078359228,"customOrder":0,"userid":"","usertocken":"","phonehttp":false} , {"sourceUrl":"https://sy.gyks.cf","sourceName":"晴天书源","sourceIcon":"http://v1.gyks.cf/favicon.ico","enabled":true,"enabledCookieJar":true,"singleUrl":true,"articleStyle":0,"enableJs":true,"loadWithBaseUrl":true,"lastUpdateTime":1767078371464,"customOrder":0,"userid":"","usertocken":"","phonehttp":false} ]