晴天书荒广场

https://www.baidu.com/晴天番茄书荒广场

分享者: 晴天 (8653)发布时间: 2天前

https://api.qingtian618.com

需要配合晴天融合完全版书源一起使用,支持直接跳转到对应书籍


4.7.17

新增七猫、塔读、书旗广场
4.7.16
修复bug
4.7.15
新增番茄书荒广场
二维码导入
{
    "articleStyle": 0,
    "customOrder": -101052,
    "enableJs": true,
    "enabled": true,
    "enabledCookieJar": true,
    "injectJs": "const host = document.location.host;\nconst path = document.location.pathname;\nconst params = new URLSearchParams(window.location.search);\nconst currentUrl = window.location.href;\nconst url = new URL(currentUrl);\n\n\/\/ 域名重定向\nif (host === 'changdunovel.com' && path.endsWith('share-v2.html')) {\n  const bookid = params.get('book_id');\n  if (bookid) {\n    document.location.href = `https:\/\/fanqienovel.com\/page\/${bookid}`;\n  }\n}\n\nconst adBlockSystem = setInterval(() => {\n  const shouldSkip = (el) => {\n    return el.closest('.horizontal-slip-modal-card') || \n           el.closest('.topic-comment-item.new-card-style');\n  };\n document.querySelectorAll('.page-reader-btn.download, .download-btn, .app-download-popup, .download-app')\n    .forEach(el => {\n      if (!shouldSkip(el) && el.textContent.match(\/下载|APP|安装\/)) {\n        el.remove();\n      }\n    });\n  document.querySelectorAll('.mask, .popup-layer, .modal-backdrop, .popup-container')\n    .forEach(el => {\n      if (!shouldSkip(el)) {\n        el.remove();\n      }\n    });\n  document.querySelectorAll('.float-ad, .bottom-ad, .fixed-ad')\n    .forEach(ad => {\n      if (!shouldSkip(ad)) {\n        ad.remove();\n      }\n    });\n}, 500);\n\nconst fixBookClick = setInterval(() => {\n  const shouldSkip = (el) => {\n    return el.closest('.horizontal-slip-modal-card') || \n           el.closest('.topic-comment-item.new-card-style');\n  };\n  \n  document.querySelectorAll('.horizontal-slip-books-item').forEach(item => {\n    if (shouldSkip(item)) return;\n    \n    item.style.pointerEvents = 'auto';\n    item.style.cursor = 'pointer';\n    \n    if (item.id && !item.hasAttribute('data-click-fixed')) {\n      item.setAttribute('data-click-fixed', 'true');\n      item.addEventListener('click', (e) => {\n        e.preventDefault();\n        window.location.href = `https:\/\/fanqienovel.com\/page\/${item.id}`;\n      });\n    }\n  });\n  \n  document.querySelectorAll('div.books-fold-card-book-item.marrow-book-item').forEach(item => {\n    if (shouldSkip(item)) return;\n    \n    item.style.pointerEvents = 'auto';\n    item.style.cursor = 'pointer';\n    \n    const bookId = item.getAttribute('data-book-id') || item.id;\n    if (bookId && !item.hasAttribute('data-click-fixed')) {\n      item.setAttribute('data-click-fixed', 'true');\n      item.addEventListener('click', (e) => {\n        e.preventDefault();\n        window.location.href = `https:\/\/fanqienovel.com\/page\/${bookId}`;\n      });\n    }\n  });\n}, 1000);\n\nconst paginationSystem = setInterval(() => {\n  const shareBottom = document.querySelector(\".share-bottom-button\");\n  const shouldSkip = (el) => {\n    return el && (el.closest('.horizontal-slip-modal-card') || \n                 el.closest('.topic-comment-item.new-card-style'));\n  };\n  \n  if (shareBottom && !shouldSkip(shareBottom)) {\n    shareBottom.remove();\n    const shareApp = document.querySelector(\".share-end-href-app\");\n    const offset = Number(url.searchParams.get('offset') || \"0\");\n    \n    if (shareApp && !shouldSkip(shareApp)) {\n      shareApp.parentNode.innerHTML = `\n        <div class=\"share-end-href-app\" style=\"display:flex;justify-content:center;gap:20px;padding:12px 0;\">\n          ${offset === 0 ? \"\" : `<a style=\"padding:8px 16px;border-radius:4px;background:#f0f0f0;color:#333;text-decoration:none;\" onclick=\"changePage(${offset-1}, url)\">上一页<\/a>`}\n          <span style=\"padding:8px 16px;color:#666;\">${offset+1}<\/span>\n          <a style=\"padding:8px 16px;border-radius:4px;background:#f0f0f0;color:#333;text-decoration:none;\" onclick=\"changePage(${offset+1}, url)\">下一页<\/a>\n        <\/div>\n      `;\n    }\n  }\n}, 1000);\n\nfunction changePage(value, url) {\n  url.searchParams.set('offset', value);\n  location.replace(url);\n}\n\nconst style = document.createElement('style');\nstyle.textContent = `\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(() => {\n  clearInterval(adBlockSystem);\n  clearInterval(fixBookClick);\n}, 30000);",
    "jsLib": "var  base_url = \t'https:\/\/api.qingtian618.com';\n\nfunction checkSum(s) {\n  return String(java.lang.String(s).hashCode())\n}\n\nfunction getKey(key) {\n  let parts = key.split(\";\");\n  for (let part of parts) {\n    if (part.includes(\"qttoken\")) {\n      return part.split(\"=\")[1];\n    }\n  }\n  return \"\";\n}\n\nvar javaImport = new JavaImporter();\njavaImport.importClass(\n  Packages.android.util.Base64,\n  Packages.java.lang.String,\n  Packages.java.net.URL,\n  Packages.okhttp3.HttpUrl\n);\nwith (javaImport) {\n  function btoa(data) {\n    return Base64.encodeToString(String(data).getBytes(\"UTF-8\"), 2);\n  }\n\n  function getSubDomain(url) {\n    let baseUrl = getBaseUrl(url);\n    if (!baseUrl) {\n      return url;\n    }\n    try {\n      let mURL = URL(baseUrl);\n      let host = mURL.host;\n      if (isIPAddress(host)) return host;\n      return HttpUrl.parse(baseUrl).topPrivateDomain() || host;\n    } catch (e) {\n      this.java.log(e);\n      return baseUrl;\n    }\n  }\n\n  function getDomain(url) {\n    let baseUrl = getBaseUrl(url);\n    if (!baseUrl) {\n      return url;\n    }\n    try {\n      return URL(baseUrl).host;\n    } catch (e) {\n      return baseUrl;\n    }\n  }\n  \/**\n   * 移除cookie\n   *\/\n  function removeCookie(url) {\n    const { cookie } = this;\n    cookie.removeCookie(url);\n    let domains = [getDomain(url), getSubDomain(url)];\n    domains.forEach((domain) => {\n      cookie.removeCookie(domain);\n    });\n  }\n}\n\nfunction getBaseUrl(url) {\n  if (!url) {\n    return null;\n  }\n  url = String(url);\n  if (url.match(\/https?:\\\/\\\/\/i)) {\n    var index = url.indexOf(\"\/\", 9);\n    return index == -1 ? url : url.substring(0, index);\n  }\n  return null;\n}\n\nfunction isIPv4Address(ip) {\n  ip = String(ip);\n  let parts = ip.split(\".\");\n  if (parts.length !== 4) return false;\n\n  for (let part of parts) {\n    if (!\/^\\d+$\/.test(part)) return false; \/\/ 必须是数字\n    if (part.length > 1 && part[0] === \"0\") return false; \/\/ 禁止前导零\n    let num = parseInt(part, 10);\n    if (num < 0 || num > 255) return false; \/\/ 范围检查\n  }\n  return true;\n}\n\nfunction isIPv6Address(ip) {\n  ip = String(ip);\n  \/\/ 处理双冒号(最多出现一次)\n  if (ip.includes(\":::\")) return false;\n  let doubleColonCount = (ip.match(\/::\/g) || []).length;\n  if (doubleColonCount > 1) return false;\n\n  \/\/ 分割成组\n  let groups = ip.split(\":\");\n  let validGroupCount = 8;\n  let actualGroupCount = groups.filter((g) => g !== \"\").length;\n\n  \/\/ 验证组数\n  if (doubleColonCount === 1) {\n    if (actualGroupCount > validGroupCount - 1) return false;\n  } else {\n    if (groups.length !== validGroupCount) return false;\n  }\n\n  \/\/ 验证每组内容\n  for (let group of groups) {\n    if (group === \"\") 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 = cookieString.match(\/sessionid=([^;]+)\/);\n    return match ? match[1] : null;\n}\n",
    "lastUpdateTime": 0,
    "loadWithBaseUrl": false,
    "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\": \"webLogin()\",\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\": \"renderVersionPageRss()\",\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\": 1\n            }\n        },\n  {\n    \ttype: \"text\",\n    \tname: \"番茄Token\"\n  }\n]",
    "loginUrl": "const localVersion = '4.7.17';\n\nfunction webLogin() {\n    var ck = String(cookie.getKey(\"fanqienovel.com\", \"sessionid\"));\n    if (ck && ck != \"\") {\n        java.toast(\"\\n\\n请不要重复登录,请先退出登录!\")\n        return false\n    } \n    try {\n            java.startBrowserAwait(\"https:\/\/fanqienovel.com\/\", \"登录\")\n    } catch (e) { java.toast(e) }\n  \n    try {\n        cookie.removeCookie(\"snssdk.com\")\n    } catch (e) {}\n    var ck = \"sessionid=\" + String(cookie.getKey(\"fanqienovel.com\", \"sessionid\"));\n    let user\n    try {\n      user = JSON.parse(java.ajax(\"https:\/\/fanqienovel.com\/api\/user\/info\/v2,\" + JSON.stringify({\n        method: \"GET\",\n        headers: {\n          \"Cookie\": ck\n        }\n      }))).data.name\n     } catch (e) {java.log(e)}\n    if (!ck || ck == \"sessionid=\" || !user) {\n        java.toast(\"\\n\\n未获取到登录凭据,登录失败\")\n        cookie.removeCookie(\"fanqienovel.com\")\n        return false\n    }\n    java.toast(\"\\n\\n欢迎 \" + user + \"\\n登录成功!\")\n    return true\n}\n\nfunction login(flag) {\n\tif (flag == undefined) {\n\t\tresult = 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 = String(result['邮箱'])\n\tlet password = String(result['密码'])\n\tlet key = String(result['密钥']||'')\n\t\n\t\/\/java.log(cookie.getCookie(base_url))\n\tif ((register_email && password || key)&& !String(getKey(String(cookie.getCookie(base_url))))) {\n\t\tremoveCookie(base_url)\n\t\tlet deviceKey = java.webView('', '', 'navigator.userAgent+window.screen.width+window.screen.height')\n\t\tif (String(deviceKey) == \"undefined\") {\n\t\t\ttry {\n\t\t\t\tdeviceKey = java.deviceID();\n\t\t\t} catch (e) {\n\t\t\t\tdeviceKey = java.androidId();\n\t\t\t}\n\t\t};\n\tlet deviceId = java.digestHex(deviceKey, \"SHA256\")\n\t\t  if (register_email && password){\n\t\t\tlet options = JSON.stringify({\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: {\n\t\t\t\t\t'Content-Type': 'application\/json'\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tregister_email: result['邮箱'],\n\t\t\t\t\tpassword: result['密码']\n\t\t\t\t})\n\t\t\t})\n\t\t\ttry {\n\t\t\t\tlet data = JSON.parse(java.ajax(`${base_url}\/login_api,${options}`))\n\t\t\t\tif (data.code == 0) {\n\t\t\t\t\tjava.toast(\"\\n\\n✅️登录成功\")\n\t\t\t\t\tcookie.setCookie(base_url, `qttoken=${data.key};deviceId=${deviceId}`)\n\t\t\t\t\tresult['密钥']=data.key\n\t\t\t\t\tputLoginInfo(JSON.stringify(result))\n\t\t\t\t} else {\n\t\t\t\t\tjava.toast('\\n\\n💔'+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=${key};deviceId=${deviceId}`)\n\t\t\tlet res=java.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=JSON.parse(res)\n\t\t\t\tif (res.id!=undefined) {\n\t\t\t\t\tjava.toast('\\n\\n密钥登录成功')\n\t\t\t\t\tresult['邮箱'] = 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&&String(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 checkStatus() {\n\tjava.longToast('\\n\\n♻️检测中...');\n\tlet res=java.ajax(`${base_url}\/user_api,{\"method\":\"POST\",\"headers\":{\"cookie\":\"${cookie.getCookie(base_url)}\"}}`)\t\n\ttry {\n\t\t\t\tres=JSON.parse(res)\n\t\t\t\tif (res.id!=undefined) {\n\t\t\t\t\tresult['邮箱'] = 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 = JSON.parse(res.device).length;\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tdevices = 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==1) {\n\t\t\t\t\t\tisVip = 'VIP';\n\t\t\t\t\t} else if (res.is_vip>=2) {\n\t\t\t\t\t\tisVip = 'SVIP';\n\t\t\t\t\t} else {\n\t\t\t\t\t\tisVip = '普通会员';\n\t\t\t\t\t}\n\t\t\t\t\ttips= `\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)==java.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 != 0?java.timeFormat(res.last_read_time * 1000):'未阅读').padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 📱关联设备  ${devices.toString().padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 👑会员状态  ${isVip.padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 🚫封禁状态  ${res.is_banned?'已封禁':'正常 '}       \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=java.ajax(`${base_url}\/clear,{\"method\":\"POST\",\"headers\":{\"cookie\":\"${cookie.getCookie(base_url)}\"}}`)\n\t\/\/java.toast(res.code === 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 = java.androidId()\n\t\tlet encodeStr = 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('http:\/\/vip.qingtian618.com', \"首页\");\n}\n\n\n\/\/打赏\nfunction vip() {\n\tjava.startBrowserAwait(base_url+ '\/coffee', \"喝咖啡\");\n\t\n}\nfunction loginqt() {\n\tjava.startBrowserAwait(base_url + '\/login', '登录晴天小说书源');\n}\n\n function logout() {\n\tcookie.removeCookie(\"fanqienovel.com\");\n\tcookie.removeCookie(\"snssdk.com\");\n\tcookie.removeCookie(base_url);\n\tcookie.removeCookie(\"qingtian618.cn\");\n\tcookie.removeCookie(\"113.45.175.112\");\n\tjava.toast(\"退出登录成功\");\n}\n\nfunction renderVersionPage() {\n\tjava.longToast(\"\\n\\n请点击网页登录-书源下载进行下载\/更新\");\n\t}\n\t\n\t\/\/ 订阅源更新\nfunction renderVersionPageRss() {\n\tlet yd = '';\n  let html = `\n<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n  <meta charset=\"UTF-8\" \/>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" \/>\n  <title>订阅源更新<\/title>\n  <style>\n    body {\n      margin: 0;\n      padding: 1em;\n      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n      background: linear-gradient(135deg, #e0c3fc 0%, #8ec5fc 100%);\n      display: flex;\n      justify-content: center;\n      align-items: center;\n      min-height: 100vh;\n      color: #333;\n    }\n\n    .container {\n      width: 100%;\n      max-width: 480px;\n      background: rgba(255, 255, 255, 0.85);\n      backdrop-filter: blur(10px);\n      border-radius: 16px;\n      padding: 1em;\n      box-shadow: 0 8px 30px rgba(0, 0, 0, 0.1);\n      animation: fadeIn 0.5s ease-in-out;\n      display: none; \n          }\n\n    @keyframes fadeIn {\n      from { opacity: 0; transform: translateY(10px); }\n      to { opacity: 1; transform: translateY(0); }\n    }\n\n    h1 {\n      text-align: center;\n      font-size: 1.6em;\n      margin-bottom: 1em;\n      color: #333;\n    }\n\n    .version-info, .status {\n      text-align: center;\n      margin-bottom: 1em;\n      font-weight: 500;\n    }\n\n    .status {\n      color: #d63384;\n      font-size: 0.9em;\n    }\n\n    .button-group {\n      display: flex;\n      flex-direction: column;\n      gap: 0.75em;\n      margin-bottom: 1.5em;\n    }\n\n    .button {\n      display: block;\n      width: 90%;\n      padding: 0.85em;\n      text-align: center;\n      font-size: 1em;\n      border: none;\n      border-radius: 8px;\n      text-decoration: none;\n      background: linear-gradient(135deg, #42e695 0%, #3bb2b8 100%);\n      color: white;\n      font-weight: bold;\n      transition: all 0.25s ease;\n      box-shadow: 0 4px 14px rgba(0, 0, 0, 0.15);\n    }\n\n    .button:hover {\n      transform: translateY(-2px);\n      box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);\n    }\n\n    .logs {\n      background: #ffffffcc;\n      padding: 1em;\n      border-radius: 8px;\n      border: 1px solid #ddd;\n      box-shadow: inset 0 1px 3px rgba(0,0,0,0.05);\n    }\n\n    .logs h2 {\n      font-size: 1.2em;\n      margin-bottom: 0.8em;\n      border-bottom: 1px solid #ccc;\n      padding-bottom: 0.3em;\n      color: #222;\n    }\n\n    .log-item {\n      margin-bottom: 0.7em;\n      line-height: 1.5;\n    }\n\n    .log-item-date {\n      font-weight: bold;\n      color: #3b3b3b;\n    }\n\n    .log-item-content {\n      margin-left: 1em;\n      color: #555;\n    }\n\n    .loading {\n      text-align: center;\n      font-size: 1.1em;\n      color: #555;\n      animation: pulse 1.2s infinite;\n    }\n\n    @keyframes pulse {\n      0% { opacity: 1; }\n      50% { opacity: 0.5; }\n      100% { opacity: 1; }\n    }\n    .ad-banner {\n            background: linear-gradient(135deg, #ff9a9e 0%, #fad0c4 100%);\n            color: white;\n            padding: 10px 15px;\n            text-align: center;\n            margin-bottom: 20px;\n            cursor: pointer;\n            border-radius: 8px;\n            border: 1px solid #ddd;\n            box-shadow: inset 0 1px 3px rgba(0,0,0,0.05);\n           }\n\n        .ad-banner:hover {\n            transform: translateY(-2px);\n            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);\n        }\n\n        .ad-banner span {\n            font-weight: 500;\n            font-size: 16px;\n        }\n  <\/style>\n<\/head>\n<body>\n  <div id=\"loading\" class=\"loading\">🔍 正在拼命检查中,请稍候~ 📡<\/div>\n\n  <div class=\"container\" id=\"container\">\n    <h1>♻️ 订阅源版本检查<\/h1>\n    <div class=\"ad-banner\" onclick=\"window.location.href='https:\/\/api.qingtian618.com\/phonecardad'\">\n        <span>📱 手机卡充值优惠活动,点击查看详情 →<\/span>\n    <\/div>\n    <div class=\"version-info\" id=\"versionInfo\">加载中...<\/div>\n    <div class=\"status\" id=\"statusText\"><\/div>\n\n    <div class=\"button-group\" id=\"buttonGroup\" style=\"display: none;\">\n          <\/div>\n\n    <div class=\"logs\" id=\"logs\" style=\"display: none;\">\n      <h2>📝 更新日志<\/h2>\n      <div id=\"logList\"><\/div>\n    <\/div>\n  <\/div>\n\n <script>\n(async function() {\n  const loading = document.getElementById('loading');\n  const container = document.getElementById('container');\n  const versionInfo = document.getElementById('versionInfo');\n  const statusText = document.getElementById('statusText');\n  const updateButton = document.getElementById('updateButton');\n  const buttonGroup = document.getElementById('buttonGroup');\n  const logsContainer = document.getElementById('logs');\n  const logList = document.getElementById('logList');\n\nconst localVer = '${String(localVersion)}';\n\/\/ 版本判断逻辑\nfunction compareVersions(vs) {\n  const parts1 = localVer.split('.').map(Number);\n  const parts2 = vs.split('.').map(Number);\n  const maxLength = Math.max(parts1.length, parts2.length);\n  for (let i = 0; i < maxLength; i++) {\n    const num1 = parts1[i] || 0;\n    const num2 = parts2[i] || 0;\n    if (num1 > num2) return 1;\n    if (num1 < num2) return -1;\n  }\n  return 0;\n}\n\nconst encodedEndpoints = [\n  'aHR0cHM6Ly9hcGkucWluZ3RpYW42MTguY29t',     \n  'aHR0cHM6Ly92MS5xaW5ndGlhbjYxOC5jb20=',      \n  'aHR0cHM6Ly92Mi5xaW5ndGlhbjYxOC5jb20=',       \n  'aHR0cHM6Ly92My5xaW5ndGlhbjYxOC5jb20=',      \n  'aHR0cHM6Ly92NC5xaW5ndGlhbjYxOC5jb20=',        \n  'aHR0cHM6Ly92NS5xaW5ndGlhbjYxOC5jb20=',       \n  'aHR0cDovLzExMy40NS4xNzUuMTEyOjg4ODg='        \n];\n\nfunction decodeEndpoint(str) {\n  return atob(str);\n}\n\nasync function fetchVersionData() {\n  for (const b64 of encodedEndpoints) {\n    const url = decodeEndpoint(b64);\n    try {\n      const response = await fetch(url + '\/version', { timeout: 2000 }); \n      if (response.ok) {\n        return await response.json();\n      }\n    } catch (e) {\n      console.warn(\\`接口失败:\\${url}\\`, e);\n    }\n  }\n  throw new Error('所有更新接口都请求失败');\n}\n  try {\n    loading.style.display = 'block';\n\n    const data = await fetchVersionData();\n    const cloudVersion = String(data.rssVersion3);\n    const updateLog = data.update_rss_log || {};\n\n    versionInfo.innerHTML = \\`🔖当前版本:v\\${localVer} <br> 🔭最新版本:v\\${cloudVersion}\\`;\n\n    logList.innerHTML = Object.entries(updateLog).map(([date, content]) => \\`\n      <div class=\"log-item\">\n        <div class=\"log-item-date\">\\${date}<\/div>\n        <div class=\"log-item-content\">\\${content}<\/div>\n      <\/div>\n    \\`).join('');\n    logsContainer.style.display = 'block';\n\n    if (compareVersions(cloudVersion) === -1) {\n      statusText.innerHTML = '<span>✨ 有新版本可用,建议立即更新!<br>${yd}<\/span>';\nconst domainMap = {\n  main: 'aHR0cDovL3N5LnFpbmd0aWFuNjE4LmNvbQ==', \n  d1:   'aHR0cHM6Ly9hcGkucWluZ3RpYW42MTguY29t', \n  d2:   'aHR0cHM6Ly92MS5xaW5ndGlhbjYxOC5jb20=',\n  d3:   'aHR0cHM6Ly92Mi5xaW5ndGlhbjYxOC5jb20=',\n  d4:   'aHR0cHM6Ly92My5xaW5ndGlhbjYxOC5jb20=',\n  d5:   'aHR0cHM6Ly92NC5xaW5ndGlhbjYxOC5jb20=',\n  d6:   'aHR0cHM6Ly92NS5xaW5ndGlhbjYxOC5jb20='\n};\n\nfunction decode(b64) {\n  return atob(b64);\n}\n\nconst path = '\/sy\/download\/晴天订阅源.json';\nconst mainPath = '\/download\/晴天订阅源.json';\n\nconst routes = [\n  { name: '🚀 主线路', domain: 'main', suffix: mainPath },\n  { name: '📦 备用线路1', domain: 'd1', suffix: path },\n  { name: '🛰️ 备用线路2', domain: 'd2', suffix: path },\n  { name: '🛰️ 备用线路3', domain: 'd3', suffix: path },\n  { name: '🛰️ 备用线路4', domain: 'd4', suffix: path },\n  { name: '🛰️ 备用线路5', domain: 'd5', suffix: path },\n  { name: '🛰️ 备用线路6', domain: 'd6', suffix: path }\n];\n\nbuttonGroup.innerHTML = routes.map(r => {\n  const fullUrl = decode(domainMap[r.domain]) + r.suffix;\n  return \\`<a href=\"legado:\/\/import\/auto?src=\\${encodeURIComponent(fullUrl)}\" class=\"button\">\\${r.name}<\/a>\\`;\n}).join('');\n      buttonGroup.style.display = 'flex';\n      } else {\n      statusText.textContent = '✅ 已是最新订阅源咯~';\n    }\n\n    loading.style.display = 'none';\n    container.style.display = 'block';\n\n  } catch (err) {\n    loading.textContent = '😢 检查失败啦~ 请稍后再试==>'+err;\n    console.error('版本检查失败:', err);\n  }\n})();\n<\/script>\n<\/body>\n<\/html>\n`;\n  java.startBrowser(`data:text\/html;base64,${java.base64Encode(html)}`, '晴天订阅源更新');\n}\n",
    "ruleArticles": "<js>\nif (baseUrl.includes('番茄')) {\nlet ck = (String(cookie.getKey(\"fanqienovel.com\", \"sessionid\")) ? String(cookie.getKey(\"fanqienovel.com\", \"sessionid\")) : (source.getLoginInfoMap() || {})['番茄Token']) || \"\";\nfunction getCellId() {\n  let sInfo = java.ajax(java.log(base_url + \"\/book_mall_tab?ssionid=\" + ck));\n  let cell_id = \"cell_id%253D6914906572011339784%2526\"\n  let body = 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 !== 'undefined') {\n       \/\/ java.log(i.cell_url)\n       cell_id = i.cell_url\n       break\n     }\n  }\n  java.log(cell_id)\n  cell_id = cell_id.split(\"cell_id%253D\")[1].split(\"%2526\")[0]\n  java.log(cell_id)\n  return cell_id\n}\nlet cell_id = getCellId();\njava.ajax(java.log(base_url + '\/book_mall_y?cell_id=' + cell_id + '&ssionid='+ck));\n} else {\n\t\/\/java.toast(baseUrl);\n\tlet other = {\n\t\t'data':{'cell_view':{'topic_data':\n\t\t[{'topic_desc':{\n\t\t\t'topic_title':'进入官网',\n\t\t\t 'topic_id':baseUrl\n\t\t\t}}]}\n\t\t}}\n\t\tother = JSON.stringify(other);\n\t\t\/\/java.toast(other)\n\t};\n\t<\/js>\n$.data.cell_view.topic_data[*]",
    "ruleImage": "$.topic_desc.topic_cover",
    "ruleLink": "<js>\nlet ruleUrl;\nif (baseUrl.includes('番茄')) { \n\truleUrl = `https:\/\/reading.snssdk.com\/wap\/topic-share.html?topic_id={{$.topic_desc.topic_id}}&sort=smart_hot&service_id=6&session_id=0&aid=1967`\n\t} else {\n\t\truleUrl = '{{$.topic_desc.topic_id}}';\n\t\t\/\/java.toast(ruleUrl)\n\t\t}\n\truleUrl\n<\/js>",
    "rulePubDate": "$.topic_desc.topic_content\n@js:\nif (baseUrl.includes('番茄')) {\n\tlet data = JSON.parse(result).skeleton.data.replace(\/<\\\/?search_link>\/g, \" \")\nlet select = Packages.org.jsoup.Jsoup.parse(data).select(\"p, span\")\nlet final = Array.from(select).map(p => p.text()).join(\" \")\njava.timeFormat(java.getString('topic_desc.create_time')*1000) + (!Packages.android.text.TextUtils.isEmpty(final) ? (' | ' + final) : '')\n}",
    "ruleTitle": "$.topic_desc.topic_title",
    "shouldOverrideUrlLoading": "function extractBookId(url) {\n    let match = url.match(\/[?&]book_id=([^&]+)\/) || 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+)\/);\n    \n    if (!match) {\n    \t     return null;\n   }\n    const bookId = match[1];\n    return bookId;\n}\n\n\/\/ java.toast(url.startsWith('legadosearch:\/\/'))\nif (url.startsWith('legadosearch:\/\/')) { \n  \/\/ java.toast('ab')\n  java.searchBook(\n    decodeURIComponent(\n      url.replace('legadosearch:\/\/', '')\n    )\n  )\n}\nlet needBreak = false\nfunction isNewLegado() {\n  try {\n    return !!Packages.io.legado.app.ui.book.manga;\n  } catch(e) {\n    return false; \n  } \n}\nif (isNewLegado()) {\n\t  if (url.match(\/book_id=\\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+)\/)) {\n  \t\/\/java.toast(url);\n  \t const bookId = java.encodeURI(java.base64Encode(extractBookId(url)));\n  \t \/\/java.toast(bookId);\n  \t let url2 = `https:\/\/api.qingtian618.com\/detail?book_id=${bookId}&source=%e7%95%aa%e8%8c%84`\n  \t if (url.includes('shuku')) {\n  \t \turl2 = `https:\/\/api.qingtian618.com\/detail?book_id=${bookId}&source=七猫`\n  \t \t}\n  \t \tif (url.includes('tadu')) {\n  \t \turl2 = `https:\/\/api.qingtian618.com\/detail?book_id=${bookId}&source=塔读`\n  \t \t}\n  \t \tif (url.includes('shuqi')) {\n  \t \turl2 = `https:\/\/api.qingtian618.com\/detail?book_id=${bookId}&source=书旗`\n  \t \t}\n  \t \tif (url.includes('ximalaya')) {\n  \t \turl2 = `https:\/\/api.qingtian618.com\/detail?book_id=${bookId}&source=喜马拉雅&tab=听书`\n  \t \t}\n  \t \tif (url.includes('qq')) {\n  \t \turl2 = `https:\/\/api.qingtian618.com\/detail?book_id=${bookId}&source=QQ`\n  \t \t}\n  \t \/\/java.toast(url2.replace('%3D',''));\n  \t java.addBook(url2.replace('%3D',''));\n    needBreak = true;\n  }\n}\n!(url.startsWith('http') || url.startsWith('legado')) || url.match(\/\\\/chapter-list\\\/\\d+\/) || needBreak",
    "singleUrl": false,
    "sortUrl": "番茄::番茄\n七猫::https:\/\/www.qimao.com\/\n塔读::https:\/\/m.tadu.com\/\n书旗::https:\/\/t.shuqi.com\/",
    "sourceComment": "原作者 未知\n二改:\n  世界有多大 (翻页)\n  梓澄qwq (个人推荐, js注入, 拦截跳转)\n  Folltoshe (js注入)\n  柚屿 (完善登录)\n  清词 (失效修复,修复有书籍无法点击跳转的情况,加强过滤)\n  期待完美的自己(兼容晴天完全版书源)\n  晴天(完善晴天订阅源)",
    "sourceIcon": "https:\/\/api.qingtian618.com\/favicon.ico",
    "sourceName": "晴天书荒广场",
    "sourceUrl": "https:\/\/www.baidu.com\/晴天番茄书荒广场"
}
广告