🎧听友FM
https://tingyou.fm/
dev-xx (13787)3天前
该用户很懒,什么介绍也没有写!
{
"bookSourceUrl": "https:\/\/tingyou.fm\/",
"bookSourceName": "🎧听友FM",
"enabledExplore": true,
"enabled": true,
"bookSourceGroup": "",
"author": "",
"help": false,
"html": "<!DOCTYPE html>\r\n<html lang=\"zh\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <title>听友FM<\/title>\r\n<\/head>\r\n<body>\r\n\r\n<\/body>\r\n<script>\r\n\r\n var isCookieJar=true;\/\/ 不需要CookieJar请修改此处\r\n class FlutterJSBridge {\r\n constructor() {\r\n this.init(); \/\/前台webview 里必须删除这行\r\n }\r\n\r\n init() {\r\n if (window.flutter_inappwebview) {\r\n this.isReady = true;\r\n this.CookieJar();\r\n } else {\r\n window.addEventListener('flutterInAppWebViewPlatformReady', () => {\r\n this.isReady = true;\r\n console.log('JSBridge初始化完成');\r\n this.CookieJar();\r\n });\r\n }\r\n }\r\n\r\n \/\/通知原生页面初始化完成,仅在书源和tts生效,webview请勿使用,只有通知加载成功后才允许运行,否则会一直等待加载成功\r\n async CookieJar() {\r\n try {\r\n await window.flutter_inappwebview.callHandler('CookieJar', isCookieJar);\r\n } catch (error) {\r\n console.error('汇报完成准备失败:', error);\r\n }\r\n }\r\n\r\n \/\/获取应用编译版本,如果版本号大于1000,请去除第一位数字\r\n async getbuildNumber() {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('buildNumber');\r\n } catch (error) {\r\n return 0;\r\n }\r\n }\r\n\r\n \/\/获取应用版本,请以编译版本为准,ios tf版本可能不会修改版本号\r\n async getversion() {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('version');\r\n } catch (error) {\r\n return \"0.0.0\";\r\n }\r\n }\r\n\r\n \/\/仅书源支持\r\n async getsourceurl() {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('getsourceurl');\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/125版本后支持,获取用户在搜索页选中的分类, -1 全部 0 小说 1 听书 2漫画(需要判断用户是不是在搜索页调用)\r\n async getsearch() {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('getsearch');\r\n } catch (error) {\r\n return -1;\r\n }\r\n }\r\n\r\n \/\/下面 2 个接口可以获取屏幕宽高 用于生成图片\r\n async getWidth( ) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('getWidth');\r\n } catch (error) {\r\n return 0;\r\n }\r\n }\r\n\r\n async getHeight( ) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('getHeight');\r\n } catch (error) {\r\n return 0;\r\n }\r\n }\r\n\r\n \/\/将html转换成正文格式\r\n async htmlToText(str) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('htmlToText',str);\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/调用内置播放器,key为唯一值,请给每个视频定义一个唯一值\r\n async showvideoplay(url,title,key) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('showvideoplay',url,title,key);\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/刷新正文页\r\n async refreshContent(bookurl) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('refreshContent',bookurl);\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/刷新发现页,如用户当前正处于发现页会直接刷新,不在发现页会清除发现页缓存\r\n async refreshExplore() {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('refreshExplore');\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/显示软件气泡选择\r\n async showsvg() {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('showsvg');\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/获取软件 svg 气泡\r\n async getsvg() {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('getsvg');\r\n } catch (error) {\r\n return [];\r\n }\r\n }\r\n\r\n \/\/新增气泡\r\n async addsvg(svg) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('addsvg',svg);\r\n } catch (error) {\r\n return [];\r\n }\r\n }\r\n\r\n \/\/动态更新 html 代码,主要用于更新在线版地址,确保地址是最新的,此函数只能在书源中使用\r\n async setHtml(str) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('setHtml',str);\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/将简体字转成繁体字\r\n async toTraditional(str) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('toTraditional',str);\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/将繁体字转成简体字\r\n async toSimplified(str) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('toSimplified',str);\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/播放朗读引擎仅tts源生效\r\n async voice() {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('voice');\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/获取设备唯一id\r\n async getDeviceid() {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('id');\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/获取设备平台 此处返回 windows、macos、ios、ohos、android\r\n async getDevice() {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('device');\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/获取轻悦时光登录用户名,没登录返回为空\r\n async getLoginUser() {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('getLoginUser');\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/输出日志,前台webview请勿使用\r\n \/\/str 为 String\r\n async log(str) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('log',str);\r\n } catch (error) {\r\n return false;\r\n }\r\n }\r\n\r\n \/\/书源调试时可输出 html 代码到前台\r\n \/\/type 0 搜索源码 , 1详情源码 ,2目录源码 ,3正文源码\r\n \/\/str 为 String\r\n \/\/type 为int\r\n async text(type,str) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('text',type,str);\r\n } catch (error) {\r\n return false;\r\n }\r\n }\r\n\r\n \/\/toast弹窗,显示3秒\r\n \/\/str 为 String\r\n async showToast(str) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('showToast',str);\r\n } catch (error) {\r\n return false;\r\n }\r\n }\r\n\r\n \/\/长toast弹窗,显示10秒\r\n \/\/str 为 String\r\n async showLongToast(str) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('showLongToast',str);\r\n } catch (error) {\r\n return false;\r\n }\r\n }\r\n\r\n \/\/webview 里禁止使用,webview请使用js获取ua (navigator.userAgent)\r\n \/\/获取默认ua\r\n async getWebViewUA() {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('getWebViewUA');\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/通过url打开外部应用\r\n \/\/url 为 String\r\n async openurl(url) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('openurl',url,\"\");\r\n } catch (error) {\r\n return false;\r\n }\r\n }\r\n\r\n \/\/通过url打开外部应用并附带mimeType\r\n \/\/url 为 String\r\n \/\/mimeType 为 String\r\n async openurlwithMimeType(url,mimeType) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('openurl',url,mimeType);\r\n } catch (error) {\r\n return false;\r\n }\r\n }\r\n\r\n \/**\r\n * 使用webView访问网络\r\n * @param html 直接用webView载入的html, 如果html为空直接访问url\r\n * @param url html内如果有相对路径的资源不传入url访问不了\r\n * @param js 用来取返回值的js语句, 没有就返回整个源代码\r\n * @param body 当参数不为空的时候,会以post请求,此时请务必在 header 中带上content-type\r\n * @param header 请求的header头,此参数必须是json字符串\r\n * @return 返回js获取的内容\r\n *\/\r\n async webview(url,js,html,body,header) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('webview',url,js,html,body,header,\"\",\"\");\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/**\r\n * overrideUrlRegex 为正则表达式\r\n * 使用方法和上面的一样\r\n * 但返回的内容为正则到的内容,如果无法正则到则返回 js 获取的内容,如果 js 为空则返回页面 html\r\n *\/\r\n async webViewGetOverrideUrl(url,js,html,body,header,overrideUrlRegex) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('webview',url,js,html,body,header,overrideUrlRegex,\"\");\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/**\r\n * 使用webView获取资源url\r\n * urlregex 为正则表达式\r\n * 使用方法和上面的一样\r\n * 但返回的内容为正则到的内容,如果无法正则到则返回 js 获取的内容,如果 js 为空则返回页面 html\r\n *\/\r\n async webViewGetSource(url,js,html,body,header,urlregex) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('webview',url,js,html,body,header,\"\",urlregex);\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/**\r\n * 使用webView拦截 ajax\r\n * ajaxregex 为正则表达式,通过 ajax 匹配 path\r\n * 匹配成功返回 ajax 的结果 失败返回 html\r\n *\/\r\n async webViewGetAjax(url,html,body,header,ajaxregex) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('webviewajax',url,html,body,header,ajaxregex);\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/**\r\n * 启动前台 webview 访问链接并获取结束时的 html,可用于手工过盾\r\n * @param url 网址\r\n * @param title 标题\r\n * @param header 请求的header头,此参数必须是json字符串\r\n * @return 返回网页的内容\r\n *\/\r\n async startBrowser(url,title,header) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('startBrowser',url,title,header);\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/**\r\n * 启动前台 webview 并对每次打开的 url 进行拦截\r\n * @param url 网址\r\n * @param title 标题\r\n * @param header 请求的header头,此参数必须是json字符串\r\n *\/\r\n async startBrowserWithShouldOverrideUrlLoading(url,title,header) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('startBrowserWithShouldOverrideUrlLoading',url,title,header);\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/专门为段评设置的半屏显示,不返回任何东西\r\n async startBrowserDp(url,title) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('startBrowserDp',url,title);\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/专门为段评设置的半屏显示,与startBrowserDp这个还需要提交html参数已加速访问,不返回任何东西\r\n async startBrowserDpwithHtml(url,html,title) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('startBrowserDpwithHtml',url,html,title);\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/仅前台webview可以使用,返回按钮,返回上一个页面\r\n async back() {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('back');\r\n } catch (error) {\r\n return false;\r\n }\r\n }\r\n\r\n \/\/将 utf8字符串转到 gbk 并 url 编码\r\n async utf8ToGbkUrlEncoded(str) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('utf8ToGbkUrlEncoded',str);\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/*\r\n * @param str为图片链接\r\n * @param header 请求的header头,此参数必须是json字符串\r\n * 此函数是让用户输入图片中的验证码,当链接为空则直接让用户输入验证码\r\n *\/\r\n async getVerificationCode(str,header) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('getVerificationCode',str,header);\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/提交内容bookUrl,我会调用书源 info 函数来获取这本书的信息\r\n async addbook(bookUrl) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('addbook',bookUrl);\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/打开搜索页并用当前源搜索\r\n async searchbook(key) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('searchbook',key);\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/获取书本当前阅读章节index\r\n async getdurChapterIndex(bookUrl) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('getdurChapterIndex',bookUrl);\r\n } catch (error) {\r\n return 0;\r\n }\r\n }\r\n\r\n \/\/这里会返回 book 类或者空 ,如果正在阅读的书本不是当前书源或者没有阅读书本则返回空\r\n async getReadBook() {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('getReadBook');\r\n } catch (error) {\r\n return null;\r\n }\r\n }\r\n\r\n \/\/utf8 字符串转base64\r\n async base64encode(str) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('base64encode',str);\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n\r\n \/\/base64 转utf8字符串\r\n async base64decode(str) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('base64decode',str);\r\n } catch (error) {\r\n return \"\";\r\n }\r\n }\r\n }\r\n\r\n \/\/webview下isCookieJar必定true 会自动处理cookie\r\n \/\/以下提交的url,headers,body 都必须为字符串,headers必须为json字符串\r\n \/\/当followRedirects 为 false 时不处理重定向,当为 true 时会自动处理重定向 ,如不明白用途直接用 true 最佳\r\n \/\/ 以下所有参数除当followRedirects外均为 String\r\n \/\/ 如果需要使用http2协议 请在url 前添加 http2:\/\/ ,例如 http2:\/\/baidu.com\r\n \/\/ 如果https一直被盾拦截 ,可以使用https2协议\r\n class Http {\r\n constructor() {\r\n \/*\r\n * 速率限制配置\r\n * requestTimestamps: 存储请求时间戳的数组\r\n * rateLimit: 速率限制,单位时间内最大请求数\r\n * rateLimitWindow: 速率限制窗口,单位毫秒\r\n *\/\r\n this.open = false; \/\/ 是否开启速率限制\r\n this.requestTimestamps = []; \/\/ 存储请求时间戳的数组\r\n this.rateLimit = 5; \/\/ 速率限制,1000毫秒内最多5次请求\r\n this.rateLimitWindow = 1000; \/\/ 速率限制窗口,1000毫秒\r\n }\r\n\r\n \/*\r\n * 检查速率限制\r\n * 实现方法:\r\n * 1. 获取当前时间戳\r\n * 2. 过滤掉超出时间窗口的时间戳\r\n * 3. 检查是否超过速率限制\r\n * 4. 如果超过限制,计算需要等待的时间并等待\r\n * 5. 递归检查速率限制\r\n * 6. 将当前时间戳添加到数组中\r\n *\/\r\n async checkRateLimit() {\r\n if(!this.open) return;\r\n const now = Date.now();\r\n \/\/ 过滤掉超出时间窗口的时间戳\r\n this.requestTimestamps = this.requestTimestamps.filter(timestamp => now - timestamp < this.rateLimitWindow);\r\n \/\/ 检查是否超过速率限制\r\n if (this.requestTimestamps.length >= this.rateLimit) {\r\n \/\/ 计算需要等待的时间\r\n const oldestTimestamp = this.requestTimestamps[0];\r\n const waitTime = this.rateLimitWindow - (now - oldestTimestamp);\r\n \/\/ 等待到速率限制可用\r\n await new Promise(resolve => setTimeout(resolve, waitTime));\r\n \/\/ 递归检查速率限制\r\n return this.checkRateLimit();\r\n }\r\n \/\/ 将当前时间戳添加到数组中\r\n this.requestTimestamps.push(now);\r\n }\r\n\r\n \/*\r\n * 通用返回字段\r\n * method post get 或者 head\r\n * body 请求返回后的字节的 base64\r\n * headers map<String,List<String>> 可通过headers[\"\"]来或者\r\n * statusCode 状态码\r\n * statusMessage\r\n * data 返回后的字节 格式化后的内容\r\n *\/\r\n \/\/ headers 传入 Object,内部自动 JSON.stringify,调用方无需手动转字符串\r\n async Get(url,headers,followRedirects) {\r\n try {\r\n await this.checkRateLimit();\r\n return await window.flutter_inappwebview.callHandler('http',\"get\",url,\"\",JSON.stringify(headers),followRedirects,\"\");\r\n } catch (error) {\r\n return null;\r\n }\r\n }\r\n\r\n async Head(url,headers,followRedirects) {\r\n try {\r\n await this.checkRateLimit();\r\n return await window.flutter_inappwebview.callHandler('http',\"head\",url,\"\",JSON.stringify(headers),followRedirects,\"\");\r\n } catch (error) {\r\n return null;\r\n }\r\n }\r\n\r\n async Post(url,headers,body,contenttype,followRedirects) {\r\n try {\r\n await this.checkRateLimit();\r\n return await window.flutter_inappwebview.callHandler('http',\"post\",url,body,JSON.stringify(headers),followRedirects,contenttype);\r\n } catch (error) {\r\n return null;\r\n }\r\n }\r\n }\r\n\r\n class Cache {\r\n constructor() {}\r\n async get(key) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('cache.get',key);\r\n } catch (error) {\r\n return null;\r\n }\r\n }\r\n\r\n async set(key,value) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('cache.set',key,value);\r\n } catch (error) {\r\n return null;\r\n }\r\n }\r\n\r\n async remove(key) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('cache.remove',key);\r\n } catch (error) {\r\n return null;\r\n }\r\n }\r\n\r\n \/\/以下3个函数获取的cache是通用cache,所有书源用同一个key获取的都一样,上面的是独立cache\r\n async allget(key) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('cache.allget',key);\r\n } catch (error) {\r\n return null;\r\n }\r\n }\r\n\r\n async allset(key,value) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('cache.allset',key,value);\r\n } catch (error) {\r\n return null;\r\n }\r\n }\r\n\r\n async allremove(key) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('cache.allremove',key);\r\n } catch (error) {\r\n return null;\r\n }\r\n }\r\n\r\n \/\/如果登录为弹窗格式的,里面输入框输入的内容可以通过这个函数获取,默认返回的json格式或者为空,需要自行转换\r\n async getLoginInfo(){\r\n return await this.get(\"LoginInfo\")\r\n }\r\n\r\n \/\/将修改后的弹窗输入内容报错 ,必须 JSON.stringify,不然会出错\r\n async putLoginInfo(info){\r\n return await this.set(\"LoginInfo\",info)\r\n }\r\n\r\n \/\/获取书本变量\r\n async getbookVariable(bookurl){\r\n return await this.get(bookurl)\r\n }\r\n\r\n \/\/写入书本变量\r\n async setbookVariable(bookurl,value){\r\n return await this.set(bookurl,value)\r\n }\r\n }\r\n\r\n class Cookie {\r\n constructor() {}\r\n\r\n \/\/通过url获取当前url的所有cookie\r\n async get(url) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('cookie.get',url);\r\n } catch (error) {\r\n return null;\r\n }\r\n }\r\n\r\n \/\/通过url删除当前url的所有cookie\r\n async remove(url) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('cookie.remove',url);\r\n } catch (error) {\r\n return null;\r\n }\r\n }\r\n\r\n \/\/通过url保存当前url的所有cookie\r\n async set(url,value) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('cookie.set',url,value);\r\n } catch (error) {\r\n return null;\r\n }\r\n }\r\n\r\n \/\/设置单独一个cookie\r\n async setCookie(url,key,value) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('cookie.setcookie',url,key,value);\r\n } catch (error) {\r\n return null;\r\n }\r\n }\r\n\r\n \/\/通过 url 获取单个 cookie 的值\r\n async getCookie(url,value) {\r\n try {\r\n return await window.flutter_inappwebview.callHandler('cookie.getCookie',url,value);\r\n } catch (error) {\r\n return null;\r\n }\r\n }\r\n }\r\n\r\n \/\/安全的创建一个 div 解析 html\r\n function parseHTMLSafely(htmlStr) {\r\n try {\r\n \/\/ 在函数作用域内创建独立的临时容器\r\n \/\/ 每个调用创建新的jQuery对象,互不影响\r\n var tempDiv = document.createElement('div');\r\n tempDiv.innerHTML = htmlStr;\r\n return $(tempDiv);\r\n } catch (e) {\r\n flutterBridge.log(\"HTML解析错误:\"+e.message);\r\n return $('<div>');\r\n }\r\n }\r\n\r\n \/\/parseHTMLSafely 创建的用完后必须删除,兼容 jQuery 对象(内部通过 [0] 解引用)\r\n function removeHTMLSafely(tempContainer) {\r\n try {\r\n if (tempContainer[0]) { tempContainer = tempContainer[0]; }\r\n tempContainer.innerHTML = '';\r\n if (tempContainer.parentNode) {\r\n tempContainer.parentNode.removeChild(tempContainer);\r\n }\r\n } catch (e) {\r\n flutterBridge.log(\"HTML移除失败:\"+e.message);\r\n }\r\n }\r\n\r\n \/\/移除 css js,创建parseHTMLSafely前如果用不上 cssjs 建议移除\r\n function removeHTMLTags(htmlString) {\r\n \/\/ 移除script标签\r\n let result = htmlString.replace(\/<script\\b[^<]*(?:(?!<\\\/script>)<[^<]*)*<\\\/script>\/gi, '');\r\n \/\/ 移除style标签\r\n result = result.replace(\/<style\\b[^<]*(?:(?!<\\\/style>)<[^<]*)*<\\\/style>\/gi, '');\r\n \/\/ 移除link标签\r\n result = result.replace(\/<link\\b[^<]*(?:(?!<\\\/link>)<[^<]*)*<\\\/link>\/gi, '');\r\n return result;\r\n }\r\n\r\n\r\n<\/script>\r\n\r\n<script>\r\nvar NobleCiphers=(()=>{var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from===\"object\"||typeof from===\"function\"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toCommonJS=mod=>__copyProps(__defProp({},\"__esModule\",{value:true}),mod);var bundle_entry_exports={};__export(bundle_entry_exports,{bytesToHex:()=>bytesToHex,bytesToUtf8:()=>bytesToUtf8,concatBytes:()=>concatBytes,gcm:()=>gcm,hexToBytes:()=>hexToBytes,utf8ToBytes:()=>utf8ToBytes,xchacha20poly1305:()=>xchacha20poly1305});function isBytes(a){return a instanceof Uint8Array||ArrayBuffer.isView(a)&&a.constructor.name===\"Uint8Array\"&&\"BYTES_PER_ELEMENT\"in a&&a.BYTES_PER_ELEMENT===1}function abool(b){if(typeof b!==\"boolean\")throw new TypeError(`boolean expected, not ${b}`)}function anumber(n){if(typeof n!==\"number\")throw new TypeError(\"number expected, got \"+typeof n);if(!Number.isSafeInteger(n)||n<0)throw new RangeError(\"positive integer expected, got \"+n)}function abytes(value,length,title=\"\"){const bytes=isBytes(value);const len=value?.length;const needsLen=length!==void 0;if(!bytes||needsLen&&len!==length){const prefix=title&&`\"${title}\" `;const ofLen=needsLen?` of length ${length}`:\"\";const got=bytes?`length=${len}`:`type=${typeof value}`;const message=prefix+\"expected Uint8Array\"+ofLen+\", got \"+got;if(!bytes)throw new TypeError(message);throw new RangeError(message)}return value}function aexists(instance,checkFinished=true){if(instance.destroyed)throw new Error(\"Hash instance has been destroyed\");if(checkFinished&&instance.finished)throw new Error(\"Hash#digest() has already been called\")}function aoutput(out,instance,onlyAligned=false){abytes(out,void 0,\"output\");const min=instance.outputLen;if(out.length<min){throw new RangeError(\"digestInto() expects output buffer of length at least \"+min)}if(onlyAligned&&!isAligned32(out))throw new Error(\"invalid output, must be aligned\")}function u8(arr){return new Uint8Array(arr.buffer,arr.byteOffset,arr.byteLength)}function u32(arr){return new Uint32Array(arr.buffer,arr.byteOffset,Math.floor(arr.byteLength\/4))}function clean(...arrays){for(let i=0;i<arrays.length;i++){arrays[i].fill(0)}}function createView(arr){return new DataView(arr.buffer,arr.byteOffset,arr.byteLength)}var isLE=(()=>new Uint8Array(new Uint32Array([287454020]).buffer)[0]===68)();var byteSwap=word=>word<<24&4278190080|word<<8&16711680|word>>>8&65280|word>>>24&255;var swap8IfBE=isLE?n=>n:n=>byteSwap(n)>>>0;var byteSwap32=arr=>{for(let i=0;i<arr.length;i++)arr[i]=byteSwap(arr[i]);return arr};var swap32IfBE=isLE?u=>u:byteSwap32;var hasHexBuiltin=(()=>typeof Uint8Array.from([]).toHex===\"function\"&&typeof Uint8Array.fromHex===\"function\")();var hexes=Array.from({length:256},(_,i)=>i.toString(16).padStart(2,\"0\"));function bytesToHex(bytes){abytes(bytes);if(hasHexBuiltin)return bytes.toHex();let hex=\"\";for(let i=0;i<bytes.length;i++){hex+=hexes[bytes[i]]}return hex}var asciis={_0:48,_9:57,A:65,F:70,a:97,f:102};function asciiToBase16(ch){if(ch>=asciis._0&&ch<=asciis._9)return ch-asciis._0;if(ch>=asciis.A&&ch<=asciis.F)return ch-(asciis.A-10);if(ch>=asciis.a&&ch<=asciis.f)return ch-(asciis.a-10);return}function hexToBytes(hex){if(typeof hex!==\"string\")throw new TypeError(\"hex string expected, got \"+typeof hex);if(hasHexBuiltin){try{return Uint8Array.fromHex(hex)}catch(error){if(error instanceof SyntaxError)throw new RangeError(error.message);throw error}}const hl=hex.length;const al=hl\/2;if(hl%2)throw new RangeError(\"hex string expected, got unpadded hex of length \"+hl);const array=new Uint8Array(al);for(let ai=0,hi=0;ai<al;ai++,hi+=2){const n1=asciiToBase16(hex.charCodeAt(hi));const n2=asciiToBase16(hex.charCodeAt(hi+1));if(n1===void 0||n2===void 0){const char=hex[hi]+hex[hi+1];throw new RangeError('hex string expected, got non-hex character \"'+char+'\" at index '+hi)}array[ai]=n1*16+n2}return array}function utf8ToBytes(str){if(typeof str!==\"string\")throw new TypeError(\"string expected\");return new Uint8Array(new TextEncoder().encode(str))}function bytesToUtf8(bytes){return new TextDecoder().decode(bytes)}function concatBytes(...arrays){let sum=0;for(let i=0;i<arrays.length;i++){const a=arrays[i];abytes(a);sum+=a.length}const res=new Uint8Array(sum);for(let i=0,pad=0;i<arrays.length;i++){const a=arrays[i];res.set(a,pad);pad+=a.length}return res}function checkOpts(defaults,opts){if(opts==null||typeof opts!==\"object\")throw new Error(\"options must be defined\");const merged=Object.assign(defaults,opts);return merged}function equalBytes(a,b){if(a.length!==b.length)return false;let diff=0;for(let i=0;i<a.length;i++)diff|=a[i]^b[i];return diff===0}function wrapMacConstructor(keyLen,macCons,fromMsg){const mac=macCons;const getArgs=fromMsg||(()=>[]);const macC=(msg,key)=>mac(key,...getArgs(msg)).update(msg).digest();const tmp=mac(new Uint8Array(keyLen),...getArgs(new Uint8Array(0)));macC.outputLen=tmp.outputLen;macC.blockLen=tmp.blockLen;macC.create=(key,...args)=>mac(key,...args);return macC}var wrapCipher=(params,constructor)=>{function wrappedCipher(key,...args){abytes(key,void 0,\"key\");if(params.nonceLength!==void 0){const nonce=args[0];abytes(nonce,params.varSizeNonce?void 0:params.nonceLength,\"nonce\")}const tagl=params.tagLength;if(tagl&&args[1]!==void 0)abytes(args[1],void 0,\"AAD\");const cipher=constructor(key,...args);const checkOutput=(fnLength,output)=>{if(output!==void 0){if(fnLength!==2)throw new Error(\"cipher output not supported\");abytes(output,void 0,\"output\")}};let called=false;const wrCipher={encrypt(data,output){if(called)throw new Error(\"cannot encrypt() twice with same key + nonce\");called=true;abytes(data);checkOutput(cipher.encrypt.length,output);return cipher.encrypt(data,output)},decrypt(data,output){abytes(data);if(tagl&&data.length<tagl)throw new Error('\"ciphertext\" expected length bigger than tagLength='+tagl);checkOutput(cipher.decrypt.length,output);return cipher.decrypt(data,output)}};return wrCipher}Object.assign(wrappedCipher,params);return wrappedCipher};function getOutput(expectedLength,out,onlyAligned=true){if(out===void 0)return new Uint8Array(expectedLength);abytes(out,void 0,\"output\");if(out.length!==expectedLength)throw new Error('\"output\" expected Uint8Array of length '+expectedLength+\", got: \"+out.length);if(onlyAligned&&!isAligned32(out))throw new Error(\"invalid output, must be aligned\");return out}function u64Lengths(dataLength,aadLength,isLE2){anumber(dataLength);anumber(aadLength);abool(isLE2);const num=new Uint8Array(16);const view=createView(num);view.setBigUint64(0,BigInt(aadLength),isLE2);view.setBigUint64(8,BigInt(dataLength),isLE2);return num}function isAligned32(bytes){return bytes.byteOffset%4===0}function copyBytes(bytes){return Uint8Array.from(abytes(bytes))}var encodeStr=str=>Uint8Array.from(str.split(\"\"),c=>c.charCodeAt(0));var sigma16_32=(()=>swap32IfBE(u32(encodeStr(\"expand 16-byte k\"))))();var sigma32_32=(()=>swap32IfBE(u32(encodeStr(\"expand 32-byte k\"))))();function rotl(a,b){return a<<b|a>>>32-b}var BLOCK_LEN=64;var BLOCK_LEN32=16;var MAX_COUNTER=(()=>2**32-1)();var U32_EMPTY=Uint32Array.of();function runCipher(core,sigma,key,nonce,data,output,counter,rounds){const len=data.length;const block=new Uint8Array(BLOCK_LEN);const b32=u32(block);const isAligned=isLE&&isAligned32(data)&&isAligned32(output);const d32=isAligned?u32(data):U32_EMPTY;const o32=isAligned?u32(output):U32_EMPTY;if(!isLE){for(let pos=0;pos<len;counter++){core(sigma,key,nonce,b32,counter,rounds);swap32IfBE(b32);if(counter>=MAX_COUNTER)throw new Error(\"arx: counter overflow\");const take=Math.min(BLOCK_LEN,len-pos);for(let j=0,posj;j<take;j++){posj=pos+j;output[posj]=data[posj]^block[j]}pos+=take}return}for(let pos=0;pos<len;counter++){core(sigma,key,nonce,b32,counter,rounds);if(counter>=MAX_COUNTER)throw new Error(\"arx: counter overflow\");const take=Math.min(BLOCK_LEN,len-pos);if(isAligned&&take===BLOCK_LEN){const pos32=pos\/4;if(pos%4!==0)throw new Error(\"arx: invalid block position\");for(let j=0,posj;j<BLOCK_LEN32;j++){posj=pos32+j;o32[posj]=d32[posj]^b32[j]}pos+=BLOCK_LEN;continue}for(let j=0,posj;j<take;j++){posj=pos+j;output[posj]=data[posj]^block[j]}pos+=take}}function createCipher(core,opts){const{allowShortKeys,extendNonceFn,counterLength,counterRight,rounds}=checkOpts({allowShortKeys:false,counterLength:8,counterRight:false,rounds:20},opts);if(typeof core!==\"function\")throw new Error(\"core must be a function\");anumber(counterLength);anumber(rounds);abool(counterRight);abool(allowShortKeys);return(key,nonce,data,output,counter=0)=>{abytes(key,void 0,\"key\");abytes(nonce,void 0,\"nonce\");abytes(data,void 0,\"data\");const len=data.length;output=getOutput(len,output,false);anumber(counter);if(counter<0||counter>=MAX_COUNTER)throw new Error(\"arx: counter overflow\");const toClean=[];let l=key.length;let k;let sigma;if(l===32){toClean.push(k=copyBytes(key));sigma=sigma32_32}else if(l===16&&allowShortKeys){k=new Uint8Array(32);k.set(key);k.set(key,16);sigma=sigma16_32;toClean.push(k)}else{abytes(key,32,\"arx key\");throw new Error(\"invalid key size\")}if(!isLE||!isAligned32(nonce))toClean.push(nonce=copyBytes(nonce));let k32=u32(k);if(extendNonceFn){if(nonce.length!==24)throw new Error(`arx: extended nonce must be 24 bytes`);const n16=nonce.subarray(0,16);if(isLE)extendNonceFn(sigma,k32,u32(n16),k32);else{const sigmaRaw=swap32IfBE(Uint32Array.from(sigma));extendNonceFn(sigmaRaw,k32,u32(n16),k32);clean(sigmaRaw);swap32IfBE(k32)}nonce=nonce.subarray(16)}else if(!isLE)swap32IfBE(k32);const nonceNcLen=16-counterLength;if(nonceNcLen!==nonce.length)throw new Error(`arx: nonce must be ${nonceNcLen} or 16 bytes`);if(nonceNcLen!==12){const nc=new Uint8Array(12);nc.set(nonce,counterRight?0:12-nonce.length);nonce=nc;toClean.push(nonce)}const n32=swap32IfBE(u32(nonce));try{runCipher(core,sigma,k32,n32,data,output,counter,rounds);return output}finally{clean(...toClean)}}}function u8to16(a,i){return a[i++]&255|(a[i++]&255)<<8}var Poly1305=class{blockLen=16;outputLen=16;buffer=new Uint8Array(16);r=new Uint16Array(10);h=new Uint16Array(10);pad=new Uint16Array(8);pos=0;finished=false;destroyed=false;constructor(key){key=copyBytes(abytes(key,32,\"key\"));const t0=u8to16(key,0);const t1=u8to16(key,2);const t2=u8to16(key,4);const t3=u8to16(key,6);const t4=u8to16(key,8);const t5=u8to16(key,10);const t6=u8to16(key,12);const t7=u8to16(key,14);this.r[0]=t0&8191;this.r[1]=(t0>>>13|t1<<3)&8191;this.r[2]=(t1>>>10|t2<<6)&7939;this.r[3]=(t2>>>7|t3<<9)&8191;this.r[4]=(t3>>>4|t4<<12)&255;this.r[5]=t4>>>1&8190;this.r[6]=(t4>>>14|t5<<2)&8191;this.r[7]=(t5>>>11|t6<<5)&8065;this.r[8]=(t6>>>8|t7<<8)&8191;this.r[9]=t7>>>5&127;for(let i=0;i<8;i++)this.pad[i]=u8to16(key,16+2*i)}process(data,offset,isLast=false){const hibit=isLast?0:1<<11;const{h,r}=this;const r0=r[0];const r1=r[1];const r2=r[2];const r3=r[3];const r4=r[4];const r5=r[5];const r6=r[6];const r7=r[7];const r8=r[8];const r9=r[9];const t0=u8to16(data,offset+0);const t1=u8to16(data,offset+2);const t2=u8to16(data,offset+4);const t3=u8to16(data,offset+6);const t4=u8to16(data,offset+8);const t5=u8to16(data,offset+10);const t6=u8to16(data,offset+12);const t7=u8to16(data,offset+14);let h0=h[0]+(t0&8191);let h1=h[1]+((t0>>>13|t1<<3)&8191);let h2=h[2]+((t1>>>10|t2<<6)&8191);let h3=h[3]+((t2>>>7|t3<<9)&8191);let h4=h[4]+((t3>>>4|t4<<12)&8191);let h5=h[5]+(t4>>>1&8191);let h6=h[6]+((t4>>>14|t5<<2)&8191);let h7=h[7]+((t5>>>11|t6<<5)&8191);let h8=h[8]+((t6>>>8|t7<<8)&8191);let h9=h[9]+(t7>>>5|hibit);let c=0;let d0=c+h0*r0+h1*(5*r9)+h2*(5*r8)+h3*(5*r7)+h4*(5*r6);c=d0>>>13;d0&=8191;d0+=h5*(5*r5)+h6*(5*r4)+h7*(5*r3)+h8*(5*r2)+h9*(5*r1);c+=d0>>>13;d0&=8191;let d1=c+h0*r1+h1*r0+h2*(5*r9)+h3*(5*r8)+h4*(5*r7);c=d1>>>13;d1&=8191;d1+=h5*(5*r6)+h6*(5*r5)+h7*(5*r4)+h8*(5*r3)+h9*(5*r2);c+=d1>>>13;d1&=8191;let d2=c+h0*r2+h1*r1+h2*r0+h3*(5*r9)+h4*(5*r8);c=d2>>>13;d2&=8191;d2+=h5*(5*r7)+h6*(5*r6)+h7*(5*r5)+h8*(5*r4)+h9*(5*r3);c+=d2>>>13;d2&=8191;let d3=c+h0*r3+h1*r2+h2*r1+h3*r0+h4*(5*r9);c=d3>>>13;d3&=8191;d3+=h5*(5*r8)+h6*(5*r7)+h7*(5*r6)+h8*(5*r5)+h9*(5*r4);c+=d3>>>13;d3&=8191;let d4=c+h0*r4+h1*r3+h2*r2+h3*r1+h4*r0;c=d4>>>13;d4&=8191;d4+=h5*(5*r9)+h6*(5*r8)+h7*(5*r7)+h8*(5*r6)+h9*(5*r5);c+=d4>>>13;d4&=8191;let d5=c+h0*r5+h1*r4+h2*r3+h3*r2+h4*r1;c=d5>>>13;d5&=8191;d5+=h5*r0+h6*(5*r9)+h7*(5*r8)+h8*(5*r7)+h9*(5*r6);c+=d5>>>13;d5&=8191;let d6=c+h0*r6+h1*r5+h2*r4+h3*r3+h4*r2;c=d6>>>13;d6&=8191;d6+=h5*r1+h6*r0+h7*(5*r9)+h8*(5*r8)+h9*(5*r7);c+=d6>>>13;d6&=8191;let d7=c+h0*r7+h1*r6+h2*r5+h3*r4+h4*r3;c=d7>>>13;d7&=8191;d7+=h5*r2+h6*r1+h7*r0+h8*(5*r9)+h9*(5*r8);c+=d7>>>13;d7&=8191;let d8=c+h0*r8+h1*r7+h2*r6+h3*r5+h4*r4;c=d8>>>13;d8&=8191;d8+=h5*r3+h6*r2+h7*r1+h8*r0+h9*(5*r9);c+=d8>>>13;d8&=8191;let d9=c+h0*r9+h1*r8+h2*r7+h3*r6+h4*r5;c=d9>>>13;d9&=8191;d9+=h5*r4+h6*r3+h7*r2+h8*r1+h9*r0;c+=d9>>>13;d9&=8191;c=(c<<2)+c|0;c=c+d0|0;d0=c&8191;c=c>>>13;d1+=c;h[0]=d0;h[1]=d1;h[2]=d2;h[3]=d3;h[4]=d4;h[5]=d5;h[6]=d6;h[7]=d7;h[8]=d8;h[9]=d9}finalize(){const{h,pad}=this;const g=new Uint16Array(10);let c=h[1]>>>13;h[1]&=8191;for(let i=2;i<10;i++){h[i]+=c;c=h[i]>>>13;h[i]&=8191}h[0]+=c*5;c=h[0]>>>13;h[0]&=8191;h[1]+=c;c=h[1]>>>13;h[1]&=8191;h[2]+=c;g[0]=h[0]+5;c=g[0]>>>13;g[0]&=8191;for(let i=1;i<10;i++){g[i]=h[i]+c;c=g[i]>>>13;g[i]&=8191}g[9]-=1<<13;let mask=(c^1)-1;for(let i=0;i<10;i++)g[i]&=mask;mask=~mask;for(let i=0;i<10;i++)h[i]=h[i]&mask|g[i];h[0]=(h[0]|h[1]<<13)&65535;h[1]=(h[1]>>>3|h[2]<<10)&65535;h[2]=(h[2]>>>6|h[3]<<7)&65535;h[3]=(h[3]>>>9|h[4]<<4)&65535;h[4]=(h[4]>>>12|h[5]<<1|h[6]<<14)&65535;h[5]=(h[6]>>>2|h[7]<<11)&65535;h[6]=(h[7]>>>5|h[8]<<8)&65535;h[7]=(h[8]>>>8|h[9]<<5)&65535;let f=h[0]+pad[0];h[0]=f&65535;for(let i=1;i<8;i++){f=(h[i]+pad[i]|0)+(f>>>16)|0;h[i]=f&65535}clean(g)}update(data){aexists(this);abytes(data);data=copyBytes(data);const{buffer,blockLen}=this;const len=data.length;for(let pos=0;pos<len;){const take=Math.min(blockLen-this.pos,len-pos);if(take===blockLen){for(;blockLen<=len-pos;pos+=blockLen)this.process(data,pos);continue}buffer.set(data.subarray(pos,pos+take),this.pos);this.pos+=take;pos+=take;if(this.pos===blockLen){this.process(buffer,0,false);this.pos=0}}return this}destroy(){this.destroyed=true;clean(this.h,this.r,this.buffer,this.pad)}digestInto(out){aexists(this);aoutput(out,this);this.finished=true;const{buffer,h}=this;let{pos}=this;if(pos){buffer[pos++]=1;for(;pos<16;pos++)buffer[pos]=0;this.process(buffer,0,true)}this.finalize();let opos=0;for(let i=0;i<8;i++){out[opos++]=h[i]>>>0;out[opos++]=h[i]>>>8}}digest(){const{buffer,outputLen}=this;this.digestInto(buffer);const res=buffer.slice(0,outputLen);this.destroy();return res}};var poly1305=wrapMacConstructor(32,key=>new Poly1305(key));function chachaCore(s,k,n,out,cnt,rounds=20){let y00=s[0],y01=s[1],y02=s[2],y03=s[3],y04=k[0],y05=k[1],y06=k[2],y07=k[3],y08=k[4],y09=k[5],y10=k[6],y11=k[7],y12=cnt,y13=n[0],y14=n[1],y15=n[2];let x00=y00,x01=y01,x02=y02,x03=y03,x04=y04,x05=y05,x06=y06,x07=y07,x08=y08,x09=y09,x10=y10,x11=y11,x12=y12,x13=y13,x14=y14,x15=y15;for(let r=0;r<rounds;r+=2){x00=x00+x04|0;x12=rotl(x12^x00,16);x08=x08+x12|0;x04=rotl(x04^x08,12);x00=x00+x04|0;x12=rotl(x12^x00,8);x08=x08+x12|0;x04=rotl(x04^x08,7);x01=x01+x05|0;x13=rotl(x13^x01,16);x09=x09+x13|0;x05=rotl(x05^x09,12);x01=x01+x05|0;x13=rotl(x13^x01,8);x09=x09+x13|0;x05=rotl(x05^x09,7);x02=x02+x06|0;x14=rotl(x14^x02,16);x10=x10+x14|0;x06=rotl(x06^x10,12);x02=x02+x06|0;x14=rotl(x14^x02,8);x10=x10+x14|0;x06=rotl(x06^x10,7);x03=x03+x07|0;x15=rotl(x15^x03,16);x11=x11+x15|0;x07=rotl(x07^x11,12);x03=x03+x07|0;x15=rotl(x15^x03,8);x11=x11+x15|0;x07=rotl(x07^x11,7);x00=x00+x05|0;x15=rotl(x15^x00,16);x10=x10+x15|0;x05=rotl(x05^x10,12);x00=x00+x05|0;x15=rotl(x15^x00,8);x10=x10+x15|0;x05=rotl(x05^x10,7);x01=x01+x06|0;x12=rotl(x12^x01,16);x11=x11+x12|0;x06=rotl(x06^x11,12);x01=x01+x06|0;x12=rotl(x12^x01,8);x11=x11+x12|0;x06=rotl(x06^x11,7);x02=x02+x07|0;x13=rotl(x13^x02,16);x08=x08+x13|0;x07=rotl(x07^x08,12);x02=x02+x07|0;x13=rotl(x13^x02,8);x08=x08+x13|0;x07=rotl(x07^x08,7);x03=x03+x04|0;x14=rotl(x14^x03,16);x09=x09+x14|0;x04=rotl(x04^x09,12);x03=x03+x04|0;x14=rotl(x14^x03,8);x09=x09+x14|0;x04=rotl(x04^x09,7)}let oi=0;out[oi++]=y00+x00|0;out[oi++]=y01+x01|0;out[oi++]=y02+x02|0;out[oi++]=y03+x03|0;out[oi++]=y04+x04|0;out[oi++]=y05+x05|0;out[oi++]=y06+x06|0;out[oi++]=y07+x07|0;out[oi++]=y08+x08|0;out[oi++]=y09+x09|0;out[oi++]=y10+x10|0;out[oi++]=y11+x11|0;out[oi++]=y12+x12|0;out[oi++]=y13+x13|0;out[oi++]=y14+x14|0;out[oi++]=y15+x15|0}function hchacha(s,k,i,out){let x00=swap8IfBE(s[0]),x01=swap8IfBE(s[1]),x02=swap8IfBE(s[2]),x03=swap8IfBE(s[3]),x04=swap8IfBE(k[0]),x05=swap8IfBE(k[1]),x06=swap8IfBE(k[2]),x07=swap8IfBE(k[3]),x08=swap8IfBE(k[4]),x09=swap8IfBE(k[5]),x10=swap8IfBE(k[6]),x11=swap8IfBE(k[7]),x12=swap8IfBE(i[0]),x13=swap8IfBE(i[1]),x14=swap8IfBE(i[2]),x15=swap8IfBE(i[3]);for(let r=0;r<20;r+=2){x00=x00+x04|0;x12=rotl(x12^x00,16);x08=x08+x12|0;x04=rotl(x04^x08,12);x00=x00+x04|0;x12=rotl(x12^x00,8);x08=x08+x12|0;x04=rotl(x04^x08,7);x01=x01+x05|0;x13=rotl(x13^x01,16);x09=x09+x13|0;x05=rotl(x05^x09,12);x01=x01+x05|0;x13=rotl(x13^x01,8);x09=x09+x13|0;x05=rotl(x05^x09,7);x02=x02+x06|0;x14=rotl(x14^x02,16);x10=x10+x14|0;x06=rotl(x06^x10,12);x02=x02+x06|0;x14=rotl(x14^x02,8);x10=x10+x14|0;x06=rotl(x06^x10,7);x03=x03+x07|0;x15=rotl(x15^x03,16);x11=x11+x15|0;x07=rotl(x07^x11,12);x03=x03+x07|0;x15=rotl(x15^x03,8);x11=x11+x15|0;x07=rotl(x07^x11,7);x00=x00+x05|0;x15=rotl(x15^x00,16);x10=x10+x15|0;x05=rotl(x05^x10,12);x00=x00+x05|0;x15=rotl(x15^x00,8);x10=x10+x15|0;x05=rotl(x05^x10,7);x01=x01+x06|0;x12=rotl(x12^x01,16);x11=x11+x12|0;x06=rotl(x06^x11,12);x01=x01+x06|0;x12=rotl(x12^x01,8);x11=x11+x12|0;x06=rotl(x06^x11,7);x02=x02+x07|0;x13=rotl(x13^x02,16);x08=x08+x13|0;x07=rotl(x07^x08,12);x02=x02+x07|0;x13=rotl(x13^x02,8);x08=x08+x13|0;x07=rotl(x07^x08,7);x03=x03+x04|0;x14=rotl(x14^x03,16);x09=x09+x14|0;x04=rotl(x04^x09,12);x03=x03+x04|0;x14=rotl(x14^x03,8);x09=x09+x14|0;x04=rotl(x04^x09,7)}let oi=0;out[oi++]=x00;out[oi++]=x01;out[oi++]=x02;out[oi++]=x03;out[oi++]=x12;out[oi++]=x13;out[oi++]=x14;out[oi++]=x15;swap32IfBE(out)}var xchacha20=createCipher(chachaCore,{counterRight:false,counterLength:8,extendNonceFn:hchacha,allowShortKeys:false});var ZEROS16=new Uint8Array(16);var updatePadded=(h,msg)=>{h.update(msg);const leftover=msg.length%16;if(leftover)h.update(ZEROS16.subarray(leftover))};var ZEROS32=new Uint8Array(32);function computeTag(fn,key,nonce,ciphertext,AAD){if(AAD!==void 0)abytes(AAD,void 0,\"AAD\");const authKey=fn(key,nonce,ZEROS32);const lengths=u64Lengths(ciphertext.length,AAD?AAD.length:0,true);const h=poly1305.create(authKey);if(AAD)updatePadded(h,AAD);updatePadded(h,ciphertext);h.update(lengths);const res=h.digest();clean(authKey,lengths);return res}var _poly1305_aead=xorStream=>(key,nonce,AAD)=>{const tagLength=16;return{encrypt(plaintext,output){const plength=plaintext.length;output=getOutput(plength+tagLength,output,false);output.set(plaintext);const oPlain=output.subarray(0,-tagLength);xorStream(key,nonce,oPlain,oPlain,1);const tag=computeTag(xorStream,key,nonce,oPlain,AAD);output.set(tag,plength);clean(tag);return output},decrypt(ciphertext,output){output=getOutput(ciphertext.length-tagLength,output,false);const data=ciphertext.subarray(0,-tagLength);const passedTag=ciphertext.subarray(-tagLength);const tag=computeTag(xorStream,key,nonce,data,AAD);if(!equalBytes(passedTag,tag)){clean(tag);throw new Error(\"invalid tag\")}output.set(ciphertext.subarray(0,-tagLength));xorStream(key,nonce,output,output,1);clean(tag);return output}}};var xchacha20poly1305=wrapCipher({blockSize:64,nonceLength:24,tagLength:16},_poly1305_aead(xchacha20));var BLOCK_SIZE=16;var ZEROS162=new Uint8Array(16);var ZEROS322=u32(ZEROS162);var POLY=225;var mul2=(s0,s1,s2,s3)=>{const hiBit=s3&1;return{s3:s2<<31|s3>>>1,s2:s1<<31|s2>>>1,s1:s0<<31|s1>>>1,s0:s0>>>1^POLY<<24&-(hiBit&1)}};var swapLE=n=>(n>>>0&255)<<24|(n>>>8&255)<<16|(n>>>16&255)<<8|n>>>24&255|0;var estimateWindow=bytes=>{if(bytes>64*1024)return 8;if(bytes>1024)return 4;return 2};var GHASH=class{blockLen=BLOCK_SIZE;outputLen=BLOCK_SIZE;s0=0;s1=0;s2=0;s3=0;finished=false;destroyed=false;t;W;windowSize;constructor(key,expectedLength){abytes(key,16,\"key\");key=copyBytes(key);const kView=createView(key);let k0=kView.getUint32(0,false);let k1=kView.getUint32(4,false);let k2=kView.getUint32(8,false);let k3=kView.getUint32(12,false);const doubles=[];for(let i=0;i<128;i++){doubles.push({s0:swapLE(k0),s1:swapLE(k1),s2:swapLE(k2),s3:swapLE(k3)});({s0:k0,s1:k1,s2:k2,s3:k3}=mul2(k0,k1,k2,k3))}const W=estimateWindow(expectedLength||1024);if(![1,2,4,8].includes(W))throw new Error(\"ghash: invalid window size, expected 2, 4 or 8\");this.W=W;const bits=128;const windows=bits\/W;const windowSize=this.windowSize=2**W;const items=[];for(let w=0;w<windows;w++){for(let byte=0;byte<windowSize;byte++){let s0=0,s1=0,s2=0,s3=0;for(let j=0;j<W;j++){const bit=byte>>>W-j-1&1;if(!bit)continue;const{s0:d0,s1:d1,s2:d2,s3:d3}=doubles[W*w+j];s0^=d0,s1^=d1,s2^=d2,s3^=d3}items.push({s0,s1,s2,s3})}}this.t=items}_updateBlock(s0,s1,s2,s3){s0^=this.s0,s1^=this.s1,s2^=this.s2,s3^=this.s3;const{W,t,windowSize}=this;let o0=0,o1=0,o2=0,o3=0;const mask=(1<<W)-1;let w=0;for(const num of[s0,s1,s2,s3]){for(let bytePos=0;bytePos<4;bytePos++){const byte=num>>>8*bytePos&255;for(let bitPos=8\/W-1;bitPos>=0;bitPos--){const bit=byte>>>W*bitPos&mask;const{s0:e0,s1:e1,s2:e2,s3:e3}=t[w*windowSize+bit];o0^=e0,o1^=e1,o2^=e2,o3^=e3;w+=1}}}this.s0=o0;this.s1=o1;this.s2=o2;this.s3=o3}update(data){aexists(this);abytes(data);data=copyBytes(data);const b32=u32(data);const blocks=Math.floor(data.length\/BLOCK_SIZE);const left=data.length%BLOCK_SIZE;for(let i=0;i<blocks;i++){this._updateBlock(swap8IfBE(b32[i*4+0]),swap8IfBE(b32[i*4+1]),swap8IfBE(b32[i*4+2]),swap8IfBE(b32[i*4+3]))}if(left){ZEROS162.set(data.subarray(blocks*BLOCK_SIZE));this._updateBlock(swap8IfBE(ZEROS322[0]),swap8IfBE(ZEROS322[1]),swap8IfBE(ZEROS322[2]),swap8IfBE(ZEROS322[3]));clean(ZEROS322)}return this}destroy(){this.destroyed=true;const{t}=this;for(const elm of t){elm.s0=0,elm.s1=0,elm.s2=0,elm.s3=0}}digestInto(out){aexists(this);aoutput(out,this,true);this.finished=true;const{s0,s1,s2,s3}=this;const o32=u32(out);o32[0]=s0;o32[1]=s1;o32[2]=s2;o32[3]=s3;swap32IfBE(o32)}digest(){const res=new Uint8Array(BLOCK_SIZE);this.digestInto(res);this.destroy();return res}};var ghash=wrapMacConstructor(16,(key,expectedLength)=>new GHASH(key,expectedLength),msg=>[msg.length]);var BLOCK_SIZE2=16;var BLOCK_SIZE32=4;var EMPTY_BLOCK=new Uint8Array(BLOCK_SIZE2);var POLY2=283;function validateKeyLength(key){if(![16,24,32].includes(key.length))throw new Error('\"aes key\" expected Uint8Array of length 16\/24\/32, got length='+key.length)}function mul22(n){return n<<1^POLY2&-(n>>7)}function mul(a,b){let res=0;for(;b>0;b>>=1){res^=a&-(b&1);a=mul22(a)}return res}var sbox=(()=>{const t=new Uint8Array(256);for(let i=0,x=1;i<256;i++,x^=mul22(x))t[i]=x;const box=new Uint8Array(256);box[0]=99;for(let i=0;i<255;i++){let x=t[255-i];x|=x<<8;box[t[i]]=(x^x>>4^x>>5^x>>6^x>>7^99)&255}clean(t);return box})();var rotr32_8=n=>n<<24|n>>>8;var rotl32_8=n=>n<<8|n>>>24;function genTtable(sbox2,fn){if(sbox2.length!==256)throw new Error(\"Wrong sbox length\");const T0=new Uint32Array(256).map((_,j)=>fn(sbox2[j]));const T1=T0.map(rotl32_8);const T2=T1.map(rotl32_8);const T3=T2.map(rotl32_8);const T01=new Uint32Array(256*256);const T23=new Uint32Array(256*256);const sbox22=new Uint16Array(256*256);for(let i=0;i<256;i++){for(let j=0;j<256;j++){const idx=i*256+j;T01[idx]=T0[i]^T1[j];T23[idx]=T2[i]^T3[j];sbox22[idx]=sbox2[i]<<8|sbox2[j]}}return{sbox:sbox2,sbox2:sbox22,T0,T1,T2,T3,T01,T23}}var tableEncoding=genTtable(sbox,s=>mul(s,3)<<24|s<<16|s<<8|mul(s,2));var xPowers=(()=>{const p=new Uint8Array(16);for(let i=0,x=1;i<16;i++,x=mul22(x))p[i]=x;return p})();function expandKeyLE(key){abytes(key);const len=key.length;validateKeyLength(key);const{sbox2}=tableEncoding;const toClean=[];if(!isLE||!isAligned32(key))toClean.push(key=copyBytes(key));const k32=swap32IfBE(u32(key));const Nk=k32.length;const subByte=n=>applySbox(sbox2,n,n,n,n);const xk=new Uint32Array(len+28);xk.set(k32);for(let i=Nk;i<xk.length;i++){let t=xk[i-1];if(i%Nk===0)t=subByte(rotr32_8(t))^xPowers[i\/Nk-1];else if(Nk>6&&i%Nk===4)t=subByte(t);xk[i]=xk[i-Nk]^t}clean(...toClean);return xk}function apply0123(T01,T23,s0,s1,s2,s3){return T01[s0<<8&65280|s1>>>8&255]^T23[s2>>>8&65280|s3>>>24&255]}function applySbox(sbox2,s0,s1,s2,s3){return sbox2[s0&255|s1&65280]|sbox2[s2>>>16&255|s3>>>16&65280]<<16}function encrypt(xk,s0,s1,s2,s3){const{sbox2,T01,T23}=tableEncoding;let k=0;s0^=xk[k++],s1^=xk[k++],s2^=xk[k++],s3^=xk[k++];const rounds=xk.length\/4-2;for(let i=0;i<rounds;i++){const t02=xk[k++]^apply0123(T01,T23,s0,s1,s2,s3);const t12=xk[k++]^apply0123(T01,T23,s1,s2,s3,s0);const t22=xk[k++]^apply0123(T01,T23,s2,s3,s0,s1);const t32=xk[k++]^apply0123(T01,T23,s3,s0,s1,s2);s0=t02,s1=t12,s2=t22,s3=t32}const t0=xk[k++]^applySbox(sbox2,s0,s1,s2,s3);const t1=xk[k++]^applySbox(sbox2,s1,s2,s3,s0);const t2=xk[k++]^applySbox(sbox2,s2,s3,s0,s1);const t3=xk[k++]^applySbox(sbox2,s3,s0,s1,s2);return{s0:t0,s1:t1,s2:t2,s3:t3}}function ctr32(xk,isLE2,nonce,src,dst){abytes(nonce,BLOCK_SIZE2,\"nonce\");abytes(src);dst=getOutput(src.length,dst);const ctr=nonce;const c32=u32(ctr);const view=createView(ctr);const src32=u32(src);const dst32=u32(dst);const ctrPos=isLE2?0:12;const srcLen=src.length;let ctrNum=view.getUint32(ctrPos,isLE2);let{s0,s1,s2,s3}=encrypt(xk,swap8IfBE(c32[0]),swap8IfBE(c32[1]),swap8IfBE(c32[2]),swap8IfBE(c32[3]));for(let i=0;i+4<=src32.length;i+=4){dst32[i+0]=src32[i+0]^swap8IfBE(s0);dst32[i+1]=src32[i+1]^swap8IfBE(s1);dst32[i+2]=src32[i+2]^swap8IfBE(s2);dst32[i+3]=src32[i+3]^swap8IfBE(s3);ctrNum=ctrNum+1>>>0;view.setUint32(ctrPos,ctrNum,isLE2);({s0,s1,s2,s3}=encrypt(xk,swap8IfBE(c32[0]),swap8IfBE(c32[1]),swap8IfBE(c32[2]),swap8IfBE(c32[3])))}const start=BLOCK_SIZE2*Math.floor(src32.length\/BLOCK_SIZE32);if(start<srcLen){const b32=new Uint32Array([s0,s1,s2,s3]);swap32IfBE(b32);const buf=u8(b32);for(let i=start,pos=0;i<srcLen;i++,pos++)dst[i]=src[i]^buf[pos];clean(b32)}return dst}function computeTag2(fn,isLE2,key,data,AAD){const aadLength=AAD?AAD.length:0;const h=fn.create(key,data.length+aadLength);if(AAD)h.update(AAD);const num=u64Lengths(8*data.length,8*aadLength,isLE2);h.update(data);h.update(num);const res=h.digest();clean(num);return res}var gcm=wrapCipher({blockSize:16,nonceLength:12,tagLength:16,varSizeNonce:true},function aesgcm(key,nonce,AAD){if(nonce.length<8)throw new Error(\"aes\/gcm: invalid nonce length\");const tagLength=16;function _computeTag(authKey,tagMask,data){const tag=computeTag2(ghash,false,authKey,data,AAD);for(let i=0;i<tagMask.length;i++)tag[i]^=tagMask[i];return tag}function deriveKeys(){const xk=expandKeyLE(key);const authKey=EMPTY_BLOCK.slice();const counter=EMPTY_BLOCK.slice();ctr32(xk,false,counter,counter,authKey);if(nonce.length===12){counter.set(nonce)}else{const nonceLen=EMPTY_BLOCK.slice();const view=createView(nonceLen);view.setBigUint64(8,BigInt(nonce.length*8),false);const g=ghash.create(authKey).update(nonce).update(nonceLen);g.digestInto(counter);g.destroy()}const tagMask=ctr32(xk,false,counter,EMPTY_BLOCK);return{xk,authKey,counter,tagMask}}return{encrypt(plaintext){const{xk,authKey,counter,tagMask}=deriveKeys();const out=new Uint8Array(plaintext.length+tagLength);const toClean=[xk,authKey,counter,tagMask];if(!isAligned32(plaintext))toClean.push(plaintext=copyBytes(plaintext));ctr32(xk,false,counter,plaintext,out.subarray(0,plaintext.length));const tag=_computeTag(authKey,tagMask,out.subarray(0,out.length-tagLength));toClean.push(tag);out.set(tag,plaintext.length);clean(...toClean);return out},decrypt(ciphertext){const{xk,authKey,counter,tagMask}=deriveKeys();const toClean=[xk,authKey,tagMask,counter];if(!isAligned32(ciphertext))toClean.push(ciphertext=copyBytes(ciphertext));const data=ciphertext.subarray(0,-tagLength);const passedTag=ciphertext.subarray(-tagLength);const tag=_computeTag(authKey,tagMask,data);toClean.push(tag);if(!equalBytes(tag,passedTag)){clean(...toClean);throw new Error(\"aes\/gcm: invalid ghash tag\")}const out=ctr32(xk,false,counter,data);clean(...toClean);return out}}});return __toCommonJS(bundle_entry_exports);})();\r\n\r\n<\/script>\r\n\r\n<script>\r\n const flutterBridge = new FlutterJSBridge();\r\n const cache = new Cache();\r\n const http = new Http();\r\n const cookie = new Cookie();\r\n\r\n\/\/ ============ 站点配置 ============\r\nvar baseurl = \"https:\/\/json.hgeuz.cn\/tyfm\/json_v1\"; \r\nvar apiurl = \"https:\/\/tingyou.fm\"; \/\/ 动态 API\r\nvar keyHex = \"ea9d9d4f9a983fe6f6382f29c7b46b8d6dc47abc6da36662e6ddff8c78902f65\";\r\nvar header = {\r\n \"User-Agent\": \"Mozilla\/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit\/605.1.15 Mobile\/15E148\",\r\n \"Accept\": \"application\/json, text\/plain, *\/*\",\r\n \"X-Payload-Version\": \"1\",\r\n \"Cookie\": \"dfp=f-c29c4:f-testfingerprintvalue1234567890\"\r\n};\r\n\r\n\/\/ ============ 加密解密(基于 @noble\/ciphers 单文件构建) ============\r\n\/\/ NobleCiphers 提供:hexToBytes\/bytesToHex\/utf8ToBytes\/bytesToUtf8\/concatBytes、\r\n\/\/ xchacha20poly1305(key, nonce) -> {encrypt,decrypt}(输出\/输入为 ciphertext||tag)、\r\n\/\/ gcm(key, nonce, aad?) -> {encrypt,decrypt}(输出\/输入为 ciphertext||tag)\r\nvar NB = typeof NobleCiphers !== 'undefined' ? NobleCiphers : null;\r\nfunction hexDecode(s) { return NB ? NB.hexToBytes(s) : null; }\r\nfunction hexEncode(b) { return NB ? NB.bytesToHex(b) : null; }\r\nfunction utf8Encode(s) { return NB ? NB.utf8ToBytes(s) : null; }\r\nfunction utf8Decode(b) { return NB ? NB.bytesToUtf8(b) : null; }\r\n\r\n\/\/ 响应载荷格式:[version][24B nonce][cipher],version=2 时 cipher 整体 reverse\r\nfunction decryptPayloadHex(hexPayload, key32) {\r\n if (!NB) return null;\r\n var enc = NB.hexToBytes(hexPayload);\r\n if (enc.length < 41) return null;\r\n var v = enc[0];\r\n var nonce = enc.subarray(1, 25);\r\n var cipher = enc.subarray(25);\r\n if (v === 2) cipher = cipher.slice().reverse();\r\n try { return NB.xchacha20poly1305(key32, nonce).decrypt(cipher); }\r\n catch (e) { return null; }\r\n}\r\n\/\/ 请求体封装:[version][12B iv][cipher+tag],version=1\r\nfunction encryptRequestPayload(key32, dataBytes) {\r\n if (!NB) return null;\r\n var iv = new Uint8Array(12);\r\n if (typeof crypto !== 'undefined' && crypto.getRandomValues) crypto.getRandomValues(iv);\r\n else for (var i = 0; i < 12; i++) iv[i] = (Math.random() * 256) | 0;\r\n var cipher = NB.gcm(key32, iv).encrypt(dataBytes);\r\n var out = new Uint8Array(1 + 12 + cipher.length);\r\n out[0] = 1; out.set(iv, 1); out.set(cipher, 13);\r\n return out;\r\n}\r\n\r\n\r\n\/\/ ============ 通用请求工具 ============\r\nvar KEY = hexDecode(keyHex);\r\n\r\n\/\/ 静态池 GET:返回解密后的 JSON 对象(或 null)\r\nasync function get1(path) {\r\n var get = await http.Get(baseurl + \"\/\" + path, header, true);\r\n if (!get || get.statusCode !== 200 || !get.data) return null;\r\n try {\r\n var j = JSON.parse(get.data);\r\n if (!j.payload) return j;\r\n var pt = decryptPayloadHex(j.payload, KEY);\r\n return pt ? JSON.parse(utf8Decode(pt)) : null;\r\n } catch (e) { return null; }\r\n}\r\n\r\n\/\/ 动态 API POST:请求体 AES-GCM 加密(hex),响应 XChaCha 解密\r\nasync function apiPost(path, bodyObj) {\r\n var payload = encryptRequestPayload(KEY, utf8Encode(JSON.stringify(bodyObj)));\r\n var body = hexEncode(payload);\r\n var post = await http.Post(apiurl + path, header, body, \"text\/plain\", true);\r\n if (!post || post.statusCode !== 200 || !post.data) return null;\r\n try {\r\n var j = JSON.parse(post.data);\r\n if (!j.payload) return j;\r\n var pt = decryptPayloadHex(j.payload, KEY);\r\n return pt ? JSON.parse(utf8Decode(pt)) : null;\r\n } catch (e) { return null; }\r\n}\r\n\r\n\/\/ 由 album 记录组装书本对象\r\nasync function makeBook(it) {\r\n var id = String(it.id);\r\n var b64 = await flutterBridge.base64encode(id);\r\n var kind = (it.type || \"\") + (it.cat && it.cat !== it.type ? \"\/\" + it.cat : \"\");\r\n return {\r\n \"bookUrl\": b64,\r\n \"name\": it.title || \"\",\r\n \"author\": (it.teller || it.author || \"\"),\r\n \"kind\": kind,\r\n \"coverUrl\": it.cover_url || \"\",\r\n \"intro\": it.description || \"\",\r\n \"tocUrl\": b64,\r\n \"wordCount\": \"\",\r\n \"type\": 1,\r\n \"latestChapterTitle\": \"\"\r\n };\r\n}\r\n\r\n\/\/ ===== 搜索函数 =====\r\nasync function search(key, page, env) {\r\n try {\r\n \/\/ 只有选择分类 -1(全部)和 1(听书)时才搜索\r\n if (env === \"searchone\") {\r\n var searchType = await flutterBridge.getsearch();\r\n if (searchType !== -1 && searchType !== 1) {\r\n return \"[]\";\r\n }\r\n }\r\n var d = await apiPost(\"\/api\/search\", { keyword: key, page: page || 1 });\r\n if (!d || !d.results) return \"[]\";\r\n var books = [];\r\n for (var i = 0; i < d.results.length; i++) {\r\n books.push(await makeBook(d.results[i]));\r\n }\r\n return JSON.stringify(books);\r\n } catch (e) { return \"[]\"; }\r\n}\r\n\r\n\/\/ ===== 筛选函数 =====\r\nasync function filter() {\r\n return \"\";\r\n}\r\n\r\n\/\/ ===== 发现筛选函数 =====\r\nasync function findfilter(url) {\r\n return \"\";\r\n}\r\n\r\n\/\/ ===== 详情页函数 =====\r\nasync function info(bookurl) {\r\n try {\r\n var id = await flutterBridge.base64decode(bookurl);\r\n var d = await get1(\"album_info\/\" + id);\r\n if (!d) return JSON.stringify({ \"bookUrl\": bookurl, \"name\": \"\", \"author\": \"\", \"coverUrl\": \"\", \"intro\": \"\", \"kind\": \"\", \"tocUrl\": \"\", \"type\": 1 });\r\n return JSON.stringify({\r\n \"bookUrl\": bookurl,\r\n \"name\": d.title || \"\",\r\n \"author\": (d.teller || d.author || \"\"),\r\n \"coverUrl\": d.cover_url || \"\",\r\n \"intro\": d.synopsis || d.description || \"\",\r\n \"kind\": (d.type || d.cat || \"\"),\r\n \"status\": (d.status === 0 ? \"已完结\" : \"连载中\"),\r\n \"wordCount\": \"\",\r\n \"tocUrl\": bookurl,\r\n \"type\": 1,\r\n \"latestChapterTitle\": \"\"\r\n });\r\n } catch (e) {\r\n return JSON.stringify({ \"bookUrl\": bookurl, \"name\": \"\", \"author\": \"\", \"coverUrl\": \"\", \"intro\": \"\", \"kind\": \"\", \"tocUrl\": \"\", \"type\": 1 });\r\n }\r\n}\r\n\r\n\/\/ ===== 目录页函数 =====\r\nasync function chapter(tocUrl, bookurl) {\r\n try {\r\n var albumId = await flutterBridge.base64decode(tocUrl);\r\n var d = await get1(\"album_chapters\/\" + albumId);\r\n if (!d || !d.chapters) return \"[]\";\r\n var list = [];\r\n var chs = d.chapters;\r\n for (var i = 0; i < chs.length; i++) {\r\n var c = chs[i];\r\n list.push({\r\n \"name\": c.title || (\"第\" + (c.index || (i + 1)) + \"集\"),\r\n \"chapterId\": await flutterBridge.base64encode(albumId + \"❌\" + c.index),\r\n \"index\": i,\r\n \"isPay\": false,\r\n \"isVip\": false,\r\n \"isVolume\": false,\r\n \"tag\": \"\"\r\n });\r\n }\r\n return JSON.stringify(list);\r\n } catch (e) { return \"[]\"; }\r\n}\r\n\r\n\/\/ ===== 正文页函数(听书源核心):返回音频URL =====\r\nasync function content(url, bookurl) {\r\n try {\r\n var decoded = await flutterBridge.base64decode(url);\r\n var parts = decoded.split(\"❌\");\r\n if (parts.length < 2) return \"\";\r\n var albumId = parts[0], idx = parts[1];\r\n var d = await apiPost(\"\/api\/play_token\", { album_id: albumId, chapter_idx: parseInt(idx, 10) });\r\n if (d && d.play_url) return d.play_url;\r\n return \"\";\r\n } catch (e) { return \"\"; }\r\n}\r\n\r\n\/\/ ===== 发现函数 =====\r\nasync function getfinds() {\r\n var list = [];\r\n list.push({ title: \"推荐\", url: await flutterBridge.base64encode(\"home\") + \"❌{{page}}\", type: 0 });\r\n list.push({ title: \"最近更新\", url: await flutterBridge.base64encode(\"recent\") + \"❌{{page}}\", type: 0 });\r\n var d = await get1(\"filters\");\r\n if (d && d.categories) {\r\n for (var c = 0; c < d.categories.length; c++) {\r\n var cat = d.categories[c];\r\n list.push({ title: cat.name, url: \"\", type: 0 });\r\n var types = cat.types || [];\r\n for (var t = 0; t < types.length; t++) {\r\n var ty = types[t];\r\n list.push({ title: ty.name, url: await flutterBridge.base64encode(\"cat❌\" + ty.id) + \"❌{{page}}\", type: 0 });\r\n }\r\n }\r\n }\r\n return JSON.stringify(list);\r\n}\r\n\r\nasync function find(url, page) {\r\n try {\r\n var parts = url.split(\"❌\");\r\n if (parts.length < 2) return \"[]\";\r\n var tag = await flutterBridge.base64decode(parts[0]);\r\n var arr = null;\r\n if (tag === \"home\" || tag === \"recent\") {\r\n if (page > 1) return \"[]\";\r\n var h = await get1(\"homepage\");\r\n if (!h) return \"[]\";\r\n arr = tag === \"home\" ? (h.recommends || []) : (h.recent_updates || []);\r\n var homeBooks = [];\r\n for (var i = 0; i < arr.length; i++) homeBooks.push(await makeBook(arr[i]));\r\n return JSON.stringify(homeBooks);\r\n }\r\n var pieces = tag.split(\"❌\");\r\n if (pieces[0] === \"cat\") {\r\n var typeId = pieces[1];\r\n var d = await get1(\"types\/\" + typeId + \"\/\/comprehensive\/p\" + page);\r\n if (!d || !d.data) return \"[]\";\r\n var books = [];\r\n for (var j = 0; j < d.data.length; j++) books.push(await makeBook(d.data[j]));\r\n return JSON.stringify(books);\r\n }\r\n return \"[]\";\r\n } catch (e) { return \"[]\"; }\r\n}\r\n\r\n\/\/ ===== 购买函数 =====\r\nasync function pay(bookurl, url) { }\r\n\r\n\/\/ ===== 登录函数 =====\r\nasync function getloginurl() {\r\n return \"\";\r\n}\r\n\r\nasync function login() { }\r\n\r\n\/\/ ===== 图片解密函数 =====\r\nasync function imagedecrypt(url, image) { }\r\n\r\n\/\/ ===== Webview拦截函数 =====\r\nasync function shouldOverrideUrlLoading(url) {\r\n return true;\r\n}\r\n\r\n\/\/ ===== 帮助函数 =====\r\nasync function gethelp() {\r\n return \"\";\r\n}\r\n\r\n\r\n<\/script>\r\n\r\n<\/html>\r\n",
"login": false,
"customButton": false,
"eventListener": false,
"lastUpdateTime": "1787316497314"
}