配置预览
+当前生效的环境变量配置
+ +日志查看
+接口调试
+推送弹幕
+支持OK影视等播放器,两端需要在同一局域网或使用公网ip,推送地址格式如 http://127.0.0.1:9978/action?do=refresh&type=danmaku&path=
+环境变量配置
+vercel/netlify/edgeone平台修改变量后需要重新部署
+
@@ -327,6 +351,7 @@ API 支持返回 Bilibili 标准 XML 格式的弹幕数据,通过查询参数
| 变量名称 | 描述 |
| ----------- | ----------- |
| TOKEN | 【可选】自定义用户token,不填默认为`87654321` |
+| ADMIN_TOKEN | 【可选】系统管理访问令牌,如果未配置此值,则无法访问系统管理功能,需要先配置后在URL中填入此token才能打开系统管理 |
| OTHER_SERVER | 【可选】兜底第三方弹幕服务器,不填默认为`https://api.danmu.icu`,其他可选:`https://fc.lyz05.cn`,`https://dmku.hls.one`,`https://se.678.ooo`,`https://danmu.56uxi.com`,`https://dm.lxlad.com` |
| VOD_SERVERS | 【可选】VOD服务器列表,支持多个服务器并发查询,格式:`名称@URL,名称@URL,...`,示例:`金蝉@https://zy.jinchancaiji.com,789@https://www.caiji.cyou,听风@https://gctf.tfdh.top`,不填默认为`金蝉@https://zy.jinchancaiji.com,789@https://www.caiji.cyou,听风@https://gctf.tfdh.top` |
| VOD_RETURN_MODE | 【可选】VOD返回模式,可选值:`all`(返回所有站点结果)、`fastest`(只返回最快的站点结果),默认为`fastest`。当配置多个VOD站点时,`all`模式会返回所有站点的结果(结果较多),`fastest`模式只返回首先响应成功的站点结果(结果较少,避免重复) |
@@ -356,12 +381,16 @@ API 支持返回 Bilibili 标准 XML 格式的弹幕数据,通过查询参数
| MAX_LAST_SELECT_MAP | 【可选】最后选择映射缓存大小限制,默认为`100`,lastSelectMap最多保存的条目数,超过限制时删除最早的条目(FIFO),用于存储查询关键字上次选择的animeId |
| UPSTASH_REDIS_REST_URL | 【可选】Upstash redis url,需配合UPSTASH_REDIS_REST_TOKEN使用,用于持久化存储,不会因为冷启动而丢失过去的查询信息(在cf/eo/claw上配置后应该能更稳定点,也能解决小幻掉匹配的问题,但会稍微影响请求速度),获取方法请参考:`https://cloud.tencent.cn/developer/article/2424508` |
| UPSTASH_REDIS_REST_TOKEN | 【可选】Upstash redis token,需配合UPSTASH_REDIS_REST_URL使用,用于持久化存储,不会因为冷启动而丢失过去的查询信息(在cf/eo/claw上配置后应该能更稳定点,也能解决小幻掉匹配的问题,但会稍微影响请求速度),获取方法请参考:`https://cloud.tencent.cn/developer/article/2424508` |
+| DEPLOY_PLATFROM_ACCOUNT | 【可选】部署账号ID,调用部署服务API需要,配置后可使用UI界面配置服务,不同部署平台获取方式可查看 [部署平台环境变量配置指南](https://github.com/huangxd-/danmu_api/tree/main/danmu_api/ui/README.md#部署平台环境变量配置指南) ,docker部署和本地node部署并不需要配置 |
+| DEPLOY_PLATFROM_PROJECT | 【可选】部署项目名称,调用部署服务API需要,配置后可使用UI界面配置服务,不同部署平台获取方式可查看 [部署平台环境变量配置指南](https://github.com/huangxd-/danmu_api/tree/main/danmu_api/ui/README.md#部署平台环境变量配置指南) ,docker部署和本地node部署并不需要配置 |
+| DEPLOY_PLATFROM_TOKEN | 【可选】部署平台token,调用部署服务API需要,配置后可使用UI界面配置服务,不同部署平台获取方式可查看 [部署平台环境变量配置指南](https://github.com/huangxd-/danmu_api/tree/main/danmu_api/ui/README.md#部署平台环境变量配置指南) ,docker部署和本地node部署并不需要配置 |
+| NODE_TLS_REJECT_UNAUTHORIZED | 【可选】在建立 HTTPS 连接时是否验证服务器的 SSL/TLS 证书,0表示忽略,默认为1 |
```regex
# EPISODE_TITLE_FILTER 默认值
(特别|惊喜|纳凉)?企划|合伙人手记|超前(营业|vlog)?|速览|vlog|reaction|纯享|加更(版|篇)?|抢先(看|版|集|篇)?|抢鲜|预告|花絮(独家)?|特辑|彩蛋|专访|幕后(故事|花絮|独家)?|直播(陪看|回顾)?|未播(片段)?|衍生|番外|会员(专享|加长|尊享|专属|版)?|片花|精华|看点|速看|解读|影评|解说|吐槽|盘点|拍摄花絮|制作花絮|幕后花絮|未播花絮|独家花絮|花絮特辑|先导预告|终极预告|正式预告|官方预告|彩蛋片段|删减片段|未播片段|番外彩蛋|精彩片段|精彩看点|精彩回顾|精彩集锦|看点解析|看点预告|NG镜头|NG花絮|番外篇|番外特辑|制作特辑|拍摄特辑|幕后特辑|导演特辑|演员特辑|片尾曲|插曲|高光回顾|背景音乐|OST|音乐MV|歌曲MV|前季回顾|剧情回顾|往期回顾|内容总结|剧情盘点|精选合集|剪辑合集|混剪视频|独家专访|演员访谈|导演访谈|主创访谈|媒体采访|发布会采访|采访|陪看(记)?|试看版|短剧|精编|Plus|独家版|特别版|短片|发布会|解忧局|走心局|火锅局|巅峰时刻|坞里都知道|福持目标坞民|.{3,}篇|(?!.*(入局|破冰局|做局)).{2,}局|观察室|上班那点事儿|周top|赛段|直拍|REACTION|VLOG|全纪录|开播|先导|总宣|展演|集锦|旅行日记|精彩分享|剧情揭秘
-# 如果你想新增过滤词,请自定义EPISODE_TITLE_FILTER,示例如下,每个词用'|'隔开,增加的词都会追加到默认值后面
+# 如果你想自定义过滤词,请新增EPISODE_TITLE_FILTER环境变量,示例如下,每个词用'|'隔开,也可参照默认值填写
测试|test
```
@@ -410,66 +439,91 @@ API 支持返回 Bilibili 标准 XML 格式的弹幕数据,通过查询参数
danmu_api/
├── .github/
│ └── workflows/
-│ ├── docker-image.yml
-│ └── sync_fork.yml # vercel自动同步配置文件
-├── danmu_api/
-│ └── apis/
-│ └── dandan-api.js # 弹弹play兼容接口函数
-│ └── configs/
-│ ├── envs.js # 环境变量处理脚本
-│ └── globals.js # 全局变量处理脚本
-│ └── models/
-│ └── dandan-model.js # 弹弹play数据模型
-│ └── sources/
-│ ├── bahamut.js # 巴哈姆特源
-│ ├── base.js # 弹幕源获取基类
-│ ├── bilibili.js # b站源
-│ ├── dandan.js # 弹弹play源
-│ ├── douban.js # 豆瓣源
-│ ├── hanjutv.js # 韩剧TV源
-│ ├── iqiyi.js # 爱奇艺源
-│ ├── kan360.js # 360看源
-│ ├── mango.js # 芒果TV源
-│ ├── other.js # 第三方弹幕服务器
-│ ├── renren.js # 人人视频源
-│ ├── tencent.js # 腾讯视频源
-│ ├── tmdb.js # TMDB源
-│ ├── vod.js # vod源
-│ └── youku.js # 优酷源
-│ └── utils/
-│ ├── cache-util.js # 缓存数据处理工具
-│ ├── codec-util.js # 编解码工具
-│ ├── common-util.js # 通用工具
-│ ├── danmu-util.js # 弹幕处理工具
-│ ├── douban-util.js # 豆瓣API请求工具
-│ ├── http-util.js # 请求工具
-│ ├── imdb-util.js # IMDB API请求工具
-│ ├── log-util.js # 日志工具
-│ ├── redis-util.js # redis工具
-│ ├── time-util.js # 时间日期工具
-│ ├── tmdb-util.js # TMDB API请求处理工具
-│ └── zh-util.js # 中文繁简转换工具
-│ ├── esm-shim.js # Node.js低版本兼容层
-│ ├── server.js # 本地node启动脚本
-│ ├── worker.js # 主 API 服务器代码
-│ └── worker.test.js # 测试文件
-├── netlify/
-│ └── functions/
-│ └── api.js # netlify 中间处理逻辑
-├── node-functions/
-│ ├── [[...path]]..js # edgeone pages 所有路由跳转指向index
-│ └── index.js # edgeone pages 中间处理逻辑
-├── .env.example # .env 配置文件示例
-├── config.yaml.example # YAML 配置文件示例(无法编辑 .env 时使用)
+│ ├── docker-image.yml # Docker镜像构建和推送工作流
+│ └── sync_fork.yml # Fork同步上游仓库工作流(vercel自动同步配置文件)
+├── .env.example # .env 配置文件示例
├── .gitignore
+├── config.yaml.example # YAML 配置文件示例(无法编辑 .env 时使用)
├── Dockerfile
-├── edgeone.json # edgeone pages 配置文件
+├── edgeone.json # edgeone pages 配置文件
├── LICENSE
-├── netlify.toml # netlify 配置文件
+├── netlify.toml # netlify 配置文件
├── package.json
├── README.md
-├── vercel.json # vercel 配置文件
-└── wrangler.toml # cloudflare worker 配置文件
+├── vercel.json # vercel 配置文件
+├── wrangler.toml # cloudflare worker 配置文件
+├── danmu_api/
+│ ├── esm-shim.js # Node.js低版本兼容层
+│ ├── server.js # 本地node启动脚本
+│ ├── worker.js # 主 API 服务器代码
+│ ├── worker.test.js # 测试文件
+│ ├── apis/
+│ │ ├── dandan-api.js # 弹弹play兼容接口函数
+│ │ ├── env-api.js # 环境变量接口函数
+│ │ └── system-api.js # 系统管理接口函数
+│ ├── configs/
+│ │ ├── envs.js # 环境变量处理脚本
+│ │ └── globals.js # 全局变量处理脚本
+│ │ └── handlers/ # 部署平台API调用及环境变量处理类
+│ │ ├── base-handler.js
+│ │ ├── cloudflare-handler.js
+│ │ ├── edgeone-handler.js
+│ │ ├── handler-factory.js
+│ │ ├── netlify-handler.js
+│ │ ├── node-handler.js
+│ │ └── vercel-handler.js
+│ ├── models/
+│ │ └── dandan-model.js # 弹弹play数据模型
+│ ├── sources/
+│ │ ├── bahamut.js # 巴哈姆特源
+│ │ ├── base.js # 弹幕源获取基类
+│ │ ├── bilibili.js # b站源
+│ │ ├── dandan.js # 弹弹play源
+│ │ ├── douban.js # 豆瓣源
+│ │ ├── hanjutv.js # 韩剧TV源
+│ │ ├── iqiyi.js # 爱奇艺源
+│ │ ├── kan360.js # 360看源
+│ │ ├── mango.js # 芒果TV源
+│ │ ├── other.js # 第三方弹幕服务器
+│ │ ├── renren.js # 人人视频源
+│ │ ├── tencent.js # 腾讯视频源
+│ │ ├── tmdb.js # TMDB源
+│ │ ├── vod.js # vod源
+│ │ └── youku.js # 优酷源
+│ ├── ui/
+│ │ ├── README.md # UI系统使用说明
+│ │ ├── template.js # UI模板文件
+│ │ ├── css/
+│ │ │ ├── base.css.js # 基础样式
+│ │ │ ├── components.css.js # 组件样式
+│ │ │ ├── forms.css.js # 表单样式
+│ │ │ └── responsive.css.js # 响应式样式
+│ │ └── js/
+│ │ ├── apitest.js # API测试脚本
+│ │ ├── logview.js # 日志查看脚本
+│ │ ├── main.js # UI主脚本
+│ │ ├── preview.js # 预览功能脚本
+│ │ ├── pushdanmu.js # 推送弹幕脚本
+│ │ └── systemsettings.js # 系统设置脚本
+│ └── utils/
+│ ├── cache-util.js # 缓存数据处理工具
+│ ├── codec-util.js # 编解码工具
+│ ├── common-util.js # 通用工具
+│ ├── danmu-util.js # 弹幕处理工具
+│ ├── douban-util.js # 豆瓣API请求工具
+│ ├── http-util.js # 请求工具
+│ ├── imdb-util.js # IMDB API请求工具
+│ ├── log-util.js # 日志工具
+│ ├── redis-util.js # redis工具
+│ ├── time-util.js # 时间日期工具
+│ ├── tmdb-util.js # TMDB API请求处理工具
+│ └── zh-util.js # 中文繁简转换工具
+├── netlify/
+│ └── functions/
+│ └── api.js # netlify 中间处理逻辑
+└── node-functions/
+ ├── [[...path]]..js # edgeone pages 所有路由跳转指向index
+ └── index.js # edgeone pages 中间处理逻辑
```
## 注意事项
diff --git a/config.yaml.example b/config.yaml.example
index a582d80..d17fc65 100644
--- a/config.yaml.example
+++ b/config.yaml.example
@@ -17,6 +17,11 @@
# 默认值:87654321
TOKEN: "87654321"
+# 系统管理访问令牌(用于系统管理功能)
+# 如果未配置此值,则无法访问系统管理功能,需要先配置后在URL中填入此token才能打开系统管理
+# 默认值:空(不启用系统管理访问控制)
+# ADMIN_TOKEN:
+
# 其他服务器地址(第三方弹幕服务器)
# 默认值:https://api.danmu.icu
OTHER_SERVER: "https://api.danmu.icu"
@@ -238,3 +243,20 @@ MAX_LAST_SELECT_MAP: 100
# 默认值:空
# UPSTASH_REDIS_REST_TOKEN: ""
+# ==================== 部署平台API接口信息 配置 ====================
+
+# 部署账号ID,调用部署服务API需要,配置后可使用UI界面配置服务
+# 默认值:空
+#DEPLOY_PLATFROM_ACCOUNT: ""
+
+# 部署项目名称,调用部署服务API需要,配置后可使用UI界面配置服务
+# 默认值:空
+#DEPLOY_PLATFROM_PROJECT: ""
+
+# 部署平台token,调用部署服务API需要,配置后可使用UI界面配置服务
+# 默认值:空
+#DEPLOY_PLATFROM_TOKEN: ""
+
+# 在建立 HTTPS 连接时是否验证服务器的 SSL/TLS 证书,0表示忽略
+# 默认值:1
+# NODE_TLS_REJECT_UNAUTHORIZED: 1
diff --git a/danmu_api/apis/env-api.js b/danmu_api/apis/env-api.js
new file mode 100644
index 0000000..1d23c35
--- /dev/null
+++ b/danmu_api/apis/env-api.js
@@ -0,0 +1,96 @@
+import { jsonResponse } from '../utils/http-util.js';
+import { HandlerFactory } from '../configs/handlers/handler-factory.js';
+import { globals } from '../configs/globals.js';
+
+/**
+ * 处理设置环境变量的请求
+ */
+export async function handleSetEnv(request) {
+ try {
+ const { key, value } = await request.json();
+
+ if (!key) {
+ return jsonResponse({ success: false, message: '缺少环境变量名称' }, 400);
+ }
+
+ // 获取当前部署平台
+ const deployPlatform = globals.deployPlatform;
+
+ // 根据部署平台获取相应的handler
+ const handler = await HandlerFactory.getHandler(deployPlatform);
+
+ // 调用handler的setEnv方法
+ const result = await handler.setEnv(key, value);
+
+ if (result) {
+ return jsonResponse({ success: true, message: `环境变量 ${key} 设置成功` });
+ } else {
+ return jsonResponse({ success: false, message: `环境变量 ${key} 设置失败` }, 500);
+ }
+ } catch (error) {
+ console.error('设置环境变量失败:', error);
+ return jsonResponse({ success: false, message: `设置环境变量失败: ${error.message}` }, 500);
+ }
+}
+
+/**
+ * 处理添加环境变量的请求
+ */
+export async function handleAddEnv(request) {
+ try {
+ const { key, value } = await request.json();
+
+ if (!key) {
+ return jsonResponse({ success: false, message: '缺少环境变量名称' }, 400);
+ }
+
+ // 获取当前部署平台
+ const deployPlatform = globals.deployPlatform ;
+
+ // 根据部署平台获取相应的handler
+ const handler = await HandlerFactory.getHandler(deployPlatform);
+
+ // 调用handler的addEnv方法
+ const result = await handler.addEnv(key, value);
+
+ if (result) {
+ return jsonResponse({ success: true, message: `环境变量 ${key} 添加成功` });
+ } else {
+ return jsonResponse({ success: false, message: `环境变量 ${key} 添加失败` }, 500);
+ }
+ } catch (error) {
+ console.error('添加环境变量失败:', error);
+ return jsonResponse({ success: false, message: `添加环境变量失败: ${error.message}` }, 500);
+ }
+}
+
+/**
+ * 处理删除环境变量的请求
+ */
+export async function handleDelEnv(request) {
+ try {
+ const { key } = await request.json();
+
+ if (!key) {
+ return jsonResponse({ success: false, message: '缺少环境变量名称' }, 400);
+ }
+
+ // 获取当前部署平台
+ const deployPlatform = globals.deployPlatform;
+
+ // 根据部署平台获取相应的handler
+ const handler = await HandlerFactory.getHandler(deployPlatform);
+
+ // 调用handler的delEnv方法
+ const result = await handler.delEnv(key);
+
+ if (result) {
+ return jsonResponse({ success: true, message: `环境变量 ${key} 删除成功` });
+ } else {
+ return jsonResponse({ success: false, message: `环境变量 ${key} 删除失败` }, 500);
+ }
+ } catch (error) {
+ console.error('删除环境变量失败:', error);
+ return jsonResponse({ success: false, message: `删除环境变量失败: ${error.message}` }, 500);
+ }
+}
diff --git a/danmu_api/apis/system-api.js b/danmu_api/apis/system-api.js
new file mode 100644
index 0000000..92f9c8a
--- /dev/null
+++ b/danmu_api/apis/system-api.js
@@ -0,0 +1,198 @@
+import { globals } from "../configs/globals.js";
+import { jsonResponse } from "../utils/http-util.js";
+import { HTML_TEMPLATE } from "../ui/template.js";
+import { formatLogMessage, log } from "../utils/log-util.js";
+import { HandlerFactory } from "../configs/handlers/handler-factory.js";
+
+export function handleUI() {
+ return new Response(HTML_TEMPLATE.replace("globals.currentToken", globals.currentToken), {
+ headers: {
+ 'Content-Type': 'text/html; charset=utf-8',
+ 'Access-Control-Allow-Origin': '*'
+ }
+ });
+}
+
+export function handleConfig(hasPermission = false) {
+ // 获取环境变量配置
+ const envVarConfig = globals.envVarConfig;
+
+ // 分类环境变量
+ const categorizedVars = {
+ api: [],
+ source: [],
+ match: [],
+ danmu: [],
+ cache: [],
+ system: []
+ };
+
+ // 获取所有环境变量 - 这是用于配置预览的
+ const previewEnvVars = {
+ ...globals.accessedEnvVars,
+ localCacheValid: globals.localCacheValid,
+ redisValid: globals.redisValid,
+ deployPlatform: globals.deployPlatform
+ };
+
+ // 将环境变量按分类组织 - 使用原始环境变量进行分类,但保持预览格式
+ Object.keys(previewEnvVars).forEach(key => {
+ const varConfig = envVarConfig[key] || { category: 'system', type: 'text', description: '未分类配置项' };
+ const category = varConfig.category || 'system';
+
+ categorizedVars[category].push({
+ key: key,
+ value: previewEnvVars[key].value || previewEnvVars[key], // 如果是新格式则取value字段,否则直接使用原值
+ type: previewEnvVars[key].type || varConfig.type || 'text', // 如果是新格式则取type字段,否则使用配置中的type或默认text
+ description: varConfig.description || '无描述',
+ options: previewEnvVars[key].options || varConfig.options // 如果是新格式则取options字段
+ });
+ });
+
+ // 检查是否配置了ADMIN_TOKEN
+ const adminToken = globals.adminToken || '';
+ const hasAdminToken = adminToken.trim() !== '';
+
+ // 准备原始环境变量,无权限时也需要脱敏
+ let originalEnvVars = { ...globals.originalEnvVars };
+ if (!hasPermission || globals.currentToken !== globals.adminToken) {
+ Object.keys(originalEnvVars).forEach(key => {
+ if (globals.currentToken !== globals.token || key !== "TOKEN") {
+ if (key in previewEnvVars && /^\*+$/.test(previewEnvVars[key])) {
+ originalEnvVars[key] = previewEnvVars[key];
+ }
+ }
+ });
+ }
+
+ return jsonResponse({
+ message: "Welcome to the LogVar Danmu API server",
+ version: globals.VERSION,
+ envs: previewEnvVars, // 配置预览使用
+ categorizedEnvVars: categorizedVars,
+ envVarConfig: envVarConfig,
+ 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或小鸡也能一键部署。",
+ 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]。"
+ });
+}
+
+/**
+ * 处理重新部署请求
+ * @returns {Response} 部署操作结果
+ */
+export async function handleDeploy() {
+ try {
+ const deployPlatform = globals.deployPlatform;
+ log("info", `[server] Deployment request received for platform: ${deployPlatform}`);
+
+ // 如果是 Node 部署,直接返回成功,因为 Node 环境不需要重新部署
+ if (deployPlatform.toLowerCase() === 'node') {
+ log("info", `[server] Node/Docker deployment - no redeployment needed, config changes take effect automatically`);
+ return jsonResponse({ success: true, message: "Node/Docker deployment - configuration changes take effect automatically" }, 200);
+ }
+
+ // 对于其他平台(如 Cloudflare、Vercel、Netlify 等),使用相应的 Handler 触发部署
+ const handler = await HandlerFactory.getHandler(deployPlatform);
+ if (!handler) {
+ log("error", `[server] No handler found for platform: ${deployPlatform}`);
+ return jsonResponse({ success: false, message: `No handler found for platform: ${deployPlatform}` }, 400);
+ }
+
+ // 调用 handler 的 deploy 方法
+ const deployResult = await handler.deploy();
+ if (deployResult) {
+ log("info", `[server] Deployment triggered successfully for platform: ${deployPlatform}`);
+ return jsonResponse({ success: true, message: "Deployment triggered successfully" }, 200);
+ } else {
+ log("error", `[server] Failed to trigger deployment for platform: ${deployPlatform}`);
+ return jsonResponse({ success: false, message: "Failed to trigger deployment" }, 500);
+ }
+ } catch (error) {
+ log("error", `[server] Deployment error: ${error.message}`);
+ return jsonResponse({ success: false, message: `Deployment failed: ${error.message}` }, 500);
+ }
+}
+
+/**
+ * 处理获取日志的请求
+ * @returns {Response} 包含日志文本的响应
+ */
+export function handleLogs() {
+ const logText = globals.logBuffer
+ .map(
+ (log) =>
+ `[${log.timestamp}] ${log.level}: ${formatLogMessage(log.message)}`
+ )
+ .join("\n");
+ return new Response(logText, { headers: { "Content-Type": "text/plain; charset=utf-8" } });
+}
+
+/**
+ * 处理清除日志的请求
+ * @returns {Response} 表示操作成功的响应
+ */
+export function handleClearLogs() {
+ globals.logBuffer = [];
+ return jsonResponse({ success: true, message: "Logs cleared" }, 200);
+}
+
+/**
+ * 处理清理缓存的请求
+ * @returns {Response} 表示操作成功的响应
+ */
+export async function handleClearCache() {
+ try {
+ // 清理 globals 中的缓存数据
+ globals.animes = [];
+ globals.episodeIds = [];
+ globals.episodeNum = 10001; // 重置为初始值
+ globals.lastSelectMap = new Map(); // 重新创建 Map 对象
+
+ // 清理搜索和弹幕缓存
+ globals.searchCache = new Map();
+ globals.commentCache = new Map();
+ globals.requestHistory = new Map();
+
+ log("info", `[server] Memory cache cleared successfully`);
+
+ // 同步清理本地缓存和Redis缓存
+ try {
+ // 如果本地缓存有效,更新本地缓存
+ if (globals.localCacheValid) {
+ const { updateLocalCaches } = await import("../utils/cache-util.js");
+ await updateLocalCaches();
+ log("info", `[server] Local cache cleared successfully`);
+ }
+ } catch (localError) {
+ log("warn", `[server] Local cache may not be available: ${localError.message}`);
+ }
+
+ try {
+ // 如果Redis有效,更新Redis缓存
+ if (globals.redisValid) {
+ const { updateRedisCaches } = await import("../utils/redis-util.js");
+ await updateRedisCaches();
+ log("info", `[server] Redis cache cleared successfully`);
+ }
+ } catch (redisError) {
+ log("warn", `[server] Redis may not be available: ${redisError.message}`);
+ }
+
+ log("info", `[server] All caches cleared successfully`);
+ return jsonResponse({ success: true, message: "Cache cleared successfully", clearedItems: {
+ animes: 0,
+ episodeIds: 0,
+ episodeNum: 10001,
+ lastSelectMap: 0,
+ searchCache: 0,
+ commentCache: 0,
+ requestHistory: 0
+ }}, 200);
+ } catch (error) {
+ log("error", `[server] Cache clear failed: ${error.message}`);
+ return jsonResponse({ success: false, message: `Cache clear failed: ${error.message}` }, 500);
+ }
+}
diff --git a/danmu_api/configs/envs.js b/danmu_api/configs/envs.js
index ec45484..794dd5c 100644
--- a/danmu_api/configs/envs.js
+++ b/danmu_api/configs/envs.js
@@ -6,6 +6,7 @@ export class Envs {
static env;
// 记录获取过的环境变量
+ static originalEnvVars = new Map();
static accessedEnvVars = new Map();
static VOD_ALLOWED_PLATFORMS = ['qiyi', 'bilibili1', 'imgo', 'youku', 'qq']; // vod允许的播放平台
@@ -23,10 +24,13 @@ export class Envs {
let value;
if (typeof this.env !== 'undefined' && this.env[key]) {
value = this.env[key];
+ this.originalEnvVars.set(key, value);
} else if (typeof process !== 'undefined' && process.env?.[key]) {
value = process.env[key];
+ this.originalEnvVars.set(key, value);
} else {
value = defaultValue;
+ this.originalEnvVars.set(key, "");
}
let parsedValue;
@@ -75,10 +79,9 @@ export class Envs {
/**
* 解析 VOD 服务器配置
- * @param {Object} env 环境对象
* @returns {Array} 服务器列表
*/
- static resolveVodServers(env) {
+ static resolveVodServers() {
const defaultVodServers = '金蝉@https://zy.jinchancaiji.com,789@https://www.caiji.cyou,听风@https://gctf.tfdh.top';
let vodServersConfig = this.get('VOD_SERVERS', defaultVodServers, 'string');
@@ -102,11 +105,9 @@ export class Envs {
/**
* 解析源排序
- * @param {Object} env 环境对象
- * @param {string} deployPlatform 部署平台
* @returns {Array} 源排序数组
*/
- static resolveSourceOrder(env, deployPlatform) {
+ static resolveSourceOrder() {
let sourceOrder = this.get('SOURCE_ORDER', '360,vod,renren,hanjutv', 'string');
const orderArr = sourceOrder
@@ -121,10 +122,9 @@ export class Envs {
/**
* 解析平台排序
- * @param {Object} env 环境对象
* @returns {Array} 平台排序数组
*/
- static resolvePlatformOrder(env) {
+ static resolvePlatformOrder() {
const orderArr = this.get('PLATFORM_ORDER', '', 'string')
.split(',')
.map(s => s.trim())
@@ -137,10 +137,9 @@ export class Envs {
/**
* 解析剧集标题过滤正则
- * @param {Object} env 环境对象
* @returns {RegExp} 过滤正则表达式
*/
- static resolveEpisodeTitleFilter(env) {
+ static resolveEpisodeTitleFilter() {
const defaultFilter = '(特别|惊喜|纳凉)?企划|合伙人手记|超前(营业|vlog)?|速览|vlog|reaction|纯享|加更(版|篇)?|抢先(看|版|集|篇)?|抢鲜|预告|花絮(独家)?|' +
'特辑|彩蛋|专访|幕后(故事|花絮|独家)?|直播(陪看|回顾)?|未播(片段)?|衍生|番外|会员(专享|加长|尊享|专属|版)?|片花|精华|看点|速看|解读|影评|解说|吐槽|盘点|拍摄花絮|制作花絮|幕后花絮|未播花絮|独家花絮|' +
'花絮特辑|先导预告|终极预告|正式预告|官方预告|彩蛋片段|删减片段|未播片段|番外彩蛋|精彩片段|精彩看点|精彩回顾|精彩集锦|看点解析|看点预告|' +
@@ -164,7 +163,14 @@ export class Envs {
}
/**
- * 解析弹幕转换颜色
+ * 获取记录的原始环境变量 JSON
+ * @returns {Map此接口无需参数
'; + return; + } + + formDiv.innerHTML = config.params.map(param => { + if (param.type === 'select') { + // 为select类型参数添加默认选项 + let optionsHtml = ''; + if (param.options) { + optionsHtml += param.options.map(opt => \`\`).join(''); + } + return \` +暂无配置
'; + }) + .catch(error => { + console.error('Failed to load config for preview:', error); + preview.innerHTML = '加载配置失败: ' + error.message + '
'; + }); +} + +// 获取类别名称 +function getCategoryName(category) { + const names = { + api: '🔗 API配置', + source: '📜 源配置', + match: '🔍 匹配配置', + danmu: '🔣 弹幕配置', + cache: '💾 缓存配置', + system: '⚙️ 系统配置' + }; + return names[category] || category; +} +`; diff --git a/danmu_api/ui/js/pushdanmu.js b/danmu_api/ui/js/pushdanmu.js new file mode 100644 index 0000000..4936627 --- /dev/null +++ b/danmu_api/ui/js/pushdanmu.js @@ -0,0 +1,180 @@ +// language=JavaScript +export const pushDanmuJsContent = /* javascript */ ` +// 推送弹幕功能相关 + +// 搜索动漫用于推送 +function searchAnimeForPush() { + const keyword = document.getElementById('push-search-keyword').value.trim(); + const pushUrl = document.getElementById('push-url').value.trim(); + const searchBtn = document.querySelector('#push-section .btn-primary'); + + if (!keyword) { + customAlert('请输入搜索关键字'); + return; + } + + // 搜索时不再校验pushUrl是否为空,只在推送时校验 + + // 添加加载状态 + const originalText = searchBtn.textContent; + searchBtn.innerHTML = ''; + searchBtn.disabled = true; + + // 构建搜索API请求URL + const searchUrl = buildApiUrl('/api/v2/search/anime?keyword=' + encodeURIComponent(keyword)); + + addLog(\`开始搜索动漫: \${keyword}\`, 'info'); + + // 发送搜索请求 + fetch(searchUrl) + .then(response => { + if (!response.ok) { + throw new Error(\`HTTP error! status: \${response.status}\`); + } + return response.json(); + }) + .then(data => { + if (data.success && data.animes.length > 0) { + displayAnimeListForPush(data.animes, pushUrl); + } else { + document.getElementById('push-anime-list').style.display = 'none'; + document.getElementById('push-episode-list').style.display = 'none'; + customAlert('未找到相关动漫'); + addLog('未找到相关动漫', 'warn'); + } + }) + .catch(error => { + console.error('搜索动漫失败:', error); + customAlert('搜索动漫失败: ' + error.message); + addLog('搜索动漫失败: ' + error.message, 'error'); + }) + .finally(() => { + // 恢复按钮状态 + searchBtn.innerHTML = originalText; + searchBtn.disabled = false; + }); +} + +// 展示动漫列表用于推送 +function displayAnimeListForPush(animes, pushUrl) { + const container = document.getElementById('push-anime-list'); + let html = '暂无配置项
'; + return; + } + + list.innerHTML = items.map((item, index) => { + const typeLabel = item.type === 'boolean' ? '布尔' : + item.type === 'number' ? '数字' : + item.type === 'select' ? '单选' : + item.type === 'multi-select' ? '多选' : '文本'; + const badgeClass = item.type === 'multi-select' ? 'multi' : ''; + + return \` +
当前生效的环境变量配置
+ +支持OK影视等播放器,两端需要在同一局域网或使用公网ip,推送地址格式如 http://127.0.0.1:9978/action?do=refresh&type=danmaku&path=
+vercel/netlify/edgeone平台修改变量后需要重新部署
+