🍅 番茄小说聚合API
http://101.35.133.34:5000
langzaier (13654)5天前
by 狼崽儿 //2026.8.9
第三方的开放番茄小说API。无法同步账号
1.支持小说,漫画,听书,短剧(但是这个API的短剧资源无法播放,所以实际上只支持前三种模式),默认小说,切换类型在登录切换,别忘了在左上角切换源类型。
2.仅支持小说评论。(其实也支持其他类型的评论,但是阅读会有兼容问题)
3.评论支持看用户名,评论正文,用户评分,点赞数,回复数。但是无法看楼中楼和具体用户信息。
4.评论数默认拉取100条,实测会在100多条的数量变动。如果需要拉取更多评论,在正文的LIMIT处修改数字,但是太多评论会很慢。
5.全面兼容所有版本的阅读
7.无段评,评论为整本书评论
【V2 更新】2026.8.10
去除评论字数限制;采用更加简单的toUrl,提高了解析目录成功率。为文章前面添加空格,优化文章显示效果。
【V3 更新】2026.8.11
重大更新!现已支持所有模式的发现页,只需要在登录处变换男女频道和四大类型就可以更新发现页。如果是旧版阅读,在发现页长按此书源,在下拉列表点击更新。同时优化当前模式的弹窗,支持查看模式,当前频道和评论开关状态。因为拉取评论容易导致校验超时,所以建议平时关掉评论开关。
【V3.1 更新】2026.8.11
支持显示卷名。
{
"bookSourceComment": "by 狼崽儿 \/\/2026.8.9\n第三方的开放番茄小说API。无法同步账号\n1.支持小说,漫画,听书,短剧(但是这个API的短剧资源无法播放,所以实际上只支持前三种模式),默认小说,切换类型在登录切换,别忘了在左上角切换源类型。\n2.仅支持小说评论。(其实也支持其他类型的评论,但是阅读会有兼容问题)\n3.评论支持看用户名,评论正文,用户评分,点赞数,回复数。但是无法看楼中楼和具体用户信息。\n4.评论数默认拉取100条,实测会在100多条的数量变动。如果需要拉取更多评论,在正文的LIMIT处修改数字,但是太多评论会很慢。\n5.全面兼容所有版本的阅读\n7.无段评,评论为整本书评论\n【V2 更新】2026.8.10\n去除评论字数限制;采用更加简单的toUrl,提高了解析目录成功率。为文章前面添加空格,优化文章显示效果。\n【V3 更新】2026.8.11\n重大更新!现已支持所有模式的发现页,只需要在登录处变换男女频道和四大类型就可以更新发现页。如果是旧版阅读,在发现页长按此书源,在下拉列表点击更新。同时优化当前模式的弹窗,支持查看模式,当前频道和评论开关状态。因为拉取评论容易导致校验超时,所以建议平时关掉评论开关。\n【V3.1 更新】2026.8.11\n支持显示卷名。",
"bookSourceName": "🍅 番茄小说聚合API",
"bookSourceType": 0,
"bookSourceUrl": "http:\/\/101.35.133.34:5000",
"customOrder": 0,
"enabled": true,
"enabledCookieJar": true,
"enabledExplore": true,
"exploreUrl": "@js:\nvar v = String(source.getVariable()).split(',');\nvar idx = parseInt(v[0]) || 0;\nvar tabs = ['小说', '听书', '漫画', '短剧'];\nvar tab = tabs[idx] || '小说';\nvar channels = ['男频', '女频'];\nvar ch = channels[parseInt(v[3]) || 0] || '男频';\nvar url = 'http:\/\/101.35.133.34:5000\/api\/discover\/style?tab=' + encodeURIComponent(tab) + '&source_type=' + encodeURIComponent(ch);\nvar d = JSON.parse(java.ajax(url));\nvar styles = d.data || [];\nvar arr = [];\nfor (var i = 0; i < styles.length; i++) {\n var it = styles[i];\n var t = String(it.title).replace(\/[°・\\*.☆]\/g, '').trim();\n if (it.url) {\n arr.push({title: t, url: it.url});\n } else {\n arr.push({title: t, url: '', style: {layout_flexGrow: 1, layout_flexBasisPercent: 1, background: '#37474f', borderRadius: '6px'}});\n }\n}\nJSON.stringify(arr);",
"header": "{\n \"User-Agent\": \"Mozilla\/5.0 (Linux; Android 10; wv) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/78.0.3904.108 Mobile Safari\/537.36 SearchCraft\/3.6.5 (Baidu; P1 9.0)\"\n}",
"jsLib": "var TypeNames = [\"小说\", \"听书\", \"漫画\", \"短剧\"];\nvar TypeValues = [3, 2, 8, 11];\n\nfunction TYPE() {\n var v = String(this.source.getVariable()).split(\",\");\n var idx = parseInt(v[0]) || 0;\n return TypeValues[idx] !== undefined ? TypeValues[idx] : 3;\n}\n\nfunction TAB() {\n var v = String(this.source.getVariable()).split(\",\");\n var idx = parseInt(v[0]) || 0;\n var tabs = [\"%E5%B0%8F%E8%AF%B4\", \"%E5%90%AC%E4%B9%A6\", \"%E6%BC%AB%E7%94%BB\", \"%E7%9F%AD%E5%89%A7\"];\n return tabs[idx] !== undefined ? tabs[idx] : \"%E5%B0%8F%E8%AF%B4\";\n}\n\nfunction CMTOFF() {\n var v = String(this.source.getVariable()).split(\",\");\n return v[1] == 'off';\n}",
"lastUpdateTime": "1786419223608",
"loginUi": "[\n {\n \"name\": \"当前模式\",\n \"type\": \"button\",\n \"action\": \"A()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n },\n {\n \"name\": \"主页\",\n \"type\": \"button\",\n \"action\": \"C()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.4\n }\n },\n{\n \"name\": \"🧑男频\",\n \"type\": \"button\",\n \"action\": \"E(0)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n{\n \"name\": \"👩女频\",\n \"type\": \"button\",\n \"action\": \"E(1)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"name\": \"📖小说\",\n \"type\": \"button\",\n \"action\": \"B(0)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"name\": \"🎧听书\",\n \"type\": \"button\",\n \"action\": \"B(1)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"name\": \"🖼漫画\",\n \"type\": \"button\",\n \"action\": \"B(2)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"name\": \"🎬短剧\",\n \"type\": \"button\",\n \"action\": \"B(3)\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.25\n }\n },\n {\n \"name\": \"💬 评论: 开启\/关闭\",\n \"type\": \"button\",\n \"action\": \"D()\",\n \"style\": {\n \"layout_flexGrow\": 1,\n \"layout_flexBasisPercent\": 0.5\n }\n }\n]",
"loginUrl": "A = () => {\n let v = String(this.source.getVariable()).split(\",\");\n let x = parseInt(v[0]) || 0;\n let names = [\"小说\", \"听书\", \"漫画\", \"短剧\"];\n let icons = [\"📖\", \"🎧\", \"🖼\", \"🎬\"];\n let chs = [\"男频\", \"女频\"];\n let ch = chs[parseInt(v[3]) || 0] || '男频';\n let cmt = v[1] == 'off' ? '关闭' : '开启';\n let nl = String.fromCharCode(10);\n java.toast('━━━━━━━━━━━' + nl +\n icons[x] + ' 当前模式' + nl +\n names[x] + nl +\n '━━━━━━━━━━━' + nl +\n '👥 频道' + nl +\n ch + nl +\n '━━━━━━━━━━━' + nl +\n '💬 评论开关' + nl +\n cmt + nl +\n '━━━━━━━━━━━');\n}\n\nB = (x) => {\n let v = String(this.source.getVariable()).split(\",\");\n v[0] = x;\n this.source.setVariable(v.join(\",\"));\n let names = [\"小说\", \"听书\", \"漫画\", \"短剧\"];\n java.toast('已切换到:' + names[x]);\n}\n\nC = () => {\n java.startBrowser('http:\/\/101.35.133.34:5000', '');\n}\n\nD = () => {\n let v = String(this.source.getVariable()).split(\",\");\n v[1] = (v[1] == 'off') ? 'on' : 'off';\n this.source.setVariable(v.join(\",\"));\n java.toast('💬 评论已' + (v[1] == 'on' ? '开启' : '关闭'));\n}\n\nE = (x) => {\n let v = String(this.source.getVariable()).split(\",\");\n v[3] = x;\n this.source.setVariable(v.join(\",\"));\n let names = [\"男频\", \"女频\"];\n java.toast('已切换到:' + names[x] + '(发现页联动)');\n}",
"respondTime": 78500,
"ruleBookInfo": {
"author": "$.data.data.author",
"coverUrl": "$.data.data.thumb_url",
"intro": "@js:\nvar d = JSON.parse(result);\nvar dd = d.data.data;\nfunction pad(n) { return n < 10 ? '0' + n : '' + n; }\nfunction fmtTime(ts) {\n var t = new Date(parseInt(ts) * 1000);\n return t.getFullYear() + '-' + pad(t.getMonth() + 1) + '-' + pad(t.getDate()) + ' ' + pad(t.getHours()) + ':' + pad(t.getMinutes()) + ':' + pad(t.getSeconds());\n}\nvar info = '';\ninfo += '🆔 书号:' + (dd.book_id || '') + '\\n';\ninfo += '📕 书名:' + (dd.book_name || '') + '\\n';\ninfo += '🎯 状况:' + (dd.creation_status == '0' ? '连载中' : '已完结') + '\\n';\ninfo += '✏️ 开坑:' + String(dd.create_time || '').substring(0, 10) + '\\n';\ninfo += '🕰️ 更新:' + (dd.last_publish_time ? fmtTime(dd.last_publish_time) : '') + '\\n';\ninfo += '⌨️ 字数:' + (dd.word_number || '0') + '字\\n';\ninfo += '🏷️ 标签:' + (dd.tags || '') + '\\n';\ninfo += '📊 评分:' + (dd.score || '0') + '分\\n';\ninfo += '🔖 分类:' + (dd.category || '') + '\\n';\ninfo += '📜 简介:\\n' + (dd.abstract || '');\nresult = info;",
"kind": "$.data.data.category",
"name": "$.data.data.book_name",
"tocUrl": "@js:\nvar m = baseUrl.match(\/book_id=(\\d+)\/);\nbaseUrl.split('detail').join('book') + (m ? '&bid=' + m[1] : '')"
},
"ruleContent": {
"content": "@js:\nvar d = JSON.parse(result);\nvar v = String(this.source.getVariable()).split(',');\nvar mode = parseInt(v[0]) || 0;\n\nvar content = '';\n\nif (mode == 0) {\n content = d.data.content || '';\n \/\/ 首段补全角空格缩进(API 首段无缩进)\n if (content) {\n var ci = 0;\n while (ci < content.length && (content.charAt(ci) === '\\n' || content.charAt(ci) === ' ')) ci++;\n if (ci < content.length && content.charAt(ci) !== '\\u3000') {\n content = content.substring(0, ci) + '\\u3000\\u3000' + content.substring(ci);\n }\n }\n} else if (mode == 1) {\n content = d.data.audio_url || d.data.content || '';\n} else if (mode == 2) {\n content = d.data.images || '';\n} else if (mode == 3) {\n content = d.data.video_url || '';\n}\n\nif (mode == 0 && typeof CMTOFF !== 'undefined' && !CMTOFF()) {\n var bid = '';\n var m = baseUrl.match(\/bid=(\\d+)\/);\n if (m) bid = m[1];\n try {\n var all = [];\n var offset = 0;\n var LIMIT = 100;\n while (all.length < LIMIT) {\n var cr = JSON.parse(java.ajax('http:\/\/101.35.133.34:5000\/api\/comment?book_id=' + bid + '&count=50&offset=' + offset));\n var cmts = cr.data.data.comment;\n if (!cmts || cmts.length === 0) break;\n all = all.concat(cmts);\n if (!cr.data.data.has_more) break;\n offset += 50;\n }\n if (all.length > 0) {\n content += '\\n\\n━━━━━━━━━━━━━━━━━━\\n💬 本书书评(共' + all.length + '条)\\n━━━━━━━━━━━━━━━━━━\\n';\n for (var i = 0; i < all.length; i++) {\n var c = all[i];\n var nick = (c.user_info && c.user_info.user_name) ? c.user_info.user_name : '匿名';\n var digg = c.digg_count || 0;\n var rep = c.reply_count || 0;\n var sc = c.score || '';\n var txt = String(c.text).split('\\n').join(' ');\n var line = '👤 ' + nick;\n if (sc) line += ' ⭐' + sc;\n line += ' 👍' + digg + ' 💬' + rep;\n content += line + '\\n📝 ' + txt + '\\n';\n }\n }\n } catch (e) {}\n}\nresult = content;"
},
"ruleExplore": {
"author": "$.author",
"bookList": "@Json:data",
"bookUrl": "$.book_id@js:'http:\/\/101.35.133.34:5000\/api\/detail?book_id=' + result",
"coverUrl": "$.thumb_url",
"intro": "$.abstract",
"kind": "$.category",
"name": "$.book_name"
},
"ruleSearch": {
"author": "$.author",
"bookList": "@js:\nvar d = JSON.parse(result);\nvar tabs = d.data.search_tabs;\nvar v = String(this.source.getVariable()).split(\",\");\nvar idx = parseInt(v[0]) || 0;\nvar typeValues = [3, 2, 8, 11];\nvar currentType = typeValues[idx] !== undefined ? typeValues[idx] : 3;\nvar books = [];\nfor (var i = 0; i < tabs.length; i++) {\n if (tabs[i].tab_type == currentType && tabs[i].data) {\n for (var j = 0; j < tabs[i].data.length; j++) {\n var g = tabs[i].data[j];\n if (currentType == 11) {\n \/\/ === 短剧: 从 video_data 取, 统一成书结构 ===\n var vd = g.video_data;\n if (vd) {\n for (var k = 0; k < vd.length; k++) {\n var it = vd[k];\n var cat = '';\n try {\n var cs = JSON.parse(it.category_schema || '[]');\n if (cs[0]) cat = cs[0].name;\n } catch (e) {}\n books.push(JSON.stringify({\n book_name: it.title || it.raw_book_name || '',\n author: it.author || '',\n category: cat,\n abstract: it.rec_text || it.sub_title || '',\n thumb_url: it.cover || it.horiz_cover || '',\n book_id: it.series_id || it.vid || ''\n }));\n }\n }\n } else {\n \/\/ === 小说\/听书\/漫画: 原有逻辑 ===\n var bd = g.book_data;\n if (bd) {\n for (var k = 0; k < bd.length; k++) {\n books.push(JSON.stringify(bd[k]));\n }\n }\n }\n }\n }\n}\nresult = books;",
"bookUrl": "$.book_id@js:'http:\/\/101.35.133.34:5000\/api\/detail?book_id=' + result",
"coverUrl": "$.thumb_url",
"intro": "$.abstract",
"kind": "$.category",
"name": "$.book_name"
},
"ruleToc": {
"chapterList": "@js:\nvar d = (typeof result === 'string') ? JSON.parse(result) : result;\nvar obj = d.data.data;\nvar clwv = obj.chapterListWithVolume || [];\nvar vnl = obj.volumeNameList || [];\nvar arr = [];\nfor (var i = 0; i < clwv.length; i++) {\n var vol = clwv[i];\n if (vol.length > 0) {\n var vn = vnl[i] || ('第' + (i + 1) + '卷');\n arr.push(JSON.stringify({title: vn, isVolume: true, itemId: vol[0].itemId}));\n }\n for (var j = 0; j < vol.length; j++) {\n var ch = vol[j];\n ch.isVolume = false;\n arr.push(JSON.stringify(ch));\n }\n}\narr;",
"chapterName": "$.title",
"chapterUrl": "@js:\nvar c = JSON.parse(result);\nvar bid = '';\nvar m = baseUrl.match(\/book_id=(\\d+)\/);\nif (m) bid = m[1];\nc.isVolume ? '' : 'http:\/\/101.35.133.34:5000\/api\/content?tab=' + TAB() + '&item_id=' + c.itemId + '&bid=' + bid;",
"isVolume": "$.isVolume"
},
"searchUrl": "@js:var base='http:\/\/101.35.133.34:5000';\nvar offset=(page-1)*10;\nbase+'\/api\/search?key='+encodeURIComponent(key)+'&tab_type='+TYPE()+'&offset='+offset",
"weight": 0
}