📚书山聚合

https://search.shusan.icu

书山 (1935)1天前

10.17日更新:

书源和订阅源适配IOS源阅,IOS不支持段评

修复段评楼中楼部分回复无数据的情况

推荐书籍新增等级标签显示(没什么用,纯好看)

二维码导入
{
    "bookSourceComment": "10.17日更新:\n适配IOS源阅,IOS设备不支持段评\n修复段评楼中楼部分回复无数据的情况\n推荐书籍新增等级标签显示(没什么用,纯好看)\n\n注:阅读请使用最新测试版\n1.所有源站每20秒最多15章,把预下载调到0-3之间使用[打赏VIP白名单无请求限制]\n2.自定义源站示例:番茄小说,七猫小说  多个源站用英文,号分隔\n源站名参考 登录URL \/\/书源配置列表 v参数\n\n3.源站带有❇️图标表示只能指定或@搜索\n\n4.搜索模式:\n书名@来源 多个来源用英文,号分隔\n示例: \n系统@番茄小说,多个源站使用英文,号分隔\n书名@类型 返回对应类型所有源站数据,可直接使用@方式搜索或者点击登陆切换模式\n示例: \n系统@小说  听书  漫画  短剧等\n默认书名排序\n指定作者优先:\n作者名@作者   作者名@作者,源站",
    "bookSourceGroup": "聚合书源",
    "bookSourceName": "📚书山聚合",
    "bookSourceType": 0,
    "bookSourceUrl": "https:\/\/search.shusan.icu",
    "bookUrlPattern": "https?:\\\/\\\/(?:[a-zA-Z0-9-]+\\.)*shusan\\.icu\\\/details.*",
    "customOrder": 0,
    "enabled": true,
    "enabledCookieJar": true,
    "enabledExplore": true,
    "exploreUrl": "<js>\nlet config = (() => {\n    try {\n        let cfg = JSON.parse(source.getVariable())[0] || {};\n        if (!cfg.host || !cfg.gender) {\n            cfg = {gender: \"boy\", host: getServerHost()};\n            source.setVariable(JSON.stringify([cfg]));\n            java.toast(\"配置初始化完成\");\n        }\n        return cfg;\n    } catch(e) {\n        let cfg = {gender: \"boy\", host: getServerHost()};\n        source.setVariable(JSON.stringify([cfg]));\n        return cfg;\n    }\n})();\n    \nlet rawVariable = source.getVariable();\nlet 个人中心 = 1;\nlet obj = (title, url, type) => ({\n  title: title,\n  url: url,\n  style: { layout_flexGrow: 1, layout_flexBasisPercent: type }\n});\n\nlet sort = [];\nlet push = (title, url, type) => sort.push(obj(title, url, type));\n\nlet currentType = \"\";\nlet currentSource = \"\";\ntry {\n  let vArray = JSON.parse(rawVariable);\n  if (vArray.length > 0) {\n    let v = vArray[0];\n    currentType = v.gender || \"\";\n    currentSource = v.source || \"\";\n    \n    if (currentSource == \"推荐\") {\n      currentType = \"recommend\";\n      v.gender = \"recommend\";\n      source.setVariable(JSON.stringify(vArray));\n    } else if (currentType == \"recommend\") {\n      currentType = \"boy\";\n      v.gender = \"boy\";\n      source.setVariable(JSON.stringify(vArray));\n    }\n  }\n} catch(e) {\n  currentType = \"\";\n  currentSource = \"\";\n}\n\nconst getGenderDisplayName = (gender) => {\n  if (gender == \"boy\") return \"男频\";\n  if (gender == \"girl\") return \"女频\";\n  if (gender == \"recommend\") return \"推荐\";\n  return \"\";\n};\n\nconst genderDisplay = getGenderDisplayName(currentType);\n\npush(`当前为【${currentSource || \"番茄小说\"}】${genderDisplay ? `【${genderDisplay}】` : ''}`, \"\", 1);\n\nconst excludedSources = [\"小说\", \"听书\", \"漫画\", \"视频\", \"短剧\", \"音频\",\"番茄小说\"];\n\nif (currentSource && currentSource !== \"推荐\" && !excludedSources.includes(currentSource)) {\n  try {\n    let apiUrl = `${getServerHost()}\/type_api?source=${currentSource}`;\n    if (currentType) {\n      apiUrl += `&gender=${currentType}`;\n    }\n    \n    let response = JSON.parse(java.ajax(apiUrl));\n    \n    if (response.data && response.data.found) {\n      response.data.found.forEach(item => {\n        let finalUrl = \"\";\n        if (item.url) {\n          finalUrl = `${getServerHost()}\/type_api?source=${currentSource}&page={{page}}&url=${item.url}`;\n          if (currentType) {\n            finalUrl += `&gender=${currentType}`;\n          }\n        }\n        sort.push({\n          title: item.title,\n          url: finalUrl,\n          style: item.style || { layout_flexGrow: 1, layout_flexBasisPercent: 0.29 }\n        });\n      });\n    } else {\n      push(`【${currentSource}】${genderDisplay ? `【${genderDisplay}】` : ''}暂无数据`, \"\", 1);\n    }\n  } catch(e) {\n    push(`【${currentSource}】${genderDisplay ? `【${genderDisplay}】` : ''}暂无数据`, \"\", 1);\n  }\n  JSON.stringify(sort);\n} else if (currentType == \"recommend\" && currentSource == \"推荐\") {\n  \n  let maleCategories = [];\n  try {\n    let maleResponse = JSON.parse(java.ajax(getServerHost() +\"\/api?action=subcategories&top_category_id=1\"));\n      maleCategories = maleResponse.data;\n  } catch(e) {\n    push('男频分类加载失败,请检查网络', \"\", 1);\n  }\n  \n  let femaleCategories = [];\n  try {\n    let femaleResponse = JSON.parse(java.ajax(getServerHost() +\"\/api?action=subcategories&top_category_id=2\"));\nfemaleCategories = femaleResponse.data;\n  } catch(e) {\n    push('女频分类加载失败,请检查网络', \"\", 1);\n  }\n  \n  if (maleCategories && maleCategories.length > 0) {\n    push('♂️ 男频推荐 ♂️', \"\", 1);\n    maleCategories.forEach(cat => {\n      push(cat.name, `${getServerHost()}\/api?action=books&sub_category_id=${cat.id}&limit=20&page={{page}}`, 0.29);\n    });\n  } else if (!maleCategories || maleCategories.length == 0) {\n    push('男频分类暂无数据', \"\", 1);\n  }\n  \n  if (femaleCategories && femaleCategories.length > 0) {\n    push('♀️ 女频推荐 ♀️', \"\", 1);\n    femaleCategories.forEach(cat => {\n      push(cat.name, `${getServerHost()}\/api?action=books&sub_category_id=${cat.id}&limit=20&page={{page}}`, 0.29);\n    });\n  } else if (!femaleCategories || femaleCategories.length === 0) {\n    push('女频分类暂无数据', \"\", 1);\n  }\n  \n  JSON.stringify(sort);\n} else {\n  let recommendUrl = getServerHost() + \"\/read_recommend?session=\" + getSessionId();\n  push('个性推荐', recommendUrl, 0.29);\n  push('巅峰榜单', 'https:\/\/fanqienovel.com\/api\/author\/misc\/top_book_list\/v1\/?limit=100&offset={{(page-1)*100}}', 0.29);\n  push('出版榜单', 'https:\/\/fanqienovel.com\/api\/node\/publication\/list?page_index={{(page-1)*100}}&page_count=100', 0.29);\n  push('爆更榜单', 'https:\/\/api-lf.fanqiesdk.com\/api\/novel\/channel\/homepage\/rank\/rank_list\/v2\/?aid=13&limit=50&offset={{(page-1)*100}}&side_type=15&type=1', 0.29);\n  push('黑马榜单', 'https:\/\/api-lf.fanqiesdk.com\/api\/novel\/channel\/homepage\/rank\/rank_list\/v2\/?aid=13&limit=50&offset={{(page-1)*100}}&side_type=13&type=1', 0.29);\n  push('热搜榜单', 'https:\/\/api-lf.fanqiesdk.com\/api\/novel\/channel\/homepage\/rank\/rank_list\/v2\/?aid=13&limit=50&offset={{(page-1)*100}}&side_type=12&type=1', 0.29);\t\n\n  let fqCategoryArr = [];\n  let showCategories = currentType == \"girl\" ? [0] : (currentType == \"boy\" ? [1] : [0, 1]);\n\n  showCategories.forEach(i => {\n    try {\n      let response = JSON.parse(java.ajax(`${getServerHost()}\/type?new_category_tab=${i}`));\n      let $ = response.data.category_tab_data;\n      \n      let tabName = $.tab_name || (i == 0 ? \"女频\" : \"男频\");\n      fqCategoryArr.push(obj(`❤️${tabName}分类❤️`, null, 1));\n      \n      $.cell_data.forEach(c => {\n        fqCategoryArr.push(obj(c.cell_name, null, 1));\n        \n        if (c.atom_data && Array.isArray(c.atom_data)) {\n          c.atom_data.slice(1).forEach(a => {\n            let d = a.category_data;\n            if (d && d.name) {\n              let gender = i;\n              let genre = 0;\n              let cid = d.category_id;\n              \n              fqCategoryArr.push({\n                title: d.name,\n                url: `${getServerHost()}\/type?category_id=${cid}&genre=${genre}&gender=${gender}&limit=20&offset={{(page-1)*100}}`,\n                style: {\n                  layout_flexGrow: 1,\n                  layout_flexBasisPercent: 0.29\n                }\n              });\n            }\n          });\n        }\n      });\n    } catch (e) {\n      fqCategoryArr.push(obj(\"分类加载失败,请重试\", null, 1));\n    }\n  });\n\n  fqCategoryArr.forEach(item => {\n  if (item.style && item.style.layout_flexBasisPercent) {\n    push(item.title, item.url, item.style.layout_flexBasisPercent);\n  } else {\n    sort.push({\n      title: item.title,\n      url: item.url,\n      style: {\n        layout_flexGrow: 1,\n        layout_flexBasisPercent: 0.29\n      }\n    });\n  }\n});\n\ncategory = () => {\n    category_url = \"https:\/\/novel.snssdk.com\/api\/novel\/channel\/homepage\/new_category\/page\/data\/v1\/?aid=13\";\n    return JSON.parse(java.ajax(category_url)).data;\n}\n  \njson = (data) => {\n    boy = data.boy_category;\n    girl = data.girl_category;\n    publish = data.publish_category;\n    json = [[\"男频\",\"gender=1\",boy],[\"女频\",\"gender=0\",girl],[\"出版\",\"genre_type=160\",publish]];\n    return JSON.parse(JSON.stringify(json));\n}\t\n\nlet categoryData = json(category());\n\nif(currentType == \"girl\") {\n    let [tit1, gender, categoryList] = categoryData[1];\n    push('其它分类', null, 1);\n    categoryList.forEach(($,index)=>{\n        index++;\n        title = $.category_name;\n        cid = $.category_id;\n        url=  `https:\/\/novel.snssdk.com\/api\/novel\/channel\/homepage\/new_category\/book_list\/v1\/?aid=1967&app_name=news_article&app_version=9.7.3&channel=tengxun_tt&creation_status=9&device_platform=android&enter_from=novel_category&novel_host&novel_version&version_code=973&version_name=9.7.3&word_count=9&os=android&device_type=ProjectTitan&os_api=29&os_version=10&offset={{(page-1)*100}}&limit=100&category_id=${cid}&${gender}`;\n        push(title, url, 0.29);\t\n    });\n} else {\n    let [tit1, gender, categoryList] = categoryData[0];\n    push('其它分类', null, 1);\n    categoryList.forEach(($,index)=>{\n        index++;\n        title = $.category_name;\n        cid = $.category_id;\n        url=  `https:\/\/novel.snssdk.com\/api\/novel\/channel\/homepage\/new_category\/book_list\/v1\/?aid=1967&app_name=news_article&app_version=9.7.3&channel=tengxun_tt&creation_status=9&device_platform=android&enter_from=novel_category&novel_host&novel_version&version_code=973&version_name=9.7.3&word_count=9&os=android&device_type=ProjectTitan&os_api=29&os_version=10&offset={{(page-1)*100}}&limit=100&category_id=${cid}&${gender}`;\n        push(title, url, 0.29);\t\n    });\n}\n\nlet [tit1, gender, categoryList] = categoryData[2];\npush('❤️'+tit1+'❤️', null, 1);\ncategoryList.forEach(($,index)=>{\n    index++;\n    title = $.category_name;\n    cid = $.category_id;\n    url=  `https:\/\/novel.snssdk.com\/api\/novel\/channel\/homepage\/new_category\/book_list\/v1\/?aid=1967&app_name=news_article&app_version=9.7.3&channel=tengxun_tt&creation_status=9&device_platform=android&enter_from=novel_category&novel_host&novel_version&version_code=973&version_name=9.7.3&word_count=9&os=android&device_type=ProjectTitan&os_api=29&os_version=10&offset={{(page-1)*100}}&limit=100&category_id=${cid}&${gender}`;\n    push(title, url, 0.29);\t\n});\n\n  let hasValidSession = false;\n  let username = \"\";\n\ntry {\n  let uinfo = java.ajax(getServerHost() + \"\/book_user?session=\" + getSessionId());\n  uinfo = JSON.parse(uinfo);\n  \n  if (uinfo && uinfo.data && uinfo.data.name) {\n    username = uinfo.data.name;\n    hasValidSession = true;\n  }\n} catch (e) {\n}\n\nif (!hasValidSession) {\n  java.toast(\"番茄登录已过期,请重新登录\");\n}\n\n  let gro = [];\n  let pushGro = (title, url, type) => gro.push(obj(title, url, type));\n\n  let sArr = [];\n\n  if (hasValidSession) {\n    try {\n      let book_shelf_info = JSON.parse(java.ajax(getServerHost() + \"\/book_shelf?session=\" + getSessionId()));\n\n      if (book_shelf_info.code == 0) {\n        个人中心 = 1;\n        \n        let groups_bookids = { \"未分组\": [] };\n        book_shelf_info.data.book_shelf_info.forEach(i => {\n          if (!groups_bookids[i.group_name ? i.group_name : \"未分组\"]) \n            groups_bookids[i.group_name] = [];\n          groups_bookids[i.group_name ? i.group_name : \"未分组\"].push(i.book_id);\n        });\n\n        Object.keys(groups_bookids).forEach(k => {\n          pushGro(k, \"https:\/\/fanqienovel.com\/fqbookshelf\/groupName\/\" + k, 0.4);\n        });\n        if (Object.keys(groups_bookids).length % 2 != 0) pushGro(\"占位\", \"\", 0.4);\n        \n        sArr.push(obj(username + '的个人中心', '', 1));\n        sArr.push(obj(\"我的书架\", \"https:\/\/fanqienovel.com\/fqbookshelf\", 1));\n        sArr = sArr.concat(gro);\n        sArr.push(obj(\"阅读历史\", getServerHost() + \"\/read_history?session=\" + getSessionId() + \"&page={{page}}\", 1));\n      } else {\n        个人中心 = 0;\n        java.toast(\"获取书架信息失败,登录可能已过期\");\n      }\n    } catch (e) {\n      个人中心 = 0;\n      java.toast(\"番茄登录过期,已隐藏个人中心\");\n    }\n  } else {\n    个人中心 = 0;\n    java.toast(\"未登录番茄账号,无法同步数据\");\n  }\n\n  sort = sArr.concat(sort);\n  JSON.stringify(sort);\n}\n<\/js>",
    "header": "{\t\"X-Novel-Token\": \"SHUSAN_READ_2025\"}",
    "jsLib": "function getServerHost() {\n\tlet { source } = this;\n    try {\n        const config = JSON.parse(source.getVariable());\n        return config?.[0]?.host || source.bookSourceUrl;\n    } catch(e) {\n        return source.bookSourceUrl;\n    }\n}\n\nfunction getSessionId() {\n    const { cookie, source } = this;\n    try {\n        let cookieHeader = String(cookie.getCookie('fanqienovel.com'));\n        let sessionId = cookieHeader.match(\/sessionid=([^;]+)\/)?.[1] || null;\n        \n        if (sessionId) {\n            return sessionId;\n        }\n    } catch (e) {\n    }\n    \n    try {\n        let loginInfo = source.getLoginInfoMap() || {};\n        return loginInfo['手动登录Token'] || \"\";\n    } catch (e) {\n        return \"\";\n    }\n}\n\nfunction splitArray(input, size) {\n  let output = []\n  for (let i = 0; i < input.length; i += size) {\n    output.push(input.slice(i, i + size))\n  }\n  return output\n}\n\nfunction getComments(content, bid, cid) {\n    let { java, cache, source } = this;\n    let host = getServerHost.call(this);\n    try {\n        let apiUrl = `${host}\/proxy_idea?item_id=${cid}`;\n        let comments = java.ajax(apiUrl);\n        \n        let lines = content.replace(\/(<img[^>]*?>)\\n\/g, \"$1\").split(\"\\n\");\n        let raw = JSON.parse(comments).data.data;\n\n        Object.keys(raw).forEach((x) => {\n            cache.putMemory(`fq-${bid}-${cid}-${x}-text`, lines[x]);\n            \n            let color = \"red\";\n            let loginInfo = source.getLoginInfoMap();\n            if (loginInfo && loginInfo['段评图标颜色'] && loginInfo['段评图标颜色'].startsWith('#')) {\n                color = loginInfo['段评图标颜色'];\n            }\n            \n            lines[x] += `<img src=\"${this.createSvg(raw[x].count, color, bid, cid, x)}\">`;\n        });\n        return lines.join(\"\\n\");\n    } catch (e) {\n        return content;\n    }\n}\n\nfunction createSvg(number, color, bid, cid, para) {\n    var displayText = number > 99 ? \"99+\" : number;\n    var date = String(Date.now()).match(\/(\\d{6}$)\/)[1];\n    var loginInfoMap = {};\n    if (this.source && typeof this.source.getLoginInfoMap === 'function') {\n        loginInfoMap = this.source.getLoginInfoMap() || {};\n    }\n    var bubbleStyle = String(loginInfoMap['段评气泡样式'] || '0');\n    var svg;\n    \n    if (bubbleStyle === '1') {\n    svg = '<svg width=\"1000\" height=\"833\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">' +\n          '<rect x=\"30\" y=\"20\" width=\"940\" height=\"793\" rx=\"180\" ry=\"180\" fill=\"none\" stroke=\"' + color + '\" stroke-width=\"40\" stroke-linejoin=\"round\"\/>' +\n          '<text x=\"500\" y=\"444\" font-family=\"Arial, sans-serif\" text-anchor=\"middle\" font-size=\"333\" fill=\"' + color + '\" dy=\"0.3em\" font-weight=\"700\" opacity=\"0.9\">' + displayText + '<\/text>' +\n          '<\/svg>';\n} else if (bubbleStyle === '2') {\n    svg = '<svg width=\"1000\" height=\"1000\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">' +\n          '<circle cx=\"500\" cy=\"500\" r=\"460\" fill=\"none\" stroke=\"' + color + '\" stroke-width=\"40\" stroke-linejoin=\"round\"\/>' +\n          '<text x=\"500\" y=\"500\" font-family=\"Arial, sans-serif\" text-anchor=\"middle\" font-size=\"360\" fill=\"' + color + '\" dy=\"0.3em\" font-weight=\"700\" opacity=\"0.9\">' + displayText + '<\/text>' +\n          '<\/svg>';\n} else {\n    svg = '<svg width=\"1000\" height=\"909\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">' +\n          '<path d=\"M80,80 h840 a60,60 0 0 1 60,60 v580 a60,60 0 0 1 -60,60 h-620 l-140,90 v-90 h-80 a60,60 0 0 1 -60,-60 v-580 a60,60 0 0 1 60,-60 z\" ' +\n          'fill=\"none\" stroke=\"' + color + '\" stroke-width=\"16\" stroke-linejoin=\"round\"\/>' +\n          '<text x=\"500\" y=\"450\" font-family=\"Arial, sans-serif\" text-anchor=\"middle\" ' +\n          'font-size=\"360\" fill=\"' + color + '\" dy=\"0.3em\">' + displayText + '<\/text>' +\n          '<\/svg>';\n}\n    \n    var encodedSvg = this.java.base64Encode(svg);\n    \n    return 'data:image\/svg+xml;base64,' + encodedSvg + ',{\\'js\\':\\'showCmt(\"' + bid + '\",\"' + cid + '\",\"' + para + '\",\"' + date + '\")\\'}';\n}\n\nfunction showCmt(bid, cid, para, date) {\n    let { java, cache, cookie, source} = this;\n    let host = getServerHost.call(this);\n    let mname = `fq-${bid}-${cid}-${para}`;\n    let load = (cache.getFromMemory(mname) ?? \"-\").split(\"-\");\n    \n    if (load[0] != \"1\" || load[1] != date) {\n        cache.putMemory(mname, \"1-\" + date);\n        return;\n    }\n    \n    let lastCallKey = `last_call_${bid}_${cid}_${para}`;\n    let lastCallTime = cache.getFromMemory(lastCallKey) || 0;\n    let currentTime = Date.now();\n    \n    if (currentTime - lastCallTime < 1000) {\n        return;\n    }\n    cache.putMemory(lastCallKey, currentTime);\n    \n    let apiUrl = `${host}\/idea_comment?item_id=${cid}&book_id=${bid}&para=${para}&sessionid=${\n  (() => {\n    let cookieSession = String(cookie.getKey(\"fanqienovel.com\", \"sessionid\"));\n    return cookieSession || (source.getLoginInfoMap() || {})['手动登录Token'];\n  })()\n}`;\n    let title = cache.getFromMemory(mname + \"-text\") ?? \"段评内容\";\n    \n    java.startBrowser(apiUrl, title);\n}\n\nfunction getSecretKey() {\n\tlet { java, source } = this;\n    const loginInfo = source.getLoginInfoMap();\n    const key = loginInfo['密钥'] || '';\n    if (!key) {\n        java.toast(\"请先填写密钥\");\n    }\n    return java.base64Encode(key);\n}",
    "lastUpdateTime": "1760771157817",
    "loginUi": "[{\n        \"name\": \"🔑获取密钥\",\n        \"type\": \"button\",\n        \"action\": \"key()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🧤密钥查询🧤\",\n        \"type\": \"button\",\n        \"action\": \"cx()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"密钥\",\n        \"type\": \"password\",\n        \"action\": \"\"\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    {\n        \"name\": \"❌退出番茄账号❌\",\n        \"type\": \"button\",\n        \"action\": \"logout()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"☁️聚合搜索☁️\",\n        \"type\": \"button\",\n        \"action\": \"sou0()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"☕请杯咖啡,解除限制\",\n        \"type\": \"button\",\n        \"action\": \"vip()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 1\n        }\n    },\n    {\n        \"name\": \"自定义源站\",\n        \"type\": \"text\"\n    },\n    {\n        \"name\": \"听书AI音色编号\",\n        \"type\": \"text\"\n    },\n    {\n        \"name\": \"❤️段评开关\",\n        \"type\": \"button\",\n        \"action\": \"toggleParacomment('paras')\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🧭书源更新\",\n        \"type\": \"button\",\n        \"action\": \"version()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"❇️ 查看推荐 ❇️\",\n        \"type\": \"button\",\n        \"action\": \"recommend()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"💞 找书\/推荐 💞\",\n        \"type\": \"button\",\n        \"action\": \"tj()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🧸男 频🧸\",\n        \"type\": \"button\",\n        \"action\": \"boy()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.45\n        }\n    },\n    {\n        \"name\": \"🎀女 频🎀\",\n        \"type\": \"button\",\n        \"action\": \"girl()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.45\n        }\n    },\n    {\n        \"name\": \"🎚服务器切换🎚\",\n        \"type\": \"button\",\n        \"action\": \"sethost()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.25\n        }\n    },\n    {\n        \"name\": \"⚡TXT下载开关\",\n        \"type\": \"button\",\n        \"action\": \"toggleFqdown('fqdown')\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.25\n        }\n    },\n    {\n        \"name\": \"↓   切换\/查询当前模式   ↓\",\n        \"type\": \"button\",\n        \"action\": \"get_cx()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 1\n        }\n    },\n    {\n        \"name\": \"📖小说模式\",\n        \"type\": \"button\",\n        \"action\": \"type1()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🎧听书模式\",\n        \"type\": \"button\",\n        \"action\": \"type2()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🌈漫画模式\",\n        \"type\": \"button\",\n        \"action\": \"type3()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"▶️视频模式\",\n        \"type\": \"button\",\n        \"action\": \"type4()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"↓   指   定   源   站   ↓\",\n        \"type\": \"button\",\n        \"action\": \"\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 1\n        }\n    },\n    {\n        \"name\": \"🍅番茄小说\",\n        \"type\": \"button\",\n        \"action\": \"sou1()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🍅番茄听书[AI音色]\",\n        \"type\": \"button\",\n        \"action\": \"sou2()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🎧番茄畅听\",\n        \"type\": \"button\",\n        \"action\": \"sou3()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🍅番茄漫画\",\n        \"type\": \"button\",\n        \"action\": \"sou4()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🍅番茄短剧\",\n        \"type\": \"button\",\n        \"action\": \"sou5()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"💫起点中文\",\n        \"type\": \"button\",\n        \"action\": \"sou7()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🐱七猫小说\",\n        \"type\": \"button\",\n        \"action\": \"sou6()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🔥101看书\",\n        \"type\": \"button\",\n        \"action\": \"sou10()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🌤️69书吧com\",\n        \"type\": \"button\",\n        \"action\": \"sou12()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🌤️69书吧co\",\n        \"type\": \"button\",\n        \"action\": \"sou34()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🐧企鹅看书\",\n        \"type\": \"button\",\n        \"action\": \"sou8()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🦉猫眼看书\",\n        \"type\": \"button\",\n        \"action\": \"sou21()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🌙笔阁趣文\",\n        \"type\": \"button\",\n        \"action\": \"sou15()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🍰淘小说\",\n        \"type\": \"button\",\n        \"action\": \"sou24()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🍒追书神器\",\n        \"type\": \"button\",\n        \"action\": \"sou19()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🍋得间小说\",\n        \"type\": \"button\",\n        \"action\": \"sou13()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🔥半夏中文\",\n        \"type\": \"button\",\n        \"action\": \"sou11()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🔥爱下电子书\",\n        \"type\": \"button\",\n        \"action\": \"sou16()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🌾小米阅读\",\n        \"type\": \"button\",\n        \"action\": \"sou20()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n     {\n        \"name\": \"🐱七猫短剧\",\n        \"type\": \"button\",\n        \"action\": \"sou33()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },\n    {\n        \"name\": \"🍭米读\",\n        \"type\": \"button\",\n        \"action\": \"sou18()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.2\n        }\n    },\n    {\n        \"name\": \"🎊疯读\",\n        \"type\": \"button\",\n        \"action\": \"sou23()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.2\n        }\n    },\n    {\n        \"name\": \"♟️书旗\",\n        \"type\": \"button\",\n        \"action\": \"sou9()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.2\n        }\n    },\n    {\n        \"name\": \"⚖️圣武书屋\",\n        \"type\": \"button\",\n        \"action\": \"sou22()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.45\n        }\n    },\n    {\n        \"name\": \"知乎盐选\",\n        \"type\": \"button\",\n        \"action\": \"sou14()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.45\n        }\n    },\n    {\n        \"name\": \"🔥笔趣阁\",\n        \"type\": \"button\",\n        \"action\": \"sou17()\",\n        \"style\": {\n            \"layout_flexGrow\": 1,\n            \"layout_flexBasisPercent\": 0.4\n        }\n    },{\n    \"name\": \"🌸NT动漫\",\n    \"type\": \"button\",\n    \"action\": \"sou35()\",\n    \"style\": {\n      \"layout_flexGrow\": 1,\n      \"layout_flexBasisPercent\": 0.4\n    }\n  },\n    {\n        \"name\": \"段评图标颜色\",\n        \"type\": \"text\"\n    },\n    {\n        \"name\": \"段评气泡样式\",\n        \"type\": \"text\"\n    },\n    {\n        \"name\": \"手动登录Token\",\n        \"type\": \"text\"\n    }\n]",
    "loginUrl": "const LOCAL_VERSION = \"4.56\";\n\nvar hosts = [\n    \"https:\/\/search.shusan.icu\",\n    \"http:\/\/137.220.171.111:8887\",\n    \"https:\/\/ju.shusan.icu\"\n];\n\nvar sourceList = [\n    {n:\"sou0\",v:null,m:\"☁️聚合搜索\"},\n    {n:\"sou1\",v:\"番茄小说\",m:\"番茄小说\"},\n    {n:\"sou2\",v:\"番茄听书\",m:\"番茄听书\"},\n    {n:\"sou3\",v:\"番茄畅听\",m:\"番茄畅听\"},\n    {n:\"sou4\",v:\"番茄漫画\",m:\"番茄漫画\"},\n    {n:\"sou5\",v:\"番茄短剧\",m:\"番茄短剧\"},\n    {n:\"sou6\",v:\"七猫\",m:\"🐱七猫\"},\n    {n:\"sou7\",v:\"起点\",m:\"💫起点中文\"},\n    {n:\"sou8\",v:\"企鹅看书\",m:\"🐧企鹅看书\"},\n    {n:\"sou9\",v:\"书旗\",m:\"♟️书旗\"},\n    {n:\"sou10\",v:\"101看书\",m:\"101看书\"},\n    {n:\"sou11\",v:\"半夏\",m:\"半夏小说\"},\n    {n:\"sou12\",v:\"69书吧\",m:\"69书吧com\"},\n    {n:\"sou13\",v:\"得间\",m:\"得间\"},\n    {n:\"sou14\",v:\"知乎\",m:\"知乎盐选\"},\n    {n:\"sou15\",v:\"笔阁趣文\",m:\"🌙笔阁趣文\"},\n    {n:\"sou16\",v:\"爱下电子书\",m:\"爱下电子书\"},\n    {n:\"sou17\",v:\"笔趣阁\",m:\"笔趣阁\"},\n    {n:\"sou18\",v:\"米读\",m:\"米读\"},\n    {n:\"sou19\",v:\"追书神器\",m:\"追书神器\"},\n    {n:\"sou20\",v:\"小米阅读\",m:\"小米阅读\"},\n    {n:\"sou21\",v:\"猫眼看书\",m:\"猫眼看书\"},\n    {n:\"sou22\",v:\"圣武书屋\",g:\"girl\",m:\"圣武书屋\"},\n    {n:\"sou23\",v:\"疯读\",m:\"疯读小说\"},\n    {n:\"sou24\",v:\"淘小说\",m:\"淘小说\"},\n    {n:\"sou25\",v:\"思兔\",m:\"思兔阅读\"},\n    {n:\"sou26\",v:\"甜梦文库\",g:\"girl\",m:\"甜梦文库\"},\n    {n:\"sou27\",v:\"三七轻小说\",m:\"三七轻小说\"},\n    {n:\"sou28\",v:\"歪瑞古德\",m:\"歪瑞古德\"},\n    {n:\"sou29\",v:\"包子漫画\",m:\"包子漫画\"},\n    {n:\"sou30\",v:\"得奇\",m:\"得奇小说\"},\n    {n:\"sou31\",v:\"速读谷\",m:\"速读谷\"},\n    {n:\"sou32\",v:\"919\",m:\"919言情\"},\n    {n:\"sou33\",v:\"七猫短剧\",m:\"🐱七猫短剧\"},\n    {n:\"sou34\",v:\"69书吧co\",m:\"69书吧co\"},\n    {n:\"sou35\",v:\"nt动漫\",m:\"🌸NT动漫\"},\n    {n:\"type1\",v:\"小说\",m:\"小说模式\"},\n    {n:\"type2\",v:\"听书\",m:\"听书模式\"},\n    {n:\"type3\",v:\"漫画\",m:\"漫画模式\"},\n    {n:\"type4\",v:\"视频\",m:\"视频模式\"}\n];\n\nfunction hasValidCustomSource() {\n    const value = (source.getLoginInfoMap())['自定义源站'];\n    return !(value == null || value == undefined || value == \"\" || String(value).trim() == \"\");\n}\n\nfunction showCustomSourceAlert() {\n    const customSource = (source.getLoginInfoMap())['自定义源站'];\n    java.toast(\n        \"\\n⚠️ 自定义源站配置提醒 ⚠️\\n\" +\n        \"──────────────────\\n\" +\n        \"检测到已设置自定义源站: \\n✨\" +\n        \"【\" + (customSource || \"\") + \"】✨\\n\" +\n        \"──────────────────\\n\" +\n        \"请前往「书源登录」清除配置\\n\" +\n        \"才能使指定源站切换生效\"\n    );\n}\n\nfunction updateConfig(key, value, message, gender) {\n    if (key == \"source\" && hasValidCustomSource()) {\n        showCustomSourceAlert();\n        return;\n    }\n    \n    try {\n        var config = JSON.parse(source.getVariable());\n        if (!config || !Array.isArray(config) || config.length === 0) {\n            config = [{}];\n        }\n        config[0][key] = value;\n        if (gender !== undefined) {\n            config[0][\"gender\"] = gender;\n        }\n        source.setVariable(JSON.stringify(config));\n        java.toast(message || \"设置已更新\");\n    } catch(e) {\n        var newConfig = {[key]: value};\n        if (gender !== undefined) {\n            newConfig[\"gender\"] = gender;\n        }\n        source.setVariable(JSON.stringify([newConfig]));\n        java.toast(message || \"初始化设置\");\n    }\n}\n\nfunction get_cx() {\n    try {\n        var configStr = source.getVariable();\n        if (!configStr || configStr.trim() == \"\") {\n            configStr = JSON.stringify([{host: hosts[0]}]);\n            source.setVariable(configStr);\n        }\n        var config = JSON.parse(configStr);\n        if (!config || !Array.isArray(config) || config.length == 0) {\n            config = [{host: hosts[0]}]; \n            source.setVariable(JSON.stringify(config)); \n        }\n        var currentHost = getServerHost();\n        var currentSource = (!('source' in config[0]) || !config[0].source) ? \"☁️ 聚合搜索 ☁️\" : (sourceList.find(item => item.v === config[0].source)?.m || config[0].source);\n        var currentGender = config[0].gender === \"boy\" ? \" 男🧸频 \" : (config[0].gender === \"girl\" ? \" 女🎀频 \" : \" 未设置 \");\n        var currentTone = config[0].sz ? \"音色\" + data[parseInt(config[0].sz) || 1][0] : \"默认音色\";\n        var customSource = (source.getLoginInfoMap())['自定义源站'] || \"未设置\"; \n        var customSourceStatus = hasValidCustomSource() ? \"🔗 \" + customSource : \"当前未设置,示例:米读,书旗\";\n        var keyStatus = (source.getLoginInfoMap())['密钥'] ? \"✅ 已填写\" : \"❌ 未填写\";\n        var username = \"未登录\";\n        \n        try {\n            var cookie_ = String(cookie.getKey(\"fanqienovel.com\", \"sessionid\")) || (source.getLoginInfoMap())['手动登录Token'];\n            if (cookie_) username = JSON.parse(java.ajax(\"https:\/\/fanqienovel.com\/api\/user\/info\/v2,\" + JSON.stringify({\n                method: \"GET\", headers: { \"Cookie\": \"sessionid=\" + cookie_ }\n            }))).data?.name || \"已登录(未获取到用户名)\";\n        } catch (e) {}\n\n        java.longToast(\n            \"\\n───────────────\\n\" +\n            \"☑️  配  置  状  态 ☑️\\n\" +\n            \"───────────────\\n\" +\n            \"🔘 服  务  器 🔘\\n\" + currentHost + \"\\n\" +\n            \"───────────────\\n\" +\n            \"🌋 书  源 🌋\\n\" + currentSource + \"\\n\" +\n            \"───────────────\\n\" +\n            \"🏔️ 偏  好 🏔️\\n\" + currentGender + \"\\n\" +\n            \"───────────────\\n\" +\n            \"🎧 AI 音 色 🎧\\n\" + currentTone + \"\\n\" +\n            \"───────────────\\n\" +\n            \"❇️ 自 定 义 源 ❇️\\n\" + customSourceStatus + \"\\n\" +\n            \"───────────────\\n\" +\n            \"🔆 密 匙 状 态 🔆\\n\" + keyStatus + \"\\n\" +\n            \"───────────────\\n\" +\n            \"🍅 登 录 用 户 🍅\\n\" + username + \"\\n\" +\n            \"───────────────\\n\" +\n            \"\\n✨ 提示:点击按钮切换配置\"\n        );\n    } catch(e) {\n        source.setVariable(JSON.stringify([{host: hosts[0]}]));\n        java.toast(\"⚠️ 配置初始化完成,请重试\");\n    }\n}\n\nthis.sethost = function() {\n    try {\n        var config = JSON.parse(source.getVariable());\n        if (!config || !Array.isArray(config) || config.length == 0) {\n            config = [{host: hosts[0]}];\n        }\n        \n        var currentHost = config[0].host || hosts[0];\n        var currentIndex = hosts.indexOf(currentHost);\n        var newIndex = (currentIndex + 1) % hosts.length;\n        var newHost = hosts[newIndex];\n        config[0].host = newHost;\n        source.setVariable(JSON.stringify(config));\n        java.toast(\"切换到:\" + newHost);\n    } catch(e) {\n        source.setVariable(JSON.stringify([{host: hosts[0]}]));\n        java.toast(\"已初始化:\" + hosts[0]);\n    }\n};\n\nfor (var i = 0; i < sourceList.length; i++) {\n    (function() {\n        var s = sourceList[i];\n        this[s.n] = function() {\n            if (hasValidCustomSource()) {\n                showCustomSourceAlert();\n                return;\n            } if (s.g) {\n                updateConfig(\"source\", s.v, \"\\n已切换\" + (s.v ? '到❇️' : '') + s.m +\"❇️\\n刷新发现页生效\", s.g);\n            } else {\n                updateConfig(\"source\", s.v, \"\\n已切换\" + (s.v ? '到❇️' : '') + s.m +\"❇️\\n刷新发现页生效\");\n            }\n        };\n    }).call(this);\n}\n\n\/\/打赏\nfunction vip() { java.startBrowserAwait('https:\/\/search.shusan.icu\/coffee.html', \"喝咖啡\"); }\nfunction key() { java.startBrowserAwait(getServerHost() + '\/key', \"获取密钥\"); }\nfunction cx() { java.startBrowserAwait(getServerHost() + '\/cx', \"密钥查询\"); }\nfunction version() { java.startBrowserAwait(getServerHost() + '\/version?id=' + LOCAL_VERSION, \"版本检查\"); }\n\nfunction Map(e) {\n    if (e == \"source\" && hasValidCustomSource()) {\n        showCustomSourceAlert();\n        return (source.getLoginInfoMap())['自定义源站'];\n    }\n    var infomap = source.getLoginInfoMap();\n    const value = infomap[e];\n    if (!value) {\n        java.longToast(\"需要填写密钥\");\n    }\n    return value;\n}\n\nfunction fq_login() {\n    try { \tjava.startBrowserAwait(\"https:\/\/fanqienovel.com\/\", \"登录\");\n    } catch (e) {\n        java.toast(e);\n    }\n    try {\n        cookie.removeCookie(\"snssdk.com\");\n    } catch (e) {}\n    \n    let cookieHeader = String(cookie.getCookie('fanqienovel.com'));\njava.toast(cookieHeader);\n    \n    const match = cookieHeader.match(\/sessionid=([^;]+)\/);\n    java.toast(match);\n    let sessionId = match ? match[1] : null;\n\n    let cookieString = sessionId ? \"sessionid=\" + sessionId : source.getLoginInfoMap()['手动登录Token'] || \"\";\n    java.toast(cookieString);\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: { \"Cookie\": cookieString }\n        }))).data.name;\n    } catch (e) { \n        java.log(e); \n    }\n    \n    if (!cookieString || cookieString == \"sessionid=\" || !user) {\n        java.toast(\"未获取到登录凭据,登录失败\");\n        return false;\n    }\n    \n    java.toast(\"\\n\\n欢迎 \" + user + \"\\n登录成功!\");\n    return true;\n}\n\nfunction login(){}\nfunction logout() {\n    cookie.removeCookie(\"fanqienovel.com\");\n    cookie.removeCookie(\"snssdk.com\");\n    if (String(cookie.getKey(\"fanqienovel.com\", \"sessionid\")) || \n        (source.getLoginInfoMap())['手动登录Token']) {\n        java.toast(\"请手动移除填写的Token\");\n    } else {\n        java.toast(\"退出登录成功\");\n    }\n}\n\nfunction toggleParacomment() {\n    const key = \"fqparas\";\n    let status = java.get(key) ?? \"off\";\n    if (status == \"on\") {\n        java.put(key, \"off\");\n        java.toast(\"\\n🍅番茄小说段评已关闭\");\n    } else {\n        java.put(key, \"on\");\n        java.toast(\"\\n🍅番茄小说段评已开启\");\n    }\n}\n\nfunction toggleFqdown(a) {\n    let status = java.get(a) ?? \"off\";\n    if (status == \"off\") {\n        java.put(a, \"on\");\n        java.toast(\"\\n🍅番茄小说\\n下载模式已开启\");\n    } else {\n        java.put(a, \"off\");\n        java.toast(\"\\n🍅番茄小说\\n下载模式已关闭\");\n    }\n}\n\nfunction boy() { updateConfig(\"gender\", \"boy\", \"\\n已设置为\\n🧸男频🧸\\n刷新发现页生效\"); }\nfunction girl() { updateConfig(\"gender\", \"girl\", \"\\n已设置为\\n🎀女频🎀\\n刷新发现页生效\"); }\nfunction recommend() { \n    updateConfig(\"gender\", \"recommend\", \"\\n已设置为\\n❇️网友推荐❇️\\n刷新发现页生效\");\n    updateConfig(\"source\", \"推荐\"); }\nfunction tj() {\n    var key = (source.getLoginInfoMap())['密钥']; java.startBrowserAwait(getServerHost() + '\/login?key=' + java.base64Encode(key), \"书籍推荐\");}",
    "respondTime": 180000,
    "ruleBookInfo": {
        "author": "$.author",
        "coverUrl": "$.cover",
        "downloadUrls": "$.book_url\n@js:\neval(String(source.loginUrl));\nlet url = java.base64Decode(result);\nlet book_id = url.match(\/\\d{19}\/)?.[0];\nif (!book_id) throw new Error(\"未找到有效书籍ID\");\nlet getkey = java.base64Encode(Map('密钥'));\nlet downloadUrl = getServerHost() + `\/down?key=${getkey}&book_id=${book_id}`;\njava.toast('\\n如果提示Unexpected webFileData,请等待几秒后点击阅读导入…\\n在线阅读关闭⚡下载模式后刷新即可');\ndownloadUrl;",
        "init": "<js>\nif (String(baseUrl).startsWith(\"data:\")) {\n    let res = JSON.parse(java.hexDecodeToString(result));\n    let {source: source_name, url: book_url, name: title} = res;\n    \n\/\/ 仅在番茄小说且开启下载模式时设置\nif (source_name == \"番茄小说\" &&   \n\t   java.get(\"fqdown\") == \"on\") {\n    book.type = 128;\n}\n\n    let request = getServerHost() +`\/details?source=${source_name}&url=${book_url}&name=${title}`;\n    \/\/java.log(request);\n    result = java.ajax(request);\n    \/\/java.log(result);\n}\nresult;\n<\/js>\n$.data",
        "intro": "&nbsp;&nbsp;\n✨ 源站:{{$.source}}{{\"\\n\"+\"​\"}}\n{{$.desc}}\n<js>\nconst tomatoSources = [\"番茄小说\", \"番茄听书\", \"番茄畅听\"];\n\nif (tomatoSources.includes(\"{{$.source}}\")) {\n    try {\n        let finalUrl;\n        let urlMatch = baseUrl.match(\/url=([^&]*)\/);\n        \n        if (urlMatch && urlMatch[1]) {\n            finalUrl = java.base64Decode(urlMatch[1]);\n        } else {\n            let fqurl = JSON.parse(java.base64Decode(baseUrl.split(\",\")[1]));\n            finalUrl = java.base64Decode(fqurl.url);\n        }\n        \n        let bookIdMatch = finalUrl.match(\/book_id=(\\d{19})\/);\n        if (bookIdMatch && bookIdMatch[1]) {\n            let bookId = bookIdMatch[1];\n            let newUrl = getServerHost() + \"\/detail?book_id=\" + bookId;\n            let response = java.ajax(newUrl);\n            let responseData = JSON.parse(response);\n            \n            let bookData;\n            if (Array.isArray(responseData.data)) {\n                bookData = responseData.data[0];\n            } else {\n                bookData = responseData.data;\n            }\n            \n            if (bookData) {\n                if (bookData.book_id) {\n                    var sessionid = getSessionId();\n                    if (sessionid && sessionid.trim() !== \"\") {\n                        var syncUrl = getServerHost() + \"\/update_history?book_id=\" + bookData.book_id + \"&sessionid=\" + sessionid;\n                        java.ajax(syncUrl);\n                    }\n                }\n                \n                let bookName = bookData.original_book_name || bookData.book_name || \"\";\n                let aliasName = bookData.book_flight_alias_name || bookData.sub_title || \"\";\n                let createTime = bookData.create_time ? bookData.create_time.split('T')[0] : \"\";\n                let updateTime = bookData.last_chapter_update_time ? java.timeFormat(parseInt(bookData.last_chapter_update_time)*1000) : \"\";\n                \n                let authors = [];\n                try {\n                    authors = bookData.original_authors ? JSON.parse(bookData.original_authors) : [];\n                } catch(e) {\n                    authors = bookData.roles ? bookData.roles.replace(\/[\\[\\]\"]\/g,'').split(',') : [];\n                }\n                let authorName = authors.length > 0 ? (authors[0].AuthorName || authors[0] || \"\") : \"\";\n                \n                let tags = bookData.pure_category_tags || bookData.tags || \"\";\n                let readCount = bookData.read_count || \"0\";\n                \n                let bookStatus = \"正常\";\n                if (bookData.book_search_visible === 'false') {\n                    bookStatus = \"下架\";\n                } else if (bookData.tomato_book_status === '3') {\n                    bookStatus = \"小黑屋\";\n                }\n                \n                let abstract = bookData.book_abstract_v2 || bookData.abstract || \"\";\n                let copyrightInfo = bookData.copyright_info || \"\";\n                \n                let output = `&nbsp;&nbsp;\n✨ 源站:{{$.source}}{{\"\\n\"+\"​\"}}\n📕 源名:${bookName}`;\n                \n                if (aliasName) {\n                    output += `\\n📖 别名:${aliasName}`;\n                }\n                \n                output += `\\n✏️ 开坑:${createTime} \n🧭 更新:${updateTime}&lrm;\n👤 作者:${authorName}\n🏷️ 标签:${tags}\n👁️ 在线:${readCount}人在读\n🔗 书籍状态:${bookStatus}`;\n                \n                if ([\"番茄听书\"].includes(\"{{$.source}}\")) {\n                    try {\n                        let tones = \"\\n===================\\n🎧AI音色编号信息: \";\n                        let info = JSON.parse(java.ajax(`https:\/\/reading.snssdk.com\/reading\/bookapi\/audio\/toneinfo\/?book_id=${bookData.book_id}&aid=1967`));\n                        for (let i of (info.data.tts_tones ? info.data.tts_tones : [])) {\n                            tones += `\\n${i.id} - ${i.title}${i.description ? \"(\" + i.description + \")\" : \"\"}`;\n                        }\n                        output += tones;\n                    } catch (e) {\n                    }\n                }\n                \n                output += `{{\"\\n\"+\"​\"}}\n📜 简介:${abstract}{{\"\\n\"+\"​\"}}`;\n                \n                if (copyrightInfo) {\n                    output += `\\n📍 ${copyrightInfo.split(',')[0]}。`;\n                }\n                \n                result = output;\n            }\n        }\n    } catch (e) {\n    }\n}\nresult;\n<\/js>",
        "kind": "$.tags",
        "lastChapter": "$.latestChapterTitle",
        "name": "$.title",
        "tocUrl": "<js>\nlet catalog = {\n    source: result.source,\n    url: result.book_url,\n    name: result.title,\n    tab: result.tab || \"novel\"\n};\n\nvar tabTips = {audio: '听书', video: '视频', comic: '漫画'}; \nif (tabTips[catalog.tab]) {\n    java.toast('当前为' + tabTips[catalog.tab] + '模式');\n}\n\nyunurl = java.base64Encode(JSON.stringify(catalog));\nresult = `data:catalogUrl;base64,${yunurl},{\"type\":\"shushan\"}`;\n<\/js>",
        "wordCount": "$.wordCount"
    },
    "ruleContent": {
        "content": "<js>\neval(String(source.loginUrl));\n\nlet deviceParam = chapter.url.match(\/device=([^&]*)\/)?.[1] || 'android';\nconst isAndroid = deviceParam == 'android';\n\nlet book_id = chapter.url.match(\/book_id=(\\d{19})\/)?.[1];\nlet item_id = chapter.url.match(\/item_id=(\\d+)\/)?.[1];\nlet qm_id = null;\n\nif (\/七猫短剧\/.test(chapter.url)) {\n    try {\n        const urlParam = chapter.url.match(\/url=([^&]+)\/)?.[1];\n        if (urlParam) {\n            const decodedUrl = java.base64Decode(urlParam);\n            qm_id = decodedUrl.match(\/qm_id=(\\d+)\/)?.[1]\n        }\n    } catch (e) {}\n}\n\nlet contentUrl = getServerHost() + baseUrl.split(',')[0].replace(\/^https?:\\\/\\\/[^\\\/]+\/, '') + `&key=${getSecretKey()}&version=9`;\nlet response = JSON.parse(java.ajax(contentUrl));\nlet result = response.data.content;\n\nif ((\/番茄短剧\/.test(chapter.url) && book_id) || (\/七猫短剧\/.test(chapter.url) && qm_id)) {\n    try {\n        const paramName = \/番茄短剧\/.test(chapter.url) ? 'book_id' : 'qm_id';\n        const paramValue = \/番茄短剧\/.test(chapter.url) ? book_id : qm_id;\n        const videoUrl = getServerHost() + `\/player?${paramName}=${paramValue}&key=${getSecretKey()}`;\n        if (book.durChapterIndex == chapter.index) {\n            java.startBrowser(videoUrl, chapter.title || '视频播放');\n            java.toast('视频加载中...')\n        }\n        result = `▶️刷新正文进入播放界面`\n    } catch (e) {}\n}\n\nif (response.data.tab == \"video\" && book.durChapterIndex == chapter.index && !\/番茄短剧|七猫短剧\/.test(chapter.url)) {\n    let normalVideoUrl = java.base64Decode(result.trim());\n    java.startBrowser(normalVideoUrl, chapter.title || '视频播放');\n    java.toast('视频加载中...');\n    result = `▶️刷新正文进入播放界面`\n}\n\nif (\/^[A-Za-z0-9+\/=]+$\/.test(result.trim())) {\n    if (isAndroid) {\n        with(new JavaImporter(Packages.java.util.zip, Packages.java.io, Packages.android.util)) {\n            let bytes = Base64.decode(result, Base64.DEFAULT);\n            try {\n                let reader = new BufferedReader(new InputStreamReader(new InflaterInputStream(new ByteArrayInputStream(bytes)), \"UTF-8\"));\n                let content = \"\";\n                while ((line = reader.readLine()) != null) content += line + \"\\n\";\n                reader.close();\n                result = content.trim()\n            } catch (e) {\n                try {\n                    let rawReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes), \"UTF-8\"));\n                    let rawContent = \"\";\n                    while ((line = rawReader.readLine()) != null) rawContent += line + \"\\n\";\n                    rawReader.close();\n                    result = rawContent.trim()\n                } catch (e2) {}\n            }\n        }\n    } else {\n        try {\n            result = java.base64Decode(result.trim());\n        } catch (e) {}\n    }\n}\n\nif (chapter.url.includes('tone_id=')) {\n    let toneId = chapter.url.match(\/tone_id=([^&]*)\/)?.[1] || '';\n    if (toneId && item_id) {\n        try {\n            let apiData = JSON.parse(java.ajax(getServerHost() + `\/audio?tone_id=${toneId}&item_ids=${item_id}`));\n            if (apiData.data?.[0]?.main_url) result = apiData.data[0].main_url\n        } catch (e) {}\n    }\n}\n\nif (isAndroid && java.get(\"fqparas\") == \"on\" && java.get(\"fqdown\") != \"on\" && book_id && !chapter.url.includes('tone_id=')) {\n    result = result.replace(\/\\n+\/g, \"\\n\");\n    result = getComments(result, book_id, item_id)\n}\n\nif (isAndroid) {\n    try {\n        let config = JSON.parse(source.getVariable());\n        let now = Date.now();\n        let fourHours = 2 * 60 * 60 * 1000;\n        if (!config[0].lastUpdateCheck || (now - config[0].lastUpdateCheck) > fourHours) {\n            config[0].lastUpdateCheck = now;\n            source.setVariable(JSON.stringify(config));\n            let versionData = JSON.parse(java.ajax(getServerHost() + \"\/version?vid=sy\"));\n            if (versionData.version) {\n                if (versionData.force && versionData.force.toString().toLowerCase() == \"true\" && versionData.version > localVersion) {\n                    java.startBrowser(version());\n                    result = \"请更新书源!下载页面已打开。\"\n                }\n                let msg = versionData.version > localVersion ? `\\n✨发现新版本V${versionData.version}(当前V${localVersion})` + (versionData.msg ? `\\n${versionData.msg}` : '') : versionData.version < localVersion ? `\\n⚠️版本异常\\n本地V${localVersion}>云端V${versionData.version}\\n请检查书源配置` : '';\n                if (msg) java.toast(msg)\n            } else if (versionData.msg) {\n                java.toast(versionData.msg)\n            }\n        }\n    } catch (e) {\n        java.toast(\"⚠️ 版本检查失败: \" + e.message)\n    }\n}\n\nlet tab = response.data.tab || \"\";\nlet fq = response.data.source || \"\";\nlet notice = response.data.notice || \"\";\nif (tab == \"novel\" && notice && notice.trim() !== \"\") {\n    result += \"\\n\" + notice\n}\n\nif (fq == \"番茄小说\" && tab == \"novel\" && book_id) {\n    if (java.get(\"fqdown\") == \"on\" && book.durChapterIndex == chapter.index) {\n        java.startBrowser(getServerHost() + `\/down?key=${getSecretKey()}&book_id=` + book_id, \"番茄\");\n        java.toast(\"\\n当前下载模式已开启,在线阅读请先关闭下载模式!!!\");\n        result = \"🔄 刷新跳转到下载页面,在线阅读请关闭下载模式后刷新正文...\"\n    }\n}\n\nresult = result.replace(chapter.title, '');\n<\/js>",
        "imageStyle": "TEXT",
        "replaceRegex": "##\\{\\!\\-\\- PGC_VOICE\\:.*\\-\\-\\}|\\(本章完\\)"
    },
    "ruleExplore": {
        "author": "$.author",
        "bookList": "<js>\nfunction getBookIdFull(url) {\n    const {java} = this;\n    let $ = JSON.parse(url).data;\n    let arr = [];\n    if ($.book_shelf_info && $.book_shelf_info.length > 0) {\n        arr = $.book_shelf_info.map(item => item.book_id);\n    } else if ($.data_list && $.data_list.length > 0) {\n        arr = $.data_list.map(item => item.book_id_str);\n    } else {\n        java.toast(\"获取 book_id 失败,你可能需要登录!\");\n    }\n    return arr;\n}\n\nlet session = getSessionId()\n\ngetShelf = () => {\n    let book_shelf_info = java.ajax(getServerHost() + \"\/book_shelf?session=\" + session)\n    \n    bid = getBookIdFull(book_shelf_info)\n    \n    let id_list = splitArray(bid, 200)\n    let urls = []\n    id_list.forEach(i => {\n        urls.push(getServerHost() +\"\/detail?book_id=\" + i.join(\",\"))\n    })\n    res = java.ajaxAll(urls)\n\n    let resp = {book_info: []}\n    res.forEach(r => {\n        resp.book_info = resp.book_info.concat(JSON.parse(r.body()).data)\n    })\n\n    return resp\n}\n\nfunction getByGroupName(name) {\n    let book_shelf_info = JSON.parse(java.ajax(getServerHost() +\"\/book_shelf?session=\" + session))\n    \n    let group_bookids = {\n        \"未分组\": []\n    }\n    book_shelf_info.data.book_shelf_info.forEach(i => {\n        if (!group_bookids[i.group_name ? i.group_name : \"未分组\"]) group_bookids[i.group_name] = []\n        group_bookids[i.group_name ? i.group_name : \"未分组\"].push(i.book_id)\n    })\n    \n    if (!group_bookids[decodeURIComponent(name)]) return {data: []}\n    \n    let book_ids = splitArray(group_bookids[decodeURIComponent(name)], 200)\n    let urls = []\n\n    book_ids.forEach(i => { \turls.push(\"https:\/\/api5-normal-sinfonlineb.fqnovel.com\/reading\/bookapi\/multi-detail\/v\/?aid=1967&iid=1&version_code=999&book_id=\" + i.join(\",\"))\n    })\n    \n    res = java.ajaxAll(urls)\n\n    let resp = {book_info: []}\n    res.forEach(r => {\n        resp.book_info = resp.book_info.concat(JSON.parse(r.body()).data)\n    })\n\n    return resp\n}\n\nfunction getByTabIndex(index) {\n    let url = _mlsec.requestHeader(\n        \"bookmall\/tab\",\n        \"version_name=5.8.9.32\",\n        null,\n        \"sessionid=\" + session\n    )\n    let all = JSON.parse(java.ajax(url))\n    let tab = all.data.tab_item[0].cell_data[index].cell_data\n    if (!tab) tab = []\n    let bookList = []\n    for (let i of tab) {\n        bookList = bookList.concat(i.book_data)\n    }\n    return { book_info: bookList }\n}\n\nfunction normalizeResponse(data) {\n    if (data.book_info) return data.book_info;\n    if (data.data && data.data.book_info) return data.data.book_info;\n    if (data.data && Array.isArray(data.data)) return data.data;\n    if (data.list) return data.list;\n    if (data.book_list) return data.book_list;\n    if (data.data && data.data.publication_list) return data.data.publication_list;\n    if (data.result) return data.result;\n    if (data.data && data.data.result) return data.data.result;\n    if (data.data && data.data.cell_view && data.data.cell_view.book_data) {\n        return data.data.cell_view.book_data;\n    }\n    if (data.data && data.data.records) return data.data.records;\n    if (data.data && data.data.list) return data.data.list;\n    return [];\n}\n\nif (baseUrl.endsWith(\"bookshelf\")) {\n    result = getShelf(\"bookshelf\/info\")\n} else if(\/read_history\/.test(baseUrl)) {\n    let pageMatch = baseUrl.match(\/page=(\\d+)\/);\n    let page = pageMatch ? pageMatch[1] : '1';\n    \n    let history_response = java.ajax(getServerHost() + \"\/read_history?session=\" + session + \"&page=\" + page)\n    let history_data = JSON.parse(history_response)\n    \n    if (history_data.code == 0 && history_data.data && history_data.data.data_list) {\n        let book_ids = history_data.data.data_list.map(item => item.book_id_str)\n        \n        let id_list = splitArray(book_ids, 200)\n        let urls = []\n        id_list.forEach(i => {\n            urls.push(\"https:\/\/api5-normal-sinfonlineb.fqnovel.com\/reading\/bookapi\/multi-detail\/v\/?aid=1967&iid=1&version_code=999&book_id=\" + i.join(\",\"))\n        })\n        \n        let resp = {book_info: []}\n        urls.forEach(url => {\n            let detailResponse = java.ajax(url)\n            let detailData = JSON.parse(detailResponse)\n            if (detailData.data) {\n                resp.book_info = resp.book_info.concat(detailData.data)\n            }\n        })\n        \n        result = resp\n    } else {\n        result = {book_info: []}\n    }\n} else {\n    let w = baseUrl.split(\"\/\")\n    if (baseUrl.includes(\"groupName\")) {\n        result = getByGroupName(w[w.length - 1])\n    } else if (baseUrl.includes(\"tab\")) {\n        result = getByTabIndex(parseInt(w[w.length - 1]))\n    } else {\n        result = JSON.parse(result)\n        if (result.data && result.data.data) {\n            result = {book_info: result.data.data}\n        }\n    }\n}\n\nlet normalizedData = normalizeResponse(result);\n\nJSON.stringify({data: normalizedData})\n<\/js>\n$.data[*]",
        "bookUrl": "<js>\nlet tjurl = result.tjurl;\nlet source = result.source;\nlet book_url = result.book_url;\nlet title = result.title || result.book_name;\nlet book_id = result.book_id || result.series_id;\n\nlet detail = {\n    source: source,\n    url: book_url,\n    name: title\n};\n\nif (tjurl && tjurl.trim() !== \"\") {\n    let sourceMatch = tjurl.match(\/source=([^&]*)\/);\n    let urlMatch = tjurl.match(\/url=([^&]*)\/);\n    let nameMatch = tjurl.match(\/name=([^&]*)\/);\n    \n    detail.source = sourceMatch ? sourceMatch[1] : \"\";\n    detail.url = urlMatch ? urlMatch[1] : java.base64Encode(tjurl.trim());\n    detail.name = nameMatch ? nameMatch[1] : \"\";\n} \nelse if (book_id && \/^\\d{19}$\/.test(book_id)) {\n    detail.url = java.base64Encode(`https:\/\/api5-normal-sinfonlineb.fqnovel.com\/reading\/bookapi\/multi-detail\/v\/?aid=1967&iid=1&version_code=999&book_id=${book_id}`);\n    detail.source = \"番茄小说\";\n} else if (book_url) {\n    detail.url = java.base64Encode(book_url);\n}\n\nlet yunurl = java.base64Encode(JSON.stringify(detail));\n`data:detailsUrl;base64,${yunurl},{\"type\":\"shushan\"}`;\n<\/js>",
        "coverUrl": "$.audio_thumb_uri||$.thumb_url||$.thumbUri||$.cover",
        "intro": "$.recommend_reason||$.abstract||$.desc",
        "kind": "$.tags",
        "lastChapter": "$.lastChapterTitle||$.last_chapter_title",
        "name": "$.book_name||$.bookName||$.title",
        "wordCount": "$.word_number||$.WordsCount"
    },
    "ruleSearch": {
        "author": "$.author",
        "bookList": "$.data",
        "bookUrl": "<js>\nlet source = result.source;\nlet book_url = result.book_url;\nlet title = result.title;\n\nlet detail = {\n    source: source,\n    url: book_url,\n    name: title\n};\n\nyunurl = java.base64Encode(JSON.stringify(detail));\n`data:detailsUrl;base64,${yunurl},{\"type\":\"shushan\"}`\n<\/js>",
        "checkKeyWord": "我在精神病院学斩神@番茄小说",
        "coverUrl": "$.cover",
        "intro": "$.desc",
        "kind": "$.tags",
        "lastChapter": "{{$.source}}·{{$.latestChapterTitle}}",
        "name": "$.title",
        "wordCount": "$.wordCount"
    },
    "ruleToc": {
        "chapterList": "<js>\nlet res = JSON.parse(java.hexDecodeToString(result));\nlet catalog = {\n    source: res.source,\n    url: res.url,\n    name: res.name,\n    tab: res.tab || \"novel\"\n};\n\nvar tabTips = {audio: '听书', video: '视频', comic: '漫画'}; \nif (tabTips[catalog.tab]) {\n    java.toast('当前为' + tabTips[catalog.tab] + '模式');\n}\n\nlet op = {\n    method: \"POST\",\n    body: {\n        source: catalog.source,\n        url: catalog.url,\n        name: catalog.name\n    }\n};\n\nlet catalogUrl = getServerHost() +`\/catalog,${JSON.stringify(op)}`;\nlet response = java.ajax(catalogUrl);\n\nfunction deviceType() {\n    try {\n        return !!java.androidId();\n    } catch (e) {\n        return false;\n    }\n}\nlet device = deviceType() ? 'android' : 'ios';\nif (device == 'android') {\n    var typeMap = {audio:32, comic:64};\n    book.type = catalog.tab in typeMap ? typeMap[catalog.tab] : 8;\n} else {\n    var typeMap = {audio:1, comic:2, video:3};\n    book.type = catalog.tab in typeMap ? typeMap[catalog.tab] : 0;\n}\n\nJSON.parse(response).data.map((x) => {\n    const isFanqieApp = ['番茄小说', '番茄短剧', '番茄听书', '番茄畅听'].includes(catalog.source);\n    const urlToMatch = x.url || catalog.url;\n    const bookId = urlToMatch.match(\/book_id=(\\d{19})\\b\/)?.[1] || null;\n    const itemId = urlToMatch.match(\/item_id=(\\d+)\/)?.[1] || null;\n    \n    let contentUrl = getServerHost() + `\/chapter?cid=${x.cid}&source=${catalog.source}&device=${device}`;\n    \n    if (!isFanqieApp) {\n        contentUrl += `&url=${catalog.url}`;\n    } else {\n        contentUrl += `&book_id=${bookId}&item_id=${itemId}`;\n        \n        if (['番茄听书', '番茄畅听'].includes(catalog.source)) {\n            const toneId = Number((source.getLoginInfoMap())['听书AI音色编号']) || 1;\n            contentUrl += `&tone_id=${toneId}`;\n        }\n    }\n    \n    if (catalog.source == '番茄小说') {\n        const commentPart = `{\"type\":\"qingci\",\"js\":\"book ? result : '${getServerHost()}\/comment?sessionid=${getSessionId()}&item_id=${itemId}&book_id=${bookId}'\"}`;\n        x.url = `${contentUrl},${commentPart}`;\n    } else {\n        x.url = contentUrl;\n    }\n    \n    return x;\n});\n<\/js>",
        "chapterName": "title",
        "chapterUrl": "url",
        "isVip": "isVip",
        "isVolume": "isVolume",
        "updateTime": "tag"
    },
    "searchUrl": "<js>\nlet config = (() => {\n    try {\n        let cfg = JSON.parse(source.getVariable())[0] || {};\n        if (!cfg.host || !cfg.gender) {\n            cfg = {gender: \"boy\", host: getServerHost()};\n            source.setVariable(JSON.stringify([cfg]));\n            java.toast(\"配置初始化完成\");\n        }\n        return cfg;\n    } catch(e) {\n        let cfg = {gender: \"boy\", host: getServerHost()};\n        source.setVariable(JSON.stringify([cfg]));\n        return cfg;\n    }\n})();\n\nvar sourceVal = '';\nvar customSource = '';\n\ntry {\n    customSource = (source.getLoginInfoMap())['自定义源站'];\n} catch(e) {\n    customSource = '';\n}\n\nif (customSource !== undefined && customSource !== null && String(customSource).trim() !== \"\") {\n    sourceVal = String(customSource).trim();\n} else if (config.source) {\n    sourceVal = config.source;\n}\n\nvar param = sourceVal ? '&source=' + encodeURIComponent(sourceVal) : '';\nvar searchUrl = getServerHost() + '\/search?page={{page}}&key={{key}}' + param;\n\nif (key && key.length == 19 && !Number.isNaN(parseInt(key))) {\n    var u = `https:\/\/api5-normal-sinfonlineb.fqnovel.com\/reading\/bookapi\/multi-detail\/v\/?aid=1967&iid=1&version_code=999&book_id=${key}`;\n    var kdy = java.base64Encode(u);\n    var response = JSON.parse(java.ajax(u));\n    var nam = response.data.book_name || (response.data[0] && response.data[0].book_name) || '未知书名';\n    result = getServerHost() + `\/details?url=${kdy}&source=番茄小说&name=${encodeURIComponent(nam)}`;\n} else {\n    result = searchUrl;\n}\n<\/js>",
    "weight": 0
}
广告