®️爱丽丝书屋
爱丽丝书屋
yezechuandl (3004)1天前
2026.5.24 修复诸多问题 ◎夜泽川◎ 2024.7.26 ◎夜泽川◎ //搜索和发现需要封面可复制规则到相应位置,因为封面是从详情取的,所以可能会导致加载变慢甚至超时,自行斟酌。↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ a@hreful = GetUL() + result; java.ajax(ul); [property$=image]@content
{
"bookSourceComment": "2026.5.24 修复诸多问题 ◎夜泽川◎\n2024.7.26 ◎夜泽川◎\n\/\/搜索和发现需要封面可复制规则到相应位置,因为封面是从详情取的,所以可能会导致加载变慢甚至超时,自行斟酌。↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓\na@href\n<js>\nul = GetUL() + result;\njava.ajax(ul);\n<\/js>\n[property$=image]@content",
"bookSourceGroup": "自制,零",
"bookSourceName": "®️爱丽丝书屋",
"bookSourceType": 0,
"bookSourceUrl": "爱丽丝书屋",
"bookUrlPattern": "https?:\\\/\\\/.*?\\..*?(xnxnxn|alice|爱丽丝|als).*?\\.[a-zA-Z]+?\\\/novel\\\/\\d+\\.html",
"customButton": false,
"customOrder": 188,
"enabled": true,
"enabledCookieJar": true,
"enabledExplore": true,
"eventListener": false,
"exploreUrl": "@js:\neval(String(source.loginUrl));\nlet Cookie = cookie.getCookie(GetUL());\nif (!\/lf_user_auth\/.test(Cookie) && source.getLoginHeader()) {\n let ck = source.getLoginHeaderMap()['Cookie']\n cookie.setCookie(GetUL(), ck);\n java.toast('登录状态掉了,已重新登陆');\n}\nvar result = [];\nvar headers = JSON.stringify({\"headers\":{\"User-Agent\": \"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/121.0.6167.171 Safari\/537.36\"}});\nvar push = (title, url, size) =>\n result.push({\n title: title,\n url: url ? `{{GetUL()}}${url},` + headers : url,\n style: {\n layout_flexGrow: 1,\n layout_flexBasisPercent: size\n }\n });\npush(`当前站源:${GetUL()}`, null, 1)\nif (source.getLoginHeader()) {\n let jc = source.getLoginHeaderMap();\n let inf = decodeURIComponent(jc.get(\"Cookie\"));\n let info = decodeURIComponent(inf).match(\/\\{[\\s\\S]+\\}\/)[0];\n let username = JSON.parse(info)['username'];\n let expe = Ajax(`${GetUL()}\/user\/index\/index.html`);\n let ex = org.jsoup.Jsoup.parse(expe).select('.group , .user-data li');\n push(`用户◎${username}◎中心`, null, 1);\n push(\"书架\", \"\/user\/bookshelf?page={{page}}\", 0.45);\n push(\"阅读记录\", \"\/user\/recentread\/index.html\", 0.45);\n ex.forEach(xp => {\n nam = String(xp.text()).replace(\/[^\\u4e00-\\u9fa5a-zA-Z0-9]\/g, \"\");\n title = \/\\d\/.test(nam) ? nam.replace(\/(\\d+)([^\\d]+)\/, \"$2:$1\") : nam.replace(\/^\/, \"用户等级:\");\n push(title, null, 0.45);\n });\n} else {\n push(\"未登录\", null, 1);\n}\npush(\"--------书库--------\", null, 1);\npush(\"最近更新\", \"\/all{{Sort_()}}.html\", 0.45);\npush(\"原创\", \"\/original.html?page={{page}}\", 0.45);\npush(\"排行\", null, 1);\nvar src = Ajax(`${GetUL()}\/all\/order\/hits+desc.html`);\nvar ph = org.jsoup.Jsoup.parse(src).select('.paihang_ds a');\nph.forEach(ta => {\n nam = ta.text();\n ul = ta.attr('href')\n push(nam, ul, 0.45);\n})\npush(\"分类\", null, 1);\nvar tag = org.jsoup.Jsoup.parse(src).select('.fenlei_ds a');\ntag.forEach(ta => {\n nam = ta.text();\n ul = String(ta.attr('href')).replace(\/$\/, \"?page={{page}}\").replace(\/lists\/, \"all\/id\").replace(\/\\.html\/, `{{Sort_()}}$&`);\n push(nam, ul, 0.25);\n})\nif (source.getLoginInfoMap()?.[\"发现自定义标签🏷️(中 \/ 英逗号分隔)\"] != \"\") {\n\t push(\"自定义标签🏷️\", null, 1);\n\t let myTags = String(source.getLoginInfoMap()[\"发现自定义标签🏷️(中 \/ 英逗号分隔)\"]).split(\/[,,]\/);\n\t myTags.forEach(tag => {\n\t \tlet url = `\/search.html?q=${tag}&f=tag&sort={{Sort_('search')}}&p={{page}}&serialize=`;\n\t \tpush(tag, url, 0.25);\n\t \t});\n}\nJSON.stringify(result);",
"header": "{\"User-Agent\": \"Mozilla\/5.0 (Android 11; Mobile; rv:147.0) Gecko\/147.0 Firefox\/147.0\"}",
"jsLib": "\/\/构建验证参数\nfunction calculateChecksum(nonce, cookieString) {\n var cpk = \"ge_ua_p\";\n if (!cookieString || !nonce) {\n return null;\n }\n \n var cookieValue = \"\";\n var cookieArray = cookieString.toString().split(\";\");\n \n for (var i = 0; i < cookieArray.length; i++) {\n var cookie = cookieArray[i].trim();\n var parts = cookie.split(\"=\");\n if (parts.length === 2 && parts[0] === cpk) {\n cookieValue = parts[1];\n break;\n }\n }\n \n if (cookieValue.length === 0) {\n return null;\n }\n \n var sum = 12345;\n for (var i = 0; i < cookieValue.length; i++) {\n var char = cookieValue[i];\n if (\/^[a-zA-Z0-9]$\/.test(char)) {\n sum += cookieValue.charCodeAt(i) * (nonce + i);\n }\n }\n \n return {\n \t\"body\": \"sum=\" + sum + \"&nonce=\" + nonce,\n \t\"cookieValue\": cookieValue\n \t};\n}\n\nfunction Check_(src, cookies = null, url) {\n const { java } = this;\n if (!\/Checking your browser\/.test(src)) return src;\n java.toast('检测到验证,正在自动处理中……');\n let nonce = parseInt(src.match(\/nonce\\s*=\\s*(\\d+)\/)[1]);\n cookies = String(cookies);\n \/\/java.log(`${cookies}|${nonce}`);\n\n let data = calculateChecksum(nonce, cookies);\n\n let headers = {\n \"User-Agent\": \"Mozilla\/5.0 (Android 11; Mobile; rv:140.0) Gecko\/140.0 Firefox\/140.0\",\n \"Content-Type\": \"application\/x-www-form-urlencoded\",\n \"Referer\": String(this.GetUL() + \"\/\"),\n \"X-Ge-Ua-Step\": \"prev\",\n \"Cookie\": String(\"ge_ua_p=\" + data.cookieValue)\n };\n \n let postResponse = java.post(this.GetUL(), data.body, headers);\n \n let success = JSON.parse(postResponse.body()).ok;\n java.toast(success ? '验证通过' : '验证失败,请重试!');\n\n if (!success) return src;\n \n return java.ajax(url);\n}\n\nfunction Sort_(t) {\n\t const { source } = this\n const sgvs = JSON.parse(source.getVariable())?.s || 0;\n \n if (!sgvs) return t === 'search' ? 'relevance' : '';\n const sorts = ['update_time+desc', 'hits+desc', 'word+desc'];\n const sort = sorts[sgvs - 1];\n \n if (t === 'search') {\n return sort.replace('+', '_');\n }\n return '\/order\/' + sort;\n}\n\nfunction GetUL() {\n\tconst { source } = this;\n\tlet sourceul = JSON.parse(source.getVariable()).sourl;\n\treturn sourceul;\n}\n\nfunction timeov(times) {\n const date = new Date(times);\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n const hours = String(date.getHours()).padStart(2, '0');\n const minutes = String(date.getMinutes()).padStart(2, '0');\n const seconds = String(date.getSeconds()).padStart(2, '0');\n \n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;\n}\n\ncodesvg = \"PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIAogICAgIHZpZXdCb3g9IjAgMCA3MDAgMjAwIiAKICAgICBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJub25lIgogICAgIHN0eWxlPSJ3aWR0aDogMTAwJTsgaGVpZ2h0OiAxMDAlOyI+CiAgPHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0id2hpdGUiLz4KICAKICA8IS0tIOmhtumDqOagh+mimCAtLT4KICA8dGV4dCB4PSI1MCUiIHk9IjQwIiAKICAgICAgICBmb250LXNpemU9IjIwIiAKICAgICAgICBmb250LXdlaWdodD0iYm9sZCIgCiAgICAgICAgdGV4dC1hbmNob3I9Im1pZGRsZSIgCiAgICAgICAgZmlsbD0iIzAwMCI+6YCJ5oup5Y+R6YCB57G75Z6LPC90ZXh0PgogIAogIDwhLS0g6K+E6K665qih5Z2XIC0tPgogIDx0ZXh0IHg9IjI1JSIgeT0iOTAiIAogICAgICAgIGZvbnQtc2l6ZT0iMTYiIAogICAgICAgIGZvbnQtd2VpZ2h0PSJib2xkIiAKICAgICAgICB0ZXh0LWFuY2hvcj0ibWlkZGxlIiAKICAgICAgICBmaWxsPSIjMDAwIj7or4Torro8L3RleHQ+CiAgPHRleHQgeD0iMjUlIiB5PSIxMTAiIAogICAgICAgIGZvbnQtc2l6ZT0iMTQiIAogICAgICAgIGZvbnQtd2VpZ2h0PSJib2xkIiAKICAgICAgICB0ZXh0LWFuY2hvcj0ibWlkZGxlIiAKICAgICAgICBmaWxsPSIjMDAwIj4o5aGr5YaZIuivhOiuuiIpPC90ZXh0PgogIAogIDwhLS0g5Zue5aSN5qih5Z2XIC0tPgogIDx0ZXh0IHg9Ijc1JSIgeT0iOTAiIAogICAgICAgIGZvbnQtc2l6ZT0iMTYiIAogICAgICAgIGZvbnQtd2VpZ2h0PSJib2xkIiAKICAgICAgICB0ZXh0LWFuY2hvcj0ibWlkZGxlIiAKICAgICAgICBmaWxsPSIjMDAwIj7lm57lpI08L3RleHQ+CiAgPHRleHQgeD0iNzUlIiB5PSIxMTAiIAogICAgICAgIGZvbnQtc2l6ZT0iMTQiIAogICAgICAgIGZvbnQtd2VpZ2h0PSJib2xkIiAKICAgICAgICB0ZXh0LWFuY2hvcj0ibWlkZGxlIiAKICAgICAgICBmaWxsPSIjMDAwIj4o5aGr5YaZIkBpZCIpPC90ZXh0PgogIAogIDwhLS0g5bqV6YOo5L+h5oGvIC0tPgogIDx0ZXh0IHg9IjUwJSIgeT0iMTgwIiAKICAgICAgICBmb250LXNpemU9IjE0IiAKICAgICAgICBmb250LXdlaWdodD0iYm9sZCIgCiAgICAgICAgdGV4dC1hbmNob3I9Im1pZGRsZSIgCiAgICAgICAgZmlsbD0iIzAwMCI+5qW85bGCaWTnroDku4vmnIk8L3RleHQ+Cjwvc3ZnPg==\";\n\nfunction Ajax(url) {\n const { java, cookie } = this;\n let result = java.ajax(url);\n result = this.Check_(result, cookie.getCookie(this.GetUL()), url);\n return result;\n}\n\nconst SALT1 = \"B3wlP9Tzo$0RIdlvX&^sg30^0&feAox%\";\nconst SALT2 = \"Rs4qM7mGrQ6aTMr8HHvv3WikTcY&kW8R\";\n\nconst PRIVATE_KEY = [\n \"MIIEogIBAAKCAQEAnOUiABBEw9zzOqivp4uJxTd3D5Givmwx2i+JLVdyj9iO2S1E\",\n \"crWOaO5k6lD4fbL0MnMH+luJhO3ySm1xDZy22ruzvPHhd+Sh3nH56+hOcj1jfpBx\",\n \"lDPlwyo2nDshY0VFr\/3fonFjepp5PP+eZKYt9YWtxrVMWOc0yNH6HuRA+zwUX28W\",\n \"RlP\/4vMWi6vEYt0XLt+lTBGqyvwxPYJBYivIehGz4exC7K1bpvX8LJWVARkvEIuf\",\n \"Y3sQHtC\/BTeYoEsipfZYafTgQHJ+KAOZSq\/CET0USeTt+Evfn6YcbWX577DrRyGt\",\n \"siJjojMEG5TKdDQWmGKTQb4E2+EpTrQYaCcaowIDAQABAoIBAC8L9noWZshkxPre\",\n \"Am43RYTB8Q3WGfsH7psCjhvukQfZZFxzWocbMiz8733j8d+ffeJy4\/2K3V3jDDiN\",\n \"QM1YJOzKREdwMLAG+xL9EnhPHNbc2azmG2jZdxhi3CVVBdoCt7biZeEMJ0xobdqA\",\n \"vDpqKnXpNAbV7qLqEcX2UQ5aW7H6BdCgGk9HRBKXs\/ll65NZmxORXLoAVg+w7Vzi\",\n \"XaLP6+43KNXUPLz0EPndDH9VkGlMcyu6q7pWLoz6eN0fNiP4Jfl9PbV4KFlye2xo\",\n \"4FI+Go8luM0onDL1+bKE5RJHXqfS+ow9hYzBJSz39jyNpiH7j8Hg8mMDPm0VIYtM\",\n \"sOF\/RgECgYEAzuuziQzrT74ZW27AQqMFQFLvqMmnrhR4CPg0mRq\/PMHSzh+Bs+nS\",\n \"Gib2d1ulkKIDHPOG9EWKXBOUvHOBmGro+sOS9fnfoJYeNhLmX5K1xcDJpsBOMdZv\",\n \"euEit2i7yy+KAc26fP+SoCQEHm1mlgZG1vcfJlPDofqwRyBeKHPAkGMCgYEAwhvb\",\n \"Fw3udE0hws92+9GYmjES8jNauBaP3hlu3lmxcnjlVqlkHbc9PkvddmCsSB\/5TUCH\",\n \"7qJRgYLo+uov40zNNavXv8cTqWvDrJxTuDFn0OSjeIvqS9kXeVHjpBP6d4CCLAZM\",\n \"b6owfM8JtBFx9ef9ll5mwBekZDrspEXOgoCQwMECgYBujaILvFpQ7alQn5ibQcxB\",\n \"dM5VKQCs0oTbjflUP+UjCg+eT1kWDfxSOrT+SnnoD5eINVjKVAk7br7N\/QylqaE2\",\n \"sZ1oTIu9mdckXu6064aw1HMo46AjooVHatgIlC2ZvpmGoytbM5VceEG3HA5uY4Yf\",\n \"vkLnUGO6vFzIc7O6+zVMLwKBgFmIab0vkt6YOUtXUIWEvwPYQOnwoBaraX7Dcm0j\",\n \"KAMqGnanuWMvgxM6ARO6MZ0vCloEuu5qdnfrfzVFUgNhCIKKGgD+fWY3K9FxZfhe\",\n \"6Yjj\/Tb8Kn0DzJ0MFZk4Ed6PKvvNh\/I1qRnYkZw6M7t+X2y9bF2MSiplN4PqIv\/0\",\n \"90\/BAoGAQXzOzA3q+vcA9mwKvwXrPiSscmZMekV6RBUxf1riRzTnds9uWSTKz8QM\",\n \"LpEoNB3tKSB+4raK6xJGJ914b+jc\/B7ayHDksStOLeJLV6t5+bmoKjk6qBrUjTQX\",\n \"y8x2rsHReaJw0SbZy+4x55nYTi\/0mdzomR7N27EzYtzM7iWk5w0=\",\n].join(\"\\n\");\n\nfunction getAuthHeaders(sourceId, chapterId, t) {\n const { java } = this;\n const signStr = SALT1 + t + sourceId + chapterId + SALT2;\n const token = java.digestHex(signStr, \"SHA-256\");\n\n return {\n \"User-Agent\": \"Mozilla\/5.0 (Android 11; Mobile; rv:147.0) Gecko\/147.0 Firefox\/147.0\",\n \"x-request-timestamp\": t,\n \"x-request-token\": token,\n \"X-Requested-With\": \"XMLHttpRequest\"\n };\n}\n\nfunction decryptChapter(chapterData) {\n const { java } = this;\n const rsa = java.createAsymmetricCrypto(\"RSA\/ECB\/PKCS1Padding\");\n rsa.setPrivateKey(java.base64DecodeToByteArray(PRIVATE_KEY));\n \n const AesKeyByte = java.base64DecodeToByteArray(rsa.decryptStr(chapterData.aes_key_encrypt, false));\n \n const aes = java.createSymmetricCrypto(\"AES\/CBC\/PKCS5Padding\", AesKeyByte, java.base64DecodeToByteArray(chapterData.iv));\n \n return aes.decryptStr(java.base64DecodeToByteArray(chapterData.content_encrypt));\n}\n\nfunction getContent(Data) {\n const { java, source } = this;\n const { source_id: sourceId, chapter_id:chapterId, t, sign} = Data;\n const url = `${this.GetUL()}\/home\/chapter\/info?id=${sourceId}&key=${chapterId}&t=${t}&sign=${sign}`;\n\n const headers = this.getAuthHeaders(sourceId, chapterId, t);\n \/\/java.log(JSON.stringify(headers))\n const response = java.get(url, headers);\n \/\/java.log(response.body())\n const json = JSON.parse(response.body());\n\n if (json.code === 1) {\n const chapter = json.data.chapter;\n const content = this.decryptChapter(chapter);\n return content;\n } else {\n return \"加载失败:\" + json.msg;\n }\n}",
"lastUpdateTime": "1781600310292",
"loginCheckJs": "if (\/小说被禁用或已删除\/.test(result.body())) java.toast('小说被禁用或已删除!');\nlet sr = Check_(result.body(), result.headers().get('set-cookie'), result.url());\nresult = Packages.io.legado.app.help.http.StrResponse(result.url(), sr);\nresult;",
"loginUi": "[ \n {\n \"name\": \"获取站源\",\n \"type\": \"button\",\n \"action\": \"Geturls()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 1\n }\n },\n {\n \"name\": \"站源1\",\n \"type\": \"button\",\n \"action\": \"Puturl(0)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"name\": \"站源2\",\n \"type\": \"button\",\n \"action\": \"Puturl(1)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"name\": \"站源3\",\n \"type\": \"button\",\n \"action\": \"Puturl(2)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"name\": \"站源4\",\n \"type\": \"button\",\n \"action\": \"Puturl(3)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"name\": \"用户名\/邮箱\",\n \"type\": \"text\"\n },\n {\n \"name\": \"密码\",\n \"type\": \"password\"\n },\n {\n \"name\": \"注册\",\n \"type\": \"button\",\n \"action\": \"reg()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"name\": \"登录\",\n \"type\": \"button\",\n \"action\": \"Login()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"name\": \"登出\",\n \"type\": \"button\",\n \"action\": \"out()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"name\": \"信息\",\n \"type\": \"button\",\n \"action\": \"show()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n },\n {\n \"name\": \"评论展示开 \/ 关\",\n \"type\": \"button\",\n \"action\": \"Comment()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n },\n {\n \"name\": \"点击切换分类排序方式\",\n \"type\": \"button\",\n \"action\": \"\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 1\n }\n },\n {\n \"name\": \"默认\",\n \"type\": \"button\",\n \"action\": \"Tgch(0)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"name\": \"时间\",\n \"type\": \"button\",\n \"action\": \"Tgch(1)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"name\": \"人气\",\n \"type\": \"button\",\n \"action\": \"Tgch(2)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"name\": \"字数\",\n \"type\": \"button\",\n \"action\": \"Tgch(3)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.2\n }\n },\n {\n \"name\": \"发现自定义标签🏷️(中 \/ 英逗号分隔)\",\n \"type\": \"text\"\n },\n {\n \"name\": \"◎↓网络书架↓◎\",\n \"type\": \"button\",\n \"action\": \"\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 1\n }\n },\n {\n \"name\": \"书籍ID\",\n \"type\": \"text\"\n },\n {\n \"name\": \"添加\",\n \"type\": \"button\",\n \"action\": \"AFBook(true)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"name\": \"移除\",\n \"type\": \"button\",\n \"action\": \"AFBook(false)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"name\": \"跳转\",\n \"type\": \"button\",\n \"action\": \"BookShelf()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"name\": \"邀请码【⚠️生成一个需消耗50积分】\",\n \"type\": \"button\",\n \"action\": \"\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 1\n }\n },\n {\n \"name\": \"💡生成邀请码\",\n \"type\": \"button\",\n \"action\": \"InvitationCode(true)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"name\": \"📜打印邀请码\",\n \"type\": \"button\",\n \"action\": \"InvitationCode()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n }\n]",
"loginUrl": "var r = {\n\t \"z\": 0,\n \"s\": 0,\n \"co\": 0,\n \"urls\": [],\n \"sourl\": \"https:\/\/www.alicesw.com\"\n};\n\ntry {\n let v = JSON.parse(source.getVariable());\n if (v === null && typeof v !== 'object' && Array.isArray(v)) {\n source.setVariable(JSON.stringify(r, null, \"\\t\"));\n java.toast('已初始化,使用默认站源');\n }\n} catch (err) {\n java.log(err.message);\n source.setVariable(JSON.stringify(r, null, \"\\t\"));\n java.toast('已初始化,使用默认站源');\n}\n\nvar sgv = JSON.parse(source.getVariable());\nvar sg = source.get(\"list\");\nvar ul = GetUL();\n\nfunction reg() {\n java.startBrowser(`${ul}\/user\/user\/reg.html`, \"注册账号\");\n}\n\nfunction Comment() {\n let sgvo = sgv.co;\n sgv.co = sgv.co ? 0 : 1;\n source.setVariable(JSON.stringify(sgv, null, \"\\t\"));\n java.toast(`\\n评论区\\n【${[\"开启\", \"禁用\"][sgvo]} → ${[\"开启\", \"禁用\"][sgv.co]}】`);\n}\n\nfunction login() {}\n\nfunction Tgch(o) {\n const sort = [\"默认\", \"更新时间\", \"人气\", \"字数\"];\n const one_ = sgv.s;\n const msg = (sgv.s = o, source.setVariable(JSON.stringify(sgv, null, \"\\t\")), `排序方式\\n【${sort[one_]}→${sort[o]}】`);\n java.toast(\"\\n\" + msg);\n}\n\nfunction Geturls() {\n sgv.urls.length = 0;\n try {\n const res = org.jsoup.Jsoup.parse(java.get('https:\/\/xn--vcsx64d.asw4.cc\/', {}).body()).select('.container a');\n const url1 = java.base64Decode(res[0].attr('href').match(\/['\"](.*?)['\"]\/)[1]);\n sgv.urls.push(String(url1).replace(\/\\\/?$\/, \"\"));\n const url2 = java.base64Decode(res[1].attr('href').match(\/['\"](.*?)['\"]\/)[1]);\n let src = java.get(java.connect(url2).url(), {}).body();\n src = java.get(org.jsoup.Jsoup.parse(src).select('#redirectButton').attr('href'), {}).body();\n const seen = new Set();\n for (let match of src.matchAll(\/targetHref\\:\\s*[\"'](https?[^\"']+)\\\/?[\"']\/g)) {\n if (!seen.has(match[1])) {\n sgv.urls.push(match[1]);\n seen.add(match[1]);\n }\n }\n source.setVariable(JSON.stringify(sgv, null, \"\\t\"));\n\n if (sgv.urls.length >= 2) {\n java.toast(`获取成功,共获取到${sgv.urls.length}个站源\\n┎┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┒\\n${sgv.urls.join('\\n')}\\n┖┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┚`);\n } else {\n java.toast('获取失败,请重试或检查网络状况');\n }\n } catch (e) {\n java.log(e);\n java.toast('\\n未知错误,请检查网络或更新阅读版本!');\n }\n}\n\nfunction Puturl(e) {\n if (!sgv.urls.length) return java.toast('\\n当前没有站源,请获取后选择');\n if (e + 1 > sgv.urls.length) return java.toast(`暂无站源${e+1}`);\n \n try {\n const stime = Date.now();\n java.get(sgv.urls[e], {});\n const speedtime = (Date.now() - stime) \/ 1000;\n \n sgv.sourl = sgv.urls[e];\n sgv?.booklist?.forEach(item => {\n item.img = item.img.replace(\/https?:\\\/\\\/[^\\\/]+\/, sgv.urls[e]);\n item.url = item.url.replace(\/https?:\\\/\\\/[^\\\/]+\/, sgv.urls[e]);\n });\n source.setVariable(JSON.stringify(sgv, null, \"\\t\"));\n \n \/\/ 切换接口保持登录状态\n const Cookie = cookie.getCookie(sgv.urls[e]);\n if (!\/lf_user_auth\/.test(Cookie) && source.getLoginHeader()) {\n cookie.setCookie(sgv.urls[e], source.getLoginHeaderMap().get('Cookie'));\n }\n java.toast(`站源已设置为【站源${e + 1}】:\\n${sgv.urls[e]}\\n♦解析用时${speedtime}秒♦`);\n } catch (err) {\n java.log(err.message);\n java.toast(`\\n【站源${e+1}:${sgv.urls[e]}】\\n已失效,请检查网络状况或切换其他站源`);\n }\n}\n\nfunction Login() {\n cookie.removeCookie(ul);\n const na = result['用户名\/邮箱'];\n const pa = result['密码'];\n \n if (!na || !pa) return;\n \n try {\n const phpid = java.get(`${ul}\/user\/user\/verify.html`, {}).header(\"set-cookies\");\n const code = java.getVerificationCode(`${ul}\/user\/user\/verify.html`);\n const response = java.post(`${ul}\/user\/user\/login.html`, \n `username=${na}&password=${pa}&code=${code}`, \n { \"x-requested-with\": \"XMLHttpRequest\", \"Cookie\": phpid });\n \n const ck = cookie.mapToCookie(response.cookies());\n const usercode = JSON.parse(response.body()).msg;\n java.toast(usercode);\n \n if (ck) {\n source.putLoginHeader(JSON.stringify({\"Cookie\": ck}));\n cookie.replaceCookie(GetUL(), ck);\n } else {\n source.removeLoginHeader();\n cookie.removeCookie(GetUL());\n }\n } catch (e) {\n java.log(e);\n java.toast('\\n登录出错,请切换其他站源重试!');\n }\n}\n\nfunction out() {\n source.removeLoginHeader();\n cookie.removeCookie(GetUL());\n java.toast(\"已退出登录状态\");\n}\n\nfunction show() {\n const jc = source.getLoginHeaderMap();\n let us, id, codes;\n \n if (jc) {\n const info = decodeURIComponent(decodeURIComponent(jc.get(\"Cookie\")).match(\/\\{[\\s\\S]+\\}\/)[0]);\n const userInfo = JSON.parse(info);\n us = userInfo.username;\n id = userInfo.uid;\n codes = \"✔️已登录\";\n } else {\n us = id = \"无\";\n codes = \"❌未登录\";\n }\n \n java.longToast(`\\n◎用户:${us}◎\\n◎用户ID:${id}◎\\n◎登录状态:${codes}◎`);\n}\n\n\nfunction InvitationCode(c) {\n if (!source.getLoginHeaderMap()) return java.toast(\"未登录,请登录后获取\");\n \n let text = \"\";\n if (c) {\n java.post(ul + \"\/user\/user\/createinvitecode.html\", \"create_num=1\", \n {\"Cookie\": source.getLoginHeaderMap()[\"Cookie\"]});\n text += \"\\n已消耗50积分生成一个邀请码\";\n }\n \n const verify_list = org.jsoup.Jsoup.parse(java.ajax(ul + \"\/user\/user\/invitecode\")).select('.verify_list .item');\n java.log(\"\\n\" + String(verify_list.html()).replace(\/<[^>]+?>\\s*|复制| (?!\\d)\/g, \"\"));\n java.toast(text + \"\\n邀请码已打印至源日志\");\n}\n\nfunction AFBook(ta) {\n const info = result['书籍ID'];\n if (!info) return java.toast(\"\\n未填入书籍id,请进书籍详情页,或者手动填写。\");\n if (!source.getLoginHeaderMap()) return java.toast(\"未登录,请登录后使用\");\n \n try {\n let url;\n if (ta) {\n url = `${ul}\/user\/bookshelf\/add?novel_id=${info}`;\n } else {\n let src = \"\";\n for (let page = 1;; page++) {\n let sr = java.ajax(`${ul}\/user\/bookshelf\/index.html?page=${page}`);\n if (page === 2) java.log(sr);\n if (!\/书架空空如也\/.test(sr)) {\n src += sr + \"\\n\";\n } else break;\n }\n \n const booklist = src.match(\/\\\/novel\\\/\\d+\\.html\/g);\n const dfid = src.match(\/\\\/user\\\/bookshelf\\\/del\\\/id[^\"']+\/g);\n const index = booklist.findIndex(book => book.includes(info));\n if (index === -1) return java.toast('未找到书籍');\n url = GetUL() + dfid[index];\n }\n java.log(index + \"我的\")\n java.log(url)\n const msg = java.get(url, {\"x-requested-with\": \"XMLHttpRequest\"});\n java.toast(JSON.parse(msg.body()).msg);\n } catch (error) {\n \t java.log(error);\n java.toast('未知错误,已打印至日志');\n }\n}\n\nfunction BookShelf() {\n if (source.getLoginHeaderMap()) {\n java.startBrowser(`${ul}\/user\/bookshelf\/`, \"书架\");\n } else {\n java.toast(\"未登录,请登录后再使用此功能。\");\n }\n}",
"respondTime": 190259,
"ruleBookInfo": {
"author": "@get:{a}",
"canReName": "1",
"coverUrl": "@get:{i}\n@js:let url = \/^https?\/.test(result) ? result : GetUL() + result;\nresult = java.connect(url).code() == 200 ? url : 'https:\/\/img.321cdn.com\/img\/01.png';\nresult;",
"init": "<js>\nvar bookid = baseUrl.match(\/novel\\\/(\\d+)\/)[1];\n\/\/书评发送\nconst bookva = book.getVariable(\"custom\");\nif (bookva && bookva != \"\") {\n if (source.getLoginHeader()) {\n const commenturl = `${GetUL()}\/home\/comment\/add.html`;\n let body = `content=${bookva}&type=novel&mid=${bookid}`;\n \n try {\n const code = String(java.getVerificationCode(`data:image\/svg+xml;base64,${codesvg}`));\n \n if (code == \"评论\" || \/^@\\d+$\/.test(code)) {\n if (\/^@\\d+$\/.test(code)) {\n body += `&pid=${code.match(\/(\\d+)\/)[1]}`;\n }\n \n const headers = { \"x-requested-with\": \"XMLHttpRequest\" };\n const response = java.post(commenturl, body, headers).body();\n java.toast(JSON.parse(response).msg);\n } else {\n Packages.java.lang.Thread.sleep(40);\n java.toast('请按图片要求填写');\n }\n } catch (err) {\n java.log(err);\n }\n } else {\n java.toast(\"未登录,请登录后操作\");\n }\n book.putCustomVariable(\"\");\n}\n\ntry {\n sourceinfo = source.getLoginInfoMap();\n sourceinfo['书籍ID'] = bookid;\n if (bookid) {\n source.putLoginInfo(JSON.stringify(sourceinfo));\n }\n $ = _ => String(java.getString(_));\n img = \/^https?\/.test($('[property$=image]@content')) ? $('[property$=image]@content') : GetUL() + $('[property$=image]@content');\n list = {\n \"ID\": bookid,\n \"img\": img,\n \"name\": $('[property$=book_name]@content'),\n \"author\": $('[property$=author]@content'),\n \"info\": $('[property$=description]@content').slice(0, 45),\n \"url\": \"legado:\/\/import\/addToBookshelf?src=\" + baseUrl\n }\n source.put(\"list\", JSON.stringify(list));\n} catch (err) {\n java.log(\"登录UI未初始化保存数据:\" + err);\n}\nsrc;\n<\/js>\n@put:{\"n\":\"[property$=book_name]@content\",\n\"a\":\"[property$=author]@content\",\n\"t\":\"class.fix@p.2:-2@text##.*[::]\",\n\"k\":\"class.tg@a@ownText##\\n##,\",\n\"i\":\"[property$=image]@content\",\n\"l\":\"[property$=latest_chapter_name]@content\",\n\"r\":\"class.fix@p.3@text##\\\\s·\\\\s##\\n📂\",\n\"T\":\"[property$=update_time]@content\",\n\"m\":\"text.查看全部章节@href\",\n\"z\":\"class.fix@p.4@text##.*:(.*)·##$1###\",\n\"o\":\"[property$=description]@content\"}",
"intro": " 📖书籍ID:{{baseUrl.match(\/novel\\\/(\\d+)\/)[1]}}\n☑当前站源:{{GetUL()}}\n🔥@get:{r}\n🏷️标签:@get:{k}\n🕰️更新时间:@get:{T}\n📜简介:\n@get:{o}\n<js>\nconst Bookid = baseUrl.match(\/novel\\\/(\\d+)\/)[1];\nconst contul = `${GetUL()}\/index.php?s=\/Home\/comment\/lists\/id\/${Bookid}\/type\/novel\/limit\/5\/size\/12`;\nvar CommentNur = JSON.parse(source.getVariable()).co;\nvar cont = \"\";\nif (!CommentNur) {\n var src = java.ajax(contul);\n java.setContent(src);\n var list = java.getElement('\/\/script[@src=\"\/public\/static\/jquery\/jquery.min.js\"]\/following-sibling::script[1]');\n var lists = JSON.parse(String(list[0]).match(\/var\\s*trre=([\\s\\S]+),page_num\/)[1]);\n \/\/java.log(JSON.stringify(lists,null,\"\\t\"));\n\n cont += \"🔻评论区:\\n❗️右上角书籍变量填入评论后刷新详情页发送评论。❗️\\n\";\n if (lists.length > 0) {\n if (source.getLoginHeader()) {\n let jc = source.getLoginHeaderMap();\n let inf = decodeURIComponent(jc.get(\"Cookie\"));\n let info = decodeURIComponent(inf).match(\/\\{[\\s\\S]+\\}\/)[0];\n let myuid = JSON.parse(info)['uid'];\n \/\/处理我的评论数据\n var myComments = [];\n\n function collectMyComments(comment, parentPath) {\n let floor = parentPath ? `${parentPath}-${comment.floorIndex}` : comment.floorIndex;\n if (comment.uid === Number(myuid)) {\n myComments.push({\n id: comment.id,\n username: comment.user.username,\n group: comment.user.group,\n floor: `【${floor}楼】`,\n time: timeov(comment.create_time * 1000),\n content: comment.content\n });\n }\n if (comment._?.forEach) {\n comment._.forEach((child, index) => {\n child.floorIndex = index + 1;\n collectMyComments(child, floor);\n });\n }\n }\n lists.forEach((c, i) => {\n c.floorIndex = i + 1;\n collectMyComments(c, \"\");\n });\n \/\/java.log(JSON.stringify(myComments));\n var mySection = \"=== 我的评论(共找到\" + myComments.length + \"条) ===\\n\\n\";\n myComments.forEach(m => {\n mySection += `┌【ID:${m.id}】| 👤${m.username} | ${m.group} | ${m.time}\\n└评论:${m.content}\\n${m.floor}\\n `;\n });\n } else {\n mySection = \"\";\n }\n\n \/\/处理全部评论数据\n function buildComments(comment, parentPath, level) {\n let floor = parentPath ? `${parentPath}-${comment.floorIndex}` : comment.floorIndex;\n let indent = ' '.repeat(level);\n let str = `${indent}${parentPath ? \"│\" : \"\"}┌【ID:${comment.id}】|👤${comment.user?.username || \"\"} | ${comment.user?.group || \"已注销用户\"} | ${timeov(comment.create_time * 1000)}\\n` +\n `${indent}${parentPath ? \"│├\" : \"\"}评论:${comment.content}\\n` +\n `└─${indent}【${floor}楼】\\n`;\n\n if (comment._?.forEach) {\n comment._.forEach((child, index) => {\n child.floorIndex = index + 1;\n str += buildComments(child, floor, level + 1);\n });\n }\n return str;\n }\n\n var allSection = \"=== 全部评论(共\" + lists.length + \"条) ===\\n\\n\";\n lists.forEach((c, i) => {\n c.floorIndex = i + 1;\n allSection += buildComments(c, \"\", 0);\n });\n\n \/\/合并评论数据\n cont += mySection + \"\\n\" + allSection;\n } else {\n cont += \"本书暂时没有评论喔\";\n }\n}\nresult = result + \"\\n\" + cont;\nresult;\n<\/js>",
"kind": "@get:{t}\n@get:{k}",
"lastChapter": "@get:{l}◎@get:{T}",
"name": "@get:{n}",
"tocUrl": "@get:{m}\n@js: GetUL() + result;",
"wordCount": "@get:{z}"
},
"ruleContent": {
"content": "@js:\nvar url = GetUL();\n\/\/处理强制登录\nvar nn = String(cookie.getCookie(url));\nvar coks = nn.split('; ');\nvar ckk = coks.filter(item => !item.startsWith(\"lf_reader_num\")).join('; ');\ncookie.setCookie(url, ckk);\nconst chapterul = java.hexDecodeToString(src);\n\nfunction content() {\n let html = java.ajax(chapterul);\n let content = String(java.getString('.content_txt@html', html));\n return content.includes('正在获取小说信息') ? (eval('bookdata = ' + html.match(\/book\\.initial\\s*=\\s*({[\\s\\S]+?};)\/)[1]),getContent(bookdata)) : content;\n}\n\nconst text = content().trim();\n\nlet retryCount = 0;\nconst maxRetries = 3;\nlet result;\nwhile (retryCount < maxRetries) {\n if (text != \"\" && !\/正在加载小说中,请稍后\/.test(text)) {\n result = text;\n break;\n } else {\n retryCount++;\n java.toast(`\\n未获取到文本,正在重试...\\n(当前第${retryCount} \/ ${maxRetries}次重试)`);\n text = content();\n }\n}\nif (retryCount === maxRetries) {\n result = \"重试三次仍未获取到文本,请检查网络状况。\";\n}\nresult;",
"imageStyle": "DEFAULT",
"replaceRegex": "##\\n*{{chapter.title}}\\n*"
},
"ruleExplore": {
"author": ".four@text||.t4@text||a[href^=\"\/search\"]@text",
"bookList": ".novel-item||.rec_rullist > ul||.list-group-item",
"bookUrl": "a[href^=\"\/novel\/\"]@href\n@js: GetUL() + result;",
"coverUrl": "img@src\n@js: \/^https?\/.test(result) ? result : GetUL() + result;",
"intro": ".content-txt@text",
"kind": "{{@@.sev@text%%.six@text}}\n{{@@.t6@text}}\n{{@@.t5@text}}\n{{@@.mb-1@text##浏览:(.*)##$1浏览###}}\n{{@@.badges@text}}\n{{@@.datainfobox@p.0:-1@text##.*?:}}",
"lastChapter": ".datainfobox@p.-2@a@text||a[href^=\"\/book\/\"]@text",
"name": "a[href^=\"\/novel\/\"]@text##^\\d+?\\.|全文阅读$",
"wordCount": ".five@text||.mb-1@text||.datainfobox@p.2@ownText\n@js:\nif (\/search\/.test(baseUrl)) result = result.split(\/\\s|\\u3000\/)[1].replace(\/.*?:\/, \"\");\nresult;"
},
"ruleSearch": {
"author": ".mb-1 a@text",
"bookList": ".list-group-item",
"bookUrl": "a@href\n@js: GetUL() + result;",
"intro": ".content-txt@text",
"kind": "{{@@.mb-1@text##浏览:(.*)##$1浏览###}}\n{{@@a[href$=\"tag\"]@text%%small@text##\\[|\\]}}\n###",
"name": "h5 a@text##^\\d+\\.",
"wordCount": ".mb-1@text\n@js:result.split(\/\\s|\\u3000\/)[1].replace(\/.*?:\/, \"\");"
},
"ruleToc": {
"chapterList": "class.section-list@a",
"chapterName": "text",
"chapterUrl": "href\n<js>\nvar url = GetUL() + result;\nresult = `data:;base64,${java.base64Encode(url)},{\"type\":\"chapter\"}`;\nresult;\n<\/js>",
"preUpdateJs": "eval(String(source.loginUrl));\nvar sourceUL = GetUL();\nif (!String(book.bookUrl).includes(sourceUL)) {\n book.bookUrl = String(book.bookUrl).replace(\/https?:\\\/\\\/[^\\\/]+\/,sourceUL);\n book.tocUrl = String(book.tocUrl).replace(\/https?:\\\/\\\/[^\\\/]+\/,sourceUL);\n java.toast(\"\\n检测到切换源站,已更新目录链接。\");\n java.refreshTocUrl();\n}"
},
"searchUrl": "{{eval(String(source.loginUrl));GetUL();}}\/search.html?q={{key}}&f=_all&sort={{Sort_('search')}}&p={{page}}&serialize=",
"weight": 0
}