八叉书库

https://bcshuku.com

autobcb_admin (12020)01/07 00:58

大灰狼制作后修复了目录
二维码导入(APP尚未完成该功能)
{
    "bookSourceUrl": "https:\/\/bcshuku.com",
    "bookSourceName": "八叉书库",
    "enabledExplore": true,
    "enabled": true,
    "bookSourceGroup": "18",
    "author": "大灰狼修复版",
    "help": false,
    "html": "\n<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <title>八叉书库<\/title>\n<\/head>\n\n<body>\n\n<\/body>\n<script src=\"https:\/\/vc.jd.com\/web\/js\/jquery-3.1.1.min.js\"><\/script>\n<!--如果要引入外部 js 必须在书源代码的上面-->\n<script>\n    var isCookieJar = true;\/\/ 不需要CookieJar请修改此处\n    class FlutterJSBridge {\n        constructor() {\n            this.init(); \/\/前台webview 里必须删除这行\n        }\n\n        init() {\n            if (window.flutter_inappwebview) {\n                this.isReady = true;\n                this.CookieJar();\n            } else {\n                window.addEventListener('flutterInAppWebViewPlatformReady', () => {\n                    this.isReady = true;\n                    console.log('JSBridge初始化完成');\n                    this.CookieJar();\n                });\n            }\n        }\n\n        \/\/通知原生页面初始化完成,仅在书源和tts生效,webview请勿使用,只有通知加载成功后才允许运行,否则会一直等待加载成功\n        async CookieJar() {\n            try {\n                await window.flutter_inappwebview.callHandler('CookieJar', isCookieJar);\n            } catch (error) {\n                console.error('汇报完成准备失败:', error);\n            }\n        }\n\n        \/\/获取应用编译版本\n        async getbuildNumber() {\n            try {\n                return await window.flutter_inappwebview.callHandler('buildNumber');\n            } catch (error) {\n                return 0;\n            }\n        }\n\n        \/\/获取应用版本\n        async getversion() {\n            try {\n                return await window.flutter_inappwebview.callHandler('version');\n            } catch (error) {\n                return \"0.0.0\";\n            }\n        }\n\n        \/\/获取设备唯一id\n        async getDeviceid() {\n            try {\n                return await window.flutter_inappwebview.callHandler('id');\n            } catch (error) {\n                return \"\";\n            }\n        }\n\n        \/\/获取设备平台 此处返回 windows、macos、ios、ohos、android\n        async getDevice() {\n            try {\n                return await window.flutter_inappwebview.callHandler('device');\n            } catch (error) {\n                return \"\";\n            }\n        }\n\n        \/\/输出日志,前台webview请勿使用\n        \/\/str 为 String\n        async log(str) {\n            try {\n                return await window.flutter_inappwebview.callHandler('log', str);\n            } catch (error) {\n                return false;\n            }\n        }\n\n        \/\/书源调试时可输出 html 代码到前台\n        \/\/type 0 搜索源码 , 1详情源码 ,2目录源码 ,3正文源码\n        \/\/str 为 String\n        \/\/type 为int\n        async text(type, str) {\n            try {\n                return await window.flutter_inappwebview.callHandler('text', type, str);\n            } catch (error) {\n                return false;\n            }\n        }\n\n        \/\/toast弹窗\n        \/\/str 为 String\n        async showToast(str) {\n            try {\n                return await window.flutter_inappwebview.callHandler('showToast', str);\n            } catch (error) {\n                return false;\n            }\n        }\n\n        \/\/获取默认ua\n        async getWebViewUA() {\n            try {\n                return await window.flutter_inappwebview.callHandler('getWebViewUA');\n            } catch (error) {\n                return \"\";\n            }\n        }\n\n        \/\/通过url打开外部应用\n        \/\/url 为 String\n        async openurl(url) {\n            try {\n                return await window.flutter_inappwebview.callHandler('openurl', url, \"\");\n            } catch (error) {\n                return false;\n            }\n        }\n\n        \/\/通过url打开外部应用并附带mimeType\n        \/\/url 为 String\n        \/\/mimeType 为 String\n        async openurlwithMimeType(url, mimeType) {\n            try {\n                return await window.flutter_inappwebview.callHandler('openurl', url, mimeType);\n            } catch (error) {\n                return false;\n            }\n        }\n\n        \/**\n         * 使用webView访问网络\n         * @param html 直接用webView载入的html, 如果html为空直接访问url\n         * @param url html内如果有相对路径的资源不传入url访问不了\n         * @param js 用来取返回值的js语句, 没有就返回整个源代码\n         * @param body 当参数不为空的时候,会以post请求,此时请务必在 header 中带上content-type\n         * @param header 请求的header头,此参数必须是json字符串\n         * @return 返回js获取的内容\n         *\/\n        async webview(url, js, html, body, header) {\n            try {\n                return await window.flutter_inappwebview.callHandler('webview', url, js, html, body, header, \"\", \"\");\n            } catch (error) {\n                return \"\";\n            }\n        }\n\n        \/**\n         * overrideUrlRegex 为正则表达式\n         * 使用方法和上面的一样\n         * 但返回的内容为正则到的内容,如果无法正则到则返回 js 获取的内容,如果 js 为空则返回页面 html\n         *\/\n        async webViewGetOverrideUrl(url, js, html, body, header, overrideUrlRegex) {\n            try {\n                return await window.flutter_inappwebview.callHandler('webview', url, js, html, body, header, overrideUrlRegex, \"\");\n            } catch (error) {\n                return \"\";\n            }\n        }\n\n        \/**\n         * 使用webView获取资源url\n         * urlregex 为正则表达式\n         * 使用方法和上面的一样\n         * 但返回的内容为正则到的内容,如果无法正则到则返回 js 获取的内容,如果 js 为空则返回页面 html\n         *\/\n        async webViewGetSource(url, js, html, body, header, urlregex) {\n            try {\n                return await window.flutter_inappwebview.callHandler('webview', url, js, html, body, header, \"\", urlregex);\n            } catch (error) {\n                return \"\";\n            }\n        }\n\n\n        \/**\n         * 启动前台 webview 访问链接并获取结束时的 html,可用于手工过盾\n         * @param url 网址\n         * @param title 标题\n         * @param header 请求的header头,此参数必须是json字符串\n         * @return 返回网页的内容\n         *\/\n        async startBrowser(url, title, header) {\n            try {\n                return await window.flutter_inappwebview.callHandler('startBrowser', url, title, header);\n            } catch (error) {\n                return \"\";\n            }\n        }\n\n        \/\/专门为段评设置的半屏显示,不返回任何东西\n        async startBrowserDp(url, title) {\n            try {\n                return await window.flutter_inappwebview.callHandler('startBrowserDp', url, title);\n            } catch (error) {\n                return \"\";\n            }\n        }\n\n        \/\/仅前台webview可以使用,返回按钮,返回上一个页面\n        async back() {\n            try {\n                return await window.flutter_inappwebview.callHandler('back');\n            } catch (error) {\n                return false;\n            }\n        }\n\n        \/\/将 utf8字符串转到 gbk 并 url 编码\n        async utf8ToGbkUrlEncoded(str) {\n            try {\n                return await window.flutter_inappwebview.callHandler('utf8ToGbkUrlEncoded', str);\n            } catch (error) {\n                return \"\";\n            }\n        }\n\n        \/*\n        * @param str为图片链接\n        * @param header 请求的header头,此参数必须是json字符串\n        * 此函数是让用户输入图片中的验证码,当链接为空则直接让用户输入验证码\n        *\/\n        async getVerificationCode(str, header) {\n            try {\n                return await window.flutter_inappwebview.callHandler('getVerificationCode', str, header);\n            } catch (error) {\n                return \"\";\n            }\n        }\n\n        \/\/提交内容书本信息 json 后的字符串\n        async addbook(book) {\n            try {\n                return await window.flutter_inappwebview.callHandler('addbook', book);\n            } catch (error) {\n                return \"\";\n            }\n        }\n\n    }\n\n    \/\/webview请勿使用\n    \/\/以下提交的url,headers,body 都必须为字符串,headers必须为json字符串\n    \/\/当followRedirects 为 false 时不处理重定向,当为 true 时会自动处理重定向 ,如不明白用途直接用 true 最佳\n    \/\/ 以下所有参数除当followRedirects外均为 String\n    class Http {\n        constructor() { }\n\n        \/*\n         * 通用返回字段\n         * method post get 或者 head\n         * body 请求返回后的字节的 base64\n         * headers  map<String,List<String>> 可通过headers[\"\"]来或者\n         * statusCode 状态码\n         * statusMessage\n         * data 返回后的字节 格式化后的内容\n         *\/\n        async Get(url, headers, followRedirects) {\n            try {\n                return await window.flutter_inappwebview.callHandler('http', \"get\", url, \"\", JSON.stringify(headers), followRedirects, \"\");\n            } catch (error) {\n                return null;\n            }\n        }\n\n        async Head(url, headers, followRedirects) {\n            try {\n                return await window.flutter_inappwebview.callHandler('http', \"head\", url, \"\", JSON.stringify(headers), followRedirects, \"\");\n            } catch (error) {\n                return null;\n            }\n        }\n\n\n        async Post(url, headers, body, contenttype, followRedirects) {\n            try {\n                return await window.flutter_inappwebview.callHandler('http', \"post\", url, body, JSON.stringify(headers), followRedirects, contenttype);\n            } catch (error) {\n                return null;\n            }\n        }\n    }\n\n    class Cache {\n        constructor() { }\n        async get(key) {\n            try {\n                return await window.flutter_inappwebview.callHandler('cache.get', key);\n            } catch (error) {\n                return null;\n            }\n        }\n\n        async set(key, value) {\n            try {\n                return await window.flutter_inappwebview.callHandler('cache.set', key, value);\n            } catch (error) {\n                return null;\n            }\n        }\n\n        async remove(key) {\n            try {\n                return await window.flutter_inappwebview.callHandler('cache.remove', key);\n            } catch (error) {\n                return null;\n            }\n        }\n\n        \/\/如果登录为弹窗格式的,里面输入框输入的内容可以通过这个函数获取,默认返回的json格式或者为空,需要自行转换\n        async getLoginInfo() {\n            return await this.get(\"LoginInfo\")\n        }\n\n        \/\/将修改后的弹窗输入内容报错 ,必须 JSON.stringify,不然会出错\n        async putLoginInfo(info) {\n            return await this.set(\"LoginInfo\", info)\n        }\n\n        \/\/获取书本变量\n        async getbookVariable(bookurl) {\n            return await this.get(bookurl)\n        }\n\n        \/\/写入书本变量\n        async setbookVariable(bookurl, value) {\n            return await this.set(bookurl, value)\n        }\n    }\n\n    class Cookie {\n        constructor() { }\n\n        \/\/通过url获取当前url的所有cookie\n        async get(url) {\n            try {\n                return await window.flutter_inappwebview.callHandler('cookie.get', url);\n            } catch (error) {\n                return null;\n            }\n        }\n\n        \/\/通过url删除当前url的所有cookie\n        async remove(url) {\n            try {\n                return await window.flutter_inappwebview.callHandler('cookie.remove', url);\n            } catch (error) {\n                return null;\n            }\n        }\n\n\n        \/\/通过url保存当前url的所有cookie\n        async set(url, value) {\n            try {\n                return await window.flutter_inappwebview.callHandler('cookie.set', url, value);\n            } catch (error) {\n                return null;\n            }\n        }\n\n        \/\/通过 url 获取单个 cookie 的值\n        async getCookie(url, value) {\n            try {\n                return await window.flutter_inappwebview.callHandler('cookie.getCookie', url, value);\n            } catch (error) {\n                return null;\n            }\n        }\n    }\n\n    \/\/安全的创建一个 div 解析 html\n    function parseHTMLSafely(htmlStr) {\n        try {\n            \/\/ 在函数作用域内创建独立的临时容器\n            \/\/ 每个调用创建新的jQuery对象,互不影响\n            var tempDiv = document.createElement('div');\n            tempDiv.innerHTML = htmlStr;\n            return $(tempDiv);\n        } catch (e) {\n            flutterBridge.log(\"HTML解析错误:\" + e.message);\n            return $('<div>');\n        }\n    }\n\n    \/\/parseHTMLSafely 创建的用完后必须删除\n    function removeHTMLSafely(tempContainer) {\n        try {\n            tempContainer.innerHTML = '';\n            if (tempContainer.parentNode) {\n                tempContainer.parentNode.removeChild(tempContainer);\n            }\n        } catch (e) {\n            flutterBridge.log(\"HTML移除失败:\" + e.message);\n        }\n    }\n\n    \/\/移除 css js,创建parseHTMLSafely前如果用不上 cssjs 建议移除\n    function removeHTMLTags(htmlString) {\n        \/\/ 移除script标签\n        let result = htmlString.replace(\/<script\\b[^<]*(?:(?!<\\\/script>)<[^<]*)*<\\\/script>\/gi, '');\n        \/\/ 移除style标签\n        result = result.replace(\/<style\\b[^<]*(?:(?!<\\\/style>)<[^<]*)*<\\\/style>\/gi, '');\n        return result;\n    }\n\n<\/script>\n<script>\n    const flutterBridge = new FlutterJSBridge();\n    const cache = new Cache();\n    const http = new Http();\n    const cookie = new Cookie();\n    var baseurl = \"https:\/\/www.8xsk.info\"\n    var header = { \"User-Agent\": \"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/131.0.0.0 Safari\/537.36\" };\n\n    \/\/ 搜索函数\n    async function search(key, page) {\n        if (page > 1) {\n            return \"[]\";\n        }\n\n        try {\n            var url = baseurl + \"\/e\/search\/index.php?keyboard=\" + encodeURIComponent(key) + \"&show=title,writer,byr&searchget=1\";\n            var myheader = {\n                ...header,\n                \"Referer\": baseurl\n            };\n\n            var get = await http.Get(url, JSON.stringify(myheader), true);\n            flutterBridge.text(0, get.data);\n\n            return parseBookList(get.data);\n        } catch (e) {\n            flutterBridge.log(\"搜索出错:\" + e.message);\n            return \"[]\";\n        }\n    }\n\n    \/\/ 书籍详情函数\n    async function info(bookurl) {\n        try {\n            var get = await http.Get(bookurl, JSON.stringify(header), true);\n            flutterBridge.text(1, get.data);\n\n            var $tempContainer = parseHTMLSafely(removeHTMLTags(get.data));\n\n            \/\/ 提取书名\n            var name = $tempContainer.find(\"h1\").first().text().trim();\n\n            \/\/ 提取作者\n            var author = \"\";\n            \/\/ 优先使用 itemprop='author' 属性\n            var $authorLink = $tempContainer.find(\"a[itemprop='author'], .info-chitiet a[href*='show=writer']\").first();\n            if ($authorLink.length > 0) {\n                \/\/ 直接获取文本\n                author = $authorLink.text().trim();\n\n                \/\/ 如果文本为空,尝试从URL解析\n                if (!author) {\n                    var href = $authorLink.attr('href');\n                    if (href) {\n                        var match = href.match(\/keyboard=([^&]+)\/); \/\/ Corrected regex\n                        if (match) {\n                            author = decodeURIComponent(match[1]);\n                        }\n                    }\n                }\n            }\n\n            \/\/ 提取封面\n            var coverUrl = \"\";\n            \/\/ 优先使用.col-md-3 img选择器(详情页结构)\n            var imgElem = $tempContainer.find(\".col-md-3 img, .img-responsive, img.img-book\").first();\n            if (imgElem.length > 0) {\n                var src = imgElem.attr('src');\n                if (src) {\n                    if (src.startsWith('http')) {\n                        coverUrl = src;\n                    } else {\n                        coverUrl = baseurl + src;\n                    }\n                }\n            }\n\n            \/\/ 提取分类\n            var kind = \"\";\n            \/\/ 优先使用 itemprop='genre' 属性\n            var $categoryLink = $tempContainer.find(\"a[itemprop='genre'], .info-chitiet a[href*='\/booklist']\").first();\n            if ($categoryLink.length > 0) {\n                var categoryText = $categoryLink.text().trim();\n                \/\/ 过滤\"未知\"\n                if (categoryText && categoryText !== \"未知\") {\n                    kind = \"分类:\" + categoryText;  \/\/ 添加\"分类:\"前缀\n                }\n            }\n\n            \/\/ 提取简介\n            var intro = \"\";\n            \/\/ 优先使用 .desc-text 选择器\n            var $descText = $tempContainer.find(\".desc-text\").first();\n            if ($descText.length > 0) {\n                intro = $descText.text().trim();\n                \/\/ 移除开头的\"小说介绍\"字样\n                intro = intro.replace(\/^小说介绍\\s*\/, \"\").trim();\n            }\n\n            \/\/ 备用方法1: 查找包含\"小说介绍\"的元素\n            if (!intro) {\n                var $introContainer = $tempContainer.find(\"*\").filter(function () {\n                    return $(this).text().trim() === \"小说介绍\" || $(this).text().includes(\"小说介绍\");\n                }).first();\n\n                if ($introContainer.length > 0) {\n                    var parentText = $introContainer.parent().text();\n                    intro = parentText.replace(\/小说介绍\\s*\/g, \"\").trim();\n                }\n            }\n\n            \/\/ 备用方法2: 查找较长的 p 标签\n            if (!intro) {\n                $tempContainer.find(\"p\").each(function () {\n                    var text = $(this).text().trim();\n                    if (text.length > 50 && !text.includes(\"最新章节\") && !text.includes(\"作者\")) {\n                        intro = text;\n                        return false;\n                    }\n                });\n            }\n\n            \/\/ 清理简介:移除\"未知\"等无意义的占位符\n            if (intro) {\n                intro = intro.replace(\/^未知\\s*$\/g, \"\").trim();  \/\/ 如果整个简介就是\"未知\",清空\n                intro = intro.replace(\/^\\s*未知\\s*$\/gm, \"\").trim();  \/\/ 移除只包含\"未知\"的行\n            }\n\n            \/\/ 提取观看人数 - 根据glyphicon-eye-open图标定位\n            var viewCount = \"\";\n\n            \/\/ 方法1: 通过glyphicon-eye-open图标查找\n            var $eyeIcon = $tempContainer.find(\".glyphicon-eye-open\").first();\n            if ($eyeIcon.length > 0) {\n                \/\/ 图标在h3中,观看人数在h3后面的span中\n                var $h3 = $eyeIcon.closest('h3');\n                if ($h3.length > 0) {\n                    var $viewElem = $h3.next('span');\n                    if ($viewElem.length > 0) {\n                        var viewText = $viewElem.text().trim();\n                        if (viewText && \/^\\d+$\/.test(viewText)) {\n                            viewCount = \"观看:\" + viewText;\n                        }\n                    }\n                }\n            }\n\n            \/\/ 方法2: 如果方法1失败,尝试查找纯数字p标签(兼容旧版HTML)\n            if (!viewCount) {\n                var $infoParagraphs = $tempContainer.find(\".info-chitiet p\");\n                $infoParagraphs.each(function () {\n                    var $p = $(this);\n                    \/\/ 跳过有图标的p标签\n                    if ($p.find(\".glyphicon\").length > 0) {\n                        return true; \/\/ continue\n                    }\n\n                    \/\/ 获取纯文本\n                    var text = $p.text().trim();\n                    \/\/ 检查是否是纯数字(观看人数)\n                    if (\/^\\d+$\/.test(text)) {\n                        viewCount = \"观看:\" + text;\n                        return false; \/\/ break\n                    }\n                });\n            }\n\n            \/\/ 提取更新日期 - 从连载状态后面提取\n            var updateDate = \"\";\n            var $statusElem = $tempContainer.find(\".info-chitiet span.text-primary\").first();\n            if ($statusElem.length > 0) {\n                var statusText = $statusElem.text().trim();\n                \/\/ 提取日期部分,格式如 \"连载中 2025-12-23\" 或 \"完结 2025-12-23\"\n                var dateMatch = statusText.match(\/(\\d{4}[-\\\/]\\d{1,2}[-\\\/]\\d{1,2})\/);\n                if (dateMatch) {\n                    updateDate = dateMatch[1];\n                }\n            }\n\n            \/\/ 组合观看人数和更新日期\n            var wordCountInfo = viewCount;\n            if (updateDate) {\n                if (wordCountInfo) {\n                    wordCountInfo += \" \" + updateDate;\n                } else {\n                    wordCountInfo = updateDate;\n                }\n            }\n\n            \/\/ 提取最新章节\n            var latestChapterTitle = \"\";\n            var latestLink = $tempContainer.find(\"a[href*='\/chapter']\").last();\n            if (latestLink.length > 0) {\n                latestChapterTitle = latestLink.text().trim();\n            }\n\n            var book = {\n                \"bookUrl\": bookurl,\n                \"name\": name,\n                \"author\": author,\n                \"kind\": kind,\n                \"coverUrl\": coverUrl,\n                \"intro\": intro,\n                \"tocUrl\": bookurl,\n                \"wordCount\": wordCountInfo,  \/\/ 使用wordCount字段存储观看人数和更新日期\n                \"type\": 0,\n                \"latestChapterTitle\": latestChapterTitle,\n            };\n\n            removeHTMLSafely($tempContainer);\n            return JSON.stringify(book);\n        } catch (e) {\n            flutterBridge.log(\"获取详情出错:\" + e.message);\n            return \"{}\";\n        }\n    }\n\n    \/\/ 章节列表函数\n    async function chapter(tocUrl) {\n        var i=0\n        var chapters = [];\n        var last=\"\"\n        while (true){\n            if(i === 0){\n                var c= await  chapter2(tocUrl)\n                last=c.last;\n                if(c.chapters.length > 0){\n                    chapters.push(...c.chapters);\n                }else{\n                    break;\n                }\n            }else{\n                var c= await  chapter2(tocUrl+\"?p=\"+(i+1))\n                if(c.chapters.length > 0){\n                    chapters.push(...c.chapters);\n                }else{\n                    break;\n                }\n            }\n            if(last == \"\"){\n                break;\n            }\n            if((tocUrl+\"?p=\"+(i+1)).includes(last)){\n                break;\n            }\n            i++;\n\n        }\n        return JSON.stringify(chapters);\n    }\n\n    async function chapter2(tocUrl) {\n        var last=\"\"\n        var chapters = [];\n        try {\n            var get = await http.Get(tocUrl, JSON.stringify(header), true);\n            flutterBridge.text(2, get.data);\n            for(var i=2 ;i< 100;i++){\n                if(get.data.includes(\"?p=\"+i)){\n                    last=\"?p=\"+i;\n                }\n            }\n\n            var $tempContainer = parseHTMLSafely(removeHTMLTags(get.data));\n\n            var index = 0;\n\n            \/\/ 提取书籍ID\n            var novelId = \"\";\n            var match = tocUrl.match(\/\\\/novel(\\d+)\\\/\/);\n            if (match) {\n                novelId = match[1];\n            }\n\n            \/\/ 查找章节列表\n            \/\/ 网站有两个章节区域:\"最新章节\"(倒序)和\"完整章节列表\"(正序)\n            \/\/ 我们只需要完整的章节列表\n\n            \/\/ 方法1: 使用主内容区域的最后一个章节列表\n            var $mainContent = $tempContainer.find(\".col-md-8, .col-xs-12\").first();\n            var $chapterLists = $mainContent.find(\"ul.list-chapter\");\n\n            \/\/ 如果有多个列表,取最后一个(完整列表)\n            var $fullChapterList = $chapterLists.length > 1 ? $chapterLists.last() : $chapterLists.first();\n\n            if ($fullChapterList.length > 0) {\n                $fullChapterList.find(\"li a\").each(function () {\n                    var $link = $(this);\n                    var chapterName = $link.text().trim();\n                    var href = $link.attr('href');\n\n                    if (chapterName && href && href.includes('chapter')) {\n                        var chapterId = \"\";\n                        if (href.startsWith('http')) {\n                            chapterId = href;\n                        } else if (href.startsWith('\/')) {\n                            chapterId = baseurl + href;\n                        } else {\n                            chapterId = baseurl + \"\/novel\" + novelId + \"\/\" + href;\n                        }\n\n                        var chapter = {\n                            \"name\": chapterName,\n                            \"chapterId\": chapterId,\n                            \"index\": index,\n                            \"isPay\": false,\n                            \"isVip\": false,\n                            \"isVolume\": false,\n                            \"tag\": \"\"\n                        };\n                        chapters.push(chapter);\n                        index++;\n                    }\n                });\n            } else {\n                \/\/ 备用方法: 如果没有找到 ul.list-chapter,使用通用选择器\n                flutterBridge.log(\"未找到标准章节列表,使用备用方法\");\n                $tempContainer.find(\"a[href*='chapter']\").each(function () {\n                    var $link = $(this);\n                    var chapterName = $link.text().trim();\n                    var href = $link.attr('href');\n\n                    if (chapterName && href) {\n                        var chapterId = \"\";\n                        if (href.startsWith('http')) {\n                            chapterId = href;\n                        } else if (href.startsWith('\/')) {\n                            chapterId = baseurl + href;\n                        } else {\n                            chapterId = baseurl + \"\/novel\" + novelId + \"\/\" + href;\n                        }\n\n                        var chapter = {\n                            \"name\": chapterName,\n                            \"chapterId\": chapterId,\n                            \"index\": index,\n                            \"isPay\": false,\n                            \"isVip\": false,\n                            \"isVolume\": false,\n                            \"tag\": \"\"\n                        };\n                        chapters.push(chapter);\n                        index++;\n                    }\n                });\n            }\n\n            removeHTMLSafely($tempContainer);\n            return {chapters,last};\n        } catch (e) {\n            flutterBridge.log(\"获取章节列表出错:\" + e.message);\n            return {chapters,last};\n        }\n    }\n\n\n    \/\/ 章节内容函数\n    async function content(url) {\n        try {\n            \/\/ 使用webview来处理JavaScript动态加载的内容\n            \/\/ 等待内容加载完成后再提取\n            var js = `\n        (function() {\n          \/\/ 等待内容加载完成\n          var checkInterval = setInterval(function() {\n            var contentDiv = document.querySelector('#chapter-content, .chapter-content');\n            if(contentDiv && contentDiv.innerText.length > 50 && !contentDiv.innerText.includes('正在加载中')) {\n              clearInterval(checkInterval);\n            }\n          }, 100);\n\n          \/\/ 最多等待5秒\n          setTimeout(function() {\n            clearInterval(checkInterval);\n          }, 5000);\n\n          \/\/ 返回内容\n          setTimeout(function() {\n            var contentDiv = document.querySelector('#chapter-content, .chapter-content');\n            if(contentDiv) {\n              return contentDiv.innerHTML;\n            }\n            return '';\n          }, 2000);\n        })();\n      `;\n\n            \/\/ 使用webview获取动态内容,使用innerText直接获取文本\n            \/\/ 网站使用JavaScript动态加载内容,需要等待加载完成\n            var jsCode = `\n        (function() {\n          var container = document.querySelector('#chapter-content, .chapter-content');\n          if (!container) return '';\n          var text = container.innerText || container.textContent || '';\n          \/\/ 过滤占位文本\n          if (text.includes('精彩内容正在加载中') || text.includes('正在加载中') || text.length < 50) {\n            return '';\n          }\n          return text;\n        })()\n      `;\n\n            var result = await flutterBridge.webview(url, jsCode, \"\", \"\", JSON.stringify(header));\n\n            flutterBridge.text(3, result);\n\n            \/\/ 检查是否成功获取内容\n            if (!result || result.length < 50 || result.includes('精彩内容正在加载中')) {\n                return \"\";\n            }\n\n            \/\/ 清理内容\n            result = result.trim();\n            \/\/ 规范化换行符\n            result = result.replace(\/\\r\\n\/g, \"\\n\").replace(\/\\r\/g, \"\\n\");\n\n            return result;\n        } catch (e) {\n            return \"\";\n        }\n    }\n\n    \/\/ 发现页分类函数\n    async function getfinds() {\n        var sort = [\n            {\n                title: \"长篇\",\n                url: baseurl + \"\/booklist1\/{{page}}\/\",\n                type: 0,\n            },\n            {\n                title: \"综合\",\n                url: baseurl + \"\/booklist2\/{{page}}\/\",\n                type: 0,\n            },\n            {\n                title: \"武侠\",\n                url: baseurl + \"\/booklist3\/{{page}}\/\",\n                type: 0,\n            },\n            {\n                title: \"历史\",\n                url: baseurl + \"\/booklist4\/{{page}}\/\",\n                type: 0,\n            },\n            {\n                title: \"都市\",\n                url: baseurl + \"\/booklist5\/{{page}}\/\",\n                type: 0,\n            },\n            {\n                title: \"玄幻\",\n                url: baseurl + \"\/booklist6\/{{page}}\/\",\n                type: 0,\n            },\n            {\n                title: \"女生\",\n                url: baseurl + \"\/booklist7\/{{page}}\/\",\n                type: 0,\n            },\n            {\n                title: \"其他\",\n                url: baseurl + \"\/booklist8\/{{page}}\/\",\n                type: 0,\n            },\n            {\n                title: \"现代\",\n                url: baseurl + \"\/booklist9\/{{page}}\/\",\n                type: 0,\n            },\n            {\n                title: \"完本小说\",\n                url: baseurl + \"\/completed\/{{page}}\/\",\n                type: 0,\n            },\n            {\n                title: \"热门排行\",\n                url: baseurl + \"\/popular\/{{page}}\/\",\n                type: 0,\n            },\n        ];\n        return JSON.stringify(sort);\n    }\n\n    \/\/ 发现页书籍列表函数\n    async function find(url, page) {\n        try {\n            var targetUrl;\n\n            \/\/ 判断URL类型\n            var isCompleted = url.includes(\"\/completed\");\n            var isPopular = url.includes(\"\/popular\");\n            var isBooklist = url.includes(\"\/booklist\");\n\n            \/\/ 处理{{page}}占位符并生成正确的分页URL\n            if (url.includes(\"{{page}}\")) {\n                \/\/ URL包含占位符,需要根据类型替换为正确的格式\n                if (isCompleted || isPopular) {\n                    \/\/ 完本小说和热门排行的分页格式\n                    \/\/ 第1页: \/completed\/\n                    \/\/ 第2页: \/completed\/index_2.html\n                    if (page === 1) {\n                        \/\/ 第1页:直接移除{{page}}部分\n                        targetUrl = url.replace(\"{{page}}\/\", \"\").replace(\"\/{{page}}\", \"\");\n                    } else {\n                        \/\/ 第N页:将{{page}}\/替换为 index_{page}.html\n                        targetUrl = url.replace(\"{{page}}\/\", \"index_\" + page + \".html\");\n                    }\n                } else if (isBooklist) {\n                    \/\/ 普通分类的分页格式\n                    \/\/ 第1页: \/booklist1\/\n                    \/\/ 第2页: \/booklist1\/1.html\n                    if (page === 1) {\n                        \/\/ 第1页:直接移除{{page}}部分\n                        targetUrl = url.replace(\"{{page}}\/\", \"\").replace(\"\/{{page}}\", \"\");\n                    } else {\n                        \/\/ 第N页:替换为 {page-1}.html\n                        targetUrl = url.replace(\"{{page}}\/\", (page - 1) + \".html\");\n                    }\n                } else {\n                    \/\/ 其他情况:直接替换为页码\n                    targetUrl = url.replace(\"{{page}}\", page.toString());\n                }\n            } else {\n                \/\/ URL不包含占位符(兼容旧格式)\n                if (isCompleted || isPopular) {\n                    if (page === 1) {\n                        targetUrl = url.replace(\/\\\/index(_\\d+)?\\.html$\/, '') + \"\/\";\n                    } else {\n                        targetUrl = url.replace(\/\\\/index(_\\d+)?\\.html$\/, '').replace(\/\\\/$\/, '') + \"\/index_\" + page + \".html\";\n                    }\n                } else if (isBooklist) {\n                    if (page === 1) {\n                        targetUrl = url.replace(\/\\\/\\d+\\.html$\/, '') + \"\/\";\n                    } else {\n                        targetUrl = url.replace(\/\\\/\\d+\\.html$\/, '').replace(\/\\\/$\/, '') + \"\/\" + (page - 1) + \".html\";\n                    }\n                } else {\n                    targetUrl = url;\n                }\n            }\n\n            \/\/ 发送请求\n            var get = await http.Get(targetUrl, JSON.stringify(header), true);\n\n            if (!get || !get.data) {\n                flutterBridge.log(\"❌ HTTP请求失败或返回空数据\");\n                return \"[]\";\n            }\n\n            flutterBridge.text(0, get.data);\n\n            \/\/ 解析书籍列表\n            var result = parseBookList(get.data);\n\n            return result;\n        } catch (e) {\n            return \"[]\";\n        }\n    }\n\n    \/\/ 解析书籍列表的通用函数\n    function parseBookList(html) {\n        try {\n            var $tempContainer = parseHTMLSafely(removeHTMLTags(html));\n            var books = [];\n\n            \/\/ 查找所有书籍卡片 - 使用正确的选择器 .home-truyendecu\n            var $bookCards = $tempContainer.find(\".home-truyendecu\");\n\n            if ($bookCards.length === 0) {\n                removeHTMLSafely($tempContainer);\n                return \"[]\";\n            }\n\n            $bookCards.each(function (index) {\n                try {\n                    var $item = $(this);\n\n                    \/\/ 提取书名和链接 - 从 .caption h3 或 h3[itemprop=\"name\"]\n                    var $titleLink = $item.find(\".caption a[itemprop='url']\").first();\n                    if ($titleLink.length === 0) {\n                        $titleLink = $item.find(\".caption h3 a\").first();\n                    }\n                    if ($titleLink.length === 0) {\n                        return; \/\/ continue\n                    }\n\n                    var name = $titleLink.find(\"h3[itemprop='name']\").text().trim();\n                    if (!name) {\n                        name = $titleLink.text().trim();\n                    }\n                    if (!name) {\n                        name = $item.find(\".caption h3\").text().trim();\n                    }\n\n                    if (!name) {\n                        return; \/\/ continue\n                    }\n\n                    var bookUrl = $titleLink.attr('href');\n                    if (!bookUrl) {\n                        return; \/\/ continue\n                    }\n\n                    \/\/ 规范化bookUrl\n                    if (!bookUrl.startsWith('http')) {\n                        if (bookUrl.startsWith('\/')) {\n                            bookUrl = baseurl + bookUrl;\n                        } else {\n                            bookUrl = baseurl + \"\/\" + bookUrl;\n                        }\n                    }\n\n                    \/\/ 提取封面 - 从 .each_truyen img\n                    var coverUrl = \"\";\n                    var $img = $item.find(\".each_truyen img\").first();\n                    if ($img.length > 0) {\n                        var src = $img.attr('src') || $img.attr('data-src');\n                        if (src) {\n                            if (src.startsWith('http')) {\n                                coverUrl = src;\n                            } else if (src.startsWith('\/')) {\n                                coverUrl = baseurl + src;\n                            } else {\n                                coverUrl = src; \/\/ 可能已经是完整URL\n                            }\n                        }\n                    }\n\n                    \/\/ 提取作者 - 列表页的作者在 .chi-tiet.chuyen-muc a 中(无href属性)\n                    var author = \"\";\n                    var $authorElem = $item.find(\".chi-tiet.chuyen-muc a\").first();\n                    if ($authorElem.length > 0) {\n                        var authorText = $authorElem.text().trim();\n                        \/\/ 过滤日期格式和纯数字(浏览量)\n                        if (authorText &&\n                            !\/^\\d{4}[-\\\/]\\d{1,2}[-\\\/]\\d{1,2}\/.test(authorText) &&  \/\/ 不是日期\n                            !\/^\\d+$\/.test(authorText) &&  \/\/ 不是纯数字\n                            authorText !== \"未知\") {  \/\/ 不是\"未知\"\n                            author = \"作者:\" + authorText;  \/\/ 添加\"作者:\"前缀\n                        }\n                    }\n\n                    \/\/ 如果没找到,尝试其他位置\n                    if (!author) {\n                        var $chiTiet = $item.find(\".chi-tiet\").first();\n                        if ($chiTiet.length > 0) {\n                            var text = $chiTiet.text().trim();\n                            if (text &&\n                                !\/^\\d{4}[-\\\/]\/.test(text) &&\n                                !\/^\\d+$\/.test(text) &&\n                                text !== \"未知\") {\n                                author = \"作者:\" + text;  \/\/ 添加\"作者:\"前缀\n                            }\n                        }\n                    }\n\n                    \/\/ 提取分类 - 列表页不显示\n                    var kind = \"\";\n\n                    \/\/ 提取简介 - 列表页不显示\n                    var intro = \"\";\n\n                    \/\/ 提取最新章节\n                    var latestChapterTitle = \"\";\n                    var $latestChapter = $item.find(\".chi-tiet.tt-status a, .tt-status a\").first();\n                    if ($latestChapter.length > 0) {\n                        latestChapterTitle = $latestChapter.text().trim();\n                    }\n\n                    var book = {\n                        \"bookUrl\": bookUrl,\n                        \"name\": name,\n                        \"author\": author,\n                        \"kind\": kind,\n                        \"coverUrl\": coverUrl,\n                        \"intro\": intro,\n                        \"tocUrl\": bookUrl,\n                        \"wordCount\": \"\",\n                        \"type\": 0,\n                        \"latestChapterTitle\": latestChapterTitle,\n                    };\n                    books.push(book);\n                } catch (e) {\n                    \/\/ 跳过解析失败的书籍\n                }\n            });\n\n            removeHTMLSafely($tempContainer);\n            return JSON.stringify(books);\n        } catch (e) {\n            return \"[]\";\n        }\n    }\n\n    \/\/ 登录相关函数(可选)\n    async function getloginurl() {\n        return \"https:\/\/www.8xsk.info\/\";\n    }\n\n    async function login() {\n\n    }\n\n    \/\/ 导出函数供APP调用\n    window.search = search;\n    window.info = info;\n    window.toc = toc;\n    window.content = content;\n    window.getfinds = getfinds;\n    window.find = find;\n    window.getloginurl = getloginurl;\n    window.login = login;\n\n<\/script>\n\n<\/html>",
    "login": true,
    "lastUpdateTime": "1767718736970"
}
广告