feat: 重构VOD服务器配置,支持多服务器并发查询。添加通过视频URL直接获取弹幕的API接口 。 (#46)
* feat: 重构VOD服务器配置,支持多服务器并发查询 - 移除 VOD_SERVER 和 VOD_SERVER2 双服务器配置 - 新增 VOD_SERVERS 支持无限个 VOD 服务器 - 配置格式: 名称@URL,名称@URL,... - 使用 Promise.allSettled 并发查询所有 VOD 服务器 - 单个服务器失败不影响其他服务器 - 调整默认源排序: 360 优先于 vod - 添加 dotenv 支持本地开发 - 新增 .env.example 环境变量配置示例 Breaking Changes: - 环境变量 VOD_SERVER 和 VOD_SERVER2 已废弃 - 请使用 VOD_SERVERS 替代 - 默认 VOD 服务器从 https://gctf.tfdh.top 改为 https://www.caiji.cyou * feat: 添加通过视频URL直接获取弹幕的API接口 - 新增 POST /api/v2/comment/by-url 接口,支持通过视频URL直接获取弹幕 - 新增 getCommentByUrl 函数处理URL推送请求 - 支持 B站、腾讯、爱奇艺、优酷、芒果TV 等主流平台 - 优化 getComment 函数的平台判断逻辑(改为 if-else if) * Update README.md * 更新版本号 修正文档错误示例
This commit is contained in:
1 parent
bc320de259
commit
694e6b9bf8
5 files changed
+258
-51
No files matched your search
@@ -0,0 +1,84 @@
|
||||
# 弹幕 API 环境变量配置示例
|
||||
# 复制此文件为 .env 并根据需要修改配置
|
||||
|
||||
# ==================== 基础配置 ====================
|
||||
|
||||
# API 访问令牌(用于鉴权)
|
||||
# 默认值:87654321
|
||||
TOKEN=87654321
|
||||
|
||||
# 其他服务器地址(第三方弹幕服务器)
|
||||
# 默认值:https://api.danmu.icu
|
||||
OTHER_SERVER=https://api.danmu.icu
|
||||
|
||||
# ==================== VOD 配置 ====================
|
||||
|
||||
# VOD 服务器配置(支持多服务器)
|
||||
# 格式:名称@URL,名称@URL,...
|
||||
# 示例:VOD_SERVERS=vod1@https://api1.com,vod2@https://api2.com,vod3@https://api3.com
|
||||
# 如果不指定名称,会自动生成 vod-1, vod-2 等名称
|
||||
# 默认值:vod@https://www.caiji.cyou
|
||||
VOD_SERVERS=vod@https://www.caiji.cyou
|
||||
|
||||
# ==================== Bilibili 配置 ====================
|
||||
|
||||
# Bilibili Cookie(用于访问需要登录的内容)
|
||||
# 默认值:空(不使用 Cookie)
|
||||
# BILIBILI_COOKIE=
|
||||
|
||||
# ==================== 优酷配置 ====================
|
||||
|
||||
# 优酷并发数(最大:16)
|
||||
# 默认值:8
|
||||
YOUKU_CONCURRENCY=8
|
||||
|
||||
# ==================== 源排序配置 ====================
|
||||
|
||||
# 数据源查询顺序(可选值:360, vod, renren, hanjutv, bahamut)
|
||||
# 默认值:360,vod,renren,hanjutv
|
||||
# 注意:bahamut 仅在 Cloudflare 和 Vercel 平台自动启用
|
||||
SOURCE_ORDER=360,vod,renren,hanjutv
|
||||
|
||||
# ==================== 平台排序配置 ====================
|
||||
|
||||
# 平台优先级排序(用于自动匹配)
|
||||
# 默认值:空(自动匹配)
|
||||
# 可选值:youku,bilibili,iqiyi,qq,mgtv
|
||||
# PLATFORM_ORDER=
|
||||
|
||||
# ==================== 剧集标题过滤 ====================
|
||||
|
||||
# 剧集标题过滤正则表达式(用于过滤花絮、预告等非正片内容)
|
||||
# 默认值:包含大量关键词的复杂正则表达式
|
||||
# 如需自定义,请参考代码中的 DEFAULT_EPISODE_TITLE_FILTER
|
||||
# EPISODE_TITLE_FILTER=
|
||||
|
||||
# ==================== 屏蔽词配置 ====================
|
||||
|
||||
# 屏蔽词列表(用于过滤弹幕内容)
|
||||
# 默认值:空
|
||||
# BLOCKED_WORDS=
|
||||
|
||||
# ==================== 弹幕去重配置 ====================
|
||||
|
||||
# 分钟内合并去重(最大值:30,0 表示不去重)
|
||||
# 默认值:1
|
||||
GROUP_MINUTE=1
|
||||
|
||||
# ==================== 代理配置 ====================
|
||||
|
||||
# 代理地址(用于访问受限资源)
|
||||
# 默认值:空(不使用代理)
|
||||
# 格式:http://proxy-server:port 或 https://proxy-server:port
|
||||
# PROXY_URL=
|
||||
|
||||
# ==================== Redis 配置(Upstash)====================
|
||||
|
||||
# Upstash Redis REST URL(用于缓存)
|
||||
# 默认值:空(不使用 Redis)
|
||||
# UPSTASH_REDIS_REST_URL=
|
||||
|
||||
# Upstash Redis REST Token
|
||||
# 默认值:空
|
||||
# UPSTASH_REDIS_REST_TOKEN=
|
||||
|
||||
@@ -34,6 +34,7 @@ LogVar 弹幕 API 服务器
|
||||
- `GET /api/v2/search/episodes`:根据关键词搜索所有匹配的剧集信息。
|
||||
- `GET /api/v2/bangumi/:animeId`:获取指定动漫的详细信息。
|
||||
- `GET /api/v2/comment/:commentId?withRelated=true&chConvert=1`:获取指定弹幕评论,支持返回相关评论和字符转换。
|
||||
- `POST /api/v2/comment/by-url`:通过视频URL直接获取弹幕。
|
||||
- `GET /api/logs`:获取最近的日志(最多 500 行,格式为 `[时间戳] 级别: 消息`)。
|
||||
- **日志记录**:捕获 `console.log`(info 级别)和 `console.error`(error 级别),JSON 内容格式化输出。
|
||||
- **部署支持**:支持本地运行、Docker 容器化、Vercel 一键部署、Cloudflare 一键部署和 Docker 一键启动。
|
||||
@@ -73,10 +74,11 @@ LogVar 弹幕 API 服务器
|
||||
使用 Postman 或 curl 测试:
|
||||
- `GET http://{ip}:9321/87654321`
|
||||
- `GET http://{ip}:9321/87654321/api/v2/search/anime?keyword=生万物`
|
||||
- `POST http://{ip}:9321/87654321/api/v2/api/v2/match`
|
||||
- `POST http://{ip}:9321/87654321/api/v2/match`
|
||||
- `GET http://{ip}:9321/87654321/api/v2/search/episodes?anime=生万物`
|
||||
- `GET http://{ip}:9321/87654321/api/v2/bangumi/1`
|
||||
- `GET http://{ip}:9321/87654321/api/v2/comment/1?withRelated=true&chConvert=1`
|
||||
- `POST http://{ip}:9321/87654321/api/v2/comment/by-url`
|
||||
- `GET http://{ip}:9321/87654321/api/logs`
|
||||
|
||||
## 使用 Docker 运行
|
||||
@@ -224,8 +226,7 @@ LogVar 弹幕 API 服务器
|
||||
| ----------- | ----------- |
|
||||
| TOKEN | 【可选】自定义用户token,不填默认为`87654321` |
|
||||
| OTHER_SERVER | 【可选】兜底第三方弹幕服务器,不填默认为`https://api.danmu.icu` |
|
||||
| VOD_SERVER | 【可选】vod查询站点,不填默认为`https://gctf.tfdh.top` |
|
||||
| VOD_SERVER2 | 【可选】vod2查询站点,如果想开启vod2源,请先填写VOD_SERVER2源地址,如`https://www.caiji.cyou`、`https://zy.xmm.hk`,并在SOURCE_ORDER环境变量中增加`vod2` |
|
||||
| VOD_SERVERS | 【可选】VOD服务器列表,支持多个服务器并发查询,格式:`名称@URL,名称@URL,...`,示例:`vod@https://www.caiji.cyou,vod2@https://zy.xmm.hk`,不填默认为`vod@https://www.caiji.cyou` |
|
||||
| BILIBILI_COOKIE | 【可选】b站cookie(填入后能抓取完整弹幕),如 `buvid3=E2BCA ... eao6; theme-avatar-tip-show=SHOWED`,请自行通过浏览器或抓包工具抓取,热心网友测试后,实际最少只需取 `SESSDATA=xxxx` 字段 |
|
||||
| YOUKU_CONCURRENCY | 【可选】youku弹幕请求并发数,用于加快youku弹幕请求速度,不填默认为`8`,最高`16` |
|
||||
| SOURCE_ORDER | 【可选】源排序,用于按源对返回资源的排序(注意:先后顺序会影响自动匹配最终的返回),默认是`vod,360,renren,hanjutv`,表示vod数据排在最前,hanjutv数据排在最后,示例:`360,renren`:只返回360数据和renren数据,且360数据靠前;当前可选择的源字段有 `vod,vod2,360,renren,hanjutv,bahamut` |
|
||||
@@ -301,7 +302,7 @@ danmu_api/
|
||||
- 运行 Docker 容器时,需通过 `-e TOKEN=87654321` 传递 `TOKEN` 环境变量。
|
||||
- cloudflare貌似被哔风控了。
|
||||
- 如果想更换兜底第三方弹幕服务器,请添加环境变量`OTHER_SERVER`,示例`https://api.danmu.icu`。
|
||||
- 如果想更换vod站点,请添加环境变量`VOD_SERVER`,示例`https://www.caiji.cyou`。
|
||||
- 如果想更换vod站点,请添加环境变量`VOD_SERVERS`,示例`vod@https://www.caiji.cyou,vod2@https://zy.xmm.hk`(支持多个服务器并发查询)。
|
||||
- 推荐vercel部署,cloudflare/edgeone/claw不稳定,当然最稳定还是自己本地docker部署最佳。
|
||||
- /api/v2/comment接口1分钟内同一IP只能请求三次。
|
||||
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
// server.js - 智能服务器启动器:根据 Node.js 环境自动选择最优启动模式
|
||||
|
||||
// 加载 .env 文件中的环境变量(本地开发时使用)
|
||||
try {
|
||||
require('dotenv').config();
|
||||
console.log('[server] .env file loaded successfully');
|
||||
} catch (e) {
|
||||
console.log('[server] dotenv not available or .env file not found, using system environment variables');
|
||||
}
|
||||
|
||||
// 导入 ES module 兼容层(始终加载,但内部会根据需要启用)
|
||||
require('./esm-shim');
|
||||
|
||||
|
||||
+159
-47
@@ -1,6 +1,6 @@
|
||||
// 全局状态(Cloudflare 和 Vercel 都可能重用实例)
|
||||
// ⚠️ 不是持久化存储,每次冷启动会丢失
|
||||
const VERSION = "1.3.1";
|
||||
const VERSION = "1.3.2";
|
||||
let animes = [];
|
||||
let episodeIds = [];
|
||||
let episodeNum = 10001; // 全局变量,用于自增 ID
|
||||
@@ -43,22 +43,39 @@ function resolveOtherServer(env) {
|
||||
return DEFAULT_OTHER_SERVER;
|
||||
}
|
||||
|
||||
const DEFAULT_VOD_SERVER = "https://gctf.tfdh.top"; // 默认 vod站点
|
||||
let vodServer = DEFAULT_VOD_SERVER;
|
||||
const DEFAULT_VOD_SERVERS = "vod@https://www.caiji.cyou"; // 默认 vod站点配置,格式:名称@URL,名称@URL
|
||||
let vodServers = [];
|
||||
|
||||
function resolveVodServer(env) {
|
||||
if (env && env.VOD_SERVER) return env.VOD_SERVER; // Cloudflare Workers
|
||||
if (typeof process !== "undefined" && process.env?.VOD_SERVER) return process.env.VOD_SERVER; // Vercel / Node
|
||||
return DEFAULT_VOD_SERVER;
|
||||
}
|
||||
function resolveVodServers(env) {
|
||||
// 获取配置字符串
|
||||
let vodServersConfig = DEFAULT_VOD_SERVERS;
|
||||
if (env && env.VOD_SERVERS) {
|
||||
vodServersConfig = env.VOD_SERVERS; // Cloudflare Workers
|
||||
} else if (typeof process !== "undefined" && process.env?.VOD_SERVERS) {
|
||||
vodServersConfig = process.env.VOD_SERVERS; // Vercel / Node
|
||||
}
|
||||
|
||||
const DEFAULT_VOD_SERVER2 = ""; // 默认 vod站点2
|
||||
let vodServer2 = DEFAULT_VOD_SERVER2;
|
||||
// 解析配置:支持 "名称@URL,名称@URL" 格式
|
||||
if (!vodServersConfig || vodServersConfig.trim() === "") {
|
||||
return [];
|
||||
}
|
||||
|
||||
function resolveVodServer2(env) {
|
||||
if (env && env.VOD_SERVER2) return env.VOD_SERVER2; // Cloudflare Workers
|
||||
if (typeof process !== "undefined" && process.env?.VOD_SERVER2) return process.env.VOD_SERVER2; // Vercel / Node
|
||||
return DEFAULT_VOD_SERVER2;
|
||||
const servers = vodServersConfig
|
||||
.split(',')
|
||||
.map(s => s.trim())
|
||||
.filter(s => s.length > 0)
|
||||
.map((item, index) => {
|
||||
if (item.includes('@')) {
|
||||
const [name, url] = item.split('@').map(s => s.trim());
|
||||
return { name: name || `vod-${index + 1}`, url };
|
||||
} else {
|
||||
// 没有 @ 符号,自动生成名称
|
||||
return { name: `vod-${index + 1}`, url: item };
|
||||
}
|
||||
})
|
||||
.filter(server => server.url && server.url.length > 0); // 过滤掉空 URL
|
||||
|
||||
return servers;
|
||||
}
|
||||
|
||||
const DEFAULT_BILIBILI_COOKIE = ""; // 默认 bilibili cookie
|
||||
@@ -87,7 +104,7 @@ function resolveYoukuConcurrency(env) {
|
||||
return Math.min(DEFAULT_YOUKU_CONCURRENCY, 16);
|
||||
}
|
||||
|
||||
const DEFAULT_SOURCE_ORDER = "vod,360,renren,hanjutv"; // 默认 源排序
|
||||
const DEFAULT_SOURCE_ORDER = "360,vod,renren,hanjutv"; // 默认 源排序
|
||||
let sourceOrderArr = [];
|
||||
|
||||
function resolveSourceOrder(env, deployPlatform) {
|
||||
@@ -103,8 +120,8 @@ function resolveSourceOrder(env, deployPlatform) {
|
||||
sourceOrder = process.env.SOURCE_ORDER; // Vercel / Node
|
||||
}
|
||||
|
||||
// 解析并校验 sourceOrder
|
||||
const allowedSources = ['vod', 'vod2', '360', 'renren', "hanjutv", "bahamut"];
|
||||
// 解析并校验 sourceOrder(移除 vod2,因为已合并到 vod)
|
||||
const allowedSources = ['360', 'vod', 'renren', "hanjutv", "bahamut"];
|
||||
|
||||
// 转换为数组并去除空格,过滤无效项
|
||||
const orderArr = sourceOrder
|
||||
@@ -848,7 +865,7 @@ async function get360Zongyi(title, entId, site, year) {
|
||||
}
|
||||
|
||||
// 查询vod站点影片信息
|
||||
async function getVodAnimes(title, server) {
|
||||
async function getVodAnimes(title, server, serverName) {
|
||||
try {
|
||||
const response = await httpGet(
|
||||
`${server}/api.php/provide/vod/?ac=detail&wd=${title}&pg=1`,
|
||||
@@ -861,23 +878,42 @@ async function getVodAnimes(title, server) {
|
||||
);
|
||||
// 检查 response.data.list 是否存在且长度大于 0
|
||||
if (response && response.data && response.data.list && response.data.list.length > 0) {
|
||||
log("info", `请求 ${vodServer} 成功`);
|
||||
log("info", `请求 ${serverName}(${server}) 成功`);
|
||||
const data = response.data;
|
||||
log("info", "vod response: ↓↓↓");
|
||||
log("info", `${serverName} response: ↓↓↓`);
|
||||
printFirst200Chars(data);
|
||||
return data.list;
|
||||
return { serverName, list: data.list };
|
||||
} else {
|
||||
log("info", `请求 ${vodServer} 成功,但 response.data.list 为空`);
|
||||
return [];
|
||||
log("info", `请求 ${serverName}(${server}) 成功,但 response.data.list 为空`);
|
||||
return { serverName, list: [] };
|
||||
}
|
||||
} catch (error) {
|
||||
log("error", `请求 ${vodServer} 失败:`, {
|
||||
log("error", `请求 ${serverName}(${server}) 失败:`, {
|
||||
message: error.message,
|
||||
name: error.name,
|
||||
stack: error.stack,
|
||||
});
|
||||
return { serverName, list: [] };
|
||||
}
|
||||
}
|
||||
|
||||
// 查询所有vod站点影片信息(并发查询)
|
||||
async function getVodAnimesFromAllServers(title, servers) {
|
||||
if (!servers || servers.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 并发查询所有服务器,使用 allSettled 确保单个服务器失败不影响其他服务器
|
||||
const promises = servers.map(server =>
|
||||
getVodAnimes(title, server.url, server.name)
|
||||
);
|
||||
|
||||
const results = await Promise.allSettled(promises);
|
||||
|
||||
// 过滤出成功的结果,即使某些服务器失败也不影响其他服务器
|
||||
return results
|
||||
.filter(result => result.status === 'fulfilled')
|
||||
.map(result => result.value);
|
||||
}
|
||||
|
||||
// =====================
|
||||
@@ -3792,9 +3828,8 @@ async function searchAnime(url) {
|
||||
// 根据 sourceOrderArr 动态构建请求数组
|
||||
log("info", `Search sourceOrderArr: ${sourceOrderArr}`);
|
||||
const requestPromises = sourceOrderArr.map(source => {
|
||||
if (source === "vod") return getVodAnimes(queryTitle, vodServer);
|
||||
if (source === "vod2") return getVodAnimes(queryTitle, vodServer2);
|
||||
if (source === "360") return get360Animes(queryTitle);
|
||||
if (source === "vod") return getVodAnimesFromAllServers(queryTitle, vodServers);
|
||||
if (source === "renren") return renrenSearch(queryTitle);
|
||||
if (source === "hanjutv") return hanjutvSearch(queryTitle);
|
||||
if (source === "bahamut") return bahamutSearch(traditionalized(queryTitle));
|
||||
@@ -3812,19 +3847,22 @@ async function searchAnime(url) {
|
||||
});
|
||||
|
||||
// 解构出返回的结果
|
||||
const { vod: animesVod, vod2: animesVod2, 360: animes360, renren: animesRenren, hanjutv: animesHanjutv, bahamut: animesBahamut } = resultData;
|
||||
const { vod: animesVodResults, 360: animes360, renren: animesRenren, hanjutv: animesHanjutv, bahamut: animesBahamut } = resultData;
|
||||
|
||||
// 按顺序处理每个来源的结果
|
||||
for (const key of sourceOrderArr) {
|
||||
if (key === 'vod') {
|
||||
// 等待处理Vod来源
|
||||
await handleVodAnimes(animesVod, curAnimes, key);
|
||||
} else if (key === 'vod2') {
|
||||
// 等待处理Vod2来源
|
||||
await handleVodAnimes(animesVod2, curAnimes, key);
|
||||
} else if (key === '360') {
|
||||
if (key === '360') {
|
||||
// 等待处理360来源
|
||||
await handle360Animes(animes360, curAnimes);
|
||||
} else if (key === 'vod') {
|
||||
// 等待处理Vod来源(遍历所有VOD服务器的结果)
|
||||
if (animesVodResults && Array.isArray(animesVodResults)) {
|
||||
for (const vodResult of animesVodResults) {
|
||||
if (vodResult && vodResult.list && vodResult.list.length > 0) {
|
||||
await handleVodAnimes(vodResult.list, curAnimes, vodResult.serverName);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (key === 'renren') {
|
||||
// 等待处理Renren来源
|
||||
await handleRenrenAnimes(animesRenren, queryTitle, curAnimes);
|
||||
@@ -4261,17 +4299,13 @@ async function getComment(path) {
|
||||
let danmus = [];
|
||||
if (url.includes('.qq.com')) {
|
||||
danmus = await fetchTencentVideo(url);
|
||||
}
|
||||
if (url.includes('.iqiyi.com')) {
|
||||
} else if (url.includes('.iqiyi.com')) {
|
||||
danmus = await fetchIqiyi(url);
|
||||
}
|
||||
if (url.includes('.mgtv.com')) {
|
||||
} else if (url.includes('.mgtv.com')) {
|
||||
danmus = await fetchMangoTV(url);
|
||||
}
|
||||
if (url.includes('.bilibili.com')) {
|
||||
} else if (url.includes('.bilibili.com')) {
|
||||
danmus = await fetchBilibili(url);
|
||||
}
|
||||
if (url.includes('.youku.com')) {
|
||||
} else if (url.includes('.youku.com')) {
|
||||
danmus = await fetchYouku(url);
|
||||
}
|
||||
|
||||
@@ -4301,15 +4335,88 @@ async function getComment(path) {
|
||||
return jsonResponse({ count: danmus.length, comments: danmus });
|
||||
}
|
||||
|
||||
// Extracted function for POST /api/v2/comment/by-url
|
||||
async function getCommentByUrl(req) {
|
||||
try {
|
||||
// 获取请求体
|
||||
const body = await req.json();
|
||||
|
||||
// 验证请求体是否有效
|
||||
if (!body || !body.videoUrl) {
|
||||
log("error", "Missing videoUrl parameter in request body");
|
||||
return jsonResponse(
|
||||
{ errorCode: 400, success: false, errorMessage: "Missing videoUrl parameter", count: 0, comments: [] },
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
const videoUrl = body.videoUrl.trim();
|
||||
|
||||
// 验证URL格式
|
||||
if (!videoUrl.startsWith('http')) {
|
||||
log("error", "Invalid videoUrl format");
|
||||
return jsonResponse(
|
||||
{ errorCode: 400, success: false, errorMessage: "Invalid videoUrl format", count: 0, comments: [] },
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
log("info", `Processing comment request for URL: ${videoUrl}`);
|
||||
|
||||
// 处理优酷302场景
|
||||
let url = videoUrl;
|
||||
if (url.includes("youku.com/video?vid")) {
|
||||
url = convertYoukuUrl(url);
|
||||
}
|
||||
|
||||
log("info", "开始从本地请求弹幕...", url);
|
||||
let danmus = [];
|
||||
|
||||
// 根据URL域名判断平台并获取弹幕
|
||||
if (url.includes('.qq.com')) {
|
||||
danmus = await fetchTencentVideo(url);
|
||||
} else if (url.includes('.iqiyi.com')) {
|
||||
danmus = await fetchIqiyi(url);
|
||||
} else if (url.includes('.mgtv.com')) {
|
||||
danmus = await fetchMangoTV(url);
|
||||
} else if (url.includes('.bilibili.com') || url.includes('b23.tv')) {
|
||||
danmus = await fetchBilibili(url);
|
||||
} else if (url.includes('.youku.com')) {
|
||||
danmus = await fetchYouku(url);
|
||||
} else {
|
||||
// 如果不是已知平台,尝试第三方弹幕服务器
|
||||
const urlPattern = /^(https?:\/\/)?([\w.-]+)\.([a-z]{2,})(\/.*)?$/i;
|
||||
if (urlPattern.test(url)) {
|
||||
danmus = await fetchOtherServer(url);
|
||||
}
|
||||
}
|
||||
|
||||
log("info", `Successfully fetched ${danmus.length} comments from URL`);
|
||||
|
||||
return jsonResponse({
|
||||
errorCode: 0,
|
||||
success: true,
|
||||
errorMessage: "",
|
||||
count: danmus.length,
|
||||
comments: danmus
|
||||
});
|
||||
} catch (error) {
|
||||
// 处理 JSON 解析错误或其他异常
|
||||
log("error", `Failed to process comment by URL request: ${error.message}`);
|
||||
return jsonResponse(
|
||||
{ errorCode: 500, success: false, errorMessage: "Internal server error", count: 0, comments: [] },
|
||||
500
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleRequest(req, env, deployPlatform, clientIp) {
|
||||
token = resolveToken(env); // 每次请求动态获取,确保热更新环境变量后也能生效
|
||||
envs["token"] = encryptStr(token);
|
||||
otherServer = resolveOtherServer(env);
|
||||
envs["otherServer"] = otherServer;
|
||||
vodServer = resolveVodServer(env);
|
||||
envs["vodServer"] = vodServer;
|
||||
vodServer2 = resolveVodServer2(env);
|
||||
envs["vodServer2"] = vodServer2;
|
||||
vodServers = resolveVodServers(env);
|
||||
envs["vodServers"] = vodServers.map(s => `${s.name}@${s.url}`).join(',');
|
||||
bilibliCookie = resolveBilibiliCookie(env);
|
||||
envs["bilibliCookie"] = encryptStr(bilibliCookie);
|
||||
youkuConcurrency = resolveYoukuConcurrency(env);
|
||||
@@ -4446,6 +4553,11 @@ async function handleRequest(req, env, deployPlatform, clientIp) {
|
||||
return getBangumi(path);
|
||||
}
|
||||
|
||||
// POST /api/v2/comment/by-url
|
||||
if (path === "/api/v2/comment/by-url" && method === "POST") {
|
||||
return getCommentByUrl(req);
|
||||
}
|
||||
|
||||
// GET /api/v2/comment/:commentId
|
||||
if (path.startsWith("/api/v2/comment/") && method === "GET") {
|
||||
// 获取当前时间戳(单位:毫秒)
|
||||
@@ -4529,7 +4641,7 @@ export async function vercelHandler(req, res) {
|
||||
}
|
||||
|
||||
// 为了测试导出 handleRequest
|
||||
export { handleRequest, searchAnime, searchEpisodes, matchAnime, getBangumi, getComment, fetchTencentVideo, fetchIqiyi,
|
||||
export { handleRequest, searchAnime, searchEpisodes, matchAnime, getBangumi, getComment, getCommentByUrl, fetchTencentVideo, fetchIqiyi,
|
||||
fetchMangoTV, fetchBilibili, fetchYouku, fetchOtherServer, httpGet, httpPost, hanjutvSearch, getHanjutvEpisodes,
|
||||
getHanjutvComments, getHanjutvDetail, bahamutSearch, getBahamutEpisodes, getBahamutComments, pingRedis, getRedisKey,
|
||||
setRedisKey, setRedisKeyWithExpiry};
|
||||
@@ -9,6 +9,7 @@
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"dotenv": "^16.4.7",
|
||||
"esbuild": "^0.25.10",
|
||||
"https-proxy-agent": "^7.0.6",
|
||||
"node-fetch": "^3.3.2"
|
||||
|
||||
Reference in new issue
Block a user