[
{
"bookSourceComment": "Pixiv 书源(系列)(更新📆:2025-02-20)\n\n使用说明:两书源功能完全相同,启用其一即可 \n可用功能:✅搜索✅发现✅添加网址✅订阅源 \n搜索小说:✅单篇✅系列✅作者✅标签✅链接 \n发现小说:✅关注✅追更✅推荐✅发现✅收藏 \n添加网址:✅Pixiv 小说链接✅Pixiv 系列链接 \n搜索网址:✅Pixiv 链接✅Linpx 链接 \n订阅用法:点击订阅源打开小说/系列小说,【刷新】,点击【加入书架】按钮,添加小说到书架\n\n书源发布:兽人阅读频道 https://t.me/FurryReading\n项目地址:https://github.com/windyhusky/PixivSource\n使用教程:https://github.com/windyhusky/PixivSource/blob/main/doc/Pixiv.md\n\n规则订阅:Import 订阅源\nhttps://cdn.jsdelivr.net/gh/windyhusky/PixivSource@main/import.json\nhttps://raw.githubusercontent.com/windyhusky/PixivSource/main/import.json\n\n⚙️ 书源设置:\n书源管理 - 编辑书源 - 基本 - 变量说明 - 修改并保存\n\n❤️ 查看他人收藏:\n发现 - 长按\"Pixiv\" - 编辑 - 右上角菜单 - 设置源变量 \n设置源变量:输入作者ID,一行一个,可添加作者名,保存 \n发现 - 长按\"Pixiv\" - 刷新 - 查看他人收藏",
"bookSourceGroup": "🔞 Pixiv",
"bookSourceName": "Pixiv",
"bookSourceType": 0,
"bookSourceUrl": "https://www.pixiv.net/novel",
"bookUrlPattern": ".*(https?://)?(www\\.)?pixiv\\.net(/ajax)?/novel/(show\\.php\\?id=|series/)?\\d+.*",
"customOrder": 0,
"enabled": true,
"enabledCookieJar": false,
"enabledExplore": true,
"exploreUrl": "@js:\nlet SHOW_GENERAL_NOVELS_NEW, SHOW_GENERAL_NOVELS_RANK, SHOW_GENERAL_NOVELS_GENRE\ntry {\n settings = JSON.parse(String(source.variableComment).match(RegExp(/{([\\s\\S]*?)}/gm)))\n SHOW_GENERAL_NOVELS_NEW = settings.SHOW_GENERAL_NOVELS_NEW // 发现:最新、企划、约稿显示一般小说\n SHOW_GENERAL_NOVELS_RANK = settings.SHOW_GENERAL_NOVELS_RANK // 发现:排行榜显示一般小说\n SHOW_GENERAL_NOVELS_GENRE = settings.SHOW_GENERAL_NOVELS_RANK // 发现:热门分类显示一般小说\n} catch (e) {\n SHOW_GENERAL_NOVELS_NEW = false\n SHOW_GENERAL_NOVELS_RANK = false\n SHOW_GENERAL_NOVELS_GENRE = false\n}\n\nli = [\n {\"⭐️ 关注\": \"https://www.pixiv.net/ajax/follow_latest/novel?p={{page}}&mode=all&lang=zh\"},\n {\"📃 追更\": \"https://www.pixiv.net/ajax/watch_list/novel?p={{page}}&new=1&lang=zh\"},\n {\"💯 推荐\": \"https://www.pixiv.net/ajax/top/novel?mode=all&lang=zh\"},\n {\"🔍 发现\": \"https://www.pixiv.net/ajax/novel/discovery?mode=all\"},\n {\"❤️ 收藏\": \"https://www.pixiv.net/ajax/user/{{cache.get(\\\"pixiv:uid\\\")}}/novels/bookmarks?tag=&offset={{(page-1)*24}}&limit=24&rest=show&lang=zh\"},\n {\"🏷️ 书签\": \"https://www.pixiv.net/novel/marker_all.php\"},\n {\"🏠 首页\": \"https://www.pixiv.net\"},\n {\"📝 编辑\": \"https://www.pixiv.net/novel/editors_picks\"}\n]\n\nr18New = [\n {\"🆕 最新 企划 约稿 💰\": \"\"},\n {\"🆕 最新\": \"https://www.pixiv.net/ajax/novel/new?lastId=0&limit=20&r18=true&lang=zh\"},\n {\"📑 企划\": \"https://www.pixiv.net/ajax/user_event/portal/novels?mode=r18&p={{page}}&lang=zh\"},\n {\"💰 约稿\": \"https://www.pixiv.net/ajax/commission/page/request/complete/novels?mode=r18&p={{page}}&lang=zh\"},\n]\n\ngeneralNew = [\n {\"🆙 最新 企划 约稿 💰\": \"\"},\n {\"🆙 最新\": \"https://www.pixiv.net/ajax/novel/new?lastId=0&limit=20&r18=false&lang=zh\"},\n {\"📄 企划\": \"https://www.pixiv.net/ajax/user_event/portal/novels?mode=&p={{page}}&lang=zh\"},\n {\"💰 约稿\": \"https://www.pixiv.net/ajax/commission/page/request/complete/novels?mode=all&p={{page}}&lang=zh\"}\n]\n\nr18Rank = [\n {\"👑 排行榜单 👑\": \"\"},\n {\"今日\": \"https://www.pixiv.net/novel/ranking.php?mode=daily_r18\"},\n {\"本周\": \"https://www.pixiv.net/novel/ranking.php?mode=weekly_r18\"},\n {\"R18G\": \"https://www.pixiv.net/novel/ranking.php?mode=r18g\"},\n {\"男性\": \"https://www.pixiv.net/novel/ranking.php?mode=male_r18\"},\n {\"女性\": \"https://www.pixiv.net/novel/ranking.php?mode=female_r18\"}\n]\n\ngeneralRank = [\n {\"🔝 排行榜单 🔝\": \"\"},\n {\"今日\": \"https://www.pixiv.net/novel/ranking.php?mode=daily\"},\n {\"本周\": \"https://www.pixiv.net/novel/ranking.php?mode=weekly\"},\n {\"本月\": \"https://www.pixiv.net/novel/ranking.php?mode=monthly\"},\n {\"男性\": \"https://www.pixiv.net/novel/ranking.php?mode=male\"},\n {\"女性\": \"https://www.pixiv.net/novel/ranking.php?mode=female\"},\n {\"新人\": \"https://www.pixiv.net/novel/ranking.php?mode=rookie\"},\n {\"原创\": \"https://www.pixiv.net/novel/ranking.php?mode=weekly_original\"},\n {\"AI生成\": \"https://www.pixiv.net/novel/ranking.php?mode=weekly_ai\"}\n]\n\nr18Genre = [\n {\"🔥 原创热门 🔥\": \"\"},\n {\"男性\": \"https://www.pixiv.net/ajax/genre/novel/male?mode=r18&lang=zh\"},\n {\"女性\": \"https://www.pixiv.net/ajax/genre/novel/female?mode=r18&lang=zh\"},\n {\"恋爱\": \"https://www.pixiv.net/ajax/genre/novel/romance?mode=r18&lang=zh\"},\n {\"异世界奇幻\": \"https://www.pixiv.net/ajax/genre/novel/isekai_fantasy?mode=r18&lang=zh\"},\n {\"现代奇幻\": \"https://www.pixiv.net/ajax/genre/novel/contemporary_fantasy?mode=r18&lang=zh\"},\n {\"悬疑\": \"https://www.pixiv.net/ajax/genre/novel/mystery?mode=r18&lang=zh\"},\n {\"恐怖\": \"https://www.pixiv.net/ajax/genre/novel/horror?mode=r18&lang=zh\"},\n {\"科幻\": \"https://www.pixiv.net/ajax/genre/novel/sci-fi?mode=r18&lang=zh\"},\n {\"文学\": \"https://www.pixiv.net/ajax/genre/novel/literature?mode=r18&lang=zh\"},\n {\"情感\": \"https://www.pixiv.net/ajax/genre/novel/drama?mode=r18&lang=zh\"},\n {\"历史\": \"https://www.pixiv.net/ajax/genre/novel/historical_pieces?mode=r18&lang=zh\"},\n {\"耽美\": \"https://www.pixiv.net/ajax/genre/novel/bl?mode=r18&lang=zh\"},\n {\"百合\": \"https://www.pixiv.net/ajax/genre/novel/yuri?mode=r18&lang=zh\"},\n {\"散文·诗歌\": \"https://www.pixiv.net/ajax/genre/novel/poetry?mode=r18&lang=zh\"},\n {\"随笔·纪实\": \"https://www.pixiv.net/ajax/genre/novel/non-fiction??mode=r18&lang=zh\"},\n {\"剧本\": \"https://www.pixiv.net/ajax/genre/novel/screenplays?mode=r18&lang=zh\"},\n {\"评论\": \"https://www.pixiv.net/ajax/genre/novel/reviews?mode=r18&lang=zh\"},\n {\"其他\": \"https://www.pixiv.net/ajax/genre/novel/other?mode=r18&lang=zh\"}\n]\n\ngeneralgGenre = [\n {\"❤️🔥 原创热门 ❤️🔥\": \"\"},\n {\"综合\": \"https://www.pixiv.net/ajax/genre/novel/all?mode=safe&lang=zh\"},\n {\"恋爱\": \"https://www.pixiv.net/ajax/genre/novel/romance?mode=safe&lang=zh\"},\n {\"异世界奇幻\": \"https://www.pixiv.net/ajax/genre/novel/isekai_fantasy?mode=safe&lang=zh\"},\n {\"现代奇幻\": \"https://www.pixiv.net/ajax/genre/novel/contemporary_fantasy?mode=safe&lang=zh\"},\n {\"悬疑\": \"https://www.pixiv.net/ajax/genre/novel/mystery?mode=safe&lang=zh\"},\n {\"恐怖\": \"https://www.pixiv.net/ajax/genre/novel/horror?mode=safe&lang=zh\"},\n {\"科幻\": \"https://www.pixiv.net/ajax/genre/novel/sci-fi?mode=safe&lang=zh\"},\n {\"文学\": \"https://www.pixiv.net/ajax/genre/novel/literature?mode=safe&lang=zh\"},\n {\"情感\": \"https://www.pixiv.net/ajax/genre/novel/drama?mode=safe&lang=zh\"},\n {\"历史\": \"https://www.pixiv.net/ajax/genre/novel/historical_pieces?mode=safe&lang=zh\"},\n {\"耽美\": \"https://www.pixiv.net/ajax/genre/novel/bl?mode=safe&lang=zh\"},\n {\"百合\": \"https://www.pixiv.net/ajax/genre/novel/yuri?mode=safe&lang=zh\"},\n {\"散文·诗歌\": \"https://www.pixiv.net/ajax/genre/novel/poetry?mode=safe&lang=zh\"},\n {\"随笔·纪实\": \"https://www.pixiv.net/ajax/genre/novel/non-fiction??mode=safe&lang=zh\"},\n {\"剧本\": \"https://www.pixiv.net/ajax/genre/novel/screenplays?mode=safe&lang=zh\"},\n {\"评论\": \"https://www.pixiv.net/ajax/genre/novel/reviews?mode=safe&lang=zh\"},\n {\"其他\": \"https://www.pixiv.net/ajax/genre/novel/other?mode=safe&lang=zh\"}\n]\n\nbookmarks = [{\"❤️ 他人收藏 ❤️\": \"\"}]\n\nli = li.concat(r18New)\nli = li.concat(r18Rank)\nli = li.concat(r18Genre)\nif (SHOW_GENERAL_NOVELS_NEW === true) {\n li = li.concat(generalNew)\n}\nif (SHOW_GENERAL_NOVELS_RANK === true) {\n li = li.concat(generalRank)\n}\nif (SHOW_GENERAL_NOVELS_GENRE === true) {\n li = li.concat(generalgGenre)\n}\n\ntry {\n authors = String(source.getVariable()).split(\"\\n\")\n if (authors[0].trim() !== \"\" && authors.length >= 1) {\n for (let i in authors) {\n if (authors[i] !== \"\") {\n let authorId = authors[i].match(RegExp(/\\d+/))[0]\n let resp = JSON.parse(java.ajax(`https://www.pixiv.net/ajax/user/${authorId}`))\n if (resp.error !== true) {\n let bookmark = {}\n bookmark[resp.body.name] = `https://www.pixiv.net/ajax/user/${authorId}/novels/bookmarks?tag=&offset={{(page-1)*24}}&limit=24&rest=show&lang=zh`\n bookmarks.push(bookmark)\n }\n }\n }\n li = li.concat(bookmarks)\n }\n} catch (e) {\n java.longToast(\"源变量设置有误\")\n}\n\nli.forEach(item => {\n item.title = Object.keys(item)[0]\n item.url = Object.values(item)[0]\n delete item[Object.keys(item)[0]]\n item.style = {}\n item.style.layout_flexGrow = 1\n item.style.layout_flexShrink = 1\n item.style.layout_alignSelf = \"auto\"\n item.style.layout_wrapBefore = \"false\"\n if (item.url === \"\") {\n item.style.layout_flexBasisPercent = 1\n } else {\n item.style.layout_flexBasisPercent = -1\n }\n})\n\nJSON.stringify(li)",
"header": "{\"referer\":\"https://www.pixiv.net\"}",
"lastUpdateTime": 1739980800251,
"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 = {}, settings = {}\n java.log(String(source.bookSourceComment).split(\"\\n\")[0]) // 输出书源信息\n java.log(`手动更新时间:${java.timeFormat(source.lastUpdateTime)}`) // 输出书源信息\n settings = JSON.parse(String(source.variableComment).match(RegExp(/{([\\s\\S]*?)}/gm)))\n if (settings !== null) {\n java.log(\"⚙️ 使用自定义设置\")\n } else {\n settings = {}\n settings.SHOW_ORIGINAL_NOVEL_LINK = true\n settings.REPLACE_BOOK_TITLE_MARKS = true\n settings.MORE_INFO_IN_DESCRIPTION = false\n settings.SHOW_NOVEL_CAPTIONS = true\n settings.SHOW_NOVEL_COMMENTS = true\n settings.DEBUG = false\n java.log(\"⚙️ 使用默认设置(无自定义设置 或 自定义设置有误)\")\n }\n u.SHOW_ORIGINAL_NOVEL_LINK = settings.SHOW_ORIGINAL_NOVEL_LINK // 目录处显示小说源链接,但会增加请求次数\n u.REPLACE_BOOK_TITLE_MARKS = settings.REPLACE_BOOK_TITLE_MARKS // 注音内容为汉字时,替换为书名号\n u.MORE_INFO_IN_DESCRIPTION = settings.MORE_INFO_IN_DESCRIPTION // 书籍简介显示更多信息\n u.SHOW_NOVEL_CAPTIONS = settings.SHOW_NOVEL_CAPTIONS // 书籍简介显示更多信息\n u.SHOW_NOVEL_COMMENTS = settings.SHOW_NOVEL_COMMENTS // 书籍简介显示更多信息\n u.DEBUG = settings.DEBUG // 调试模式\n\n if (u.DEBUG === true) {\n java.log(JSON.stringify(settings, null, 4))\n java.log(`DEBUG = ${u.DEBUG}`)\n }\n\n\n u.debugFunc = (func) => {\n if (util.DEBUG) {\n func()\n }\n }\n u.cacheGetAndSet = (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 = (url) => {\n return util.cacheGetAndSet(url, () => {\n return JSON.parse(java.ajax(url))\n })\n }\n u.getWebviewJson = (url, parseFunc) => {\n return util.cacheGetAndSet(url, () => {\n let html = java.webView(null, url, null)\n return JSON.parse(parseFunc(html))\n })\n }\n\n u.urlNovelUrl = (novelId) => {\n return `https://www.pixiv.net/novel/show.php?id=${novelId}`\n }\n u.urlNovelDetailed = (novelId) => {\n return `https://www.pixiv.net/ajax/novel/${novelId}`\n }\n u.urlNovelsDetailed = (userId, nidList) => {\n return `https://www.pixiv.net/ajax/user/${userId}/novels?${nidList.map(v => \"ids[]=\" + v).join(\"&\")}`\n }\n u.urlNovelComments = (novelId, offset, limit) => {\n return `https://www.pixiv.net/ajax/novels/comments/roots?novel_id=${novelId}&offset=${offset}&limit=${limit}&lang=zh`\n }\n u.urlNovelCommentsReply = (commentId, page) => {\n return `https://www.pixiv.net/ajax/novels/comments/replies?comment_id=${commentId}&page=${page}&lang=zh`\n }\n u.urlNovel = (novelId) => {\n if (util.SHOW_ORIGINAL_NOVEL_LINK) {\n return util.urlNovelUrl(novelId)\n } else {\n return util.urlNovelDetailed(novelId)\n }\n }\n\n u.urlSeriesUrl = (seriesId) => {\n return `https://www.pixiv.net/novel/series/${seriesId}`\n }\n u.urlSeriesDetailed = (seriesId) => {\n return `https://www.pixiv.net/ajax/novel/series/${seriesId}?lang=zh`\n }\n u.urlSeriesNovels = (seriesId, limit, offset) => {\n if (limit > 30) {\n limit = 30\n }\n if (limit < 10) {\n limit = 10\n }\n return `https://www.pixiv.net/ajax/novel/series_content/${seriesId}?limit=${limit}&last_order=${offset}&order_by=asc&lang=zh`\n }\n u.urlSeries = (seriesId) => {\n if (util.SHOW_ORIGINAL_NOVEL_LINK) {\n return util.urlSeriesUrl(seriesId)\n } else {\n return util.urlSeriesDetailed(seriesId)\n }\n }\n\n u.urlUserUrl = (userId) => {\n return `https://www.pixiv.net/users/${userId}`\n }\n u.urlUserDetailed = (userId) => {\n return `https://www.pixiv.net/ajax/user/${userId}`\n }\n u.urlUserAllWorks = (userId) => {\n return `https://www.pixiv.net/ajax/user/${userId}/profile/all?lang=zh`\n }\n\n u.urlSearchNovel = (novelName, page) =>{\n return `https://www.pixiv.net/ajax/search/novels/${encodeURI(novelName)}?word=${encodeURI(novelName)}&order=date_d&mode=all&p=${page}&s_mode=s_tag&lang=zh`\n }\n u.urlSearchSeries = (seriesName, page) => {\n return`https://www.pixiv.net/ajax/search/novels/${encodeURI(seriesName)}?word=${encodeURI(seriesName)}&order=date_d&mode=all&p=${page}&s_mode=s_tag&gs=1&lang=zh`\n }\n // 完全匹配用户名\n u.urlSearchUser = (userName) => {\n return `https://www.pixiv.net/search/users?nick=${encodeURI(userName)}&s_mode=s_usr&nick_mf=1`\n }\n\n u.urlCoverUrl = (url) => {\n return `${url}, {\"headers\": {\"Referer\":\"https://www.pixiv.net/\"}}`\n }\n u.urlIllustUrl = (illustId) => {\n return `https://www.pixiv.net/artworks/${illustId}`\n }\n u.urlIllustDetailed = (illustId) => {\n return `https://www.pixiv.net/ajax/illust/${illustId}?lang=zh`\n }\n u.urlIllustOriginal = (illustId, order) => {\n let illustOriginal = util.getAjaxJson(util.urlIllustDetailed(illustId)).body.urls.original\n if (order >= 1) {\n illustOriginal = illustOriginal.replace(`_p0`, `_p${order - 1}`)\n }\n return illustOriginal\n }\n\n u.urlSeriesIllustsUrl = (userId, seriesId) => {\n return `https://www.pixiv.net/user/${userId}/series/${seriesId}`\n }\n u.urlSeriesIllustsDetailed = (seriesId) => {\n return `https://www.pixiv.net/ajax/series/${seriesId}?p=1&lang=zh`\n }\n\n // 将多个长篇小说解析为一本书\n u.combineNovels = function (novels) {\n return novels.filter(novel => {\n // 单本直接解析为一本书\n if (novel.seriesId === undefined || novel.seriesId === null) {\n return true\n }\n // 集合中没有该系列解析为一本书\n if (!seriesSet.has(novel.seriesId)) {\n seriesSet.add(novel.seriesId)\n return true\n }\n return false\n })\n }\n\n // 处理 novels 列表\n u.handNovels = function (novels) {\n novels.forEach(novel => {\n // 处理正文 tag\n if (!(novel.tags instanceof Array)) {\n novel.tags = novel.tags.tags.map(item => item.tag)\n novel.updateDate = novel.uploadDate\n if (novel.seriesNavData !== null){\n novel.seriesId = novel.seriesNavData.seriesId\n }\n }\n if (novel.tags === undefined || novel.tags === null) {\n novel.tags = []\n }\n // novel.id = novel.id\n // novel.title = novel.title\n // novel.userName = novel.userName\n if (novel.isOneshot !== undefined) { // 搜索系列\n if (novel.isOneshot === true) {\n novel.seriesId = undefined\n novel.id = novel.novelId // 获取真正的 novelId\n } else { //系列\n novel.seriesId = novel.id // 获取系列小说id\n // novel.id = novel.latestEpisodeId // 最近一篇\n }\n novel.textCount = novel.textLength\n novel.description = novel.caption\n try {\n novel.coverUrl = novel.cover.urls[\"480mw\"]\n } catch (e) { // 可能 novel.cover === null\n novel.coverUrl = \"\"\n }\n if (novel.createDate === undefined) { // 兼容搜索作者获取获取系列小说\n novel.createDate = novel.createDateTime\n novel.updateDate = novel.updateDateTime\n }\n\n } else { // 搜索作者,发现排行榜\n // novel.textCount = novel.textCount\n // novel.description = novel.description\n if (novel.coverUrl === undefined) { // 兼容发现排行榜\n novel.coverUrl = novel.url\n }\n // novel.createDate = novel.createDate\n // novel.updateDate = novel.updateDate\n }\n\n if (novel.seriesId === undefined || novel.seriesId === null) { // 单篇\n novel.tags.unshift(\"单本\")\n novel.latestChapter = novel.title\n novel.detailedUrl = util.urlNovelDetailed(novel.id)\n } else { // 系列\n // novel.seriesId = novel.seriesId\n let series = util.getAjaxJson(util.urlSeriesDetailed(novel.seriesId)).body\n novel.id = series.firstNovelId\n novel.title = series.title\n // novel.userName = novel.userName\n novel.tags = series.tags\n novel.textCount = series.publishedTotalCharacterCount\n // novel.lastChapter = util.getAjaxJson(util.urlNovelDetailed(series.lastNovelId)).body.title\n novel.description = series.caption\n novel.coverUrl = series.cover.urls[\"480mw\"]\n novel.detailedUrl = util.urlSeriesDetailed(novel.seriesId)\n\n // 发送请求获取第一章 获取标签与简介\n let firstNovel = {}\n try {\n firstNovel = util.getAjaxJson(util.urlNovelDetailed(series.firstNovelId)).body\n novel.tags = novel.tags.concat(firstNovel.tags.tags.map(item => item.tag))\n } catch (e) { // 防止系列首篇无权限获取\n try {\n firstNovel = util.getAjaxJson(util.urlSeriesNovels(novel.seriesId, 30, 0)).body.thumbnails.novel[0]\n novel.id = novel.firstNovelId = firstNovel.id\n novel.tags = novel.tags.concat(firstNovel.tags)\n } catch (e) { // 防止系列首篇无权限获取\n firstNovel = {}\n firstNovel.description = \"\"\n }\n }\n novel.tags.unshift(\"长篇\")\n novel.tags = Array.from(new Set(novel.tags))\n if (novel.description === \"\") {\n novel.description = firstNovel.description\n }\n }\n })\n util.debugFunc(() => {\n java.log(`处理小说完成`)\n })\n return novels\n }\n\n // 小说信息格式化\n u.formatNovels = function (novels) {\n novels.forEach(novel => {\n novel.title = novel.title.replace(RegExp(/^\\s+|\\s+$/g), \"\")\n novel.tags = novel.tags.join(\",\")\n novel.coverUrl = this.urlCoverUrl(novel.coverUrl)\n novel.readingTime = `${novel.readingTime / 60} 分钟`\n novel.createDate = this.dateFormat(novel.createDate);\n novel.updateDate = this.dateFormat(novel.updateDate);\n if (util.MORE_INFO_IN_DESCRIPTION) {\n novel.description = `\\n书名:${novel.title}\\n作者:${novel.userName}\\n标签:${novel.tags}\\n上传:${novel.createDate}\\n更新:${novel.updateDate}\\n简介:${novel.description}`\n } else {\n novel.description = `\\n${novel.description}\\n上传时间:${novel.createDate}\\n更新时间:${novel.updateDate}`\n }\n })\n return novels\n }\n\n // 正文,搜索:从网址获取id,返回单篇小说 res,系列返回首篇小说 res\n u.getNovelRes = function (result) {\n let novelId = 0, seriesId = 0, res = {}\n // 兼容搜索直接输入链接\n pattern = \"(https?://)?(api\\\\.|www\\\\.)?((furrynovel\\\\.(ink|xyz))|pixiv\\\\.net)(/ajax)?/(pn|(pixiv/)?novel)/(show\\\\.php\\\\?id=|series/)?\\\\d+(/cache)?\"\n // pattern = String(bookSourceUrl).replace(\".*\", \"\")\n if (RegExp(pattern).test(result) && !(result.startsWith(\"\"))) {\n baseUrl = result.match(RegExp(pattern))[0]\n result = \"\"\n java.log(`匹配链接:${baseUrl}`)\n }\n\n let isHtml = result.startsWith(\"\")\n if (isHtml) {\n let id = baseUrl.match(new RegExp(\"\\\\d+\"))[0]\n let pattern = \"(https?://)?(www\\\\.)?pixiv\\\\.net(/ajax)?/novel/(series/)?\\\\d+\"\n let isSeries = baseUrl.match(new RegExp(pattern))\n if (isSeries) {\n java.log(`系列ID:${id}`)\n seriesId = id\n } else {\n let pattern = \"((furrynovel\\\\.(ink|xyz))|pixiv\\\\.net)/(pn|(pixiv/)?novel)/(show\\\\.php\\\\?id=)?\\\\d+\"\n let isNovel = baseUrl.match(new RegExp(pattern))\n if (isNovel) {\n res = util.getAjaxJson(util.urlNovelDetailed(id))\n novelId = id\n }\n }\n } else {\n res = JSON.parse(result)\n }\n\n if (res.body !== undefined && res.body.firstNovelId !== undefined && res.body.firstNovelId !== null) {\n seriesId = res.body.seriesNavData.seriesId\n }\n if (seriesId) { // 防止系列首篇无权限获取\n res = util.getAjaxJson(util.urlSeriesNovels(seriesId, 30, 0))\n res.body = res.body.thumbnails.novel[0]\n novelId = res.body.id\n }\n java.log(`匹配小说ID:${novelId}`)\n if (res.error === true) {\n java.log(`无法从 Pixiv 获取当前小说`)\n java.log(JSON.stringify(res))\n return {}\n }\n return res.body\n }\n\n // 详情、目录:从网址获取id,尽可能返回系列 res,单篇小说返回小说 res\n u.getNovelResSeries = function (result) {\n let seriesId = 0, res = {}\n // 兼容详情,添加网址直接输入链接\n // pixiv 默认分享信息中有 # 号,不会被识别成链接,无法使用添加网址\n // baseUrl = baseUrl.replace(\"#\", \"%23\")\n pattern = \"(https?://)?(api\\\\.|www\\\\.)?((furrynovel\\\\.(ink|xyz))|pixiv\\\\.net)(/ajax)?/(pn|(pixiv/)?novel)/(show\\\\.php\\\\?id=|series/)?\\\\d+(/cache)?\"\n // pattern = String(bookSourceUrl).replace(\".*\", \"\")\n if (!(result.startsWith(\"\")) && JSON.parse(result).error === true && RegExp(pattern).test(baseUrl)) {\n baseUrl = baseUrl.match(RegExp(pattern))[0]\n result = \"\"\n java.log(`匹配链接:${baseUrl}`)\n }\n\n let isHtml = result.startsWith(\"\")\n if (isHtml) {\n let id = baseUrl.match(new RegExp(\"\\\\d+\"))[0]\n let pattern = \"(https?://)?(www\\\\.)?pixiv\\\\.net(/ajax)?/novel/(series/)?\\\\d+\"\n let isSeries = baseUrl.match(new RegExp(pattern))\n if (isSeries) {\n seriesId = id\n } else {\n let pattern = \"((furrynovel\\\\.(ink|xyz))|pixiv\\\\.net)/(pn|(pixiv/)?novel)/(show\\\\.php\\\\?id=)?\\\\d+\"\n let isNovel = baseUrl.match(new RegExp(pattern))\n if (isNovel) {\n java.log(`匹配小说ID:${id}`)\n res = util.getAjaxJson(util.urlNovelDetailed(id))\n }\n }\n } else {\n res = JSON.parse(result)\n }\n if (res.body !== undefined && res.body.seriesNavData !== undefined && res.body.seriesNavData !== null) {\n seriesId = res.body.seriesNavData.seriesId\n }\n if (seriesId) {\n java.log(`系列ID:${seriesId}`)\n res = util.getAjaxJson(util.urlSeriesDetailed(seriesId))\n }\n if (res.error === true) {\n java.log(`无法从 Pixiv 获取当前小说`)\n java.log(JSON.stringify(res))\n }\n return res.body\n }\n\n u.dateFormat = function (str) {\n let addZero = function (num) {\n return num < 10 ? '0' + num : num;\n }\n let time = new Date(str);\n let Y = time.getFullYear() + \"年\";\n let M = addZero(time.getMonth() + 1) + \"月\";\n let D = addZero(time.getDate()) + \"日\";\n return Y + M + D;\n }\n u.timeTextFormat = function (text) {\n return `${text.slice(0, 10)} ${text.slice(11, 19)}`\n }\n u.sleep = function (time) {\n let endTime = new Date().getTime() + time\n while(true){\n if (new Date().getTime() > endTime){\n return;\n }\n }\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": "https://accounts.pixiv.net/login",
"respondTime": 180000,
"ruleBookInfo": {
"author": "userName",
"canReName": "true",
"coverUrl": "coverUrl",
"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\nfunction oneShotHandler(res) {\n let info = {}\n info.seriesId = undefined\n info.id = info.novelId = res.id\n info.title = info.latestChapter = res.title.replace(RegExp(/^\\s+|\\s+$/g), \"\")\n info.userName = res.userName\n info.tags = res.tags.tags.map(item => item.tag)\n info.tags.unshift('单本')\n // info.textCount = res.textCount // 无数据\n info.textCount = res.userNovels[`${info.novelId}`].textCount\n info.description = res.description\n info.coverUrl = util.urlCoverUrl(res.coverUrl)\n info.detailedUrl = util.urlNovelUrl(info.novelId)\n info.catalogUrl = util.urlNovelDetailed(info.novelId)\n info.createDate = util.dateFormat(res.createDate)\n info.updateDate = util.dateFormat(res.uploadDate)\n\n info.readingTime = `${res.userNovels[`${info.novelId}`].readingTime / 60} 分钟`\n return info\n}\n\nfunction seriesHandler(res) {\n let info = {}\n info.seriesId = res.id\n info.id = info.novelId = res.firstNovelId\n info.title = res.title.replace(RegExp(/^\\s+|\\s+$/g), \"\")\n info.userName = res.userName\n info.tags = res.tags //合并当前章节 tags\n info.tags.unshift('长篇')\n info.textCount = res.publishedTotalCharacterCount\n info.description = res.caption\n info.coverUrl = util.urlCoverUrl(res.cover.urls[\"480mw\"]) // 240mw, 480mw, 1200x1200, 128x128, original\n info.detailedUrl = util.urlSeriesUrl(info.seriesId)\n info.catalogUrl = util.urlSeriesDetailed(info.seriesId)\n info.createDate = util.dateFormat(res.createDate)\n info.updateDate = util.dateFormat(res.updateDate)\n\n // 发送请求获取第一章 获取标签与简介\n let firstNovel = {}\n try {\n firstNovel = util.getAjaxJson(util.urlNovelDetailed(info.novelId)).body\n info.tags = info.tags.concat(firstNovel.tags.tags.map(item => item.tag))\n } catch (e) { // 防止系列首篇无权限获取\n try {\n firstNovel = util.getAjaxJson(util.urlSeriesNovels(info.seriesId, 30, 0)).body.thumbnails.novel[0]\n info.id = info.novelId = firstNovel.id\n info.tags = info.tags.concat(firstNovel.tags)\n } catch (e) {\n firstNovel = {}\n firstNovel.description = \"\"\n }\n }\n info.tags = Array.from(new Set(info.tags))\n if (info.description === \"\") {\n info.description = firstNovel.description\n }\n\n info.readingTime = `${res.publishedReadingTime / 60} 分钟`\n info.latestChapter = \"\"\n info.language = res.language\n info.totalChapterNum = info.total = res.total //章节总数\n info.latestNovelId = res.latestNovelId\n return info\n}\n\nfunction novelHandler(res){\n let info = {}\n if (res.firstNovelId !== undefined) {\n info = seriesHandler(res)\n } else {\n info = oneShotHandler(res)\n }\n info.tags = info.tags.join(\",\")\n if (util.MORE_INFO_IN_DESCRIPTION) {\n info.description = `\\n书名:${info.title}\\n作者:${info.userName}\\n标签:${info.tags}\\n上传:${info.createDate}\\n更新:${info.updateDate}\\n简介:${info.description}`\n } else {\n info.description = `\\n${info.description}\\n上传时间:${info.createDate}\\n更新时间:${info.updateDate}`\n }\n return info\n}\n\n(function (res) {\n res = util.getNovelResSeries(result)\n // res = util.getNovelRes(result)\n // if (res.seriesNavData !== null) { // 使用 util.getNovelRes(result) 时\n // res = util.getAjaxJson(util.urlSeriesDetailed(res.seriesNavData.seriesId)).body\n // }\n try {\n return novelHandler(res)\n } catch (e) {\n java.log(e)\n java.log(`受 Pixiv 的限制,无法获取当前小说数据`)\n }\n})();",
"intro": "description",
"kind": "tags",
"lastChapter": "latestChapter",
"name": "title",
"tocUrl": "catalogUrl",
"wordCount": "textCount"
},
"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\nfunction getContent(res) {\n let content = res.content\n // 在正文内部添加小说描述\n if (util.SHOW_NOVEL_COMMENTS === true && res.description !== \"\") {\n content = res.description + \"\\n\" + \"——————————\\n\".repeat(2) + content\n }\n\n // 获取 [uploadedimage:] 的图片链接\n let hasEmbeddedImages = res.textEmbeddedImages !== undefined && res.textEmbeddedImages !== null\n if (hasEmbeddedImages) {\n Object.keys(res.textEmbeddedImages).forEach((key) => {\n content = content.replace(`[uploadedimage:${key}]`, `
`)\n })\n }\n\n // 获取 [pixivimage:] 的图片链接 [pixivimage:1234] [pixivimage:1234-1]\n let matched = content.match(RegExp(/\\[pixivimage:(\\d+)-?(\\d+)]/gm))\n if (matched) {\n for (let i in matched) {\n let illustId, order\n let matched2 = matched[i].match(RegExp(\"(\\\\d+)-?(\\\\d+)\"))\n let temp = matched2[0].split(\"-\")\n illustId = temp[0]\n if (temp.length >= 2) {\n order = temp[1]\n }\n content = content.replace(`${matched[i]}`, `
`)\n }\n }\n\n // 替换 Pixiv 分页标记符号 [newpage]\n matched = content.match(RegExp(/[ ]*\\[newpage][ ]*/gm))\n if (matched) {\n for (let i in matched) {\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]}`, `${chapter}
`)\n }\n }\n\n // 替换 Pixiv 跳转页面标记符号 [[jump:]]\n matched = content.match(RegExp(/\\[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(RegExp(/\\[\\[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(RegExp(/\\[\\[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\n if (!util.REPLACE_BOOK_TITLE_MARKS) {\n // 默认替换成(括号)\n content = content.replace(`${matchedText}`, `${kanji}(${kana})`)\n } else {\n let reg = RegExp(\"[\\\\u4E00-\\\\u9FFF]+\", \"g\");\n if (reg.test(kana)) {\n // kana为中文,则替换回《书名号》\n content = content.replace(`${matchedText}`, `${kanji}《${kana}》`)\n } else {\n // 阅读不支持