支持咪咕源并增加请求记录标签页 (#186)

* 增加咪咕源

* 完善咪咕源,包括从豆瓣源获取咪咕弹幕

* 修改弹幕源简介

* EPISODE_TITLE_FILTER环境变量不再应用于剧标题过滤,只对集标题生效

* 增加处理简繁同源场景,比如吃->喫;注意->註意,实际不用转换

* 增加请求历史记录

* 增加请求记录ui界面

* 删除清空记录按钮

* 将请求记录的参数改为请求body体

* 对record.interface进行解码

* 请求参数为空的清空下不显示请求体

* 在没有请求体的情况下虚线也不显示

* 增加todayReqNum全局变量,用于记录今日请求数量

* 在UI界面显示今日请求总数

* 修改README

* 修复云部署的服务配置redis后请求记录还是0的问题
This commit is contained in:
huangxd- authored and GitHub committed 2026-02-08 23:16:26 +08:00
1 parent f1f5d285fb
commit 2ad2d5fa1a
26 files changed
+1793 -62

No files matched your search

+13 -8
View File
@@ -18,7 +18,7 @@ LogVar 弹幕 API 服务器
---
一个人人都能部署的基于 js 的弹幕 API 服务器,支持爱优腾芒哔人韩巴弹幕直接获取,兼容弹弹play的搜索、详情查询和弹幕获取接口规范,并提供日志记录,支持vercel/netlify/edgeone/cloudflare/docker/claw等部署方式,不用提前下载弹幕,没有nas或小鸡也能一键部署。
一个人人都能部署的基于 js 的弹幕 API 服务器,支持爱优腾芒哔咪人韩巴狐乐西弹幕直接获取,兼容弹弹play的搜索、详情查询和弹幕获取接口规范,并提供日志记录,支持vercel/netlify/edgeone/cloudflare/docker/claw等部署方式,不用提前下载弹幕,没有nas或小鸡也能一键部署。
本项目仅为个人爱好开发,代码开源。如有任何侵权行为,请联系本人删除。
@@ -71,7 +71,7 @@ LogVar 弹幕 API 服务器
- 本地和Docker部署支持实时保存缓存到文件(挂载.cache目录即可)
- **部署支持**:支持本地运行、Docker 容器化、Vercel 一键部署、Netlify 一键部署、Edgeone 一键部署、Cloudflare 一键部署、Claw部署和 Docker 一键启动。
- **手动选择记忆**:支持记住之前搜索title时手动选择的anime,并在后续的match自动匹配时优选该anime【实验性】。
- **手动搜索支持输入播放链接获取弹幕**:支持手动搜索的播放器输入爱优腾芒哔播放链接可获取弹幕,如`senplayer`。
- **手动搜索支持输入播放链接获取弹幕**:支持手动搜索的播放器输入爱优腾芒哔咪狐乐西播放链接可获取弹幕,如`senplayer`。
- **弹幕转换功能**:支持通过环境变量配置弹幕转换规则,包括:
- 将顶部和底部弹幕转换为浮动弹幕(`CONVERT_TOP_BOTTOM_TO_SCROLL`)
- 转换弹幕颜色为白色或彩色(`CONVERT_COLOR`)
@@ -85,6 +85,7 @@ LogVar 弹幕 API 服务器
- 日志查看
- 接口调试
- 推送弹幕
- 请求记录
- 系统管理
## 前置条件
@@ -318,7 +319,7 @@ LogVar 弹幕 API 服务器
<img src="https://i.mji.rip/2025/09/14/80aa5205d49a767447f61938f2dada20.jpeg" style="width:400px" />
<img src="https://i.mji.rip/2025/09/14/9fdf945fb247994518042691f60d7849.jpeg" style="width:400px" />
<img src="https://i.mji.rip/2025/09/14/dbacc0cf9c8a839f16b8960de1f38f11.jpeg" style="width:400px" />
4. 现已支持手动搜索标题输入爱优腾芒哔播放链接获取弹幕。
4. 现已支持手动搜索标题输入爱优腾芒哔咪狐乐西播放链接获取弹幕。
### XML 格式说明
@@ -371,9 +372,9 @@ API 支持返回 Bilibili 标准 XML 格式的弹幕数据,通过查询参数
| VOD_REQUEST_TIMEOUT | 【可选】VOD服务器单个请求超时时间(毫秒),防止慢速或失效的采集站阻塞搜索,默认为`10000`(10秒),建议值:`5000-15000`。由于`fastest`模式只返回最快响应的站点,可以设置较大的超时时间给慢速站点更多机会 |
| BILIBILI_COOKIE | 【可选】b站cookie(填入后能抓取完整弹幕和启用港澳台App接口),如 `buvid3=E2BCA ... eao6; theme-avatar-tip-show=SHOWED`,请自行通过浏览器或抓包工具抓取,热心网友测试后,弹幕获取实际最少只需取 `SESSDATA=xxxx` 字段,但如果需要使用港澳台区域稳定的App搜索接口还需要`bili_jct=xxxx`或`access_key=xxxx` 字段,不知道怎么获取cookie的,可以从工具 [cookie-butler](https://cookie-butler.do-u.me) 获取 |
| YOUKU_CONCURRENCY | 【可选】youku弹幕请求并发数,用于加快youku弹幕请求速度,不填默认为`8`,最高`16` |
| SOURCE_ORDER | 【可选】源排序,用于按源对返回资源的排序(注意:先后顺序会影响自动匹配最终的返回),默认是`360,vod,renren,hanjutv`,表示360数据排在最前,hanjutv数据排在最后,示例:`360,renren`:只返回360数据和renren数据,且360数据靠前;当前可选择的源字段有 `360,vod,tmdb,douban,tencent,youku,iqiyi,imgo,bilibili,sohu,leshi,xigua,renren,hanjutv,bahamut,dandan,animeko,custom` |
| PLATFORM_ORDER | 【可选】自动匹配优选平台,按顺序优先返回指定平台弹幕,默认为空,即返回第一个满足条件的平台,示例:`bilibili1,qq`,表示如果有b站的播放源,则优先返回b站的弹幕,否则就返回腾讯的弹幕,两者都没有,则返回第一个满足条件的平台,当配置合并平台的时候为指定期望的合并源;当前可选择的平台字段有 `qiyi, bilibili1, imgo, youku, qq, sohu, leshi, xigua, renren, hanjutv, bahamut, dandan, animeko, custom` |
| MERGE_SOURCE_PAIRS | 【可选】源合并配置,配置后将对应源合并同时一起获取弹幕返回,默认为空,格式是`源字段&源字段&源字段`,示例:`imgo&iqiyi,dandan&bahamut&animeko,imgo`, 允许多组、允许同时存在、允许多源,允许填单源表示保留原结果,一组中第一个为主源其余为副源,副源往主源合并,主源如果没有结果会轮替下一个作为主源循环,目前允许合并的源字段有`tencent,youku,iqiyi,imgo,bilibili,sohu,leshi,xigua,renren,hanjutv,bahamut,dandan,animeko` |
| SOURCE_ORDER | 【可选】源排序,用于按源对返回资源的排序(注意:先后顺序会影响自动匹配最终的返回),默认是`360,vod,renren,hanjutv`,表示360数据排在最前,hanjutv数据排在最后,示例:`360,renren`:只返回360数据和renren数据,且360数据靠前;当前可选择的源字段有 `360,vod,tmdb,douban,tencent,youku,iqiyi,imgo,bilibili,migu,sohu,leshi,xigua,renren,hanjutv,bahamut,dandan,animeko,custom` |
| PLATFORM_ORDER | 【可选】自动匹配优选平台,按顺序优先返回指定平台弹幕,默认为空,即返回第一个满足条件的平台,示例:`bilibili1,qq`,表示如果有b站的播放源,则优先返回b站的弹幕,否则就返回腾讯的弹幕,两者都没有,则返回第一个满足条件的平台,当配置合并平台的时候为指定期望的合并源;当前可选择的平台字段有 `qiyi, bilibili1, imgo, youku, qq, migu, sohu, leshi, xigua, renren, hanjutv, bahamut, dandan, animeko, custom` |
| MERGE_SOURCE_PAIRS | 【可选】源合并配置,配置后将对应源合并同时一起获取弹幕返回,默认为空,格式是`源字段&源字段&源字段`,示例:`imgo&iqiyi,dandan&bahamut&animeko,imgo`, 允许多组、允许同时存在、允许多源,允许填单源表示保留原结果,一组中第一个为主源其余为副源,副源往主源合并,主源如果没有结果会轮替下一个作为主源循环,目前允许合并的源字段有`tencent,youku,iqiyi,imgo,bilibili,migu,sohu,leshi,xigua,renren,hanjutv,bahamut,dandan,animeko` |
| EPISODE_TITLE_FILTER | 【可选】剧集标题正则过滤,按正则关键字对剧集或综艺的集标题进行过滤,适用于过滤一些预告或综艺非正式集,只支持match自动匹配,默认值如下 |
| ENABLE_EPISODE_FILTER | 【可选】是否在手动选择接口中启用集标题过滤,默认为`false`(禁用),启用后 GET /api/v2/bangumi/{id} 和 GET /api/v2/search/anime 接口会过滤掉预告、花絮等特殊集,以及名称包含特殊关键词的动漫。 |
| STRICT_TITLE_MATCH | 【可选】是否启用严格标题匹配模式,默认为`false`(宽松模糊匹配),启用后只匹配标题开头或完全匹配的结果。例如:搜索"遮天"时,`false`会匹配"古惑仔3之只手遮天",`true`只匹配"遮天"、"遮天 第一季"等。可选值:`true`、`false` |
@@ -437,13 +438,14 @@ API 支持返回 Bilibili 标准 XML 格式的弹幕数据,通过查询参数
| ----------- | ----------- |
| 360 | qiyi, bilibili1, imgo, youku, qq |
| vod | qiyi, bilibili1, imgo, youku, qq |
| tmdb | qiyi, bilibili1, youku, qq |
| douban | qiyi, bilibili1, youku, qq |
| tmdb | qiyi, bilibili1, youku, qq, migu |
| douban | qiyi, bilibili1, youku, qq, migu |
| tencent | qq |
| youku | youku |
| iqiyi | qiyi |
| imgo | imgo |
| bilibili | bilibili1 |
| migu | migu |
| sohu | sohu |
| leshi | leshi |
| xigua | xigua |
@@ -503,6 +505,7 @@ API 支持返回 Bilibili 标准 XML 格式的弹幕数据,通过查询参数
│ │ ├── kan360.js # 360看源
│ │ ├── leshi.js # 乐视视频源
│ │ ├── mango.js # 芒果TV源
│ │ ├── migu.js # 咪咕视频源
│ │ ├── other.js # 第三方弹幕服务器
│ │ ├── renren.js # 人人视频源
│ │ ├── sohu.js # 搜狐视频源
@@ -525,6 +528,7 @@ API 支持返回 Bilibili 标准 XML 格式的弹幕数据,通过查询参数
│ │ ├── main.js # UI主脚本
│ │ ├── preview.js # 预览功能脚本
│ │ ├── pushdanmu.js # 推送弹幕脚本
│ │ ├── requestrecords.js # 请求记录脚本
│ │ └── systemsettings.js # 系统设置脚本
│ └── utils/
│ ├── cache-util.js # 缓存数据处理工具
@@ -537,6 +541,7 @@ API 支持返回 Bilibili 标准 XML 格式的弹幕数据,通过查询参数
│ ├── imdb-util.js # IMDB API请求工具
│ ├── log-util.js # 日志工具
│ ├── merge-util.js # 源合并处理工具
│ ├── migu-util.js # 咪咕工具
│ ├── redis-util.js # redis工具
│ ├── time-util.js # 时间日期工具
│ ├── tmdb-util.js # TMDB API请求处理工具
+5 -5
View File
@@ -68,9 +68,9 @@ YOUKU_CONCURRENCY=8
# ==================== 源排序配置 ====================
# 数据源查询顺序(可选值:360, vod, tmdb, douban, tencent, youku, iqiyi, imgo, bilibili, renren, hanjutv, bahamut, dandan, sohu, leshi, xigua, animeko, custom)
# 默认值:360,vod,renren,hanjutv(不包含 tencent, youku, iqiyi, imgo, bilibili, sohu , leshi, xigua等)
# 如需使用腾讯源、优酷源、爱奇艺源、芒果源、B站源、搜狐源、乐视源、西瓜源,请手动添加:SOURCE_ORDER=360,vod,tencent,youku,iqiyi,imgo,bilibili,ren,hanjutv,sohu,leshi,xigua
# 数据源查询顺序(可选值:360, vod, tmdb, douban, tencent, youku, iqiyi, imgo, bilibili, migu, renren, hanjutv, bahamut, dandan, sohu, leshi, xigua, animeko, custom)
# 默认值:360,vod,renren,hanjutv(不包含 tencent, youku, iqiyi, imgo, bilibili, migu, sohu , leshi, xigua等)
# 如需使用腾讯源、优酷源、爱奇艺源、芒果源、B站源、搜狐源、乐视源、西瓜源,请手动添加:SOURCE_ORDER=360,vod,tencent,youku,iqiyi,imgo,bilibili,migu,renren,hanjutv,sohu,leshi,xigua
# 如需使用巴哈姆特源,请手动添加:SOURCE_ORDER=360,vod,renren,hanjutv,bahamut
# 如需使用弹弹play源,请手动添加:SOURCE_ORDER=360,vod,renren,hanjutv,dandan
# 如需使用豆瓣源,请手动添加:SOURCE_ORDER=360,vod,douban,renren,hanjutv
@@ -81,12 +81,12 @@ SOURCE_ORDER=360,vod,renren,hanjutv
# 平台优先级排序(用于自动匹配)
# 默认值:空(自动匹配)
# 可选值:qiyi, bilibili1, imgo, youku, qq, sohu, leshi, xigua, renren, hanjutv, bahamut, dandan, animeko, custom 或 qiyi&bilibili1&imgo,dandan&animeko
# 可选值:qiyi, bilibili1, imgo, youku, qq, migu, sohu, leshi, xigua, renren, hanjutv, bahamut, dandan, animeko, custom 或 qiyi&bilibili1&imgo,dandan&animeko
# 说明:平台排序配置,可以配置自动匹配时的优选平台,当配置合并平台的时候可以指定期望的合并源
# PLATFORM_ORDER=
# ==================== 源合并配置 ====================
# 数据源合并配置(可选值:tencent, youku, iqiyi, imgo, bilibili, renren, hanjutv, bahamut, dandan, sohu, leshi, xigua, animeko)
# 数据源合并配置(可选值:tencent, youku, iqiyi, imgo, bilibili, migu, renren, hanjutv, bahamut, dandan, sohu, leshi, xigua, animeko)
# 默认值:空
# 说明:配置后将对应源合并同时一起获取弹幕返回,允许多组、允许同时存在、允许多源,允许填单源表示保留原结果,一组中第一个为主源其余为副源,副源往主源合并,主源如果没有结果会轮替下一个作为主源循环
# 格式:源字段&源字段&源字段,源字段
+29 -8
View File
@@ -24,6 +24,7 @@ import TencentSource from "../sources/tencent.js";
import IqiyiSource from "../sources/iqiyi.js";
import MangoSource from "../sources/mango.js";
import BilibiliSource from "../sources/bilibili.js";
import MiguSource from "../sources/migu.js";
import YoukuSource from "../sources/youku.js";
import SohuSource from "../sources/sohu.js";
import LeshiSource from "../sources/leshi.js";
@@ -48,12 +49,13 @@ const youkuSource = new YoukuSource();
const iqiyiSource = new IqiyiSource();
const mangoSource = new MangoSource();
const bilibiliSource = new BilibiliSource();
const miguSource = new MiguSource();
const sohuSource = new SohuSource();
const leshiSource = new LeshiSource();
const xiguaSource = new XiguaSource();
const animekoSource = new AnimekoSource();
const otherSource = new OtherSource();
const doubanSource = new DoubanSource(tencentSource, iqiyiSource, youkuSource, bilibiliSource);
const doubanSource = new DoubanSource(tencentSource, iqiyiSource, youkuSource, bilibiliSource, miguSource);
const tmdbSource = new TmdbSource(doubanSource);
// 用于聚合请求的去重Map
@@ -156,6 +158,14 @@ export async function searchAnime(url, preferAnimeId = null, preferSource = null
platform = "youku";
} else if (queryTitle.includes(".bilibili.com")) {
platform = "bilibili1";
} else if (queryTitle.includes('.miguvideo.com')) {
platform = "migu";
} else if (queryTitle.includes('.sohu.com')) {
platform = "sohu";
} else if (queryTitle.includes('.le.com')) {
platform = "leshi";
} else if (queryTitle.includes('.douyin.com') || queryTitle.includes('.ixigua.com')) {
platform = "xigua";
}
const pageTitle = await getPageTitle(queryTitle);
@@ -204,6 +214,7 @@ export async function searchAnime(url, preferAnimeId = null, preferSource = null
if (source === "iqiyi") return iqiyiSource.search(queryTitle);
if (source === "imgo") return mangoSource.search(queryTitle);
if (source === "bilibili") return bilibiliSource.search(queryTitle);
if (source === "migu") return miguSource.search(queryTitle);
if (source === "sohu") return sohuSource.search(queryTitle);
if (source === "leshi") return leshiSource.search(queryTitle);
if (source === "xigua") return xiguaSource.search(queryTitle);
@@ -226,7 +237,7 @@ export async function searchAnime(url, preferAnimeId = null, preferSource = null
vod: animesVodResults, 360: animes360, tmdb: animesTmdb, douban: animesDouban, renren: animesRenren,
hanjutv: animesHanjutv, bahamut: animesBahamut, dandan: animesDandan, custom: animesCustom,
tencent: animesTencent, youku: animesYouku, iqiyi: animesIqiyi, imgo: animesImgo, bilibili: animesBilibili,
sohu: animesSohu, leshi: animesLeshi, xigua: animesXigua, animeko: animesAnimeko
migu: animesMigu, sohu: animesSohu, leshi: animesLeshi, xigua: animesXigua, animeko: animesAnimeko
} = resultData;
// 按顺序处理每个来源的结果
@@ -279,6 +290,9 @@ export async function searchAnime(url, preferAnimeId = null, preferSource = null
} else if (key === 'bilibili') {
// 等待处理Bilibili来源
await bilibiliSource.handleAnimes(animesBilibili, queryTitle, curAnimes);
} else if (key === 'migu') {
// 等待处理Migu来源
await miguSource.handleAnimes(animesMigu, queryTitle, curAnimes);
} else if (key === 'sohu') {
// 等待处理Sohu来源
await sohuSource.handleAnimes(animesSohu, queryTitle, curAnimes);
@@ -308,12 +322,12 @@ export async function searchAnime(url, preferAnimeId = null, preferSource = null
if (globals.enableEpisodeFilter) {
const validAnimes = [];
for (const anime of curAnimes) {
// 首先检查动漫名称是否包含过滤关键词
const animeTitle = anime.animeTitle || '';
if (globals.episodeTitleFilter.test(animeTitle)) {
log("info", `[searchAnime] Anime ${anime.animeId} filtered by name: ${animeTitle}`);
continue; // 跳过该动漫
}
// // 首先检查动漫名称是否包含过滤关键词
// const animeTitle = anime.animeTitle || '';
// if (globals.episodeTitleFilter.test(animeTitle)) {
// log("info", `[searchAnime] Anime ${anime.animeId} filtered by name: ${animeTitle}`);
// continue; // 跳过该动漫
// }
const animeData = globals.animes.find(a => a.animeId === anime.animeId);
if (animeData && animeData.links) {
@@ -1094,6 +1108,7 @@ async function fetchMergedComments(url) {
else if (sourceName === 'iqiyi') sourceInstance = iqiyiSource;
else if (sourceName === 'imgo') sourceInstance = mangoSource;
else if (sourceName === 'bilibili') sourceInstance = bilibiliSource;
else if (sourceName === 'migu') sourceInstance = miguSource;
else if (sourceName === 'sohu') sourceInstance = sohuSource;
else if (sourceName === 'leshi') sourceInstance = leshiSource;
else if (sourceName === 'xigua') sourceInstance = xiguaSource;
@@ -1185,6 +1200,8 @@ export async function getComment(path, queryFormat, segmentFlag) {
danmus = await bilibiliSource.getComments(url, plat, segmentFlag);
} else if (url.includes('.youku.com')) {
danmus = await youkuSource.getComments(url, plat, segmentFlag);
} else if (url.includes('.miguvideo.com')) {
danmus = await miguSource.getComments(url, plat, segmentFlag);
} else if (url.includes('.sohu.com')) {
danmus = await sohuSource.getComments(url, plat, segmentFlag);
} else if (url.includes('.le.com')) {
@@ -1298,6 +1315,8 @@ export async function getCommentByUrl(videoUrl, queryFormat, segmentFlag) {
danmus = await bilibiliSource.getComments(url, "bilibili1", segmentFlag);
} else if (url.includes('.youku.com')) {
danmus = await youkuSource.getComments(url, "youku", segmentFlag);
} else if (url.includes('.miguvideo.com')) {
danmus = await miguSource.getComments(url, "migu", segmentFlag);
} else if (url.includes('.sohu.com')) {
danmus = await sohuSource.getComments(url, "sohu", segmentFlag);
} else if (url.includes('.le.com')) {
@@ -1383,6 +1402,8 @@ export async function getSegmentComment(segment, queryFormat) {
danmus = await bilibiliSource.getSegmentComments(segment);
} else if (platform === "youku") {
danmus = await youkuSource.getSegmentComments(segment);
} else if (platform === "migu") {
danmus = await miguSource.getSegmentComments(segment);
} else if (platform === "sohu") {
danmus = await sohuSource.getSegmentComments(segment);
} else if (platform === "leshi") {
+13 -1
View File
@@ -74,7 +74,7 @@ export function handleConfig(hasPermission = false) {
originalEnvVars: originalEnvVars, // 系统设置使用原始环境变量(已脱敏)
hasAdminToken: hasAdminToken, // 添加admin token配置状态
repository: "https://github.com/huangxd-/danmu_api.git",
description: "一个人人都能部署的基于 js 的弹幕 API 服务器,支持爱优腾芒哔人韩巴弹幕直接获取,兼容弹弹play的搜索、详情查询和弹幕获取接口规范,并提供日志记录,支持vercel/netlify/edgeone/cloudflare/docker/claw等部署方式,不用提前下载弹幕,没有nas或小鸡也能一键部署。",
description: "一个人人都能部署的基于 js 的弹幕 API 服务器,支持爱优腾芒哔咪人韩巴狐乐西弹幕直接获取,兼容弹弹play的搜索、详情查询和弹幕获取接口规范,并提供日志记录,支持vercel/netlify/edgeone/cloudflare/docker/claw等部署方式,不用提前下载弹幕,没有nas或小鸡也能一键部署。",
notice: "本项目仅为个人爱好开发,代码开源。如有任何侵权行为,请联系本人删除。有问题提issue或私信机器人都ok,TG MSG ROBOT: [https://t.me/ddjdd_bot]; 推荐加互助群咨询,TG GROUP: [https://t.me/logvar_danmu_group]; 关注频道获取最新更新内容,TG CHANNEL: [https://t.me/logvar_danmu_channel]。"
});
}
@@ -196,3 +196,15 @@ export async function handleClearCache() {
return jsonResponse({ success: false, message: `Cache clear failed: ${error.message}` }, 500);
}
}
/**
* 处理获取请求记录的请求
* @returns {Response} 包含请求记录的响应
*/
export function handleReqRecords() {
// 返回请求记录,按时间倒序排列(最新的在前)
const records = [...globals.reqRecords].reverse();
const todayReqNum = globals.todayReqNum || 0;
return jsonResponse({ records, todayReqNum }, 200);
}
+4 -4
View File
@@ -9,10 +9,10 @@ export class Envs {
static originalEnvVars = new Map();
static accessedEnvVars = new Map();
static VOD_ALLOWED_PLATFORMS = ['qiyi', 'bilibili1', 'imgo', 'youku', 'qq', 'sohu', 'leshi', 'xigua']; // vod允许的播放平台
static ALLOWED_PLATFORMS = ['qiyi', 'bilibili1', 'imgo', 'youku', 'qq', 'renren', 'hanjutv', 'bahamut', 'dandan', 'sohu', 'leshi', 'xigua', 'animeko', 'custom']; // 全部源允许的播放平台
static ALLOWED_SOURCES = ['360', 'vod', 'tmdb', 'douban', 'tencent', 'youku', 'iqiyi', 'imgo', 'bilibili', 'renren', 'hanjutv', 'bahamut', 'dandan', 'sohu', 'leshi', 'xigua', 'animeko', 'custom']; // 允许的源
static MERGE_ALLOWED_SOURCES = ['tencent', 'youku', 'iqiyi', 'imgo', 'bilibili', 'renren', 'hanjutv', 'bahamut', 'dandan', 'sohu', 'leshi', 'xigua', 'animeko']; // 允许的源合并
static VOD_ALLOWED_PLATFORMS = ['qiyi', 'bilibili1', 'imgo', 'youku', 'qq', 'migu', 'sohu', 'leshi', 'xigua']; // vod允许的播放平台
static ALLOWED_PLATFORMS = ['qiyi', 'bilibili1', 'imgo', 'youku', 'qq', 'migu', 'renren', 'hanjutv', 'bahamut', 'dandan', 'sohu', 'leshi', 'xigua', 'animeko', 'custom']; // 全部源允许的播放平台
static ALLOWED_SOURCES = ['360', 'vod', 'tmdb', 'douban', 'tencent', 'youku', 'iqiyi', 'imgo', 'bilibili', 'migu', 'renren', 'hanjutv', 'bahamut', 'dandan', 'sohu', 'leshi', 'xigua', 'animeko', 'custom']; // 允许的源
static MERGE_ALLOWED_SOURCES = ['tencent', 'youku', 'iqiyi', 'imgo', 'bilibili', 'migu', 'renren', 'hanjutv', 'bahamut', 'dandan', 'sohu', 'leshi', 'xigua', 'animeko']; // 允许的源合并
/**
* 获取环境变量
+9 -3
View File
@@ -13,9 +13,10 @@ export const Globals = {
accessedEnvVars: {},
// 静态常量
VERSION: '1.13.8',
VERSION: '1.14.0',
MAX_LOGS: 1000, // 日志存储,最多保存 1000 行
MAX_ANIMES: 100,
MAX_RECORDS: 100, // 请求记录最大数量
// 运行时状态
animes: [],
@@ -28,11 +29,15 @@ export const Globals = {
redisValid: false, // redis是否生效
redisCacheInitialized: false, // redis 缓存是否已初始化
lastSelectMap: new Map(), // 存储查询关键字上次选择的animeId,用于下次match自动匹配时优先选择该anime
reqRecords: [], // 记录请求历史,包括接口/参数/请求时间
todayReqNum: 0, // 今日请求数量统计
lastHashes: { // 存储上一次各变量哈希值
animes: null,
episodeIds: null,
episodeNum: null,
lastSelectMap: null
lastSelectMap: null,
reqRecords: null,
todayReqNum: null
},
searchCache: new Map(), // 搜索结果缓存,存储格式:{ keyword: { results, timestamp } }
commentCache: new Map(), // 弹幕缓存,存储格式:{ videoUrl: { comments, timestamp } }
@@ -158,6 +163,7 @@ export const Globals = {
if (prop === 'version') return self.VERSION;
if (prop === 'maxLogs') return self.MAX_LOGS;
if (prop === 'maxAnimes') return self.MAX_ANIMES;
if (prop === 'maxRecords') return self.MAX_RECORDS;
if (prop === 'maxLastSelectMap') return self.MAX_LAST_SELECT_MAP;
// 暴露方法
@@ -203,4 +209,4 @@ export const globals = new Proxy({}, {
getOwnPropertyDescriptor(target, prop) {
return Object.getOwnPropertyDescriptor(Globals.getConfig(), prop);
}
});
});
+1 -1
View File
@@ -32,7 +32,7 @@ export default class CustomSource extends BaseSource {
}
// 正常情况下输出 JSON 字符串
log("info", `customnSourceSearchresp: ${JSON.stringify(resp.data.animes)}`);
log("info", `[Custom] 搜索找到 ${resp.data.animes.length} 个有效结果`);
return resp.data.animes;
} catch (error) {
+1 -1
View File
@@ -32,7 +32,7 @@ export default class DandanSource extends BaseSource {
}
// 正常情况下输出 JSON 字符串
log("info", `dandanSearchresp: ${JSON.stringify(resp.data.animes)}`);
log("info", `[Dandan] 搜索找到 ${resp.data.animes.length} 个有效结果`);
return resp.data.animes;
} catch (error) {
+16 -1
View File
@@ -6,12 +6,13 @@ import { getDoubanDetail, searchDoubanTitles } from "../utils/douban-util.js";
// 获取豆瓣源播放链接
// =====================
export default class DoubanSource extends BaseSource {
constructor(tencentSource, iqiyiSource, youkuSource, bilibiliSource) {
constructor(tencentSource, iqiyiSource, youkuSource, bilibiliSource, miguSource) {
super('BaseSource');
this.tencentSource = tencentSource;
this.iqiyiSource = iqiyiSource;
this.youkuSource = youkuSource;
this.bilibiliSource = bilibiliSource;
this.miguSource = miguSource;
}
async search(keyword) {
@@ -143,6 +144,20 @@ export default class DoubanSource extends BaseSource {
}
break;
}
case "miguvideo": {
let epId = null;
const decodeUrl = decodeURIComponent(vendor.uri);
const contentIdMatch = decodeUrl.match(/"contentID":"([^"]+)"/);
if (contentIdMatch && contentIdMatch[1]) {
epId = contentIdMatch[1];
}
if (epId) {
tmpAnimes[0].provider = "migu";
tmpAnimes[0].mediaId = `https://v3-sc.miguvideo.com/program/v4/cont/content-info/${epId}/1`;
await this.miguSource.handleAnimes(tmpAnimes, response.data?.title, doubanAnimes)
}
break;
}
}
}
return results;
+1 -1
View File
@@ -34,7 +34,7 @@ export default class HanjutvSource extends BaseSource {
}
// 正常情况下输出 JSON 字符串
log("info", `hanjutvSearchresp: ${JSON.stringify(resp.data.seriesData.seriesList)}`);
log("info", `[Hanjutv] 搜索找到 ${resp.data.seriesData.seriesList.length} 个有效结果`);
let resList = [];
for (const anime of resp.data.seriesData.seriesList) {
+368
View File
@@ -0,0 +1,368 @@
import BaseSource from './base.js';
import { globals } from '../configs/globals.js';
import { log } from "../utils/log-util.js";
import { httpGet, httpPost } from "../utils/http-util.js";
import { convertToAsciiSum } from "../utils/codec-util.js";
import { hexToInt } from "../utils/danmu-util.js";
import { generateValidStartDate, time_to_second } from "../utils/time-util.js";
import { addAnime, removeEarliestAnime } from "../utils/cache-util.js";
import { decrypt } from "../utils/migu-util.js";
import { printFirst200Chars, titleMatches } from "../utils/common-util.js";
import { SegmentListResponse } from '../models/dandan-model.js';
// =====================
// 获取咪咕视频弹幕
// =====================
class MiguSource extends BaseSource {
async search(keyword) {
try {
const searchUrl = `https://jadeite.migu.cn/search/v3/open-search`;
const payload = {
appVersion: "6.1.1.00",
ct: 101,
isCorrectWord: 1,
k: keyword,
mediaSource: 9000000,
packId: "1002581,1002601,1003861,1003862,1003863,1003864,1003865,1003866,1004041,1004121,1004261,1004262,1004281,1004321,1004262,1004281,1004322,1004261,1004421,1004422,1002781,1004301,1004641,1004761,1005061,1005261,1005301,1005321,1005361,1005362,1005341,1005342,1005521,1005722,1005721,1015749,1015761,1015760,1015762,1015763,1015768,1015786,1015790,1015812,1015813,1015814,1015815,1015816,1015817,1015820,1015819,1015821",
pageIdx: 1,
pageSize: 20,
sid: "1X4A395AL3XS3UV5MT8PQ1L5JUYK6KFM8VKDSDD48S5Y7YX5WY1MOUHRT6512988",
copyrightTerminal: 3,
searchScene: 2,
uiVersion: "A3.26.0"
};
const headers = {
"Accept": "application/json, text/plain, */*",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "keep-alive",
"Content-Type": "application/json",
"Origin": "https://www.miguvideo.com",
"Referer": "https://www.miguvideo.com/",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "cross-site",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
"appId": "miguvideo",
"sec-ch-ua": 'Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "Windows",
"terminalId": "www"
};
const response = await httpPost(searchUrl, JSON.stringify(payload), {
headers: headers
});
if (!response || !response.data) {
log("info", "[Migu] 搜索响应为空");
return [];
}
const data = typeof response.data === "string" ? JSON.parse(response.data) : response.data;
const contentInfoList = data?.body?.contentInfoList;
const animes = [];
contentInfoList.forEach(contentInfo => {
const shortMediaAsset = contentInfo?.shortMediaAsset;
if (shortMediaAsset && shortMediaAsset.isLong) {
let epId;
if (shortMediaAsset?.extraData) {
epId = shortMediaAsset?.extraData?.episodes?.[0];
} else {
epId = shortMediaAsset?.pID;
}
animes.push({
name: shortMediaAsset.name,
type: shortMediaAsset.contDisplayName,
year: shortMediaAsset.year.trim(),
img: shortMediaAsset.h5pics?.highResolutionV,
url: `https://v3-sc.miguvideo.com/program/v4/cont/content-info/${epId}/1`,
epsId: epId
});
}
});
// 正常情况下输出 JSON 字符串
log("info", `[Migu] 搜索找到 ${animes.length} 个有效结果`);
return animes;
} catch (error) {
// 捕获请求中的错误
log("error", "getMiguAnimes error:", {
message: error.message,
name: error.name,
stack: error.stack,
});
return [];
}
}
extractEpId(url) {
// 先去除 ? 及其后的所有字符
const baseUrl = url.split('?')[0];
// 分割路径,获取最后一个 / 后的部分(非空)
const segments = baseUrl.split('/').filter(segment => segment !== '');
return segments[segments.length - 1] || '';
}
async getDetail(id) {
try {
const resp = await httpGet(`https://v3-sc.miguvideo.com/program/v4/cont/content-info/${id}/1`, {
headers: {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36"
}
});
// 判断 resp 和 resp.data 是否存在
if (!resp || !resp.data) {
log("info", "getMiguDetail: 请求失败或无数据返回");
return { duration: 0, epsID: null };
}
const duration = resp.data?.body?.data?.playing?.duration || 0;
const epsID = resp.data?.body?.data?.epsID || null;
return { duration, epsID };
} catch (error) {
// 捕获请求中的错误
log("error", "getMiguDetail error:", {
message: error.message,
name: error.name,
stack: error.stack,
});
return { duration: 0, epsID: null };
}
}
async getEpisodes(id) {
try {
const detailResp = await httpGet(id, {
headers: {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36"
}
});
// 判断 resp 和 resp.data 是否存在
if (!detailResp || !detailResp.data) {
log("info", "getMiguEposides: 请求失败或无数据返回");
return [];
}
const eps = detailResp.data?.body?.data?.datas;
if (eps) {
return eps;
} else {
// datas不存在,找playing/pID
const name = detailResp.data?.body?.data?.name;
const pID = detailResp.data?.body?.data?.playing?.pID;
if (pID) {
return [{
name,
pID
}];
}
log("info", "getMiguEposides: eps 不存在");
return [];
}
} catch (error) {
// 捕获请求中的错误
log("error", "getMiguEposides error:", {
message: error.message,
name: error.name,
stack: error.stack,
});
return [];
}
}
async handleAnimes(sourceAnimes, queryTitle, curAnimes) {
const tmpAnimes = [];
// 添加错误处理,确保sourceAnimes是数组
if (!sourceAnimes || !Array.isArray(sourceAnimes)) {
log("error", "[Migu] sourceAnimes is not a valid array");
return [];
}
// 使用 map 和 async 时需要返回 Promise 数组,并等待所有 Promise 完成
const processMiguAnimes = await Promise.all(sourceAnimes
.filter(s => titleMatches(s.name || s.title, queryTitle))
.map(async (anime) => {
try {
const eps = await this.getEpisodes(anime.url || anime.mediaId);
let links = [];
for (const ep of eps) {
links.push({
"name": ep.name,
"url": `https://webapi.miguvideo.com/gateway/live_barrage/videox/barrage/v2/list/${anime.epsId ?? ep.pID}/${ep.pID}`,
"title": `【migu】 ${ep.name}`
});
}
if (links.length > 0) {
let transformedAnime = {
animeId: convertToAsciiSum(anime.epsId ?? eps[0]?.pID),
bangumiId: String(anime.epsId ?? eps[0]?.pID),
animeTitle: `${anime.name || anime.title}(${anime.year})【${anime.type}】from migu`,
type: anime.type,
typeDescription: anime.type,
imageUrl: anime.img ?? anime.imageUrl,
startDate: generateValidStartDate(anime.year),
episodeCount: links.length,
rating: 0,
isFavorited: true,
source: "migu",
};
tmpAnimes.push(transformedAnime);
addAnime({...transformedAnime, links: links});
if (globals.animes.length > globals.MAX_ANIMES) removeEarliestAnime();
}
} catch (error) {
log("error", `[Migu] Error processing anime: ${error.message}`);
}
})
);
this.sortAndPushAnimesByYear(tmpAnimes, curAnimes);
return processMiguAnimes;
}
async getEpisodeDanmu(id) {
log("info", "开始从本地请求咪咕视频弹幕...", id);
// 获取弹幕分段数据
const segmentResult = await this.getEpisodeDanmuSegments(id);
if (!segmentResult || !segmentResult.segmentList || segmentResult.segmentList.length === 0) {
return [];
}
const segmentList = segmentResult.segmentList;
log("info", `弹幕分段数量: ${segmentList.length}`);
// 并发请求所有弹幕段,限制并发数量为50
const MAX_CONCURRENT = 100;
const allComments = [];
// 将segmentList分批处理,每批最多MAX_CONCURRENT个请求
for (let i = 0; i < segmentList.length; i += MAX_CONCURRENT) {
const batch = segmentList.slice(i, i + MAX_CONCURRENT);
// 并发处理当前批次的请求
const batchPromises = batch.map(segment => this.getEpisodeSegmentDanmu(segment));
const batchResults = await Promise.allSettled(batchPromises);
// 处理结果
for (let j = 0; j < batchResults.length; j++) {
const result = batchResults[j];
const segment = batch[j];
const start = segment.segment_start;
const end = segment.segment_end;
if (result.status === 'fulfilled') {
const comments = result.value;
if (comments && comments.length > 0) {
allComments.push(...comments);
}
} else {
log("error", `获取弹幕段失败 (${start}-${end}s):`, result.reason.message);
}
}
// 批次之间稍作延迟,避免过于频繁的请求
if (i + MAX_CONCURRENT < segmentList.length) {
await new Promise(resolve => setTimeout(resolve, 200));
}
}
if (allComments.length === 0) {
log("info", `咪咕视频: 该视频暂无弹幕数据 (vid=${id})`);
return [];
}
printFirst200Chars(allComments);
return allComments;
}
async getEpisodeDanmuSegments(id) {
log("info", "获取咪咕视频弹幕分段列表...", id);
const itemId = this.extractEpId(id);
const detail = await this.getDetail(itemId);
const durationSec = time_to_second(detail.duration);
log("info", "itemId:", itemId);
log("info", "durationSec:", durationSec);
log("info", "epsID:", detail.epsID);
const segmentDuration = 30; // 每个分片30秒钟
const segmentList = [];
for (let i = 0; i < durationSec; i += segmentDuration) {
const segmentStart = i; // 转换为毫秒
const segmentEnd = Math.min(i + segmentDuration, durationSec); // 不超过总时长
const danmuUrl = `https://webapi.miguvideo.com/gateway/live_barrage/videox/barrage/v2/list/${detail.epsID ?? itemId}/${itemId}/${segmentStart}/${segmentEnd}/020`;
segmentList.push({
"type": "migu",
"segment_start": segmentStart,
"segment_end": segmentEnd,
"url": danmuUrl
});
}
return new SegmentListResponse({
"type": "migu",
"segmentList": segmentList
});
}
async getEpisodeSegmentDanmu(segment) {
try {
const response = await httpGet(segment.url, {
headers: {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
"appCode": "miguvideo_default_h5"
},
retries: 1,
});
// 处理响应数据并返回 contents 格式的弹幕
let contents = [];
if (response && response.data) {
const decodeData = await decrypt(response.data);
const parsedData = typeof response.data === "string" ? JSON.parse(decodeData) : decodeData;
const danmakuList = parsedData?.body?.result ?? [];
contents.push(...danmakuList);
}
return contents;
} catch (error) {
log("error", "请求分片弹幕失败:", error);
return []; // 返回空数组而不是抛出错误,保持与getEpisodeDanmu一致的行为
}
}
formatComments(comments) {
return comments.map(c => ({
cid: Number(c.cid),
p: `${c.playtime},1,${hexToInt(c.textcolor)},[migu]`,
m: c.msg,
t: c.playtime
}));
}
}
export default MiguSource;
+3 -3
View File
@@ -82,7 +82,7 @@ class XiguaSource extends BaseSource {
}
// 正常情况下输出 JSON 字符串
log("info", `xiguaSearchresp: ${JSON.stringify(animes)}`);
log("info", `[Xigua] 搜索找到 ${animes.length} 个有效结果`);
return animes;
} catch (error) {
// 捕获请求中的错误
@@ -111,7 +111,7 @@ class XiguaSource extends BaseSource {
// 判断 resp 和 resp.data 是否存在
if (!resp || !resp.data) {
log("info", "getXiguaDetail: 请求失败或无数据返回");
return [];
return 0;
}
const match = resp.data.match(/"duration"\s*:\s*([\d.]+)/);
@@ -123,7 +123,7 @@ class XiguaSource extends BaseSource {
name: error.name,
stack: error.stack,
});
return [];
return 0;
}
}
+19 -3
View File
@@ -8,7 +8,8 @@
- [2. 日志查看](#2-日志查看)
- [3. 接口调试](#3-接口调试)
- [4. 推送弹幕](#4-推送弹幕)
- [5. 系统配置](#5-系统配置)
- [5. 请求记录](#5-请求记录)
- [6. 系统配置](#6-系统配置)
- [安全说明](#安全说明)
- [部署平台支持](#部署平台支持)
- [部署平台环境变量配置指南](#部署平台环境变量配置指南)
@@ -33,7 +34,8 @@ UI 系统提供了以下主要功能模块:
2. **日志查看** - 实时查看系统运行日志
3. **接口调试** - 测试和调试 API 接口
4. **推送弹幕** - 向播放器推送弹幕
5. **系统配置** - 环境变量配置和系统管理
5. **请求记录** - 查看最近的 API 请求记录
6. **系统配置** - 环境变量配置和系统管理
## 访问方式
@@ -83,7 +85,21 @@ UI 系统需要通过在 URL 中添加 TOKEN 来访问,以确保安全性:
- 推送地址格式如:`http://127.0.0.1:9978/action?do=refresh&type=danmaku&path=`
- 需要在同一局域网或使用公网 IP
### 5. 系统配置
### 5. 请求记录
请求记录页面提供:
- 查看最近一段时间内的 API 请求历史
- 显示每条请求的详细信息,包括:
- 请求时间
- 请求方法 (GET, POST, etc.)
- 请求 URL
- 请求参数
- 请求来源 IP
- 查看今日请求总数
### 6. 系统配置
系统配置页面包含:
+147
View File
@@ -940,4 +940,151 @@ export const componentsCssContent = /* css */ `
border-color: #eee;
box-shadow: none;
}
/* 请求记录样式 */
.request-records-container {
border-radius: 8px;
}
.no-records {
text-align: center;
color: #fff;
padding: 60px;
font-style: italic;
font-size: 16px;
}
.record-item {
background: linear-gradient(145deg, #ffffff 0%, #f8f9fa 100%);
border: none;
border-radius: 16px;
padding: 10px;
margin-bottom: 10px;
box-shadow: 0 8px 32px rgba(0,0,0,0.15);
transition: transform 0.2s, box-shadow 0.2s;
}
.record-item:hover {
transform: translateY(-2px);
box-shadow: 0 12px 40px rgba(0,0,0,0.2);
}
.record-header {
display: flex;
justify-content: flex-start;
align-items: center;
margin-bottom: 15px;
flex-wrap: wrap;
gap: 15px;
}
.record-method {
background: linear-gradient(135deg, #00b4db 0%, #0083b0 100%);
color: white;
padding: 8px 16px;
border-radius: 10px;
font-size: 14px;
font-weight: bold;
min-width: 60px;
text-align: center;
box-shadow: 0 4px 15px rgba(0,180,219,0.3);
}
.record-interface {
flex: 1;
font-family: 'Courier New', monospace;
font-weight: 600;
color: #2d3748;
word-break: break-all;
font-size: 15px;
background: #edf2f7;
padding: 8px 16px;
border-radius: 8px;
}
.record-ip {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: white;
padding: 8px 16px;
border-radius: 10px;
font-size: 13px;
min-width: 120px;
text-align: center;
font-weight: 500;
box-shadow: 0 4px 15px rgba(245,87,108,0.3);
}
.record-timestamp {
color: #718096;
font-size: 14px;
margin-bottom: 15px;
padding-bottom: 15px;
border-bottom: 2px dashed #e2e8f0;
display: flex;
align-items: center;
gap: 8px;
}
.record-timestamp.no-params {
border-bottom: none;
margin-bottom: 0;
padding-bottom: 0;
}
.record-timestamp::before {
content: '🕐';
font-size: 16px;
}
.record-params {
background: #f5f5f5;
border-radius: 12px;
padding: 15px;
border: 1px solid #e0e0e0;
}
.record-params-title {
color: #667eea;
font-weight: 600;
font-size: 14px;
margin-bottom: 12px;
display: flex;
align-items: center;
gap: 8px;
}
.record-params-title::before {
content: '📋';
font-size: 16px;
}
.record-params pre {
margin: 0;
padding: 15px;
background: #ffffff;
color: #333;
border-radius: 8px;
font-family: 'Courier New', monospace;
font-size: 13px;
white-space: pre-wrap;
word-wrap: break-word;
overflow-x: auto;
line-height: 1.6;
border: 1px solid #ddd;
}
/* 请求记录移动端适配 */
@media (max-width: 768px) {
.record-header {
flex-direction: column;
align-items: stretch;
}
.record-method,
.record-interface,
.record-ip {
width: 100%;
box-sizing: border-box;
}
}
`;
+4 -4
View File
@@ -363,8 +363,8 @@ function getDockerVersion() {
// 切换导航
function switchSection(section, event = null) {
// 检查是否尝试访问受token保护的section(日志查看、接口调试、系统配置需要token访问)
if (section === 'logs' || section === 'api' || section === 'env' || section === 'push') {
// 检查是否尝试访问受token保护的section(日志查看、接口调试、推送弹幕、请求记录、系统配置需要token访问)
if (section === 'logs' || section === 'api' || section === 'env' || section === 'push' || section === 'request-records') {
let _reverseProxy = customBaseUrl; // 使用全局配置
// 获取URL路径并提取token
@@ -443,7 +443,7 @@ function switchSection(section, event = null) {
event.target.classList.add('active');
}
addLog(\`切换到\${section === 'env' ? '环境变量' : section === 'preview' ? '配置预览' : section === 'logs' ? '日志查看' : section === 'push' ? '推送弹幕' : '接口调试'}模块\`, 'info');
addLog(\`切换到\${section === 'env' ? '环境变量' : section === 'preview' ? '配置预览' : section === 'logs' ? '日志查看' : section === 'push' ? '推送弹幕' : section === 'request-records' ? '请求记录' : '接口调试'}模块\`, 'info');
}
});
} else {
@@ -456,7 +456,7 @@ function switchSection(section, event = null) {
event.target.classList.add('active');
}
addLog(\`切换到\${section === 'env' ? '环境变量' : section === 'preview' ? '配置预览' : section === 'logs' ? '日志查看' : section === 'push' ? '推送弹幕' : '接口调试'}模块\`, 'info');
addLog(\`切换到\${section === 'env' ? '环境变量' : section === 'preview' ? '配置预览' : section === 'logs' ? '日志查看' : section === 'push' ? '推送弹幕' : section === 'request-records' ? '请求记录' : '接口调试'}模块\`, 'info');
// 如果切换到日志查看页面,则立即刷新日志
if (section === 'logs') {
+111
View File
@@ -0,0 +1,111 @@
// language=JavaScript
export const requestRecordsJsContent = /* javascript */ `
// 请求记录相关功能
async function renderRequestRecords() {
const recordsContainer = document.getElementById('request-records-list');
if (!recordsContainer) {
console.error('未找到请求记录容器');
return;
}
try {
// 从API获取请求记录
const response = await fetch(buildApiUrl('/api/reqrecords'));
if (!response.ok) {
throw new Error('获取请求记录失败');
}
const data = await response.json();
const records = data.records;
const todayReqNum = data.todayReqNum;
// 显示今日请求总数
const totalRequestsElement = document.getElementById('total-requests-today');
if (totalRequestsElement) {
totalRequestsElement.textContent = \`今日请求总数: \${todayReqNum}\`;
}
if (records.length === 0) {
recordsContainer.innerHTML = '<div class="no-records">暂无请求记录</div>';
return;
}
// 生成记录HTML
const recordsHtml = records.map(record => {
const interfaceName = decodeURIComponent(record.interface) || '未知接口';
const params = record.params || {};
const timestamp = record.timestamp ? new Date(record.timestamp).toLocaleString('zh-CN') : '未知时间';
const method = record.method || 'GET';
const clientIp = record.clientIp || '未知IP';
// 格式化参数显示
const hasParams = Object.keys(params).length > 0;
const paramsHtml = hasParams
? \`<div class="record-params">
<div class="record-params-title">请求参数</div>
<pre>\${JSON.stringify(params, null, 2)}</pre>
</div>\`
: '';
// 如果没有参数,给时间戳添加 no-params 类以隐藏虚线
const timestampClass = hasParams ? 'record-timestamp' : 'record-timestamp no-params';
return \`
<div class="record-item">
<div class="record-header">
<div class="record-method">\${method}</div>
<div class="record-interface">\${interfaceName}</div>
<div class="record-ip">\${clientIp}</div>
</div>
<div class="\${timestampClass}">\${timestamp}</div>
\${paramsHtml}
</div>\`;
}).join('');
recordsContainer.innerHTML = recordsHtml;
} catch (error) {
console.error('获取请求记录时出错:', error);
recordsContainer.innerHTML = '<div class="no-records">获取请求记录失败: ' + error.message + '</div>';
}
}
// 初始化请求记录界面
function initRequestRecordsInterface() {
// 确保在切换到请求记录标签页时也更新记录
const originalSwitchSection = window.switchSection;
if (originalSwitchSection && typeof originalSwitchSection === 'function') {
window.switchSection = function(section, event = null) {
// 调用原函数
originalSwitchSection(section, event);
// 如果切换到请求记录页面,则刷新记录
if (section === 'request-records') {
setTimeout(renderRequestRecords, 100);
}
};
}
// 首次初始化
if (document.getElementById('request-records-section') &&
document.querySelector('.nav-btn[data-section="request-records"]') &&
document.querySelector('.nav-btn[data-section="request-records"]').classList.contains('active')) {
renderRequestRecords();
}
}
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', function() {
if (typeof initRequestRecordsInterface === 'function') {
initRequestRecordsInterface();
}
// 添加刷新按钮功能
const refreshBtn = document.getElementById('refresh-request-records');
if (refreshBtn) {
refreshBtn.onclick = function() {
renderRequestRecords();
};
}
});
`;
+17 -1
View File
@@ -8,6 +8,7 @@ import { previewJsContent } from "./js/preview.js";
import { logviewJsContent } from "./js/logview.js";
import { apitestJsContent } from "./js/apitest.js";
import { pushDanmuJsContent } from "./js/pushdanmu.js";
import { requestRecordsJsContent } from "./js/requestrecords.js";
import { systemSettingsJsContent } from "./js/systemsettings.js";
// language=HTML
@@ -54,6 +55,7 @@ export const HTML_TEMPLATE = /* html */ `
<button class="nav-btn" onclick="switchSection('logs', event)">日志查看</button>
<button class="nav-btn" onclick="switchSection('api', event)">接口调试</button>
<button class="nav-btn" onclick="switchSection('push', event)">推送弹幕</button>
<button class="nav-btn" onclick="switchSection('request-records', event)">请求记录</button>
<button class="nav-btn" onclick="switchSection('env', event)" id="env-nav-btn">系统配置</button>
</div>
</div>
@@ -143,6 +145,19 @@ export const HTML_TEMPLATE = /* html */ `
<div id="push-episode-list" class="episode-list" style="display: none; margin-top: 20px;"></div>
</div>
<!-- 请求记录 -->
<div class="section" id="request-records-section">
<h2>请求记录</h2>
<div class="log-controls">
<div>
<button class="btn btn-primary" id="refresh-request-records">🔄 刷新记录</button>
<span id="total-requests-today" style="color: #ff5722; margin-left: 15px; vertical-align: middle; font-size: 1.2em; font-weight: bold;"></span>
</div>
<span style="color: #666;">云服务部署需要配置redis</span>
</div>
<div class="request-records-container" id="request-records-list"></div>
</div>
<!-- 系统配置 -->
<div class="section" id="env-section">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; flex-wrap: wrap; gap: 10px;">
@@ -288,7 +303,7 @@ export const HTML_TEMPLATE = /* html */ `
<!-- 项目声明 -->
<footer class="footer">
<p class="footer-text">
一个人人都能部署的基于 js 的弹幕 API 服务器,支持爱优腾芒哔人韩巴弹幕直接获取,兼容弹弹play的搜索、详情查询和弹幕获取接口规范,并提供日志记录,支持vercel/netlify/edgeone/cloudflare/docker/claw等部署方式,不用提前下载弹幕,没有nas或小鸡也能一键部署。
一个人人都能部署的基于 js 的弹幕 API 服务器,支持爱优腾芒哔咪人韩巴狐乐西弹幕直接获取,兼容弹弹play的搜索、详情查询和弹幕获取接口规范,并提供日志记录,支持vercel/netlify/edgeone/cloudflare/docker/claw等部署方式,不用提前下载弹幕,没有nas或小鸡也能一键部署。
</p>
<p class="footer-text">本项目仅为个人爱好开发,代码开源。如有任何侵权行为,请联系本人删除。</p>
<p class="footer-links">
@@ -309,6 +324,7 @@ export const HTML_TEMPLATE = /* html */ `
${logviewJsContent}
${apitestJsContent}
${pushDanmuJsContent}
${requestRecordsJsContent}
${systemSettingsJsContent}
</script>
</body>
+7 -1
View File
@@ -346,6 +346,8 @@ export async function getLocalCaches() {
globals.animes = JSON.parse(readCacheFromFile('animes')) || globals.animes;
globals.episodeIds = JSON.parse(readCacheFromFile('episodeIds')) || globals.episodeIds;
globals.episodeNum = JSON.parse(readCacheFromFile('episodeNum')) || globals.episodeNum;
globals.reqRecords = JSON.parse(readCacheFromFile('reqRecords')) || globals.reqRecords;
globals.todayReqNum = JSON.parse(readCacheFromFile('todayReqNum')) || globals.todayReqNum;
// 恢复 lastSelectMap 并转换为 Map 对象
const lastSelectMapData = readCacheFromFile('lastSelectMap');
@@ -358,6 +360,8 @@ export async function getLocalCaches() {
globals.lastHashes.animes = simpleHash(JSON.stringify(globals.animes));
globals.lastHashes.episodeIds = simpleHash(JSON.stringify(globals.episodeIds));
globals.lastHashes.episodeNum = simpleHash(JSON.stringify(globals.episodeNum));
globals.lastHashes.reqRecords = simpleHash(JSON.stringify(globals.reqRecords));
globals.lastHashes.todayReqNum = simpleHash(JSON.stringify(globals.todayReqNum));
globals.lastHashes.lastSelectMap = simpleHash(JSON.stringify(Object.fromEntries(globals.lastSelectMap)));
globals.localCacheInitialized = true;
@@ -380,7 +384,9 @@ export async function updateLocalCaches() {
{ key: 'animes', value: globals.animes },
{ key: 'episodeIds', value: globals.episodeIds },
{ key: 'episodeNum', value: globals.episodeNum },
{ key: 'lastSelectMap', value: globals.lastSelectMap }
{ key: 'reqRecords', value: globals.reqRecords },
{ key: 'lastSelectMap', value: globals.lastSelectMap },
{ key: 'todayReqNum', value: globals.todayReqNum }
];
for (const { key, value } of variables) {
+2 -2
View File
@@ -472,7 +472,7 @@ function BufferBase64Decode(b64) {
// ====================== 主函数 ======================
// Uint8Array UTF-8 解码成字符串,替代 TextDecoder
function utf8BytesToString(bytes) {
export function utf8BytesToString(bytes) {
let str = "";
let i = 0;
while (i < bytes.length) {
@@ -503,7 +503,7 @@ function utf8BytesToString(bytes) {
}
// 同时替换 TextEncoder
function stringToUtf8Bytes(str) {
export function stringToUtf8Bytes(str) {
const bytes = [];
for (let i = 0; i < str.length; i++) {
let code = str.charCodeAt(i);
+9
View File
@@ -332,6 +332,15 @@ export function rgbToInt(color) {
return color.r * 256 * 256 + color.g * 256 + color.b;
}
// 解析 hex 到 int(假设不带 #)
export function hexToInt(hex) {
// 简单校验:确保是 6 位 hex 字符串(不带 #)
if (typeof hex !== 'string' || hex.length !== 6 || !/^[0-9A-Fa-f]{6}$/.test(hex)) {
return 16777215; // 无效输入,返回 16777215 白色
}
return parseInt(hex, 16); // 直接转换为整数
}
// 将弹幕 JSON 数据转换为 XML 格式(Bilibili 标准格式)
export function convertDanmuToXml(danmuData) {
let xml = '<?xml version="1.0" ?>\n';
+869
View File
@@ -0,0 +1,869 @@
#!/usr/bin/env node
/**
* Gateway Crypto WASM Decryptor
* Based on vue_mgvendor.js analysis
*
* Decrypts Migu Video API responses using gateway-crypto.wasm
*
* Usage: node gateway_decrypt.js <encrypted_data> [key]
* - encrypted_data: Base64 encoded encrypted string
* - key: Optional Base64 encoded key (uses WASM default if not provided)
*/
import { stringToUtf8Bytes, utf8BytesToString } from "./codec-util.js";
// WASM binary embedded as base64 (from gateway-crypto.wasm)
const WASM_BASE64 = `
AGFzbQEAAAABWA5gAn9/AX9gA39/fwF/YAJ/fwBgA39/fwBgAX8Bf2ABfwBgBX9/f39/AX9gBX9/f39/AGAAAX9gBH9/f38AYAR/
f39/AX9gAn5/AX9gBn9/f39/fwBgAAACXAMDd2JnGl9fd2JpbmRnZW5fb2JqZWN0X2Ryb3BfcmVmAAUDd2JnFV9fd2JpbmRnZW5f
c3RyaW5nX25ldwAAA3diZxdfX3diaW5kZ2VuX2RlYnVnX3N0cmluZwACA4gBhgEEAgUBAAIGBQMFAQMBAgMCAwMCAgAGAAsABQIB
CAcHAAIHBgMJAwwDAAMDCQAAAAACBwIDAwMDAAIDAwUAAQIBAwAABg0CCgAAAgUFAwIFBAQCAQAFAAoDBAAAAAAAAgICAgQABAQE
BAIEAAAEBQAAAAQEBAQAAAIAAAECAgABAQgAAAQEBQQFAXABOTkFAwEAEQYJAX8BQYCAwAALB58BCQZtZW1vcnkCAAZlbnNpZ24A
JA9nYXRld2F5X2VuY3J5cHQAIA9nYXRld2F5X2RlY3J5cHQAIQdnZXRfa2V5AIMBEV9fd2JpbmRnZW5fbWFsbG9jAEUSX193Ymlu
ZGdlbl9yZWFsbG9jAEkfX193YmluZGdlbl9hZGRfdG9fc3RhY2tfcG9pbnRlcgBvD19fd2JpbmRnZW5fZnJlZQBaCUgBAEEBCzhw
RF5fL4gBKzJXMYgBcnFfiAFKS247UUAZc2OIAWJBZE4jM4gBYYgBSlFCe3mIAVZ4UTptXWaIAWGIAQ8/fIABGyIKv+YChgG+IQIP
fwF+IwBBEGsiCyQAAkACQAJ/AkAgAEH1AU8EQEEIQQgQWCEGQRRBCBBYIQVBEEEIEFghAUEAQRBBCBBYQQJ0ayICQYCAfCABIAUg
Bmpqa0F3cUEDayIBIAEgAksbIABNDQQgAEEEakEIEFghBEG0psAAKAIARQ0DQQAgBGshAwJ/QQAgBEGAAkkNABpBHyAEQf///wdL
DQAaIARBBiAEQQh2ZyIAa3ZBAXEgAEEBdGtBPmoLIgZBAnRBmKPAAGooAgAiAUUEQEEAIQBBACEFDAILIAQgBhBTdCEHQQAhAEEA
IQUDQAJAIAEQdCICIARJDQAgAiAEayICIANPDQAgASEFIAIiAw0AQQAhAyABIQBBAAwECyABQRRqKAIAIgIgACACIAEgB0EddkEE
cWpBEGooAgAiAUcbIAAgAhshACAHQQF0IQcgAQ0ACwwBC0EQIABBBGpBEEEIEFhBBWsgAEsbQQgQWCEEQbCmwAAoAgAiASAEQQN2
IgB2IgJBA3EEQAJAIAJBf3NBAXEgAGoiA0EDdCIAQbCkwABqKAIAIgVBCGooAgAiAiAAQaikwABqIgBHBEAgAiAANgIMIAAgAjYC
CAwBC0GwpsAAIAFBfiADd3E2AgALIAUgA0EDdBBQIAUQhgEhAwwECyAEQbimwAAoAgBNDQICQAJAAkACQAJAAkAgAkUEQEG0psAA
KAIAIgBFDQkgABBpaEECdEGYo8AAaigCACIBEHQgBGshAyABEFIiAARAA0AgABB0IARrIgIgAyACIANJIgIbIQMgACABIAIbIQEg
ABBSIgANAAsLIAEgBBCEASEFIAEQHEEQQQgQWCADSw0CIAEgBBBrIAUgAxBUQbimwAAoAgAiAA0BDAULAkBBASAAQR9xIgB0EFsg
AiAAdHEQaWgiAkEDdCIAQbCkwABqKAIAIgNBCGooAgAiASAAQaikwABqIgBHBEAgASAANgIMIAAgATYCCAwBC0GwpsAAQbCmwAAo
AgBBfiACd3E2AgALIAMgBBBrIAMgBBCEASIFIAJBA3QgBGsiAhBUQbimwAAoAgAiAA0CDAMLIABBeHFBqKTAAGohB0HApsAAKAIA
IQYCf0GwpsAAKAIAIgJBASAAQQN2dCIAcUUEQEGwpsAAIAAgAnI2AgAgBwwBCyAHKAIICyEAIAcgBjYCCCAAIAY2AgwgBiAHNgIM
IAYgADYCCAwDCyABIAMgBGoQUAwDCyAAQXhxQaikwABqIQdBwKbAACgCACEGAn9BsKbAACgCACIBQQEgAEEDdnQiAHFFBEBBsKbA
ACAAIAFyNgIAIAcMAQsgBygCCAshACAHIAY2AgggACAGNgIMIAYgBzYCDCAGIAA2AggLQcCmwAAgBTYCAEG4psAAIAI2AgAgAxCG
ASEDDAULQcCmwAAgBTYCAEG4psAAIAM2AgALIAEQhgEiA0UNAgwDCyAAIAVyRQRAQQAhBUEBIAZ0EFtBtKbAACgCAHEiAEUNAiAA
EGloQQJ0QZijwABqKAIAIQALQQELIQEDQCABRQRAIAUgACAFIAAQdCIBIARrIgYgA0kiAhsgASAESSIBGyEFIAMgBiADIAIbIAEb
IQMgABBSIQBBASEBDAELIAAEQEEAIQEMAQUgBUUNAiAEQbimwAAoAgAiAE0gAyAAIARrT3ENAiAFIAQQhAEhBiAFEBwCQEEQQQgQ
WCADTQRAIAUgBBBrIAYgAxBUIANBgAJPBEAgBiADEB0MAgsgA0F4cUGopMAAaiECAn9BsKbAACgCACIBQQEgA0EDdnQiAHFFBEBB
sKbAACAAIAFyNgIAIAIMAQsgAigCCAshACACIAY2AgggACAGNgIMIAYgAjYCDCAGIAA2AggMAQsgBSADIARqEFALIAUQhgEiAw0D
CwsLAkACQCAEQbimwAAoAgAiAEsEQCAEQbymwAAoAgAiAE8EQEEIQQgQWCAEakEUQQgQWGpBEEEIEFhqQYCABBBYIgBBEHZAACEC
IAtBBGoiAUEANgIIIAFBACAAQYCAfHEgAkF/RiIAGzYCBCABQQAgAkEQdCAAGzYCACALKAIEIghFBEBBACEDDAULIAsoAgwhDEHI
psAAIAsoAggiCkHIpsAAKAIAaiIBNgIAQcymwABBzKbAACgCACIAIAEgACABSxs2AgACQEHEpsAAKAIABEBBmKTAACEAA0AgABBs
IAhGDQIgACgCCCIADQALDAQLQdSmwAAoAgAiAEEAIAAgCE0bRQRAQdSmwAAgCDYCAAtB2KbAAEH/HzYCAEGkpMAAIAw2AgBBnKTA
ACAKNgIAQZikwAAgCDYCAEG0pMAAQaikwAA2AgBBvKTAAEGwpMAANgIAQbCkwABBqKTAADYCAEHEpMAAQbikwAA2AgBBuKTAAEGw
pMAANgIAQcykwABBwKTAADYCAEHApMAAQbikwAA2AgBB1KTAAEHIpMAANgIAQcikwABBwKTAADYCAEHcpMAAQdCkwAA2AgBB0KTA
AEHIpMAANgIAQeSkwABB2KTAADYCAEHYpMAAQdCkwAA2AgBB7KTAAEHgpMAANgIAQeCkwABB2KTAADYCAEH0pMAAQeikwAA2AgBB
6KTAAEHgpMAANgIAQfCkwABB6KTAADYCAEH8pMAAQfCkwAA2AgBB+KTAAEHwpMAANgIAQYSlwABB+KTAADYCAEGApcAAQfikwAA2
AgBBjKXAAEGApcAANgIAQYilwABBgKXAADYCAEGUpcAAQYilwAA2AgBBkKXAAEGIpcAANgIAQZylwABBkKXAADYCAEGYpcAAQZCl
wAA2AgBBpKXAAEGYpcAANgIAQaClwABBmKXAADYCAEGspcAAQaClwAA2AgBBqKXAAEGgpcAANgIAQbSlwABBqKXAADYCAEG8pcAA
QbClwAA2AgBBsKXAAEGopcAANgIAQcSlwABBuKXAADYCAEG4pcAAQbClwAA2AgBBzKXAAEHApcAANgIAQcClwABBuKXAADYCAEHU
pcAAQcilwAA2AgBByKXAAEHApcAANgIAQdylwABB0KXAADYCAEHQpcAAQcilwAA2AgBB5KXAAEHYpcAANgIAQdilwABB0KXAADYC
AEHspcAAQeClwAA2AgBB4KXAAEHYpcAANgIAQfSlwABB6KXAADYCAEHopcAAQeClwAA2AgBB/KXAAEHwpcAANgIAQfClwABB6KXA
ADYCAEGEpsAAQfilwAA2AgBB+KXAAEHwpcAANgIAQYymwABBgKbAADYCAEGApsAAQfilwAA2AgBBlKbAAEGIpsAANgIAQYimwABB
gKbAADYCAEGcpsAAQZCmwAA2AgBBkKbAAEGIpsAANgIAQaSmwABBmKbAADYCAEGYpsAAQZCmwAA2AgBBrKbAAEGgpsAANgIAQaCm
wABBmKbAADYCAEGopsAAQaCmwAA2AgBBCEEIEFghBUEUQQgQWCECQRBBCBBYIQFBxKbAACAIIAgQhgEiAEEIEFggAGsiABCEASID
NgIAQbymwAAgCkEIaiABIAIgBWpqIABqayIFNgIAIAMgBUEBcjYCBEEIQQgQWCECQRRBCBBYIQFBEEEIEFghACADIAUQhAEgACAB
IAJBCGtqajYCBEHQpsAAQYCAgAE2AgAMBAsgABB2DQIgABB3IAxHDQIgACgCACICQcSmwAAoAgAiAU0EfyACIAAoAgRqIAFLBUEA
C0UNAiAAIAAoAgQgCmo2AgRBvKbAACgCACAKaiEBQcSmwAAoAgAiACAAEIYBIgBBCBBYIABrIgAQhAEhA0G8psAAIAEgAGsiBTYC
AEHEpsAAIAM2AgAgAyAFQQFyNgIEQQhBCBBYIQJBFEEIEFghAUEQQQgQWCEAIAMgBRCEASAAIAEgAkEIa2pqNgIEQdCmwABBgICA
ATYCAAwDC0G8psAAIAAgBGsiATYCAEHEpsAAQcSmwAAoAgAiAiAEEIQBIgA2AgAgACABQQFyNgIEIAIgBBBrIAIQhgEhAwwDC0HA
psAAKAIAIQJBEEEIEFggACAEayIBTQRAIAIgBBCEASEAQbimwAAgATYCAEHApsAAIAA2AgAgACABEFQgAiAEEGsgAhCGASEDDAML
QcCmwABBADYCAEG4psAAKAIAIQBBuKbAAEEANgIAIAIgABBQIAIQhgEhAwwCC0HUpsAAQdSmwAAoAgAiACAIIAAgCEkbNgIAIAgg
CmohAUGYpMAAIQACQANAIAEgACgCAEcEQCAAKAIIIgANAQwCCwsgABB2DQAgABB3IAxHDQAgACgCACEDIAAgCDYCACAAIAAoAgQg
Cmo2AgQgCBCGASIFQQgQWCECIAMQhgEiAUEIEFghACAIIAIgBWtqIgYgBBCEASEHIAYgBBBrIAMgACABa2oiACAEIAZqayEEAkBB
xKbAACgCACAARwRAIABBwKbAACgCAEYNASAAKAIEQQNxQQFGBEACQCAAEHQiBUGAAk8EQCAAEBwMAQsgAEEMaigCACICIABBCGoo
AgAiAUcEQCABIAI2AgwgAiABNgIIDAELQbCmwABBsKbAACgCAEF+IAVBA3Z3cTYCAAsgBCAFaiEEIAAgBRCEASEACyAHIAQgABBP
IARBgAJPBEAgByAEEB0gBhCGASEDDAULIARBeHFBqKTAAGohAgJ/QbCmwAAoAgAiAUEBIARBA3Z0IgBxRQRAQbCmwAAgACABcjYC
ACACDAELIAIoAggLIQAgAiAHNgIIIAAgBzYCDCAHIAI2AgwgByAANgIIIAYQhgEhAwwEC0HEpsAAIAc2AgBBvKbAAEG8psAAKAIA
IARqIgA2AgAgByAAQQFyNgIEIAYQhgEhAwwDC0HApsAAIAc2AgBBuKbAAEG4psAAKAIAIARqIgA2AgAgByAAEFQgBhCGASEDDAIL
QcSmwAAoAgAhCUGYpMAAIQACQANAIAkgACgCAE8EQCAAEGwgCUsNAgsgACgCCCIADQALQQAhAAsgCSAAEGwiBkEUQQgQWCIPa0EX
ayIBEIYBIgBBCBBYIABrIAFqIgAgAEEQQQgQWCAJakkbIg0QhgEhDiANIA8QhAEhAEEIQQgQWCEDQRRBCBBYIQVBEEEIEFghAkHE
psAAIAggCBCGASIBQQgQWCABayIBEIQBIgc2AgBBvKbAACAKQQhqIAIgAyAFamogAWprIgM2AgAgByADQQFyNgIEQQhBCBBYIQVB
FEEIEFghAkEQQQgQWCEBIAcgAxCEASABIAIgBUEIa2pqNgIEQdCmwABBgICAATYCACANIA8Qa0GYpMAAKQIAIRAgDkEIakGgpMAA
KQIANwIAIA4gEDcCAEGkpMAAIAw2AgBBnKTAACAKNgIAQZikwAAgCDYCAEGgpMAAIA42AgADQCAAQQQQhAEgAEEHNgIEIgBBBGog
BkkNAAsgCSANRg0AIAkgDSAJayIAIAkgABCEARBPIABBgAJPBEAgCSAAEB0MAQsgAEF4cUGopMAAaiECAn9BsKbAACgCACIBQQEg
AEEDdnQiAHFFBEBBsKbAACAAIAFyNgIAIAIMAQsgAigCCAshACACIAk2AgggACAJNgIMIAkgAjYCDCAJIAA2AggLQQAhA0G8psAA
KAIAIgAgBE0NAEG8psAAIAAgBGsiATYCAEHEpsAAQcSmwAAoAgAiAiAEEIQBIgA2AgAgACABQQFyNgIEIAIgBBBrIAIQhgEhAwsg
C0EQaiQAIAMLrRABGH8gACABKAIQIgkgASgCICIHIAEoAjAiCiABKAIAIgsgASgCJCIMIAEoAjQiDSABKAIEIg4gASgCFCIPIA0g
DCAPIA4gCiAHIAkgCyAAKAIAIhkgACgCCCIQIAAoAgQiCHFqIAAoAgwiGCAIQX9zcWpqQYi31cQCa0EHdyAIaiICaiAOIBhqIBAg
AkF/c3FqIAIgCHFqQaqR4bkBa0EMdyACaiIDIAggASgCDCIRaiACIAMgECABKAIIIhJqIAggA0F/c3FqIAIgA3FqQdvhgaECakER
d2oiBUF/c3FqIAMgBXFqQZLiiPIDa0EWdyAFaiIEQX9zcWogBCAFcWpB0eCP1ABrQQd3IARqIgJqIAMgD2ogBSACQX9zcWogAiAE
cWpBqoyfvARqQQx3IAJqIgMgASgCHCITIARqIAIgAyABKAIYIhQgBWogBCADQX9zcWogAiADcWpB7fO+vgVrQRF3aiIFQX9zcWog
AyAFcWpB/9XlFWtBFncgBWoiAkF/c3FqIAIgBXFqQdixgswGakEHdyACaiIEaiADIAxqIAUgBEF/c3FqIAIgBHFqQdGQ7KUHa0EM
dyAEaiIDIAEoAiwiFSACaiAEIAMgASgCKCIWIAVqIAIgA0F/c3FqIAMgBHFqQc/IAmtBEXdqIgJBf3NxaiACIANxakHC0Iy1B2tB
FncgAmoiBUF/c3FqIAIgBXFqQaKiwNwGakEHdyAFaiIGaiABKAI4IhcgAmogBSADIA1qIAIgBkF/c3FqIAUgBnFqQe2cnhNrQQx3
IAZqIgRBf3MiAnFqIAQgBnFqQfL4mswFa0ERdyAEaiIDIAJxaiAFIAEoAjwiBWogBiADQX9zIgFxaiADIARxakGhkNDNBGpBFncg
A2oiBiAEcWpBnrWHzwBrQQV3IAZqIgJqIAMgFWogAiAGQX9zcWogBCAUaiABIAZxaiACIANxakHAmf39A2tBCXcgAmoiBCAGcWpB
0bT5sgJqQQ53IARqIgMgBEF/c3FqIAYgC2ogBCACQX9zcWogAiADcWpB1vCksgFrQRR3IANqIgIgBHFqQaPfw84Ca0EFdyACaiIB
aiADIAVqIAEgAkF/c3FqIAQgFmogAiADQX9zcWogASADcWpB06iQEmpBCXcgAWoiBCACcWpB/7L4ugJrQQ53IARqIgMgBEF/c3Fq
IAIgCWogBCABQX9zcWogASADcWpBuIiwwQFrQRR3IANqIgIgBHFqQeabh48CakEFdyACaiIBaiADIBFqIAEgAkF/c3FqIAQgF2og
AiADQX9zcWogASADcWpBqvCj5gNrQQl3IAFqIgQgAnFqQfnkq9kAa0EOdyAEaiIDIARBf3NxaiACIAdqIAQgAUF/c3FqIAEgA3Fq
Qe2p6KoEakEUdyADaiICIARxakH7rfCwBWtBBXcgAmoiAWogAiAKaiAEIBJqIAIgA0F/c3FqIAEgA3FqQYi4wRhrQQl3IAFqIgYg
AUF/c3FqIAMgE2ogASACQX9zcWogAiAGcWpB2YW8uwZqQQ53IAZqIgQgAXFqQfbm1pYHa0EUdyAEaiIDIARzIgEgBnNqQb6NF2tB
BHcgA2oiAmogBCAVaiACIAYgB2ogASACc2pB/5K4xAdrQQt3IAJqIgJzIgEgA3NqQaLC9ewGakEQdyACaiIEIAJzIAMgF2ogASAE
c2pB9I/rEGtBF3cgBGoiB3NqQbyrhNoFa0EEdyAHaiIBaiAEIBNqIAIgCWogBCAHcyABc2pBqZ/73gRqQQt3IAFqIgQgASAHc3Nq
QaDpksoAa0EQdyAEaiIDIARzIAcgFmogASAEcyADc2pBkIeBigRrQRd3IANqIgJzakHG/e3EAmpBBHcgAmoiAWogAyARaiAEIAtq
IAIgA3MgAXNqQYaw+6oBa0ELdyABaiIEIAEgAnNzakH7nsPYAmtBEHcgBGoiAyAEcyACIBRqIAEgBHMgA3NqQYW6oCRqQRd3IANq
IgJzakHH36yxAmtBBHcgAmoiAWogAiASaiAEIApqIAIgA3MgAXNqQZvMkckBa0ELdyABaiIEIAFzIAMgBWogASACcyAEc2pB+PmJ
/QFqQRB3IARqIgNzakGb087aA2tBF3cgA2oiAiAEQX9zciADc2pBvLvb3gBrQQZ3IAJqIgFqIAIgD2ogAyAXaiAEIBNqIAEgA0F/
c3IgAnNqQZf/q5kEakEKdyABaiIEIAJBf3NyIAFzakHZuK+jBWtBD3cgBGoiAyABQX9zciAEc2pBx7+xG2tBFXcgA2oiAiAEQX9z
ciADc2pBw7PtqgZqQQZ3IAJqIgFqIAIgDmogAyAWaiAEIBFqIAEgA0F/c3IgAnNqQe7mzIcHa0EKdyABaiIEIAJBf3NyIAFzakGD
l8AAa0EPdyAEaiICIAFBf3NyIARzakGvxO7TB2tBFXcgAmoiASAEQX9zciACc2pBz/yh/QZqQQZ3IAFqIgNqIAEgDWogAiAUaiAE
IAVqIAMgAkF/c3IgAXNqQaCyzA5rQQp3IANqIgIgAUF/c3IgA3NqQez5+ucFa0EPdyACaiIBIANBf3NyIAJzakGho6DwBGpBFXcg
AWoiBCACQX9zciABc2pB/oKyxQBrQQZ3IARqIgMgGWo2AgAgACAYIAIgFWogAyABQX9zciAEc2pBy5uUlgRrQQp3IANqIgJqNgIM
IAAgECABIBJqIAIgBEF/c3IgA3NqQbul39YCakEPdyACaiIBajYCCCAAIAEgCGogBCAMaiABIANBf3NyIAJzakHv2OSjAWtBFXdq
NgIEC5IHAQV/IAAQhwEiACAAEHQiARCEASECAkACQAJAAkACQAJAAkACQAJAIAAQdQ0AIAAoAgAhAyAAEGoNASABIANqIQEgACAD
EIUBIgBBwKbAACgCAEYEQCACKAIEQQNxQQNHDQFBuKbAACABNgIAIAAgASACEE8MCQsgA0GAAk8EQCAAEBwMAQsgAEEMaigCACIE
IABBCGooAgAiBUcEQCAFIAQ2AgwgBCAFNgIIDAELQbCmwABBsKbAACgCAEF+IANBA3Z3cTYCAAsgAhBlDQIgAkHEpsAAKAIARg0E
IAJBwKbAACgCAEcNAUHApsAAIAA2AgBBuKbAAEG4psAAKAIAIAFqIgI2AgAgACACEFQPCyABIANqQRBqIQAMBgsgAhB0IgMgAWoh
AQJAIANBgAJPBEAgAhAcDAELIAJBDGooAgAiBCACQQhqKAIAIgJHBEAgAiAENgIMIAQgAjYCCAwBC0GwpsAAQbCmwAAoAgBBfiAD
QQN2d3E2AgALIAAgARBUIABBwKbAACgCAEcNAUG4psAAIAE2AgAPCyAAIAEgAhBPCyABQYACSQ0BIAAgARAdQdimwABB2KbAACgC
AEEBayIANgIAIAANAxAfGg8LQcSmwAAgADYCAEG8psAAQbymwAAoAgAgAWoiAjYCACAAIAJBAXI2AgRBwKbAACgCACAARgRAQbim
wABBADYCAEHApsAAQQA2AgALIAJB0KbAACgCAE0NAkEIQQgQWCEAQRRBCBBYIQJBEEEIEFghA0EAQRBBCBBYQQJ0ayIBQYCAfCAD
IAAgAmpqa0F3cUEDayIAIAAgAUsbRQ0CQcSmwAAoAgBFDQJBCEEIEFghAEEUQQgQWCECQRBBCBBYIQFBACEDQbymwAAoAgAiBCAB
IAIgAEEIa2pqIgBNDQEgBCAAa0H//wNqQYCAfHEiBEGAgARrIQJBxKbAACgCACEBQZikwAAhAAJAA0AgASAAKAIATwRAIAAQbCAB
Sw0CCyAAKAIIIgANAAtBACEACyAAEHYNASAAKAIMGgwBCyABQXhxQaikwABqIQICf0GwpsAAKAIAIgNBASABQQN2dCIBcUUEQEGw
psAAIAEgA3I2AgAgAgwBCyACKAIICyEDIAIgADYCCCADIAA2AgwgACACNgIMIAAgAzYCCA8LEB9BACADa0cNAEG8psAAKAIAQdCm
wAAoAgBNDQBB0KbAAEF/NgIACwv0BgEIfwJAIAAoAgAiCiAAKAIIIgNyBEACQCADRQ0AIAEgAmohCCAAQQxqKAIAQQFqIQcgASEF
A0ACQCAFIQMgB0EBayIHRQ0AIAMgCEYNAgJ/IAMsAAAiBkEATgRAIAZB/wFxIQYgA0EBagwBCyADLQABQT9xIQkgBkEfcSEFIAZB
X00EQCAFQQZ0IAlyIQYgA0ECagwBCyADLQACQT9xIAlBBnRyIQkgBkFwSQRAIAkgBUEMdHIhBiADQQNqDAELIAVBEnRBgIDwAHEg
Ay0AA0E/cSAJQQZ0cnIiBkGAgMQARg0DIANBBGoLIgUgBCADa2ohBCAGQYCAxABHDQEMAgsLIAMgCEYNACADLAAAIgVBAE4gBUFg
SXIgBUFwSXJFBEAgBUH/AXFBEnRBgIDwAHEgAy0AA0E/cSADLQACQT9xQQZ0IAMtAAFBP3FBDHRycnJBgIDEAEYNAQsCQAJAIARF
DQAgAiAETQRAQQAhAyACIARGDQEMAgtBACEDIAEgBGosAABBQEgNAQsgASEDCyAEIAIgAxshAiADIAEgAxshAQsgCkUNASAAKAIE
IQgCQCACQRBPBEAgASACEAchAwwBCyACRQRAQQAhAwwBCyACQQNxIQcCQCACQQRJBEBBACEDQQAhBgwBCyACQXxxIQVBACEDQQAh
BgNAIAMgASAGaiIELAAAQb9/SmogBEEBaiwAAEG/f0pqIARBAmosAABBv39KaiAEQQNqLAAAQb9/SmohAyAFIAZBBGoiBkcNAAsL
IAdFDQAgASAGaiEFA0AgAyAFLAAAQb9/SmohAyAFQQFqIQUgB0EBayIHDQALCwJAIAMgCEkEQCAIIANrIQRBACEDAkACQAJAIAAt
ACBBAWsOAgABAgsgBCEDQQAhBAwBCyAEQQF2IQMgBEEBakEBdiEECyADQQFqIQMgAEEYaigCACEFIAAoAhAhBiAAKAIUIQADQCAD
QQFrIgNFDQIgACAGIAUoAhARAABFDQALQQEPCwwCC0EBIQMgACABIAIgBSgCDBEBAAR/IAMFQQAhAwJ/A0AgBCADIARGDQEaIANB
AWohAyAAIAYgBSgCEBEAAEUNAAsgA0EBawsgBEkLDwsgACgCFCABIAIgAEEYaigCACgCDBEBAA8LIAAoAhQgASACIABBGGooAgAo
AgwRAQAL1wYBCH8CQAJAIAEgAEEDakF8cSICIABrIghJDQAgASAIayIGQQRJDQAgBkEDcSEHQQAhAQJAIAAgAkYiCQ0AAkAgAiAA
QX9zakEDSQRADAELA0AgASAAIARqIgMsAABBv39KaiADQQFqLAAAQb9/SmogA0ECaiwAAEG/f0pqIANBA2osAABBv39KaiEBIARB
BGoiBA0ACwsgCQ0AIAAgAmshAyAAIARqIQIDQCABIAIsAABBv39KaiEBIAJBAWohAiADQQFqIgMNAAsLIAAgCGohBAJAIAdFDQAg
BCAGQXxxaiIALAAAQb9/SiEFIAdBAUYNACAFIAAsAAFBv39KaiEFIAdBAkYNACAFIAAsAAJBv39KaiEFCyAGQQJ2IQYgASAFaiED
A0AgBCEAIAZFDQJBwAEgBiAGQcABTxsiBUEDcSEHIAVBAnQhBEEAIQIgBUEETwRAIAAgBEHwB3FqIQggACEBA0AgAiABKAIAIgJB
f3NBB3YgAkEGdnJBgYKECHFqIAFBBGooAgAiAkF/c0EHdiACQQZ2ckGBgoQIcWogAUEIaigCACICQX9zQQd2IAJBBnZyQYGChAhx
aiABQQxqKAIAIgJBf3NBB3YgAkEGdnJBgYKECHFqIQIgAUEQaiIBIAhHDQALCyAGIAVrIQYgACAEaiEEIAJBCHZB/4H8B3EgAkH/
gfwHcWpBgYAEbEEQdiADaiEDIAdFDQALAn8gACAFQfwBcUECdGoiACgCACIBQX9zQQd2IAFBBnZyQYGChAhxIgEgB0EBRg0AGiAB
IAAoAgQiAUF/c0EHdiABQQZ2ckGBgoQIcWoiASAHQQJGDQAaIAAoAggiAEF/c0EHdiAAQQZ2ckGBgoQIcSABagsiAUEIdkH/gRxx
IAFB/4H8B3FqQYGABGxBEHYgA2oPCyABRQRAQQAPCyABQQNxIQQCQCABQQRJBEBBACECDAELIAFBfHEhBUEAIQIDQCADIAAgAmoi
ASwAAEG/f0pqIAFBAWosAABBv39KaiABQQJqLAAAQb9/SmogAUEDaiwAAEG/f0pqIQMgBSACQQRqIgJHDQALCyAERQ0AIAAgAmoh
AQNAIAMgASwAAEG/f0pqIQMgAUEBaiEBIARBAWsiBA0ACwsgAwunBgEGfyMAQeADayIFJAAgBUEAQeADEIEBIgUgASABEBQgBUEg
aiABQRBqIgEgARAUQcAAIQZBCCEHA0AgBSAHEDUgAyAFaiIBQUBrIgQQDCAEIAQoAgBBf3M2AgAgAUHEAGoiBCAEKAIAQX9zNgIA
IAFB1ABqIgQgBCgCAEF/czYCACABQdgAaiIEIAQoAgBBf3M2AgAgBSAGaiIEIAQoAgBBgIADczYCACAFIAdBCGoiB0EOECogA0GA
A0YEQCAFQeAAaiEHIAVBQGshAyAFQSBqIQZBAyEEA0AgBEEBayEEQQAhAQNAIAEgBmoiAiACKAIAIgIgAiACQQR2c0GAmLwYcSIC
QQR0cyACcyICIAIgAkECdnNBgOaAmANxIgJBAnRzIAJzNgIAIAFBBGoiAUEgRw0AC0EAIQEDQCABIANqIgIgAigCACICIAIgAkEE
dnNBgJ6A+ABxIgJBBHRzIAJzNgIAIAFBBGoiAUEgRw0AC0EAIQEDQCABIAdqIgIgAigCACICIAIgAkEEdnNBgIa84ABxIgJBBHRz
IAJzIgIgAiACQQJ2c0GA5oCYA3EiAkECdHMgAnM2AgAgAUEEaiIBQSBHDQALIAdBgAFqIQcgA0GAAWohAyAGQYABaiEGIAQNAAtB
oAMhAQNAIAEgBWoiAyADKAIAIgMgAyADQQR2c0GAmLwYcSIDQQR0cyADcyIDIAMgA0ECdnNBgOaAmANxIgNBAnRzIANzNgIAIAFB
BGoiAUHAA0cNAAtBACEDA0AgAyAFaiIBQSBqIgYgBigCAEF/czYCACABQSRqIgYgBigCAEF/czYCACABQTRqIgYgBigCAEF/czYC
ACABQThqIgEgASgCAEF/czYCACADQSBqIgNBwANHDQALIAAgBUHgAxCCARogBUHgA2okAAUgBSAHEDUgAUHgAGoiBBAMIAQgBCgC
AEF/czYCACABQeQAaiIEIAQoAgBBf3M2AgAgAUH0AGoiBCAEKAIAQX9zNgIAIAFB+ABqIgEgASgCAEF/czYCACAFIAdBCGoiB0EG
ECogBkHEAGohBiADQUBrIQMMAQsLC7QFAQh/QStBgIDEACAAKAIcIghBAXEiBhshDCAEIAZqIQYCQCAIQQRxRQRAQQAhAQwBCwJA
IAJBEE8EQCABIAIQByEFDAELIAJFBEAMAQsgAkEDcSEJAkAgAkEESQRADAELIAJBfHEhCgNAIAUgASAHaiILLAAAQb9/SmogC0EB
aiwAAEG/f0pqIAtBAmosAABBv39KaiALQQNqLAAAQb9/SmohBSAKIAdBBGoiB0cNAAsLIAlFDQAgASAHaiEHA0AgBSAHLAAAQb9/
SmohBSAHQQFqIQcgCUEBayIJDQALCyAFIAZqIQYLAkACQCAAKAIARQRAQQEhBSAAKAIUIgYgACgCGCIAIAwgASACEEYNAQwCCyAG
IAAoAgQiB08EQEEBIQUgACgCFCIGIAAoAhgiACAMIAEgAhBGDQEMAgsgCEEIcQRAIAAoAhAhCCAAQTA2AhAgAC0AICEKQQEhBSAA
QQE6ACAgACgCFCIJIAAoAhgiCyAMIAEgAhBGDQEgByAGa0EBaiEFAkADQCAFQQFrIgVFDQEgCUEwIAsoAhARAABFDQALQQEPC0EB
IQUgCSADIAQgCygCDBEBAA0BIAAgCjoAICAAIAg2AhBBACEFDAELIAcgBmshBgJAAkACQCAALQAgIgVBAWsOAwABAAILIAYhBUEA
IQYMAQsgBkEBdiEFIAZBAWpBAXYhBgsgBUEBaiEFIABBGGooAgAhCCAAKAIQIQogACgCFCEAAkADQCAFQQFrIgVFDQEgACAKIAgo
AhARAABFDQALQQEPC0EBIQUgACAIIAwgASACEEYNACAAIAMgBCAIKAIMEQEADQBBACEFA0AgBSAGRgRAQQAPCyAFQQFqIQUgACAK
IAgoAhARAABFDQALIAVBAWsgBkkPCyAFDwsgBiADIAQgACgCDBEBAAvYBAEcfyAAIAAoAggiBCAAKAIEIgVzIgwgACgCHCINIAAo
AhAiAXMiFiAAKAIYIgJzIhcgFnFzIAIgDXMiAyAAKAIMIgYgACgCACIHcyIIcyIJcyADIAUgB3MiCnMiEyABIAJzIg8gBCAAKAIU
IgRzIhBzIhlxIhRzIAYgF3MiFSABIAZzIgEgDHMiGHEgCSAYcyABcSILcyIOcyIRIA4gDyABIAdzIhpxIAIgBXMiBSAEIAZzcyIH
IAEgCnMiDnJzcyIScSICIAsgAyAJcXMiCyAHIA5xIAogD3MiCiAEcyIbIAUgCHMiHHFzIAFzIARzcyIGcyARIBQgCiANIBBzIhRx
IAhzcyALcyIEcyIIcSAEcyIFIAYgEnMiCyACIARzcSAGcyINcyIQIAFxIAogDXEiCnMgDSALIAQgEnFBf3NxIAJzIgFzIgQgE3Eg
AyACIAYgEXEgCHFzIAhzIgIgAXMiA3EiCHMiEXM2AgAgACAHIAIgBXMiB3EiBiAFIBtxIhJzIAMgEHMiEyAVcSIVIAMgCXEiA3Mi
CyAQIAkgDHNxIgwgByAOcSIHIAIgD3EiD3NzIg5zIglzNgIcIAAgDCACIBpxIgIgASAXcXMiDCAGIAUgHHFzc3MiBSADIA0gFHEi
AyABIBZxcyIBIA9zcyARc3M2AhggACABIApzIgEgB3MgC3MgBXM2AhQgACADIAQgGXEiA3MgCXM2AhAgACATIBhxIAJzIA5zIgIg
ASADIBJzIgEgCHNzczYCDCAAIAEgDHMgCXM2AgggACAGIBVzIAJzNgIEC9QFAgZ/An4CQCACRQ0AIAJBB2siA0EAIAIgA08bIQcg
AUEDakF8cSABayEIQQAhAwNAAkACQAJAIAEgA2otAAAiBcAiBkEATgRAIAggA2tBA3ENASADIAdPDQIDQCABIANqIgRBBGooAgAg
BCgCAHJBgIGChHhxDQMgA0EIaiIDIAdJDQALDAILQoCAgICAICEKQoCAgIAQIQkCQAJAAn4CQAJAAkACQAJAAkACQAJAAkAgBUGM
oMAAai0AAEECaw4DAAECCgsgA0EBaiIEIAJJDQJCACEKQgAhCQwJC0IAIQogA0EBaiIEIAJJDQJCACEJDAgLQgAhCiADQQFqIgQg
AkkNAkIAIQkMBwsgASAEaiwAAEG/f0oNBgwHCyABIARqLAAAIQQCQAJAIAVB4AFrIgUEQCAFQQ1GBEAMAgUMAwsACyAEQWBxQaB/
Rg0EDAMLIARBn39KDQIMAwsgBkEfakH/AXFBDE8EQCAGQX5xQW5HDQIgBEFASA0DDAILIARBQEgNAgwBCyABIARqLAAAIQQCQAJA
AkACQCAFQfABaw4FAQAAAAIACyAGQQ9qQf8BcUECSyAEQUBOcg0DDAILIARB8ABqQf8BcUEwTw0CDAELIARBj39KDQELIAIgA0EC
aiIETQRAQgAhCQwFCyABIARqLAAAQb9/Sg0CQgAhCSADQQNqIgQgAk8NBCABIARqLAAAQb9/TA0FQoCAgICA4AAMAwtCgICAgIAg
DAILQgAhCSADQQJqIgQgAk8NAiABIARqLAAAQb9/TA0DC0KAgICAgMAACyEKQoCAgIAQIQkLIAAgCiADrYQgCYQ3AgQgAEEBNgIA
DwsgBEEBaiEDDAILIANBAWohAwwBCyACIANNDQADQCABIANqLAAAQQBIDQEgAiADQQFqIgNHDQALDAILIAIgA0sNAAsLIAAgATYC
BCAAQQhqIAI2AgAgAEEANgIAC6YEARt/IAAgACgCHCIBIAAoAgQiBHMiByAAKAIQIgUgACgCCCIKcyIMcyIRIAAoAgxzIgggACgC
GCIGcyILIAEgBXMiEnMiCSAGIAAoAhRzIgJzIgMgBCACIAAoAgAiBHMiBnMiEyAGcXMgAyAHcSINcyAHcyAJIBJxIg4gAiAIIApz
IgJzIgggCXMiFyAMcXMiD3MiECAPIAIgEXEiDyALIAIgBHMiGCATIAEgCnMiCnMiGXFzc3MiFHEiCyAIIApxIA5zIg4gDyAFIAZz
Ig8gBHEgCnMgCHNzcyIFcyAOIA0gAyAEIAlzIg0gASAGcyIOcXNzIAFzcyIBIBBzcSIVIAtzIAFxIhYgEHMiECACcSIaIAQgASAV
cyIEcXMiFSAFIAEgC3MiAiAFIBRzIgVxcyIBIA1xcyADIAIgFnMgAXEgBXMiAyABcyILcSINcyIUIAMgE3FzIAwgAyAEIBBzIgJz
IgUgASAEcyIMcyITcSAMIBJxIhJzIhZzIhsgDSADIAZxcyIGIBMgF3FzIgMgByALcSIHIAUgCHEgFXNzcyIIczYCBCAAIAcgG3M2
AgAgACAWIAIgGXFzIgcgECARcXMiESADIAkgDHFzIglzNgIcIAAgCCABIA5xcyIDIAUgCnEgEnMgCXNzNgIUIAAgAiAYcSAacyAG
cyARcyIBNgIQIAAgByAEIA9xcyADczYCCCAAIAEgCXM2AhggACABIBRzNgIMC4YFAQp/IwBBMGsiAyQAIANBJGogATYCACADQQM6
ACwgA0EgNgIcIANBADYCKCADIAA2AiAgA0EANgIUIANBADYCDAJ/AkACQAJAIAIoAhAiCkUEQCACQQxqKAIAIgBFDQEgAigCCCEB
IABBA3QhBSAAQQFrQf////8BcUEBaiEHIAIoAgAhAANAIABBBGooAgAiBARAIAMoAiAgACgCACAEIAMoAiQoAgwRAQANBAsgASgC
ACADQQxqIAFBBGooAgARAAANAyABQQhqIQEgAEEIaiEAIAVBCGsiBQ0ACwwBCyACQRRqKAIAIgBFDQAgAEEFdCELIABBAWtB////
P3FBAWohByACKAIIIQggAigCACEAA0AgAEEEaigCACIBBEAgAygCICAAKAIAIAEgAygCJCgCDBEBAA0DCyADIAUgCmoiAUEQaigC
ADYCHCADIAFBHGotAAA6ACwgAyABQRhqKAIANgIoIAFBDGooAgAhBkEAIQlBACEEAkACQAJAIAFBCGooAgBBAWsOAgACAQsgBkED
dCAIaiIMKAIEQS1HDQEgDCgCACgCACEGC0EBIQQLIAMgBjYCECADIAQ2AgwgAUEEaigCACEEAkACQAJAIAEoAgBBAWsOAgACAQsg
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
EGoQPiAHKAIYIQEgBygCECEEQQAhA0EABUEBCzYCDCAAIAM2AgggACABNgIEIAAgBDYCACAHQSBqJAALjQIBAn8jAEEQayICJAAC
QCAAKAIAIgMtAABFBEAgASgCFEGNosAAQQQgAUEYaigCACgCDBEBACEADAELQQEhACACIANBAWo2AgAgAiABKAIUQZGiwABBBCAB
QRhqKAIAKAIMEQEAOgAMIAIgATYCCCACQQA6AA0gAkEANgIEIAJBBGogAkHsnMAAEB4gAi0ADCEBKAIAIgNFBEAgAUEARyEADAEL
IAENACACKAIIIQECQCADQQFHDQAgAi0ADUUNACABLQAcQQRxDQAgASgCFEHonMAAQQEgAUEYaigCACgCDBEBAA0BCyABKAIUQcSb
wABBASABQRhqKAIAKAIMEQEAIQALIAJBEGokACAAC/ABAgR/AX4jAEEwayICJAAgAUEEaiEEIAEoAgRFBEAgASgCACEDIAJBLGoi
BUEANgIAIAJCATcCJCACQSRqQaCXwAAgAxANGiACQSBqIAUoAgAiAzYCACACIAIpAiQiBjcDGCAEQQhqIAM2AgAgBCAGNwIACyAC
QRBqIgMgBEEIaigCADYCACABQQxqQQA2AgAgBCkCACEGIAFCATcCBEHdosAALQAAGiACIAY3AwhBDEEEEGAiAUUEQEEEQQwQegAL
IAEgAikDCDcCACABQQhqIAMoAgA2AgAgAEHQmMAANgIEIAAgATYCACACQTBqJAAL1wYBCn8jAEEQayIFJAAgBSACNgIIIAUgAjYC
BCAFIAE2AgAgBRA+IAUoAgghCyAFKAIAIQEgBSAENgIIIAUgBDYCBCAFIAM2AgAgBRA+IAUoAgAiDCEEIAUoAgghAyMAQfABayIC
JAAgAiALNgIEIAIgATYCACACIAM2AgwgAiAENgIIIAJBmAFqQYSJwABBLBATIAIoApgBRQRAIAIgAigCnAE2AkBB3IfAAEErIAJB
QGtBqIjAAEGwicAAEDQACyACQRhqIAJBoAFqKAIANgIAIAIgAikCmAE3AxAgAkHMAGpCAzcCACACQawBakEDNgIAIAJBpAFqIg1B
BDYCACACQQM2AkQgAkHAicAANgJAIAJBAzYCnAEgAiACQZgBaiIHNgJIIAIgAkEIajYCqAEgAiACQRBqIg42AqABIAIgAjYCmAEg
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
DAELIAAoAhRB4pzAAEEBIAAoAhgoAgwRAQALIAJBEGokACADQRBqJAALNwACQCABaUEBR0GAgICAeCABayAASXINACAABEBB3aLA
AC0AABogACABEGAiAUUNAQsgAQ8LAAs5AAJAAn8gAkGAgMQARwRAQQEgACACIAEoAhARAAANARoLIAMNAUEACw8LIAAgAyAEIAEo
AgwRAQALPwEBfyMAQSBrIgAkACAAQRRqQgA3AgAgAEEBNgIMIABBgJrAADYCCCAAQbiZwAA2AhAgAEEIakGImsAAEEgAC8kCAQJ/
IwBBIGsiAiQAIAJBATsBHCACIAE2AhggAiAANgIUIAJB1JvAADYCECACQcSbwAA2AgwjAEEQayIBJAACQCACQQxqIgAoAgwiAgRA
IAAoAggiA0UNASABIAI2AgwgASAANgIIIAEgAzYCBCMAQRBrIgAkACABQQRqIgEoAgAiAkEMaigCACEDAkACfwJAAkAgAigCBA4C
AAEDCyADDQJBACECQfSWwAAMAQsgAw0BIAIoAgAiAygCBCECIAMoAgALIQMgACACNgIEIAAgAzYCACAAQfCYwAAgASgCBCIAKAII
IAEoAgggAC0AECAALQARECkACyAAQQA2AgQgACACNgIAIABBhJnAACABKAIEIgAoAgggASgCCCAALQAQIAAtABEQKQALQfSWwABB
K0GwmMAAEEMAC0H0lsAAQStBwJjAABBDAAstAAJAIANpQQFHQYCAgIB4IANrIAFJckUEQCAAIAEgAyACEFkiAA0BCwALIAALsgEB
A38gACgCACEAIAEQZ0UEQCABEGhFBEAgADEAACABEBoPCyMAQYABayIDJAAgAC0AACEAA0AgAiADakH/AGpBMEE3IABBD3EiBEEK
SRsgBGo6AAAgAkEBayECIAAiBEEEdiEAIARBEE8NAAsgAkGAAWoiAEGAAUsEQCAAQYABQZidwAAQNgALIAFBqJ3AAEECIAIgA2pB
gAFqQQAgAmsQCSADQYABaiQADwsgACABEDALpwIBA38gARBnRQRAIAEQaEUEQCAAIAEQbg8LIwBBgAFrIgMkACAAKAIAIQADQCAC
IANqQf8AakEwQTcgAEEPcSIEQQpJGyAEajoAACACQQFrIQIgAEEQSSAAQQR2IQBFDQALIAJBgAFqIgBBgAFLBEAgAEGAAUGYncAA
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
CQsgBEGAAWokAAwCCyAAQYABQZidwAAQNgALIABBgAFBmJ3AABA2AAsLrwEBA38gASEFAkAgAkEQSQRAIAAhAQwBCyAAQQAgAGtB
A3EiA2ohBCADBEAgACEBA0AgASAFOgAAIAFBAWoiASAESQ0ACwsgBCACIANrIgJBfHEiA2ohASADQQBKBEAgBUH/AXFBgYKECGwh
AwNAIAQgAzYCACAEQQRqIgQgAUkNAAsLIAJBA3EhAgsgAgRAIAEgAmohAgNAIAEgBToAACABQQFqIgEgAkkNAAsLIAALuAIBB38C
QCACIgRBEEkEQCAAIQIMAQsgAEEAIABrQQNxIgNqIQUgAwRAIAAhAiABIQYDQCACIAYtAAA6AAAgBkEBaiEGIAJBAWoiAiAFSQ0A
CwsgBSAEIANrIghBfHEiB2ohAgJAIAEgA2oiA0EDcQRAIAdBAEwNASADQQN0IgRBGHEhCSADQXxxIgZBBGohAUEAIARrQRhxIQQg
BigCACEGA0AgBSAGIAl2IAEoAgAiBiAEdHI2AgAgAUEEaiEBIAVBBGoiBSACSQ0ACwwBCyAHQQBMDQAgAyEBA0AgBSABKAIANgIA
IAFBBGohASAFQQRqIgUgAkkNAAsLIAhBA3EhBCADIAdqIQELIAQEQCACIARqIQMDQCACIAEtAAA6AAAgAUEBaiEBIAJBAWoiAiAD
SQ0ACwsgAAsLAEGEicAAQSwQAQsHACAAIAFqCwcAIAAgAWsLBwAgAEEIagsHACAAQQhrCwMAAQsL7SEEAEGAgMAAC/MKL1VzZXJz
L21hZ3Vhbmd6aGkvLmNhcmdvL3JlZ2lzdHJ5L3NyYy9pbmRleC5jcmF0ZXMuaW8tNmYxN2QyMmJiYTE1MDAxZi9ibG9jay1wYWRk
aW5nLTAuMy4zL3NyYy9saWIucnNhc3NlcnRpb24gZmFpbGVkOiBuIDw9IGJzAAAAABAAZQAAAFEAAAARAAAAAQAAABQAAAAEAAAA
AgAAAFRyaWVkIHRvIHNocmluayB0byBhIGxhcmdlciBjYXBhY2l0eaAAEAAkAAAAL3J1c3RjLzc5ZTk3MTZjOTgwNTcwYmZkMWY2
NjZlM2IxNmFjNTgzZjAxNjg5NjIvbGlicmFyeS9hbGxvYy9zcmMvcmF3X3ZlYy5yc8wAEABMAAAArgEAAAkAAAABAAFBQkNERUZH
SElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsv////////////////////////
/////////////////////////////////z7///8/NDU2Nzg5Ojs8Pf////////8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGf//
/////xobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIz////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////y9Vc2Vycy9tYWd1YW5nemhpLy5jYXJnby9yZWdpc3RyeS9zcmMvaW5kZXguY3JhdGVzLmlvLTZmMTdkMjJi
YmExNTAwMWYvYmFzZTY0LTAuMjEuMi9zcmMvZW5jb2RlLnJzAAAAawIQAGIAAABQAAAAMwAAAHVzaXplIG92ZXJmbG93IHdoZW4g
Y2FsY3VsYXRpbmcgYjY0IGxlbmd0aAAAawIQAGIAAABXAAAACgAAAC9Vc2Vycy9tYWd1YW5nemhpLy5jYXJnby9yZWdpc3RyeS9z
cmMvaW5kZXguY3JhdGVzLmlvLTZmMTdkMjJiYmExNTAwMWYvYmFzZTY0LTAuMjEuMi9zcmMvZW5naW5lL21vZC5yc2ludGVnZXIg
b3ZlcmZsb3cgd2hlbiBjYWxjdWxhdGluZyBidWZmZXIgc2l6ZQAcAxAAZgAAAHcAAAAOAAAASW52YWxpZCBVVEY4HAMQAGYAAAB8
AAAAIAAAAGNhbGxlZCBgUmVzdWx0Ojp1bndyYXAoKWAgb24gYW4gYEVycmAgdmFsdWUABgAAAAgAAAAEAAAABwAAAAYAAAAIAAAA
BAAAAAgAAAAJAAAABAAAAAQAAAAKAAAACwAAAAAAAAABAAAADAAAAHNyYy9saWIucnMAAEgEEAAKAAAAeQAAACUAAAADBQcADwoN
AQsOBAYJDAgCSAQQAAoAAAB7AAAAJwAAAEFMc1BEcnNPQjdDN0RBZTN1cjhNQ3dzQnNBRUh1Z0M2QXdBQUI3OEtBQTg9SAQQAAoA
AAAVAAAALwAAANwDEAAAAAAA3AMQAAAAAADcAxAAAAAAANwDEAAAAAAAdnd3THU3ZTZ1ZzRIQVFNQXVnOENzQThIRDdvSER3dXhB
ZzRIQVFHNkRMQT1IBBAACgAAADcAAAAKAAAARXJyb3IgS2V5AAAASAQQAAoAAABaAAAANgAAAEVycm9yIGRlY29kaW5nIGNpcGhl
ciB0ZXh0IDFFcnJvciBkZWNyeXB0aW5nIGNpcGhlciB0ZXh0IDKAAEG0i8AAC9gVsgUQAAAAAABKc1ZhbHVlKCkAAAC8BRAACAAA
AMQFEAABAAAADwAAAAQAAAAEAAAAEAAAAC9Vc2Vycy9tYWd1YW5nemhpLy5jYXJnby9yZWdpc3RyeS9zcmMvaW5kZXguY3JhdGVz
LmlvLTZmMTdkMjJiYmExNTAwMWYvYmFzZTY0LTAuMjEuMi9zcmMvZW5naW5lL2dlbmVyYWxfcHVycG9zZS9kZWNvZGVfc3VmZml4
LnJz6AUQAIAAAAAdAAAAGQAAAOgFEACAAAAAmgAAAAkAAABpbnRlcm5hbCBlcnJvcjogZW50ZXJlZCB1bnJlYWNoYWJsZSBjb2Rl
OiBJbXBvc3NpYmxlOiBtdXN0IG9ubHkgaGF2ZSAwIHRvIDggaW5wdXQgYnl0ZXMgaW4gbGFzdCBjaHVuaywgd2l0aCBubyBpbnZh
bGlkIGxlbmd0aHMAAIgGEAB+AAAA6AUQAIAAAACFAAAADgAAAGludGVybmFsIGVycm9yOiBlbnRlcmVkIHVucmVhY2hhYmxlIGNv
ZGU6IEltcG9zc2libGUgcmVtYWluZGVyAAAgBxAAPgAAAC9Vc2Vycy9tYWd1YW5nemhpLy5jYXJnby9yZWdpc3RyeS9zcmMvaW5k
ZXguY3JhdGVzLmlvLTZmMTdkMjJiYmExNTAwMWYvYmFzZTY0LTAuMjEuMi9zcmMvZW5jb2RlLnJzAABoBxAAYgAAAG4AAAAWAAAA
aAcQAGIAAACCAAAACQAAAA8AAAAEAAAABAAAABEAAABJbnZhbGlkTGVuZ3RoSW52YWxpZEJ5dGVJbnZhbGlkTGFzdFN5bWJvbElu
dmFsaWRQYWRkaW5nL1VzZXJzL21hZ3Vhbmd6aGkvLmNhcmdvL3JlZ2lzdHJ5L3NyYy9pbmRleC5jcmF0ZXMuaW8tNmYxN2QyMmJi
YTE1MDAxZi9iYXNlNjQtMC4yMS4yL3NyYy9lbmdpbmUvZ2VuZXJhbF9wdXJwb3NlL2RlY29kZS5yczMIEAB5AAAAcgAAACkAAAAz
CBAAeQAAAHMAAAAvAAAAMwgQAHkAAACZAAAAGwAAADMIEAB5AAAAnQAAABkAAAAzCBAAeQAAALAAAAATAAAAMwgQAHkAAACzAAAA
GAAAADMIEAB5AAAA2gAAAB8AAAAzCBAAeQAAAOAAAAAfAAAAMwgQAHkAAADpAAAAHwAAADMIEAB5AAAA8gAAAB8AAAAzCBAAeQAA
APsAAAAfAAAAMwgQAHkAAAAEAQAAHwAAADMIEAB5AAAADQEAAB8AAAAzCBAAeQAAABYBAAAfAAAAL1VzZXJzL21hZ3Vhbmd6aGkv
LmNhcmdvL3JlZ2lzdHJ5L3NyYy9pbmRleC5jcmF0ZXMuaW8tNmYxN2QyMmJiYTE1MDAxZi9iYXNlNjQtMC4yMS4yL3NyYy9lbmdp
bmUvZ2VuZXJhbF9wdXJwb3NlL21vZC5ycwAAjAkQAHYAAACUAAAADQAAAIwJEAB2AAAAlgAAAEAAAACMCRAAdgAAAJUAAAANAAAA
jAkQAHYAAACYAAAADQAAAIwJEAB2AAAAnAAAAA0AAACMCRAAdgAAAJ0AAAANAAAAjAkQAHYAAACFAAAAJQAAAIwJEAB2AAAAhgAA
ACsAAACMCRAAdgAAAD4AAAAbAAAAjAkQAHYAAABAAAAAIAAAAC9Vc2Vycy9tYWd1YW5nemhpLy5jYXJnby9yZWdpc3RyeS9zcmMv
aW5kZXguY3JhdGVzLmlvLTZmMTdkMjJiYmExNTAwMWYvYWVzLTAuOC4zL3NyYy9zb2Z0L2ZpeHNsaWNlMzIucnMApAoQAGcAAADd
AQAAKQAAAKQKEABnAAAA8gEAAC0AAACkChAAZwAAAIkEAAASAAAApAoQAGcAAACJBAAAPQAAAKQKEABnAAAAFAUAACIAAACkChAA
ZwAAABQFAAAJAAAAUGFkRXJyb3JjYWxsZWQgYE9wdGlvbjo6dW53cmFwKClgIG9uIGEgYE5vbmVgIHZhbHVlABQAAAAMAAAABAAA
ABUAAAAWAAAAFwAAAG1lbW9yeSBhbGxvY2F0aW9uIG9mICBieXRlcyBmYWlsZWQAALgLEAAVAAAAzQsQAA0AAABsaWJyYXJ5L3N0
ZC9zcmMvYWxsb2MucnPsCxAAGAAAAGIBAAAJAAAAbGlicmFyeS9zdGQvc3JjL3Bhbmlja2luZy5ycxQMEAAcAAAAUwIAAB8AAAAU
DBAAHAAAAFQCAAAeAAAAFAAAAAwAAAAEAAAAGAAAABkAAAAIAAAABAAAABoAAAAZAAAACAAAAAQAAAAbAAAAHAAAAB0AAAAQAAAA
BAAAAB4AAAAfAAAAIAAAAAAAAAABAAAAIQAAACIAAAAEAAAABAAAACMAAAAkAAAADAAAAAQAAAAlAAAAJgAAACcAAABsaWJyYXJ5
L2FsbG9jL3NyYy9yYXdfdmVjLnJzY2FwYWNpdHkgb3ZlcmZsb3cAAADsDBAAEQAAANAMEAAcAAAAFgIAAAUAAABhIGZvcm1hdHRp
bmcgdHJhaXQgaW1wbGVtZW50YXRpb24gcmV0dXJuZWQgYW4gZXJyb3IAKAAAAAAAAAABAAAAKQAAAGxpYnJhcnkvYWxsb2Mvc3Jj
L2ZtdC5yc1wNEAAYAAAAYgIAACAAAADvv71ieXRlc2Vycm9yAAAAIgAAAAQAAAAEAAAAKgAAAEZyb21VdGY4RXJyb3IAAAArAAAA
DAAAAAQAAAAsAAAAKQAAAMQNEAAAAAAAWwAAADAAAAAAAAAAAQAAADEAAABpbmRleCBvdXQgb2YgYm91bmRzOiB0aGUgbGVuIGlz
ICBidXQgdGhlIGluZGV4IGlzIAAA5A0QACAAAAAEDhAAEgAAADogAADEDRAAAAAAACgOEAACAAAAMgAAAAwAAAAEAAAAMwAAADQA
AAA1AAAAICAgICB7ICwgIHsKLAp9IH0oKAosCgAAMgAAAAQAAAAEAAAANgAAAF1saWJyYXJ5L2NvcmUvc3JjL2ZtdC9udW0ucnN9
DhAAGwAAAGkAAAAXAAAAMHgwMDAxMDIwMzA0MDUwNjA3MDgwOTEwMTExMjEzMTQxNTE2MTcxODE5MjAyMTIyMjMyNDI1MjYyNzI4
MjkzMDMxMzIzMzM0MzUzNjM3MzgzOTQwNDE0MjQzNDQ0NTQ2NDc0ODQ5NTA1MTUyNTM1NDU1NTY1NzU4NTk2MDYxNjI2MzY0NjU2
NjY3Njg2OTcwNzE3MjczNzQ3NTc2Nzc3ODc5ODA4MTgyODM4NDg1ODY4Nzg4ODk5MDkxOTI5Mzk0OTU5Njk3OTg5OXJhbmdlIHN0
YXJ0IGluZGV4ICBvdXQgb2YgcmFuZ2UgZm9yIHNsaWNlIG9mIGxlbmd0aCAAAHIPEAASAAAAhA8QACIAAAByYW5nZSBlbmQgaW5k
ZXgguA8QABAAAACEDxAAIgAAAHNsaWNlIGluZGV4IHN0YXJ0cyBhdCAgYnV0IGVuZHMgYXQgANgPEAAWAAAA7g8QAA0AAAABAQEB
AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB
AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQBBzqHAAAszAgICAgICAgICAgICAgICAgIC
AgICAgICAgICAgICAwMDAwMDAwMDAwMDAwMDAwQEBAQEAEGNosAAC0xOb25lU29tZQAAADIAAAAEAAAABAAAADcAAABFcnJvclV0
ZjhFcnJvcnZhbGlkX3VwX3RvZXJyb3JfbGVuAAAyAAAABAAAAAQAAAA4AHsJcHJvZHVjZXJzAghsYW5ndWFnZQEEUnVzdAAMcHJv
Y2Vzc2VkLWJ5AwVydXN0Yx0xLjc0LjAgKDc5ZTk3MTZjOSAyMDIzLTExLTEzKQZ3YWxydXMGMC4xOS4wDHdhc20tYmluZGdlbhIw
LjIuODcgKGYwYThhZTNiOSkALA90YXJnZXRfZmVhdHVyZXMCKw9tdXRhYmxlLWdsb2JhbHMrCHNpZ24tZXh0
`;
// Global state for WASM
let yf = null;
let Mf = null;
let jf = null;
let memoryRef = null;
let Pf = 0;
// Ef - object reference table
const Ef = new Array(132).fill(undefined);
Ef.push(void 0, null, true, false);
let Af = Ef.length;
function Cf(l) {
const n = Ef[l];
if (l >= 132) {
Ef[l] = Af;
Af = l;
}
return n;
}
function If() {
if (jf === null || jf.byteLength === 0) {
jf = new Uint8Array(memoryRef.buffer);
}
return jf;
}
function Df() {
if (Mf === null || Mf.byteLength === 0) {
Mf = new Int32Array(memoryRef.buffer);
}
return Mf;
}
function Tf(l, n) {
l = l >>> 0;
return utf8BytesToString(If().subarray(l, l + n));
}
function Nf(l, n, u) {
if (u === undefined) {
const t = stringToUtf8Bytes(l);
const e = n(t.length, 1) >>> 0;
If().subarray(e, e + t.length).set(t);
Pf = t.length;
return e;
}
const t = stringToUtf8Bytes(l);
const e = n(t.length, 1) >>> 0;
If().subarray(e, e + t.length).set(t);
Pf = t.length;
return e;
}
function Uf(l) {
return l == null;
}
function base64ToUint8Array(base64) {
const binaryString = atob(base64.replace(/\s+/g, ''));
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes;
}
async function initWasm() {
if (yf !== null) {
return yf;
}
// 从嵌入的 base64 加载 WASM
const wasmBuffer = base64ToUint8Array(WASM_BASE64);
const importObject = {
wbg: {
__wbindgen_object_drop_ref: (l) => Cf(l),
__wbindgen_string_new: (ptr, len) => {
const str = Tf(ptr, len);
if (Af === Ef.length) {
Ef.push(Ef.length + 1);
}
const idx = Af;
Af = Ef[idx];
Ef[idx] = str;
return idx;
},
__wbindgen_debug_string: () => {}
}
};
const result = await WebAssembly.instantiate(wasmBuffer, importObject);
yf = result.instance.exports;
memoryRef = yf.memory;
Mf = null;
jf = null;
return yf;
}
function Hf(l, n) {
let u, t;
try {
const e = yf.__wbindgen_add_to_stack_pointer(-16);
const r = Nf(l, yf.__wbindgen_malloc, yf.__wbindgen_realloc);
const o = Pf;
const i = Uf(n) ? 0 : Nf(n, yf.__wbindgen_malloc, yf.__wbindgen_realloc);
const a = Pf;
yf.gateway_decrypt(e, r, o, i, a);
const s = Df()[e / 4 + 0];
const c = Df()[e / 4 + 1];
const f = Df()[e / 4 + 2];
const p = Df()[e / 4 + 3];
let d = s;
let h = c;
if (p) {
d = 0;
h = 0;
throw Cf(f);
}
u = d;
t = h;
return Tf(d, h);
} finally {
yf.__wbindgen_add_to_stack_pointer(16);
if (u !== undefined && t !== undefined) {
yf.__wbindgen_free(u, t, 1);
}
}
}
function Ff() {
const idx = yf.get_key();
return Ef[idx];
}
export async function decrypt(encryptedData, key) {
encryptedData = encryptedData.replace(/\s+/g, '');
await initWasm();
return Hf(encryptedData, key);
}
// CLI interface
// if (require.main === module) {
// const args = process.argv.slice(2);
// if (args.length < 1) {
// console.error('Usage: node gateway_decrypt.js <encrypted_data> [key]');
// console.error(' encrypted_data: Base64 encoded encrypted string');
// console.error(' key: Optional Base64 encoded key');
// process.exit(1);
// }
// const encryptedData = args[0];
// const key = args[1] || null;
// decrypt(encryptedData, key)
// .then(result => {
// console.log(result);
// })
// .catch(err => {
// console.error('Decryption failed:', err.message);
// process.exit(1);
// });
// }
+9 -3
View File
@@ -152,7 +152,7 @@ export async function getRedisCaches() {
if (!globals.redisCacheInitialized) {
try {
log("info", 'getRedisCaches start.');
const keys = ['animes', 'episodeIds', 'episodeNum', 'lastSelectMap'];
const keys = ['animes', 'episodeIds', 'episodeNum', 'reqRecords', 'lastSelectMap', 'todayReqNum'];
const commands = keys.map(key => ['GET', key]); // 构造 pipeline 命令
const results = await runPipeline(commands);
@@ -160,19 +160,23 @@ export async function getRedisCaches() {
globals.animes = results[0].result ? JSON.parse(results[0].result) : globals.animes;
globals.episodeIds = results[1].result ? JSON.parse(results[1].result) : globals.episodeIds;
globals.episodeNum = results[2].result ? JSON.parse(results[2].result) : globals.episodeNum;
globals.reqRecords = results[3].result ? JSON.parse(results[3].result) : globals.reqRecords;
// 恢复 lastSelectMap 并转换为 Map 对象
const lastSelectMapData = results[3].result ? JSON.parse(results[3].result) : null;
const lastSelectMapData = results[4].result ? JSON.parse(results[4].result) : null;
if (lastSelectMapData && typeof lastSelectMapData === 'object') {
globals.lastSelectMap = new Map(Object.entries(lastSelectMapData));
log("info", `Restored lastSelectMap from Redis with ${globals.lastSelectMap.size} entries`);
}
globals.todayReqNum = results[5].result ? parseInt(results[5].result, 10) : globals.todayReqNum;
// 更新哈希值
globals.lastHashes.animes = simpleHash(JSON.stringify(globals.animes));
globals.lastHashes.episodeIds = simpleHash(JSON.stringify(globals.episodeIds));
globals.lastHashes.episodeNum = simpleHash(JSON.stringify(globals.episodeNum));
globals.lastHashes.reqRecords = simpleHash(JSON.stringify(globals.reqRecords));
globals.lastHashes.lastSelectMap = simpleHash(JSON.stringify(Object.fromEntries(globals.lastSelectMap)));
globals.lastHashes.todayReqNum = simpleHash(JSON.stringify(globals.todayReqNum));
globals.redisCacheInitialized = true;
log("info", 'getRedisCaches completed successfully.');
@@ -195,7 +199,9 @@ export async function updateRedisCaches() {
{ key: 'animes', value: globals.animes },
{ key: 'episodeIds', value: globals.episodeIds },
{ key: 'episodeNum', value: globals.episodeNum },
{ key: 'lastSelectMap', value: globals.lastSelectMap }
{ key: 'reqRecords', value: globals.reqRecords },
{ key: 'lastSelectMap', value: globals.lastSelectMap },
{ key: 'todayReqNum', value: globals.todayReqNum }
];
for (const { key, value } of variables) {
+20 -4
View File
@@ -9,13 +9,29 @@ function ftPYStr(){
return '錒皚藹礙愛噯嬡璦曖靄諳銨鵪骯襖奧媼驁鰲壩罷鈀擺敗唄頒辦絆鈑幫綁鎊謗剝飽寶報鮑鴇齙輩貝鋇狽備憊鵯賁錛繃筆畢斃幣閉蓽嗶潷鉍篳蹕邊編貶變辯辮芐緶籩標驃颮飆鏢鑣鰾鱉別癟瀕濱賓擯儐繽檳殯臏鑌髕鬢餅稟撥缽鉑駁餑鈸鵓補鈽財參蠶殘慚慘燦驂黲蒼艙倉滄廁側冊測惻層詫鍤儕釵攙摻蟬饞讒纏鏟產闡顫囅諂讖蕆懺嬋驏覘禪鐔場嘗長償腸廠暢倀萇悵閶鯧鈔車徹硨塵陳襯傖諶櫬磣齔撐稱懲誠騁棖檉鋮鐺癡遲馳恥齒熾飭鴟沖衝蟲寵銃疇躊籌綢儔幬讎櫥廚鋤雛礎儲觸處芻絀躕傳釧瘡闖創愴錘綞純鶉綽輟齪辭詞賜鶿聰蔥囪從叢蓯驄樅湊輳躥竄攛錯銼鹺達噠韃帶貸駘紿擔單鄲撣膽憚誕彈殫賧癉簞當擋黨蕩檔讜碭襠搗島禱導盜燾燈鄧鐙敵滌遞締糴詆諦綈覿鏑顛點墊電巔鈿癲釣調銚鯛諜疊鰈釘頂錠訂鋌丟銩東動棟凍崠鶇竇犢獨讀賭鍍瀆櫝牘篤黷鍛斷緞籪兌隊對懟鐓噸頓鈍燉躉奪墮鐸鵝額訛惡餓諤堊閼軛鋨鍔鶚顎顓鱷誒兒爾餌貳邇鉺鴯鮞發罰閥琺礬釩煩販飯訪紡鈁魴飛誹廢費緋鐨鯡紛墳奮憤糞僨豐楓鋒風瘋馮縫諷鳳灃膚輻撫輔賦復負訃婦縛鳧駙紱紼賻麩鮒鰒釓該鈣蓋賅桿趕稈贛尷搟紺岡剛鋼綱崗戇鎬睪誥縞鋯擱鴿閣鉻個紇鎘潁給亙賡綆鯁龔宮鞏貢鉤溝茍構購夠詬緱覯蠱顧詁轂鈷錮鴣鵠鶻剮掛鴰摑關觀館慣貫詿摜鸛鰥廣獷規歸龜閨軌詭貴劊匭劌媯檜鮭鱖輥滾袞緄鯀鍋國過堝咼幗槨蟈鉿駭韓漢闞絎頡號灝顥閡鶴賀訶闔蠣橫轟鴻紅黌訌葒閎鱟壺護滬戶滸鶘嘩華畫劃話驊樺鏵懷壞歡環還緩換喚瘓煥渙奐繯鍰鯇黃謊鰉揮輝毀賄穢會燴匯諱誨繪詼薈噦澮繢琿暉葷渾諢餛閽獲貨禍鈥鑊擊機積饑跡譏雞績緝極輯級擠幾薊劑濟計記際繼紀訐詰薺嘰嚌驥璣覬齏磯羈蠆躋霽鱭鯽夾莢頰賈鉀價駕郟浹鋏鎵蟯殲監堅箋間艱緘繭檢堿鹼揀撿簡儉減薦檻鑒踐賤見鍵艦劍餞漸濺澗諫縑戔戩瞼鶼筧鰹韉將漿蔣槳獎講醬絳韁膠澆驕嬌攪鉸矯僥腳餃繳絞轎較撟嶠鷦鮫階節潔結誡屆癤頜鮚緊錦僅謹進晉燼盡勁荊莖巹藎饉縉贐覲鯨驚經頸靜鏡徑痙競凈剄涇逕弳脛靚糾廄舊鬮鳩鷲駒舉據鋸懼劇詎屨櫸颶鉅鋦窶齟鵑絹錈鐫雋覺決絕譎玨鈞軍駿皸開凱剴塏愾愷鎧鍇龕閌鈧銬顆殼課騍緙軻鈳錁頷墾懇齦鏗摳庫褲嚳塊儈鄶噲膾寬獪髖礦曠況誆誑鄺壙纊貺虧巋窺饋潰匱蕢憒聵簣閫錕鯤擴闊蠐蠟臘萊來賴崍徠淶瀨賚睞錸癩籟藍欄攔籃闌蘭瀾讕攬覽懶纜爛濫嵐欖斕鑭襤瑯閬鋃撈勞澇嘮嶗銠鐒癆樂鰳鐳壘類淚誄縲籬貍離鯉禮麗厲勵礫歷瀝隸儷酈壢藶蒞蘺嚦邐驪縭櫪櫟轢礪鋰鸝癘糲躒靂鱺鱧倆聯蓮連鐮憐漣簾斂臉鏈戀煉練蘞奩瀲璉殮褳襝鰱糧涼兩輛諒魎療遼鐐繚釕鷯獵臨鄰鱗凜賃藺廩檁轔躪齡鈴靈嶺領綾欞蟶鯪餾劉瀏騮綹鎦鷚龍聾嚨籠壟攏隴蘢瀧瓏櫳朧礱樓婁摟簍僂蔞嘍嶁鏤瘺耬螻髏蘆盧顱廬爐擄鹵虜魯賂祿錄陸壚擼嚕閭瀘淥櫨櫓轤輅轆氌臚鸕鷺艫鱸巒攣孿灤亂臠孌欒鸞鑾掄輪倫侖淪綸論圇蘿羅邏鑼籮騾駱絡犖玀濼欏腡鏍驢呂鋁侶屢縷慮濾綠櫚褸鋝嘸媽瑪碼螞馬罵嗎嘜嬤榪買麥賣邁脈勱瞞饅蠻滿謾縵鏝顙鰻貓錨鉚貿麼沒鎂門悶們捫燜懣鍆錳夢瞇謎彌覓冪羋謐獼禰綿緬澠靦黽廟緲繆滅憫閩閔緡鳴銘謬謨驀饃歿鏌謀畝鉬吶鈉納難撓腦惱鬧鐃訥餒內擬膩鈮鯢攆輦鯰釀鳥蔦裊聶嚙鑷鎳隉蘗囁顢躡檸獰寧擰濘苧嚀聹鈕紐膿濃農儂噥駑釹諾儺瘧歐鷗毆嘔漚謳慪甌盤蹣龐拋皰賠轡噴鵬紕羆鈹騙諞駢飄縹頻貧嬪蘋憑評潑頗釙撲鋪樸譜鏷鐠棲臍齊騎豈啟氣棄訖蘄騏綺榿磧頎頏鰭牽釬鉛遷簽謙錢鉗潛淺譴塹僉蕁慳騫繾槧鈐槍嗆墻薔強搶嬙檣戧熗錆鏘鏹羥蹌鍬橋喬僑翹竅誚譙蕎繰磽蹺竊愜鍥篋欽親寢鋟輕氫傾頃請慶撳鯖瓊窮煢蛺巰賕蟣鰍趨區軀驅齲詘嶇闃覷鴝顴權勸詮綣輇銓卻鵲確闋闕愨讓饒擾繞蕘嬈橈熱韌認紉飪軔榮絨嶸蠑縟銣顰軟銳蜆閏潤灑薩颯鰓賽傘毿糝喪騷掃繅澀嗇銫穡殺剎紗鎩鯊篩曬釃刪閃陜贍繕訕姍騸釤鱔墑傷賞坰殤觴燒紹賒攝懾設厙灄畬紳審嬸腎滲詵諗瀋聲繩勝師獅濕詩時蝕實識駛勢適釋飾視試謚塒蒔弒軾貰鈰鰣壽獸綬樞輸書贖屬術樹豎數攄紓帥閂雙誰稅順說碩爍鑠絲飼廝駟緦鍶鷥聳慫頌訟誦擻藪餿颼鎪蘇訴肅謖穌雖隨綏歲誶孫損筍蓀猻縮瑣鎖嗩脧獺撻闥鉈鰨臺態鈦鮐攤貪癱灘壇譚談嘆曇鉭錟頇湯燙儻餳鐋鏜濤絳討韜鋱騰謄銻題體屜緹鵜闐條糶齠鰷貼鐵廳聽烴銅統慟頭鈄禿圖釷團摶頹蛻飩脫鴕馱駝橢籜鼉襪媧膃彎灣頑萬紈綰網輞韋違圍為濰維葦偉偽緯謂衛諉幃闈溈潿瑋韙煒鮪溫聞紋穩問閿甕Line truncated
}
// 例外列表:简体字 -> 繁体字(这些字不转换)
const exceptionMap = new Map([
['吃', '吃'], // 吃 -> 喫,但同源,不转换
['注', '注'], // 注 -> 註,但同源,不转换
]);
export function traditionalized(cc){
let str = '';
for(let i=0; i<cc.length; i++){
if(charPYStr().indexOf(cc.charAt(i))!=-1)
str+=ftPYStr().charAt(charPYStr().indexOf(cc.charAt(i)));
else
str+=cc.charAt(i);
const char = cc.charAt(i);
// 检查是否在例外列表中
if (exceptionMap.has(char)) {
str += char; // 保持原样,不转换
continue;
}
const index = charPYStr().indexOf(char);
if(index !== -1) {
str += ftPYStr().charAt(index);
} else {
str += char;
}
}
return str;
}
+88 -5
View File
@@ -5,7 +5,7 @@ import { getRedisCaches, judgeRedisValid } from "./utils/redis-util.js";
import { cleanupExpiredIPs, findUrlById, getCommentCache, getLocalCaches, judgeLocalCacheValid } from "./utils/cache-util.js";
import { formatDanmuResponse } from "./utils/danmu-util.js";
import { getBangumi, getComment, getCommentByUrl, getSegmentComment, matchAnime, searchAnime, searchEpisodes } from "./apis/dandan-api.js";
import { handleConfig, handleUI, handleLogs, handleClearLogs, handleDeploy, handleClearCache } from "./apis/system-api.js";
import { handleConfig, handleUI, handleLogs, handleClearLogs, handleDeploy, handleClearCache, handleReqRecords } from "./apis/system-api.js";
import { handleSetEnv, handleAddEnv, handleDelEnv } from "./apis/env-api.js";
import { Segment } from "./models/dandan-model.js"
import {
@@ -58,6 +58,84 @@ async function handleRequest(req, env, deployPlatform, clientIp) {
await getRedisCaches();
}
// 检查路径是否包含指定的接口关键字
const targetPaths = [
'/api/v2/search/anime',
'/api/v2/match',
'/api/v2/search/episodes',
'/api/v2/bangumi',
'/api/v2/comment',
'/api/v2/segmentcomment'
];
// 只有当path包含指定接口关键字时才添加到请求记录数组
if (targetPaths.some(targetPath => path.includes(targetPath))) {
// 更新今日请求计数
// 从 reqRecords 最后一个元素获取上一个请求的时间
const lastRecord = globals.reqRecords.length > 0 ? globals.reqRecords[globals.reqRecords.length - 1] : null;
const currentDate = new Date().toDateString();
if (lastRecord) {
const lastDate = new Date(lastRecord.timestamp).toDateString();
console.log("currentDate: ", currentDate);
console.log("lastDate: ", lastDate);
if (lastDate !== currentDate) {
// 新的一天,重置计数
globals.todayReqNum = 1;
} else {
// 同一天,计数加1
globals.todayReqNum++;
}
} else {
// 没有历史记录,重置为1
globals.todayReqNum = 1;
}
// 处理路径,只保留从/api/v2开始的部分
let normalizedPath = req.url;
const apiV2Index = normalizedPath.indexOf('/api/v2');
if (apiV2Index !== -1) {
normalizedPath = normalizedPath.substring(apiV2Index);
}
// 获取请求体JSON(如果是POST/PUT/PATCH请求)
let requestBody = null;
if (method === 'POST' || method === 'PUT' || method === 'PATCH') {
try {
const clonedReq = req.clone();
const contentType = clonedReq.headers.get('content-type') || '';
if (contentType.includes('application/json')) {
requestBody = await clonedReq.json();
} else {
// 尝试解析为JSON,即使content-type不匹配
const text = await clonedReq.text();
if (text) {
requestBody = JSON.parse(text);
}
}
} catch (e) {
// JSON解析失败,保持为null
requestBody = null;
}
}
// 记录请求历史,包括接口/参数/请求时间
const requestRecord = {
interface: normalizedPath,
params: requestBody, // 请求体JSON
timestamp: new Date().toISOString(), // 请求时间
method: method, // HTTP方法
clientIp: clientIp // 客户端IP
};
globals.reqRecords.push(requestRecord);
// 限制记录数量不超过 MAX_RECORDS
if (globals.reqRecords.length > globals.MAX_RECORDS) {
globals.reqRecords = globals.reqRecords.slice(-globals.MAX_RECORDS);
}
}
// GET /
if (path === "/" && method === "GET") {
return handleUI();
@@ -118,6 +196,11 @@ async function handleRequest(req, env, deployPlatform, clientIp) {
return handleConfig(true); // 有权限
}
// GET /api/reqrecords - 获取请求记录 (需要 token)
if (path === "/api/reqrecords" && method === "GET") {
return handleReqRecords();
}
log("info", path);
// 智能处理API路径前缀,确保最终有一个正确的 /api/v2
@@ -127,14 +210,14 @@ async function handleRequest(req, env, deployPlatform, clientIp) {
log("info", `[Path Check] Starting path normalization for: "${path}"`);
const pathBeforeCleanup = path; // 保存清理前的路径检查是否修改
// 1. 清理:应对“用户填写/api/v2”+“客户端添加/api/v2”导致的重复前缀
// 1. 清理:应对"用户填写/api/v2"+"客户端添加/api/v2"导致的重复前缀
while (path.startsWith('/api/v2/api/v2/')) {
log("info", `[Path Check] Found redundant /api/v2 prefix. Cleaning...`);
// 从第二个 /api/v2 的位置开始截取,相当于移除第一个
path = path.substring('/api/v2'.length);
}
// 打印日志:只有在发生清理时才显示清理后的路径,否则显示“无需清理”
// 打印日志:只有在发生清理时才显示清理后的路径,否则显示"无需清理"
if (path !== pathBeforeCleanup) {
log("info", `[Path Check] Path after cleanup: "${path}"`);
} else {
@@ -150,7 +233,7 @@ async function handleRequest(req, env, deployPlatform, clientIp) {
path = '/api/v2' + path;
}
// 打印日志:只有在发生添加前缀时才显示添加后的路径,否则显示“无需补全”
// 打印日志:只有在发生添加前缀时才显示添加后的路径,否则显示"无需补全"
if (path === pathBeforePrefixCheck) {
log("info", `[Path Check] Prefix Check: No prefix addition needed.`);
}
@@ -472,4 +555,4 @@ export async function netlifyHandler(event, context) {
}
// 为了测试导出 handleRequest
export { handleRequest};
export { handleRequest};
+25
View File
@@ -18,6 +18,7 @@ import IqiyiSource from "./sources/iqiyi.js";
import MangoSource from "./sources/mango.js";
import BilibiliSource from "./sources/bilibili.js";
import YoukuSource from "./sources/youku.js";
import MiguSource from "./sources/migu.js";
import SohuSource from "./sources/sohu.js";
import LeshiSource from "./sources/leshi.js";
import XiguaSource from "./sources/xigua.js";
@@ -62,6 +63,7 @@ test('worker.js API endpoints', async (t) => {
const mangoSource = new MangoSource();
const bilibiliSource = new BilibiliSource();
const youkuSource = new YoukuSource();
const miguSource = new MiguSource();
const sohuSource = new SohuSource();
const leshiSource = new LeshiSource();
const xiguaSource = new XiguaSource();
@@ -211,6 +213,29 @@ test('worker.js API endpoints', async (t) => {
// assert(res.length >= 0, `Expected res.length >= 0, but got ${res.length}`);
// });
// await t.test('GET migu danmu', async () => {
// const res = await miguSource.getComments("https://www.miguvideo.com/p/detail/725117610", "migu");
// assert(res.length > 2, `Expected res.length > 2, but got ${res.length}`);
// });
// await t.test('GET migu danmu segments', async () => {
// const res = await miguSource.getComments("https://www.miguvideo.com/p/detail/725117610", "migu", true);
// console.log(res.segmentList);
// assert(res.type === "migu", `Expected res.type === "migu", but got ${res.type === "migu"}`);
// assert(res.segmentList.length >= 0, `Expected res.segmentList.length >= 0, but got ${res.segmentList.length}`);
// });
// await t.test('GET migu segment danmu', async () => {
// const segment = Segment.fromJson({
// type: 'migu',
// segment_start: 0,
// segment_end: 300,
// url: 'https://webapi.miguvideo.com/gateway/live_barrage/videox/barrage/v2/list/760834922/760835542/0/30/020',
// });
// const res = await miguSource.getSegmentComments(segment);
// assert(res.length >= 0, `Expected res.length >= 0, but got ${res.length}`);
// });
// await t.test('GET sohu danmu', async () => {
// const res = await sohuSource.getComments("https://film.sohu.com/album/8345543.html");
// assert(res.length > 2, `Expected res.length > 2, but got ${res.length}`);
+3 -3
View File
@@ -16,7 +16,7 @@ WidgetMetadata = {
// 源配置
{
name: "sourceOrder",
title: "源排序配置,默认'360,vod,renren,hanjutv',可选['360', 'vod', 'tmdb', 'douban', 'tencent', 'youku', 'iqiyi', 'imgo', 'bilibili', 'sohu', 'leshi', 'xigua', 'renren', 'hanjutv', 'bahamut', 'dandan', 'custom']",
title: "源排序配置,默认'360,vod,renren,hanjutv',可选['360', 'vod', 'tmdb', 'douban', 'tencent', 'youku', 'iqiyi', 'imgo', 'bilibili', 'migu', 'sohu', 'leshi', 'xigua', 'renren', 'hanjutv', 'bahamut', 'dandan', 'custom']",
type: "input",
placeholders: [
{
@@ -151,12 +151,12 @@ WidgetMetadata = {
// 匹配配置
{
name: "platformOrder",
title: "平台优选配置,可选['qiyi', 'bilibili1', 'imgo', 'youku', 'qq', 'sohu', 'leshi, 'xigua', 'renren', 'hanjutv', 'bahamut', 'dandan', 'custom']",
title: "平台优选配置,可选['qiyi', 'bilibili1', 'imgo', 'youku', 'qq', 'migu', 'sohu', 'leshi, 'xigua', 'renren', 'hanjutv', 'bahamut', 'dandan', 'custom']",
type: "input",
placeholders: [
{
title: "配置1",
value: "qq,qiyi,imgo,bilibili1,youku,sohu,leshi,xigua,renren,hanjutv,bahamut,dandan,custom",
value: "qq,qiyi,imgo,bilibili1,youku,migu,sohu,leshi,xigua,renren,hanjutv,bahamut,dandan,custom",
},
{
title: "配置2",