🌙 七猫小说 · API
https://api-bc.wtzw.com
t2157111 (9598)1天前
v26.10.01 [阅读书源] 七猫小说API源
附注:
做了很多细节上的处理,使用体验上会好很多,自行测试
七猫小说 · 妍希(原作者)
// 2026/09/16 By sjshb57 二改内容:
· 正文:弃用失效的第三方接口,改为七猫官方接口 + AES 解密
· 短篇:自动带 reader_agent=1,修复部分书籍报错
· 出版物:自动解压 EPUB 章节,支持文字与图片
· 重构:签名/请求头/接口统一收进 jsLib,规则精简
· 修正:@put 规范写法、简介标签去重
· 发现页:按官方分类目录重写(男频/女频/出版)
- 分组可折叠,支持状态/字数/排序筛选
- 等宽格子排版,短标签 4 列、长标签 3 列,空位补齐
// 2026/10/01 By sjshb57 优化详情与发现加载
· 优化书籍详情页布局,使其更加美观
· 补全发现页排行榜单,其内容不再使用硬编码,改为API读取官方分类解析
强烈推荐搭配使用主包制作的legado数字标题!!非常智能!代码已开源↓
推推:https://github.com/sjshb57/legado-57
{
"bookSourceComment": "\/\/ 七猫小说 By 妍希 [原作者]\n\/\/ 2026\/09\/16 By sjshb57 二改内容如下:\n· 正文:弃用失效的第三方接口,改为七猫官方接口 + AES 解密\n· 短篇:自动带 reader_agent=1,修复部分书籍报错\n· 出版物:自动解压 EPUB 章节,支持文字与图片\n· 重构:签名\/请求头\/接口统一收进 jsLib,规则精简\n· 修正:@put 规范写法、简介标签去重\n· 发现页:按官方分类目录重写(男频\/女频\/出版)\n - 分组可折叠,支持状态\/字数\/排序筛选\n - 等宽格子排版,短标签 4 列、长标签 3 列,空位补齐\n\/\/ 2026\/10\/01 By sjshb57 优化详情与发现加载\n· 优化书籍详情页布局,使其更加美观\n· 补全发现页排行榜单,其内容不再使用硬编码,改为API读取官方分类解析",
"bookSourceGroup": "🌙 小说",
"bookSourceName": "🌙 七猫小说 · API",
"bookSourceType": 0,
"bookSourceUrl": "https:\/\/api-bc.wtzw.com",
"customButton": false,
"customOrder": 0,
"enabled": true,
"enabledCookieJar": false,
"enabledExplore": true,
"eventListener": false,
"exploreUrl": "@js:\nvar cfg = {};\ntry { cfg = JSON.parse(String(source.getVariable() || '{}')) || {}; } catch (e) {}\n\nvar CH = [['男频', '♂', 1], ['女频', '♀', 2], ['出版', '✎', 3]];\nvar ch = CH.filter(function (c) { return c[0] == cfg.ch; })[0] || CH[0];\n\nvar cache = cfg.cat || {};\nvar data = cfg.fast && cache[ch[2]];\nif (!data || !data.g) {\n data = {g: [], r: []};\n try {\n data.g = JSON.parse(java.ajax(qmIndex(ch[2]))).data.category_list.map(function (g) {\n return [String(g.title), g.list.filter(function (c) {\n return c.category_type == '2' && c.category_id;\n }).map(function (c) { return [String(c.title), String(c.category_id)]; })];\n }).filter(function (g) { return g[1].length; });\n } catch (e) {}\n try {\n JSON.parse(java.ajax(qmRankIndex(ch[2]))).data.rank_list.forEach(function (r) {\n if (r.type == 'character_list' || r.show_type == '6') return;\n data.r.push([String(r.title), String(r.type) + ((r.sub_titles || []).length > 1 ? '|month' : '')]);\n });\n } catch (e) {}\n if (ch[2] == 1 || ch[2] == 2) {\n data.r.push(['殿堂作品', 'sp:hall'], ['原创风云榜', 'sp:award'], ['宗师作家', 'sp:master']);\n }\n if (ch[2] == 2) {\n try {\n JSON.parse(java.ajax(qmStoryIndex())).data.rank_list.forEach(function (r) {\n data.r.push(['短篇' + r.title, 'story:' + r.type]);\n });\n } catch (e) {}\n }\n if (data.g.length) cache[ch[2]] = data;\n}\nvar groups = data.g, ranks = data.r;\ncfg.cat = cache;\ndelete cfg.fast;\nsource.setVariable(JSON.stringify(cfg));\n\nvar open = cfg.open || {};\nvar over = cfg.over || '-99', words = cfg.words || '-99', sort = cfg.sort || '0';\n\nvar OVER = [['全部状态', '-99'], ['完结', '1'], ['连载', '0']];\nvar WORDS = [['全部字数', '-99'], ['50万以下', '1'], ['50-100万', '2'], ['100-300万', '3'], ['300万以上', '4']];\nvar SORT = [['按热度', '0'], ['按更新', '1'], ['按评分', '2'], ['按新书', '3']];\nfunction label(opts, v) { return (opts.filter(function (o) { return o[1] == v; })[0] || opts[0])[0]; }\n\nvar LAYOUT = {gap: 0.042, pad: 0.068, ch: 0.0368, shortMax: 3.3};\n\nfunction textWidth(t) {\n var w = 0;\n for (var i = 0; i < t.length; i++) {\n var c = t.charCodeAt(i);\n if (c == 32) w += 0.32;\n else if (c < 128) w += 0.65;\n else if (c == 0xB7) w += 0.5;\n else if (c == 0x25CF) w += 0.9;\n else w += 1;\n }\n return w;\n}\n\nvar s = [];\n\nfunction pack(items, cols) {\n cols = cols || 4;\n var g = LAYOUT.gap, cell = (1 - g * (cols - 1)) \/ cols;\n var fit = (cell - LAYOUT.pad) \/ LAYOUT.ch;\n var queue = items.map(function (it) {\n return {it: it, span: Math.min(cols, Math.ceil(textWidth(it.title) \/ fit) || 1)};\n });\n while (queue.length) {\n var row = [], left = cols;\n while (queue.length && left > 0) {\n var k = 0;\n while (k < queue.length && queue[k].span > left) k++;\n if (k == queue.length) break;\n var x = queue.splice(k, 1)[0];\n row.push(x); left -= x.span;\n }\n for (; left > 0; left--) row.push({it: {title: ' ', url: ''}, span: 1});\n row.forEach(function (x, i) {\n var st = {layout_flexGrow: x.span, layout_flexBasisPercent: Math.round((x.span \/ (cols + 1) + (x.span - 1) * g) * 1e4) \/ 1e4};\n if (i == 0) st.layout_wrapBefore = true;\n x.it.style = st;\n s.push(x.it);\n });\n }\n}\n\nfunction action(js) {\n return \"(function(){var c={};try{c=JSON.parse(String(source.getVariable()||'{}'))||{};}catch(e){}\"\n + js + \"c.fast=1;source.setVariable(JSON.stringify(c));java.refreshExplore();})()\";\n}\nfunction button(title, js) {\n return {title: title, type: 'button', action: action(js)};\n}\nfunction bar(title, js) {\n var b = button(title, js);\n b.style = {layout_flexGrow: 1, layout_flexBasisPercent: 1, layout_wrapBefore: true};\n s.push(b);\n}\nfunction optionRow(key, opts, cur) {\n pack(opts.map(function (o) {\n return button((o[1] == cur ? '● ' : '') + o[0], 'c[' + JSON.stringify(key) + ']=' + JSON.stringify(o[1]) + ';');\n }), 3);\n}\n\npack(CH.map(function (c) {\n return button((c[0] == ch[0] ? '● ' : '') + c[1] + ' ' + c[0], 'c.ch=' + JSON.stringify(c[0]) + ';');\n}), 3);\n\nvar filterTitle = '⚙ 筛选:' + label(OVER, over) + ' · ' + label(WORDS, words) + ' · ' + label(SORT, sort);\nbar(filterTitle + (cfg.filt ? ' ▾' : ' ▸'), 'c.filt=!c.filt;');\nif (cfg.filt) {\n optionRow('over', OVER, over);\n optionRow('words', WORDS, words);\n optionRow('sort', SORT, sort);\n}\n\nif (!groups.length) s.push({title: '⚠ 分类加载失败', url: '', style: {layout_flexGrow: 1, layout_flexBasisPercent: 1, layout_wrapBefore: true}});\n\nfunction split(items) {\n var short = [], long = [];\n items.forEach(function (it) { (textWidth(it.title) > LAYOUT.shortMax ? long : short).push(it); });\n pack(short, 4);\n pack(long, 3);\n}\n\nif (ranks.length) {\n var rkey = ch[0] + '|排行';\n var rOpen = !!open[rkey];\n bar((rOpen ? '▾ ' : '▸ ') + '排行(' + ranks.length + ')',\n 'var o=c.open||{};o[' + JSON.stringify(rkey) + ']=' + (rOpen ? 0 : 1) + ';c.open=o;');\n if (rOpen) split(ranks.map(function (r) {\n var t = r[1].split(':'), url;\n if (t[0] == 'sp') url = \"{{qmSpecial('\" + t[1] + \"',\" + ch[2] + ',page)}}';\n else if (t[0] == 'story') url = \"{{qmStoryRank('\" + t[1] + \"',page)}}\";\n else url = '{{qmRank(' + ch[2] + \",'\" + r[1].split('|')[0] + \"',page,'\" + (r[1].split('|')[1] || '') + \"')}}\";\n return {title: r[0], url: url};\n }));\n}\n\ngroups.forEach(function (g, gi) {\n var key = ch[0] + '|' + g[0];\n var isOpen = key in open ? !!open[key] : gi == 0;\n bar((isOpen ? '▾ ' : '▸ ') + g[0] + '(' + g[1].length + ')',\n 'var o=c.open||{};o[' + JSON.stringify(key) + ']=' + (isOpen ? 0 : 1) + ';c.open=o;');\n if (!isOpen) return;\n split(g[1].map(function (kv) {\n return {title: kv[0], url: '{{qmTag(' + ch[2] + ',' + kv[1] + ',page,' + over + ',' + words + ',' + sort + ')}}'};\n }));\n});\n\nJSON.stringify(s);\n",
"jsLib": "var QM_KEY = 'd3dGiJc651gSQ8w1';\nvar QM_AES = '242ccb8230d709e1';\nvar QM_BC = 'https:\/\/api-bc.wtzw.com';\nvar QM_KS = 'https:\/\/api-ks.wtzw.com';\n\nfunction qmMd5(s) {\n var b = Packages.java.security.MessageDigest.getInstance('MD5')\n .digest(new Packages.java.lang.String(s).getBytes('UTF-8'));\n var h = '';\n for (var i = 0; i < b.length; i++) {\n var x = (b[i] & 0xff).toString(16);\n h += (x.length < 2 ? '0' : '') + x;\n }\n return h;\n}\n\nfunction qmSign(o) {\n return qmMd5(Object.keys(o).sort().map(function (k) { return k + '=' + o[k]; }).join('') + QM_KEY);\n}\n\nvar QM_HEADERS = (function () {\n var h = {'app-version': '80400', 'platform': 'android', 'reg': '0', 'AUTHORIZATION': '',\n 'application-id': 'com.****.reader', 'net-env': '1', 'channel': 'unknown', 'qm-params': ''};\n h.sign = qmSign(h);\n return JSON.stringify({headers: h});\n})();\n\nfunction qmUrl(base, path, params) {\n params.sign = qmSign(params);\n var q = Object.keys(params).map(function (k) {\n return k + '=' + encodeURIComponent(params[k]);\n }).join('&');\n return base + path + '?' + q + ',' + QM_HEADERS;\n}\n\nfunction qmSearch(key, page) {\n return qmUrl(QM_BC, '\/search\/v1\/words', {gender: '3', imei_ip: '2937357107', page: page, wd: key});\n}\nfunction qmDetail(id) {\n return qmUrl(QM_BC, '\/api\/v4\/book\/detail', {id: id, imei_ip: '2937357107', teeny_mode: 0});\n}\nfunction qmToc(id) {\n return qmUrl(QM_KS, '\/api\/v1\/chapter\/chapter-list', {id: id});\n}\nfunction qmTag(gender, tid, page, over, words, sort) {\n var p = {gender: gender, need_filters: 1, page: page, tag_id: tid,\n over: over == null ? -99 : over, words: words == null ? -99 : words, sort: sort == null ? 0 : sort};\n if (gender == 1 || gender == 2) p.book_preference = gender;\n return qmUrl(QM_BC, '\/api\/v4\/tag\/index', p);\n}\n\nfunction qmIndex(tab) {\n return qmUrl(QM_BC, '\/api\/v5\/category\/index', {gender: '2', tab_type: tab, read_preference: '0', book_privacy: '1', category_new_hot: '0'});\n}\n\nfunction qmForm(base, path, params) {\n params.sign = qmSign(params);\n var body = Object.keys(params).map(function (k) {\n return k + '=' + encodeURIComponent(params[k]);\n }).join('&');\n var h = JSON.parse(QM_HEADERS).headers;\n h['Content-Type'] = 'application\/x-www-form-urlencoded';\n return base + path + ',' + JSON.stringify({method: 'POST', body: body, headers: h});\n}\n\nfunction qmRankIndex(tab) {\n return qmUrl(QM_BC, '\/api\/v1\/leader-board', {rank_type: '', category_id: 0, category_type: 0, tab_type: tab, imei_ip: '2937357107', book_privacy: 1, read_preference: 0});\n}\n\nfunction qmStoryIndex() {\n return qmUrl(QM_BC, '\/api\/v1\/story\/leader-board', {rank_type: '', category_id: 0, category_type: 0, page_no: 1, book_privacy: 1});\n}\n\nfunction qmRank(tab, type, page, period) {\n var p = {rank_type: type, category_id: 0, category_type: 0, tab_type: tab, imei_ip: '2937357107', book_privacy: 1, read_preference: 0, page_no: page};\n if (period == 'month') p.list_type = 'month';\n return qmUrl(QM_BC, '\/api\/v1\/leader-board', p);\n}\n\nfunction qmStoryRank(type, page) {\n return qmUrl(QM_BC, '\/api\/v1\/story\/leader-board', {rank_type: type, category_id: 0, category_type: 0, page_no: page, book_privacy: 1});\n}\n\nfunction qmSpecial(kind, gender, page) {\n if (kind == 'award') return qmUrl(QM_BC, '\/api\/v1\/h5\/book-original-award\/list', {gender: gender, page: page});\n if (kind == 'hall') return qmUrl(QM_BC, '\/api\/v1\/h5\/hall-of-fame\/list', {gender: gender, page_no: page});\n return qmUrl(QM_BC, '\/api\/v1\/h5\/original-author-master\/list', {page_no: page});\n}\n\nfunction qmParam(url, k) {\n var m = String(url).match(new RegExp('[?&]' + k + '=([^&,]*)'));\n return m ? decodeURIComponent(m[1]) : '';\n}\n\nfunction qmItem(o) {\n var tags = o.ptags;\n if (!tags && o.book_title) tags = (o.type == 1 ? '宗师作家' : '大师作家') + ' · ' + o.year;\n if (!tags) tags = [o.sub_title, o.heat_number].filter(function (v) { return v; }).join(' · ');\n return {\n id: String(o.id || o.book_id || ''),\n title: String(o.title || o.book_title || ''),\n author: String(o.author || o.author_name || ''),\n image_link: String(o.image_link || o.img || ''),\n intro: String(o.intro || o.rec_desc || ''),\n ptags: String(tags || ''),\n words_num: String(o.words_num || '')\n };\n}\n\nfunction qmFill(items, java) {\n var need = items.filter(function (o) { return o.id && (!o.author || !o.intro || !o.ptags); });\n for (var i = 0; i < need.length; i += 10) {\n var batch = need.slice(i, i + 10);\n var res = [];\n try { res = java.ajaxAll(batch.map(function (o) { return qmDetail(o.id); })); } catch (e) {}\n batch.forEach(function (o, j) {\n try {\n var b = JSON.parse(String(res[j].body())).data.book;\n if (!o.author) o.author = String(b.author || '');\n if (!o.intro) o.intro = String(b.intro || '');\n if (!o.words_num) o.words_num = String(b.words_num || '');\n if (!o.ptags) o.ptags = String(b.category_over_words || '');\n } catch (e) {}\n });\n }\n return items;\n}\n\nfunction qmList(result, url, java) {\n url = String(url);\n var page = parseInt(qmParam(url, 'page') || qmParam(url, 'page_no')) || 1;\n var d = {};\n try { d = JSON.parse(result).data || {}; } catch (e) {}\n var list = d.books || [];\n if (url.indexOf('\/tag\/index') >= 0 && !list.length) {\n var p = {\n category_id: qmParam(url, 'tag_id'), category_type: '2', gender: qmParam(url, 'gender'),\n need_filters: '1', page: String(page), book_privacy: '1', from: '4', read_preference: '0',\n over: qmParam(url, 'over') || '-99', words: qmParam(url, 'words') || '-99',\n sort: {'0': '1', '1': '3', '2': '2', '3': '4'}[qmParam(url, 'sort')] || '1'\n };\n if (qmParam(url, 'book_preference')) p.book_preference = qmParam(url, 'book_preference');\n try { list = (JSON.parse(java.ajax(qmForm(QM_BC, '\/api\/v5\/category\/get-list', p))).data || {}).books || []; } catch (e) {}\n } else if (url.indexOf('\/story\/leader-board') >= 0) {\n if (page > 1 && !d.refresh_page) list = [];\n } else if (url.indexOf('original-author-master') >= 0) {\n list = page > 1 ? [] : (d.list || []);\n } else if (url.indexOf('hall-of-fame') >= 0 || url.indexOf('\/leader-board') >= 0) {\n if (page > 1) list = [];\n else if (qmParam(url, 'list_type') == 'month') list = d.month_books || [];\n }\n return qmFill(list.map(qmItem), java).map(function (o) { return JSON.stringify(o); });\n}\n\nfunction qmContent(bid, cid, agent) {\n var p = {id: bid, chapterId: cid};\n if (agent) p.reader_agent = '1';\n return qmUrl(QM_KS, '\/api\/v1\/chapter\/content', p);\n}\n\nfunction qmChapterUrl(cid, md5, agent) {\n var s = cid + '\/' + md5 + '\/' + (agent == '1' ? '1' : '0');\n var b64 = Packages.java.util.Base64.getEncoder()\n .encodeToString(new Packages.java.lang.String(s).getBytes('UTF-8'));\n return 'data:;base64,' + b64 + ',{\"type\":\"qm\"}';\n}\n\nfunction qmUnzipEpub(b) {\n function u16(p) { return (b[p] & 0xff) | (b[p + 1] & 0xff) << 8; }\n function u32(p) { return (u16(p) | u16(p + 2) << 16) >>> 0; }\n var eocd = b.length - 22;\n while (eocd >= 0 && u32(eocd) != 0x06054b50) eocd--;\n if (eocd < 0) return '';\n var p = u32(eocd + 16), count = u16(eocd + 10), html = '';\n for (var i = 0; i < count; i++) {\n var method = u16(p + 10), csize = u32(p + 20), usize = u32(p + 24);\n var nlen = u16(p + 28), total = 46 + nlen + u16(p + 30) + u16(p + 32);\n var name = String(new Packages.java.lang.String(b, p + 46, nlen, 'UTF-8'));\n var lh = u32(p + 42);\n p += total;\n if (!\/\\.x?html?$\/i.test(name)) continue;\n var start = lh + 30 + u16(lh + 26) + u16(lh + 28), text;\n if (method == 0) {\n text = new Packages.java.lang.String(b, start, csize, 'UTF-8');\n } else {\n var inf = new Packages.java.util.zip.Inflater(true);\n inf.setInput(b, start, csize);\n var out = Packages.java.util.Arrays.copyOf(b, usize);\n inf.inflate(out);\n inf.end();\n text = new Packages.java.lang.String(out, 'UTF-8');\n }\n var m = String(text).match(\/<body[^>]*>([\\s\\S]*)<\\\/body>\/i);\n if (m) html += m[1];\n }\n return html.replace(\/<h\\d[^>]*>[\\s\\S]*?<\\\/h\\d>\/gi, '')\n .replace(\/&\/g, '&').trim();\n}\n\nfunction qmDecode(content) {\n var A = Packages.java.util.Arrays;\n var raw = Packages.java.util.Base64.getDecoder().decode(String(content));\n var key = new Packages.javax.crypto.spec.SecretKeySpec(new Packages.java.lang.String(QM_AES).getBytes('UTF-8'), 'AES');\n var iv = new Packages.javax.crypto.spec.IvParameterSpec(A.copyOfRange(raw, 0, 16));\n var c = Packages.javax.crypto.Cipher.getInstance('AES\/CBC\/PKCS5Padding');\n c.init(2, key, iv);\n var b = c.doFinal(A.copyOfRange(raw, 16, raw.length));\n if (b.length > 3 && b[0] == 0x50 && b[1] == 0x4B) return qmUnzipEpub(b);\n return String(new Packages.java.lang.String(b, 'UTF-8'));\n}\n",
"lastUpdateTime": "1790858563576",
"respondTime": 180000,
"ruleBookInfo": {
"author": "author",
"coverUrl": "image_link",
"init": "data.book",
"intro": "<js>\n(function () {\n var g = function (r) {\n try { return String(java.getString(r) || '').trim(); } catch (e) { return ''; }\n };\n var uniq = function (v, i, a) { return v && a.indexOf(v) == i; };\n\n var words = parseInt(g('$.words_num')) || 0;\n var ws = words >= 10000 ? (words \/ 10000).toFixed(1) + '万字' : (words ? words + '字' : '');\n var chapters = g('$.chapters');\n var state = [ws, g('$.is_over') == '1' ? '已完结' : '连载中', chapters ? '共' + chapters + '章' : ''].filter(uniq).join(' · ');\n\n var ts = parseInt(g('$.update_time')) || 0;\n var time = ts ? String(java.timeFormat(ts * 1000)).replace(\/\\\/\/g, '-') : '';\n\n var cat = [g('$.category1_name'), g('$.category2_name')].filter(uniq).join(' · ');\n var tags = g('$.book_tag_list[*].title').split(\/\\s*\\n\\s*\/).filter(uniq).join(' · ');\n\n var score = g('$.attribute.score');\n var scoreT = g('$.attribute.score_title');\n var info = g('$.attribute.reading_info_list[*]').split(\/\\s*\\n\\s*\/);\n var hot = [];\n if (info[0]) hot.push(info[0] + (info[1] ? '(' + info[1].split('・').pop() + ')' : ''));\n if (info[2]) hot.push(info[2] + '人在读');\n\n var desc = g('$.intro')\n .replace(\/\\r\/g, '')\n .replace(\/^[\\s\\u3000]+\/, '')\n .replace(\/[ \\t\\u3000]*\\n[\\s\\u3000]*\/g, '\\n')\n .replace(\/\\n\/g, '\\n\\u3000\\u3000');\n\n var L = [];\n var add = function (icon, label, val) {\n if (val) L.push('\\u3000\\u3000' + icon + ' ' + label + ':' + val);\n };\n add('📕', '书名', g('$.title'));\n add('👤', '作者', g('$.author'));\n add('🗂️', '分类', cat);\n add('📊', '字数', state);\n add('🔖', '标签', tags);\n add('⭐', '评分', score ? score + (scoreT ? '(' + scoreT + ')' : '') : '');\n add('🔥', '人气', hot.join(' · '));\n add('🕐', '更新', time);\n add('📖', '最新', g('$.latest_chapter_title'));\n if (desc) {\n L.push('\\u3000\\u3000\\u200b');\n L.push('\\u3000\\u3000📜 简介:');\n L.push('\\u3000\\u3000' + desc);\n }\n var src = g('$.source');\n if (src) {\n L.push('\\u3000\\u3000\\u200b');\n L.push('\\u3000\\u3000📍 版权来源:' + src);\n }\n return L.join('\\n');\n})()\n<\/js>",
"kind": "book_tag_list[*].title##\\s##,",
"lastChapter": "{{$.latest_chapter_title}} • {{java.timeFormat(java.getString('$.update_time')*1000)}}\n<js>result.replace(\/\\s\\d+:\\d+\/,'').replace(\/\\\/\/g,'-')<\/js>",
"name": "title@put:{\"bid\":\"$.id\"}",
"tocUrl": "@js:qmToc('{{$.id}}')",
"wordCount": "words_num"
},
"ruleContent": {
"content": "@js:\nvar seg = String(java.hexDecodeToString(result)).split('\/');\nvar bid = String(java.get('bid'));\nvar story = seg[2] == '1';\nvar out;\ntry {\n var res = JSON.parse(java.ajax(qmContent(bid, seg[0], story)));\n if (!(res.data && res.data.content)) res = JSON.parse(java.ajax(qmContent(bid, seg[0], !story)));\n out = (res.data && res.data.content) ? qmDecode(res.data.content)\n : '七猫服务器未返回本章正文:' + (res.errors ? res.errors.details : '未知错误');\n} catch (e) {\n out = '正文获取失败:' + e;\n}\nout;\n"
},
"ruleExplore": {
"author": "$.author",
"bookList": "@js:qmList(result, baseUrl, java)",
"bookUrl": "@js:qmDetail('{{$.id}}')",
"coverUrl": "$.image_link",
"intro": "$.intro",
"kind": "$.ptags",
"name": "$.title",
"wordCount": "$.words_num"
},
"ruleSearch": {
"author": "original_author",
"bookList": "data.books",
"bookUrl": "@js:qmDetail('{{$.id}}')",
"coverUrl": "image_link",
"intro": "intro",
"kind": "ptags",
"name": "original_title",
"wordCount": "words_num"
},
"ruleToc": {
"chapterList": "<js>java.put('qm_agent', String(JSON.parse(String(result)).data.reader_type) == '4' ? '1' : '0'); result<\/js>\n$.data.chapter_lists",
"chapterName": "title",
"chapterUrl": "@js:qmChapterUrl('{{$.id}}', '{{$.content_md5}}', java.get('qm_agent'))",
"updateTime": "{{$.words}}字"
},
"searchUrl": "@js:qmSearch(key, page)",
"weight": 0
}