优书网

https://www.ypshuo.com/

dev-xx (13787)08/04 11:28

该用户很懒,什么介绍也没有写!
二维码导入(APP尚未完成该功能)
{
    "bookSourceUrl": "https:\/\/www.ypshuo.com\/",
    "bookSourceName": "优书网",
    "enabledExplore": true,
    "enabled": true,
    "bookSourceGroup": "",
    "author": "",
    "help": false,
    "html": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>优书网<\/title>\n<\/head>\n<body>\n\n<\/body>\n<!-- 没用到jq请去掉-->\n<script src=\"https:\/\/vc.jd.com\/web\/js\/jquery-3.1.1.min.js\"><\/script>\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/crypto-js\/4.2.0\/crypto-js.min.js\"><\/script>\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        \/\/获取应用编译版本,如果版本号大于1000,请去除第一位数字\n        async getbuildNumber() {\n            try {\n                return await window.flutter_inappwebview.callHandler('buildNumber');\n            } catch (error) {\n                return  0;\n            }\n        }\n\n        \/\/获取应用版本,请以编译版本为准,ios tf版本可能不会修改版本号\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        \/\/仅书源支持\n        async getsourceurl() {\n            try {\n                return await window.flutter_inappwebview.callHandler('getsourceurl');\n            } catch (error) {\n                return \"\";\n            }\n        }\n\n        \/\/125版本后支持,获取用户在搜索页选中的分类, -1 全部 0 小说 1 听书 2漫画(需要判断用户是不是在搜索页调用)\n        async getsearch() {\n            try {\n                return await window.flutter_inappwebview.callHandler('getsearch');\n            } catch (error) {\n                return  0;\n            }\n        }\n\n        \/\/下面 2 个接口可以获取屏幕宽高 用于生成图片\n        async getWidth() {\n            try {\n                return await window.flutter_inappwebview.callHandler('getWidth');\n            } catch (error) {\n                return  0;\n            }\n        }\n\n        async getHeight() {\n            try {\n                return await window.flutter_inappwebview.callHandler('getHeight');\n            } catch (error) {\n                return  0;\n            }\n        }\n\n        \/\/将html转换成正文格式\n        async htmlToText(str) {\n            try {\n                return await window.flutter_inappwebview.callHandler('htmlToText',str);\n            } catch (error) {\n                return  \"\";\n            }\n        }\n\n        \/\/调用内置播放器,key为唯一值,请给每个视频定义一个唯一值\n        async showvideoplay(url,title,key) {\n            try {\n                return await window.flutter_inappwebview.callHandler('showvideoplay',url,title,key);\n            } catch (error) {\n                return  \"\";\n            }\n        }\n\n        \/\/刷新正文页\n        async refreshContent(bookurl) {\n            try {\n                return await window.flutter_inappwebview.callHandler('refreshContent',bookurl);\n            } catch (error) {\n                return  \"\";\n            }\n        }\n\n        \/\/刷新发现页,如用户当前正处于发现页会直接刷新,不在发现页会清除发现页缓存\n        async refreshExplore() {\n            try {\n                return await window.flutter_inappwebview.callHandler('refreshExplore');\n            } catch (error) {\n                return  \"\";\n            }\n        }\n\n        \/\/显示软件气泡选择\n        async showsvg() {\n            try {\n                return await window.flutter_inappwebview.callHandler('showsvg');\n            } catch (error) {\n                return  \"\";\n            }\n        }\n\n        \/\/获取软件 svg 气泡\n        async getsvg() {\n            try {\n                return await window.flutter_inappwebview.callHandler('getsvg');\n            } catch (error) {\n                return  [];\n            }\n        }\n\n        \/\/新增气泡\n        async addsvg(svg) {\n            try {\n                return await window.flutter_inappwebview.callHandler('addsvg',svg);\n            } catch (error) {\n                return  [];\n            }\n        }\n\n        \/\/动态更新 html 代码,主要用于更新在线版地址,确保地址是最新的,此函数只能在书源中使用\n        async setHtml(str) {\n            try {\n                return await window.flutter_inappwebview.callHandler('setHtml',str);\n            } catch (error) {\n                return  \"\";\n            }\n        }\n\n        \/\/将简体字转成繁体字\n        async toTraditional(str) {\n            try {\n                return await window.flutter_inappwebview.callHandler('toTraditional',str);\n            } catch (error) {\n                return  \"\";\n            }\n        }\n\n        \/\/将繁体字转成简体字\n        async toSimplified(str) {\n            try {\n                return await window.flutter_inappwebview.callHandler('toSimplified',str);\n            } catch (error) {\n                return  \"\";\n            }\n        }\n\n        \/\/播放朗读引擎仅tts源生效\n        async voice() {\n            try {\n                return await window.flutter_inappwebview.callHandler('voice');\n            } catch (error) {\n                return  \"\";\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        \/\/获取轻悦时光登录用户名,没登录返回为空\n        async getLoginUser() {\n            try {\n                return await window.flutter_inappwebview.callHandler('getLoginUser');\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弹窗,显示3秒\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        \/\/长toast弹窗,显示10秒\n        \/\/str 为 String\n        async showLongToast(str) {\n            try {\n                return await window.flutter_inappwebview.callHandler('showLongToast',str);\n            } catch (error) {\n                return  false;\n            }\n        }\n\n        \/\/webview 里禁止使用,webview请使用js获取ua (navigator.userAgent)\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         * 使用webView拦截 ajax\n         * ajaxregex 为正则表达式,通过 ajax 匹配 path\n         * 匹配成功返回 ajax 的结果 失败返回 html\n         *\/\n        async webViewGetAjax(url,html,body,header,ajaxregex) {\n            try {\n                return await window.flutter_inappwebview.callHandler('webviewajax',url,html,body,header,ajaxregex);\n            } catch (error) {\n                return  \"\";\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         * 启动前台 webview 并对每次打开的 url 进行拦截\n         * @param url 网址\n         * @param title 标题\n         * @param header 请求的header头,此参数必须是json字符串\n         *\/\n        async startBrowserWithShouldOverrideUrlLoading(url,title,header) {\n            try {\n                return await window.flutter_inappwebview.callHandler('startBrowserWithShouldOverrideUrlLoading',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        \/\/专门为段评设置的半屏显示,与startBrowserDp这个还需要提交html参数已加速访问,不返回任何东西\n        async startBrowserDpwithHtml(url,html,title) {\n            try {\n                return await window.flutter_inappwebview.callHandler('startBrowserDpwithHtml',url,html,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        \/\/提交内容bookUrl,我会调用书源 info 函数来获取这本书的信息\n        async addbook(bookUrl) {\n            try {\n                return await window.flutter_inappwebview.callHandler('addbook',bookUrl);\n            } catch (error) {\n                return  \"\";\n            }\n        }\n\n        \/\/打开搜索页并用当前源搜索\n        async searchbook(key) {\n            try {\n                return await window.flutter_inappwebview.callHandler('searchbook',key);\n            } catch (error) {\n                return  \"\";\n            }\n        }\n\n        \/\/获取书本当前阅读章节index\n        async getdurChapterIndex(bookUrl) {\n            try {\n                return await window.flutter_inappwebview.callHandler('getdurChapterIndex',bookUrl);\n            } catch (error) {\n                return  0;\n            }\n        }\n\n        \/\/这里会返回 book 类或者空 ,如果正在阅读的书本不是当前书源或者没有阅读书本则返回空\n        async getReadBook() {\n            try {\n                return await window.flutter_inappwebview.callHandler('getReadBook');\n            } catch (error) {\n                return   null;\n            }\n        }\n\n        \/\/utf8 字符串转base64\n        async base64encode(str) {\n            try {\n                return await window.flutter_inappwebview.callHandler('base64encode',str);\n            } catch (error) {\n                return  \"\";\n            }\n        }\n\n        \/\/base64 转utf8字符串\n        async base64decode(str) {\n            try {\n                return await window.flutter_inappwebview.callHandler('base64decode',str);\n            } catch (error) {\n                return  \"\";\n            }\n        }\n    }\n\n    \/\/webview下isCookieJar必定true 会自动处理cookie\n    \/\/以下提交的url,headers,body 都必须为字符串,headers必须为json字符串\n    \/\/当followRedirects 为 false 时不处理重定向,当为 true 时会自动处理重定向 ,如不明白用途直接用 true 最佳\n    \/\/ 以下所有参数除当followRedirects外均为 String\n    \/\/ 如果需要使用http2协议 请在url 前添加 http2:\/\/ ,例如 http2:\/\/baidu.com\n    \/\/ 如果https一直被盾拦截 ,可以使用https2协议\n    class Http {\n        constructor() {\n            \/*\n             * 速率限制配置\n             * requestTimestamps: 存储请求时间戳的数组\n             * rateLimit: 速率限制,单位时间内最大请求数\n             * rateLimitWindow: 速率限制窗口,单位毫秒\n             *\/\n            this.open = false; \/\/ 是否开启速率限制\n            this.requestTimestamps = []; \/\/ 存储请求时间戳的数组\n            this.rateLimit = 5; \/\/ 速率限制,1000毫秒内最多5次请求\n            this.rateLimitWindow = 1000; \/\/ 速率限制窗口,1000毫秒\n        }\n\n        \/*\n         * 检查速率限制\n         * 实现方法:\n         * 1. 获取当前时间戳\n         * 2. 过滤掉超出时间窗口的时间戳\n         * 3. 检查是否超过速率限制\n         * 4. 如果超过限制,计算需要等待的时间并等待\n         * 5. 递归检查速率限制\n         * 6. 将当前时间戳添加到数组中\n         *\/\n        async checkRateLimit() {\n            if(!this.open) return;\n            const now = Date.now();\n            \/\/ 过滤掉超出时间窗口的时间戳\n            this.requestTimestamps = this.requestTimestamps.filter(timestamp => now - timestamp < this.rateLimitWindow);\n            \/\/ 检查是否超过速率限制\n            if (this.requestTimestamps.length >= this.rateLimit) {\n                \/\/ 计算需要等待的时间\n                const oldestTimestamp = this.requestTimestamps[0];\n                const waitTime = this.rateLimitWindow - (now - oldestTimestamp);\n                \/\/ 等待到速率限制可用\n                await new Promise(resolve => setTimeout(resolve, waitTime));\n                \/\/ 递归检查速率限制\n                return this.checkRateLimit();\n            }\n            \/\/ 将当前时间戳添加到数组中\n            this.requestTimestamps.push(now);\n        }\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        \/\/ headers 传入 Object,内部自动 JSON.stringify,调用方无需手动转字符串\n        async Get(url,headers,followRedirects) {\n            try {\n                await this.checkRateLimit();\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                await this.checkRateLimit();\n                return await window.flutter_inappwebview.callHandler('http',\"head\",url,\"\",JSON.stringify(headers),followRedirects,\"\");\n            } catch (error) {\n                return  null;\n            }\n        }\n\n        async Post(url,headers,body,contenttype,followRedirects) {\n            try {\n                await this.checkRateLimit();\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        \/\/以下3个函数获取的cache是通用cache,所有书源用同一个key获取的都一样,上面的是独立cache\n        async allget(key) {\n            try {\n                return await window.flutter_inappwebview.callHandler('cache.allget',key);\n            } catch (error) {\n                return  null;\n            }\n        }\n\n        async allset(key,value) {\n            try {\n                return await window.flutter_inappwebview.callHandler('cache.allset',key,value);\n            } catch (error) {\n                return  null;\n            }\n        }\n\n        async allremove(key) {\n            try {\n                return await window.flutter_inappwebview.callHandler('cache.allremove',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        \/\/通过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        \/\/设置单独一个cookie\n        async setCookie(url,key,value) {\n            try {\n                return await window.flutter_inappwebview.callHandler('cookie.setcookie',url,key,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 创建的用完后必须删除,兼容 jQuery 对象(内部通过 [0] 解引用)\n    function removeHTMLSafely(tempContainer) {\n        try {\n            if (tempContainer[0]) { tempContainer = tempContainer[0]; }\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        \/\/ 移除link标签\n        result = result.replace(\/<link\\b[^<]*(?:(?!<\\\/link>)<[^<]*)*<\\\/link>\/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    \/\/ [REPLACE: site domain, e.g. \"http:\/\/www.example.com\"]\n    var baseurl = \"https:\/\/www.ypshuo.com\";\n    \/\/ [REPLACE: request headers — Http 类内部自动 JSON.stringify,此处传 Object]\n    var header = {\n        \"User-Agent\": \"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/120.0.0.0 Safari\/537.36\",\n        \"Referer\": baseurl\n    };\n    function absUrl(u) {\n        if (!u) { return \"\"; }\n        if (u.indexOf(\"http:\/\/\") === 0 || u.indexOf(\"https:\/\/\") === 0) { return u; }\n        return baseurl + u;\n    }\n\n    \/\/ 筛选界面,镜像优书网真实书库(https:\/\/www.ypshuo.com\/bookstore):\n    \/\/   频道(type) → 分类(categoryId) \/ 标签(tags) 联动:\n    \/\/     选男频只显示男频分类与男频标签,选女频只显示女频分类与女频标签\n    \/\/   频道\/分类\/状态(updateStatus)\/更新(update)\/排序(sort) 服务端 getList 原生支持,直接拼进 URL;\n    \/\/   标签(多选,任一所选命中即通过) \/ 字数(word) \/ 人数筛选(scorer) 服务端忽略,结果本地过滤。\n    \/\/ prefix 为 cache key 前缀:搜索用 ypshuo_search_,发现用 ypshuo_find_\n    function buildFilterHtml(prefix) {\n        var categories = [\n            [\"玄幻\", 1, 1], [\"奇幻\", 2, 1], [\"武侠\", 3, 1], [\"仙侠\", 4, 1], [\"都市\", 5, 1], [\"现实\", 6, 1],\n            [\"军事\", 7, 1], [\"历史\", 8, 1], [\"悬疑\", 9, 1], [\"游戏\", 10, 1], [\"竞技\", 11, 1], [\"科幻\", 12, 1],\n            [\"灵异\", 13, 1], [\"二次元\", 14, 1], [\"同人\", 15, 1], [\"其他\", 16, 1], [\"穿越时空\", 17, 2],\n            [\"架空历史\", 18, 2], [\"总裁豪门\", 19, 2], [\"都市言情\", 20, 2], [\"仙侠奇缘\", 21, 2], [\"幻想言情\", 22, 2],\n            [\"悬疑推理\", 23, 2], [\"耽美纯爱\", 24, 2], [\"衍生同人\", 25, 2], [\"轻小说\", 26, 2], [\"综合其他\", 27, 2],\n            [\"诸天无限\", 28, 1]\n        ];\n        var maleTags = [\"玄幻\",\"王朝争霸\",\"异世大陆\",\"东方玄幻\",\"历史\",\"清史民国\",\"军事\",\"军旅生涯\",\"都市\",\"异术超能\",\"都市生活\",\"仙侠武侠\",\"洪荒封神\",\"奇幻玄幻\",\"仙侠\",\"幻想修仙\",\"体育\",\"足球运动\",\"奇幻\",\"剑与魔法\",\"修真文明\",\"都市娱乐\",\"科幻\",\"时空穿梭\",\"未来世界\",\"青春校园\",\"科幻末世\",\"末世危机\",\"游戏\",\"虚拟网游\",\"现代魔法\",\"古武机甲\",\"黑暗幻想\",\"现实\",\"现实百态\",\"现代修真\",\"武侠\",\"武侠幻想\",\"超级科技\",\"武侠仙侠\",\"悬疑\",\"探险生存\",\"都市小说\",\"都市激战\",\"游戏异界\",\"神话修真\",\"科幻游戏\",\"传统武侠\",\"星际文明\",\"两宋元明\",\"架空历史\",\"秦汉三国\",\"两晋隋唐\",\"悬疑灵异\",\"奇幻修真\",\"未来幻想\",\"玄幻奇幻\",\"娱乐明星\",\"奇妙世界\",\"游戏竞技\",\"西方奇幻\",\"游戏生涯\",\"电子竞技\",\"进化变异\",\"历史军事\",\"历史穿越\",\"轻小说\",\"衍生同人\",\"国术无双\",\"商业大亨\",\"史诗奇幻\",\"异界大陆\",\"网游情缘\",\"古代言情\",\"古典架空\",\"古典仙侠\",\"外国历史\",\"诸天无限\",\"无限\",\"历史传奇\",\"星际战争\",\"魔幻\",\"体育赛事\",\"东方仙侠\",\"原生幻想\",\"同人衍生\",\"悬疑推理\",\"探险揭秘\",\"穿越\",\"搞笑\",\"甜文\",\"二次元\",\"篮球运动\",\"转世重生\",\"都市异能\",\"商战职场\",\"校园风云\",\"诸天\",\"宅文\",\"免费同人\",\"官场沉浮\",\"宅系小说\",\"同人\",\"乡土种田\",\"上古先秦\",\"都市重生\",\"仙侠奇缘\",\"诡秘悬疑\",\"古言\",\"科幻空间\",\"科幻无限\",\"同人小说\",\"动漫同人\",\"情有独钟\",\"天作之合\",\"仙侠修真\",\"原创\",\"纯爱\",\"爱情\",\"穿梭时空\",\"影视同人\",\"小说同人\",\"警匪\",\"卧底\",\"线人\",\"武侠修真\",\"穿越时空\",\"娱乐圈\",\"励志人生\",\"系统\",\"言情\",\"近代现代\",\"重幻想\",\"军事科幻\",\"神州\",\"幻想神州\",\"烧脑\",\"智斗\",\"历史架空\",\"谍战特工\",\"轻幻想\",\"超能\",\"民间奇谈\",\"社科\",\"爆笑幽默\",\"装逼打脸\",\"风流才子\",\"勾心斗角\",\"萌系小说\",\"异界幻想\",\"超现实都市\",\"动漫穿越\",\"现言\",\"宫闱宅斗\",\"都市青春\",\"神话传说\",\"游戏世界\",\"神秘未知\",\"灵异未知\",\"男频\",\"古风\",\"高武世界\",\"搞笑吐槽\",\"现代\",\"架空世界\",\"成功励志\",\"古今传奇\",\"侦探推理\",\"历史神话\",\"西游\",\"重生\",\"游戏动漫\",\"西幻传说\",\"热血\",\"战争\",\"唐朝\",\"性转\",\"变百\",\"修罗场\",\"另类幻想\",\"励志\",\"现实题材\",\"白云天\",\"未来科技\",\"恐怖灵异\",\"推理悬念\",\"异能•幻想\",\"幻想\",\"神魔\",\"吐槽\",\"崩坏\",\"恶搞\",\"战争历史\",\"游戏系统\",\"无限流\",\"热血竞技\",\"末世\",\"快穿\",\"轻松\",\"都市传奇\",\"神秘幻想\",\"军事战争\",\"游戏衍生\",\"科幻·奇幻\",\"穿越奇情\",\"游戏主播\",\"安德鲁\",\"都市言情\",\"青春文学\",\"玄幻\/新武侠\/魔幻\/\",\"古武未来\",\"恐怖惊悚\",\"灵异神怪\",\"异能战斗\",\"文库本\",\"网游RPG\",\"冒险\",\"武侠同人\",\"民国旧影\",\"爽文\",\"逆袭\",\"泛次元\",\"推理侦探\",\"悬疑探险\",\"战争幻想\",\"恋爱日常\",\"科幻时空\",\"青春日常\",\"古代\",\"综合\",\"抗战烽火\",\"修仙世界\",\"重生年代\",\"科幻网游\",\"修仙\",\"土著主角\",\"星际科幻\",\"都市逸闻\",\"短篇\",\"生活随笔\",\"末世异能\",\"打脸\",\"幻想战争\",\"近代战争\",\"元明清\",\"近代国史\",\"魔法世界\",\"穿越重生\",\"热血豪情\",\"都市种田\",\"种田\",\"年代\",\"都市高武\",\"开局\",\"脑洞创意\",\"创意都市\",\"百合\",\"战斗\",\"21年度最佳\",\"人间百态\",\"斩神\",\"悬疑脑洞\",\"直播\",\"灵异\",\"小说\",\"都市脑洞\",\"神豪\",\"无脑爽\",\"时代洪流\",\"恋爱\",\"白学\",\"后宫\",\"校园\",\"职场\",\"穿书\",\"dnd\",\"史诗幻想\",\"萌宝\",\"传统玄幻\",\"扮猪吃虎\",\"剑道\",\"无后宫\",\"奇幻仙侠\",\"剑修\",\"升级流\",\"魂穿\",\"综漫\",\"现代都市\",\"网游\",\"魔兽世界\",\"搞笑轻松\",\"玄幻脑洞\",\"无女主\",\"断层\",\"星际\",\"克苏鲁\",\"诸天万界\",\"副本\",\"动漫衍生\",\"无CP\",\"都市日常\",\"游戏体育\",\"现代言情\",\"空间\",\"架空\",\"推理\",\"求生\",\"末日求生\",\"琥珀流\",\"上古神话\",\"穿越附身\",\"火影\",\"海贼\",\"男频衍生\",\"第一人称\",\"黑化\",\"四合院\",\"天才\",\"无敌\",\"赘婿\",\"腹黑\",\"囤物资\",\"特战精英\",\"灵气复苏\",\"嫡女\",\"反派\",\"丧尸\",\"单女主\",\"争霸\",\"乡村\",\"1v1\",\"都市修真\",\"校花\",\"聊天群\",\"发家致富\",\"学霸\",\"大佬\",\"国运\",\"规则怪谈\",\"女帝\",\"海贼王\",\"西幻\",\"群像\",\"奇闻轶事\",\"惊悚游戏\",\"破案\",\"冰山\",\"前世今生\",\"无敌流\",\"时空门\",\"特种兵\",\"基因\",\"谋略\",\"英美衍生\",\"超级英雄\",\"马甲文\",\"现代诡秘\",\"诡秘养成\",\"探险\",\"管理局\",\"脑洞大\",\"思路清奇\",\"经营\",\"文娱\",\"杀伐果断\",\"职业文\",\"智商在线\",\"无节操\",\"日常文\",\"草根崛起\",\"凡人流\",\"宗门\",\"冷静\",\"谨慎\",\"系统流\",\"天才流\",\"魔法\",\"养成\",\"幕后流\",\"三国\",\"无金手指\",\"技术流\",\"美洲\",\"猎人\",\"创业\",\"奋斗\",\"医生流\",\"明朝\",\"随身流\",\"练功流\",\"诸天流\",\"武道\",\"钢铁直男\",\"秦汉\",\"策略流\",\"布局流\",\"寒门子弟\",\"机甲\",\"蒸汽朋克\",\"赛博朋克\",\"诡秘修行\",\"进化\",\"轮回者\",\"侠客\",\"老板\",\"玩家\",\"农民\",\"护花高手\",\"商战\",\"年代文\",\"厨师\",\"时空文\",\"领主种田\",\"神奇生物\",\"供应商\",\"自律\",\"修真\",\"治愈\",\"正能量\",\"斗罗大陆\",\"灵根\",\"古典修仙\",\"炼器\",\"家族\",\"学者\",\"女神\",\"明星\",\"成熟\",\"练功\",\"抗战\",\"长生\",\"强者流\",\"快节奏\",\"两界穿梭\",\"学院流\",\"事务所\",\"学生\",\"赚钱\",\"美食\",\"气运流\",\"都市修仙\",\"异世穿越\",\"巫师流\",\"炼金师\",\"军工\",\"航空\",\"军迷\",\"佣兵\",\"炮兵\",\"原创副本\",\"大师兄\",\"中医\",\"强者归来\",\"废柴流\",\"异能\",\"开局流\",\"御兽流\",\"宠物\",\"洪荒\",\"枭雄\",\"召唤流\",\"搞怪\",\"宅男\",\"朝堂\",\"皇帝流\",\"科举\",\"夫妻\",\"开挂流\",\"动漫\",\"炼丹\",\"玄学\",\"道士\",\"斗破苍穹\",\"属性流\",\"软饭流\",\"互联网\",\"工业\",\"三教九流\",\"舰长\",\"氪金\",\"抽奖\",\"国术\",\"LOL\",\"电竞\",\"职业选手\",\"三观正\",\"领主流\",\"骑士\",\"悬疑流\",\"诡异游戏\",\"生存挑战\",\"封神\",\"专业文\",\"神话\",\"足球\",\"运动员\",\"科技\",\"签到\",\"锦衣卫\",\"驸马\",\"杀手\",\"曝光流\",\"视频流\",\"科技修真\",\"反转\",\"异兽流\",\"思想迪化\",\"嘴炮\",\"奇幻历史\",\"水浒\",\"NPC\",\"奶爸\",\"警察\",\"盛世\",\"隋唐\",\"强国\",\"鉴宝\",\"权谋\",\"宋朝\",\"金融\",\"第四天灾\",\"异能者\",\"战神流\",\"王侯\",\"科学家\",\"谍战\",\"特工\",\"反英雄\",\"反套路\",\"女尊\",\"门阀\",\"刑侦\",\"游戏制作\",\"清朝\",\"篮球\",\"NBA\",\"卡牌\",\"极道流\",\"骷髅兵\",\"游戏玩家\",\"田径\",\"摊牌流\",\"成神流\",\"朝堂江湖\",\"掌门流\",\"美食家\",\"神医流\",\"红楼\",\"战士\",\"荒野求生\",\"法师\",\"精灵文\",\"BOSS流\",\"法医\",\"手游\",\"打工\",\"升学\",\"写手\",\"科普向\",\"欧洲\",\"指挥官\",\"综艺文\",\"主神\",\"高武\",\"直播文\",\"元宇宙\",\"祖宗流\",\"基因武者\",\"符纹师\",\"贞观\",\"分身\",\"老师\",\"赛车\",\"黑客\",\"英雄\",\"民俗悬疑\",\"山海经\",\"恶魔交易\",\"非洲\",\"原始流\",\"影视原著\",\"保镖\",\"白蛇\",\"阵法师\",\"夺舍\",\"古代怪异\",\"驱魔人\",\"赘婿流\",\"虚拟现实\",\"海外\",\"神级流\",\"基建流\",\"剧透\",\"皇子\",\"垂钓\",\"掠夺流\",\"扶贫\",\"硬科幻\",\"传统文化\",\"吸血鬼\",\"婚姻\",\"天庭文\",\"女强\",\"富民\",\"仙帝\",\"小兵\",\"改革开放\",\"蜀山\",\"律师\",\"牧师\",\"术士\",\"单机\",\"漫威\",\"儒道流\",\"太监\",\"扮演流\",\"外国怪异\",\"主神创世\",\"房地产\",\"和尚\",\"卫生员\",\"非遗\",\"相声演员\",\"聊斋\",\"捕快\",\"死神\",\"心声\",\"考古\",\"技术\",\"九叔\",\"萝莉控\",\"朋克\",\"衍生\",\"萝莉\",\"玄幻魔法\",\"基建\",\"成长\",\"少年漫\",\"排球少年\",\"幽默\",\"宝可梦\",\"教练\",\"强强\",\"汉朝\",\"爆笑\",\"升级\",\"序列\",\"文青\",\"日本\",\"文抄\",\"青春\",\"倒追\",\"日常\",\"读档流\",\"脑洞\",\"大车\",\"官场\",\"多女主\",\"历史古代\",\"忠诚\",\"半岛\",\"带韩冥国\",\"五共\",\"P社人\",\"日本战国\",\"明日方舟\",\"女神异闻录\",\"哭泣少女乐队\",\"华娱\",\"演员\",\"仕途\",\"惊悚灵异\",\"美国梦\",\"异世界\",\"魔幻三国\",\"美国\",\"导演\",\"文豪\",\"妹控\",\"变身\",\"苟道\",\"探案推理\",\"特摄\",\"乐队\",\"沙雕\",\"星穹铁道 \",\"魔法少女小圆\",\"原神\",\"民俗\",\"专业\",\"古武\",\"北宋\",\"中世纪\",\"  今奇闻\",\"市井俗谈\",\"游戏现实\",\"围棋\",\"诡异\",\"遮天\",\"综武\",\"江湖\",\"熟练度\",\"兵王\",\"志怪\",\"航海\",\"考据\",\"千禧年\",\"史诗感\",\"精神异常\",\"无系统\",\"美娱\",\"设定党\",\"玩梗\",\"无穿越\",\"民国\",\"斩妖除魔\",\"慢热\",\"学霸文\",\"模拟器\",\"僵尸\",\"店主流\",\"悠闲\",\"怀旧\",\"加点流\",\"香港\",\"咒术回战\",\"冷战\",\"苏联\",\"歌手\",\"偶像\",\"白月光\",\"暗恋\",\"照夜真人\",\"鸡犬升天\",\"大嫂\",\"一腔热血扫不平\",\"迎接你们的王\",\"十四亿分之一\",\"臣子受恩必以忠心报之\",\"愿效犬马之劳\",\"忠心不二\",\"殿下的小迷妹\",\"请尽情吩咐\",\"角色太过神秘还没有简介\",\"粉噗叽\",\"隔壁哥布林喝的是你吗\",\"菌主\",\"走路菇\",\"会被做成汤吗\",\"女儿\",\"百章零点6级\",\"我真不是哥布林\",\"蘑菇汤重度依赖\",\"不是哥布林\",\"是噗叽汤吗\",\"奶油蘑菇湯重度依賴\",\"噗叽汤教教主\",\"被渣男喝掉\",\"韩娱\",\"地光黑粉头子\",\"作者除了泰妍的最爱\",\"脸脸\",\"元气兔兔\",\"颜永一\",\"小姐姐\",\"满30减12\",\"裴惊吓\",\"世首美\",\"怦然心动周子瑜\",\"纯元皇后\",\"胖丁\",\"白给\",\"氪星女骑士\",\"亚马逊女骑士\",\"实力不详遇强则强\",\"实力不详\",\"三无始祖\",\"傲娇始祖\",\"改一下行吗\",\"改成什么好呢\",\"只要是正确的都行啊\",\"那我加个女友凉了\",\"高考状元\",\"威尼斯最佳新人\",\"威尼斯影帝\",\"华表奖最佳新人\",\"夸父计划总指挥\",\"安安内定嫂子\",\"云上青雨\",\"望雨党头顶青天\",\"挟安安以令小姜\",\"坏女人谁不爱呢\",\"重塑姜望三观\",\"女主\",\"妙玉党无敌\",\"身坠深渊心向光明\",\"是为腾龙境天下第一\",\"无数闺阁的梦中人\",\"我自行我道\",\"血脉修仙者\",\"妖兽王者\",\"最强妖兽\",\"老硬币\",\"大小姐\",\"白素贞\",\"铁憨憨\",\"雷霆都司传人\",\"那拏天\",\"威善济端公\",\"猖神\",\"真·牛马\",\"酒鬼\",\"收藏家\",\"帮亲不帮理\",\"又毒又美\",\"任性可爱\",\"星宿派小毒物\",\"星宿小仙\",\"出门在外身份龙傲天\",\"寻宝小达人\",\"天空三兄弟之四\",\"马上觅蜂猴\",\"别看我只是一只猴\",\"平生爱吃毒物\",\"诗爷\",\"青梅\",\"呆呆的\",\"一姐\",\"宋一一\",\"竹马\",\"帅帅的\",\"后宫佳丽三千\",\"一百二十岁的金丹\",\"虾头小仙男\",\"莽小将\",\"爱吃驴肠头\",\"爱吃驴肠头天下皆知\",\"人人杨合\",\"道友请留步\",\"检查官\",\"文明收集者\",\"莽汉肌肉流代言人\",\"大B哥\",\"牢丁\",\"珍妮妈妈\",\"惨遭改名\",\"自带女巫视角Pro\",\"男主\",\"邪教颠佬\",\"有那么多姐姐妹妹\",\"已经不见了\",\"菈日萝的教皇\",\"曌姬之下第二13王\",\"手册在手天下我有\",\"正部级唾手可得\",\"邱途怎么还不回家\",\"小醋坛子\",\"小管家婆可爱捏\",\"令人垂涎\",\"好险差点饿死\",\"报仇不隔夜\",\"识文断字小能手\",\"冬眠鳄鱼一只\",\"不能动\",\"挠挠爪子\",\"死亡摇滚\",\"这家没我得散\",\"勇敢鲶鲶不怕困难\",\"鱼鱼我啊就喜欢打工\",\"无足蛙\",\"真女主\",\"威龙级电力机车\",\"双子星11R\",\"巨鲸03E\",\"机械之心\",\"林队\",\"略懂机械\",\"点子王\",\"傲娇\",\"暴力更新\",\"嗜血爆更\",\"巅峰律师\",\"cpu高手\",\"大秦的百年孤独\",\"善治水\",\"师承荀子\",\"腰斩于市\",\"大秦丞相\",\"最后的法家\",\"嬴政\",\"竟然不是小南娘\",\"叫这名字一定很安静吧\",\"竟然不是小南酿\",\"七曜七杀之天命\",\"轻寒生平不喜争抢\",\"先天文盲圣体\",\"就是这个白毛爽\",\"牢白\",\"剑灵\",\"可爱滴捏\",\"只要是长条都是剑\",\"长条\",\"生命的第二次可能\",\"采雏菊的小姑娘\",\"驴姥姥\",\"其实很有猎人的天赋哦\",\"金莫CP\",\"不加入家派的猎人\",\"其实很怕跳楼\",\"柴犬\",\"长腿王八\",\"法外狂徒\",\"超级幸运\",\"绵绵\",\"永不坠落的四叶草吊坠\",\"谜语人\",\"670\",\"抱歉哥\",\"木头\",\"被世面瞧见了\",\"因为落落喜欢吃\",\"落落又叛变了\",\"我才是大哥\",\"亭亭玉立一女壮士\",\"我哥天下第一\",\"太好吃了哥你先让一下\",\"不烫啊\",\"圣书.zip\",\"只要天才来走都是捷径\",\"落派秘籍\",\"谭维安真身\",\"剑种\",\"直男\",\"被爱的男人\",\"湿件\",\"哈基米\",\"梭哈是一种智慧\",\"注定要封神的女人\",\"大陆第一美人\",\"起名暗影之主\",\"念作风流之主\",\"心灵术士\",\"奶芙\",\"帝兆老爷\",\"收税之神\",\"百变史莱姆\",\"吃货\",\"土木剑仙\",\"亡灵骑士\",\"无敌的我又迷路了\",\"又嚣张又怂\",\"话痨乌鸦\",\"温婉大方\",\"相夫教子型\",\"简单\",\"小飒\",\"见面请喊陛下\",\"根器非凡\",\"东夏游子\",\"肯定是孙夫子\",\"希望快點出現\",\"最神秘的女主\",\"这曲子你练的怎么样了\",\"努力保命的白切黑\",\"吃定小董\",\"小董的王\",\"小越越很看好你哦\",\"未亡人富婆\",\"高级炼器大师\",\"有刷子在手上\",\"落花有意\",\"魅魔\",\"无情的任务人\",\"怪力乱神\",\"本书物理战力最高\",\"铁拳少女\",\"小奶狗饲主\",\"魔犬召唤师\",\"狼人少女\",\"能做羽子妈妈的女人\",\"惊世一跪\",\"见稽古之眼\",\"羽书星怒\",\"自然练体就是最吊的\",\"阿羽头顶怎么尖尖的\",\"要不是羽书拖累\",\"白真真义母\",\"提款机1号\",\"嵩阳市最强高中生\",\"符批\",\"烟是本体\",\"人格分裂\",\"罪物免疫体\",\"平易近人季店长\",\"杀死季礼我就是主角\",\"对别人狠对自己更狠\",\"方无言\",\"扣1教你吹横笛\",\"听梅花落下的声音\",\"为什么要逼我\",\"深蓝加点\",\"黑印加点\",\"加点\",\"好巧啊是情侣腿\",\"同是天涯断腿人\",\"御姐\",\"天行剑宗少主\",\"来不及了你最先出场\",\"检察官系列paly\",\"夫妻宫不是正宫\",\"纯路人吃瓜\",\"小丑鱼\",\"病娇妖女\",\"不是情侣名就能装情侣\",\"舔不到陆行舟的女人\",\"群穿\",\"战锤\",\"综影视\",\"崇祯\",\"魔女\",\"秦朝\",\"荒野\",\"打猎\",\"时间线\",\"东南亚\",\"盘龙\",\"高达\",\"元朝\",\"神秘复苏\",\"历史脑洞\",\"韩国\",\"抗战谍战\",\"革命\",\"战神赘婿\",\"神医\",\"南宋\",\"五代十国\",\"大唐\",\"全民流\",\"都市江湖\",\"捉鬼\",\"风水秘术\",\"永乐\",\"南洋建国\",\"两晋\",\"碧蓝航线 \",\"皇帝\",\"假面骑士 \",\"嘉靖\",\"日娱\",\"洪武\",\"万历\",\"废土\",\"正德\",\"福尔摩斯\",\"精品小说\",\"家族修仙\",\"军旅\",\"词条\"];\n        var femaleTags = [\"历史\",\"两晋隋唐\",\"两宋元明\",\"架空历史\",\"秦汉三国\",\"清史民国\",\"历史军事\",\"奇幻\",\"剑与魔法\",\"游戏\",\"虚拟网游\",\"仙侠\",\"修真文明\",\"历史穿越\",\"现代魔法\",\"玄幻\",\"王朝争霸\",\"都市\",\"都市生活\",\"上古先秦\",\"古代言情\",\"古典架空\",\"穿越奇情\",\"现代言情\",\"豪门世家\",\"异术超能\",\"科幻\",\"未来世界\",\"历史传记\",\"仙侠武侠\",\"古典仙侠\",\"黑暗幻想\",\"仙侠奇缘\",\"奇幻魔幻\",\"穿越时空\",\"衍生\",\"言情\",\"近代现代\",\"西方衍生\",\"玄幻言情\",\"东方玄幻\",\"异世大陆\",\"现代修真\",\"游戏异界\",\"情有独钟\",\"爱情战争\",\"青梅竹马\",\"军事\",\"军事战争\",\"末世危机\",\"宅文\",\"免费同人\",\"都市情缘\",\"原创\",\"爱情\",\"宫廷侯爵\",\"竞技\",\"传奇\",\"玄幻奇幻\",\"西方奇幻\",\"重生\",\"无CP\",\"超级科技\",\"游戏竞技\",\"灵魂转换\",\"诸天无限\",\"无限\",\"进化变异\",\"战争幻想\",\"外国历史\",\"武侠\",\"武侠幻想\",\"体育\",\"体育赛事\",\"幻想空间\",\"游戏网游\",\"幻想未来\",\"东方衍生\",\"死神\",\"火影\",\"综漫\",\"圣斗士\",\"纯爱\",\"幻想修仙\",\"古色古香\",\"清穿\",\"都市小说\",\"现实题材\",\"布衣生活\",\"魔法校园\",\"种田文\",\"前世今生\",\"足球运动\",\"电子竞技\",\"青春校园\",\"灵异神怪\",\"惊悚\",\"天作之合\",\"阴差阳错\",\"虐恋情深\",\"悬疑\",\"探险生存\",\"性别转换\",\"正剧\",\"异能\",\"猎人\",\"欢喜冤家\",\"仙侠修真\",\"史诗奇幻\",\"骑士与剑\",\"经商种田\",\"宫闱宅斗\",\"红楼梦\",\"古典衍生\",\"网王\",\"宅斗\",\"五代十国\",\"科幻末世\",\"星际战争\",\"少年漫\",\"三教九流\",\"未知\",\"江湖恩怨\",\"篮球运动\",\"天下足球\",\"英美衍生\",\"无限流\",\"其他衍生\",\"天之骄子\",\"娱乐明星\",\"浪漫青春\",\"花季雨季\",\"近水楼台\",\"诸天\",\"竞技同人\",\"西方名著\",\"西方罗曼\",\"年下\",\"强强\",\"复仇虐渣\",\"校园\",\"女强\",\"轻松\",\"女主\",\"末世\",\"悬疑推理\",\"民间奇谈\",\"相爱相杀\",\"体育竞技\",\"因缘邂逅\",\"百合\",\"随身空间\",\"平步青云\",\"恋爱合约\",\"宫斗\",\"历史传奇\",\"洪荒封神\",\"乔装改扮\",\"系统\",\"机甲\",\"未来架空\",\"异国奇缘\",\"时空穿梭\",\"领主贵族\",\"抗战烽火\",\"星际文明\",\"游戏生涯\",\"科幻空间\",\"未来幻想\",\"恐怖\",\"探险\",\"诡异\",\"古言\",\"现言\",\"时代奇缘\",\"快穿\",\"娱乐圈\",\"业界精英\",\"异闻传说\",\"奇谭\",\"美食\",\"星际\",\"甜文\",\"爽文\",\"轻小说\",\"衍生同人\",\"现代架空\",\"励志人生\",\"姐弟恋\",\"女配\",\"女扮男装\",\"古穿今\",\"七五\",\"炮灰\",\"洪荒\",\"美娱\",\"港台\",\"传统武侠\",\"魔幻\",\"男主\",\"穿书\",\"制服情缘\",\"田园\",\"同人小说\",\"动漫同人\",\"原著向\",\"历史衍生\",\"银魂\",\"都市言情\",\"都市异能\",\"生子\",\"打脸\",\"乡村爱情\",\"励志\",\"破镜重圆\",\"古典名著\",\"民国旧影\",\"星际争霸\",\"升级流\",\"江湖\",\"科举\",\"神州\",\"幻想神州\",\"重幻想\",\"军事科幻\",\"边缘恋歌\",\"基建\",\"轻幻想\",\"超能\",\"新派武侠\",\"烧脑\",\"灵异\",\"网配\",\"超级英雄\",\"主受\",\"主攻\",\"婚恋\",\"血族\",\"少女漫\",\"历史架空\",\"脑洞\",\"畅销经典\",\"最新畅销\",\"家教\",\"黑篮\",\"商战\",\"204\",\"虐文\",\"西幻\",\"童话\",\"剧情\",\"逆袭\",\"现实\",\"女尊\",\"穿梭时空\",\"同人\",\"都市青春\",\"青春日常\",\"文教\",\"宫斗权谋\",\"幻想言情\",\"奇幻魔法\",\"都市异闻\",\"网红\",\"直播\",\"婚恋情缘\",\"日韩\",\"海贼王\",\"神话传说\",\"魔法幻情\",\"爆笑\",\"市井生活\",\"古武机甲\",\"静官新书\",\"热血\",\"超强架构\",\"短篇\",\"短篇小说\",\"朝堂之上\",\"现代\",\"职场\",\"奇幻异界\",\"超能都市\",\"恋爱\",\"日常\",\"现实百态\",\"古今传奇\",\"幻情\",\"怪奇\",\"神话\",\"成长\",\"异能•幻想\",\"幻想\",\"原生幻想\",\"古代幻想\",\"迪化流\",\"另类幻想\",\"奇幻修真\",\"未来科幻\",\"超能青春\",\"都市娱乐\",\"精彩商战\",\"美女诱惑\",\"魔法\",\"玄学\",\"年代文\",\"刺激\",\"萌宠\",\"鬼怪\",\"驱魔人\",\"道术\",\"超现实都市\",\"小门小户\",\"七年之痒\",\"武侠情缘\",\"朝堂\",\"古代情缘\",\"异能超术\",\"时尚流行\",\"犬夜叉\",\"时代新风\",\"柯南\",\"高武世界\",\"异想天开\",\"经商\",\"克苏鲁\",\"新浪潮\",\"历史神话\",\"锦鲤\",\"奇妙世界\",\"亡灵异族\",\"男配\",\"马甲文\",\"文野\",\"齐神\",\"婆媳\",\"咒回\",\"恐怖灵异\",\"恐怖惊悚\",\"追爱火葬场\",\"读心术\",\"日久生情\",\"师徒\",\"另类校园\",\"权谋\",\"救赎\",\"大冒险\",\"白月光\",\"经营\",\"沙雕\",\"灵气复苏\",\"群像\",\"不明\",\"大男主\",\"评论\",\"吃货\",\"荒野求生\",\"史诗幻想\",\"穿越重生\",\"同人衍生\",\"ABO\",\"JOJO\",\"聊斋\",\"清朝民国\",\"刀剑乱舞\",\"NPC\",\"万人迷\",\"反套路\",\"近代战争\",\"古风\",\"排球少年\",\"浪漫言情\",\"日韩泰\",\"转生\",\"民国\",\"鬼灭\",\"第四天灾\",\"天选之子\",\"高岭之花\",\"app\",\"近代国史\",\"群穿\",\"职场生涯\",\"三国穿越\",\"电竞\",\"模拟器\",\"HE\",\"论坛体\",\"其他\",\"开荒\",\"萌娃\",\"失忆\",\"综艺\",\"世界历史\",\"奇幻玄幻\",\"团宠\",\"抽奖抽卡\",\"远古洪荒\",\"赛博朋克\",\"武侠仙侠\",\"军事历史\",\"三国梦想\",\"美强惨\",\"高智商\",\"规则怪谈\",\"古典仙缘\",\"架空\",\"哨向\",\"仙侣奇缘\",\"傲娇\",\"多元\",\"历史古代\",\"穿越\",\"学霸\",\"剧透\",\"现言脑洞\",\"废土\",\"明朝\",\"魂穿\",\"随笔\",\"全息\",\"历史脑洞\",\"搞笑轻松\",\"足球\",\"蒸汽朋克\",\"豪门总裁\",\"吐槽役\",\"推理侦探\",\"空间\",\"大唐\",\"今穿古\",\"虫族\",\"多重人格\",\"奇幻仙侠\",\"悲剧\",\"召唤流\",\"三国\",\"开局\",\"原始社会\",\"古言脑洞\",\"悬疑恋爱\",\"推理\",\"暗恋\",\"星际恋歌\",\"封神\",\"吐槽\",\"龙傲天\",\"职场婚恋\",\"家庭\",\"病娇\",\"种田\",\"恶役\",\"唐穿\",\"读档流\",\"明穿\",\"囤货\",\"脑洞创意\",\"治愈\",\"先婚后爱\",\"单元文\",\"虐渣\",\"大佬\",\"原神\",\"开挂\",\"纸片人\",\"BE\",\"星穹铁道\",\"创业\",\"卡牌\",\"异族恋情\",\"位面\",\"人间百态\",\"神豪流\",\"签到流\",\"皇帝\",\"争霸\",\"港风\",\"抗战谍战\",\"乙女向\",\"破案\",\"养成\",\"后宫\",\"腹黑\",\"悬疑脑洞\",\"盗墓\",\"御兽\",\"古早\",\"动漫衍生\",\"二次元\",\"多视角\",\"天灾\",\"FGO\",\"厨娘\",\"宫斗宅斗\",\"公主\",\"女频衍生\",\"综影视\",\"异世穿越\",\"真假少爷\",\"橘味\",\"年代\",\"萌宝\",\"钓系\",\"星光璀璨\",\"甜宠\",\"男频衍生\",\"诸天万界\",\"漫威\",\"无敌\",\"忠犬\",\"双男主\",\"无敌流\",\"谋略\",\"蓝锁\",\"单女主\",\"1v1\",\"玄幻脑洞\",\"无系统\",\"妹控\",\"骨科\",\"扮猪吃虎\",\"女频悬疑\"];\n\n        var groupHtml =\n            '<div class=\"group\"><label>频道<\/label><div class=\"btns\" data-g=\"channel\">' +\n            '<button class=\"b active\" data-v=\"\">全部<\/button><button class=\"b\" data-v=\"1\">男频<\/button><button class=\"b\" data-v=\"2\">女频<\/button>' +\n            '<\/div><\/div>' +\n            '<div class=\"group\"><label>分类<\/label><div class=\"btns grid\" data-g=\"category\" id=\"catBox\"><\/div><\/div>' +\n            '<div class=\"group\"><label>标签(可多选)<\/label><div class=\"selwrap\" data-g=\"tag\">' +\n            '<div class=\"selbox\" id=\"tagSelBox\"><span class=\"seltags\" id=\"tagSelChips\"><\/span><span class=\"selph\" id=\"tagSelPh\">请选择<\/span><span class=\"selarr\">&#9660;<\/span><\/div>' +\n            '<div class=\"seldrop\" id=\"tagDrop\"><div class=\"selscroll\" id=\"tagOpts\"><\/div><\/div>' +\n            '<div class=\"tip\" id=\"tagTip\"><\/div><\/div><\/div>' +\n            '<div class=\"group\"><label>字数<\/label><div class=\"btns\" data-g=\"word\">' +\n            '<button class=\"b\" data-v=\"\">全部<\/button><button class=\"b\" data-v=\"1\">100万以下<\/button>' +\n            '<button class=\"b\" data-v=\"2\">100万-200万<\/button><button class=\"b\" data-v=\"3\">200万以上<\/button>' +\n            '<\/div><\/div>' +\n            '<div class=\"group\"><label>状态<\/label><div class=\"btns\" data-g=\"status\">' +\n            '<button class=\"b\" data-v=\"\">全部<\/button><button class=\"b\" data-v=\"0\">连载中<\/button>' +\n            '<button class=\"b\" data-v=\"1\">已完结<\/button><button class=\"b\" data-v=\"2\">已太监<\/button>' +\n            '<\/div><\/div>' +\n            '<div class=\"group\"><label>更新<\/label><div class=\"btns\" data-g=\"update\">' +\n            '<button class=\"b\" data-v=\"\">全部<\/button><button class=\"b\" data-v=\"5\">三日内<\/button>' +\n            '<button class=\"b\" data-v=\"1\">2026<\/button><button class=\"b\" data-v=\"2\">2025<\/button>' +\n            '<button class=\"b\" data-v=\"3\">2024<\/button><button class=\"b\" data-v=\"4\">三年前<\/button>' +\n            '<\/div><\/div>' +\n            '<div class=\"group\"><label>排序<\/label><div class=\"btns\" data-g=\"sort\">' +\n            '<button class=\"b\" data-v=\"\">默认<\/button><button class=\"b\" data-v=\"scorer\">评分人数<\/button>' +\n            '<button class=\"b\" data-v=\"update_time\">时间<\/button><button class=\"b\" data-v=\"word_number\">字数<\/button>' +\n            '<button class=\"b\" data-v=\"score\">评分<\/button><button class=\"b\" data-v=\"point\">硬币<\/button>' +\n            '<\/div><\/div>' +\n            '<div class=\"group\" id=\"bookAgeGroup\" style=\"display:none;\"><label>书龄<\/label><div class=\"btns\" data-g=\"bookage\">' +\n            '<button class=\"b\" data-v=\"\">综合<\/button><button class=\"b\" data-v=\"1\">三年内<\/button>' +\n            '<button class=\"b\" data-v=\"2\">七年内<\/button><button class=\"b\" data-v=\"3\">七年上<\/button>' +\n            '<\/div><\/div>' +\n            '<div class=\"group\"><label>人数筛选<\/label><div class=\"btns\" data-g=\"scorer\">' +\n            '<button class=\"b\" data-v=\"\">全部<\/button><button class=\"b\" data-v=\"10\">10人以上<\/button>' +\n            '<button class=\"b\" data-v=\"100\">100人以上<\/button><button class=\"b\" data-v=\"300\">300人以上<\/button>' +\n            '<\/div><\/div>';\n\n        return '<!DOCTYPE html><html lang=\"zh\"><head><meta charset=\"UTF-8\">' +\n            '<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">' +\n            '<title>优书网筛选<\/title><style>' +\n            'body{font-family:system-ui,-apple-system,sans-serif;padding:16px;background:#f5f6fa;color:#333;margin:0;}' +\n            '.group{margin-bottom:16px;}.group label{display:block;font-size:14px;color:#666;margin-bottom:6px;font-weight:600;}' +\n            '.btns{display:flex;flex-wrap:wrap;gap:8px;}' +\n            '.btns.grid .b{padding:6px 10px;font-size:13px;}' +\n            '.b{padding:8px 14px;border:1px solid #d0d3d9;border-radius:8px;background:#fff;font-size:14px;cursor:pointer;color:#444;}' +\n            '.b.active{background:#3b82f6;color:#fff;border-color:#3b82f6;font-weight:600;}' +\n            '.tip{font-size:12px;color:#999;margin-top:4px;}' +\n            '.selwrap{position:relative;}' +\n            '.selbox{display:flex;align-items:center;justify-content:space-between;border:1px solid #d0d3d9;border-radius:8px;background:#fff;padding:6px 10px;font-size:14px;color:#444;cursor:pointer;min-height:18px;}' +\n            '.selbox.open{border-color:#3b82f6;}' +\n            '.seltags{display:flex;flex-wrap:wrap;gap:4px;flex:1;}' +\n            '.seltag{background:#eef4ff;color:#3b82f6;border-radius:4px;padding:2px 6px;font-size:12px;line-height:16px;display:flex;align-items:center;}' +\n            '.selx{font-style:normal;margin-left:4px;cursor:pointer;color:#3b82f6;opacity:.7;}' +\n            '.selx:hover{opacity:1;color:#e11d48;}' +\n            '.selph{color:#999;}' +\n            '.selarr{color:#999;font-size:12px;margin-left:6px;}' +\n            '.seldrop{position:absolute;top:calc(100% + 4px);left:0;right:0;background:#fff;border:1px solid #d0d3d9;border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,.12);z-index:20;display:none;max-height:260px;overflow:hidden;}' +\n            '.seldrop.open{display:flex;flex-direction:column;}' +\n            '.selscroll{overflow-y:auto;flex:1;}' +\n            '.opt{display:flex;justify-content:space-between;align-items:center;padding:8px 10px;font-size:14px;color:#444;cursor:pointer;}' +\n            '.opt:hover{background:#f0f4ff;}' +\n            '.opt.active{color:#3b82f6;font-weight:600;}' +\n            '.opt .ch{font-size:12px;color:#8492a6;margin-left:8px;flex-shrink:0;}' +\n            '.actions{display:flex;gap:10px;margin-top:20px;position:sticky;bottom:0;background:#f5f6fa;padding:8px 0;}' +\n            'button.act{flex:1;padding:12px;border:none;border-radius:8px;font-size:15px;cursor:pointer;}' +\n            '.btn-ok{background:#3b82f6;color:#fff;}.btn-reset{background:#e5e7eb;color:#333;}' +\n            '<\/style><\/head><body>' +\n            groupHtml +\n            '<div class=\"actions\">' +\n            '<button class=\"act btn-ok\" onclick=\"save(true)\">应用并刷新<\/button>' +\n            '<button class=\"act btn-reset\" onclick=\"save(false)\">清除筛选<\/button>' +\n            '<\/div>' +\n            '<script>' +\n            'var bridge=window.flutter_inappwebview;' +\n            'var KEY=' + JSON.stringify(prefix + \"filter\") + ';' +\n            'var CATS=' + JSON.stringify(categories) + ';' +\n            'var MALE_TAGS=' + JSON.stringify(maleTags) + ';' +\n            'var FEMALE_TAGS=' + JSON.stringify(femaleTags) + ';' +\n            'var fSaved={};' +\n            'function get(k){try{return bridge.callHandler(\"cache.get\",k);}catch(e){return Promise.resolve(null);}}' +\n            'function set(k,v){try{return bridge.callHandler(\"cache.set\",k,v);}catch(e){return Promise.resolve(null);}}' +\n            'function renderCategory(){var ch=document.querySelector(\\'[data-g=\"channel\"] .b.active\\').getAttribute(\"data-v\");' +\n            'var box=document.getElementById(\"catBox\");var html=\"\";' +\n            'var list=[];' +\n            'for(var i=0;i<CATS.length;i++){if(!ch||String(CATS[i][2])==ch){list.push(CATS[i]);}}' +\n            'html+=\\'<button class=\"b\" data-v=\"\">全部<\/button>\\';' +\n            'for(var j=0;j<list.length;j++){html+=\\'<button class=\"b\" data-v=\"\\'+list[j][1]+\\'\">\\'+list[j][0]+\\'<\/button>\\';}' +\n            'box.innerHTML=html;' +\n            'bindGroup(box);' +\n            'markActive(\"category\",fSaved.category||\"\");}' +\n            'function renderTag(){var ch=document.querySelector(\\'[data-g=\"channel\"] .b.active\\').getAttribute(\"data-v\");' +\n            'var tags=(ch===\"1\")?MALE_TAGS:(ch===\"2\"?FEMALE_TAGS:MALE_TAGS.concat(FEMALE_TAGS));' +\n            'var list=document.getElementById(\"tagOpts\");var html=\"\";' +\n            'for(var i=0;i<tags.length;i++){' +\n            'var chTag=(MALE_TAGS.indexOf(tags[i])>=0)?\"男频\":\"女频\";' +\n            'html+=\\'<div class=\"opt\" data-v=\"\\'+tags[i]+\\'\"><span>\\'+tags[i]+\\'<\/span><span class=\"ch\">\\'+chTag+\\'<\/span><\/div>\\';}' +\n            'list.innerHTML=html;' +\n            'var sel=fSaved.tag||[];' +\n            'for(var j=0;j<sel.length;j++){var o=list.querySelector(\\'[data-v=\"\\'+sel[j]+\\'\"]\\');' +\n            'if(o)o.classList.add(\"active\");}' +\n            'renderTagChips();' +\n            'var tip=document.getElementById(\"tagTip\");' +\n             'if(!ch){tip.innerHTML=\"共\"+tags.length+\"个标签,可多选(建议先选频道)\";}else{tip.innerHTML=\"共\"+tags.length+\"个标签,可多选\";}}' +\n            'function renderTagChips(){' +\n            'var os=document.querySelectorAll(\\'[data-g=\"tag\"] .opt.active\\');' +\n            'var chips=document.getElementById(\"tagSelChips\");' +\n            'var ph=document.getElementById(\"tagSelPh\");' +\n            'var html=\"\";' +\n            'for(var i=0;i<os.length;i++){' +\n            'var v=os[i].getAttribute(\"data-v\");' +\n            'html+=\\'<span class=\"seltag\">\\'+v+\\'<i class=\"selx\" data-v=\"\\'+v+\\'\">&#10005;<\/i><\/span>\\';}' +\n            'chips.innerHTML=html;' +\n            'if(os.length){ph.style.display=\"none\";}else{ph.style.display=\"inline\";}}' +\n            'function bindTagSelect(){var box=document.getElementById(\"tagSelBox\");' +\n            'var drop=document.getElementById(\"tagDrop\");' +\n            'box.addEventListener(\"click\",function(){drop.classList.toggle(\"open\");box.classList.toggle(\"open\");});' +\n            'document.addEventListener(\"click\",function(e){' +\n            'if(!document.getElementById(\"tagSelBox\").contains(e.target)){drop.classList.remove(\"open\");box.classList.remove(\"open\");}});' +\n            'var opts=document.getElementById(\"tagOpts\");' +\n            'opts.addEventListener(\"click\",function(e){' +\n            'var t=e.target;while(t&&t!==opts&&!t.classList.contains(\"opt\")){t=t.parentNode;}' +\n            'if(t&&t.classList.contains(\"opt\")){t.classList.toggle(\"active\");renderTagChips();}});' +\n            'var chips=document.getElementById(\"tagSelChips\");' +\n            'chips.addEventListener(\"click\",function(e){' +\n            'var x=e.target;if(!x.classList||!x.classList.contains(\"selx\"))return;' +\n            'var o=opts.querySelector(\\'[data-v=\"\\'+x.getAttribute(\"data-v\")+\\'\"]\\');' +\n            'if(o)o.classList.remove(\"active\");' +\n            'renderTagChips();});}' +\n            'function markActive(groupName,val){var c=document.querySelector(\\'[data-g=\"\\'+groupName+\\'\"]\\');' +\n            'if(!c)return;var bs=c.querySelectorAll(\".b\");' +\n            'for(var i=0;i<bs.length;i++){bs[i].classList.toggle(\"active\",bs[i].getAttribute(\"data-v\")==val);}}' +\n            'function bindGroup(box){var bs=box.querySelectorAll(\".b\");' +\n            'for(var i=0;i<bs.length;i++){bs[i].addEventListener(\"click\",(function(b,isTag){return function(){' +\n            'if(isTag){b.classList.toggle(\"active\");}else{' +\n            'var old=b.parentNode.querySelector(\".b.active\");if(old)old.classList.remove(\"active\");' +\n            'b.classList.add(\"active\");' +\n            'if(b.parentNode.getAttribute(\"data-g\")===\"sort\"){updateBookAge();}}}})(bs[i],box.getAttribute(\"data-g\")===\"tag\"));}}' +\n            'function updateBookAge(){' +\n            'var so=document.querySelector(\\'[data-g=\"sort\"] .b.active\\');' +\n            'var val=so?so.getAttribute(\"data-v\"):\"\";' +\n            'var grp=document.getElementById(\"bookAgeGroup\");' +\n            'if(val===\"score\"||val===\"scorer\"){grp.style.display=\"block\";}' +\n            'else{grp.style.display=\"none\";' +\n            'var ab=grp.querySelector(\\'[data-g=\"bookage\"] .b.active\\');if(ab)ab.classList.remove(\"active\");' +\n            'var def=grp.querySelector(\\'[data-g=\"bookage\"] .b[data-v=\"\"]\\');if(def)def.classList.add(\"active\");}}' +\n            'function bindChannels(){var box=document.querySelector(\\'[data-g=\"channel\"]\\');' +\n            'var bs=box.querySelectorAll(\".b\");' +\n            'for(var i=0;i<bs.length;i++){bs[i].addEventListener(\"click\",function(){' +\n            'var old=box.querySelector(\".b.active\");if(old)old.classList.remove(\"active\");' +\n            'this.classList.add(\"active\");' +\n            'if(fSaved.channel!==undefined){fSaved.channel=this.getAttribute(\"data-v\");}' +\n            'renderCategory();renderTag();});}}' +\n            'function init(){get(KEY).then(function(raw){' +\n            'if(raw){try{fSaved=JSON.parse(raw);}catch(e){}}' +\n            'var ch=fSaved.channel||\"\";' +\n            'markActive(\"channel\",ch);' +\n            'markActive(\"word\",fSaved.word||\"\");markActive(\"status\",fSaved.status||\"\");' +\n            'markActive(\"update\",fSaved.update||\"\");markActive(\"sort\",fSaved.sort||\"\");' +\n            'markActive(\"bookage\",fSaved.bookage||\"\");' +\n            'markActive(\"scorer\",fSaved.scorer||\"\");' +\n            'updateBookAge();' +\n            'renderCategory();renderTag();});}' +\n            'function readGroups(){var f={};var gs=document.querySelectorAll(\".btns\");' +\n            'for(var i=0;i<gs.length;i++){var g=gs[i].getAttribute(\"data-g\");' +\n            'var active=gs[i].querySelector(\".b.active\");' +\n            'f[g]=active?active.getAttribute(\"data-v\"):\"\";}' +\n            'var os=document.querySelectorAll(\\'[data-g=\"tag\"] .opt.active\\');' +\n            'var sel=[];for(var k=0;k<os.length;k++){sel.push(os[k].getAttribute(\"data-v\"));}' +\n            'f.tag=sel;' +\n            'return f;}' +\n            'function clearAll(){' +\n            'var gs=document.querySelectorAll(\".btns\");' +\n            'for(var i=0;i<gs.length;i++){var actives=gs[i].querySelectorAll(\".b.active\");' +\n            'for(var j=0;j<actives.length;j++){actives[j].classList.remove(\"active\");}}' +\n            'var os=document.querySelectorAll(\\'[data-g=\"tag\"] .opt.active\\');' +\n            'for(var k=0;k<os.length;k++){os[k].classList.remove(\"active\");}' +\n            'var chb=document.querySelector(\\'[data-g=\"channel\"] .b[data-v=\"\"]\\');if(chb)chb.classList.add(\"active\");' +\n            'var wb=document.querySelector(\\'[data-g=\"word\"] .b[data-v=\"\"]\\');if(wb)wb.classList.add(\"active\");' +\n            'var sb=document.querySelector(\\'[data-g=\"status\"] .b[data-v=\"\"]\\');if(sb)sb.classList.add(\"active\");' +\n            'var ub=document.querySelector(\\'[data-g=\"update\"] .b[data-v=\"\"]\\');if(ub)ub.classList.add(\"active\");' +\n            'var ob=document.querySelector(\\'[data-g=\"sort\"] .b[data-v=\"\"]\\');if(ob)ob.classList.add(\"active\");' +\n            'var rr=document.querySelector(\\'[data-g=\"scorer\"] .b[data-v=\"\"]\\');if(rr)rr.classList.add(\"active\");' +\n            'var bb=document.querySelector(\\'[data-g=\"bookage\"] .b[data-v=\"\"]\\');if(bb)bb.classList.add(\"active\");' +\n            'updateBookAge();' +\n            'fSaved={};renderCategory();renderTag();}' +\n            'function save(apply){' +\n            'if(!apply){clearAll();}' +\n            'set(KEY,JSON.stringify(readGroups()));' +\n            'if(apply||!apply){try{bridge.callHandler(\"back\");}catch(e){}}}' +\n            'function bind(){' +\n            'var gs=document.querySelectorAll(\".btns\");' +\n            'for(var i=0;i<gs.length;i++){var g=gs[i].getAttribute(\"data-g\");' +\n            'if(g===\"channel\"){bindChannels();continue;}' +\n            'if(g===\"category\"){continue;}' +\n            'bindGroup(gs[i]);}' +\n            'bindTagSelect();}' +\n            'if(bridge){bind();init();}else{window.addEventListener(\"flutterInAppWebViewPlatformReady\",function(){bind();init();});}' +\n            '<\\\/script><\/body><\/html>';\n    }\n\n    function encodeDataUrl(html) {\n        try {\n            var b64 = \"\";\n            try { b64 = flutterBridge.base64encode(html); } catch (e) {}\n            if (typeof b64 !== \"string\") { b64 = \"\"; }\n            if (!b64 && typeof btoa === \"function\") {\n                try { b64 = btoa(unescape(encodeURIComponent(html))); } catch (e2) {}\n            }\n            if (!b64) { return \"\"; }\n            return \"data:text\/html;base64,\" + b64;\n        } catch (e) {\n            return \"\";\n        }\n    }\n\n    \/\/ 读取筛选 JSON:prefix + \"filter\"\n    async function readFilter(prefix) {\n        var f = {};\n        try {\n            var raw = await cache.get(prefix + \"filter\");\n            if (raw) { f = JSON.parse(raw); }\n        } catch (e) {}\n        return f || {};\n    }\n\n    \/\/ 本地过滤(服务端忽略的部分):字数 \/ 人数筛选\n    function passLocalFilter(item, f) {\n        if (!f) { return true; }\n        var wnum = parseInt(item.word_number, 10) || 0;\n        if (f.word === \"1\" && !(wnum < 1000000)) { return false; }\n        if (f.word === \"2\" && !(wnum >= 1000000 && wnum < 2000000)) { return false; }\n        if (f.word === \"3\" && !(wnum >= 2000000)) { return false; }\n        if (f.scorer) {\n            var min = parseInt(f.scorer, 10) || 0;\n            if (min > 0 && (parseInt(item.scorer, 10) || 0) < min) { return false; }\n        }\n        return true;\n    }\n\n    \/\/ 把服务端支持的筛选参数合并进发现 URL(type\/categoryId\/updateStatus\/update\/tagList\/sort)\n    \/\/ 会替换 URL 中已存在的同名参数,避免重复\n    function mergeFindParams(url, f) {\n        if (!f) { return url; }\n        var add = {};\n        if (f.channel) { add.type = f.channel; }\n        if (f.category) { add.categoryId = f.category; }\n        if (f.status) { add.updateStatus = f.status; }\n        if (f.update) { add.update = f.update; }\n        \/\/ 标签:服务端 getList 支持 tagList(逗号分隔,AND 语义),与真实网站 getNovelList 一致\n        var tagArr = f.tag;\n        if (typeof tagArr === \"string\") { tagArr = tagArr ? [tagArr] : []; }\n        if (Array.isArray(tagArr) && tagArr.length) { add.tagList = tagArr.join(\",\"); }\n        \/\/ 排序:评分\/评分人数时,书龄子选项覆盖为 score_1~3 \/ scorer_1~3(同网站 getNovelList 逻辑)\n        var sortVal = f.sort || \"\";\n        if (f.bookage && (sortVal === \"score\" || sortVal === \"scorer\")) {\n            sortVal = sortVal + \"_\" + f.bookage;\n        }\n        if (sortVal) { add.sort = sortVal; }\n        var addKeys = Object.keys(add);\n        if (!addKeys.length) { return url; }\n\n        var qi = url.indexOf(\"?\");\n        if (qi < 0) {\n            var q = [];\n            for (var k0 = 0; k0 < addKeys.length; k0++) { q.push(addKeys[k0] + \"=\" + encodeURIComponent(add[addKeys[k0]])); }\n            return url + \"?\" + q.join(\"&\");\n        }\n        var base = url.substring(0, qi);\n        var qs = url.substring(qi + 1);\n        var parts = qs ? qs.split(\"&\") : [];\n        var replaced = {};\n        var out = [];\n        for (var i = 0; i < parts.length; i++) {\n            var p = parts[i];\n            var eq = p.indexOf(\"=\");\n            var name = eq >= 0 ? p.substring(0, eq) : p;\n            if (Object.prototype.hasOwnProperty.call(add, name)) {\n                if (!replaced[name]) {\n                    out.push(name + \"=\" + encodeURIComponent(add[name]));\n                    replaced[name] = true;\n                }\n            } else {\n                out.push(p);\n            }\n        }\n        for (var j = 0; j < addKeys.length; j++) {\n            var n = addKeys[j];\n            if (!replaced[n]) { out.push(n + \"=\" + encodeURIComponent(add[n])); }\n        }\n        return base + \"?\" + out.join(\"&\");\n    }\n\n    \/\/ ===== 书本类 =====\n    \/\/ {\n    \/\/    \"bookUrl\": \"\",                 \/\/书本 url 不可重复\n    \/\/    \"name\": \"\",                    \/\/书本名称\n    \/\/    \"author\": \"\",                  \/\/作者\n    \/\/    \"kind\": \"\",                    \/\/分类\n    \/\/    \"coverUrl\": \"\",                \/\/封面\n    \/\/    \"intro\": \"\",                   \/\/简介\n    \/\/    \"tocUrl\": \"\",                  \/\/目录 url\n    \/\/    \"wordCount\": \"\",               \/\/字数\n    \/\/    \"type\": \"\",                    \/\/书本类别 0 小说 1 听书 2 漫画 4 短剧\n    \/\/    \"latestChapterTitle\": \"\",      \/\/最新章节标题\n    \/\/    \"downloadUrls\": \"\"             \/\/下载地址,如果支持下载书籍可以提供\n    \/\/ }\n\n    \/\/ ===== 目录类 =====\n    \/\/ {\n    \/\/     \"name\" :\"\",                   \/\/章节标题\n    \/\/     \"chapterId\":\"\",               \/\/正文 url\n    \/\/     \"index\" :0,                   \/\/index\n    \/\/     \"isPay\":false,                \/\/是否需要付费\n    \/\/     \"isVip\":false,                \/\/是否是 vip\n    \/\/     \"isVolume\":false,             \/\/是否是卷名\n    \/\/     \"tag\":\"\"                      \/\/小标题\n    \/\/ }\n    \/\/ 当isvip 为 true ispay 为false时会显示购买按钮\n\n    \/\/ ===== 发现类 =====\n    \/\/ {\n    \/\/     \"title\" :\"\",                  \/\/标题,当下拉框或者输入框值修改时会自动调用 cache.set(title,值)\n    \/\/     \"url\":\"\",                     \/\/url\n    \/\/     \"js\":\"\",                      \/\/type 为 0 时生效,要运行的 js\n    \/\/     \"action\":\"\",                  \/\/type 为 2 3 4 时生效,要运行的 js\n    \/\/     \"chars\":[],                   \/\/下拉框的值的数组\n    \/\/     \"default\":\"\",                 \/\/type 为 2 3 时生效,默认值\n    \/\/     \"type\" :0,\n    \/\/     \"useShouldOverrideUrlLoading\" :false,  \/\/是否使用shouldOverrideUrlLoading拦截url,type 为1时生效\n    \/\/     \"width\": 0,\n    \/\/ }\n    \/\/ url 和 js 只能填一个\n    \/\/ type > 1 仅适用于非满行按钮\n    \/\/ 当type为 0 正常解析发现页,当 type 为 1 则会用 webview 打开 url, type 为 2 时 显示下拉框, type 为 3 时 输入框, 4 为按钮 点击运行action\n    \/\/ width 为 0 时则默认处理宽度(1行3个),1 是一行2个,3 是一行1个\n    \/\/ url 和 js 都为空时会按照 width = 3 处理\n    \/\/ 如果发现支持分页需要在url中带有page字符,如果用不上可以在find函数中替换掉\n\n    \/\/ ===== 登录类 =====\n    \/\/ {\n    \/\/     \"name\" :\"\",                   \/\/标题\n    \/\/     \"action\":\"\",                  \/\/执行的js 仅button生效\n    \/\/     \"type\" :\"\",                   \/\/button text select 或者 password\n    \/\/ }\n\n    \/\/ ===== 搜索函数 =====\n    \/\/ 如果没有分页 请在 page 为 2 及以上返回 \"[]\"\n    \/\/ env 为搜索类型,可以判断是不是在搜索界面搜索或者是换源,当env为searchone 时为单书源搜索,允许使用筛选功能\n    \/\/ 当env为searchone 又启用了filter时 请不要通过getsearch 函数获取搜索类型\n    async function search(key, page, env) {\n        try {\n            var u = baseurl + \"\/api\/novel\/search?keyword=\" + encodeURIComponent(key) + \"&page=\" + page;\n            var get = await http.Get(u, header, true);\n            if (!get || !get.data) { return \"[]\"; }\n            flutterBridge.text(0, get.data);\n\n            var json = JSON.parse(get.data);\n            if (json.code !== \"00\" || !json.data || !json.data.data) { return \"[]\"; }\n\n            var books = [];\n            json.data.data.forEach(function(item) {\n                var bookUrl = baseurl + \"\/novel\/\" + item.id + \".html\";\n                var status = item.update_status === 0 ? \"连载中\" : (item.update_status === 1 ? \"已完结\" : (item.update_status === 2 ? \"已太监\" : \"\"));\n                var wordCount = item.word_number ? Math.floor((parseInt(item.word_number, 10) || 0) \/ 10000) + \"万字\" : \"\";\n                var kind = item.tags ? item.tags.split(\",\")[0] : \"\";\n                books.push({\n                    bookUrl: bookUrl,\n                    name: item.novel_name,\n                    author: item.author_name,\n                    kind: kind,\n                    coverUrl: item.novel_img || \"\",\n                    wordCount: wordCount,\n                    intro: item.synopsis || \"\",\n                    tocUrl: bookUrl,\n                    type: 0\n                });\n            });\n\n            return JSON.stringify(books);\n        } catch (e) {\n            flutterBridge.log(\"search error:\" + e.message);\n            return \"[]\";\n        }\n    }\n\n    \/\/ ===== 筛选函数 =====\n    \/\/ 是否提供搜索筛选功能,如果提供可以反馈一个网址,或者以data开头base64加密的html\n    \/\/ 实现模式:返回 base64 的筛选界面 HTML,用户点选后把条件存到缓存(见 SKILL.md \"发现\/搜索筛选实现模式\")\n    \/\/   搜索\/发现里读缓存执行过滤:服务端 API 原生支持的参数拼进 URL,服务端忽略的(标签\/字数\/评分人数)本地过滤\n    \/\/   可选联动:频道(单选)→分类(单选)\/标签 联动;标签模仿站点的下拉多选(每项显示标签名+频道后缀),数据可抓取后直接注入 HTML 作为 JS 数组\n    async function filter() {\n        return \"\";\n    }\n    \/\/ ===== 发现筛选函数 =====\n    \/\/ 是否对发现提供筛选功能,如果提供可以反馈一个网址,或者以data开头base64加密的html\n    \/\/ 缓存键用独立前缀(如 ypshuo_find_filter),与搜索筛选区分\n    async function findfilter(url) {\n        try {\n            var html = buildFilterHtml(\"ypshuo_find_\");\n            return encodeDataUrl(html);\n        } catch (e) {\n            flutterBridge.log(\"findfilter error:\" + e.message);\n            return \"\";\n        }\n    }\n\n    \/\/ ===== 详情页函数 =====\n    \/\/ ⚠️ bookUrl 必须原样返回 bookurl 入参,不可改动!\n    async function info(bookurl) {\n        try {\n            var u = absUrl(bookurl);\n            var get = await http.Get(u, header, true);\n            if (!get || !get.data) {\n                return JSON.stringify({ \"bookUrl\": bookurl, \"name\": \"\", \"author\": \"\", \"coverUrl\": \"\", \"intro\": \"\", \"kind\": \"\", \"wordCount\": \"\", \"status\": \"\", \"tocUrl\": bookurl, \"type\": 0 });\n            }\n            flutterBridge.text(1, get.data);\n\n            var html = removeHTMLTags(get.data);\n            var $doc = parseHTMLSafely(html);\n\n            var name = $doc.find('meta[name=\"og:novel:book_name\"]').attr(\"content\") || $doc.find(\".book-name\").text().trim() || \"\";\n            var author = $doc.find('meta[name=\"og:novel:author\"]').attr(\"content\") || $doc.find(\".author-info .text-red-500\").text().trim() || \"\";\n            var coverUrl = $doc.find('meta[data-hid=\"og:image\"]').attr(\"content\") || $doc.find(\"img.book-img\").attr(\"src\") || \"\";\n            var kind = \"\";\n            $doc.find(\".tag-list .el-tag\").each(function() {\n                var t = $(this).text().trim();\n                if (t) { kind = kind ? kind + \" \" + t : t; }\n            });\n            if (!kind) {\n                kind = $doc.find('meta[name=\"og:novel:category\"]').attr(\"content\") || \"\";\n            }\n            var desc = $doc.find('meta[name=\"description\"]').attr(\"content\") || \"\";\n            var intro = \"\";\n            var idx = desc.indexOf(\"简介:\");\n            if (idx >= 0) {\n                intro = desc.substring(idx + 3);\n            } else {\n                intro = $doc.find(\".book-intro\").text().trim() || desc;\n            }\n            var status = $doc.find(\".book-status\").text().trim().replace(\/^状态:\/, \"\").replace(\/[\\s].*$\/, \"\");\n            var wordCount = $doc.find(\".book-word\").text().trim().replace(\/^[^\\d]*\/, \"\");\n\n            removeHTMLSafely($doc);\n\n            return JSON.stringify({\n                bookUrl: bookurl,\n                name: name,\n                author: author,\n                coverUrl: coverUrl,\n                intro: intro,\n                kind: kind,\n                status: status,\n                wordCount: wordCount,\n                tocUrl: bookurl,\n                type: 0\n            });\n        } catch (e) {\n            flutterBridge.log(\"info error:\" + e.message);\n            return JSON.stringify({ \"bookUrl\": bookurl, \"name\": \"\", \"author\": \"\", \"coverUrl\": \"\", \"intro\": \"\", \"kind\": \"\", \"wordCount\": \"\", \"status\": \"\", \"tocUrl\": bookurl, \"type\": 0 });\n        }\n    }\n\n    \/\/ ===== 目录页函数 =====\n    async function chapter(tocUrl,bookurl) {\n        return  \"[]\";\n    }\n    \/\/ ===== 正文页函数 =====\n    \/\/ 提交内容为目录类里的chapterId\n    async function content(url,bookurl) {\n        return \"\";\n    }\n    \/\/ ===== 发现函数 =====\n    async function getfinds() {\n        try {\n            var result = [];\n            var push = function (title, url, type) { result.push({ title: title, url: url, type: type }); };\n            push(\"全部\", \"\", 1);\n            push(\"全部\", baseurl + \"\/api\/novel\/getList?page={{page}}\", 0);\n            push(\"玄幻\", baseurl + \"\/api\/novel\/getList?categoryId=1&page={{page}}\", 0);\n            push(\"奇幻\", baseurl + \"\/api\/novel\/getList?categoryId=2&page={{page}}\", 0);\n            push(\"武侠\", baseurl + \"\/api\/novel\/getList?categoryId=3&page={{page}}\", 0);\n            push(\"仙侠\", baseurl + \"\/api\/novel\/getList?categoryId=4&page={{page}}\", 0);\n            push(\"都市\", baseurl + \"\/api\/novel\/getList?categoryId=5&page={{page}}\", 0);\n            push(\"现实\", baseurl + \"\/api\/novel\/getList?categoryId=6&page={{page}}\", 0);\n            push(\"军事\", baseurl + \"\/api\/novel\/getList?categoryId=7&page={{page}}\", 0);\n            push(\"历史\", baseurl + \"\/api\/novel\/getList?categoryId=8&page={{page}}\", 0);\n            push(\"悬疑\", baseurl + \"\/api\/novel\/getList?categoryId=9&page={{page}}\", 0);\n            push(\"游戏\", baseurl + \"\/api\/novel\/getList?categoryId=10&page={{page}}\", 0);\n            push(\"竞技\", baseurl + \"\/api\/novel\/getList?categoryId=11&page={{page}}\", 0);\n            push(\"科幻\", baseurl + \"\/api\/novel\/getList?categoryId=12&page={{page}}\", 0);\n            push(\"灵异\", baseurl + \"\/api\/novel\/getList?categoryId=13&page={{page}}\", 0);\n            push(\"二次元\", baseurl + \"\/api\/novel\/getList?categoryId=14&page={{page}}\", 0);\n            push(\"同人\", baseurl + \"\/api\/novel\/getList?categoryId=15&page={{page}}\", 0);\n            push(\"穿越时空\", baseurl + \"\/api\/novel\/getList?categoryId=17&page={{page}}\", 0);\n            push(\"架空历史\", baseurl + \"\/api\/novel\/getList?categoryId=18&page={{page}}\", 0);\n            push(\"总裁豪门\", baseurl + \"\/api\/novel\/getList?categoryId=19&page={{page}}\", 0);\n            push(\"古典架空\", baseurl + \"\/api\/novel\/getList?categoryId=20&page={{page}}\", 0);\n            push(\"前世今生\", baseurl + \"\/api\/novel\/getList?categoryId=21&page={{page}}\", 0);\n            push(\"灵异科幻\", baseurl + \"\/api\/novel\/getList?categoryId=22&page={{page}}\", 0);\n            push(\"西方罗曼\", baseurl + \"\/api\/novel\/getList?categoryId=23&page={{page}}\", 0);\n            push(\"青梅竹马\", baseurl + \"\/api\/novel\/getList?categoryId=24&page={{page}}\", 0);\n            push(\"其它同人\", baseurl + \"\/api\/novel\/getList?categoryId=25&page={{page}}\", 0);\n            push(\"短小说\", baseurl + \"\/api\/novel\/getList?categoryId=26&page={{page}}\", 0);\n            push(\"综合其它\", baseurl + \"\/api\/novel\/getList?categoryId=27&page={{page}}\", 0);\n            push(\"男频\", \"\", 1);\n            push(\"全部\", baseurl + \"\/api\/novel\/getList?type=1&page={{page}}\", 0);\n            push(\"玄幻\", baseurl + \"\/api\/novel\/getList?type=1&categoryId=1&page={{page}}\", 0);\n            push(\"奇幻\", baseurl + \"\/api\/novel\/getList?type=1&categoryId=2&page={{page}}\", 0);\n            push(\"武侠\", baseurl + \"\/api\/novel\/getList?type=1&categoryId=3&page={{page}}\", 0);\n            push(\"仙侠\", baseurl + \"\/api\/novel\/getList?type=1&categoryId=4&page={{page}}\", 0);\n            push(\"都市\", baseurl + \"\/api\/novel\/getList?type=1&categoryId=5&page={{page}}\", 0);\n            push(\"现实\", baseurl + \"\/api\/novel\/getList?type=1&categoryId=6&page={{page}}\", 0);\n            push(\"军事\", baseurl + \"\/api\/novel\/getList?type=1&categoryId=7&page={{page}}\", 0);\n            push(\"历史\", baseurl + \"\/api\/novel\/getList?type=1&categoryId=8&page={{page}}\", 0);\n            push(\"悬疑\", baseurl + \"\/api\/novel\/getList?type=1&categoryId=9&page={{page}}\", 0);\n            push(\"游戏\", baseurl + \"\/api\/novel\/getList?type=1&categoryId=10&page={{page}}\", 0);\n            push(\"竞技\", baseurl + \"\/api\/novel\/getList?type=1&categoryId=11&page={{page}}\", 0);\n            push(\"科幻\", baseurl + \"\/api\/novel\/getList?type=1&categoryId=12&page={{page}}\", 0);\n            push(\"灵异\", baseurl + \"\/api\/novel\/getList?type=1&categoryId=13&page={{page}}\", 0);\n            push(\"二次元\", baseurl + \"\/api\/novel\/getList?type=1&categoryId=14&page={{page}}\", 0);\n            push(\"同人\", baseurl + \"\/api\/novel\/getList?type=1&categoryId=15&page={{page}}\", 0);\n            push(\"女频\", \"\", 1);\n            push(\"全部\", baseurl + \"\/api\/novel\/getList?type=2&page={{page}}\", 0);\n            push(\"穿越时空\", baseurl + \"\/api\/novel\/getList?type=2&categoryId=17&page={{page}}\", 0);\n            push(\"架空历史\", baseurl + \"\/api\/novel\/getList?type=2&categoryId=18&page={{page}}\", 0);\n            push(\"总裁豪门\", baseurl + \"\/api\/novel\/getList?type=2&categoryId=19&page={{page}}\", 0);\n            push(\"古典架空\", baseurl + \"\/api\/novel\/getList?type=2&categoryId=20&page={{page}}\", 0);\n            push(\"前世今生\", baseurl + \"\/api\/novel\/getList?type=2&categoryId=21&page={{page}}\", 0);\n            push(\"灵异科幻\", baseurl + \"\/api\/novel\/getList?type=2&categoryId=22&page={{page}}\", 0);\n            push(\"西方罗曼\", baseurl + \"\/api\/novel\/getList?type=2&categoryId=23&page={{page}}\", 0);\n            push(\"青梅竹马\", baseurl + \"\/api\/novel\/getList?type=2&categoryId=24&page={{page}}\", 0);\n            push(\"其它同人\", baseurl + \"\/api\/novel\/getList?type=2&categoryId=25&page={{page}}\", 0);\n            push(\"短小说\", baseurl + \"\/api\/novel\/getList?type=2&categoryId=26&page={{page}}\", 0);\n            push(\"综合其它\", baseurl + \"\/api\/novel\/getList?type=2&categoryId=27&page={{page}}\", 0);\n            return JSON.stringify(result);\n        } catch (e) {\n            flutterBridge.log(\"getfinds error:\" + e.message);\n            return \"[]\";\n        }\n    }\n\n    function clientSalt() {\n        var n = new Date().getTime() \/ 1000;\n        var key = CryptoJS.enc.Utf8.parse(\"1234567890123456\");\n        var iv = CryptoJS.enc.Utf8.parse(\"efcf77768be478cb\");\n        var encrypted = CryptoJS.AES.encrypt(n.toString(), key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });\n        return encrypted.toString();\n    }\n\n    \/\/ ===== 发现搜索函数 =====\n    async function find(url, page) {\n        try {\n            \/\/ 读取发现筛选并合并服务端参数(type\/categoryId\/updateStatus\/update\/sort)\n            var f = await readFilter(\"ypshuo_find_\");\n            var u = mergeFindParams(url.replace(\"{{page}}\", page), f);\n            if (page > 1) { u = u + \"&clientSalt=\" + encodeURIComponent(clientSalt()); }\n            flutterBridge.log(\"find URL: \" + u);\n\n            var get = await http.Get(u, header, true);\n            if (!get || !get.data) return \"[]\";\n\n            var json = JSON.parse(get.data);\n            if (json.code !== \"00\" || !json.data || !json.data.data) return \"[]\";\n\n            var books = [];\n            json.data.data.forEach(function(item) {\n                \/\/ 服务端已按 channel\/category\/status\/update\/tagList\/sort 过滤,本地只需补 word\/scorer\n                var fLocal = {};\n                fLocal.word = f.word;\n                fLocal.scorer = f.scorer;\n                if (!passLocalFilter(item, fLocal)) { return; }\n\n                var bookUrl = baseurl + \"\/novel\/\" + item.id + \".html\";\n                var status = item.update_status === 0 ? \"连载中\" : (item.update_status === 1 ? \"已完结\" : (item.update_status === 2 ? \"已太监\" : \"\"));\n                var wordCount = item.word_number ? Math.floor((parseInt(item.word_number, 10) || 0) \/ 10000) + \"万字\" : \"\";\n                var kind = item.tags ? item.tags.split(\",\")[0] : \"\";\n                books.push({\n                    bookUrl: bookUrl,\n                    name: item.novel_name,\n                    author: item.author_name,\n                    kind: kind,\n                    coverUrl: item.novel_img || \"\",\n                    wordCount: wordCount,\n                    intro: item.synopsis || \"\",\n                    tocUrl: bookUrl,\n                    type: 0\n                });\n            });\n\n            flutterBridge.log(\"find books: \" + books.length);\n            return JSON.stringify(books);\n        } catch (e) {\n            flutterBridge.log(\"find error:\" + e.message);\n            return \"[]\";\n        }\n    }\n\n    \/\/ ===== 购买函数 =====\n    \/\/ 执行完成后会刷新目录和正文\n    async function pay(bookurl,url) {\n\n    }\n\n    \/\/ ===== 登录函数 =====\n    \/\/ 返回http开头的url 或者 登录数组的json\n    \/\/ 如果是登录数组的json 用户登录完会执行 await login()\n    async function getloginurl() {\n        return baseurl;\n    }\n\n    async function login() {\n\n    }\n\n    \/\/ ===== 图片解密函数 =====\n    \/\/ url 为图片的url,如果需要传递参数可以在图片后接json字符串,例如:http:\/\/127.0.0.1,{'headers':{'a':'b'}}\n    \/\/ image 为加密的图片的base64,执行的js必须是字符串所以这参数只能base64转码\n    \/\/ 这个函数得返回byteList List<int> ,并且能直接被Uint8List.fromList(byteList)接受\n    async function imagedecrypt(url,image) {\n\n    }\n\n    \/\/ ===== Webview拦截函数 =====\n    \/\/ 当调用startBrowserWithShouldOverrideUrlLoading时必须有此函数\n    \/\/ url 为每次打开的 url\n    \/\/ 返回 false 则会取消打开这个网页\n    async function shouldOverrideUrlLoading(url) {\n        return true;\n    }\n\n    \/\/ ===== 帮助函数 =====\n    \/\/ 开启帮助后点击帮助将会显示函数反馈的内容\n    \/\/ 三种反馈方式:\n    \/\/ 1. http 开头的链接\n    \/\/ 2. 纯文字\n    \/\/ 3. @html: 开头的 html 内容\n    async function gethelp() {\n        return \"\";\n    }\n<\/script>\n\n<\/html>\n",
    "login": false,
    "lastUpdateTime": "1785814138225"
}
广告