diff --git a/src/app/api/music/route.ts b/src/app/api/music/route.ts index e24e5c3..70634c6 100644 --- a/src/app/api/music/route.ts +++ b/src/app/api/music/route.ts @@ -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(), @@ -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); + } } } diff --git a/src/app/music/page.tsx b/src/app/music/page.tsx index 2a8758b..60d0e52 100644 --- a/src/app/music/page.tsx +++ b/src/app/music/page.tsx @@ -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) {