├── .github └── workflows │ ├── delete.yml │ └── update.yaml ├── README.md ├── books ├── Bot.json ├── Japan.json ├── bilinovel-like.json ├── bilinovel.json ├── esjzone.json ├── fishhawk.json ├── fqweb.json ├── lk-lightnovel-us.json ├── masiro.json ├── rezero.json ├── wenku.json └── zaimanhua.json ├── light-novel.js ├── light-novel.sh └── source ├── light-novel-web.json └── light-novel.json /.github/workflows/delete.yml: -------------------------------------------------------------------------------- 1 | name: Cleanup Old Workflows 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 0 * * 0' 7 | 8 | jobs: 9 | cleanup: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Delete releases and workflows runs 13 | uses: ophub/delete-releases-workflows@main 14 | with: 15 | delete_releases: false 16 | releases_keep_latest: 5 17 | delete_workflows: true 18 | workflows_keep_day: 10 19 | gh_token: ${{ secrets.GITHUB_TOKEN }} 20 | -------------------------------------------------------------------------------- /.github/workflows/update.yaml: -------------------------------------------------------------------------------- 1 | name: Update 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 0 * * 0' 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v3 14 | 15 | - name: Node.JS 16 | uses: actions/setup-node@v4 17 | 18 | - name: Update 19 | run: | 20 | chmod 777 -R * 21 | bash light-novel.sh 22 | 23 | - name: Push 24 | run: | 25 | git config --local user.name "github-actions[bot]" 26 | git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" 27 | git add . 28 | git diff-index --quiet HEAD || git commit -m "Update" 29 | git remote rm origin 30 | git remote add origin "https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}" 31 | git push -f -u origin main 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## [阅读自用轻小说书源(整合)](https://github.com/gedoor/legado) 2 | 3 | |类型|订阅链接| 4 | |---|---| 5 | |书源|https://raw.githubusercontent.com/MajoSissi/legado-source/main/source/light-novel.json| 6 | |订阅源|https://raw.githubusercontent.com/MajoSissi/legado-source/main/source/light-novel-web.json| 7 | -------------------------------------------------------------------------------- /books/Bot.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "bookSourceComment": "by·holzora", 4 | "bookSourceGroup": "轻小说", 5 | "bookSourceName": "机翻机器人", 6 | "bookSourceType": 0, 7 | "bookSourceUrl": "https://books.fishhawk.top", 8 | "bookUrlPattern": "(?:https?://)?books\\d?.fishhawk.top/(?:api/)?novel/\\w+/[\\w-]+", 9 | "customOrder": -41336, 10 | "enabled": true, 11 | "enabledCookieJar": false, 12 | "enabledExplore": true, 13 | "exploreUrl": "\ndiscover = [];\npush = (title, url, style) => discover.push({ title: title, url: url, style: { layout_flexGrow: 1, layout_flexBasisPercent: style } });\naddSlots = (count, style) => {\n remainder = count % 3;\n slotsAdd = remainder === 0 ? 0 : 3 - remainder;\n for (i = 0; i < slotsAdd; i++) {\n push(\"\", null, style);\n }\n};\npush(\"收藏夹\", null, 1);\ntry {\n favored = java.ajax(`${baseUrl}/api/user/favored`);\n if (favored.includes(\"Token不合法或者过期\")) {\n push(\"账号未登录\", null, 0.25);\n addSlots(1, 0.25);\n } else {\n favoredData = JSON.parse(favored).favoredWeb;\n favoredData.forEach(item => {\n push(item.title, `/api/user/favored-web/${item.id}?page={{(page-1)}}&pageSize=30&sort=update`, 0.25);\n });\n addSlots(favoredData.length, 0.25);\n }\n} catch (e) {\n push(\"未知错误\", null, 0.25);\n addSlots(1, 0.25);\n};\npush(\"来源\", null, 1);\nproviders = [\"全部\", \"kakuyomu\", \"syosetu\", \"novelup\", \"hameln\", \"pixiv\", \"alphapolis\"];\nproviders.forEach(provider => {\n url = provider === \"全部\" ? \n `/api/novel?page={{(page-1)}}&pageSize=20&query=&provider=${providers.slice(1).join('%2C')}&type=0&level=0&translate=0&sort=0` : \n `/api/novel?page={{(page-1)}}&pageSize=20&query=&provider=${provider}&type=0&level=0&translate=0&sort=0`;\n push(provider, url, 0.25);\n});\naddSlots(providers.length, 0.25);\npush(\"类型\", null, 1);\ntypes = [\"全部\", \"连载中\", \"已完结\", \"短篇\"];\ntypes.forEach((type, index) => {\n url = `/api/novel?page={{(page-1)}}&pageSize=20&query=&provider=kakuyomu%2Csyosetu%2Cnovelup%2Chameln%2Cpixiv%2Calphapolis&type=${index}&level=0&translate=0&sort=0`;\n push(type, url, 0.25);\n});\naddSlots(types.length, 0.25);\npush(\"排序\", null, 1);\nsorts = [\"更新\", \"点击\"];\nsorts.forEach((sort, index) => {\n url = `/api/novel?page={{(page-1)}}&pageSize=20&query=&provider=kakuyomu%2Csyosetu%2Cnovelup%2Chameln%2Cpixiv%2Calphapolis&type=0&level=0&translate=0&sort=${index}`;\n push(sort, url, 0.25);\n});\naddSlots(sorts.length, 0.25);\nJSON.stringify(discover);\n", 14 | "header": "\nheader = {\n \"Referer\": baseUrl\n};\nJSON.stringify(header);\n", 15 | "lastUpdateTime": 1743052461039, 16 | "loginUi": "[\n {\n \"name\": \"账号\",\n \"type\": \"text\"\n },\n {\n \"name\": \"密码\",\n \"type\": \"password\"\n }\n]", 17 | "loginUrl": "\nfunction login() {\n username = source.getLoginInfoMap().get(\"账号\");\n password = source.getLoginInfoMap().get(\"密码\");\n url = `${baseUrl}/api/auth/sign-in`;\n body = JSON.stringify({\n emailOrUsername: username,\n password: password\n });\n headers = {\n \"Content-Type\": \"application/json\"\n };\n response = java.post(url, body, headers);\n responseBody = response.body();\n authorizationObject = {\n Authorization: `Bearer ${responseBody}`\n };\n header = JSON.stringify(authorizationObject);\n source.putLoginHeader(header);\n}\nlogin();\n", 18 | "respondTime": 180000, 19 | "ruleBookInfo": { 20 | "author": "authors..name", 21 | "coverUrl": "", 22 | "init": "\nurl = book.bookUrl.includes('api/novel') ? book.bookUrl : book.bookUrl.replace('novel', 'api/novel');\nbody = book.bookUrl.includes('api/novel') ? result : java.ajax(url);\nif (body.includes('ID不合适,应当使用')) {\n match = body.match(/\\/\\w+\\/[\\w-]+/);\n url = `${book.origin}/api/novel${match}`;\n body = java.ajax(url);\n}\njava.put('url', url);\nbody\n", 23 | "intro": "\nvalue = String(book.getVariable(\"custom\")) || String(source.getVariable());\nresult = JSON.parse(result);\nintro = ['5', '8', '9'].includes(value) ? result.introductionJp : result.introductionZh || result.introductionJp;\ntimeStamp = '{{$.toc[-1].createAt}}' || '{{$.syncAt}}';\nintro = '  📬最近' + ('{{$.toc[-1].createAt}}' ? '更新' : '同步') + ':' + java.timeFormat(timeStamp * 1000) + '\\n‎\\n' + intro;\nintro\n", 24 | "kind": "{{$.type##中|已}},{{$.attentions}},{{$.keywords[:3]}}", 25 | "lastChapter": "", 26 | "name": "\nvalue = String(book.getVariable(\"custom\")) || String(source.getVariable());\nresult = JSON.parse(result);\nname = ['5', '8', '9'].includes(value) ? result.titleJp : result.titleZh || result.titleJp;\nname\n", 27 | "tocUrl": "{{java.get('url')}}", 28 | "wordCount": "totalCharacters" 29 | }, 30 | "ruleContent": { 31 | "content": "\nvalue = String(book.getVariable(\"custom\")) || String(source.getVariable());\nget = (value >= '1' && value <= '9') ? value : '1';\nconfig = {\n 1: 'sakuraParagraphs',\n 2: 'gptParagraphs',\n 3: 'youdaoParagraphs',\n 4: 'baiduParagraphs',\n 5: 'paragraphs'\n};\nresult = JSON.parse(result);\ncontent = result[config[get]] || result[config[2]] || result[config[3]] || result[config[4]] || result[config[5]];\nif (['6', '7', '8', '9'].includes(get)) {\n type = ['6', '8'].includes(get);\n jpContent = result[config[5]];\n cnContent = result[config[1]] || result[config[2]] || result[config[3]] || result[config[4]];\n if (cnContent) {\n content = jpContent.flatMap((jp, i) => (type ? [cnContent[i], jp] : [jp, cnContent[i]])).filter(Boolean);\n } else {\n content = jpContent;\n }\n};\nregex = content => {\n displayedImages = new Set();\n return JSON.stringify(content).replace(/<图片>(https?:\\/\\/[^\"\\s]+)/g, (_, p1) => {\n if (displayedImages.has(p1)) return '';\n displayedImages.add(p1);\n return '';\n });\n};\nformat = content => content.replace(/^\\[|\\]$/g, '').split(',').map(item => item.trim().replace(/^\"|\"$/g, '')).filter(Boolean).map((item, i) => item.startsWith('{\"headers\"') && i > 0 ? ',' + item : ' ' + item).join(\"\\n\");\nformat(regex(content));\n", 32 | "payAction": "", 33 | "replaceRegex": "", 34 | "title": "", 35 | "webJs": "" 36 | }, 37 | "ruleExplore": { 38 | "bookList": "", 39 | "intro": "" 40 | }, 41 | "ruleSearch": { 42 | "author": "", 43 | "bookList": "items", 44 | "bookUrl": "/api/novel/{{$.providerId}}/{{$..novelId}}", 45 | "checkKeyWord": "", 46 | "intro": "  源站:{{$.providerId}}{{'\\n'}}📬最近同步:{{java.timeFormat(java.getString('$.updateAt')*1000)}}{{'\\n'}}总计{{$.total}}|百度{{$.baidu}}|有道{{$.youdao}}|gpt{{$.gpt}}|sakura{{$.sakura}}", 47 | "kind": "{{$.type##中|已}},{{$.attentions}},{{$.keywords}}", 48 | "lastChapter": "", 49 | "name": "\nvalue = String(book.getVariable(\"custom\")) || String(source.getVariable());\nname = ['5', '8', '9'].includes(value) ? result.titleJp : result.titleZh || result.titleJp;\nname\n" 50 | }, 51 | "ruleToc": { 52 | "chapterList": "toc\n\nresult.forEach(item => {\n if ('chapterId' in item) {\n item.isVolume = false;\n item.url = `${baseUrl}/chapter/${item.chapterId}`;\n timeStamp = item.createAt ? item.createAt * 1000 : null;\n if (timeStamp) {\n item.time = java.timeFormat(timeStamp);\n } else {\n item.time = '';\n }\n } else {\n item.isVolume = true;\n }\n});\nresult\n", 53 | "chapterName": "\nvalue = String(book.getVariable(\"custom\")) || String(source.getVariable());\nname = ['5', '8', '9'].includes(value) ? result.titleJp : result.titleZh || result.titleJp;\nname\n", 54 | "chapterUrl": "url", 55 | "formatJs": "", 56 | "isPay": "", 57 | "isVolume": "isVolume", 58 | "updateTime": "time" 59 | }, 60 | "searchUrl": "\nproviders = {\n kakuyomu: /(?:https?:\\/\\/)?kakuyomu\\.jp\\/works\\/(\\d+)/,\n syosetu: /(?:https?:\\/\\/)?(ncode|novel18)\\.syosetu\\.com\\/(\\w+)/,\n novelup: /(?:https?:\\/\\/)?novelup\\.plus\\/story\\/(\\d+)/,\n hameln: /(?:https?:\\/\\/)?syosetu\\.org\\/novel\\/(\\d+)/,\n pixiv: /(?:https?:\\/\\/)?(www\\.pixiv\\.net\\/novel\\/series\\/(\\d+)|www\\.pixiv\\.net\\/novel\\/show\\.php\\?id=(\\d+))/,\n alphapolis: /(?:https?:\\/\\/)?www\\.alphapolis\\.co\\.jp\\/novel\\/(\\d+)\\/(\\d+)/,\n sakura: /(?:https?:\\/\\/)?books\\d?\\.fishhawk\\.top\\/(?:api\\/)?novel\\/(\\w+)\\/([\\w-]+)/\n};\nfor (provider in providers) {\n match = key.match(providers[provider]);\n if (match) {\n providerId = provider === 'sakura' ? match[1] : provider;\n novelId = provider === 'alphapolis' ? `${match[1]}-${match[2]}` : provider === 'pixiv' ? (match[3] ? `s${match[3]}` : match[2]) : (match[2] || match[1]);\n url = `${baseUrl}/api/novel/${providerId}/${novelId}`;\n break;\n } else {\n url = `${baseUrl}/api/novel?page=${page-1}&pageSize=20&query=${key}&provider=kakuyomu,syosetu,novelup,hameln,pixiv,alphapolis&type=0&level=0&translate=0&sort=1`;\n }\n url\n}\n", 61 | "variableComment": "输入对应数字刷新即可获取对应文本,{1: \"sakura译文\", 2: \"gpt译文\", 3: \"有道译文\", 4: \"百度译文\", 5: \"原文\", 6: \"中日\", 7: \"日中\", 8: \"5+6\", 9: \"5+7\"},默认sakura译文。书籍变量作用于一本书,源变量作用于整个书源,书籍变量优先级高于源变量。", 62 | "weight": 0 63 | } 64 | ] 65 | -------------------------------------------------------------------------------- /books/bilinovel-like.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "bookSourceComment": "建议登录\n\n酷安 @吉王义昊\nGitHub:https://github.com/jiwangyihao/source-j-legado\n\n# 关于许可的额外声明(在线版本参见 GitHub,以在线版本为准)\n\n- 当许可证与本声明冲突时,以本声明为准;\n- 对于本仓库中的任意代码片段:按照 `MPL 2.0` 中有关约定执行;\n- 对于本仓库中的某一完整书源的转载或二次开发,需满足以下全部条件:\n - 在[本仓库](https://github.com/jiwangyihao/source-j-legado)的 `issue` 中提出请求并具体说明转载地址、二次开发后的书源开源地址以及其他必要信息;\n - 等待原作者(即本仓库的初始所有者和初始代码贡献者 [@jiwangyihao](https://github.com/jiwangyihao))查看并通过 `issue` 或依据原作者要求更改转载方式或补充更详细的信息。\n - 考虑到本项目弃坑的可能,新 `issue` 开启后超过 20 个工作日原作者没有回复或者原作者回复要求更改的 `issue` 在更改后超过 20 个工作日原作者没有回复即视为原作者通过该 `issue`:\n - 此处的 `issue` 仅包括在[本仓库](https://github.com/jiwangyihao/source-j-legado)开启的,处于「开启状态」的 issue。(也就是说,请不要在已经关闭的 issue 中回复)。\n - 对于此种方式通过的 issue,转载/二次开发者仍应当遵守本声明中已经写明的相关约定。\n - 不得上传至源仓库或整理至`非轻小说专用`的书源合集中并应当避免其他人将转载/二次开发版本上传至源仓库或整理至`非轻小说专用`的书源合集中:\n - 关于轻小说的定义的额外说明:不包括国内的原创网络文学作品(如 `SF 轻小说` 中的原创轻小说以及`起点中文网`中标签包含轻小说的作品)。\n - 轻小说专用的定义:有且仅有想看轻小说的人可能会添加。\n - 必须在转载/二次开发地址的明显位置完整包含本声明的全部内容。\n - 必须保留源注释中原有的更改记录。", 4 | "bookSourceGroup": "轻小说,哔轻类似物", 5 | "bookSourceName": "轻之文库轻小说", 6 | "bookSourceType": 0, 7 | "bookSourceUrl": "https://m.wenkuchina.com", 8 | "bookUrlPattern": "", 9 | "concurrentRate": "", 10 | "coverDecodeJs": "", 11 | "customOrder": -41323, 12 | "enabled": true, 13 | "enabledCookieJar": true, 14 | "enabledExplore": true, 15 | "exploreUrl": "@js:\nres = []\n\n//筛选链接生成\nfunction generateFilterUrl(new_values) {\n values = {\n order: 'lastupdate',\n anime: '0',\n sortid: '0',\n typeid: '0',\n words: '0',\n rgroupid: '0',\n update: '0',\n isfull: '0',\n page: '{{page}}',\n }\n for (key in new_values) {\n \t values[key]=new_values[key]\n \t}\n return source.bookSourceUrl + '/wenku/' + values.order + '_' + values.anime + '_' + values.sortid + '_' + values.typeid + '_' + values.words + '_' + values.rgroupid + '_' + values.update + '_' + values.isfull + '_' + values.page + '.html';\n}\n\n//书架\nuser = ajax(source.bookSourceUrl + \"/user.php\")\n//java.toast(user)\ntry {\nif (user.match(/

(登录|错误).*轻之文库轻小说.+<\\/h2>/gi)) {\n //未登录\n res.push(\n {\n title: `>> 我的书架 | 未登录 <<`,\n url: '',\n style: { layout_flexGrow: 1, layout_flexBasisPercent: 1 }\n })\n} else {\n //已登录\n res.push(\n {\n title: `>> 我的书架 | ${user.match(/.+<\\/span>/gi)[0].replace(/<\\/?span.*?>/gi,'')} <<`,\n url: '',\n style: { layout_flexGrow: 1, layout_flexBasisPercent: 1 }\n })\n bookcase = ajax(source.bookSourceUrl + \"/bookcase.php\")\n bookcase.match(//gi)[0].match(//gi).forEach(option => {\n res.push(\n {\n title: option.match(/>.*(?=<)/gi)[0].replace('>', ''),\n url: source.bookSourceUrl + \"/bookcase.php?classid=\" + option.match(/value=\\\".+?(?=\\\")/gi)[0].replace(/(value=\\\")/gi, ''),\n style: { layout_flexGrow: 1 }\n })\n })\n}\n} catch (e) {\n throw(\"书架加载失败:\\n\"+e+\"\\n登录页源码:\\n\"+user)\n}\n\ncontent = ajax(source.bookSourceUrl + \"/wenku/\")\ncontent.match(/排序[\\s\\S]+?<\\/div>/gi)[0].match(//gi).forEach(a => {\n let filter = {}\n let sortTitle = a.match(/>.+(?=<)/gi)[0].replace('>', '')\n let type = \"order\"\n let value = a.match(/\\/[^_/]+(?=_)/gi)[0].replace('/', '')\n filter[type]=value;\n content.match(/作品分类[\\s\\S]+?<\\/div>/gi)[0].match(//gi).forEach((v, i) => {\n let v_type = \"anime\"\n let v_value = v.match(/\\/[^_/]+_\\d+(?=_)/gi)[0].replace(/\\/[^_/]+_/gi, '')\n filter[v_type]=v_value;\n if (i == 0) {\n res.push(\n {\n title: `>> 作品分类 | ${sortTitle} <<`,\n url: generateFilterUrl(filter),\n style: { layout_flexGrow: 1, layout_flexBasisPercent: 1 }\n })\n } else {\n res.push(\n {\n title: v.match(/>.+(?=<)/gi)[0].replace('>', ''),\n url: generateFilterUrl(filter),\n style: { layout_flexGrow: 1 }\n })\n }\n })\n})\n\ncontent.match(/排序[\\s\\S]+?重置/gi)[0].match(//gi).forEach(li => {\n let sortTitle = li.match(/>.+(?=<\\/h3>)/gi)[0].replace('>', '')\n res.push(\n {\n title: `>> ${sortTitle} <<`,\n url: '',\n style: { layout_flexGrow: 1, layout_flexBasisPercent: 1 }\n })\n li.match(//gi).forEach((v, i) => {\n if (i != 0) {\n res.push(\n {\n title: v.match(/>.+(?=<)/gi)[0].replace('>', ''),\n url: v.match(/href=\"[^\"]+(?=\")/gi)[0].replace('href=\"',\"\").replace(\"1.html\",\"{{page}}.html\"),\n style: { layout_flexGrow: 1 }\n })\n }\n })\n})\ntagContent = ajax(source.bookSourceUrl + \"/taglist/1.html\")\nres.push(\n {\n title: '>> 标签分类 <<',\n url: '',\n style: { layout_flexGrow: 1, layout_flexBasisPercent: 1 }\n })\ntry {\ntagContent.match(/标签分类<\\/h3>[\\s\\S]+?重置/gi)[0].match(//gi).forEach((v, i) => {\n res.push(\n {\n title: v.match(/>.+(?=<)/gi)[0].replace('>', '').replace(\" \",\"\"),\n url: v.match(/href=\"[^\"]+(?=\")/gi)[0].replace('href=\"',\"\").replace(\"1.html\",\"{{page}}.html\"),\n style: { layout_flexGrow: 1 }\n })\n})\n} catch (e) {\n throw(\"标签页解析错误:\"+e+\"\\n标签页源码:\\n\"+tagContent)\n}\nJSON.stringify(res)\n//throw(JSON.stringify(res))", 16 | "header": "{\n\"Referer\": \"https://m.wenkuchina.com/\",\n\"User-Agent\":\"\",\n\"Accept-Language\":\"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6\",\n\"Accept\":\"*/*\"\n}", 17 | "jsLib": "function errorReg() {\n return /(java.net.+Exception)|(okhttp.+Exception)|(error code: 1015)|(503 Service Temporarily Unavailable)|(Parse error.+in.+wwwroot.+php)|(_cf_chl_opt|challenges.css)|(.+不支持)|(章节内容不支持该浏览器显示)/gi\n}\nfunction ajax(url) {\n const { java, cookie } = this;\n let content = \"\";\n let time=1;\n \tcontent = java.ajax(url);\n \twhile (String(content).match(errorReg())) {\n if (time>10) {\n \t java.toast(\"重试10次后仍请求失败:\"+url)\n \t throw(\"重试10次后仍请求失败:\"+url+content)\n \t break;\n \t}\n \tif(!!String(content).match(/不支持/gi)) {\n //java.log(cookie.getCookie(url));\n cookie.replaceCookie(url,java.webView(null,url,\"document.cookie\"));\n \t}\n \tif (!!String(content).match(/_cf_chl_opt|challenges.css/gi)) {\n \t\t i = 1;\n \twhile (!!String(content).match(/_cf_chl_opt|challenges.css/gi)) {\n\t java.log('盾');\n\t java.log(content);\n if (i <= 1) {\n java.toast(\"哦呼,五秒盾,正在尝试静默破盾ing……\");\n content = java.webView(null,url,null);\n } else {\n java.toast(\"啊哦,静默破盾好像不管用,试试手动过校验吧!\");\n content = java.startBrowserAwait(url,\"加载完毕后点完成,此页面可能会弹出多次\").body();\n }\n i++;\n }\n continue;\n }\n \t\t java.log(\"请求失败:\"+url)\n \t\t java.log(\"重试\"+time+\"次\")\n \t\t let t=new Date().getTime()\n while (new Date().getTime() - t < 500) { }\n if (String(content).match(/1015|503|php/gi)) {\n \t while (new Date().getTime() - t < 5000) { }\n \t}\n \t\t content = java.ajax(url);\n \t\t time++;\n \t}\n \treturn String(content);\n}", 18 | "lastUpdateTime": 1717578188165, 19 | "loginUi": "[\n {\n \"name\": \"账号\",\n \"type\": \"text\"\n },\n {\n \"name\": \"密码\",\n \"type\": \"password\"\n }\n]", 20 | "loginUrl": "@js:\nfunction login() {\n let une = source.getLoginInfoMap().get(\"账号\")\n let pwd = source.getLoginInfoMap().get(\"密码\")\n if (une && pwd) {\n let body = String('username=' + une + '&password=' + pwd + '&usecookie=86400&act=login')\n let url = source.bookSourceUrl + '/login.php?do=submit'\n let res = java.post(url, body, {\n \"Content-Type\": \"application/x-www-form-urlencoded\"\n })\n let ck = res.cookies()\n if (res.body().match(/错误/gi)) {\n throw(res.body().match(/
[\\s\\S]+
/gi)[0].replace(/<.+>\\s*/gi,\"\"))\n }\n let header = JSON.stringify({\n \"Cookie\": String(ck).match(/\\{(.*?)\\}/)[1].replace(/,/g, ';')\n })\n source.putLoginHeader(header)\n }\n}", 21 | "respondTime": 180000, 22 | "ruleBookInfo": { 23 | "author": "[property=\"og:novel:author\"]@content", 24 | "canReName": "1", 25 | "coverUrl": "[property=\"og:image\"]@content", 26 | "intro": "标签:{{@@class.tag-small red@text##\\s## - }}\n{{@@id.bookSummary@tag.content@textNodes}}", 27 | "kind": "class.book-cell@tag.p.1@ownText&&class.tag-small red@text\n##.*万字|·.*", 28 | "lastChapter": "class.gray ell@text##(\\d+-\\d+-\\d+\\s\\d+:\\d+)·(.*)##$2 • $1", 29 | "name": "[property=\"og:novel:book_name\"]@content", 30 | "tocUrl": "class.btn-normal red@href", 31 | "wordCount": "class.book-cell@tag.p.1@ownText##连载|完结" 32 | }, 33 | "ruleContent": { 34 | "content": "id.acontent@html", 35 | "imageDecode": "", 36 | "imageStyle": "FULL", 37 | "nextContentUrl": "id.footlink@tag.a.-1@href\n@js:\n//121_2.html这样的是下一页,纯数字则是下一章\n//带有catalog是详情页\njava.log(\"url: \"+result)\nif (result==\"\") java.log(src)\nvar isNew=/(\\/(\\d+).html)|catalog/.test(result);\nvar out=isNew?'':result;\nout", 38 | "payAction": "", 39 | "replaceRegex": "##((?<=[\\u4e00-\\u9fa5“‘「(,])\\s+)?\\s*|((?<=[\\u4e00-\\u9fa5“‘「(,])\\s+)?\\(本章未完\\)\\s*|.+tmygod.+\\n", 40 | "title": "id.atitle@text" 41 | }, 42 | "ruleExplore": { 43 | "author": "class.book-author@ownText", 44 | "bookList": "@js:\ni = 1;\n\nif (String(src).match(errorReg())) {\n src=ajax(baseUrl);\n}\njava.setContent(src)\nresult = java.getElement(\"class.book-ol@tag.li\");\nresult;", 45 | "bookUrl": "a@href\n@js:\nresult.replace(/&cid=\\d+/gi, \"\")", 46 | "coverUrl": "img@data-src", 47 | "intro": "class.book-desc@text&&class.ell@text", 48 | "kind": "class.tag-small-group origin-right@tag.em.0@text&&\nclass.tag-small-group origin-right@tag.em.1@text&&\ntag.time@text\n@js:\nres=[]\nresult.forEach(item=>{\n item.split(new RegExp(\"[ \\/]\",\"gi\")).forEach(i=>res.push(i))\n})\nres", 49 | "name": "class.book-li@tag.img@alt", 50 | "wordCount": "class.tag-small blue@text" 51 | }, 52 | "ruleSearch": { 53 | "author": "class.book-author@textNodes", 54 | "bookList": "@js:\nif (String(result).match(errorReg())&&!result.includes(\"somework\")) {\n result=ajax(baseUrl);\n}\nif (result.includes(\"no-js\")) {\n java.log(result)\n jsContent = java.cacheFile(java.getString(\"tag.script@src\").match(/http.+somework.+\\?v.+/gi)[0])\n window = {\n a: result.match(/window.a=\\'.+\\'/gi)[0].replace(/window.a=|\\'/gi, ''),\n b: result.match(/window.b=\\'.+\\'/gi)[0].replace(/window.b=|\\'/gi, ''),\n c: result.match(/window.c=\\'.+\\'/gi)[0].replace(/window.c=|\\'/gi, ''),\n crypto: {\n subtle: {\n importKey(format, keyData, algorithm, extractable, keyUsages) {\n return {\n then(func) { func(keyData) }\n }\n },\n decrypt(algorithm, key, data) {\n cipher = java.createSymmetricCrypto(\"AES/CTR/NoPadding\", key, algorithm.counter)\n return {\n then: (func) => { func(cipher.decryptStr(data)) }\n }\n }\n }\n }\n }\n setTimeout = () => { }\n function TextDecoder() { }\n TextDecoder.prototype.decode = bytes => bytes\n document = { cookie: \"\" }\n java.log(jsContent)\n funcName=String(jsContent).match(/^function.+\\(/gi)[0].replace(/function| |\\(/gi,'')\n \tjava.log(funcName)\n eval(funcName + ' = str => java.base64DecodeToByteArray(str)')\n eval(String(jsContent)\n .replace(/^function.+\\(/gi, 'function ('))\n java.log(document.cookie)\n cookie.replaceCookie(baseUrl, document.cookie)\n do {\n t = new Date().getTime()\n while (new Date().getTime() - t < 5000) { }\n java.setContent(result = ajax(baseUrl + \",\"\n + JSON.stringify({\n headers: {\n Cookie: cookie.getCookie(baseUrl)\n }\n })))\n java.log(result)\n } while (result.includes(\"no-js\"))\n}\njava.getElement(\"class.book-ol book-ol-normal@tag.li\")", 55 | "bookUrl": "tag.a.0@href", 56 | "checkKeyWord": "我的青春恋爱喜剧", 57 | "coverUrl": "img@data-src", 58 | "intro": "class.book-desc@text", 59 | "kind": "class.tag-small-group origin-right@tag.em@text\n@js:\nres=[]\nresult.forEach(item=>{\n item.split(new RegExp(\"[ \\/]\",\"gi\")).forEach(i=>res.push(i))\n})\nres", 60 | "name": "class.book-title-x@class.book-title@text" 61 | }, 62 | "ruleToc": { 63 | "chapterList": "id.catelogX@class.chapter-li\n@js:\n //现实debug(尝试修复正文链接问题,和目录不全)\n //《好友角色的我怎么可能大受欢迎》第三卷12\n //《我的青春恋爱喜剧》\n //2022-8-19\n //原来的代码在源注释(已移除)\n //2022-8-20修复https://w.linovelib.com/novel/2765.html目录加载失败\n //2023-9-30使用易于理解的变量命名\n //2023-10-7处理cid(1)以及连续多个cid(0)\n //2023-11-11解决了一个原来手滑写出的bug\n //2023-11-16处理连续多个卷名\n //2023-12-12适配新版卷名\n //2024-2-6处理《谁说从妥协开始的恋爱一定没结果》\n\nres = result\n//java.log(res)\n\nfor (i = 0; i < res.length; i++) {\n java.setContent(res[i])\n if (java.getString(\"tag.a@href\").match(/javascript:cid\\(.+\\)/gi)) {\n if (String(res[(i == res.length - 1?i:i+1)]).match(/javascript:cid\\(.+\\)/gi)) {\n java.setContent(res[i - 1])\n prevLink = java.getString(\"tag.a@href\")\n if (prevLink == \"\") {\n java.setContent(res[i - 2])\n prevLink = java.getString(\"tag.a@href\")\n }\n content = ajax(source.bookSourceUrl + prevLink)\n java.setContent(content)\n foot = java.getElements(\"id.footlink\")\n path = prevLink\n\n //java.log(foot)\n while (String(foot).match(/下一页|下一頁/gi)) {\n \t //java.log(foot)\n str = content.match(/