🍅大灰狼融合3.6.15(完全版)
https://api.doubi.tk
大灰狼 (3463)5天前
阅读app,源阅
{ "bookSourceComment": "更新日志请点击登录,更新书源中查看", "bookSourceGroup": "大灰狼聚合", "bookSourceName": "🍅大灰狼融合3.6.15(完全版)", "bookSourceType": 0, "bookSourceUrl": "https:\/\/api.doubi.tk", "customOrder": 2, "enabled": true, "enabledCookieJar": true, "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\nfunction getFanqieCookie() {\n try {\n return String(cookie.getCookie('fanqienovel.com') || java.getCookie('fanqienovel.com') || '');\n } catch (e) {\n return '';\n }\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 ? encodeURIComponent(match[0]) : '';\nif (!fqcookie) {\n java.toast('您还未登陆番茄账号,无法同步数据哦!');\n }\nvar fqsjurl = base_url + \"\/bookshelf?page={{page}}&cookie=\" + fqcookie;\n\nvar groupDatas = [];\nvar infoData = [];\n\nfunction deviceType() {\n try {\n return !!java.androidId();\n } catch (e) {\n return false;\n }\n}\n\nvar device = deviceType() ? 'android' : 'ios';\nvar hasValidCookie = fqcookie.length > 0;\n\nif (device === 'android' && hasValidCookie) {\n function groupQuery() {\n try {\n var url = base_url + \"\/group_name?cookie=\" + fqcookie;\n var res = java.ajax(url);\n var response = JSON.parse(res);\n \n if (!(response && response.data)) {\n }\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 \tvar option = {\r\n \"method\": \"POST\" ,\r\n \"body\": {\"book_ids\":value,\n \"page\":\"{{page}}\"}\n };\r\n groupDatas.push({\n title: key,\n url: base_url + \"\/bookshelf3,\" + 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(\"分组获取失败: \" + e.message);\n }\n }\n\n try {\n java.longToast(\"正在加载分组数据...\");\n var sessionid = match ? match[0] : '';\n var userUrl = base_url + \"\/fquser?\" + sessionid;\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 infoData = [{\n title: userName + \"个人中心\",\n url: fqsjurl,\n style: {\n layout_flexGrow: 1,\n layout_flexBasisPercent: 1\n }\n }];\n \n groupQuery();\n } catch (e) {\n java.longToast(\"操作失败: \" + e.message);\n }\n}\n\nvar style_list = [];\ntry {\n var durl = `${base_url}\/discover_style?source=${sources}&source_type=${source_type}&tab=${tab}`;\n var res = java.ajax(durl);\n var result = JSON.parse(res);\n style_list = result.style_list || [];\n java.toast(result.msg);\n} catch (e) {\n java.toast(\"发现样式获取失败\");\n}\n\nvar finalData = infoData.concat(groupDatas, style_list);\nJSON.stringify(finalData);\n<\/js>", "jsLib": "const host = [\n'https:\/\/api.doubi.tk',\n'http:\/\/219.154.201.122:5006'\n]\n\nfunction getKey(key) {\n const parts = key.split(\";\");\n for (let part of parts) {\n if (part.includes(\"secretKey2\")) {\n return part.split(\"=\")[1];\n }\n }\n return \"\";\n}\n\nfunction getArguments(open_argument,key) {\n try {\n open_argument = JSON.parse(open_argument);\n } catch (e) {\n const serverList = host;\n open_argument = {\n \"media\": \"小说\",\n \"tone_id\": \"默认音色\",\n \"server\": serverList[0],\n \"source\":\"全部\"\n };\n }\n if (key) {return open_argument[key];} else {return open_argument}\n}\n\n\neval(function(p,a,c,k,e,r){e=function(c){return(c<62?'':e(parseInt(c\/62)))+((c=c%62)>35?String.fromCharCode(c+29):c.toString(36))};if('0'.replace(0,e)==0){while(c--)r[e(c)]=k[c];k=[function(e){return r[e]||e}];e=function(){return'[3-9abe-hl-oq-zA]'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('function decrypt(4){3 i=4.5-1;while(i>=0){3 c=4.l(i);m(c!==\\'\\\\n\\'&&c!==\\'\\\\u200c\\'&&c!==\\'\\\\o\\')break;i--}3 8=4.q(0,i+1);3 r=4.q(i+1);3 9=[];3 a=r.split(\\'\\\\o\\');6(3 p=0;p<a.5;p++){3 b=a[p];m(b.5!==s)continue;3 e=\\'\\';6(3 j=0;j<s;j++){3 t=b.l(j);e+=t===\\'\\\\n\\'?\\'0\\':\\'1\\'}9.u(v.w(parseInt(e,2)))}3 f=9.x(\\'\\');3 7=0;6(3 k=0;k<f.5;k++){7+=f.y(k)}7%=g;3 h=[];6(3 d=0;d<8.5;d++){3 z=8.y(d);3 A=(z-7+g)%g;h.u(v.w(A))}return h.x(\\'\\')}',[],37,'|||var|encryptedStr|length|for|shift|encryptedText|keyChars|parts|part|||binary|key|65536|decrypted||||charAt|if|u200b|u200d||substring|zwPart|16|bit|push|String|fromCharCode|join|charCodeAt|code|decryptedCode'.split('|'),0,{}))", "lastUpdateTime": "1750497056547", "loginUi": "[ {\n \"name\": \"♥♥ 登录大灰狼账号♥♥\",\n \"type\": \"button\",\n \"action\":\"loginqt()\"\n }, {\n \"name\": \"♻️ 更新书源\",\n \"type\": \"button\",\n \"action\": \"renderVersionPage()\"\n },{\n \"name\": \"🍅🍅🍅番茄登录🍅🍅🍅\",\n \"type\": \"button\",\n \"action\": \"fq_login()\"\n },{\n \"name\": \" 退出登录 \",\n \"type\": \"button\",\n \"action\": \"logout()\"\n },{\n \"name\": \" ♂男频 \",\n \"type\": \"button\",\n \"action\": \"set_source_type('男频')\"\n },{\n \"name\": \" ♀女频 \",\n \"type\": \"button\",\n \"action\": \"set_source_type('女频')\"\n },{\n \"name\": \"☕打赏享更多福利\",\n \"type\": \"button\",\n \"action\": \"vip()\"\n },{\n \"name\": \" ♻️检测服务器 \",\n \"type\": \"button\",\n \"action\": \"api()\"\n },{\n \"name\": \" 🎚切换服务器 \",\n \"type\": \"button\",\n \"action\": \"set_server(server)\"\n },{\n \"name\": \" 🖱当前服务器 \",\n \"type\": \"button\",\n \"action\": \"get_server()\"\n },{\n \"name\": \" 🗂当前模式 \",\n \"type\": \"button\",\n \"action\": \"get_media()\"\n },{\n \"name\": \" 📖小说模式 \",\n \"type\": \"button\",\n \"action\": \"set_media('小说')\"\n },{\n \"name\": \" 🔊听书模式 \",\n \"type\": \"button\",\n \"action\": \"set_media('听书')\"\n },{\n \"name\": \" 🏞漫画模式 \",\n \"type\": \"button\",\n \"action\": \"set_media('漫画')\"\n },{\n \"name\": \" 🖲短剧模式 \",\n \"type\": \"button\",\n \"action\": \"set_media('短剧')\"\n },{\n \"name\": \"听书Ai音色填写后点击右上角✔\",\n \"type\": \"text\"\n },{\n \"name\": \"自定义服务器(可不填)\",\n \"type\": \"text\"\n }, {\n \"name\": \"手动填写番茄token(可不填)\",\n \"type\": \"text\"\n }, {\n \"name\": \"书旗id(可不填)\",\n \"type\": \"text\"\n },{\n \"name\": \"↓↓下方可切换来源用于搜索\/发现页↓↓\",\n \"type\": \"button\",\n \"action\": \"get_media()\"\n }\n,{\n \"name\": \"全部\",\n \"type\": \"button\",\n \"action\": \"set_source('全部')\"\n },{\n \"name\": \"番茄\",\n \"type\": \"button\",\n \"action\": \"set_source('番茄')\"\n },{\n \"name\": \"七猫\",\n \"type\": \"button\",\n \"action\": \"set_source('七猫')\"\n },{\n \"name\": \"得间\",\n \"type\": \"button\",\n \"action\": \"set_source('得间')\"\n },{\n \"name\": \"书旗\",\n \"type\": \"button\",\n \"action\": \"set_source('书旗')\"\n },{\n \"name\": \"知乎(部分)\",\n \"type\": \"button\",\n \"action\": \"set_source('知乎')\"\n },{\n \"name\": \"QQ\",\n \"type\": \"button\",\n \"action\": \"set_source('QQ')\"\n },{\n \"name\": \"熊猫\",\n \"type\": \"button\",\n \"action\": \"set_source('熊猫')\"\n },{\n \"name\": \"塔读\",\n \"type\": \"button\",\n \"action\": \"set_source('塔读')\"\n },{\n \"name\": \"猫眼\",\n \"type\": \"button\",\n \"action\": \"set_source('猫眼')\"\n },{\n \"name\": \"米读\",\n \"type\": \"button\",\n \"action\": \"set_source('米读')\"\n },{\n \"name\": \"小米\",\n \"type\": \"button\",\n \"action\": \"set_source('小米')\"\n },{\n \"name\": \"百度\",\n \"type\": \"button\",\n \"action\": \"set_source('百度')\"\n },{\n \"name\": \"起点(部分)\",\n \"type\": \"button\",\n \"action\": \"set_source('起点')\"\n },{\n \"name\": \"69书吧\",\n \"type\": \"button\",\n \"action\": \"set_source('69书吧')\"\n },{\n \"name\": \"得奇\",\n \"type\": \"button\",\n \"action\": \"set_source('得奇')\"\n },{\n \"name\": \"搜书神器\",\n \"type\": \"button\",\n \"action\": \"set_source('搜书神器')\"\n },{\n \"name\": \"爱下电子书\",\n \"type\": \"button\",\n \"action\": \"set_source('爱下电子书')\"\n },{\n \"name\": \"笔趣阁\",\n \"type\": \"button\",\n \"action\": \"set_source('笔趣阁22')\"\n },{\n \"name\": \"星星小说\",\n \"type\": \"button\",\n \"action\": \"set_source('星星小说')\"\n },{\n \"name\": \"顶点\",\n \"type\": \"button\",\n \"action\": \"set_source('顶点')\"\n },{ \n \"name\": \"土豆小说网\",\n \"type\": \"button\",\n \"action\": \"set_source('土豆小说网')\"\n },{\n \"name\": \"速读谷\",\n \"type\": \"button\",\n \"action\": \"set_source('速读谷')\"\n },{\n \"name\": \"万相书城\",\n \"type\": \"button\",\n \"action\": \"set_source('万相书城')\"\n },{\n \"name\": \"九九读小说\",\n \"type\": \"button\",\n \"action\": \"set_source('九九读小说')\"\n },{\n \"name\": \"全本小说\",\n \"type\": \"button\",\n \"action\": \"set_source('全本小说')\"\n },{ \n \"name\": \"纵横中文网\",\n \"type\": \"button\",\n \"action\": \"set_source('纵横中文网')\"\n },{ \n \"name\": \"铅笔轻小说\",\n \"type\": \"button\",\n \"action\": \"set_source('铅笔轻小说')\"\n },{\n \"name\": \"轻小说文库\",\n \"type\": \"button\",\n \"action\": \"set_source('轻小说文库')\"\n },{ \n \"name\": \"漫画屋\",\n \"type\": \"button\",\n \"action\": \"set_source('漫画屋')\"\n },{ \n \"name\": \"沧元图\",\n \"type\": \"button\",\n \"action\": \"set_source('沧元图')\"\n },{\n \"name\": \"如漫画\",\n \"type\": \"button\",\n \"action\": \"set_source('如漫画')\"\n },{\n \"name\": \"全本同人\",\n \"type\": \"button\",\n \"action\": \"set_source('全本同人')\"\n },{ \n \"name\": \"SF轻小说\",\n \"type\": \"button\",\n \"action\": \"set_source('SF轻小说')\"\n },{ \n \"name\": \"阅读库\",\n \"type\": \"button\",\n \"action\": \"set_source('阅读库')\"\n },{ \n \"name\": \"骑士小说\",\n \"type\": \"button\",\n \"action\": \"set_source('骑士小说')\"\n },{ \t\n \"name\": \"飞书小说\",\r\n \"type\": \"button\",\r\n \"action\": \"set_source('飞书小说')\"\r\n },{\r\n \"name\": \"侠客中文网\",\r\n \"type\": \"button\",\r\n \"action\": \"set_source('侠客中文网')\"\r\n },{ \r\n \"name\": \"书荒小说网\",\r\n \"type\": \"button\",\r\n \"action\": \"set_source('书荒小说网')\"\r\n },{ \t\r\n \"name\": \"无忧小说网\",\r\n \"type\": \"button\",\r\n \"action\": \"set_source('无忧小说网')\"\r\n },{\r\n \"name\": \"情幻文学网\",\r\n \"type\": \"button\",\r\n \"action\": \"set_source('情幻文学网')\"\r\n },{ \r\n \"name\": \"乐看小说\",\r\n \"type\": \"button\",\r\n \"action\": \"set_source('乐看小说')\"\r\n },{ \r\n \"name\": \"轻之文库\",\r\n \"type\": \"button\",\r\n \"action\": \"set_source('轻之文库')\"\r\n },{ \r\n \"name\": \"潇湘书院\",\r\n \"type\": \"button\",\r\n \"action\": \"set_source('潇湘书院')\"\r\n },{ \r\n \"name\": \"QQ阅读\",\r\n \"type\": \"button\",\r\n \"action\": \"set_source('QQ阅读')\"\r\n },{ \r\n \"name\": \"星空小说\",\r\n \"type\": \"button\",\r\n \"action\": \"set_source('星空小说')\"\r\n },{ \r\n \"name\": \"小说三千\",\r\n \"type\": \"button\",\r\n \"action\": \"set_source('小说三千')\"\r\n },{ \r\n \"name\": \"飞速小说\",\r\n \"type\": \"button\",\r\n \"action\": \"set_source('飞速小说')\"\r\n },{ \r\n \"name\": \"漫画网\",\r\n \"type\": \"button\",\r\n \"action\": \"set_source('漫画网')\"\r\n },{\n \"name\": \"酷我听书\",\n \"type\": \"button\",\n \"action\": \"set_source('酷我听书')\"\n },{ \t \t \t\n \"name\": \"海洋听书\",\n \"type\": \"button\",\n \"action\": \"set_source('海洋听书')\"\n },{ \t\n \"name\": \"喜马拉雅\",\n \"type\": \"button\",\n \"action\": \"set_source('喜马拉雅')\"\n },{\n \"name\": \"毒舌影视\",\n \"type\": \"button\",\n \"action\": \"set_source('毒舌影视')\"\n },{\n \"name\": \"歪瑞古德漫画\",\n \"type\": \"button\",\n \"action\": \"set_source('歪瑞古德')\"\n }]", "loginUrl": "\/\/ 当前书源版本号,切勿修改,否则影响更新的识别\nconst localVersion = '3.6.15';\n\n\nfunction login() {\n let zdyserver;\n try {\n zdyserver = String(source.getLoginInfoMap()['自定义服务器(可不填)']);\n if (zdyserver.includes('http')) {\n setArgument('server', zdyserver);\n java.toast(`\\n\\n当前服务器为自定义服务器\\n${zdyserver}\\n\\n切换服务器请先清空服务器地址中的数据`);\n } \n } catch (error) {\n }\n let zdytone_id;\n try {\n zdytone_id = String(source.getLoginInfoMap()['听书Ai音色填写后点击右上角✔']);\n if (zdytone_id) {\n setArgument('tone_id', zdytone_id);\n } else {\n setArgument('tone_id', '默认音色');\n }\n } catch (error) {\n }\n let sq_user_id;\n try {\n sq_user_id = String(source.getLoginInfoMap()['书旗id(可不填)']);\n if (sq_user_id) {\n setArgument('sq_user_id', sq_user_id);\n } else {\n setArgument('sq_user_id', '0');\n }\n } catch (error) {\n }\n}\n\nfunction qtsj() {\n\tjava.startBrowserAwait(getArgument('server') + '\/online_bookshelf','大灰狼书架');\n\t}\n\n\/\/ 填写密钥\nfunction loginqt() {\n java.startBrowserAwait(getArgument('server') + '\/login', '登录大灰狼小说书源');\n }\n\n\/\/登录番茄\nfunction fq_login() {\n var cookies = cookie.getCookie('fanqienovel.com') || java.getCookie('fanqienovel.com')\n java.log(cookies);\n if (cookies && cookies != \"\") {\n java.toast(\"请不要重复登录,请先退出登录!\")\n return false\n }\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 }\n var cookies = cookie.getCookie(\"fanqienovel.com\")\n if (!cookies || cookies == \"\") {\n java.toast(\"登录失败!\")\n return false\n }\n java.toast(\"登录成功!\")\n return true\n}\n\n\/\/退出登录\nfunction logout() {\n cookie.removeCookie(\"fanqienovel.com\");\n cookie.removeCookie(\"snssdk.com\");\n \n const servers = host\n for (let server of servers) {\n cookie.removeCookie(server);\n }\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\/\/设置男女频\nfunction set_source_type(source_type) {\n\t setArgument(\"source_type\", source_type);\n\t java.toast(\"\\n发现页已设置为:\"+source_type);\n\t}\n\t\n\/\/首页\nfunction api() { java.startBrowserAwait('http:\/\/fb.langge.cf', \"首页\");\n}\n\n\/\/打赏\nfunction vip() {\n java.startBrowserAwait(getArgument('server') + '\/coffee', \"喝咖啡\");\n}\n\n\/\/获取密钥\nfunction hqmy() {\n java.startBrowserAwait(getArgument('server') + '\/key', \"获取密钥\");\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 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 java.toast(`\\n\\n当前使用源:${source}-${media}`);\n\n}\n\n\/\/获取服务器\nfunction get_server() {\n var server = getArgument('server');\n var tishi = '\\n\\n当前服务器:' + server\n java.toast(tishi);\n return server\n}\n\n\n\/\/设置服务器\nfunction set_server() {\n let zdyserver;\n try {\n zdyserver = String(source.getLoginInfoMap()['自定义服务器(可不填)']);\n if (zdyserver.includes('http')) {\n setArgument('server', zdyserver);\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 java.toast(`\\n\\n当前服务器${nextIndex+1}:${nextServer}\\n\\n注意:切换服务器后需要在详情页刷新目录才能生效`);\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 let zdytone_id;\n try {\n zdytone_id = String(source.getLoginInfoMap()['其他音色填写后点击右上角✔']);\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(source) {\n\t setArgument('source', source);\n\t set_media('小说');\n java.toast(`\\n\\n当前来源已切换为:\\n${source}\\n\\n切换后请重新搜索`);\n }\n\n\n\/\/ 书源更新\nfunction renderVersionPage() {\n\tlet yd = '';\n let html = `\n<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\" \/>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" \/>\n <title>书源更新<\/title>\n <style>\n body {\n margin: 0;\n padding: 1em;\n font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n background: linear-gradient(135deg, #e0c3fc 0%, #8ec5fc 100%);\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 100vh;\n color: #333;\n }\n\n .container {\n width: 100%;\n max-width: 480px;\n background: rgba(255, 255, 255, 0.85);\n backdrop-filter: blur(10px);\n border-radius: 16px;\n padding: 1em;\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.1);\n animation: fadeIn 0.5s ease-in-out;\n display: none; \n }\n\n @keyframes fadeIn {\n from { opacity: 0; transform: translateY(10px); }\n to { opacity: 1; transform: translateY(0); }\n }\n\n h1 {\n text-align: center;\n font-size: 1.6em;\n margin-bottom: 1em;\n color: #333;\n }\n\n .version-info, .status {\n text-align: center;\n margin-bottom: 1em;\n font-weight: 500;\n }\n\n .status {\n color: #d63384;\n font-size: 0.9em;\n }\n\n .button-group {\n display: flex;\n flex-direction: column;\n gap: 0.75em;\n margin-bottom: 1.5em;\n }\n\n .button {\n display: block;\n width: 90%;\n padding: 0.85em;\n text-align: center;\n font-size: 1em;\n border: none;\n border-radius: 8px;\n text-decoration: none;\n background: linear-gradient(135deg, #42e695 0%, #3bb2b8 100%);\n color: white;\n font-weight: bold;\n transition: all 0.25s ease;\n box-shadow: 0 4px 14px rgba(0, 0, 0, 0.15);\n }\n\n .button:hover {\n transform: translateY(-2px);\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);\n }\n\n .logs {\n background: #ffffffcc;\n padding: 1em;\n border-radius: 8px;\n border: 1px solid #ddd;\n box-shadow: inset 0 1px 3px rgba(0,0,0,0.05);\n }\n\n .logs h2 {\n font-size: 1.2em;\n margin-bottom: 0.8em;\n border-bottom: 1px solid #ccc;\n padding-bottom: 0.3em;\n color: #222;\n }\n\n .log-item {\n margin-bottom: 0.7em;\n line-height: 1.5;\n }\n\n .log-item-date {\n font-weight: bold;\n color: #3b3b3b;\n }\n\n .log-item-content {\n margin-left: 1em;\n color: #555;\n }\n\n .loading {\n text-align: center;\n font-size: 1.1em;\n color: #555;\n animation: pulse 1.2s infinite;\n }\n\n @keyframes pulse {\n 0% { opacity: 1; }\n 50% { opacity: 0.5; }\n 100% { opacity: 1; }\n }\n .ad-banner {\n background: linear-gradient(135deg, #ff9a9e 0%, #fad0c4 100%);\n color: white;\n padding: 10px 15px;\n text-align: center;\n margin-bottom: 20px;\n cursor: pointer;\n border-radius: 8px;\n border: 1px solid #ddd;\n box-shadow: inset 0 1px 3px rgba(0,0,0,0.05);\n }\n\n .ad-banner:hover {\n transform: translateY(-2px);\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);\n }\n\n .ad-banner span {\n font-weight: 500;\n font-size: 16px;\n }\n <\/style>\n<\/head>\n<body>\n <div id=\"loading\" class=\"loading\">🔍 正在拼命检查中,请稍候~ 📡<\/div>\n\n <div class=\"container\" id=\"container\">\n <h1>📚 书源版本检查<\/h1>\n <div class=\"ad-banner\" onclick=\"window.location.href='https:\/\/api.qingtian618.com\/phonecardad'\">\n <span>📱 手机卡充值优惠活动,点击查看详情 →<\/span>\n <\/div>\n <div class=\"version-info\" id=\"versionInfo\">加载中...<\/div>\n <div class=\"status\" id=\"statusText\"><\/div>\n\n <div class=\"button-group\" id=\"buttonGroup\" style=\"display: none;\">\n <\/div>\n\n <div class=\"logs\" id=\"logs\" style=\"display: none;\">\n <h2>📝 更新日志<\/h2>\n <div id=\"logList\"><\/div>\n <\/div>\n <\/div>\n\n <script>\n(async function() {\n const loading = document.getElementById('loading');\n const container = document.getElementById('container');\n const versionInfo = document.getElementById('versionInfo');\n const statusText = document.getElementById('statusText');\n const updateButton = document.getElementById('updateButton');\n const buttonGroup = document.getElementById('buttonGroup');\n const logsContainer = document.getElementById('logs');\n const logList = document.getElementById('logList');\n\nconst localVer = '${String(localVersion)}';\n\/\/ 版本判断逻辑\nfunction compareVersions(vs) {\n const parts1 = localVer.split('.').map(Number);\n const parts2 = vs.split('.').map(Number);\n const maxLength = Math.max(parts1.length, parts2.length);\n for (let i = 0; i < maxLength; i++) {\n const num1 = parts1[i] || 0;\n const num2 = parts2[i] || 0;\n if (num1 > num2) return 1;\n if (num1 < num2) return -1;\n }\n return 0;\n}\n\nconst encodedEndpoints = [\n 'aHR0cHM6Ly9hcGkubGFuZ2dlLmNm', \r\n \r\n'aHR0cHM6Ly8yMC5sYW5nZ2UudGs=', \r\n \r\n'aHR0cHM6Ly9hcGkuZG91YmkudGs=',\r\n \r\n'aHR0cHM6Ly92OS5jenlsLmNm',\r\n \r\n'aHR0cHM6Ly92OC5jenlsLmNm', \r\n \r\n'aHR0cDovL3YyLmRhaHVpbGFuZy5jZg==', \r\n \r\n'aHR0cDovLzExMC40MC4zOC40OjUwMDY=',\r\n\r\n'aHR0cDovL3ZpcC5sYW5nZ2UuY2Y6NDU4MDA=' \n];\n\nfunction decodeEndpoint(str) {\n return atob(str);\n}\n\nasync function fetchVersionData() {\n for (const b64 of encodedEndpoints) {\n const url = decodeEndpoint(b64);\n try {\n const response = await fetch(url + '\/version', { timeout: 2000 }); \n if (response.ok) {\n return await response.json();\n }\n } catch (e) {\n console.warn(\\`接口失败:\\${url}\\`, e);\n }\n }\n throw new Error('所有更新接口都请求失败');\n}\n try {\n loading.style.display = 'block';\n\n const data = await fetchVersionData();\n const cloudVersion = String(data.version3);\n const updateLog = data.update_log || {};\n\n versionInfo.innerHTML = \\`📌 当前版本:v\\${localVer} | 云端版本:v\\${cloudVersion}\\`;\n\n logList.innerHTML = Object.entries(updateLog).map(([date, content]) => \\`\n <div class=\"log-item\">\n <div class=\"log-item-date\">\\${date}<\/div>\n <div class=\"log-item-content\">\\${content}<\/div>\n <\/div>\n \\`).join('');\n logsContainer.style.display = 'block';\n\n if (compareVersions(cloudVersion) === -1) {\n statusText.innerHTML = '<span>✨ 有新版本可用,建议立即更新!<br>${yd}<\/span>';\nconst domainMap = {\n main: 'aHR0cHM6Ly9zeS5kYXNoYWJpLnRr', \r\n d1: \r\n'aHR0cHM6Ly9hcGkubGFuZ2dlLmNm', \r\n d2: \r\n'aHR0cHM6Ly8yMC5sYW5nZ2UudGs=',\r\n d3: \r\n'aHR0cHM6Ly9hcGkuZG91YmkudGs=',\r\n d4: \r\n'aHR0cHM6Ly92OC5jenlsLmNm',\r\n d5: \r\n'aHR0cHM6Ly92OS5jenlsLmNm',\r\n d6: \r\n'aHR0cDovLzExMC40MC4zOC40OjUwMDY=',\r\n d7: \r\n'aHR0cDovL3ZpcC5sYW5nZ2UuY2Y6NDU4MDA=',\r\n d8: \r\n'aHR0cDovL3YyLmRhaHVpbGFuZy5jZg=='\n};\n\nfunction decode(b64) {\n return atob(b64);\n}\n\nconst path = '\/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%883.0(%E5%AE%8C%E5%85%A8%E7%89%88).json';\nconst mainPath = '\/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%883.0(%E5%AE%8C%E5%85%A8%E7%89%88).json';\n\nconst routes = [\n { name: '🚀 主线路', domain: 'main', suffix: mainPath },\n { name: '📦 备用线路1', domain: 'd1', suffix: path },\n { name: '🛰️ 备用线路2', domain: 'd2', suffix: path },\n { name: '🛰️ 备用线路3', domain: 'd3', suffix: path },\n { name: '🛰️ 备用线路4', domain: 'd4', suffix: path },\n { name: '🛰️ 备用线路5', domain: 'd5', suffix: path },\n { name: '🛰️ 备用线路6', domain: 'd6', suffix: \npath },\n { name: '🛰️ 备用线路7', domain: 'd7', suffix: path },\n { name: '🛰️ 备用线路8', domain: 'd8', suffix: path } \n];\n\nbuttonGroup.innerHTML = routes.map(r => {\n const fullUrl = decode(domainMap[r.domain]) + r.suffix;\n return \\`<a href=\"yuedu:\/\/booksource\/importonline?src=\\${encodeURIComponent(fullUrl)}\" class=\"button\">\\${r.name}<\/a>\\`;\n}).join('');\n buttonGroup.style.display = 'flex';\n } else {\n statusText.textContent = '✅ 已是最新书源咯~';\n }\n\n loading.style.display = 'none';\n container.style.display = 'block';\n\n } catch (err) {\n loading.textContent = '😢 检查失败啦~ 请稍后再试==>'+err;\n console.error('版本检查失败:', err);\n }\n})();\n<\/script>\n<\/body>\n<\/html>\n`;\n java.startBrowser(`data:text\/html;base64,${java.base64Encode(html)}`, '大灰狼书源更新');\n}\n\n\n\n", "respondTime": 180000, "ruleBookInfo": { "author": "$.author", "coverUrl": "$.thumb_url", "init": "$.book_detail", "intro": "<js>\nconst {\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 media,\n abstract,\n book_review,\n copyright_info\n} = result;\njava.put('book_detail',JSON.stringify(result));\nlet info;\nlet base_url = getArguments(source.getVariable(),'server');\nlet key = '';\n\ntry {\n\tkey = String(cookie.getCookie(base_url)) || String(java.getCookie(base_url));\n\tkey = getKey(key);\n } catch (e) {key='';}\nif (key != ''){key = '✅️已登录';} else {key = '‼️⛔️您还未登录大灰狼账号哦,可以点击右上角登录♨️';}\ninfo = ` 🎚当前服务器:${base_url}\n🪄大灰狼账号:${key}\n🎴当前来源:${sources}\n🗂当前模式:${tab}\\n`\nif (tab =='听书') {info = info+\t'🔊当前音色:'+ getArguments(source.getVariable(),'tone_id')+'\\n'+book_tts+'\\n‎';}\nif (`${tags}`) {info = info + `🕹分类:${tags}\\n`};\nif (`${role}`) {info = info + `🎗书籍主角:${role}\\n`};\nif (`${last_chapter_title}`) {info = info + `🎯最新章节:${last_chapter_title}\\n`};\nif (`${last_chapter_update_time}`) {info = info + `⏳更新时间:${last_chapter_update_time}\\n`};\nif (`${word_number}`) {info = info + `📝书籍字数:${word_number}\\n`};\nif (`${status}`) {info = info + `💥书籍状态:${status}\\n`};\nif (`${score}`) {info = info + `✨书籍评分:${score}\\n`};\nif (`${media}`) {info = info + `📌出版媒体:${media}\\n`};\nif (`${abstract}`) {info = info + `‎\n📚书籍简介:\n${abstract}\\n`};\nif (`${book_review}`) {info = info + `‎\\n${book_review}\\n`};\nif (`${copyright_info}`) {info = info + `📍${copyright_info}`};\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 base_url = getArguments(source.getVariable(),'server');\nlet sq_user_id = getArguments(source.getVariable(),'sq_user_id') || '0';\n`${base_url}\/catalog?book_id=${book_id}&source=${sources}&tab=${tab}&sq_user_id=${sq_user_id}`\n<\/js>", "wordCount": "$.word_number" }, "ruleContent": { "content": "<js>\n\nlet res =java.hexDecodeToString(result).split('大灰狼融合2.1');\n\nlet item_id = res[0];\nlet tab = res[1];\nlet title = res[2];\nlet sources = res[3];\nlet tone_id = getArguments(source.getVariable(),'tone_id');\nlet base_url = getArguments(source.getVariable(),'server');\nlet key2 = '';\ntry {\n\tkey2 = String(cookie.getCookie(base_url)) || String(java.getCookie(base_url));\n\tkey2 = getKey(key2);\n } catch (e) {key2='';} \nlet device,device_type;\ntry {\n device = java.androidId();\n device_type='安卓';\n} catch (e) {\n try{\ndevice = java.deviceID();\ndevice_type='苹果';\n}catch (e) {device = '';\ndevice_type='安卓';\n}\n}\nlet sq_user_id = getArguments(source.getVariable(),'sq_user_id') || '0';\n\nlet content_url;\nif (tab=='小说') {\n\tcontent_url= `\/content?item_id=${item_id}&device=${device}&source=${sources}&tab=${tab}&sq_user_id=${sq_user_id}&key=${key2}&version=3`;\n } \n else if (tab=='听书') {\n \t \tcontent_url= `\/content?item_id=${item_id}&device=${device}&tone_id=${tone_id}&source=${sources}&tab=${tab}&key=${key2}&version=3`;\n \t} else if (tab=='漫画') {\n \t\t \tcontent_url=\t`\/content?item_id=${item_id}&device=${device}&source=${sources}&tab=${tab}&key=${key2}&version=3`;\n \t\t} else if (tab=='短剧' || tab=='视频') {\n \t\tcontent_url=\t`\/content?item_id=${item_id}&device=${device}&source=${sources}&tab=${tab}&key=${key2}&version=3`;\n \t\t\t}\n let data = java.ajax(base_url+content_url);\n try {\nif (JSON.parse(data).msg) {\n\tjava.toast(JSON.parse(data).msg);\n\t}}catch (e) {}\ndata = JSON.parse(data);\nlet content = decrypt(data.content);\ndata = JSON.stringify({'content':content});\n\/\/java.log(decrypt(data.content));\nif (device_type=='安卓' && (tab == '短剧' || tab== '视频')){\n\tdata = {'content':`【右上角刷新】开启播放(下一集请切换下一章刷新)\\n播放直链:\\n${content}`}\n\tdata = JSON.stringify(data);\n\t if (book.durChapterIndex===chapter.index){\n\t \/\/let b64 = java.base64Encode(generateVideoPage(title,content));\n\t\/\/ let dataUrl = `data:text\/html;base64,${b64}`;\n\t\/\/ \tjava.startBrowser(dataUrl,title);\n\t \tjava.startBrowser(content,title);\n\t \tjava.toast('正在加载视频...');\n\t}};\n\ndata;\n<\/js>\n$.content" }, "ruleExplore": { "author": "$.author", "bookList": "$.discover_data&&$.books&&$.data.data", "bookUrl": "<js>\nlet book_id = result.book_id;\nlet sources = result.source;\nlet tab = result.tab || '小说';\nlet base_url = getArguments(source.getVariable(),'server');\n`${base_url}\/detail?book_id=${book_id}&source=${sources}&tab=${tab}`\n<\/js>", "coverUrl": "$.thumb_url", "intro": "{{$.source}}\n{{$.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": "$.books", "bookUrl": "<js>\nlet book_id = result.book_id;\nlet sources = result.source;\nlet tab = result.tab || '小说';\nlet base_url = getArguments(source.getVariable(),'server');\nlet sq_user_id = getArguments(source.getVariable(),'sq_user_id') || '0';\n`${base_url}\/detail?book_id=${book_id}&source=${sources}&tab=${tab}&sq_user_id=${sq_user_id}`\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": "$.chapter_list\n<js>\nlet book_detail = JSON.parse(java.get('book_detail'));\nlet device;\nlet device_type;\nlet tab = book_detail.tab;\ntry {\n device = java.androidId();\n device_type='安卓';\n} catch (e) {\n device_type='苹果';\n};\n\nif (tab=='小说') {\n\tif (device_type == '安卓') {\n book.type = 8;} else {\n \tbook.type = 0;\n \t}\n } \n else if (tab=='听书') {\n \tif (device_type == '安卓') {\n book.type = 32;} else {\n \tbook.type = 1;\n \t}\n \t} else if (tab=='漫画') {\n \t\tif (device_type == '安卓') {\n book.type = 64;} else {\n \tbook.type = 2;\n \t}\n \t } else if (tab=='短剧') {\n \t\t\tif (device_type == '安卓') {\n book.type = 8;} else {\n \tbook.type = 3;\n \t}\n \t\t \t\t\t} else {\n \t\t \t\t\t\tif (device_type == '安卓') {\n book.type = 8;} else {\n \tbook.type = 0;\n \t}\t\t\n \t\t \t\t\t\t}\n \tresult;\n\t<\/js>", "chapterName": "$.title", "chapterUrl": "<js>\nlet tab = result.tab;\nlet sources = result.source;\nlet title = result.title;\nlet item_id = result.item_id;\n\nlet content_url = `${item_id}大灰狼融合2.1${tab}大灰狼融合2.1${title}大灰狼融合2.1${sources}`;\ncontent_url= java.base64Encode(content_url);\ncontent_url= `data:;base64,${content_url},{\"type\":\"qingtian\"}`;\n<\/js>", "updateTime": "$.first_pass_time" }, "searchUrl": "<js>\nlet base_url = getArguments(source.getVariable(),'server');\nlet key2 = '';\ntry {\n\tkey2 = String(cookie.getCookie(base_url)) || String(java.getCookie(base_url));\n\tkey2 = getKey(key2);\n } catch (e) {key2='';}\n\n\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\tmedia = \"小说\"\n key = key.slice(2)\n\t} else {\n\tmedia = getArguments(source.getVariable(),'media');\n\t}\nif (key.includes('@')) {\n const parts = key.split('@');\n key = parts[0];\n sources = parts[1] || sources;\n}\n\t`${base_url}\/search?title=${key}&tab=${media}&source=${sources}&key=${key2}`\n<\/js>", "weight": 60 }