[
{
"bookSourceComment": "如果是用的官方版阅读,或者低版本阅读,推荐更新阅读以使用新功能,否则很多功能无法使用哦\n软件下载地址:https://legado.qingtian618.com\n推荐使用阅读R或者阅读Sigma\n\n\n晴天聚合重构,已适配所有安卓版本阅读\n目前不适配苹果端栖阅(可以正常阅读,发现页无法适配)\n\n更新日志请点击登录,更新书源中查看\n\n基础使用教程:\n1、搜索:\n 1)基础搜索:在发现页长按该书源,点击搜索,直接搜,搜索范围(全部来源小说)\n 2)进阶搜索:在登陆-书源设置中选择指定模式/来源,可搜索指定模式/来源内容\n 3)快捷搜索:使用特殊关键词(x,t,m,d,@)搜索\n x:书名@来源 如(x:十日终焉@番茄)\n t:书名@来源 如(t:十日终焉@番茄)\n m:书名@来源 如(m:十日终焉@番茄)\n d:书名@来源 如(d:十日终焉@番茄)\n 其中:x表示小说(可省略),t表示听书,m表示漫画,d表示短剧\n 冒号支持中文英文\n \n2、发现页:\n 在书源设置中选择指定模式或者单个来源,然后刷新发现页即可\n \n3、更多使用方式进入书源设置页面应该能一目了然",
"bookSourceGroup": "📖番茄小说",
"bookSourceName": "🔅光遇聚合",
"bookSourceType": 0,
"bookSourceUrl": "光遇聚合",
"bookUrlPattern": "https?:\\/\\/(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(?::\\d+)?\\/detail.*",
"customButton": false,
"customOrder": 0,
"enabled": true,
"enabledCookieJar": true,
"enabledExplore": true,
"eventListener": false,
"exploreUrl": "\n\n\nlet moreSettings = getVariable('更多设置');\nvar base_url = BaseUrl();\nvar source_type = getVariable('频道') || '男频';\nlet tab = moreSettings && moreSettings['搜索模式'] || '小说';\nlet sources = getVariable(\"发现页来源\") || moreSettings && moreSettings[tab] || '全部';\nlet islyc = checkEnv();\nlet wordNum = getVariable('字数') || '不限';\nlet update = getVariable('更新') || '不限';\nlet sort = getVariable('排序') || '综合';\nlet wordNumMap = {\n '不限': 'word_num_default',\n '10万字以内': 'word_num_lte10',\n '30万字以内': 'word_num_lte30',\n '50万字以内': 'word_num_lte50',\n '30万字以上': 'word_num_gte30',\n '50万字以上': 'word_num_gte50',\n '100万字以上': 'word_num_gte100',\n '200万字以上': 'word_num_gte200',\n '300万字以上': 'word_num_gte300',\n '500万字以上': 'word_num_gte500'\n};\nlet wordNumParam = wordNumMap[wordNum] || 'word_num_default';\nlet updateMap = {\n '不限': 'creation_status_default',\n '完结': 'creation_status_end',\n '半年内完结': 'creation_status_half_year_end',\n '连载中': 'creation_status_loading',\n '3日内更新': 'creation_status_3day_update',\n '7日内更新': 'creation_status_7day_update',\n '1月内更新': 'creation_status_1month_update'\n};\nlet updateParam = updateMap[update] || 'creation_status_default';\nlet sortMap = {\n '综合': 'sort_default',\n '新书': 'sort_new_book',\n '高分': 'sort_score',\n '字数': 'sort_word_number'\n};\nlet sortParam = sortMap[sort] || 'sort_default';\nlet selected_items = `${wordNumParam},${updateParam},${sortParam}`;\n\n\nif (islyc != \"苹果\" && islyc != \"安卓\"){\n\ttab = getVariable(\"发现页类型\");\n\t}\n\n\nlet js;\n\njs = getVariable('云端配置');\n//java.longToast(JSON.stringify(js))\nif (!!!js) {\n getCloudSettings(true);\n js = getVariable('云端配置');\n }\n\n\nlet source_list = [];\ntry{\nsource_list = js[tab];\n} catch (e) {\n\tjava.longToast(e);\n\t}\n\nlet fqssionid = getFqToken();\nif (!fqssionid && (sources == '番茄' || sources == '全部')) {\n java.toast('您还未登陆番茄账号,无法同步数据哦!');\n} \nvar fqsjurl = base_url + \"/bookshelf?page={{page}}&ssionid=\" + fqssionid;\nvar fqtjurl = base_url + \"/fqrecommend?page={{page}}&ssionid=\" + fqssionid;\nvar fqlsurl = base_url + \"/fqhistory?page={{page}}&ssionid=\" + fqssionid;\n\n\nvar groupDatas = [];\nvar infoData = [ ];\nif (sources == '番茄' || sources == '全部') {\ninfoData = [{\n \"title\": \"登录番茄\",\n \"url\": '{\\{java.startBrowser(\"https://fanqienovel.com/\",\"番茄登录\");}}',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.45\n }\n }];\n}\n\nvar hasValidCookie = fqssionid.length > 0;\n\nif (hasValidCookie && (sources == '番茄' || sources == '全部')) {\n function groupQuery() {\n try {\n var url = base_url + \"/group_name?ssionid=\" + fqssionid;\n var res = java.ajax(url);\n var response = JSON.parse(res);\n\n if (!(response && response.data)) {}\n\n response.data.forEach(function(group) {\n var keys = Object.keys(group);\n if (keys.length > 0) {\n var key = keys[0];\n var value = group[key];\n if (value && value.length) {\n var option = {\n \"method\": \"POST\",\n \"body\": {\n \"book_ids\": value,\n \"page\": \"{{page}}\"\n }\n };\n groupDatas.push({\n title: key,\n url: base_url + \"/bookshelf,\" + JSON.stringify(option),\n style: {\n layout_flexGrow: 1,\n layout_flexBasisPercent: 0.25\n }\n });\n }\n }\n });\n\n if (groupDatas.length % 2 != 0) {\n groupDatas.push({\n title: \"--\",\n url: \"\",\n style: {\n layout_flexGrow: 1,\n layout_flexBasisPercent: 0.25\n }\n });\n }\n if (groupDatas.length % 3 != 0) {\n groupDatas.push({\n title: \"--\",\n url: \"\",\n style: {\n layout_flexGrow: 1,\n layout_flexBasisPercent: 0.25\n }\n });\n }\n } catch (e) {\n java.longToast(\"番茄登录过期,已隐藏番茄书架\" + fqssionid);\n }\n }\n\n try {\n java.longToast(\"正在加载番茄分组数据...\");\n var userUrl = base_url + \"/fquser?ssionid=\" + fqssionid;\n var userRes = java.ajax(userUrl);\n var userData = JSON.parse(userRes);\n\n var userName = (userData && userData.data && userData.data.name) ? userData.data.name : '未知用户';\n if (!userName.includes('未知用户')) {\n infoData = [{\n title: userName+'的番茄',\n url: '',\n style: {\n layout_flexGrow: 1,\n layout_flexBasisPercent: 1\n }\n },\n {\n title: '番茄书架',\n url: fqsjurl,\n style: {\n layout_flexGrow: 1,\n layout_flexBasisPercent: 0.25\n }\n }, \n {\n title: \"个性推荐\",\n url: fqtjurl,\n style: {\n layout_flexGrow: 1,\n layout_flexBasisPercent: 0.25\n }\n }, {\n title: \"历史阅读\",\n url: fqlsurl,\n style: {\n layout_flexGrow: 1,\n layout_flexBasisPercent: 0.25\n }\n }];\n }\n groupQuery();\n } catch (e) {\n java.longToast(\"番茄登录过期,已隐藏番茄书架\");\n }\n}\n\nvar style_list = [];\ntry {\n var durl = `${base_url}/discovestyle?source=${sources}&source_type=${source_type}&tab=${tab}`;\n var res = java.ajax(durl);\n var result = JSON.parse(res);\n style_list = result.data || [];\n if (sources == \"番茄\" && islyc != \"苹果\" && islyc != \"安卓\") {\n for (var i = 0; i < style_list.length; i++) {\n if (style_list[i].title && style_list[i].title.indexOf(\"热门标签\") != -1) {\n style_list.splice(i, 0,\n createFilter(\n \"字数\",\n [\"不限\",\"10万字以内\",\"30万字以内\",\"50万字以内\",\"30万字以上\",\"50万字以上\",\"100万字以上\",\"200万字以上\",\"300万字以上\",\"500万字以上\"],\n \"不限\",\n \"字数\",\n 0.4,\n \"'字数'\"\n ),\n createFilter(\n \"更新\",\n [\"不限\",\"完结\",\"半年内完结\",\"连载中\",\"3日内更新\",\"7日内更新\",\"1月内更新\"],\n \"不限\",\n \"更新\",\n 0.4,\n \"'更新'\"\n ),\n createFilter(\n \"排序\",\n [\"综合\",\"新书\",\"高分\",\"字数\"],\n \"综合\",\n \"排序\",\n 0.1,\n \"'排序'\"\n )\n );\n break;\n }\n }\n }\n if (result.msg) {\n java.toast(result.msg);\n }\n} catch (e) {\n java.toast(\"发现样式获取失败\");\n}\nlet qttoken = getToken();\n//let qtcookie = \"\"\nlet qtop = {\n method: \"GET\",\n headers: {\n cookie: `qttoken=${qttoken}`\n },\n};\n\n\n\nqtop = JSON.stringify(qtop);\nlet qtsjurl = base_url + '/get_book_shelf,' + qtop;\n\nlet qtsj = [];\n\nif (islyc != \"苹果\" && islyc != \"安卓\") {\n try {\n let hostsbk = getVariable('云端配置')['hosts'] || hosts;\n qtsj.push(createFilter(\n \"线路\",\n hostsbk,\n base_url,\n \"线路\",\n 1,\n \"'线路'\"\n ));\n qtsj.push(createFilter(\n \"类型\",\n [\"小说\", \"听书\", \"短剧\", \"漫画\"],\n tab,\n \"发现页类型\",\n 0.4,\n \"'类型'\"\n ));\n qtsj.push(createFilter(\n \"频道\",\n [\"男频\", \"女频\"],\n source_type,\n \"频道\",\n 0.4,\n \"'频道'\"\n ));\n qtsj.push(createFilter(\n \"平台\",\n source_list,\n sources,\n \"发现页来源\",\n 1,\n \"'平台'\"\n ));\n let searchKey = getVariable('搜索关键词') || \"\";\n qtsj.push(createText(\n '搜索关键词', \n \"setVariable('搜索关键词',(infoMap['搜索关键词'] || (infoMap.get && infoMap.get('搜索关键词'))))\", \n searchKey , \n 0.5,\n \"'搜索书名或作者'\"\n ));\n \n qtsj.push(createButton(\n '🔍搜索', \n 'exploreSearch()', \n 0.3\n ));\n\n qtsj.push({\n \"title\": \"更新配置\",\n \"type\": \"button\",\n \"action\": \"getCloudSettings(true)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n })\n qtsj.push({\n \"title\": \"更新书源\",\n \"type\": \"button\",\n \"action\": \"renderVersionPage()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n })\n qtsj.push({\n \"title\": \"书源设置\",\n \"type\": \"button\",\n \"action\": \"getHtmlSettings()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n })\n const excludeTitles = ['点击登录可切换来源', '切换后长按刷新即可'];\n style_list = style_list.filter(item => !excludeTitles.includes(item.title));\n style_list.forEach(item => {\n if (item.url && typeof item.url == 'string') {\n item.url += '&ssionid='+fqssionid+'&selected_items='+selected_items;\n }\n});\n } catch {}\n} else {\n\tif (islyc == '安卓'){\n\tqtsj.push({\n \"title\": \"下载阅读Sigma最新测试版\",\n \"url\": `{\\{java.longToast(\"本书源推荐使用最新版洛娅橙改版阅读Σ\\\\n请安装后重新导入书源\");java.startBrowser(\"https://legado.qingtian618.com\",\"下载阅读Sigma最新测试版\");}}`,\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 1\n }\n })}\n\t}\n\nif (qttoken.length > 10) {\nqtsj.push({\n title: \"晴天书架\",\n url: qtsjurl,\n style: {\n layout_flexGrow: 1,\n layout_flexBasisPercent: 1\n }\n})\n} else {\nqtsj.push({\n title: \"登录晴天书源\",\n url: `{\\{java.startBrowser(\"${base_url}/login\",\"登录书源\");}}`,\n style: {\n layout_flexGrow: 1,\n layout_flexBasisPercent: 1\n }\n})\n}\n\n\nvar finalData = infoData.concat(groupDatas, style_list);\nfinalData = qtsj.concat(finalData);\nJSON.stringify(finalData);\n\n\n",
"jsLib": "// 当前书源版本号,切勿修改,否则影响更新的识别\nlet localVersion = '26.10.9';\n\n// 初始服务器列表\nlet hosts = [\n 'https://v1.qingtian618.com',\n 'https://cdn.qingtian618.com',\n 'https://v2.qingtian618.com',\n 'https://v3.qingtian618.com',\n 'https://v4.qingtian618.com',\n 'https://v5.qingtian618.com',\n 'https://v6.qingtian618.com',\n 'https://v7.qingtian618.com'\n];\n\nfunction isSpecialMedia (sources) {\n\tlet SOURCES_SPECIAL_MEDIA = ['毒舌影视', 'NT动漫'];\n\t return SOURCES_SPECIAL_MEDIA.some(src => sources.includes(src));\n\t}\n\nfunction buildDiscussionButton(url,sources) {\n let clickAction =\n `showCmt(\"${url}\",\"${sources}\",'本书讨论')`;\n\n return `\n \n `;\n};\n\n// 初始化值\nconst defaultConfig = {\n 线路: hosts[0],\n 发现页来源: \"番茄\",\n 发现页类型: \"小说\"\n};\n\n// 获取云端配置\nfunction getCloudSettings(r) {\n if (r == undefined) r = false;\n const {\n java,\n cache\n } = this;\n let c = this.getVariable('云端配置').version;\n if (r || !c) {\n java.longToast(`\\n正在更新最新配置`);\n try {\n let url = `/static/source_config/config.json`;\n //\tjava.longToast(url)\n let js = this.request(url);\n js = JSON.parse(String(js));\n let intc = parseInt(c);\n let intv = parseInt(js['version']);\n if (intc >= intv) {\n \t java.longToast(`\\n已是最新配置:${js['version']}`);\n \t return;\n \t} else if (!intc && intv) {\n \t\tjava.longToast(`\\n已初始化配置:${intv}`);\n \t\t} else if (intc < intv || !intc && intv) {\n java.longToast(`\\n已更新配置:${intc}→${intv}`);\n } else {\n java.longToast(`\\n获取配置失败:请切换线路再试试~`);\n return;\n }\n this.setVariable('云端配置', js);\n \n return js;\n } catch (e) {\n java.longToast(`\\n获取最新配置失败:${e}`);\n }\n }\n}\n\n// 统一获取和解析变量\nfunction _getParsedVariable() {\n const {\n source,\n java\n } = this;\n let v = source.getVariable();\n try {\n return JSON.parse(v);\n } catch {\n return defaultConfig;\n }\n}\n\n// 获取设置变量\nfunction getLoginInfo(k) {\n const {\n source,\n java\n } = this;\n let res = source.getLoginInfoMap();\n if (!res) {\n res = defaultConfig;\n }\n if (res[k] == '❌') {\n return '0';\n } else if (res[k] == '✅') {\n return '1';\n }\n return res[k]\n}\n\n// 还原\nfunction deleteVariable() {\n const {\n source,\n java,\n cache\n } = this;\n source.setVariable('');\n cache.delete('gyksconfig');\n java.longToast('\\n所有设置已还原到初始化导入状态');\n}\n\n// 获取源变量\nfunction getVariable(k) {\n if (k == undefined) k = \"\";\n const { source } = this;\n let parsed = {}\n try {\n parsed = JSON.parse(source.getVariable());\n } catch {}\n if (k == \"\") {\n return parsed;\n }\n let value = parsed[k];\n if (value == undefined) {\n value = defaultConfig[k];\n }\n return value != undefined ? value : \"\";\n}\n\n// 设置源变量\nfunction setVariable(k, v, t) {\n if (t == undefined) t = true;\n const {\n source,\n java\n } = this;\n const vs = this.getVariable();\n vs[k] = v;\n source.setVariable(JSON.stringify(vs, null, 4));\n if (k != '云端配置' && t && k!='搜索关键词') {\n java.toast(`\\n设置 ${k} 为 ${v}`)\n }\n}\n\n// 获取正在使用的线路\nfunction BaseUrl() {\n let hostsbk = this.getVariable('云端配置')['hosts'] || hosts;\n let h = this.getVariable(\"线路\");\n if (!h || String(h) == \"undefind\") {\n h = hostsbk[0]\n }\n return h;\n}\n\n// 切换线路\nfunction switchToNextLine(toast) {\n if (toast == undefined) toast = false;\n const currentLine = this.BaseUrl();\n let hostsbk = this.getVariable('云端配置')['hosts'] || hosts;\n let currentIndex = hostsbk.findIndex(item => item == currentLine);\n let nextIndex = (currentIndex + 1) % hostsbk.length;\n const nextLine = hostsbk[nextIndex];\n this.setVariable(\"线路\", nextLine,false);\n let switchToast = this.getVariable(\"切换提醒\") || \"false\";\n if (toast && switchToast == \"true\") {\n this.java.longToast(`\\n${toast}\\n自动切换到:${nextLine}`)\n }\n return nextLine;\n}\n\n\n// 备用设置方案\nfunction ste(v) {\n const {\n java\n } = this;\n let moreSettings = this.getVariable(\"更多设置\") || {};\n let paraSettings = this.getVariable(\"段评设置\") || {};\n if (v==\"段评\"){\n if (paraSettings[\"段评开关\"] != \"false\"){\n paraSettings[\"段评开关\"]= \"false\";\n java.longToast(\"\\n❌段评已关闭\");\n }else{\n paraSettings[\"段评开关\"]= \"true\";\n java.longToast(\"\\n✅段评已开启\");\n }\n }\n if (v==\"小说\" || v==\"听书\" || v==\"漫画\" || v==\"短剧\"){\n moreSettings[\"搜索模式\"]=v;\n java.longToast(`\\n已设置搜索模式为 ${v}`);\n }\n if (v==\"图片\"){\n if (moreSettings[\"显示图片\"] != \"false\"){\n moreSettings[\"显示图片\"]= \"false\";\n java.longToast(\"\\n❌已关闭图片显示\");\n }else{\n moreSettings[\"显示图片\"]= \"true\";\n java.longToast(\"\\n✅已开启图片显示\");\n }\n }\n if (v==\"简介\"){\n if (moreSettings[\"完整简介\"] != \"false\"){\n moreSettings[\"完整简介\"]= \"false\";\n java.longToast(\"\\n❌已关闭完整简介\");\n }else{\n moreSettings[\"完整简介\"]= \"true\";\n java.longToast(\"\\n✅已开启完整简介\");\n }\n }\n if (v==\"同步\"){\n if (moreSettings[\"同步书架\"] != \"false\"){\n moreSettings[\"同步书架\"]= \"false\";\n java.longToast(\"\\n❌已关闭同步书架\");\n }else{\n moreSettings[\"同步书架\"]= \"true\";\n java.longToast(\"\\n✅已开启同步书架\");\n }\n }\n if (v==\"强制\"){\n if (moreSettings[\"强制搜索\"] != \"false\"){\n moreSettings[\"强制搜索\"]= \"false\";\n java.longToast(\"\\n❌已关闭强制搜索\");\n }else{\n moreSettings[\"强制搜索\"]= \"true\";\n java.longToast(\"\\n✅已开启强制搜索\");\n }\n }\n if (v==\"目录\"){\n if (moreSettings[\"目录显示来源\"] != \"false\"){\n moreSettings[\"目录显示来源\"]= \"false\";\n java.longToast(\"\\n❌已关闭目录显示来源\");\n }else{\n moreSettings[\"目录显示来源\"]= \"true\";\n java.longToast(\"\\n✅已开启目录显示来源\");\n }\n }\n if (v==\"网络\"){\n if (moreSettings[\"网络模式\"] != \"服务器\"){\n moreSettings[\"网络模式\"]= \"服务器\";\n java.longToast(\"\\n已切换为 服务器 模式\");\n }else{\n moreSettings[\"网络模式\"]= \"本地\";\n java.longToast(\"\\n已切换为 本地 模式\");\n }\n }\n this.setVariable(\"更多设置\", moreSettings, false);\n this.setVariable(\"段评设置\", paraSettings, false);\n}\n\nfunction parseBadMap(str) {\n str = str\n .replace(/^{|}$/g, '');\n\n const result = {};\n\n str.split(',').forEach(item => {\n const parts = item.split('=');\n\n if (parts.length === 2) {\n const key = parts[0].trim();\n const value = parts[1].trim();\n\n result[key] = value;\n }\n });\n\n return result;\n}\n\nfunction findItemIndex(data, item_id) {\n if (!data || !Array.isArray(data)) {\n return 0;\n }\n for (let i = 0; i < data.length; i++) {\n if (data[i] && data[i].item_id == item_id) {\n return i;\n }\n }\n return 0;\n}\n\n// 判断当前环境\nfunction checkEnv() {\n const {\n java,\n source\n } = this;\n\n try {\n java.qread();\n return \"轻阅读\";\n } catch (e) {}\n\n try {\n if (typeof java.reLoginView == 'function') {\n return \"改版\";\n }\n new Packages.io.legato.kazusa.utils.TimeoutCancellationException('');\n return \"改版\";\n } catch (e) {}\n try {\n java.deviceID();\n return \"苹果\";\n } catch (e) {}\n\n if (typeof source.loginUi == 'function') {\n return \"安卓\";\n }\n\n return \"改版\";\n}\n\n// 获取番茄token\nfunction getFqToken() {\n const {\n java,\n cookie\n } = this;\n\n try {\n let cookieValue = String(cookie.getCookie('fanqienovel.com')) || String(java.getCookie('fanqienovel.com'));\n let parts = cookieValue.split(\";\");\n for (let part of parts) {\n if (part.includes(\"sessionid\")) {\n return part.split(\"=\")[1];\n }\n }\n } catch {}\n return \"\";\n}\n\n// 获取登陆token\nfunction getToken() {\n const {\n java,\n cookie\n } = this;\n let hostsbk = this.getVariable('云端配置')['hosts'] || hosts;\n try {\n for (let h of hostsbk) {\n let cookieValue = String(cookie.getCookie(h)) || String(java.getCookie(h));\n let parts = cookieValue.split(\";\");\n for (let part of parts) {\n if (part.includes(\"qttoken\")) {\n return part.split(\"=\")[1];\n }\n }\n }\n } catch {}\n return \"\";\n}\n\n// 移除ck\nfunction removeAllCookies() {\n const {\n java,\n cookie\n } = this;\n let hostsbk = this.getVariable('云端配置')['hosts'] || hosts;\n for (let h of hostsbk) {\n cookie.removeCookie(h);\n }\n cookie.removeCookie('fanqienovel.com');\n java.toast('\\n已退出登陆')\n}\n\n// 设置ck\nfunction setAllCookies(ck) {\n const {\n cookie\n } = this;\n let hostsbk = this.getVariable('云端配置')['hosts'] || hosts;\n for (let h of hostsbk) {\n cookie.setCookie(h, ck);\n }\n}\n\n// 请求封装\nfunction request(url, method, body, req, index) {\n if (method == undefined) method = 'GET';\n if (body == undefined) body = {};\n if (req == undefined) req = true;\n if (index == undefined) index = 0;\n\n let urla = url;\n if (!url.includes('http')) {\n urla = this.BaseUrl() + url;\n }\n\n const { java } = this;\n let device = '';\n try {\n device = java.androidId();\n } catch {\n try {\n device = java.deviceID();\n } catch {}\n }\n\n let qttoken = this.getToken();\n let options = {\n method: method,\n headers: {\n 'cookie': `qttoken=${qttoken};deviceId=${device};`,\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(body)\n };\n\n urla = `${urla},${JSON.stringify(options)}`;\n java.log(urla);\n\n if (!req) {\n return urla;\n }\n\n const startTime = new Date().getTime();\n\n let data;\n let requestTimedOut = false;\n let requestFailed = false;\n\n try {\n data = java.ajax(urla);\n JSON.parse(data);\n } catch (error) {\n requestFailed = true;\n } finally {\n const endTime = new Date().getTime();\n const duration = endTime - startTime;\n let timeout = this.getVariable('超时时间') || '10';\n timeout = parseInt(timeout)*1000\n if (!requestFailed && duration > timeout ) {\n requestTimedOut = true;\n }\n }\n if (requestTimedOut) {\n let timeoutSwitch = this.getVariable('超时自动切换') || 'true';\n if (timeoutSwitch!= \"false\") {\n java.log('检测到当前线路较慢,已切换线路');\n this.switchToNextLine('⚠️当前线路较慢');\n }\n return data;\n }\n if (requestFailed) {\n java.log('线路报错,自动切换下一个');\n let hostsbk = this.getVariable('云端配置')['hosts'] || hosts;\n let autoSwitch = this.getVariable('自动切换') || 'true';\n\n if (hostsbk.length > index && autoSwitch != \"false\") {\n this.switchToNextLine('❌线路报错');\n return this.request(url, method, body, req, index + 1);\n } else {\n return \"\";\n }\n }\n return data;\n}\n\nfunction parseJsonSafely(str, defaultValue) {\n if (defaultValue == null) defaultValue = null;\n try {\n return JSON.parse(str);\n } catch (e) {\n return defaultValue;\n }\n}\n\n\n//去除图片\nfunction removeAllImgTags(htmlString) {\n const imgTagRegex = /
]*>|<\\/img>|
]*\\/>/gi;\n return htmlString.replace(imgTagRegex, '');\n}\n\n// 段评气泡生成\nfunction paraForAndroid(content, sources) {\n let {\n java,\n cache,\n source\n } = this;\n const createSvg = this.createSvg.bind(this);\n const createGod = this.createGod.bind(this);\n content = content.replace(\n /
<\\/p>/g,\n (match, ident, src) => {\n return `
${createGod(ident, src)}
`;\n }\n );\n \n\n return content.replace(/(.*?)(?:)?<\\/p>/g,\n (match, text, url, count) => {\n if (url && count) {\n const click = 0;\n cache.putMemory(url, click);\n const encodedUrl = url;\n return `
${text}
`;\n } else {\n return `${text}
`;\n }\n }\n );\n}\n// 创建神评论\nfunction createGod(url,svg) {\n var jc = 'js';\n let islyc = this.checkEnv()\n if (islyc == \"改版\") {\n jc = 'click'\n }\n let cz= `{\"${jc}\":\"showCmt('${url}','段评' )\",\"style\":\"FULL\"}`\n\tlet img = `
`\n\tif (islyc == \"苹果\") {\n\t\timg = ``\n \t}\n\treturn img\n\t}\n\nlet svgs = [\n \"\",\n\n \"\",\n\n \"\",\n\n\n\n \"\",\n\n\n\n \"\",\n\n\n\n\n ``\n];\n\n\n// 创建svg\nfunction createSvg(number, encodedUrl, sources) {\n var displayText = number > 99 ? \"99+\" : number.toString();\n let data = this.getVariable('段评设置');\n let svgstyle = data['段评样式'] || \"0\";\n let color = data['段评边框颜色'] || \"#A7A7A7\";\n let tccolor = data['段评填充颜色'] || \"transparent\";\n let fontcolor = data['段评字体颜色'] || \"#A7A7A7\";\n let zdy = svgs[0];\n try {\n zdy = data['自定义段评样式'][svgstyle] || svgs[0];\n } catch {}\n const styleMap = {\n \"0\": svgs[0],\n \"1\": svgs[1],\n \"2\": svgs[2],\n \"3\": svgs[3],\n \"4\": svgs[4],\n \"5\": svgs[5],\n };\n let svg = styleMap[svgstyle] || zdy;\n svg = svg.replace('$color', color)\n .replace('$tccolor', tccolor)\n .replace('$fontcolor', fontcolor)\n .replace('$displayText', displayText);\n var jc = 'js';\n let islyc = this.checkEnv()\n if (islyc == \"改版\") {\n jc = 'click'\n }\n let style = data['气泡增大'] == \"true\" ? 'TEXT' : 'text';\n var encodedSvg = this.java.base64Encode(svg);\n return `data:image/svg+xml;base64,${encodedSvg},{\"${jc}\":\"showCmt('${encodedUrl}', '${sources}' ,'段评')\",\"style\":\"${style}\"}`;\n}\n\n\n\n\n// 显示弹窗\nfunction showCmt(url, sources,ident) {\n let {\n java,\n cache\n } = this;\n if (ident == null) ident = '段评';\n const currentTime = Date.now();\n const click = cache.getFromMemory(url);\n let islyc = this.checkEnv()\n if (click < 1 && islyc == \"安卓\") {\n cache.putMemory(url, click + 1);\n return;\n } else {\n if (islyc == \"轻阅读\") {\n java.startBrowserDp(url, sources + ident);\n } else if (islyc == \"改版\") {\n let paradata = new Date().toLocaleDateString();\n let htmlContent = cache.get(paradata+ident+sources+\"new3\");\n if (!htmlContent || String(htmlContent).indexOf(\"评论\") == -1) {\n java.longToast(`\\n${paradata} 初始化${sources}${ident}页面,请稍等~`);\n try {\n htmlContent = java.ajax(url);\n } catch {\n\n }\n\n cache.put(paradata+ident+sources+\"new3\", htmlContent);\n java.longToast(`\\n${paradata} 初始化${sources}${ident}页面成功~`);\n }\n java.showBrowser(\n url,\n htmlContent,\n `window.java=java;`,\n JSON.stringify({\n \"expandedCornersRadius\": 20,\n \"dismissOnTouchOutside\": true,\n \"isDraggable\": true,\n \"shouldDimBackground\": true,\n \"backgroundDimAmount\": 0.5,\n \"hardwareAccelerated\": true,\n \"isNestedScrollingEnabled\": true,\n \"isGestureInsetBottomIgnored\": true,\n \"setFitToContents\": true,\n \"isHideable\": true,\n \"heightPercentage\": 0.8\n })\n );\n } else {\n java.startBrowser(url, sources + ident);\n }\n }\n}\n\n//源阅段评\nfunction paraForiOS(html, sources) {\n\t let result = html.replace(\n /
<\\/p>/g,\n (match, ident, src) => {\n return `
${createGod(ident, src)}
`;\n }\n );\n result = result.replace(\n /(.*?)(?:)?<\\/p>/g,\n function(match, text, url, count) {\n if (url && count) {\n const encodedUrl = url.replace(/&/g, '&');\n let displayCount = count;\n const numCount = Number(count);\n if (!isNaN(numCount) && numCount > 99) {\n displayCount = '99';\n }\n return `
${text}
`;\n } else {\n return `${text}
`;\n }\n }\n );\n return result.replace(/"/g, '\"');\n}\n\n\nfunction endclick(url,sources) {\n\tif (sources == null) sources = '番茄';\n var jc = 'js';\n let islyc = this.checkEnv()\n if (islyc == \"改版\") {\n jc = 'click'\n }\n return `\"${jc}\":\"showCmt('${url}','${sources}','本章说' )\"`\n}\n\n\n//按钮切换时改变源变量并刷新发现\nfunction show(m, t) {\n const {\n java,\n source\n } = this;\n let data = {};\n try {\n data = JSON.parse(source.getVariable())\n } catch {}\n data[t] = m;\n if (t == \"发现页类型\") {\n data[\"发现页来源\"] = '番茄';\n }\n source.setVariable(JSON.stringify(data, null, 2));\n java.refreshExplore();\n}\n\nfunction createFilter(title, chars, defaultVal, paramKey, size, viewName) {\n if (viewName == undefined) viewName = \"'请选择类型'\";\n return {\n title: title,\n type: \"select\",\n chars: chars,\n default: defaultVal,\n \"viewName\": viewName,\n action: `show(infoMap['${title}'],'${paramKey}')`,\n style: {\n layout_flexGrow: 1,\n layout_flexBasisPercent: size\n }\n };\n}\n\nfunction createLoginFilter(title, chars, defaultVal, paramKey, size, viewName) {\n const {\n source,\n java\n } = this;\n if (viewName == undefined) viewName = \"'请选择类型'\";\n \n let loginMap = source.getLoginInfoMap();\n //java.longToast(loginMap);\n return {\n name: title,\n type: \"select\",\n chars: chars,\n default: defaultVal,\n \"viewName\": viewName,\n action: `show('${loginMap[title]}','${paramKey}')`,\n style: {\n layout_flexGrow: 1,\n layout_flexBasisPercent: size\n }\n };\n}\n\nfunction createText(title, action, defaultValue, size, viewName) {\n return {\n title: title,\n type: 'text',\n default: defaultValue || '',\n action: action,\n viewName: viewName || title,\n style: {\n layout_flexGrow: 1,\n layout_flexBasisPercent: size\n }\n };\n }\nfunction createButton(title, action, size) {\n return {\n title: title,\n type: 'button',\n action: action,\n style: {\n layout_flexGrow: 1,\n layout_flexBasisPercent: size\n }\n };\n }\n\nfunction exploreSearch() {\n let {java,source} = this;\n var key = this.getVariable('搜索关键词');\n var tab = this.getVariable('发现页类型') || '小说';\n var sources = this.getVariable('发现页来源') || '全部';\n if (!key) {\n try { java.toast('请输入搜索关键词'); } catch (e) {}\n return;\n }\n if (['t:', 'x:', 'd:', 'm:', 't:', 'x:', 'd:', 'm:'].some(p => key.startsWith(p))) {\n tab = '';\n}\nif(key.includes('@')) {\n\tsources=\"\";\n\t} else {\n\t\tsources = `@${sources}`\n\t\t}\n var tabMap = {\n \t'小说':'x:',\n \t'漫画':'m:',\n \t'听书':'t:',\n \t'短剧':'d:',\n \t'':''\n \t}\n key = `${tabMap[tab]}${key}${sources}`;\n try {\n java.searchBook(key, source.bookSourceName+\"::\"+source.getKey());\n } catch (e1) {\n try { java.open('search', key); } catch (e2) { try { java.toast('搜索失败'); } catch (e3) {} }\n }\n java.refreshExplore();\n}\n\n// 书源更新\nfunction renderVersionPage() {\n let {\n java\n } = this;\n let hostsbk = this.getVariable('云端配置')['hosts'] || hosts;\n let yd = '';\n let html = `\n\n\n\n \n \n 书源更新\n \n \n \n\n\n \n \n\n \n\n \n \n\n
\n
\n
待检查
\n
当前版本
\n
-
\n
您的当前版本
\n
\n\n
\n \n
\n\n
\n
最新版本
\n
最新版本
\n
-
\n
可用最新版本
\n
\n
\n\n
\n
\n\n \n\n\n`;\n java.startBrowser(`data:text/html;base64,${java.base64Encode(html)}`, '光遇书源更新');\n}\n\n\n\n// 线路设置\nfunction getServerSettings() {\n const {java} = this;\n let data = this.getVariable('线路');\n //java.toast(data)\n let hostsbk = this.getVariable('云端配置')['hosts'] || hosts;\n \n let html = `\n\n\n\n\n\n光遇小说 - 线路设置\n\n\n\n\n\n
\n \n \n \n
\n \n \n \n
\n \n 最后检测: --:--:--\n \n
\n \n
\n
\n
失败自动切换
\n
当前线路失败时自动尝试切换到其他可用线路
\n
\n
\n
\n \n
\n
\n
超时自动切换
\n
请求超时后自动切换到其他可用线路
\n
\n
\n \n \n
\n
\n \n
\n
\n
切换提醒弹窗
\n
线路切换时显示提醒弹窗通知
\n
\n
\n
\n \n
\n \n
\n ${data || hostsbk[0]}\n ${this.getVariable('自动切换') || 'true'}\n ${this.getVariable('超时自动切换') || 'true'}\n ${this.getVariable('超时时间') || '10'}\n ${this.getVariable('切换提醒') || 'false'}\n
\n
\n
\n\n\n\n\n `;\n let body;\n try {\n body = java.startBrowserAwait(`data:text/html;base64,${java.base64Encode(html)}`, '光遇服务器设置', false).body();\n } catch (e) {\n let islyc = this.checkEnv()\n if (islyc == \"安卓\") {\n this.switchToNextLine();\n } else {\n java.longToast(\"\\n请点击页面右上角√才能设置成功哦~\");\n }\n return;\n }\n \n let host = hostsbk[0];\n let autoSwitch = 'true';\n let timeoutSwitch = 'true';\n let timeout = '10';\n let notifySwitch = 'false';\n try {\n const getSpanText = (spanId) => {\n const regex = new RegExp('id=\"' + spanId + '\"\\s*>\\s*([^<]*?)\\s*<\\/span>');\n const match = body.match(regex);\n return match ? match[1].trim() : \"\";\n };\n host = getSpanText('serverValue') || hostsbk[0];\n autoSwitch = getSpanText('autoSwitchValue') || 'true';\n timeoutSwitch = getSpanText('timeoutSwitchValue') || 'true';\n timeout = getSpanText('timeoutValue') || '10';\n notifySwitch = getSpanText('notifySwitchValue') || 'false';\n } catch (e) {\n host = hostsbk[0];\n autoSwitch = 'true';\n timeoutSwitch = 'true';\n timeout = '10';\n notifySwitch = 'true';\n }\n const settingsText = `线路: ${host}\\n失败自动切换: ${autoSwitch == 'true' ? '开启' : '关闭'}\\n超时自动切换: ${timeoutSwitch == 'true' ? '开启' : '关闭'}\\n超时时间: ${timeout}秒\\n切换提醒弹窗: ${notifySwitch == 'true' ? '开启' : '关闭'}`;\n java.longToast(\"\\n\" + settingsText);\n this.setVariable(\"线路\", host, false);\n this.setVariable(\"自动切换\", autoSwitch, false);\n this.setVariable(\"超时自动切换\", timeoutSwitch, false);\n this.setVariable(\"超时时间\", timeout, false);\n this.setVariable(\"切换提醒\", notifySwitch, false);\n}\n\n\n\n\n// 段评设置页面\nfunction getSvgSettings() {\n const {\n java\n } = this;\n const islyc = this.checkEnv();\n if (islyc == \"苹果\") {\n java.longToast(\"\\n当前软件不支持设置段评样式\");\n return;\n }\n let data = this.getVariable('段评设置');\n let base_url = this.BaseUrl();\n let qttoken = this.getToken();\n\n let html = `\n\n\n\n\n\n光遇小说 - 段评设置\n\n\n\n\n\n
\n
\n \n
\n
\n
段评
\n
仅 番茄、七猫、书旗、塔读、QQ阅读 支持
\n
\n
\n
\n \n
\n
\n
神评论
\n
需要开启段评开关才可生效,仅支持 番茄、七猫、书旗
\n
\n
\n
\n \n
\n \n
\n
\n
气泡增大
\n
开启后,气泡显示会加大一些
\n
\n
\n
\n \n
\n
\n
段评样式
\n
选择段评显示的样式风格,下方可实时预览效果
\n
\n
\n \n
\n
\n \n
\n \n
\n \n
\n \n \n
\n
\n
\n
自定义样式管理
\n
点击下方\"+\"添加新的自定义样式,支持自定义名称
\n
\n
\n \n \n \n
\n
\n \n
\n
\n
\n \n \n
\n
\n \n \n
\n
\n ${(data && data.段评开关) || 'true'}\n ${(data && data.神评论开关) || 'true'}\n ${(data && data.本章说开关) || 'true'}\n ${(data && data.气泡增大) || 'false'}\n ${(data && data.段评样式) || '0'}\n ${(data && data.段评边框颜色) || '#A7A7A7'}\n ${(data && data.段评字体颜色) || '#A7A7A7'}\n ${(data && data.段评填充颜色) || 'transparent'}\n ${base_url}\n ${qttoken}\n
\n
\n
\n \n \n
\n
\n\n\n\n\n `;\n let body;\n try {\n body = java.startBrowserAwait(`data:text/html;base64,${java.base64Encode(html)}`, '光遇段评设置', false).body();\n } catch (e) {\n if (islyc == \"安卓\") {\n java.longToast(\"\\n当前软件版本过低,请更新软件,或者使用底部备用设置方案~\");\n } else {\n java.longToast(\"\\n请点击页面右上角√才能设置成功哦~\");\n }\n return;\n }\n \n let settings = {};\n try {\n const getSpanText = (spanId) => {\n const regex = new RegExp('id=\"' + spanId + '\"\\s*>\\s*([^<]*?)\\s*<\\/span>');\n const match = body.match(regex);\n return match ? match[1].trim() : \"\";\n };\n const getTextareaValue = (textareaId) => {\n const regex = new RegExp('