music 兼容cloudflarer

This commit is contained in:
mtvpls
2026-02-04 00:34:50 +08:00
parent 500d5604d9
commit 521205a8c2
2 changed files with 87 additions and 16 deletions
+55 -11
View File
@@ -7,6 +7,9 @@ import { OpenListClient } from '@/lib/openlist.client';
export const runtime = 'nodejs';
// 检测是否为 Cloudflare 环境
const isCloudflare = process.env.CF_PAGES === '1' || process.env.BUILD_TARGET === 'cloudflare';
// 服务器端内存缓存
const serverCache = {
methodConfigs: new Map<string, { data: any; timestamp: number }>(),
@@ -249,11 +252,45 @@ async function executeMethod(
const expressionRegex = /\{\{(.+?)\}\}/g;
return value.replace(expressionRegex, (match, expression) => {
try {
// 创建一个函数来执行表达式,传入所有变量作为参数
// eslint-disable-next-line no-new-func
const func = new Function(...Object.keys(evalContext), `return ${expression}`);
const result = func(...Object.values(evalContext));
return String(result);
// 在 Cloudflare 环境下,使用简单的表达式替换
if (isCloudflare) {
const expr = expression.trim();
// 检查是否是单个变量(没有运算符)
if (evalContext.hasOwnProperty(expr)) {
// 直接返回变量值
return String(evalContext[expr]);
}
// 处理包含运算的表达式(如 page - 1)
let result: any = expr;
// 替换变量为其值
for (const [key, val] of Object.entries(evalContext)) {
const regex = new RegExp(`\\b${key}\\b`, 'g');
// 对于数字直接替换,对于字符串需要加引号以便 eval
const replacement = typeof val === 'number' ? String(val) : `"${String(val).replace(/"/g, '\\"')}"`;
result = result.replace(regex, replacement);
}
// 尝试计算表达式
try {
// eslint-disable-next-line no-eval
result = eval(result);
} catch (err) {
console.error(`[executeMethod] Cloudflare 环境执行表达式失败: ${expr}`, err);
// 如果计算失败,尝试直接返回替换后的结果(去掉可能的引号)
result = result.replace(/^["']|["']$/g, '');
}
return String(result);
} else {
// 在 Node.js 环境下,使用 Function 构造器
// eslint-disable-next-line no-new-func
const func = new Function(...Object.keys(evalContext), `return ${expression}`);
const result = func(...Object.values(evalContext));
return String(result);
}
} catch (err) {
console.error(`[executeMethod] 执行表达式失败: ${expression}`, err);
return '0'; // 默认值
@@ -312,12 +349,19 @@ async function executeMethod(
// 5. 执行 transform 函数(如果有)
if (config.transform) {
try {
// eslint-disable-next-line no-eval
const transformFn = eval(`(${config.transform})`);
data = transformFn(data);
} catch (err) {
console.error('[executeMethod] Transform 函数执行失败:', err);
// 在 Cloudflare 环境下,将 transform 函数返回给前端执行
if (isCloudflare) {
// 将 transform 函数字符串附加到响应数据中
data.__transform = config.transform;
} else {
// 在 Node.js 环境下,直接执行 transform
try {
// eslint-disable-next-line no-eval
const transformFn = eval(`(${config.transform})`);
data = transformFn(data);
} catch (err) {
console.error('[executeMethod] Transform 函数执行失败:', err);
}
}
}
+32 -5
View File
@@ -267,7 +267,9 @@ export default function MusicPage() {
}),
});
const data = await parseResponse.json();
let data = await parseResponse.json();
// 执行前端 transform(如果有)
data = executeTransform(data);
if (data.code === 0 && data.data?.data && data.data.data.length > 0) {
const songData = data.data.data[0];
@@ -357,6 +359,23 @@ export default function MusicPage() {
}
}, [playRecords, pendingSongToPlay]);
// 执行前端 transform(用于 Cloudflare 环境)
const executeTransform = (data: any) => {
if (data && typeof data === 'object' && data.__transform) {
try {
// eslint-disable-next-line no-eval
const transformFn = eval(`(${data.__transform})`);
delete data.__transform; // 删除 transform 字段
return transformFn(data);
} catch (err) {
console.error('[Frontend] Transform 函数执行失败:', err);
delete data.__transform;
return data;
}
}
return data;
};
// 加载排行榜列表
const loadPlaylists = async (source: string) => {
setLoading(true);
@@ -364,7 +383,9 @@ export default function MusicPage() {
const response = await fetch(
`/api/music?action=toplists&platform=${source}`
);
const data = await response.json();
let data = await response.json();
// 执行前端 transform(如果有)
data = executeTransform(data);
// 确保返回的是数组
setPlaylists(Array.isArray(data) ? data : []);
} catch (error) {
@@ -382,7 +403,9 @@ export default function MusicPage() {
const response = await fetch(
`/api/music?action=toplist&platform=${currentSource}&id=${playlistId}`
);
const data = await response.json();
let data = await response.json();
// 执行前端 transform(如果有)
data = executeTransform(data);
// 确保返回的是数组
setSongs(Array.isArray(data) ? data : []);
setCurrentPlaylistTitle(playlistName);
@@ -404,7 +427,9 @@ export default function MusicPage() {
const response = await fetch(
`/api/music?action=search&platform=${currentSource}&keyword=${encodeURIComponent(searchKeyword)}&page=1&pageSize=20`
);
const data = await response.json();
let data = await response.json();
// 执行前端 transform(如果有)
data = executeTransform(data);
// 确保返回的是数组
setSongs(Array.isArray(data) ? data : []);
setCurrentPlaylistTitle(`搜索: ${searchKeyword}`);
@@ -743,7 +768,9 @@ export default function MusicPage() {
}),
});
const data = await response.json();
let data = await response.json();
// 执行前端 transform(如果有)
data = executeTransform(data);
// TuneHub 返回格式: { code: 0, data: { data: [...] } }
if (data.code === 0 && data.data?.data && data.data.data.length > 0) {