[{"bookSourceComment":"刺猬书库 (m.ciweiku.com) 书源 v6：全站免登录，搜索\/发现\/详情\/目录\/正文均已用真实页面逐步验证（全职法师 3177 章、凡人武圣 104 章；正文自动拼接与净化）。注意：该站对 App 普通请求上 Cloudflare 验证，v5 起搜索、发现、目录、正文、正文分页全部改走 WebView 请求；v6 起正文自动净化掉多页章节里个别失败页带入的 Cloudflare 提示行（整章都失败时仍保留提示）。by斯诺伤","bookSourceGroup":"小说","bookSourceName":"刺猬书库","bookSourceType":0,"bookSourceUrl":"http:\/\/m.ciweiku.com","bookUrlPattern":"ciweiku\\.com\/ciwei\/\\d+_\\d+","customButton":false,"customOrder":0,"enabled":true,"enabledCookieJar":true,"enabledExplore":true,"eventListener":false,"exploreUrl":"[{\"title\": \"🦔 刺猬书库\", \"url\": \"\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 1}}, {\"title\": \"🔥 热门推荐\", \"url\": \"http:\/\/m.ciweiku.com\/?board=rec,{\\\"webView\\\":true}\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 0.5}}, {\"title\": \"━━━  排行榜  ━━━\", \"url\": \"\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 1}}, {\"title\": \"阅读排行\", \"url\": \"http:\/\/m.ciweiku.com\/?board=read,{\\\"webView\\\":true}\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 0.25}}, {\"title\": \"热赞排行\", \"url\": \"http:\/\/m.ciweiku.com\/?board=zan,{\\\"webView\\\":true}\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 0.25}}, {\"title\": \"今日更新\", \"url\": \"http:\/\/m.ciweiku.com\/?board=update,{\\\"webView\\\":true}\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 0.25}}, {\"title\": \"新书入库\", \"url\": \"http:\/\/m.ciweiku.com\/?board=new,{\\\"webView\\\":true}\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 0.25}}, {\"title\": \"网友热搜\", \"url\": \"http:\/\/m.ciweiku.com\/?board=hot,{\\\"webView\\\":true}\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 0.25}}, {\"title\": \"\", \"url\": \"\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 0.25}}, {\"title\": \"━━━  分类  ━━━\", \"url\": \"\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 1}}, {\"title\": \"玄幻\", \"url\": \"http:\/\/m.ciweiku.com\/ciwei121-{{page}}.html,{\\\"webView\\\":true}\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 0.25}}, {\"title\": \"仙侠\", \"url\": \"http:\/\/m.ciweiku.com\/ciwei122-{{page}}.html,{\\\"webView\\\":true}\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 0.25}}, {\"title\": \"都市\", \"url\": \"http:\/\/m.ciweiku.com\/ciwei123-{{page}}.html,{\\\"webView\\\":true}\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 0.25}}, {\"title\": \"历史\", \"url\": \"http:\/\/m.ciweiku.com\/ciwei124-{{page}}.html,{\\\"webView\\\":true}\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 0.25}}, {\"title\": \"网游\", \"url\": \"http:\/\/m.ciweiku.com\/ciwei125-{{page}}.html,{\\\"webView\\\":true}\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 0.25}}, {\"title\": \"科幻\", \"url\": \"http:\/\/m.ciweiku.com\/ciwei126-{{page}}.html,{\\\"webView\\\":true}\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 0.25}}, {\"title\": \"其他\", \"url\": \"http:\/\/m.ciweiku.com\/ciwei127-{{page}}.html,{\\\"webView\\\":true}\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 0.25}}, {\"title\": \"\", \"url\": \"\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 0.25}}, {\"title\": \"\", \"url\": \"\", \"style\": {\"layout_flexGrow\": 1, \"layout_flexBasisPercent\": 0.25}}]","header":"{\"User-Agent\": \"Mozilla\/5.0 (Linux; Android 12; V2283A) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/120.0 Mobile Safari\/537.36\", \"Referer\": \"http:\/\/m.ciweiku.com\/\"}","jsLib":"function coverOf(bookUrl) {\nvar m = String(bookUrl || '').match(\/ciwei\\\/(\\d+)_(\\d+)\\\/\/);\nif (!m) return '';\nreturn 'http:\/\/m.ciweiku.com\/files\/article\/image\/' + m[1] + '\/' + m[2] + '\/' + m[2] + 's.jpg';\n}\nfunction cleanIntroText(t) {\nvar s = String(t || '').replace(\/\\s+\/g, ' ').trim();\ns = s.replace(\/\\s*\\.\\.\\.[\\s\\S]*$\/, '');\ns = s.replace(\/\\[点击阅读\\]\/g, '').trim();\nreturn s;\n}\nfunction mkCard(name, author, kind, last, intro, cover, bookUrl, upd) {\nvar div = new org.jsoup.nodes.Element('div');\nvar h3 = new org.jsoup.nodes.Element('h3');\nvar a = new org.jsoup.nodes.Element('a');\na.attr('href', bookUrl);\na.text(name || '');\nh3.appendChild(a);\ndiv.appendChild(h3);\nif (cover) {\nvar im = new org.jsoup.nodes.Element('img');\nim.attr('src', cover);\ndiv.appendChild(im);\n}\nvar fields = [['au', author], ['ki', kind], ['lc', last], ['ut', upd]];\nfor (var i = 0; i < fields.length; i++) {\nvar sp = new org.jsoup.nodes.Element('span');\nsp.attr('class', fields[i][0]);\nsp.text(fields[i][1] || '');\ndiv.appendChild(sp);\n}\nvar p = new org.jsoup.nodes.Element('p');\np.text(intro || '');\ndiv.appendChild(p);\nreturn div;\n}\nfunction mediaCards(scope) {\nvar out = new org.jsoup.select.Elements();\nvar items = scope.select('div.media, li.list-group-item');\nfor (var i = 0; i < items.size(); i++) {\nvar c = items.get(i);\nif (String(c.tagName()) === 'li') {\nvar la = c.select('a[href*=\"\/ciwei\/\"]').first();\nif (!la) continue;\nvar lname = String(la.text()).replace(\/\\s+\/g, ' ').trim();\nvar lurl = String(la.attr('abs:href') || la.attr('href') || '');\nif (!lname || !lurl) continue;\nout.add(mkCard(lname, '', '', '', '', coverOf(lurl), lurl, ''));\ncontinue;\n}\nvar a = c.select('h4.book-title a').first();\nif (!a) continue;\nvar name = String(a.text()).replace(\/\\s+\/g, ' ').trim();\nvar url = String(a.attr('abs:href') || a.attr('href') || '');\nif (!name || !url) continue;\nvar au = c.select('.book_author a').first();\nvar author = au ? String(au.text()).trim() : '';\nvar ip = c.select('p.book-intro-index, p.cat-book-intro').first();\nvar intro = '';\nif (ip) {\nvar clone = ip.clone();\nclone.select('a').remove();\nintro = cleanIntroText(clone.text());\n}\nvar img = c.select('.media-left img, img').first();\nvar cover = img ? String(img.attr('abs:src') || img.attr('src') || '') : '';\nif (!cover) cover = coverOf(url);\nout.add(mkCard(name, author, '', '', intro, cover, url, ''));\n}\nreturn out;\n}\nfunction findPanel(doc, kw) {\nvar panels = doc.select('.panel');\nfor (var i = 0; i < panels.size(); i++) {\nvar hd = panels.get(i).select('.panel-heading').first();\nif (hd && String(hd.text()).indexOf(kw) >= 0) return panels.get(i);\n}\nreturn null;\n}\nfunction tocLis(doc) {\nvar panels = doc.select('.panel');\nfor (var i = 0; i < panels.size(); i++) {\nvar hd = panels.get(i).select('.panel-heading').first();\nif (hd && String(hd.text()).indexOf('全部章节') >= 0) return panels.get(i).select('ul.list-charts li');\n}\nvar firstUl = doc.select('ul.list-charts').first();\nreturn firstUl ? firstUl.select('li') : new org.jsoup.select.Elements();\n}function tipItem(msg, url) {\nvar out = new org.jsoup.select.Elements();\nvar div = new org.jsoup.nodes.Element('div');\nvar h3 = new org.jsoup.nodes.Element('h3');\nvar a = new org.jsoup.nodes.Element('a');\na.attr('href', url);\na.text(msg);\nh3.appendChild(a);\ndiv.appendChild(h3);\nout.add(div);\nreturn out;\n}\n","lastUpdateTime":"1792764654453","loginUrl":"http:\/\/m.ciweiku.com\/","respondTime":60000,"ruleBookInfo":{"author":".info2 h3 a@text","coverUrl":".info1 img@src##^##http:\/\/m.ciweiku.com","intro":".info2 div p@text","kind":"@js:\n(function () {\nvar doc = org.jsoup.Jsoup.parse(String(result || ''), String(baseUrl || ''));\nvar p = doc.select('.info3 p').first();\nif (!p) return '';\nvar t = String(p.text());\nvar kind = '';\nvar status = '';\nvar mk = t.match(\/小说类别[:：]\\s*([^\/]+)\/);\nif (mk) kind = mk[1].trim();\nvar ms = t.match(\/写作状态[:：]\\s*(\\S+)\/);\nif (ms) status = ms[1].trim();\nif (kind && status) return kind + ' · ' + status;\nreturn kind || status;\n})()","lastChapter":"@js:\n(function () {\nvar doc = org.jsoup.Jsoup.parse(String(result || ''), String(baseUrl || ''));\nvar lis = tocLis(doc);\nif (lis.size() > 0) {\nvar la = lis.get(lis.size() - 1).select('a').first();\nif (la) return String(la.text()).replace(\/\\s+\/g, ' ').trim();\n}\nvar a = doc.select('.info3 a[href*=\"\/ciweik\/\"]').first();\nreturn a ? String(a.text()).replace(\/\\s+\/g, ' ').trim() : '';\n})()","name":".info2 h1@text","tocUrl":"@js:\n(function () {\ntry {\nvar u = String(baseUrl || '');\nif (u) return u + ',{\"webView\":true}';\n} catch (e) {}\ntry {\nvar doc = org.jsoup.Jsoup.parse(String(result || ''));\nvar og = doc.select('meta[property=og:url]').first();\nvar u2 = og ? String(og.attr('content') || '') : '';\nif (u2) return u2 + ',{\"webView\":true}';\n} catch (e2) {}\nreturn '';\n})()"},"ruleContent":{"content":"@js:\n(function () {\nfunction extract(htmlText, url) {\nvar doc = org.jsoup.Jsoup.parse(htmlText, url);\nvar art = doc.select('div.content-body').first();\nif (!art) {\nvar divs = doc.select('div, td');\nvar best = null, bs = -1;\nfor (var i = 0; i < divs.size(); i++) {\nvar el = divs.get(i);\nvar t = String(el.text());\nvar sc = t.length - el.select('a').size() * 60;\nif (sc > bs) { bs = sc; best = el; }\n}\nart = best;\n}\nif (!art) return '';\nart.select('script, style, ins, iframe, #content_tip').remove();\nvar h = String(art.html());\nh = h.replace(\/（本章未完，请点击下一页继续阅读）\/g, '');\nh = h.replace(\/最新网址：m\\.ciweiku\\.com\/g, '');\nh = h.replace(\/^\\s*(<br\\s*\\\/?>\\s*)*[^<]{0,80}?\\(第\\d+\\\/\\d+页\\)\/, '');\nh = h.replace(\/^(\\s|<br\\s*\\\/?>)+\/, '');\ntry {\nvar cn = String(chapter.name || '').replace(\/\\s+\/g, ' ').trim();\nif (cn) {\nvar segEnd = h.indexOf('<br');\nvar seg = (segEnd >= 0 ? h.substring(0, segEnd) : h).replace(\/<[^>]+>\/g, '').replace(\/\\s+\/g, ' ').trim();\nif (seg === cn) {\nvar rest = segEnd >= 0 ? h.substring(segEnd) : '';\nh = rest.replace(\/^(\\s|<br\\s*\\\/?>)+\/, '');\n}\n}\n} catch (e) {}\nvar _cl = h.replace(\/[^<>]*被 Cloudflare 拦截[^<>]*\/g, '');\nif (_cl.replace(\/<[^>]+>\/g, '').replace(\/\\s+\/g, '')) h = _cl;\nreturn h;\n}\nvar _h = String(result || '');\nif (_h.indexOf('Just a moment') >= 0) return '本章被 Cloudflare 拦截：请先关闭 VPN，或点源菜单『登录』在网页里过一次验证后再读。';\nreturn extract(_h, String(baseUrl || ''));\n})()","nextContentUrl":"@js:\n(function () {\nvar doc = org.jsoup.Jsoup.parse(String(result || ''), String(baseUrl || ''));\nvar as = doc.select('ul.pager a');\nfor (var i = 0; i < as.size(); i++) {\nif (String(as.get(i).text()).replace(\/\\s+\/g, '') === '下一页') {\nvar u = String(as.get(i).attr('abs:href') || '');\nreturn u ? u + ',{\"webView\":true}' : '';\n}\n}\nreturn '';\n})()","replaceRegex":"##本章被 Cloudflare 拦截[^\\n<]*|被 Cloudflare 拦截[^\\n<]*"},"ruleExplore":{"author":"span.au@text","bookList":"@js:\n(function () {\nvar _html = String(result || '');\nif (_html.indexOf('Just a moment') >= 0) return tipItem('被 Cloudflare 拦截：请先关闭 VPN 再试；若仍被拦，点源菜单『登录』在网页里过一次验证', String(baseUrl || ''));\nvar doc = org.jsoup.Jsoup.parse(String(result || ''), String(baseUrl || ''));\nvar url = String(baseUrl || '');\nvar bm = url.match(\/[?&]board=(\\w+)\/);\nvar board = bm ? bm[1] : '';\nif (!board) {\nvar mp = findPanel(doc, '列表');\nreturn mp ? mediaCards(mp) : mediaCards(doc);\n}\nif (board === 'rec') { var p1 = findPanel(doc, '为您推荐'); return p1 ? mediaCards(p1) : mediaCards(doc); }\nif (board === 'new') { var p2 = findPanel(doc, '新书入库'); return p2 ? mediaCards(p2) : new org.jsoup.select.Elements(); }\nif (board === 'read') { var p3 = findPanel(doc, '阅读排行'); return p3 ? mediaCards(p3) : new org.jsoup.select.Elements(); }\nif (board === 'zan') { var p4 = findPanel(doc, '热赞排行'); return p4 ? mediaCards(p4) : new org.jsoup.select.Elements(); }\nif (board === 'hot') {\nvar out = new org.jsoup.select.Elements();\nvar ph = findPanel(doc, '网友热搜');\nif (ph) {\nvar lis = ph.select('li');\nfor (var i = 0; i < lis.size(); i++) {\nvar a = lis.get(i).select('a[href*=\"\/ciwei\/\"]').first();\nif (!a) continue;\nvar name = String(a.text()).replace(\/\\s+\/g, ' ').trim();\nvar u = String(a.attr('abs:href') || a.attr('href') || '');\nif (!name || !u) continue;\nvar lt = String(lis.get(i).text());\nvar ma = lt.match(\/[(（]([^)）]+)[)）]\/);\nout.add(mkCard(name, ma ? ma[1] : '', '', '', '', coverOf(u), u, ''));\n}\n}\nreturn out;\n}\nif (board === 'update') {\nvar out2 = new org.jsoup.select.Elements();\nvar pu = findPanel(doc, '今日更新');\nif (pu) {\nvar rows = pu.select('tr');\nfor (var j = 0; j < rows.size(); j++) {\nvar tr = rows.get(j);\nvar a2 = tr.select('td a[href*=\"\/ciwei\/\"]').first();\nif (!a2) continue;\nvar name2 = String(a2.text()).replace(\/\\s+\/g, ' ').trim();\nvar u2 = String(a2.attr('abs:href') || a2.attr('href') || '');\nif (!name2 || !u2) continue;\nvar kind = '';\nvar ka = tr.select('td.book_author a[href*=\"ciwei\"]').first();\nif (ka) kind = String(ka.text()).trim();\nvar lc = '';\nvar la = tr.select('td.index-chapter a').first();\nif (la) lc = String(la.text()).replace(\/\\s+\/g, ' ').trim();\nvar author2 = '';\nvar aua = tr.select('td.book_author a:not([href])').first();\nif (aua) author2 = String(aua.text()).trim();\nif (!author2) {\nvar aut = tr.select('td.book_author');\nfor (var q = 0; q < aut.size(); q++) {\nvar at = String(aut.get(q).text()).trim();\nif (at && at !== kind && at.charAt(0) !== '[') author2 = at;\n}\n}\nvar upd2 = '';\nvar upe = tr.select('td.book_update').first();\nif (upe) upd2 = String(upe.text()).trim();\nout2.add(mkCard(name2, author2, kind, lc, '', coverOf(u2), u2, upd2));\n}\n}\nreturn out2;\n}\nreturn mediaCards(doc);\n})()","bookUrl":"h3 a@href","coverUrl":"img@src","intro":"p@text","kind":"span.ki@text","lastChapter":"span.lc@text","name":"h3 a@text"},"ruleSearch":{"author":"span.au@text","bookList":"@js:\n(function () {\nvar _html = String(result || '');\nif (_html.indexOf('Just a moment') >= 0) return tipItem('被 Cloudflare 拦截：请先关闭 VPN 再试；若仍被拦，点源菜单『登录』在网页里过一次验证', String(baseUrl || ''));\nvar doc = org.jsoup.Jsoup.parse(String(result || ''), String(baseUrl || ''));\nvar out = new org.jsoup.select.Elements();\nvar rows = doc.select('table.bookcon tr');\nfor (var i = 0; i < rows.size(); i++) {\nvar tr = rows.get(i);\nvar a = tr.select('td a[href*=\"\/ciwei\/\"]').first();\nif (!a) continue;\nvar url = String(a.attr('abs:href') || a.attr('href') || '');\nvar name = String(a.text()).replace(\/\\s+\/g, ' ').trim();\nif (!name || !url) continue;\nvar tds = tr.select('td');\nvar author = tds.size() > 2 ? String(tds.get(2).text()).trim() : '';\nvar upd = tds.size() > 3 ? String(tds.get(3).text()).trim() : '';\nvar status = tds.size() > 4 ? String(tds.get(4).text()).trim() : '';\nout.add(mkCard(name, author, status, '', '', coverOf(url), url, upd));\n}\nreturn out;\n})()","bookUrl":"h3 a@href","coverUrl":"img@src","intro":"p@text","kind":"span.ki@text","lastChapter":"span.lc@text","name":"h3 a@text"},"ruleToc":{"chapterList":"@js:\n(function () {\nvar doc = org.jsoup.Jsoup.parse(String(result || ''), String(baseUrl || ''));\nreturn tocLis(doc);\n})()","chapterName":"a@text","chapterUrl":"@js:\n(function () {\nvar base = '';\ntry { base = String(baseUrl || ''); } catch (e) {}\nfunction fix(u) {\nif (!u) return '';\nu = String(u);\nif (u.indexOf('http') === 0) return u;\nvar m = base.match(\/^(https?:\\\/\\\/[^\\\/]+)\/);\nif (m) return m[1] + (u.charAt(0) === '\/' ? u : '\/' + u);\nreturn u;\n}\nvar u = '';\ntry {\nif (result && result.select) {\nvar els = result.select('a');\nif (els && els.size() > 0) u = String(els.first().attr('abs:href') || els.first().attr('href') || '');\n}\n} catch (e) {}\nif (!u) {\ntry {\nvar doc = org.jsoup.Jsoup.parse(String(result || ''), base);\nvar a = doc.select('a').first();\nif (a) u = String(a.attr('abs:href') || a.attr('href') || '');\n} catch (e2) {}\n}\nif (!u) {\ntry {\nvar mm = String(result || '').match(\/href\\s*=\\s*\"([^\"]+)\"\/) || String(result || '').match(\/href\\s*=\\s*'([^']+)'\/);\nif (mm) u = mm[1];\n} catch (e3) {}\n}\nu = fix(u);\nreturn u ? u + ',{\"webView\":true}' : '';\n})()"},"searchUrl":"@js:\n(function () {\nreturn 'http:\/\/m.ciweiku.com\/search.html?searchkey=' + encodeURIComponent(String(key || '')) + ',{\"webView\":true}';\n})()","weight":0}]