[
{
"bookSourceComment": "Linpx 书源(更新时间:2024-06-17)\n\n可用功能:✅搜索✅发现✅添加网址✅订阅源\n搜索小说:✅小说名称❌作者名称✅小说标签\n发现小说:❌推荐作者✅最近更新\n添加网址:✅Linpx链接✅Pixiv小说链接❌Pixiv系列小说链接\n订阅用法:点击订阅源打开小说,点击【添加到书架】按钮添加小说到书架\n\n书源发布:兽人阅读频道 https://t.me/FurryReading\n项目地址:https://github.com/windyhusky/PixivSource\n规则订阅:\nhttps://cdn.jsdelivr.net/gh/windyhusky/PixivSource@main/linpx.json\nhttps://raw.githubusercontent.com/windyhusky/PixivSource/main/linpx.json",
"bookSourceGroup": "🔞 Pixiv",
"bookSourceName": "Linpx",
"bookSourceType": 0,
"bookSourceUrl": "https://furrynovel.ink",
"bookUrlPattern": "(https?://)?(api.|www.)?(furrynovel.(ink|xyz)|pixiv.net)/.*",
"customOrder": 2,
"enabled": true,
"enabledCookieJar": false,
"enabledExplore": true,
"exploreUrl": "[\n {\n \"title\": \"推荐作者\",\n \"url\": \"https://api.furrynovel.ink/fav/user/cache\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\":0.3\n }\n },\n {\n \"title\": \"最新小说\",\n \"url\": \"https://api.furrynovel.ink/pixiv/novels/recent/cache?page={{page}}\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\":0.3\n }\n }\n]",
"header": "{\"referer\":\"https://furrynovel.ink/\"}",
"lastUpdateTime": 1718249291450,
"loginCheckJs": "var util = {}\n\nfunction objStringify(obj) {\n return JSON.stringify(obj, (n, v) => {\n if (typeof v == \"function\")\n return v.toString();\n return v;\n });\n}\n\nfunction publicFunc() {\n let u = {}\n\n u.cacheGetAndSet = function (key, supplyFunc) {\n let v = cache.get(key)\n if (v === undefined || v === null) {\n v = JSON.stringify(supplyFunc())\n // 缓存10分钟\n cache.put(key, v, 600)\n }\n return JSON.parse(v)\n }\n u.getAjaxJson = function (url) {\n return util.cacheGetAndSet(url, () => {\n return JSON.parse(java.ajax(url))\n })\n }\n u.getWebviewJson = function (url) {\n return util.cacheGetAndSet(url, () => {\n let html = java.webView(null, url, null)\n return JSON.parse((html.match(new RegExp(\">\\\\[\\\\{.*?}]<\"))[0].replace(\">\", \"\").replace(\"<\", \"\")))\n })\n }\n\n\n u.debugFunc = (func) => {\n if (String(source.getVariable()) === \"debug\") {\n func()\n }\n }\n\n u.urlNovelUrl = function (id){\n return `https://api.furrynovel.ink/pixiv/novel/${id}/cache`\n }\n u.urlSeriesUrl = function (id){\n return `https://api.furrynovel.ink/pixiv/series/${id}/cache`\n }\n u.urlUserUrl = function (id) {\n return `https://api.furrynovel.ink/pixiv/user/${id}/cache`\n }\n u.urlSearchNovel = function (novelname) {\n return `https://api.furrynovel.ink/pixiv/search/novel/${novelname}/cache`\n }\n u.urlSearchUsers = function (username) {\n return `https://api.furrynovel.ink/pixiv/search/user/${username}/cache`\n }\n u.urlNovelsDetailed = function (nidList) {\n return `https://api.furrynovel.ink/pixiv/novels/cache?${nidList.map(v => \"ids[]=\" + v).join(\"&\")}`\n }\n u.urlUserDetailed = function (uidList) {\n return `https://api.furrynovel.ink/pixiv/users/cache?${uidList.map(v => \"ids[]=\" + v).join(\"&\")}`\n }\n u.urlCoverUrl = function (pxImgUrl) {\n return `https://pximg.furrynovel.ink/?url=${pxImgUrl}&w=800`\n }\n u.urlIllustOriginalUrl = function (illustId) {\n // 使用 pixiv.cat 获取插图\n // return `https://pixiv.cat/${illustId}.png` // 已墙不可用\n return `https://pixiv.re/${illustId}.png`\n // return `https://pixiv.nl/${illustId}.png`\n }\n\n util = u\n java.put(\"util\", objStringify(u))\n}\n\npublicFunc()\n\n// 获取请求的user id方便其他ajax请求构造\nlet uid = java.getResponse().headers().get(\"x-userid\")\nif (uid != null) {\n cache.put(\"pixiv:uid\", uid)\n}\njava.getStrResponse(null, null)",
"loginUrl": "",
"respondTime": 180000,
"ruleBookInfo": {
"author": "author",
"coverUrl": "cover_url",
"init": "@js:\nvar util = objParse(String(java.get(\"util\")))\n\nfunction objParse(obj) {\n return JSON.parse(obj, (n, v) => {\n if (typeof v == \"string\" && v.match(\"()\")) {\n return eval(`(${v})`)\n }\n return v;\n })\n}\n\n(function (res) {\n result = {} //兼容搜索 for 循环\n result.novels = []\n // java.log(JSON.stringify(res))\n let isHtml = res.startsWith(\"\")\n if (isHtml) {\n let matchResult = baseUrl.match(new RegExp(\"pn|pixiv/novel|pixiv.net/novel\"))\n if (matchResult == null) {\n return []\n }\n let id = baseUrl.match(new RegExp(\"\\\\d+\"))[0]\n java.log(`匹配小说ID:${id}`)\n // res = util.getAjaxJson(util.urlNovelUrl(id))\n result.novels.push(util.getAjaxJson(util.urlNovelUrl(id)))\n } else {\n // 兼容 api 链接\n let isApiJson = baseUrl.match(new RegExp(\"pn|pixiv/novel|pixiv.net/novel\"))\n if (isApiJson && typeof(JSON.parse(res)) === \"object\") {\n result.novels.push(JSON.parse(res))\n } else {\n result = JSON.parse(res)\n if (result.total === 0) {\n return []\n }\n }\n }\n\n\n // api更新后,需要使用 for 循环\n for (let i in result.novels) {\n res = result.novels[i]\n let prop = {}\n //为了兼顾导入书架直接走详情页逻辑\n //这里不能直接用book.xxx 来复用搜索页处理结果\n prop.author = res.userName\n prop.tags = res.tags\n prop.count = res.length\n prop.desc = res.desc\n prop.cover_url = util.urlCoverUrl(res.coverUrl)\n\n if (res.series === undefined || res.series === null) {\n prop.name = res.title\n prop.tags.unshift('单本')\n // prop.catalog = `https://api.furrynovel.ink/pixiv/novel/${res.id}/cache`\n prop.catalog = util.urlNovelUrl(res.id)\n\n } else {\n prop.name = res.series.title\n prop.tags.unshift('长篇')\n // prop.catalog = `https://api.furrynovel.ink/pixiv/series/${res.series.id}/cache`\n prop.catalog = util.urlSeriesUrl(res.series.id)\n }\n prop.tags = prop.tags.join(\",\")\n return prop\n }\n})(result)\n",
"intro": "desc",
"kind": "tags",
"lastChapter": "latest_chapter",
"name": "name",
"tocUrl": "catalog",
"wordCount": "count"
},
"ruleContent": {
"content": "@js:\nvar util = objParse(String(java.get(\"util\")))\n\nfunction objParse(obj) {\n return JSON.parse(obj, (n, v) => {\n if (typeof v == \"string\" && v.match(\"()\")) {\n return eval(`(${v})`)\n }\n return v;\n })\n}\n\n(function (res) {\n res = JSON.parse(res)\n let content = res.content\n if (res.series !== null && res.desc !== undefined && res.desc !== \"\") {\n content = res.desc + \"\\n\" + \"——————————\\n\".repeat(2) + content\n }\n\n // 获取 [uploadedimage:] 的图片链接\n //将存在的pixiv图片链接替换为可访问的直连\n if (res.images !== undefined && res.images !== null) {\n Object.keys(res.images).forEach((key) => {\n content = content.replace(`[uploadedimage:${key}]`, ``)\n })\n }\n\n // // 获取 [pixivimage:] 的图片链接\n let rex = /\\[pixivimage:(\\d+)]/gm\n let matched = content.match(RegExp(rex))\n if (matched) {\n for (let i in matched) {\n let illustId = matched[i].match(RegExp(\"\\\\d+\"))\n content = content.replace(`${matched[i]}`, `
`)\n }\n }\n\n\n\n // 替换 Pixiv 分页标记符号 [newpage]\n matched = content.match(RegExp(/[ ]*\\[newpage][ ]*/gm))\n if (matched) {\n for (let i in matched){\n java.log(matched[i])\n content = content.replace(`${matched[i]}`, `${\"
\".repeat(3)}`)\n }\n }\n\n // 替换 Pixiv 章节标记符号 [chapter:]\n matched = content.match(RegExp(/\\[chapter:(.*?)]/gm))\n if (matched) {\n for (let i in matched) {\n let matched2 = matched[i].match(/\\[chapter:(.*?)]/m)\n let chapter = matched2[1].trim()\n // content = content.replace(`${matched[i]}`, `${\"
\".repeat(3)}${chapter}
`)\n content = content.replace(`${matched[i]}`, `${chapter}
`)\n }\n }\n\n // 替换 Pixiv 跳转页面标记符号 [[jump:]]\n matched = content.match(/\\[jump:(\\d+)]/gm)\n if (matched) {\n for (let i in matched) {\n let page = matched[i].match(/\\d+/)\n content = content.replace(`${matched[i]}`, `\\n\\n跳转至第${page}节`)\n }\n }\n\n // 替换 Pixiv 链接标记符号 [[jumpuri: > ]]\n matched = content.match(/\\[\\[jumpuri:(.*?)>(.*?)]]/gm)\n if (matched) {\n for (let i in matched) {\n let matched2 = matched[i].match(/\\[\\[jumpuri:(.*?)>(.*?)]]/m)\n let matchedText = matched2[0]\n let urlName = matched2[1].trim()\n let urlLink = matched2[2].trim()\n // 阅读不支持超链接\n //content = content.replace(`${matchedText}`, `${urlName}`)\n if (urlLink === urlName) {\n content = content.replace(`${matchedText}`, `${urlName}`)\n } else {\n content = content.replace(`${matchedText}`, `${urlName}: ${urlLink}`)\n }\n }\n }\n\n // 替换 Pixiv 注音标记符号 [[rb: > ]]\n matched = content.match(/\\[\\[rb:(.*?)>(.*?)]]/gm)\n if (matched) {\n for (let i in matched) {\n let matched2 = matched[i].match(/\\[\\[rb:(.*?)>(.*?)]]/m)\n let matchedText = matched2[0]\n let kanji = matched2[1].trim()\n let kana = matched2[2].trim()\n // kana为中文,则替换回《书名号》\n var reg = new RegExp(\"[\\\\u4E00-\\\\u9FFF]+\",\"g\");\n if (reg.test(kana)) {\n content = content.replace(`${matchedText}`, `${kanji}《${kana}》`)\n } else{\n // 阅读不支持