mirror of
https://github.com/Tthfyth/source.git
synced 2026-03-19 10:30:06 +08:00
246 lines
126 KiB
JSON
246 lines
126 KiB
JSON
[
|
||
{
|
||
"bookSourceComment": "漫画发布页:https://wn01.link/\n1⃣️无需翻墙,国内直连\n2⃣️漫画没加载出来尝试刷新一下\n3⃣️脸黑🌚刷不出来的,别用wifi,用流量看。",
|
||
"bookSourceGroup": "漫画",
|
||
"bookSourceName": "绅士漫画( 优+++ )",
|
||
"bookSourceType": 2,
|
||
"bookSourceUrl": "https://www.wnacg.ru/",
|
||
"customOrder": 472,
|
||
"enabled": true,
|
||
"enabledCookieJar": true,
|
||
"enabledExplore": true,
|
||
"exploreUrl": "[\n {\n \"title\": \"🔖排行🔖\",\n \"url\": \"\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 1\n }\n },\n {\n \"title\": \"月榜\",\n \"url\": \"https://www.wnacg.ru/albums-favorite_ranking-page-{{page}}-type-month.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"title\": \"周榜\",\n \"url\": \"https://www.wnacg.ru/albums-favorite_ranking-page-{{page}}-type-week.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"title\": \"日榜\",\n \"url\": \"https://www.wnacg.ru/albums-favorite_ranking-page-{{page}}-type-day.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"title\": \"🔖同人志🔖\",\n \"url\": \"\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 1\n }\n },\n {\n \"title\": \"创建时间\",\n \"url\": \"https://www.wnacg.ru/albums-index-page-{{page}}-cate-1.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"title\": \"上传时间\",\n \"url\": \"https://www.wnacg.ru/albums-index-page-{{page}}-cate-1.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"title\": \"图片数\",\n \"url\": \"https://www.wnacg.ru/albums-index-page-{{page}}-cate-1.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"title\": \"🔖韩漫🔖\",\n \"url\": \"\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 1\n }\n },\n {\n \"title\": \"创建时间\",\n \"url\": \"https://www.wnacg.ru/albums-index-page-{{page}}-cate-20.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"title\": \"上传时间\",\n \"url\": \"https://www.wnacg.ru/albums-index-page-{{page}}-cate-20.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"title\": \"图片数\",\n \"url\": \"https://www.wnacg.ru/albums-index-page-{{page}}-cate-20.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n\n {\n \"title\": \"🔖单行本🔖\",\n \"url\": \"\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 1\n }\n },\n {\n \"title\": \"创建时间\",\n \"url\": \"https://www.wnacg.ru/albums-index-page-{{page}}-cate-9.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"title\": \"上传时间\",\n \"url\": \"https://www.wnacg.ru/albums-index-page-{{page}}-cate-9.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"title\": \"图片数\",\n \"url\": \"https://www.wnacg.ru/albums-index-page-{{page}}-cate-9.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"title\": \"🔖杂志&短篇🔖\",\n \"url\": \"\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 1\n }\n },\n {\n \"title\": \"创建时间\",\n \"url\": \"https://www.wnacg.ru/albums-index-page-{{page}}-cate-10.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"title\": \"上传时间\",\n \"url\": \"https://www.wnacg.ru/albums-index-page-{{page}}-cate-10.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"title\": \"图片数\",\n \"url\": \"https://www.wnacg.ru/albums-index-page-{{page}}-cate-10.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n }\n]",
|
||
"header": "@js:\nJSON.stringify({\n\"Referer\":baseUrl\n})",
|
||
"lastUpdateTime": "1763999238954",
|
||
"respondTime": 180000,
|
||
"ruleBookInfo": {
|
||
"coverUrl": "//div[@class='asTB']/div[@class='asTBcell uwthumb']/img/@src##////##https://",
|
||
"downloadUrls": "//div[@id='ads']/a[1]/@href",
|
||
"intro": "//div[@class='asTBcell uwconn']/p/text()@js:result.split('\\n').join('')",
|
||
"kind": "//div[@class='addtags']/a[@class='tagshow']/text()",
|
||
"wordCount": "//div[@class='asTBcell uwconn']/label/text()@js:\nconst infoSplit = result.split('\\n')\nconst info = []\nfor(var i = 0;i<infoSplit .length;i++){\ninfo.push(infoSplit[i].split(':')[1])\n}\ninfo.join(' ')"
|
||
},
|
||
"ruleContent": {
|
||
"content": "//span[@id='imgarea']/a/img/@src##//##https://@js:\n\n// 获取前缀URL\nconst regexStr = \"^https://img5\\\\.qy0\\\\.ru/data/\\\\d+/\\\\d+/\";\nconst regex = new RegExp(regexStr, \"g\");\nconst prefixUrlMatch = result.match(regex);\nconst prefixUrl = prefixUrlMatch ? prefixUrlMatch[0] : \"\";\n\n// 解析图片信息数组(容错:数组为空时设为[])\nconst imgInfoList = JSON.parse(java.get('imgInfoList') || '[]');\n\n// 拼接完整图片链接(直接使用原始imgName)\nconst imgUrlList = [];\nif (prefixUrl) {\n imgInfoList.forEach(item => {\n // 仅做空值容错,不修改imgName原始值\n const imgName = item.imgName || '';\n const imgExtension = item.imgExtension || 'jpg';\n const fullImgUrl = prefixUrl + imgName + \".\" + imgExtension;\n imgUrlList.push(fullImgUrl);\n });\n}\n\n// 规则输出拼接后的img标签\nimgUrlList.map(x=>'<img src=\\\"'+x+'\\\">')\n.join(\"\\n\")",
|
||
"imageStyle": "FULL"
|
||
},
|
||
"ruleExplore": [],
|
||
"ruleSearch": {
|
||
"bookList": "//div[@class='gallary_wrap']/ul/li",
|
||
"bookUrl": "//div[@class='info']/div[@class='title']/a/@href,{\"webView\":true}",
|
||
"checkKeyWord": "元魔法",
|
||
"coverUrl": "//li/div[1]/a/img/@src",
|
||
"intro": "//li/div[@class='info']/div[@class='info_col']/text()@js:\nvar timeStr = result.split(\",\")[1] || \"\";\nvar updateTime = timeStr.match(/創建於(\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2})/)?.[1] || \"无时间\";\n'更新时间: ' + updateTime;",
|
||
"kind": "//li/div[1]/@class@js:\nif (result[0].indexOf('cate-1') !== -1) { \n '同人志/汉化'; // 加return,否则无返回值\n} else if (result[0].indexOf('cate-12') !== -1) {\n '同人志/日语'; \n} else if (result[0].indexOf('cate-9') !== -1) {\n '单行本/汉化';\n} else if (result[0].indexOf('cate-13') !== -1) {\n '单行本/日语';\n} else if (result[0].indexOf('cate-10') !== -1) {\n '杂志&短篇/汉化';\n} else if (result[0].indexOf('cate-14') !== -1) {\n '杂志&短篇/日语';\n} else if (result[0].indexOf('cate-18') !== -1) {\n '杂志&短篇/English';\n} else if (result[0].indexOf('cate-20') !== -1) {\n '韩漫/汉化';\n} else if (result[0].indexOf('cate-21') !== -1) {\n '韩漫/生肉';\n} else {\n ''; \n}",
|
||
"name": "//div[@class='info']/div[@class='title']/a//text()@js:\nconst bookname= result.split('\\n').join('').replace(/^.*?]/g, '')\nbookname",
|
||
"wordCount": "//li/div[@class='info']/div[@class='info_col']/text()@js:\nvar imgNum = result.split(\",\")[0].match(/\\d+(?=張圖片)/g)[0]\nimgNum+'页'"
|
||
},
|
||
"ruleToc": {
|
||
"chapterList": "//div[@class='gallary_wrap tb']/ul/li[1]@js:\nvar imgInfoList = [];\nvar nextPageUrl = [];\n\n// 1. 处理分页URL(保留有效逻辑)\nvar rawHrefs = java.getString(\"//div[@class='f_left paginator']/a/@href\") || \"\";\nnextPageUrl = rawHrefs.split('\\n').filter(x => x.trim());\nnextPageUrl = nextPageUrl.map(x => {\n var url = x.trim();\n while (url.startsWith(\"/\")) {\n url = url.slice(1);\n }\n return url.startsWith(\"http\") ? url : \"https://www.wnacg.ru/\" + url;\n});\nnextPageUrl.unshift(baseUrl);\n\n// 2. 核心工具函数:预处理HTML(移除注释+清理空格)\nfunction cleanHtml(html) {\n if (!html) return \"\";\n // 步骤1:移除所有HTML注释(<!-- ... -->),彻底消除干扰\n html = html.replace(/<!--[\\s\\S]*?-->/g, \"\");\n // 步骤2:移除多余空白字符(换行、制表符等),简化匹配\n html = html.replace(/\\s+/g, \" \");\n return html;\n}\n\n// 3. 核心工具函数:提取单页的“序号数组”和“图片src数组”\nfunction extractPageData(cleanedHtml) {\n var names = []; // 序号数组(001、002、003...)\n var srcs = []; // 图片src数组(与序号一一对应)\n\n // 提取所有序号(<span class=\"name tb\">xxx</span>)\n var nameRegex = /<span class=\"name tb\">([\\d]+)<\\/span>/g;\n var nameMatch;\n while ((nameMatch = nameRegex.exec(cleanedHtml)) !== null) {\n names.push(nameMatch[1]);\n }\n\n // 提取所有有效图片src(与序号对应的img,alt包含“_序号”)\n var srcRegex = /<img src=\"([^\"]+)\" alt=\"[^\"]+_([\\d]+)\"/g;\n var srcMatch;\n while ((srcMatch = srcRegex.exec(cleanedHtml)) !== null) {\n // 确保src对应的序号在names数组中(避免无关图片)\n if (names.includes(srcMatch[2])) {\n srcs.push(srcMatch[1]);\n }\n }\n\n return { names: names, srcs: srcs };\n}\n\n// 4. 执行多页提取\ntry {\n for (var p = 0; p < nextPageUrl.length; p++) {\n var pageUrl = nextPageUrl[p];\n var pageNum = p + 1;\n\n // 步骤1:获取并清理HTML(移除注释+多余空格)\n var rawHtml = new String(java.ajax(pageUrl)) || \"\";\n var cleanedHtml = cleanHtml(rawHtml);\n\n // 步骤2:提取当前页的序号和src数组\n var pageData = extractPageData(cleanedHtml);\n var pageNames = pageData.names;\n var pageSrcs = pageData.srcs;\n\n // 步骤3:按索引配对(序号和src一一对应),避免漏配\n var addedNum = 0;\n for (var i = 0; i < pageNames.length; i++) {\n var imgName = pageNames[i];\n var imgSrc = pageSrcs[i] || \"\";\n var imgExtension = \"\";\n\n // 提取扩展名\n if (imgSrc) {\n var dotIndex = imgSrc.lastIndexOf(\".\");\n if (dotIndex !== -1) {\n imgExtension = imgSrc.slice(dotIndex + 1).toLowerCase().split(/[?#]/)[0];\n }\n }\n\n // 去重并添加到数组\n if (imgName && imgExtension && !imgInfoList.some(item => item.imgName === imgName)) {\n imgInfoList.push({ imgName: imgName, imgExtension: imgExtension });\n addedNum++;\n }\n }\n\n }\n} catch (e) {\n java.log(\"提取报错:\" + e.message);\n}\n\nimgInfoList.sort((a, b) => parseInt(a.imgName) - parseInt(b.imgName));\n\n// 返回原结果,不影响目录列表\njava.put('imgInfoList',JSON.stringify(imgInfoList))\nresult;",
|
||
"chapterName": "//li/text()@js:'全话阅读'",
|
||
"chapterUrl": "//li//a/@href,{\"webView\":true}",
|
||
"updateTime": "//li/div[@class='info']/div[@class='info_col']/text()"
|
||
},
|
||
"searchUrl": "https://www.wnacg.ru/search/?q={{key}}&f=_all&s=create_time_DESC&syn=yes",
|
||
"weight": 500
|
||
},
|
||
{
|
||
"bookSourceName": "飘天(梯子 模糊搜索)",
|
||
"bookSourceType": 0,
|
||
"bookSourceUrl": "https://www.piaotia.com",
|
||
"customOrder": 0,
|
||
"enabled": true,
|
||
"enabledCookieJar": false,
|
||
"enabledExplore": true,
|
||
"lastUpdateTime": "1764413976626",
|
||
"respondTime": 30000,
|
||
"ruleBookInfo": {
|
||
"intro": "tr:nth-child(1) > td:nth-child(2) > div@text",
|
||
"tocUrl": "caption > a@href"
|
||
},
|
||
"ruleContent": {
|
||
"content": "@js:result=result.match(/style4.js[\\s\\S]+<br>([\\s\\S]+)<\\/div>[\\s\\S]+!-- 翻页上\\/)[1]\n"
|
||
},
|
||
"ruleExplore": [],
|
||
"ruleSearch": {
|
||
"author": ".odd:nth-child(3)@text",
|
||
"bookList": "tr:nth-child(n+2)",
|
||
"bookUrl": ".odd > a@href",
|
||
"kind": ".even:nth-child(6)@text",
|
||
"lastChapter": ".even > a@text",
|
||
"name": ".odd > a@text",
|
||
"wordCount": ".even:nth-child(4)@text@js:String(parseInt(result.replace('k',''))*1000)"
|
||
},
|
||
"ruleToc": {
|
||
"chapterList": ".centent ul li",
|
||
"chapterName": "a@text",
|
||
"chapterUrl": "a@href"
|
||
},
|
||
"searchUrl": "/modules/article/search.php?searchkey={{java.encodeURI(key,'gbk')}}&searchtype=articlename",
|
||
"weight": 0
|
||
},
|
||
{
|
||
"bookSourceComment": "更新日志请点击登录,更新书源中查看\n\n兼容正式版阅读app",
|
||
"bookSourceGroup": "大灰狼聚合",
|
||
"bookSourceName": "🍅大灰狼融合4.11.25(完全版)",
|
||
"bookSourceType": 0,
|
||
"bookSourceUrl": "大灰狼融合4.0",
|
||
"bookUrlPattern": "https?:\\/\\/(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(?::\\d+)?\\/detail.*",
|
||
"customOrder": 22,
|
||
"enabled": true,
|
||
"enabledCookieJar": false,
|
||
"enabledExplore": true,
|
||
"exploreUrl": "<js>\nfunction setArgument(key, value) {\n var open_argument = source.getVariable();\n open_argument = getArguments(open_argument, '') || {};\n open_argument[key] = value;\n var result = JSON.stringify(open_argument);\n source.setVariable(result);\n return result;\n}\n\nvar open_argument = source.getVariable();\nvar base_url = getArguments(open_argument, 'server') || '';\nvar ms = getArguments(open_argument, 'tone_id') || '';\nvar source_type = getArguments(open_argument, 'source_type') || '男频';\nvar tab = getArguments(open_argument, 'media') || '小说';\nvar sources = getArguments(open_argument, 'source') || '番茄';\n\n\nvar sdtoken;\ntry {\n var loginInfoMap = source.getLoginInfoMap ? source.getLoginInfoMap() : {};\n sdtoken = String(loginInfoMap['手动填写番茄token(可不填)'] || '');\n} catch (e) {\n sdtoken = '';\n}\n\nvar rawCookie = getFanqieCookie() || sdtoken;\nvar match = rawCookie.match(/sessionid=[^;]+/);\nvar fqcookie = match ? match[0] : '';\nvar fqssionid = '';\nif (!fqcookie) {\n java.toast('您还未登陆番茄账号,无法同步数据哦!');\n} else {\n fqssionid = getSessionId(fqcookie)\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\nvar groupDatas = [];\nvar infoData = [];\n\nfunction deviceType() {\n try {\n return !!java.androidId();\n } catch (e) {\n return false;\n }\n}\n\nvar hasValidCookie = fqcookie.length > 0;\n\nif (hasValidCookie) {\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.45\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.45\n }\n });\n }\n } catch (e) {\n java.longToast(\"番茄登录过期,已隐藏番茄书架\");\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: fqsjurl,\n style: {\n layout_flexGrow: 1,\n layout_flexBasisPercent: 1\n }\n }, {\n title: \"个性推荐(番茄)\",\n url: fqtjurl,\n style: {\n layout_flexGrow: 1,\n layout_flexBasisPercent: 0.45\n }\n }, {\n title: \"历史阅读(番茄)\",\n url: fqlsurl,\n style: {\n layout_flexGrow: 1,\n layout_flexBasisPercent: 0.45\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 (result.msg) {\n java.toast(result.msg);\n }\n} catch (e) {\n java.toast(\"发现样式获取失败\");\n}\n\nvar finalData = infoData.concat(groupDatas, style_list);\nJSON.stringify(finalData);\n</js>",
|
||
"header": "{ \"User-Agent\":\"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36 Edg/138.0.0.0\" }",
|
||
"jsLib": "var host = [\n 'http://219.154.201.122:5006'\n];\n\nfunction getArguments(open_argument, key) {\n try {\n open_argument = JSON.parse(open_argument);\n } catch (e) {\n open_argument = {\n media: \"小说\",\n tone_id: \"默认音色\",\n server: host[0],\n source: \"全部\",\n source_type: \"男频\",\n };\n }\n if (key) {\n return open_argument[key];\n } else {\n return open_argument;\n }\n}\n\nfunction setArguments(key, value) {\n const {\n source\n } = this;\n let open_argument = source.getVariable();\n open_argument = getArguments(open_argument, '');\n open_argument[key] = value;\n open_argument = JSON.stringify(open_argument);\n source.setVariable(open_argument);\n return open_argument;\n}\n\nfunction decrypt(Text) {\n return Text;\n}\n\nfunction paraForAndroid(content, sources) {\n let {\n java,\n cache,\n source\n } = this;\n let plcolor = getArguments(source.getVariable(), \"plcolor\");\n if (!plcolor) {\n plcolor = \"#000000\";\n }\n\n const createSvg = this.createSvg.bind(this);\n\n return content.replace(/<p>(.*?)(?:<comment ident=\"([^\"]*)\" count=\"([^\"]*)\" \\/>)?<\\/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 `<p>${text}<img src=\"${createSvg(count, plcolor,encodedUrl,sources)}\"></p>`;\n } else {\n return `<p>${text}</p>`;\n }\n }\n );\n}\n\n\nfunction showCmt(url, sources) {\n let {\n java,\n cache\n } = this;\n\n const currentTime = Date.now();\n const click = cache.getFromMemory(url);\n let isqread = false;\n try {\n java.qread();\n isqread = true;\n } catch (e) {}\n if (click < 1 && !isqread) {\n cache.putMemory(url, click + 1);\n return;\n } else {\n try {\n java.startBrowserDp(url, sources + '段评');\n } catch (e) {\n java.startBrowser(url, sources + '段评');\n }\n }\n}\n\n\n\nfunction createSvg(number, color, encodedUrl, sources) {\n var displayText = number > 99 ? \"99+\" : number.toString();\n var loginInfoMap = {};\n\n if (this.source && typeof this.source.getLoginInfoMap == 'function') {\n loginInfoMap = this.source.getLoginInfoMap() || {};\n }\n\n var bubbleStyle = String(loginInfoMap['段评气泡样式'] || '0');\n var svg;\n\n // 样式1:精致圆形 - 简洁优雅\n if (bubbleStyle == '1') {\n svg = '<svg width=\"1000\" height=\"1000\" xmlns=\"http://www.w3.org/2000/svg\">' +\n '<circle cx=\"500\" cy=\"500\" r=\"440\" fill=\"none\" stroke=\"' + color + '\" stroke-width=\"32\" opacity=\"0.2\"/>' +\n '<circle cx=\"500\" cy=\"500\" r=\"440\" fill=\"none\" stroke=\"' + color + '\" stroke-width=\"4\"/>' +\n '<text x=\"500\" y=\"500\" font-family=\"-apple-system, sans-serif\" text-anchor=\"middle\" ' +\n 'font-size=\"400\" fill=\"' + color + '\" dy=\"0.35em\" font-weight=\"500\">' + displayText + '</text>' +\n '</svg>';\n }\n // 样式2:微信风格 - 熟悉亲切的对话气泡\n else if (bubbleStyle == '2') {\n svg = '<svg width=\"1000\" height=\"900\" xmlns=\"http://www.w3.org/2000/svg\">' +\n '<path d=\"M120,120 L880,120 Q920,120 920,160 L920,680 Q920,720 880,720 L280,720 L120,840 L120,720 Q80,720 80,680 L80,160 Q80,120 120,120 Z\" ' +\n 'fill=\"none\" stroke=\"' + color + '\" stroke-width=\"24\" stroke-linejoin=\"round\"/>' +\n '<text x=\"500\" y=\"440\" font-family=\"-apple-system, sans-serif\" text-anchor=\"middle\" ' +\n 'font-size=\"360\" fill=\"' + color + '\" dy=\"0.32em\" font-weight=\"500\">' + displayText + '</text>' +\n '</svg>';\n }\n // 样式3:悬浮标签 - 扁平现代风格\n else if (bubbleStyle == '3') {\n svg = '<svg width=\"1000\" height=\"600\" xmlns=\"http://www.w3.org/2000/svg\">' +\n '<rect x=\"80\" y=\"80\" width=\"840\" height=\"440\" rx=\"220\" ry=\"220\" ' +\n 'fill=\"none\" stroke=\"' + color + '\" stroke-width=\"6\"/>' +\n '<rect x=\"100\" y=\"100\" width=\"800\" height=\"400\" rx=\"200\" ry=\"200\" ' +\n 'fill=\"none\" stroke=\"' + color + '\" stroke-width=\"20\" opacity=\"0.3\"/>' +\n '<text x=\"500\" y=\"310\" font-family=\"-apple-system, sans-serif\" text-anchor=\"middle\" ' +\n 'font-size=\"280\" fill=\"' + color + '\" dy=\"0.32em\" font-weight=\"500\" letter-spacing=\"8\">' + displayText + '</text>' +\n '</svg>';\n }\n // 样式4:书签标注 - 符合阅读场景\n else if (bubbleStyle == '4') {\n svg = '<svg width=\"900\" height=\"1000\" xmlns=\"http://www.w3.org/2000/svg\">' +\n '<path d=\"M150,80 L750,80 Q800,80 800,130 L800,870 Q800,920 750,920 L480,920 L450,980 L420,920 L150,920 Q100,920 100,870 L100,130 Q100,80 150,80 Z\" ' +\n 'fill=\"none\" stroke=\"' + color + '\" stroke-width=\"24\" stroke-linejoin=\"round\"/>' +\n '<line x1=\"150\" y1=\"280\" x2=\"750\" y2=\"280\" stroke=\"' + color + '\" stroke-width=\"3\" opacity=\"0.3\"/>' +\n '<text x=\"450\" y=\"520\" font-family=\"Georgia, serif\" text-anchor=\"middle\" ' +\n 'font-size=\"360\" fill=\"' + color + '\" dy=\"0.32em\" font-weight=\"400\">' + displayText + '</text>' +\n '<text x=\"450\" y=\"800\" font-family=\"-apple-system, sans-serif\" text-anchor=\"middle\" ' +\n 'font-size=\"70\" fill=\"' + color + '\" opacity=\"0.6\" letter-spacing=\"3\">评论</text>' +\n '</svg>';\n }\n // 默认返回样式0\n else {\n svg = '<svg width=\"160\" height=\"120\" xmlns=\"http://www.w3.org/2000/svg\">' +\n '<path d=\"M 55 10 ' +\n 'L 120 10 ' +\n 'Q 150 10 150 40 ' +\n 'L 150 80 ' +\n 'Q 150 110 120 110 ' +\n 'L 55 110 ' +\n 'Q 25 110 25 80 ' +\n 'L 25 75 ' +\n 'L 3 60 ' +\n 'L 25 45 ' +\n 'L 25 40 ' +\n 'Q 25 10 55 10 Z\" ' +\n 'fill=\"none\" ' +\n 'stroke=\"' + color + '\" ' +\n 'stroke-width=\"2\" ' +\n 'stroke-linejoin=\"round\"/>' +\n '<!-- 数字文本 -->' +\n '<text x=\"87\" y=\"75\" ' +\n 'font-family=\"Arial, sans-serif\" ' +\n 'text-anchor=\"middle\" ' +\n 'dominant-baseline=\"middle\" ' +\n 'font-size=\"50\" ' +\n 'font-weight=\"bold\" ' +\n 'fill=\"' + color + '\">' +\n displayText +\n '</text>' +\n '<!-- 提示文本 -->' +\n '<text x=\"87\" y=\"95\" ' +\n 'font-family=\"Arial, sans-serif\" ' +\n 'text-anchor=\"middle\" ' +\n 'dominant-baseline=\"middle\" ' +\n 'font-size=\"9\" ' +\n 'fill=\"' + color + '\" ' +\n 'opacity=\"0.7\">' +\n '刷新查看' +\n '</text>' +\n '</svg>';\n }\n\n var encodedSvg = this.java.base64Encode(svg);\n return 'data:image/svg+xml;base64,' + encodedSvg + ',{\"js\":\"showCmt(\\'' + encodedUrl + '\\', \\'' + sources + '\\')\",\"style\":\"text\"}';\n}\n\n\n\nfunction cleanHTML(html) {\n let result = html\n .replace(/<header[^>]*>[\\s\\S]*?<\\/header>/gi, \"\")\n .replace(/<div class=\"tt-title\"[^>]*>[\\s\\S]*?<\\/div>/gi, \"\")\n .replace(/<(?!\\/?p\\b|\\/?img\\b)[^>]+>/gi, \"\");\n result = result.replace(/<\\/?p[^>]*>/g, \"\\n\");\n return result.replace(/\\n+/g, \"\\n\").trim();\n}\n\nfunction getSessionId(cookieString) {\n const match = cookieString.match(/sessionid=([^;]+)/);\n return match ? match[1] : null;\n}\n\nfunction getKey(key) {\n let parts = key.split(\";\");\n for (let part of parts) {\n if (part.includes(\"qttoken\")) {\n return part.split(\"=\")[1];\n }\n }\n return \"\";\n}\n\nfunction getFanqieCookie() {\n const {\n cookie\n } = this;\n try {\n return String(cookie.getCookie('fanqienovel.com') || java.getCookie('fanqienovel.com') || '');\n } catch (e) {\n return '';\n }\n}\n\n\nfunction paraForiOS(html, sources) {\n return html.replace(\n /<p>(.*?)(?:<comment ident=\"([^\"]*)\" count=\"([^\"]*)\" \\/>)?<\\/p>/g,\n function(match, text, url, count) {\n if (url && count) {\n const encodedUrl = url.replace(/&/g, '&');\n return `<span rs-native>${text}<comment count=\"${count}\" onPress=\"java.showReadingBrowser('${encodedUrl}','${sources}段评')\"></span>`;\n } else {\n return `<span rs-native>${text}</span>`;\n }\n }\n );\n}",
|
||
"lastUpdateTime": "1764434902238",
|
||
"loginUi": "[{\n \"name\": \"邮箱\",\n \"type\": \"text\"\n },\n {\n \"name\": \"密码\",\n \"type\": \"password\"\n },\n {\n \"name\": \"♥登录书源\",\n \"type\": \"button\",\n \"action\": \"login(true)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \"name\": \"🍅番茄登录\",\n \"type\": \"button\",\n \"action\": \"fq_login()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n },\n {\n \"name\": \"🏝用户后台/注册\",\n \"type\": \"button\",\n \"action\": \"loginqt()\",\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 \"name\": \"🔮 检测登录\",\n \"type\": \"button\",\n \"action\": \"checkStatus()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n\n }, {\n \"name\": \" 🗑 清除设备\",\n \"type\": \"button\",\n \"action\": \"clearDevice()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n\n }, {\n \"name\": \"📑更少简介\",\n \"type\": \"button\",\n \"action\": \"set_info()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \"name\": \"📝段评开关\",\n \"type\": \"button\",\n \"action\": \"paracomment('fqpara')\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \"name\": \"👨🦱男频发现\",\n \"type\": \"button\",\n \"action\": \"set_source_type('男频')\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \"name\": \"👩🦰女频发现\",\n \"type\": \"button\",\n \"action\": \"set_source_type('女频')\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \"name\": \"☕打赏享福利\",\n \"type\": \"button\",\n \"action\": \"vip()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \"name\": \"❇️ 更新书源\",\n \"type\": \"button\",\n \"action\": \"renderVersionPage()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \"name\": \"🗂当前模式\",\n \"type\": \"button\",\n \"action\": \"get_media()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 1\n }\n }, {\n \"name\": \"📖小说模式\",\n \"type\": \"button\",\n \"action\": \"set_media('小说')\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \"name\": \"🔊听书模式\",\n \"type\": \"button\",\n \"action\": \"set_media('听书')\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \"name\": \"🏞漫画模式\",\n \"type\": \"button\",\n \"action\": \"set_media('漫画')\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \"name\": \"🖲短剧模式\",\n \"type\": \"button\",\n \"action\": \"set_media('短剧')\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \"name\": \"🎚切换服务器\",\n \"type\": \"button\",\n \"action\": \"set_server()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \"name\": \"♻️检测当前服务器\",\n \"type\": \"button\",\n \"action\": \"checkNet()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \"name\": \"⚕️本地/服务器 \",\n \"type\": \"button\",\n \"action\": \"get_proxy()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \"name\": \"📌永久发布页📌\",\n \"type\": \"button\",\n \"action\": \"api()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \"name\": \"↓↓下方可切换来源用于搜索/发现页↓↓\",\n \"type\": \"button\",\n \"action\": \"get_media()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 1\n }\n }, {\n \"name\": \"✨️网友推荐\",\n \"type\": \"button\",\n \"action\": \"set_source('推荐')\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \"name\": \"💖我来推荐\",\n \"type\": \"button\",\n \"action\": \"put_book()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \"name\": \"全部\",\n \"type\": \"button\",\n \"action\": \"set_source('全部')\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('番茄')\",\n 'name': '番茄',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('69书吧')\",\n 'name': '69书吧',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('七猫')\",\n 'name': '七猫',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('百度')\",\n 'name': '百度',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('起点')\",\n 'name': '起点(第三方)',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('得间')\",\n 'name': '得间',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('塔读')\",\n 'name': '塔读',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('书旗')\",\n 'name': '书旗',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('QQ')\",\n 'name': 'QQ',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('猫眼')\",\n 'name': '猫眼',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('搜书神器')\",\n 'name': '搜书神器',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('得奇')\",\n 'name': '得奇',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('伪69')\",\n 'name': '伪69',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('爱下电子书')\",\n 'name': '爱下电子书',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('小米')\",\n 'name': '小米',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('星星小说')\",\n 'name': '星星小说',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('笔趣阁22')\",\n 'name': '笔趣阁22',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('顶点')\",\n 'name': '顶点',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('幻梦轻小说')\",\n 'name': '幻梦轻小说',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('江湖')\",\n 'name': '江湖',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('歪瑞古德')\",\n 'name': '歪瑞古德漫画',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('河马')\",\n 'name': '河马短剧',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('知乎')\",\n 'name': '知乎',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('vip')\",\n 'name': '下方为VIP专属书源(点击此处搜所有vip)',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 1\n }\n }, {\n 'action': \"set_source('喜马拉雅')\",\n 'name': '喜马拉雅',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('酷我')\",\n 'name': '酷我',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('svip')\",\n 'name': '下方为SVIP专属书源(点击此处搜所有svip)',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 1\n }\n }, {\n 'action': \"set_source('超会专属短剧')\",\n 'name': '超会专属短剧',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('超会专属小说')\",\n 'name': '超会专属小说',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('台湾小说')\",\n 'name': '台湾小说',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('3A小说')\",\n 'name': '3A小说',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('包子漫画')\",\n 'name': '包子漫画',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, { \t \t\n 'action': \"set_source('QQ阅读')\",\n 'name': 'QQ(会员书籍免费)',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('书香之家')\",\n 'name': '书香之家',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \t 'action': \"set_source('追更人')\",\n 'name': '追更人',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('漫画屋')\",\n 'name': '漫画屋',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('漫画网')\",\n 'name': '漫画网',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('海洋听书')\",\n 'name': '海洋听书',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('鹿鹿')\",\n 'name': '鹿鹿',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('完本小说')\",\n 'name': '完本小说',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('盐选文库')\",\n 'name': '盐选文库',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, { \t \t\n 'action': \"set_source('福利小说')\",\n 'name': '福利小说',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('轻之文库')\",\n 'name': '轻之文库',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('小说三千')\",\n 'name': '小说三千',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('阅友小说')\",\n 'name': '阅友小说',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('星空小说')\",\n 'name': '星空小说',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('全免漫画')\",\n 'name': '全免漫画',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('365小说')\",\n 'name': '365小说',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('福利漫画')\",\n 'name': '福利漫画',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('万相书城')\",\n 'name': '万相书城',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('独步小说')\",\n 'name': '独步小说',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('铅笔轻小说')\",\n 'name': '铅笔轻小说',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('沧元图')\",\n 'name': '沧元图',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('全本同人')\",\n 'name': '全本同人',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n 'action': \"set_source('毒舌影视')\",\n 'name': '毒舌影视',\n 'type': 'button',\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n }, {\n \"name\": \"自定义搜索源(多个用英文,分割)\",\n \"type\": \"text\"\n }, {\n \"name\": \"听书Ai音色填写后点击右上角✔\",\n \"type\": \"text\"\n }, {\n \"name\": \"自定义服务器(可不填)\",\n \"type\": \"text\"\n }, {\n \"name\": \"自定义评论颜色(可不填)\",\n \"type\": \"text\"\n }, {\n \"name\": \"段评气泡样式\",\n \"type\": \"text\"\n }, {\n \"name\": \"手动填写番茄token(可不填)\",\n \"type\": \"text\"\n }\n]",
|
||
"loginUrl": "// 当前书源版本号,切勿修改,否则影响更新的识别\nconst localVersion = '4.11.25';\n\nfunction login(flag) {\n if (flag == undefined) {\n result = JSON.parse(source.getLoginInfo())\n } else {\n java.longToast(\"\\n\\n💞正在登录中...\")\n putLoginInfo(JSON.stringify(result))\n }\n let base_url = getArgument('server')\n let zdyserver = String(result['自定义服务器(可不填)']);\n if (zdyserver.includes('http')) {\n setArgument('server', zdyserver);\n if (getKey(String(cookie.getCookie(base_url)))) {\n let cookies = cookie.getCookie(base_url)\ntry{cookie.removeCookie(base_url)} catch(e){cookie.removeCookie(base_url)}\n cookie.setCookie(zdyserver, cookies)\n }\n java.toast(`\\n\\n当前服务器为自定义服务器\\n${zdyserver}\\n\\n切换服务器请先清空服务器地址中的数据`);\n }\n let zdytone_id = String(result['听书Ai音色填写后点击右上角✔'] || '');\n if (zdytone_id) {\n setArgument('tone_id', zdytone_id);\n } else {\n setArgument('tone_id', '默认音色');\n }\n let plcolor = String(result['自定义评论颜色(可不填)'] || '#000000');\n if (plcolor) {\n setArgument('plcolor', plcolor);\n } else {\n setArgument('plcolor', '#000000');\n }\n let zdysources = String(result['自定义搜索源(多个用英文,分割)'] || '');\n if (zdysources) {\n setArgument('source', zdysources);\n };\n base_url = getArgument('server')\n let register_email = String(result['邮箱'])\n let password = String(result['密码'])\n let key = String(result['密钥'] || '')\n\n //java.log(cookie.getCookie(base_url))\n if ((register_email && password || key) && !String(getKey(String(cookie.getCookie(base_url))))) {\n try{cookie.removeCookie(base_url)} catch(e){cookie.removeCookie(base_url)}\n let deviceKey = '';\n try {\n deviceKey = java.deviceID();\n } catch (e) {\n deviceKey = java.androidId();\n };\n let deviceId = deviceKey;\n if (register_email && password) {\n let options = JSON.stringify({\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n register_email: result['邮箱'],\n password: result['密码']\n })\n })\n try {\n let data = JSON.parse(java.ajax(`${base_url}/login_api,${options}`))\n if (data.code == 0) {\n //java.toast(deviceId)\n java.toast(\"\\n\\n✅️登录成功\")\n cookie.setCookie(base_url, `qttoken=${data.key};deviceId=${deviceId}`)\n result['密钥'] = data.key\n putLoginInfo(JSON.stringify(result))\n } else {\n java.toast('\\n\\n💔' + data.msg || \"登录失败,请重试!\")\n }\n } catch (e) {\n java.toast(\"\\n\\n💔登录失败,请重试!\\n\" + e.message)\n }\n } else {\n cookie.setCookie(base_url, `qttoken=${key};deviceId=${deviceId}`)\n let res = java.ajax(`${base_url}/user_api,{\"method\":\"POST\",\"headers\":{\"cookie\":\"${cookie.getCookie(base_url)}\"}}`)\n try {\n res = JSON.parse(res)\n if (res.id != undefined) {\n java.toast('\\n\\n密钥登录成功')\n result['邮箱'] = res.email\n putLoginInfo(JSON.stringify(result))\n } else {\n throw new Error()\n }\n } catch (e) {\n java.log(e)\n java.toast(\"\\n\\n💔登录失败\")\n }\n }\n } else if (flag && String(getKey(String(cookie.getCookie(base_url))))) {\n java.toast(\"\\n\\n当前✅️已登录,请🚫退出登录后重新登录\");\n //checkStatus();\n } else if (flag) {\n java.toast(\"\\n\\n⛔️请先填写邮箱和密码\");\n }\n}\n\n// 检测服务器\nfunction checkNet() {\n let url = getArgument('server');\n java.longToast(`\\n\\n♻️正在检测:${url}\\n请稍等~`);\n let date1 = new Date().getTime();\n let html = java.ajax(url + '/login');\n let date2 = new Date().getTime();\n let t = date2 - date1;\n let c = String(html).indexOf('大灰狼');\n let code = 1;\n let time = t / 1000 + 's';\n let logTime = '【' + url + '】\\n┋┋\\n' + '解析时间:' + time;\n if (c == -1 || t > 5000) {\n java.longToast('\\n💔【访问失败提示】\\n' + '┏┅━┅━┅━┅━┅┅━┅━┅┓\\n┋┋\\n' + logTime + '\\n┋┋\\n♣️当前接口无法访问(可能被墙)♣️\\n┋┋\\n请切换其他接口/切换网络环境\\n┋┋' + '\\n┗┅━┅━┅━┅━┅┅━┅━┅┛');\n } else if (t < 1000) {\n java.longToast('\\n💖【网络环境优良】\\n' + '┏┅━┅━┅━┅━┅┅━┅━┅┓\\n┋┋\\n' + logTime + '\\n┋┋\\n❤️延迟低,推荐使用此接口❤️\\n┋┋\\n网络环境优良,请继续保持状态\\n┋┋' + '\\n┗┅━┅━┅━┅━┅┅━┅━┅┛');\n } else if (t >= 1000 && t < 2000) {\n java.longToast('\\n💛【网络环境一般】\\n' + '┏┅━┅━┅━┅━┅┅━┅━┅┓\\n┋┋\\n' + logTime + '\\n┋┋\\n♦️延迟一般,勉强可使用♦️\\n┋┋\\n请切换其他接口或切换网络环境\\n┋┋' + '\\n┗┅━┅━┅━┅━┅┅━┅━┅┛');\n } else if (t >= 2000 && t < 5000) {\n java.longToast('\\n💔【网络环境堪忧】\\n' + '┏┅━┅━┅━┅━┅┅━┅━┅┓\\n┋┋\\n' + logTime + '\\n┋┋\\n♠延迟过高,不建议使用♠\\n┋┋\\n请切换其他接口或切换网络环境\\n┋┋' + '\\n┗┅━┅━┅━┅━┅┅━┅━┅┛');\n }\n}\n\nfunction isVips(res) {\n let isVIP = '';\n let vipEndTime = res.vip_end_time;\n let formattedDate = '';\n\n if (vipEndTime && vipEndTime !== 0) {\n let date = new Date(vipEndTime * 1000);\n formattedDate = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;\n let currentTime = Math.floor(Date.now() / 1000);\n let remainingDays = Math.ceil((vipEndTime - currentTime) / (24 * 60 * 60));\n if (currentTime > vipEndTime) {\n isVIP = `${res.vip_level === 1 ? \"VIP\" : \"SVIP\"} (已过期)`;\n } else if (remainingDays <= 7) {\n isVIP = `${res.vip_level === 1 ? \"VIP\" : \"SVIP\"} 剩余${remainingDays}天`;\n } else {\n if (vipEndTime < 1912946812) {\n isVIP = `${res.vip_level === 1 ? \"VIP\" : \"SVIP\"}(${formattedDate})`;\n } else {\n isVIP = `${res.vip_level === 1 ? \"VIP\" : \"SVIP\"} (永久)`;\n }\n }\n } else {\n isVIP = '您尚未开通VIP';\n }\n return isVIP;\n}\n\nfunction checkStatus() {\n java.longToast('\\n\\n♻️检测中...');\n let base_url = getArgument('server')\n let res = java.ajax(`${base_url}/user_api,{\"method\":\"POST\",\"headers\":{\"cookie\":\"${cookie.getCookie(base_url)}\"}}`)\n try {\n res = JSON.parse(res)\n if (res.id != undefined) {\n result['邮箱'] = res.email\n putLoginInfo(JSON.stringify(result))\n let devices\n try {\n devices = JSON.parse(res.device).length;\n } catch (e) {\n devices = res.device ? 1 : 0;\n }\n let isVip = isVips(res);\n tips = `\n┏┅┅┅┅┅┅┱┄┄┄┄┄┄┄┄┄┄┐\n 🧢昵称 ${res.nickname.padEnd(20,\"\\t\") || \"未设置\".padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n ✉️邮箱 ${res.email.replace(/(.{3}).*?@/,\"$1***@\").padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 🔑密钥 ${(`${res.user_key.substring(0,4)}***${res.user_key.slice(-4)}`).padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 📅注册时间 ${java.timeFormat(res.register_time*1000).padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 🗒️今日阅读 ${(java.timeFormat(new Date()).slice(0,10)==java.timeFormat(res.last_read_time * 1000).slice(0,10)?res.day_read_count:0).toString().padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 📚累计阅读 ${res.all_read_count.toString().padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 🕓最后阅读 ${(res.last_read_time != 0?java.timeFormat(res.last_read_time * 1000):'未阅读').padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 📱关联设备 ${devices.toString().padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 👑会员状态 ${isVip.padEnd(20,\"\\t\")}\n┣┅┅┅┅┅┅╉┄┄┄┄┄┄┄┄┄┄┤\n 🚫封禁状态 ${res.is_banned?'已封禁':'正常 '} \n┗┅┅┅┅┅┅┹┄┄┄┄┄┄┄┄┄┄┘\n`\n java.log(tips)\n java.longToast(tips)\n } else {\n throw new Error(res.msg)\n }\n } catch (e) {\n //java.log(e)\n java.toast(\"\\n检测登录失败\\n\" + e.message)\n }\n}\n\nfunction clearDevice() {\n let base_url = getArgument('server')\n let res = java.ajax(`${base_url}/clear,{\"method\":\"POST\",\"headers\":{\"cookie\":\"${cookie.getCookie(base_url)}\"}}`)\n java.toast(res.code === 0 ? \"\\n\\n📴设备清除成功\" : res.msg)\n Packages.java.lang.Thread.sleep(500)\n checkStatus()\n}\n// 保存登录UI信息\nfunction putLoginInfo(info) {\n try {\n let key = java.androidId()\n let encodeStr = Packages.android.util.Base64.encodeToString(java.createSymmetricCrypto(\"AES\", key).encrypt(info), 2)\n cache.put(`userInfo_${source.getKey()}`, encodeStr)\n return true\n } catch (e) {\n java.log(e)\n return source.putLoginInfo(info)\n }\n}\n\n// 填写密钥\nfunction loginqt() {\n java.startBrowserAwait(getArgument('server') + '/login', '登录大灰狼小说书源');\n}\n\n//登录番茄\nfunction fq_login() {\n try {\n java.startBrowserAwait(\"https://fanqienovel.com/\", \"登录\")\n } catch (e) {\n java.toast(e)\n }\n try {\n cookie.removeCookie(\"snssdk.com\")\n } catch (e) {}\n var cookie_ = \"sessionid=\" + (String(cookie.getKey(\"fanqienovel.com\", \"sessionid\")) ? String(cookie.getKey(\"fanqienovel.com\", \"sessionid\")) : source.getLoginInfoMap()['手动登录Token'])\n let user\n try {\n user = JSON.parse(java.ajax(\"https://fanqienovel.com/api/user/info/v2,\" + JSON.stringify({\n method: \"GET\",\n headers: {\n \"Cookie\": cookie_\n }\n }))).data.name\n } catch (e) {\n java.log(e)\n }\n if (!cookie_ || cookie_ == \"sessionid=\" || !user) {\n java.toast(\"未获取到登录凭据,登录失败\")\n return false\n }\n java.toast(\"\\n\\n欢迎 \" + user + \"\\n登录成功!\")\n return true\n}\n\n//退出登录\nfunction logout() {\n cookie.removeCookie(\"fanqienovel.com\");\n cookie.removeCookie(\"snssdk.com\");\n cookie.removeCookie(\"69shuba.com\");\n /*\n let servers = host\n for (let server of servers) {\n \ttry{cookie.removeCookie(server )} catch(e){cookie.removeCookie(server )}\n }\n */\ntry{cookie.removeCookie(getArgument('server'))} catch(e){cookie.removeCookie(getArgument('server'))}\n java.toast(\"退出登录成功\");\n}\n\n//获取参数\nfunction getArgument(key) {\n let open_argument = source.getVariable();\n open_argument = getArguments(open_argument, '');\n return open_argument[key];\n}\n\n//设置参数\nfunction setArgument(key, value) {\n let open_argument = source.getVariable();\n open_argument = getArguments(open_argument, '');\n open_argument[key] = value;\n open_argument = JSON.stringify(open_argument);\n source.setVariable(open_argument);\n return open_argument;\n}\n\n// 设置本地or云端访问\nfunction get_proxy() {\n let proxy = getArgument('proxy');\n if (proxy == '本地') {\n setArgument('proxy', '云端');\n java.longToast('\\n所有数据采用\\n\\n服务器网络访问\\n\\n如果发现用不了,请切换本地网络访问,如69书吧');\n } else {\n setArgument('proxy', '本地');\n java.longToast('\\n所有数据采用\\n\\n本地网络访问\\n\\n如果发现用不了,请开启网络代理,如69书吧');\n }\n}\n\n\n//设置男女频\nfunction set_source_type(source_type) {\n setArgument(\"source_type\", source_type);\n java.toast(\"\\n发现页已设置为:\" + source_type);\n}\n\n//首页\nfunction api() {\n java.startBrowserAwait('http://fb.langge.cf', \"首页\");\n}\n\n//打赏\nfunction vip() {\n java.startBrowserAwait(getArgument('server') + '/coffee', \"喝咖啡\");\n}\n\nvar server = getArgument('server');\n\n//设置搜索媒体\nfunction set_media(media) {\n const mediaConfig = {\n '喜马拉雅': ['听书'],\n '番茄': '*',\n '福利小说':['小说'],\n '全免漫画':['漫画'],\n '包子漫画':['漫画'],\n '漫画网':['漫画'],\n '风车漫画':['漫画'],\n '福利漫画':['漫画'],\n '好看漫画':['漫画'],\n '酷我':['听书'],\n '海洋听书':['听书'],\n '七猫': ['小说', '听书'],\n '河马': ['短剧'],\n '超会专属短剧': ['短剧'],\n '歪瑞古德': ['漫画'],\n '毒舌影视':['短剧'],\n '全部': '*', // 允许所有模式\n '默认': ['小说']\n };\n\n const source = getArgument('source');\n const allowedModes = mediaConfig[source] || mediaConfig['默认'];\n let targetMedia = mediaConfig['默认'][0];\n let isAllowed = false;\n\n if (allowedModes === '*' || allowedModes.includes(media)) {\n targetMedia = media;\n isAllowed = true;\n } else if (Array.isArray(allowedModes)) {\n targetMedia = allowedModes[0];\n }\n\n const message = isAllowed ?\n `\\n\\n已切换至:${targetMedia}\\n请重新搜索书籍!` :\n `\\n\\n目前${source}:不支持【${media}】模式!\\n已自动切换至:${targetMedia}`;\n\n setArgument('media', targetMedia);\n java.toast(message);\n}\n\n//获取搜索媒体\nfunction get_media() {\n let media = getArgument('media');\n let source = getArgument('source');\n if (media == '') {\n media = '全部';\n }\n var tishi = '\\n\\n当前服务器:' + getArgument('server')\n java.longToast(`\\n\\n当前使用源:${source}-${media}${tishi}`);\n}\n\n\n//设置服务器\nfunction set_server() {\n putLoginInfo(JSON.stringify(result))\n let zdyserver;\n let base_url = getArgument('server')\n try {\n zdyserver = String(result['自定义服务器(可不填)']);\n if (zdyserver.includes('http')) {\n setArgument('server', zdyserver);\n if (getKey(String(cookie.getCookie(base_url)))) {\n let cookies = cookie.getCookie(base_url)\n try{cookie.removeCookie(base_url)} catch(e){cookie.removeCookie(base_url)}\n cookie.setCookie(zdyserver, cookies)\n }\n java.toast(`\\n\\n当前服务器为自定义服务器\\n${zdyserver}\\n\\n切换服务器请先清空服务器地址中的数据`);\n } else {\n zdyserver = '';\n }\n } catch (error) {\n zdyserver = '';\n }\n if (!zdyserver) {\n const servers = host\n const currentServer = getArgument('server') || '';\n const currentIndex = servers.indexOf(currentServer);\n\n const nextIndex = currentIndex >= 0 ? (currentIndex + 1) % servers.length : 0;\n const nextServer = servers[nextIndex];\n\n setArgument('server', nextServer);\n if (getKey(String(cookie.getCookie(currentServer)))) {\n let cookies = cookie.getCookie(currentServer)\ntry{cookie.removeCookie(currentServer)} catch(e){cookie.removeCookie(currentServer)}\n cookie.setCookie(nextServer, cookies)\n }\n java.longToast(`\\n\\n服务器【${nextIndex+1}】:${nextServer}`);\n }\n}\n\n//获取音色\nvar tone_id = getArgument('tone_id');\n\nfunction get_tone_id(arg) {\n var datadist = {\n \"0\": \"默认音色\",\n \"-1\": \"阅读模式\",\n \"-2\": \"漫画模式\",\n \"51\": \"多人发音\",\n \"1\": \"甜美少女\",\n \"2\": \"清亮青叔\",\n \"5\": \"开朗青年\",\n \"6\": \"温柔淑女\",\n \"4\": \"成熟大叔\",\n \"74\": \"大叔升级\",\n \"30\": \"优雅御姐\"\n };\n var tone_id = datadist[arg] || arg;\n var tishi = '\\n\\n当前音色:' + tone_id;\n java.toast(tishi);\n}\n\n//设置音色\nfunction set_tone_id(mode, name) {\n putLoginInfo(JSON.stringify(result))\n let zdytone_id;\n try {\n zdytone_id = String(result['其他音色填写后点击右上角✔']);\n if (zdytone_id) {\n setArgument('tone_id', zdytone_id);\n java.toast(`\\n\\n当前音色为自定义音色\\n${zdytone_id}\\n\\n切换音色请先清空音色输入框中的数据`);\n } else {\n zdytone_id = '';\n }\n } catch (error) {\n zdytone_id = '';\n }\n if (!zdytone_id) {\n let toast = \"\\n\\n已切换至:\" + name + '\\n\\n切换后需要刷新详情页';\n setArgument('tone_id', mode);\n java.toast(toast);\n }\n}\n\n//设置来源\nfunction set_source(sources) {\n let zdysources = String(result['自定义搜索源(多个用英文,分割)'] || '');\n if (zdysources.length > 1 && zdysources != 'undefined') {\n java.toast('\\n\\n请先清空自定义源再设置');\n } else {\n setArgument('source', sources);\n set_media('小说');\n java.toast(`\\n\\n当前来源已切换为:\\n${sources}\\n\\n切换后请重新搜索`);\n }\n}\n\n// 设置简介\nfunction set_info() {\n var info = getArgument('info');\n if (info == 'on') {\n setArgument('info', 'off');\n java.toast('\\n\\n已恢复详情页详细简介');\n } else {\n setArgument('info', 'on');\n java.toast('\\n\\n已精简详情页简介');\n }\n}\n\n// 番茄段评\nfunction paracomment() {\n var fqpara = getArgument('fqpara');\n if (fqpara == 'on') {\n setArgument('fqpara', 'off');\n java.longToast('\\n\\n段评已关闭');\n } else {\n setArgument('fqpara', 'on');\n java.longToast(\"\\n\\n段评已开启\\n\\n长按刷新段后面的图片即可\\n\\n如果图片不显示,刷新无反应\\n请更新测试版阅读app\");\n }\n}\n\n\n// 我要推荐\nfunction put_book() {\n java.startBrowserAwait(getArgument('server') + '/put_book', '我来推荐');\n}\n\n// 书源更新\nfunction renderVersionPage() {\n let yd = '';\n let html = `\n<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>书源更新</title>\n <!-- Font Awesome 图标库 -->\n <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css\" />\n <style>\n :root {\n --primary-gradient: linear-gradient(135deg, #4e6ef2, #6b2dd8);\n --latest-gradient: linear-gradient(135deg, #8e2de2 0%, #4a00e0 50%, #d4af37 100%);\n --success-color: #28c76f;\n --warning-color: #ff9f43;\n --error-color: #ea5455;\n --text-main: #1f2937;\n --text-secondary: #6b7280;\n --card-bg: #ffffff;\n --border-color: #e5e7eb;\n --light-bg: #f9fafb;\n --shadow: 0 4px 12px rgba(78, 110, 242, 0.1);\n --shadow-hover: 0 6px 18px rgba(78, 110, 242, 0.2);\n --glow-shadow: 0 0 25px rgba(142, 45, 226, 0.5), 0 0 50px rgba(212, 175, 55, 0.3);\n --modal-bg: rgba(31, 41, 55, 0.8);\n --modal-content-bg: #ffffff;\n }\n\n * {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n font-family: 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;\n }\n\n body {\n background: linear-gradient(135deg, #eef2ff, #f5f7ff);\n color: var(--text-main);\n min-height: 100vh;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 16px;\n }\n\n /* 加载动画 */\n .loading-wrapper {\n text-align: center;\n animation: fadeIn 0.3s ease;\n }\n\n .loading-spinner {\n width: 50px;\n height: 50px;\n border: 4px solid rgba(78, 110, 242, 0.3);\n border-top-color: #4e6ef2;\n border-radius: 50%;\n margin: 0 auto 20px;\n animation: spin 1s linear infinite;\n }\n\n .loading-text {\n color: var(--text-main);\n font-size: 16px;\n font-weight: 500;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n @keyframes fadeIn {\n from { opacity: 0; transform: translateY(20px); }\n to { opacity: 1; transform: translateY(0); }\n }\n\n @keyframes slideIn {\n from { opacity: 0; transform: translateY(30px); }\n to { opacity: 1; transform: translateY(0); }\n }\n\n @keyframes pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.7; }\n }\n\n @keyframes gradientAnimation {\n 0% { background-position: 0% 50%; }\n 50% { background-position: 100% 50%; }\n 100% { background-position: 0% 50%; }\n }\n\n @keyframes breathe {\n 0%, 100% { \n transform: scale(1);\n box-shadow: var(--glow-shadow), var(--shadow);\n }\n 50% { \n transform: scale(1.02);\n box-shadow: 0 0 30px rgba(142, 45, 226, 0.6), 0 0 60px rgba(212, 175, 55, 0.4), var(--shadow);\n }\n }\n\n @keyframes shimmer {\n 0% {\n background-position: -200% center;\n }\n 100% {\n background-position: 200% center;\n }\n }\n\n /* 主容器 */\n .container {\n width: 100%;\n max-width: 420px;\n background: var(--card-bg);\n border-radius: 24px;\n overflow: hidden;\n box-shadow: var(--shadow);\n position: relative;\n z-index: 1;\n animation: slideIn 0.5s ease;\n display: none;\n }\n\n /* 头部 */\n .header {\n background: var(--primary-gradient);\n color: #ffffff;\n padding: 24px 16px;\n text-align: center;\n position: relative;\n overflow: hidden;\n }\n\n .header::before {\n content: '';\n position: absolute;\n top: -30px;\n left: -30px;\n width: 80px;\n height: 80px;\n background: rgba(255, 255, 255, 0.15);\n border-radius: 50%;\n }\n\n .header::after {\n content: '';\n position: absolute;\n bottom: -60px;\n right: -60px;\n width: 150px;\n height: 150px;\n background: rgba(255, 255, 255, 0.1);\n border-radius: 50%;\n }\n\n .header h1 {\n font-size: 1.4rem;\n font-weight: 700;\n margin-bottom: 8px;\n position: relative;\n z-index: 2;\n }\n\n .header p {\n font-size: 0.9rem;\n opacity: 0.9;\n line-height: 1.4;\n position: relative;\n z-index: 2;\n }\n\n .header-icon {\n font-size: 48px;\n margin-bottom: 10px;\n display: inline-block;\n animation: bounce 2s ease infinite;\n }\n\n @keyframes bounce {\n 0%, 100% { transform: translateY(0); }\n 50% { transform: translateY(-10px); }\n }\n\n /* 版本对比 */\n .version-comparison {\n display: flex;\n flex-wrap: nowrap;\n gap: 12px;\n padding: 16px;\n margin-top: 8px;\n position: relative;\n z-index: 10;\n }\n\n .version-card {\n flex: 1;\n min-width: 45%;\n background: var(--card-bg);\n border-radius: 16px;\n padding: 28px 16px 16px;\n box-shadow: var(--shadow);\n text-align: center;\n position: relative;\n transition: transform 0.3s ease, box-shadow 0.3s ease;\n overflow: hidden;\n border: 1px solid rgba(120, 130, 240, 0.1);\n }\n\n .version-card:hover {\n transform: translateY(-4px);\n box-shadow: var(--shadow-hover);\n }\n\n .version-card.current-version {\n background: linear-gradient(135deg, #ffffff 0%, #f8f9ff 100%);\n border: 1px solid rgba(78, 110, 242, 0.15);\n }\n\n .version-card.current-version:hover {\n box-shadow: 0 6px 20px rgba(78, 110, 242, 0.15);\n }\n\n .version-card.current-version h3,\n .version-card.current-version .version-number,\n .version-card.current-version .version-date {\n color: var(--text-main);\n }\n\n .version-card.latest-version {\n background: var(--latest-gradient);\n background-size: 300% 300%;\n box-shadow: var(--glow-shadow), var(--shadow);\n color: #fff;\n z-index: 2;\n animation: gradientAnimation 6s ease infinite, breathe 3s ease-in-out infinite;\n position: relative;\n overflow: hidden;\n }\n\n .version-card.latest-version::before {\n content: '';\n position: absolute;\n top: -50%;\n left: -50%;\n width: 200%;\n height: 200%;\n background: linear-gradient(\n 90deg,\n transparent,\n rgba(255, 255, 255, 0.3),\n transparent\n );\n transform: rotate(45deg);\n animation: shimmer 3s infinite;\n }\n\n .version-card.latest-version h3,\n .version-card.latest-version .version-number,\n .version-card.latest-version .version-date {\n color: #fff;\n text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);\n position: relative;\n z-index: 1;\n }\n\n .version-status {\n position: absolute;\n top: 6px;\n right: 6px;\n padding: 3px 7px;\n font-size: 0.65rem;\n font-weight: 600;\n border-radius: 6px;\n color: #fff;\n line-height: 1.2;\n white-space: nowrap;\n z-index: 2;\n }\n\n .version-card.latest-version .version-status {\n background: rgba(255, 255, 255, 0.25);\n backdrop-filter: blur(5px);\n border: 1px solid rgba(255, 255, 255, 0.3);\n color: #fff;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n }\n\n .status-outdated { background: var(--warning-color); }\n .status-latest { background: var(--success-color); }\n .status-invalid { background: var(--error-color); }\n\n .version-card h3 {\n font-size: 0.9rem;\n color: var(--text-secondary);\n margin-bottom: 8px;\n font-weight: 500;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n }\n\n .version-number {\n font-size: 1.25rem;\n font-weight: 700;\n color: var(--text-main);\n margin: 8px 0;\n transition: all 0.3s ease;\n font-family: 'Courier New', monospace;\n }\n\n .version-card.latest-version .version-number {\n font-size: 1.4rem;\n transform: scale(1.05);\n text-shadow: \n 0 2px 4px rgba(0, 0, 0, 0.3),\n 0 0 10px rgba(212, 175, 55, 0.8),\n 0 0 20px rgba(212, 175, 55, 0.5);\n animation: pulse-glow 2s ease-in-out infinite;\n }\n\n @keyframes pulse-glow {\n 0%, 100% {\n text-shadow: \n 0 2px 4px rgba(0, 0, 0, 0.3),\n 0 0 10px rgba(212, 175, 55, 0.8),\n 0 0 20px rgba(212, 175, 55, 0.5);\n }\n 50% {\n text-shadow: \n 0 2px 4px rgba(0, 0, 0, 0.3),\n 0 0 15px rgba(212, 175, 55, 1),\n 0 0 30px rgba(212, 175, 55, 0.7);\n }\n }\n\n .version-date {\n font-size: 0.8rem;\n color: var(--text-secondary);\n margin-top: 4px;\n }\n\n /* 版本对比指示器 */\n .version-indicator {\n position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n z-index: 5;\n width: 32px;\n height: 32px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n color: white;\n }\n\n .version-indicator.update-needed {\n background: var(--error-color);\n box-shadow: 0 2px 8px rgba(234, 84, 85, 0.4);\n animation: pulse-indicator 1.5s infinite;\n }\n\n .version-indicator.is-latest {\n background: var(--success-color);\n box-shadow: 0 2px 8px rgba(40, 199, 111, 0.4);\n }\n\n @keyframes pulse-indicator {\n 0% { transform: translate(-50%, -50%) scale(1); }\n 50% { transform: translate(-50%, -50%) scale(1.1); }\n 100% { transform: translate(-50%, -50%) scale(1); }\n }\n\n /* 内容区 */\n .content-container {\n padding: 16px;\n }\n\n /* 状态提示 */\n .status-alert {\n background: var(--card-bg);\n border-radius: 16px;\n box-shadow: var(--shadow);\n margin-bottom: 16px;\n overflow: hidden;\n border: 1px solid rgba(120, 130, 240, 0.1);\n padding: 12px 16px;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 10px;\n font-weight: 500;\n font-size: 14px;\n animation: slideIn 0.5s ease 0.3s backwards;\n }\n\n .status-alert i {\n font-size: 20px;\n }\n\n .status-alert.update-available {\n background: linear-gradient(135deg, #ffeaa7 0%, #fdcb6e 100%);\n color: #d63031;\n box-shadow: 0 4px 15px rgba(253, 203, 110, 0.4);\n }\n\n .status-alert.up-to-date {\n background: linear-gradient(135deg, #55efc4 0%, #00b894 100%);\n color: white;\n box-shadow: 0 4px 15px rgba(0, 184, 148, 0.4);\n }\n\n /* 更新容器 */\n .update-container {\n background: var(--card-bg);\n border-radius: 16px;\n box-shadow: var(--shadow);\n margin-bottom: 16px;\n overflow: hidden;\n border: 1px solid rgba(120, 130, 240, 0.1);\n animation: slideIn 0.5s ease 0.4s backwards;\n }\n\n .update-header {\n background: var(--light-bg);\n padding: 12px 16px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n border-bottom: 1px solid var(--border-color);\n }\n\n .update-header h2 {\n font-size: 1rem;\n font-weight: 600;\n color: var(--text-main);\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .update-header h2 i {\n color: #4e6ef2;\n }\n\n .update-tag {\n background: rgba(78, 110, 242, 0.1);\n color: #4e6ef2;\n padding: 4px 8px;\n border-radius: 8px;\n font-size: 0.75rem;\n font-weight: 600;\n }\n\n .update-content {\n padding: 16px;\n }\n\n .update-date {\n font-weight: 600;\n color: #4e6ef2;\n margin-bottom: 12px;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 0;\n border-bottom: 1px dashed #e0e0e0;\n }\n\n .update-text {\n margin: 8px 0;\n position: relative;\n padding-left: 16px;\n line-height: 1.5;\n color: var(--text-main);\n font-size: 0.95rem;\n white-space: pre-wrap;\n word-break: break-word;\n }\n\n .update-text::before {\n content: '•';\n position: absolute;\n left: 0;\n font-weight: bold;\n color: #4e6ef2;\n font-size: 1.2rem;\n line-height: 1;\n }\n\n /* 历史日志 */\n .history-container {\n background: var(--card-bg);\n border-radius: 16px;\n box-shadow: var(--shadow);\n margin-bottom: 16px;\n border: 1px solid rgba(120, 130, 240, 0.1);\n animation: slideIn 0.5s ease 0.5s backwards;\n }\n\n .history-header {\n background: var(--light-bg);\n padding: 12px 16px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n border-bottom: 1px solid var(--border-color);\n cursor: pointer;\n user-select: none;\n }\n\n .history-header:hover {\n opacity: 0.8;\n }\n\n .history-header h2 {\n font-size: 1rem;\n font-weight: 600;\n color: var(--text-main);\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .history-header h2 i {\n color: #4e6ef2;\n }\n\n .toggle-history {\n background: none;\n border: none;\n color: var(--text-secondary);\n cursor: pointer;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 0.85rem;\n transition: color 0.2s ease;\n }\n\n .toggle-history:hover {\n color: #4e6ef2;\n }\n\n .history-content {\n padding: 0 16px;\n max-height: 0;\n overflow: hidden;\n transition: max-height 0.4s ease, padding 0.4s ease;\n }\n\n .history-content.expanded {\n max-height: 60vh;\n overflow-y: auto;\n padding: 16px;\n scrollbar-width: thin;\n scrollbar-color: #4e6ef2 #f0f0f0;\n }\n\n .history-content.expanded::-webkit-scrollbar {\n width: 6px;\n }\n\n .history-content.expanded::-webkit-scrollbar-track {\n background: #f0f0f0;\n border-radius: 4px;\n }\n\n .history-content.expanded::-webkit-scrollbar-thumb {\n background: #4e6ef2;\n border-radius: 4px;\n }\n\n .history-content.expanded::-webkit-scrollbar-thumb:hover {\n background: #3a56d0;\n }\n\n .history-item {\n margin-bottom: 16px;\n padding-bottom: 16px;\n border-bottom: 1px dashed var(--border-color);\n }\n\n .history-item:last-child {\n border-bottom: none;\n margin-bottom: 0;\n padding-bottom: 0;\n }\n\n .history-date {\n font-weight: 600;\n color: var(--text-main);\n margin-bottom: 8px;\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 0.9rem;\n background: rgba(78, 110, 242, 0.05);\n padding: 6px 10px;\n border-radius: 6px;\n }\n\n .history-text {\n margin: 8px 0;\n padding-left: 16px;\n line-height: 1.4;\n color: var(--text-secondary);\n position: relative;\n font-size: 0.9rem;\n white-space: pre-wrap;\n word-break: break-word;\n }\n\n .history-text::before {\n content: '•';\n position: absolute;\n left: 0;\n color: #4e6ef2;\n font-weight: bold;\n font-size: 1.2rem;\n line-height: 1;\n }\n\n /* 按钮组 */\n .button-group {\n display: flex;\n flex-direction: column;\n gap: 10px;\n margin-bottom: 16px;\n }\n\n .button {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 10px;\n padding: 14px 28px;\n text-align: center;\n font-size: 1rem;\n border: none;\n border-radius: 12px;\n text-decoration: none;\n background: var(--primary-gradient);\n color: white;\n font-weight: 600;\n transition: all 0.3s ease;\n box-shadow: var(--shadow);\n position: relative;\n overflow: hidden;\n cursor: pointer;\n }\n\n .button i {\n font-size: 1rem;\n }\n\n .button::after {\n content: '';\n position: absolute;\n top: -50%;\n left: -50%;\n width: 200%;\n height: 200%;\n background: rgba(255, 255, 255, 0.1);\n transform: rotate(30deg);\n transition: all 0.6s ease;\n pointer-events: none;\n }\n\n .button:hover {\n transform: translateY(-3px);\n box-shadow: var(--shadow-hover);\n }\n\n .button:hover::after {\n transform: rotate(30deg) translate(20%, 20%);\n }\n\n .button:active {\n transform: scale(0.95);\n }\n\n /* 错误状态 */\n .error-state {\n text-align: center;\n padding: 40px 20px;\n color: var(--text-main);\n }\n\n .error-icon {\n font-size: 64px;\n margin-bottom: 20px;\n color: var(--error-color);\n }\n\n .error-text {\n font-size: 16px;\n line-height: 1.6;\n margin-bottom: 20px;\n }\n\n .retry-button {\n background: var(--primary-gradient);\n color: white;\n padding: 12px 30px;\n border-radius: 12px;\n border: none;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.3s ease;\n font-size: 14px;\n box-shadow: var(--shadow);\n }\n\n .retry-button:hover {\n transform: translateY(-2px);\n box-shadow: var(--shadow-hover);\n }\n\n .retry-button:active {\n transform: scale(0.95);\n }\n\n /* 装饰元素 */\n .decoration {\n position: absolute;\n z-index: 0;\n pointer-events: none;\n }\n\n .decoration.circle {\n width: 120px;\n height: 120px;\n border-radius: 50%;\n background: rgba(107, 45, 216, 0.05);\n top: 10%;\n left: 10%;\n }\n\n .decoration.square {\n width: 80px;\n height: 80px;\n transform: rotate(45deg);\n background: rgba(78, 110, 242, 0.05);\n bottom: 10%;\n right: 10%;\n }\n\n /* 响应式 */\n @media (max-width: 768px) {\n body {\n padding: 12px;\n }\n\n .container {\n max-width: 100%;\n border-radius: 20px;\n }\n\n .header {\n padding: 20px 15px;\n }\n\n .header h1 {\n font-size: 1.3rem;\n }\n\n .header-icon {\n font-size: 40px;\n }\n\n .version-comparison {\n flex-direction: row;\n flex-wrap: nowrap;\n gap: 10px;\n padding: 12px;\n margin-top: 6px;\n overflow-x: auto;\n }\n\n .version-card {\n min-width: 45%;\n padding: 26px 12px 12px;\n }\n\n /* 移动端减弱呼吸动效 */\n .version-card.latest-version {\n animation: gradientAnimation 6s ease infinite;\n }\n\n .version-status {\n top: 5px;\n right: 5px;\n padding: 2px 5px;\n font-size: 0.6rem;\n }\n\n .version-number {\n font-size: 1.1rem;\n }\n\n .version-card.latest-version .version-number {\n font-size: 1.2rem;\n }\n\n .update-header h2, .history-header h2 {\n font-size: 0.9rem;\n }\n\n .button {\n padding: 12px 24px;\n font-size: 0.95rem;\n }\n\n .history-content.expanded {\n max-height: 50vh;\n -webkit-overflow-scrolling: touch;\n }\n }\n\n @media (max-width: 380px) {\n .header h1 {\n font-size: 1.2rem;\n }\n\n .version-number {\n font-size: 1rem;\n }\n\n .version-card.latest-version .version-number {\n font-size: 1.1rem;\n }\n\n .button {\n padding: 11px;\n font-size: 0.9rem;\n }\n }\n </style>\n</head>\n<body>\n <div class=\"decoration circle\"></div>\n <div class=\"decoration square\"></div>\n\n <div id=\"loading\" class=\"loading-wrapper\">\n <div class=\"loading-spinner\"></div>\n <div class=\"loading-text\"><i class=\"fas fa-search\"></i> 正在检查更新...</div>\n </div>\n\n <div class=\"container\" id=\"container\">\n <div class=\"header\">\n <div class=\"header-icon\"><i class=\"fas fa-book\"></i></div>\n <h1>大灰狼书源更新</h1>\n <p>请使用阅读测试版,不支持正式版</p>\n </div>\n\n <div class=\"version-comparison\">\n <div class=\"version-card current-version\">\n <div class=\"version-status status-outdated\" id=\"currentStatus\">待检查</div>\n <h3><i class=\"fas fa-cube\"></i> 当前版本</h3>\n <div class=\"version-number\" id=\"currentVersion\">-</div>\n <div class=\"version-date\">您的当前版本</div>\n </div>\n\n <div class=\"version-indicator update-needed\" id=\"versionIndicator\" style=\"display: none;\">\n <i class=\"fas fa-arrow-right\"></i>\n </div>\n\n <div class=\"version-card latest-version\">\n <div class=\"version-status status-latest\" id=\"latestStatus\">最新版本</div>\n <h3><i class=\"fas fa-star\"></i> 最新版本</h3>\n <div class=\"version-number\" id=\"latestVersion\">-</div>\n <div class=\"version-date\">可用最新版本</div>\n </div>\n </div>\n\n <div class=\"content-container\">\n <div class=\"status-alert\" id=\"statusAlert\" style=\"display: none;\"></div>\n\n <div id=\"latestLogContainer\" style=\"display: none;\">\n <div class=\"update-container\">\n <div class=\"update-header\">\n <h2><i class=\"fas fa-bolt\"></i> 最新更新</h2>\n <div class=\"update-tag\">最新发布</div>\n </div>\n <div class=\"update-content\">\n <div class=\"update-date\" id=\"latestLogDate\"></div>\n <div class=\"update-text\" id=\"latestLogContent\"></div>\n </div>\n </div>\n </div>\n\n <div class=\"button-group\" id=\"buttonGroup\" style=\"display: none;\"></div>\n\n <div class=\"history-container\" id=\"logs\" style=\"display: none;\">\n <div class=\"history-header\" onclick=\"toggleLogs()\">\n <h2><i class=\"fas fa-history\"></i> 历史更新 <span id=\"historyCount\"></span></h2>\n <button class=\"toggle-history\" id=\"toggleButton\">\n <span id=\"toggleText\">展开历史</span>\n <i class=\"fas fa-chevron-down\" id=\"toggleIcon\"></i>\n </button>\n </div>\n <div class=\"history-content\" id=\"logList\"></div>\n </div>\n </div>\n </div>\n\n <script>\n let logsCollapsed = true;\n\n function toggleLogs() {\n logsCollapsed = !logsCollapsed;\n const logList = document.getElementById('logList');\n const toggleText = document.getElementById('toggleText');\n const toggleIcon = document.getElementById('toggleIcon');\n \n if (logsCollapsed) {\n logList.classList.remove('expanded');\n toggleText.textContent = '展开历史';\n toggleIcon.className = 'fas fa-chevron-down';\n } else {\n logList.classList.add('expanded');\n toggleText.textContent = '收起历史';\n toggleIcon.className = 'fas fa-chevron-up';\n }\n }\n\n (async function() {\n const loading = document.getElementById('loading');\n const container = document.getElementById('container');\n const currentVersion = document.getElementById('currentVersion');\n const latestVersion = document.getElementById('latestVersion');\n const currentStatus = document.getElementById('currentStatus');\n const latestStatus = document.getElementById('latestStatus');\n const versionIndicator = document.getElementById('versionIndicator');\n const statusAlert = document.getElementById('statusAlert');\n const buttonGroup = document.getElementById('buttonGroup');\n const latestLogContainer = document.getElementById('latestLogContainer');\n const latestLogDate = document.getElementById('latestLogDate');\n const latestLogContent = document.getElementById('latestLogContent');\n const logsContainer = document.getElementById('logs');\n const logList = document.getElementById('logList');\n const historyCount = document.getElementById('historyCount');\n\n const localVer = '${String(localVersion)}';\n\n // 统一的服务器配置 - 方便维护\n const serverConfig = {\n main: {\n name: '主线路',\n icon: 'rocket',\n baseUrl: 'https://sy.dashabi.tk',\n downloadPath: '/download/%E5%AE%89%E5%8D%93%E9%98%85%E8%AF%BBapp-%E5%A4%A7%E7%81%B0%E7%8B%BC%E8%9E%8D%E5%90%884.0(%E5%AE%8C%E5%85%A8%E7%89%88).json'\n },\n backup1: {\n name: '备用线路1',\n icon: 'box',\n baseUrl: 'https://api.langge.cf',\n downloadPath: '/sy/download/%E5%AE%89%E5%8D%93%E9%98%85%E8%AF%BBapp-%E5%A4%A7%E7%81%B0%E7%8B%BC%E8%9E%8D%E5%90%884.0(%E5%AE%8C%E5%85%A8%E7%89%88).json'\n },\n backup2: {\n name: '备用线路2',\n icon: 'satellite',\n baseUrl: 'https://20.langge.tk',\n downloadPath: '/sy/download/%E5%AE%89%E5%8D%93%E9%98%85%E8%AF%BBapp-%E5%A4%A7%E7%81%B0%E7%8B%BC%E8%9E%8D%E5%90%884.0(%E5%AE%8C%E5%85%A8%E7%89%88).json'\n },\n backup3: {\n name: '备用线路3',\n icon: 'link',\n baseUrl: 'http://219.154.201.122:5006',\n downloadPath: '/sy/download/%E5%AE%89%E5%8D%93%E9%98%85%E8%AF%BBapp-%E5%A4%A7%E7%81%B0%E7%8B%BC%E8%9E%8D%E5%90%884.0(%E5%AE%8C%E5%85%A8%E7%89%88).json'\n },\n backup4: {\n name: '备用线路4',\n icon: 'bolt',\n baseUrl: 'https://v2.czyl.cf',\n downloadPath: '/sy/download/%E5%AE%89%E5%8D%93%E9%98%85%E8%AF%BBapp-%E5%A4%A7%E7%81%B0%E7%8B%BC%E8%9E%8D%E5%90%884.0(%E5%AE%8C%E5%85%A8%E7%89%88).json'\n },\n backup5: {\n name: '备用线路5',\n icon: 'globe',\n baseUrl: 'https://v7.czyl.cf',\n downloadPath: '/sy/download/%E5%AE%89%E5%8D%93%E9%98%85%E8%AF%BBapp-%E5%A4%A7%E7%81%B0%E7%8B%BC%E8%9E%8D%E5%90%884.0(%E5%AE%8C%E5%85%A8%E7%89%88).json'\n },\n backup6: {\n name: '备用线路6',\n icon: 'broadcast-tower',\n baseUrl: 'https://v8.czyl.cf',\n downloadPath: '/sy/download/%E5%AE%89%E5%8D%93%E9%98%85%E8%AF%BBapp-%E5%A4%A7%E7%81%B0%E7%8B%BC%E8%9E%8D%E5%90%884.0(%E5%AE%8C%E5%85%A8%E7%89%88).json'\n }\n };\n\n // 版本比较函数\n function compareVersions(vs) {\n const normalize = (v) => {\n return v.split('.').map(n => {\n const num = parseInt(n, 10);\n return isNaN(num) ? 0 : num;\n });\n };\n\n const parts1 = normalize(localVer);\n const parts2 = normalize(vs);\n const maxLength = Math.max(parts1.length, parts2.length);\n \n for (let i = 0; i < maxLength; i++) {\n const num1 = parts1[i] || 0;\n const num2 = parts2[i] || 0;\n if (num1 > num2) return 1;\n if (num1 < num2) return -1;\n }\n return 0;\n }\n\n async function fetchVersionData() {\n // 使用统一配置中除主线路外的备用线路进行版本检查\n const serversToCheck = Object.values(serverConfig).filter(s => s.baseUrl.includes('czyl.cf') || s.baseUrl.includes('langge.tk') || s.baseUrl.includes('langge.cf') || s.baseUrl.includes('219.154'));\n \n for (const server of serversToCheck) {\n try {\n const response = await fetch(server.baseUrl + '/version', { timeout: 2000 });\n if (response.ok) {\n return await response.json();\n }\n } catch (e) {\n console.warn(\\`接口失败:\\${server.baseUrl}\\`, e);\n }\n }\n throw new Error('所有更新接口都请求失败');\n }\n\n function showError(message) {\n loading.innerHTML = \\`\n <div class=\"error-state\">\n <div class=\"error-icon\"><i class=\"fas fa-exclamation-triangle\"></i></div>\n <div class=\"error-text\">\\${message}</div>\n <button class=\"retry-button\" onclick=\"location.reload()\"><i class=\"fas fa-redo\"></i> 重试</button>\n </div>\n \\`;\n }\n\n try {\n const data = await fetchVersionData();\n const cloudVersion = String(data.version3);\n const updateLog = data.update_log || {};\n\n // 显示版本信息\n currentVersion.textContent = \\`v\\${localVer}\\`;\n latestVersion.textContent = \\`v\\${cloudVersion}\\`;\n\n // 处理日志\n const logEntries = Object.entries(updateLog);\n if (logEntries.length > 0) {\n // 显示最新日志\n const [latestDate, latestContent] = logEntries[0];\n latestLogDate.innerHTML = \\`<i class=\"fas fa-calendar-alt\"></i> \\${latestDate}\\`;\n latestLogContent.textContent = latestContent;\n latestLogContainer.style.display = 'block';\n\n // 显示历史日志\n if (logEntries.length > 1) {\n const historyLogs = logEntries.slice(1);\n historyCount.textContent = \\`(\\${historyLogs.length}条)\\`;\n logList.innerHTML = historyLogs.map(([date, content]) => \\`\n <div class=\"history-item\">\n <div class=\"history-date\">\n <i class=\"fas fa-calendar-day\"></i>\n <span>\\${date}</span>\n </div>\n <div class=\"history-text\">\\${content}</div>\n </div>\n \\`).join('');\n logsContainer.style.display = 'block';\n }\n }\n\n // 检查更新状态\n const compareResult = compareVersions(cloudVersion);\n \n // 显示版本指示器\n versionIndicator.style.display = 'flex';\n \n if (compareResult === -1) {\n // 需要更新\n currentStatus.textContent = '待更新';\n currentStatus.className = 'version-status status-outdated';\n versionIndicator.className = 'version-indicator update-needed';\n versionIndicator.innerHTML = '<i class=\"fas fa-arrow-right\"></i>';\n\n // 使用统一配置生成下载按钮\n buttonGroup.innerHTML = Object.values(serverConfig).map(server => {\n const fullUrl = server.baseUrl + server.downloadPath;\n return \\`\n <a href=\"yuedu://booksource/importonline?src=\\${encodeURIComponent(fullUrl)}\" class=\"button\">\n <i class=\"fas fa-\\${server.icon}\"></i>\n <span>\\${server.name}</span>\n </a>\n \\`;\n }).join('');\n buttonGroup.style.display = 'flex';\n } else {\n // 已是最新版本\n currentStatus.textContent = '最新';\n currentStatus.className = 'version-status status-latest';\n versionIndicator.className = 'version-indicator is-latest';\n versionIndicator.innerHTML = '<i class=\"fas fa-check\"></i>';\n \n statusAlert.className = 'status-alert up-to-date';\n statusAlert.innerHTML = '<i class=\"fas fa-check-circle\"></i> <div>您已是最新版本</div>';\n statusAlert.style.display = 'flex';\n }\n\n // 显示主容器,隐藏加载\n loading.style.display = 'none';\n container.style.display = 'block';\n\n } catch (err) {\n console.error('版本检查失败:', err);\n showError('<i class=\"fas fa-exclamation-circle\"></i> 检查更新失败,请稍后重试<br><small>' + err.message + '</small>');\n }\n })();\n </script>\n</body>\n</html>\n`;\n java.startBrowser(`data:text/html;base64,${java.base64Encode(html)}`, '大灰狼书源更新');\n}",
|
||
"respondTime": 180000,
|
||
"ruleBookInfo": {
|
||
"author": "$.author",
|
||
"canReName": "1",
|
||
"coverUrl": "$.thumb_url",
|
||
"init": "<js>\nif (String(baseUrl).startsWith(\"data:\")) {\n let res = JSON.parse(java.hexDecodeToString(result));\n let book_id = res.book_id;\n let tab = res.tab;\n let sources = res.sources;\n let url = res.url;\n let html = \"\";\n let proxy = getArguments(source.getVariable(), \"proxy\");\n if (url != \"\" && proxy == \"本地\") {\n if (sources == '69书吧') {\n let ck69 = String(cookie.getCookie(url));\n let headers = {\n \"Cookie\": ck69\n };\n let op = JSON.stringify({\n \"headers\": headers\n });\n html = java.ajax(url + ',' + op);\n } else {\n html = java.ajax(url);\n }\n //java.log(html);\n if (html.includes(\"Just a moment...\") && sources == '69书吧') {\n cookie.removeCookie(url);\n var x = `https://www.69shuba.com`;\n java.longToast('需要真人验证,请进入任意书籍详情页过验证');\n var s = java.startBrowserAwait(x, \"需要真人验证,请进入任意书籍详情页过验证\").body();\n\n let ck69 = String(cookie.getCookie(url));\n let headers = {\n \"Cookie\": ck69\n };\n let op = JSON.stringify({\n \"headers\": headers\n });\n java.log(op);\n html = java.ajax(url + ',' + op);\n //java.log(html);\n }\n }\n let base_url = getArguments(source.getVariable(), \"server\");\n let op = {\n method: \"POST\",\n body: {\n html: html\n }\n };\n op = JSON.stringify(op);\n let varia = String(book.getVariable('custom'));\n if (varia == 'null') {\n varia = '';\n }\n varia = JSON.stringify({\n 'custom': varia\n });\n //varia = java.base64Encode(varia);\n java.log(`${base_url}/detail?book_id=${book_id}&source=${sources}&tab=${tab}&variable=${varia},${op}`);\n result = java.ajax(`${base_url}/detail?book_id=${book_id}&source=${sources}&tab=${tab}&variable=${varia},${op}`);\n}\nresult\n</js>$.data",
|
||
"intro": "<js>\nlet {\n book_id,\n source: sources,\n tab,\n book_tts,\n tags,\n role,\n last_chapter_title,\n last_chapter_update_time,\n word_number,\n status,\n score,\n abstract,\n copyright_info\n} = result;\nlet proxy = getArguments(source.getVariable(), \"proxy\");\nif (proxy == \"本地\") {\n proxy = \"本地网络\";\n} else {\n proxy = \"服务器网络\";\n}\njava.put(\"book_detail\", JSON.stringify(result));\n\nlet base_url = getArguments(source.getVariable(), \"server\");\nlet key = \"\";\ntry {\n let cookieValue =\n String(cookie.getCookie(base_url)) || String(java.getCookie(base_url));\n key = getKey(cookieValue);\n} catch (e) {\n key = \"\";\n}\n\nif (key == \"\") {\n java.log(\"当前服务器未查询到登录状态,尝试查询其他服务器登录状态...\");\n let cookieValue;\n for (let h of host) {\n try {\n cookieValue = String(cookie.getCookie(h)) || String(java.getCookie(h));\n key = getKey(cookieValue);\n } catch (e) {\n key = \"\";\n }\n if (key) {\n java.log(`已在${h}登录,退出查询,正在转移登录状态到当前服务${base_url}`);\n //java.log(cookieValue)\n cookie.removeCookie(h);\n cookie.removeCookie(base_url);\n cookie.setCookie(base_url, cookieValue);\n break;\n }\n }\n}\n\nif (book.readConfig == null || book.readConfig.useReplaceRule == null) {\n book.setUseReplaceRule(false);\n}\n\nlet nickname = '账号状态:⚠️ 未登录 | 点击右上角 🔖 登录';\ntry {\n let opcx = {\n method: \"GET\",\n headers: {\n cookie: 'qttoken=' + key + ';'\n },\n };\n opcx = JSON.stringify(opcx);\n let user_info = JSON.parse(java.ajax(base_url + '/get_avatar,' + opcx));\n if (user_info.code == 0) {\n if (user_info.nickname) {\n nickname = '欢迎回来:' + user_info.nickname\n } else {\n nickname = '欢迎回来:' + user_info.email + \"(请前往用户后台设置用户名)\"\n }\n }\n} catch (e) {\n if (key) {\n nickname = '账号状态:已登录'\n }\n};\n\nlet loginStatus = nickname;\n\nlet lightDivider = \"❇️───────❇️───────❇️\";\nlet heavyDivider = \"‎\\n‎\";\n\nlet isValid = (value) => String(value).length > 1;\n\nlet info = `\n 📡 当前服务:${base_url}\n 🔑 ${loginStatus}\n 🏷 数据来源:${sources}\n 🔄 当前模式:${tab}\n ⚙️ 访问模式:${proxy}\n`;\n\nif (tab == \"听书\") {\n let toneId = getArguments(source.getVariable(), \"tone_id\");\n if (isValid(book_tts)) {\n info += `${lightDivider}\n 🎵 音色配置:${toneId}\n ${book_tts}\n`;\n }\n}\n\nlet basicInfo = \"\";\nlet addBasicInfo = (value, prefix, icon) => {\n if (isValid(value)) basicInfo += ` ${icon} ${prefix} ${value}\\n`;\n};\n\naddBasicInfo(tags, \"书籍分类:\", \"🌈\");\naddBasicInfo(role, \"书籍主角:\", \"👑\");\naddBasicInfo(last_chapter_title, \"最新章节:\", \"📚\");\naddBasicInfo(last_chapter_update_time, \"更新时间:\", \"⏳\");\naddBasicInfo(word_number, \"书籍字数:\", \"📊\");\naddBasicInfo(status, \"书籍状态:\", \"🚩\");\naddBasicInfo(score, \"书籍评分:\", \"⭐\");\n\nif (basicInfo) info += `${lightDivider}\\n${basicInfo}`;\n\nif (isValid(abstract)) {\n let indentedAbstract = abstract\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n info += `${heavyDivider}\n 📖 书籍简介:\n${indentedAbstract}\n`;\n} else {\n info += `${heavyDivider}`;\n}\n\nif (isValid(copyright_info)) {\n info += `${lightDivider}\n © ${copyright_info}\n`;\n} else {\n info += `${lightDivider}`;\n}\n\ninfo += `\n${heavyDivider}\n 💠💠💠 数据更新于 ${new Date().toLocaleString()} 💠💠💠\n`;\nlet jjinfo = getArguments(source.getVariable(), \"info\");\n\nif (jjinfo != \"on\") {\n info = String(info)\n .split(\"\\n\")\n .map((line) => line.replace(/^ {4}/, \"\"))\n .join(\"\\n\");\n} else {\n basicInfo = \"\";\n addBasicInfo(last_chapter_title, \"最新章节:\", \"📚\");\n addBasicInfo(last_chapter_update_time, \"更新时间:\", \"⏳\");\n addBasicInfo(word_number, \"书籍字数:\", \"📊\");\n addBasicInfo(status, \"书籍状态:\", \"🚩\");\n addBasicInfo(score, \"书籍评分:\", \"⭐\");\n if (isValid(abstract)) {\n let indentedAbstract = abstract\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n basicInfo += `\n \\n‎\n 📖 书籍简介:\n${indentedAbstract}\n`;\n } else {\n basicInfo += `${heavyDivider}`;\n }\n info = `‎\\n🏷 数据来源:${sources}\\n` + basicInfo;\n}\n</js>",
|
||
"lastChapter": "{{$.source}} {{$.last_chapter_title}} {{$.last_chapter_update_time}}",
|
||
"name": "$.book_name",
|
||
"tocUrl": "<js>\nlet book_id = result.book_id;\nlet sources = result.source;\nlet tab = result.tab || \"小说\";\nlet url = result.toc_url || \"\";\nvar sdtoken;\ntry {\n var loginInfoMap = source.getLoginInfoMap ? source.getLoginInfoMap() : {};\n sdtoken = String(loginInfoMap['手动填写番茄token(可不填)'] || '');\n} catch (e) {\n sdtoken = '';\n}\nvar rawCookie = getFanqieCookie() || sdtoken;\nvar match = rawCookie.match(/sessionid=[^;]+/);\nvar fqcookie = match ? match[0] : '';\nvar fqssionid = '';\nif (fqcookie) {\n fqssionid = getSessionId(fqcookie);\n};\nsetArguments('fqssionid', fqssionid);\njava.put(\"tab\", tab);\njava.put(\"book_id\", book_id);\nlet qtcatalog = {\n book_id: book_id,\n sources: sources,\n tab: tab,\n url: url,\n};\nqtcatalog = java.base64Encode(JSON.stringify(qtcatalog));\n`data:;base64,${qtcatalog},{\"type\":\"qingtian2\"}`;\n</js>",
|
||
"wordCount": "$.word_number"
|
||
},
|
||
"ruleContent": {
|
||
"content": "<js>\nresult = String(java.hexDecodeToString(result));\nlet res;\nif (result.match(/大灰狼融合/)) {\n result = result.split(\"大灰狼融合4\");\n res = {\n item_id: result[0],\n tab: result[1],\n title: result[2],\n sources: result[3],\n url: \"\"\n };\n} else {\n res = JSON.parse(result);\n}\nlet varia = String(book.getVariable('custom'));\nif (varia == 'null') {\n varia = '';\n}\nvaria = JSON.stringify({\n 'custom': varia\n});\n// varia = java.base64Encode(varia);\nlet book_id = res.book_id;\nlet item_id = res.item_id;\nlet tab = res.tab;\nlet title = res.title;\nlet sources = res.sources;\nlet url = res.url;\nlet html = \"\";\nlet proxy = getArguments(source.getVariable(), \"proxy\");\nif (url != \"\" && proxy == \"本地\") {\n if (sources == '69书吧') {\n let ck69 = String(cookie.getCookie(url));\n let headers = {\n \"Cookie\": ck69,\n \"User-Agent\": \"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36 Edg/138.0.0.0\"\n };\n let op = JSON.stringify({\n \"headers\": headers\n });\n java.log(url);\n java.log(op);\n html = java.ajax(url + ',' + op);\n } else {\n html = java.ajax(url);\n }\n java.log(html);\n if (html.includes(\"Just a moment...\") && sources == '69书吧' && book.durChapterIndex === chapter.index) {\n cookie.removeCookie(url);\n var x = url;\n java.longToast('需要真人验证,请进入任意书籍详情页过验证');\n var s = java.startBrowserAwait(x, \"需要真人验证,请进入任意书籍详情页过验证\").body();\n\n let ck69 = String(cookie.getCookie(url));\n let headers = {\n \"User-Agent\": \"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36 Edg/138.0.0.0\",\n \"Cookie\": ck69\n };\n let op = JSON.stringify({\n \"headers\": headers\n });\n java.log(op);\n html = java.ajax(url + ',' + op);\n //java.log(html);\n }\n};\nlet content = \"\";\nlet data;\nlet tone_id = getArguments(source.getVariable(), \"tone_id\");\nlet base_url = getArguments(source.getVariable(), \"server\");\nlet device, device_type;\ntry {\n device = java.deviceID();\n device_type = \"苹果\";\n} catch (e) {\n try {\n device = java.androidId();\n device_type = \"安卓\";\n } catch (e) {\n device = \"\";\n device_type = \"安卓\";\n }\n}\n\nlet qtcookie = cookie.getCookie(base_url);\ntry {\n qtcookie = `qttoken=${String(cookie.getKey(base_url, \"qttoken\"))}; deviceId=${device};`\n} catch (e) {}\n\nvar params = {\n html: html,\n item_id: item_id,\n source: sources,\n tab: tab,\n tone_id: tone_id,\n variable: varia,\n version: '4.11.5.1'\n};\n\nvar content_url = '/content';\n\nif ((sources == \"番茄\" || sources == \"七猫\" || sources == \"塔读\") && getArguments(source.getVariable(), \"fqpara\") == \"on\" && tab == \"小说\") {\n content_url = '/content?review=1';\n}\n\n//var signInfo = generateComplexSignature('POST', content_url, {}, APP_SECRET, params);\n\n\n//var signedParams = copyObject(params);\n//signedParams.timestamp = signInfo.timestamp;\n//signedParams.nonce = signInfo.nonce;\n//signedParams.sign = signInfo.sign;\n\n\nvar op = {\n method: \"POST\",\n body: JSON.stringify(params),\n headers: {\n cookie: qtcookie,\n 'Content-Type': 'application/json'\n }\n};\n\nop = JSON.stringify(op);\njava.log(op);\ndata = java.ajax(base_url + content_url + `,${op}`);\n\ntry {\n data = JSON.parse(data);\n if (data.msg) {\n java.toast(data.msg);\n }\n} catch (e) {}\n\ncontent = data.content\n\nif ((sources == \"番茄\" || sources == \"七猫\" || sources == \"塔读\") && getArguments(source.getVariable(), \"fqpara\") == \"on\" && tab == \"小说\") {\n var fqssionid = getArguments(source.getVariable(), \"fqssionid\") || \"\";\n content = content\n .replace(/ident=\"/g, 'ident=\"' + base_url)\n .replace(/book_id=/g, 'book_id=' + book_id + '&ssionid=' + fqssionid);\n if (device_type == \"苹果\") {\n content = paraForiOS(content, sources);\n } else {\n content = paraForAndroid(content, sources);\n }\n\n\n}\ndata = JSON.stringify({\n content: content,\n});\n\nif (device_type == \"安卓\" && (tab == \"短剧\" || tab == \"视频\" || sources == '毒舌影视')) {\n data = {\n content: `【右上角刷新】开启播放(下一集请切换下一章刷新)\\n播放直链:\\n${content}`,\n };\n data = JSON.stringify(data);\n if (book.durChapterIndex === chapter.index) {\n let video_url = `${base_url}/online_video?book_id=${book_id}&source=${sources}&tab=${tab}`;\n if (sources == '毒舌影视') {\n video_url = content;\n };\n java.startBrowser(video_url, title);\n java.toast(\"正在加载视频...\");\n }\n\n}\ndata;\n</js>$.content",
|
||
"imageStyle": "TEXT"
|
||
},
|
||
"ruleExplore": {
|
||
"author": "$.author",
|
||
"bookList": "$.data",
|
||
"bookUrl": "<js>\nlet book_id = result.book_id;\nlet sources = result.source;\nlet tab = result.tab || '小说';\nlet url = result.toc_url || '';\n\nlet qtdetail = {\n book_id: book_id,\n sources: sources,\n tab: tab,\n url: url\n}\nqtdetail = java.base64Encode(JSON.stringify(qtdetail));\n`data:;base64,${qtdetail},{\"type\":\"qingtian\"}`\n</js>",
|
||
"coverUrl": "$.thumb_url",
|
||
"intro": "$.abstract",
|
||
"kind": "{{$.category}}\n{{$.score}}\n{{$.status}}\n{{$.source}}\n{{$.tags}}",
|
||
"lastChapter": "{{$.last_chapter_title}} • {{$.last_update_time}}",
|
||
"name": "$.book_name",
|
||
"wordCount": "$.word_number"
|
||
},
|
||
"ruleSearch": {
|
||
"author": "$.author",
|
||
"bookList": "$.data",
|
||
"bookUrl": "<js>\nlet book_id = result.book_id;\nlet sources = result.source;\nlet tab = result.tab || '小说';\nlet url = result.toc_url || '';\n\nlet qtdetail = {\n book_id: book_id,\n sources: sources,\n tab: tab,\n url: url\n}\nqtdetail = java.base64Encode(JSON.stringify(qtdetail));\n`data:;base64,${qtdetail},{\"type\":\"qingtian\"}`\n</js>",
|
||
"checkKeyWord": "我的26岁女房客@番茄",
|
||
"coverUrl": "$.thumb_url",
|
||
"intro": "$.abstract",
|
||
"kind": "{{$.status}},{{$.score}},{{$.tags}},{{$.last_chapter_update_time}}",
|
||
"lastChapter": "{{$.source}} {{$.last_chapter_title}}",
|
||
"name": "$.book_name##(别名:.*?)",
|
||
"wordCount": "$.word_number"
|
||
},
|
||
"ruleToc": {
|
||
"chapterList": "<js>\nlet res = JSON.parse(java.hexDecodeToString(result));\nif (res.method) {\n res = Object.fromEntries(\n res.body\n .replace(\"source\", \"sources\")\n .split(\"&\")\n .map((query) => query.split(\"=\"))\n );\n res.url = \"\";\n}\nlet book_id = res.book_id;\njava.put('book_id', book_id);\nlet tab = res.tab;\nlet sources = res.sources;\nlet url = res.url;\nlet html = \"\";\nlet proxy = getArguments(source.getVariable(), \"proxy\");\nif (url != \"\" && proxy == \"本地\") {\n if (sources == '69书吧') {\n let ck69 = String(cookie.getCookie(url));\n let headers = {\n \"Cookie\": ck69\n };\n let op = JSON.stringify({\n \"headers\": headers\n });\n html = java.ajax(url + ',' + op);\n } else {\n html = java.ajax(url);\n }\n //java.log(html);\n if (html.includes(\"Just a moment...\") && sources == '69书吧') {\n cookie.removeCookie(url);\n var x = `https://www.69shuba.com`;\n java.longToast('需要真人验证,请进入任意书籍详情页过验证');\n var s = java.startBrowserAwait(x, \"需要真人验证,请进入任意书籍详情页过验证\").body();\n\n let ck69 = String(cookie.getCookie(url));\n let headers = {\n \"Cookie\": ck69\n };\n let op = JSON.stringify({\n \"headers\": headers\n });\n //java.log(op);\n html = java.ajax(url + ',' + op);\n //java.log(html);\n }\n};\nlet base_url = getArguments(source.getVariable(), \"server\");\nlet op = {\n method: \"POST\",\n body: {\n html: html\n }\n};\nop = JSON.stringify(op);\nlet varia = String(book.getVariable('custom'));\nif (varia == 'null') {\n varia = '';\n}\nvaria = JSON.stringify({\n 'custom': varia\n});\n// varia = java.base64Encode(varia);\n//java.log(`${base_url}/catalog?book_id=${book_id}&source=${sources}&tab=${tab}&variable=${varia},${op}`);\nlet data = java.ajax(\n `${base_url}/catalog?book_id=${book_id}&source=${sources}&tab=${tab}&variable=${varia},${op}`\n);\nlet device, device_type;\ntry {\n device = java.deviceID();\n device_type = \"苹果\";\n} catch (e) {\n try {\n device = java.androidId();\n device_type = \"安卓\";\n } catch (e) {\n device = \"\";\n device_type = \"安卓\";\n }\n}\n\nif (tab == \"小说\") {\n if (device_type == \"安卓\") {\n book.type = 8;\n } else {\n book.type = 0;\n }\n} else if (tab == \"听书\") {\n if (device_type == \"安卓\") {\n book.type = 32;\n } else {\n book.type = 1;\n }\n} else if (tab == \"漫画\") {\n if (device_type == \"安卓\") {\n book.type = 64;\n } else {\n book.type = 2;\n }\n} else if (tab == \"短剧\") {\n if (device_type == \"安卓\") {\n book.type = 8;\n } else {\n book.type = 3;\n }\n} else {\n if (device_type == \"安卓\") {\n book.type = 8;\n } else {\n book.type = 0;\n }\n}\ndata;\n</js>$.data",
|
||
"chapterName": "$.title",
|
||
"chapterUrl": "<js>\nlet tab = result.tab;\nlet sources = result.source;\nlet title = result.title;\nlet item_id = result.item_id;\nlet book_id = java.get(\"book_id\");\nlet url = result.toc_url || \"\";\nlet qtcontent = {\n book_id: book_id,\n item_id: item_id,\n title: title,\n sources: sources,\n tab: tab,\n url: url,\n};\nqtcontent = java.base64Encode(JSON.stringify(qtcontent));\nif (sources == '卷') {\n content_url = item_id\n} else if ((sources == \"番茄\" || sources == \"七猫\" || sources == \"塔读\") && tab == \"小说\") {\n var base_url = getArguments(source.getVariable(), \"server\") || \"\";\n var fqssionid = getArguments(source.getVariable(), \"fqssionid\") || \"\";\n let sourcess = sources.replace('svip_', '');\n content_url = `data:;base64,${qtcontent},{\"type\":\"qingtian3\",\"js\":\"book ? result : '${base_url}/get_review?book_id=${book_id}&item_id=${item_id}&ssionid=${fqssionid}&source=${sourcess}'\"}`;\n} else {\n content_url = `data:;base64,${qtcontent},{\"type\":\"qingtian3\"}`;\n}\n</js>",
|
||
"updateTime": "$.first_pass_time"
|
||
},
|
||
"searchUrl": "<js>\nlet base_url = getArguments(source.getVariable(), 'server');\nlet media;\nlet sources = getArguments(source.getVariable(), 'source');\nif (String(key).startsWith(\"m:\") || String(key).startsWith(\"m:\")) {\n media = \"漫画\"\n key = key.slice(2)\n} else if (String(key).startsWith(\"t:\") || String(key).startsWith(\"t:\")) {\n media = \"听书\"\n key = key.slice(2)\n} else if (String(key).startsWith(\"d:\") || String(key).startsWith(\"d:\")) {\n media = \"短剧\"\n key = key.slice(2)\n} else if (String(key).startsWith(\"x:\") || String(key).startsWith(\"x:\")) {\n media = \"小说\"\n key = key.slice(2)\n} else {\n media = getArguments(source.getVariable(), 'media');\n}\nif (key.includes('@')) {\n var parts = key.split('@');\n key = parts[0];\n sources = parts[1] || sources;\n}\nlet qtcookie = cookie.getCookie(base_url);\nlet op = {\n method: \"GET\",\n headers: {\n cookie: qtcookie\n },\n};\nop = JSON.stringify(op);\n`${base_url}/search?title=${key}&tab=${media}&source=${sources}&page={{page}},${op}`\n</js>",
|
||
"weight": 0
|
||
},
|
||
{
|
||
"bookSourceComment": "00shu小说网书源,编码GBK,适配章节/搜索/详情解析",
|
||
"bookSourceGroup": "CSS; 正则",
|
||
"bookSourceName": "00shu小说",
|
||
"bookSourceType": 0,
|
||
"bookSourceUrl": "https://www.00shu.la",
|
||
"bookUrlPattern": "",
|
||
"customOrder": 0,
|
||
"enabled": true,
|
||
"enabledExplore": false,
|
||
"exploreUrl": "",
|
||
"lastUpdateTime": "1764478609406",
|
||
"loginUrl": "",
|
||
"ruleBookInfo": {
|
||
"author": "##:author\"[^\"]+\"([^\"]*)##$1###",
|
||
"coverUrl": "##og:image\"[^\"]+\"([^\"]*)##$1###",
|
||
"intro": "##:description\"[^\"]+\"([\\w\\W]*?)\"/##$1###",
|
||
"kind": "##:category\"[^\"]+\"([^\"]*)##$1###",
|
||
"lastChapter": "##_chapter_name\"[^\"]+\"([^\"]*)##$1###",
|
||
"name": "##:book_name\"[^\"]+\"([^\"]*)##$1###",
|
||
"tocUrl": ""
|
||
},
|
||
"ruleContent": {
|
||
"content": "@css:#content p@textNodes##广告|弹窗|手机阅读|记住网址|<!\\[CDATA\\[|\\]\\]>",
|
||
"nextContentUrl": ""
|
||
},
|
||
"ruleExplore": [],
|
||
"ruleSearch": {
|
||
"author": "@css:.s2>a@text",
|
||
"bookList": "@css:div.result-list>ul>li",
|
||
"bookUrl": "@css:.s1>a@href",
|
||
"coverUrl": "@css:.s3>img@src",
|
||
"intro": "@css:.s4@text",
|
||
"kind": "@css:.s5@text",
|
||
"lastChapter": "@css:.s6@text",
|
||
"name": "@css:.s1>a@text"
|
||
},
|
||
"ruleToc": {
|
||
"chapterList": "-:<li><a[^\"]+\"([^\"]*)\">([^<]*)",
|
||
"chapterName": "$2",
|
||
"chapterUrl": "$1",
|
||
"nextTocUrl": ""
|
||
},
|
||
"searchUrl": "/search.aspx?key={{key}}&page={{page}},{\"charset\": \"gbk\"}",
|
||
"weight": 0
|
||
},
|
||
{
|
||
"bookSourceComment": "",
|
||
"bookSourceName": "22笔趣阁(pc)",
|
||
"bookSourceType": 0,
|
||
"bookSourceUrl": "https://www.22biqu.com",
|
||
"customOrder": 0,
|
||
"enabled": true,
|
||
"enabledCookieJar": true,
|
||
"enabledExplore": true,
|
||
"exploreUrl": "[\n{\n \"title\": \"♕ 分类 ♕\",\n \"url\": \"\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 1\n }\n },\n {\n \"title\": \"玄幻魔法\",\n \"url\": \"/fenlei/1_{{page}}.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"武侠修真\",\n \"url\": \"/fenlei/2_{{page}}.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"都市言情\",\n \"url\": \"/fenlei/3_{{page}}.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"历史军事\",\n \"url\": \"/fenlei/4_{{page}}.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"科幻灵异\",\n \"url\": \"/fenlei/6_{{page}}.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"游戏竞技\",\n \"url\": \"/fenlei/5_{{page}}.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"女生耽美\",\n \"url\": \"/fenlei/7_{{page}}.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"其他类型\",\n \"url\": \"/fenlei/8_{{page}}.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"♕ 排行榜 ♕\",\n \"url\": \"\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 1\n }\n },\n {\n \"title\": \"总排行榜\",\n \"url\": \"/rank/allvisit/\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"月排行榜\",\n \"url\": \"/rank/monthvisit/\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"周排行榜\",\n \"url\": \"/rank/weekvisit/\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"收 藏 榜\",\n \"url\": \"/rank/goodnum/\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"♕ 全本 ♕\",\n \"url\": \"\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 1\n }\n },\n {\n \"title\": \"玄幻魔法\",\n \"url\": \"/quanben/fenlei/1_{{page}}.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"武侠修真\",\n \"url\": \"/quanben/fenlei/2_{{page}}.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"都市言情\",\n \"url\": \"/quanben/fenlei/3_{{page}}.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"历史军事\",\n \"url\": \"/quanben/fenlei/4_{{page}}.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"科幻灵异\",\n \"url\": \"/quanben/fenlei/6_{{page}}.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"游戏竞技\",\n \"url\": \"/quanben/fenlei/5_{{page}}.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"女生耽美\",\n \"url\": \"/quanben/fenlei/7_{{page}}.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"title\": \"其他类型\",\n \"url\": \"/quanben/fenlei/8_{{page}}.html\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n }\n]",
|
||
"header": "{\n \"User-Agent\": \"Mozilla/5.0 (Linux; Android 8.0.0; MI 5s Plus Build/OPR1.170623.032; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36\"\n}",
|
||
"lastUpdateTime": 1764641625153,
|
||
"respondTime": 180000,
|
||
"ruleBookInfo": {
|
||
"author": "[property=\"og:novel:author\"]@content",
|
||
"coverUrl": "[property=\"og:image\"]@content",
|
||
"intro": "[property=\"og:description\"]@content",
|
||
"kind": "[property~=category|status|update_time]@content",
|
||
"lastChapter": "[property~=las?test_chapter_name]@content",
|
||
"name": "[property=\"og:novel:book_name\"]@content",
|
||
"tocUrl": ""
|
||
},
|
||
"ruleContent": {
|
||
"content": "#content@p@html##本章未完.*",
|
||
"nextContentUrl": "text.下一页@href"
|
||
},
|
||
"ruleExplore": {
|
||
"author": ".author@text##作者:|(\\d.*)",
|
||
"bookList": ".hot_sale",
|
||
"bookUrl": "a@href",
|
||
"coverUrl": "a.0@href##.+\\D((\\d+)\\d{3})\\D##https://img.22biqu.com/$2/$1/$1s.jpg###",
|
||
"intro": ".review@text",
|
||
"name": ".title@text##^\\d+\\."
|
||
},
|
||
"ruleSearch": {
|
||
"author": ".s4@text",
|
||
"bookList": ".txt-list.txt-list-row5 > li:not(:first-child)",
|
||
"bookUrl": "a.0@href",
|
||
"coverUrl": "",
|
||
"kind": ".s1@text",
|
||
"lastChapter": ".s3@text",
|
||
"name": ".s2@text",
|
||
"checkKeyWord": "系统"
|
||
},
|
||
"ruleToc": {
|
||
"chapterList": "class.section-list fix@li@a",
|
||
"chapterName": "text",
|
||
"chapterUrl": "href",
|
||
"nextTocUrl": "option@value"
|
||
},
|
||
"searchUrl": "{{cookie.removeCookie(source.key)}}/ss/,{\n \"body\": \"searchkey={{key}}&submit=搜索\",\n \"method\": \"POST\"\n}",
|
||
"weight": 0
|
||
}
|
||
] |