addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)) }) // Base58 编码函数(Cloudflare Workers 兼容) const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' function base58Encode(obj) { const str = JSON.stringify(obj) const bytes = new TextEncoder().encode(str) // Uint8Array // 转 BigInt let intVal = 0n for (let b of bytes) { intVal = (intVal << 8n) + BigInt(b) } // 编码为 Base58 let result = '' while (intVal > 0n) { const mod = intVal % 58n result = BASE58_ALPHABET[Number(mod)] + result intVal = intVal / 58n } // 保留前导零 for (let b of bytes) { if (b === 0) result = BASE58_ALPHABET[0] + result else break } return result } // JSON api 字段前缀替换 function addOrReplacePrefix(obj, newPrefix) { if (typeof obj !== 'object' || obj === null) return obj if (Array.isArray(obj)) return obj.map(item => addOrReplacePrefix(item, newPrefix)) const newObj = {} for (const key in obj) { if (key === 'api' && typeof obj[key] === 'string') { let apiUrl = obj[key] const urlIndex = apiUrl.indexOf('?url=') if (urlIndex !== -1) apiUrl = apiUrl.slice(urlIndex + 5) if (!apiUrl.startsWith(newPrefix)) apiUrl = newPrefix + apiUrl newObj[key] = apiUrl } else { newObj[key] = addOrReplacePrefix(obj[key], newPrefix) } } return newObj } async function handleRequest(request) { const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization', 'Access-Control-Max-Age': '86400', } if (request.method === 'OPTIONS') return new Response(null, { status: 204, headers: corsHeaders }) const reqUrl = new URL(request.url) const targetUrlParam = reqUrl.searchParams.get('url') const configParam = reqUrl.searchParams.get('config') const prefixParam = reqUrl.searchParams.get('prefix') const encodeParam = reqUrl.searchParams.get('encode') const currentOrigin = reqUrl.origin const defaultPrefix = currentOrigin + '/?url=' // -------------------- 通用 API 中转代理 -------------------- if (targetUrlParam) { let fullTargetUrl = targetUrlParam const urlMatch = request.url.match(/[?&]url=([^&]+(?:&.*)?)/) if (urlMatch) fullTargetUrl = decodeURIComponent(urlMatch[1]) let targetURL try { targetURL = new URL(fullTargetUrl) } catch (e) { return new Response(JSON.stringify({ error: 'Invalid URL', url: fullTargetUrl }, null, 2), { status: 400, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }) } try { const proxyRequest = new Request(targetURL.toString(), { method: request.method, headers: request.headers, body: request.method !== 'GET' && request.method !== 'HEAD' ? await request.arrayBuffer() : undefined, }) const controller = new AbortController() const timeoutId = setTimeout(() => controller.abort(), 30000) const response = await fetch(proxyRequest, { signal: controller.signal }) clearTimeout(timeoutId) const responseHeaders = new Headers(corsHeaders) const excludeHeaders = [ 'content-encoding', 'content-length', 'transfer-encoding', 'connection', 'keep-alive', 'set-cookie', 'set-cookie2' ] for (const [key, value] of response.headers) { if (!excludeHeaders.includes(key.toLowerCase())) responseHeaders.set(key, value) } return new Response(response.body, { status: response.status, statusText: response.statusText, headers: responseHeaders }) } catch (err) { return new Response(JSON.stringify({ error: 'Proxy Error', message: err.message || '代理请求失败', target: fullTargetUrl, timestamp: new Date().toISOString() }, null, 2), { status: 502, headers: { 'Content-Type': 'application/json; charset=utf-8', ...corsHeaders } }) } } // -------------------- JSON 配置 + API 前缀替换 + Base58 -------------------- if (configParam === '1') { try { const jsonUrl = 'https://raw.githubusercontent.com/hafrey1/LunaTV-config/main/LunaTV-config.json' const response = await fetch(jsonUrl) const data = await response.json() const newData = addOrReplacePrefix(data, prefixParam || defaultPrefix) if (encodeParam === 'base58') { const encoded = base58Encode(newData) return new Response(encoded, { headers: { 'Content-Type': 'text/plain;charset=UTF-8', ...corsHeaders }, }) } else { return new Response(JSON.stringify(newData), { headers: { 'Content-Type': 'application/json;charset=UTF-8', ...corsHeaders }, }) } } catch (err) { return new Response(JSON.stringify({ error: err.message }), { status: 500, headers: { 'Content-Type': 'application/json;charset=UTF-8', ...corsHeaders }, }) } } // -------------------- JSON 配置(原始,不加前缀) config=0 -------------------- if (configParam === '0') { try { const jsonUrl = 'https://raw.githubusercontent.com/hafrey1/LunaTV-config/main/LunaTV-config.json' const response = await fetch(jsonUrl) const data = await response.json() if (encodeParam === 'base58') { const encoded = base58Encode(data) return new Response(encoded, { headers: { 'Content-Type': 'text/plain;charset=UTF-8', ...corsHeaders }, }) } else { return new Response(JSON.stringify(data), { headers: { 'Content-Type': 'application/json;charset=UTF-8', ...corsHeaders }, }) } } catch (err) { return new Response(JSON.stringify({ error: err.message }), { status: 500, headers: { 'Content-Type': 'application/json;charset=UTF-8', ...corsHeaders }, }) } } // -------------------- 根目录或其他情况返回说明页面 -------------------- const html = `
通用 API 中转代理,用于访问被墙或限制的接口。
中转任意 API:在请求 URL 后添加 ?url=目标地址
参数
${defaultPrefix}https://example.com/api
原始JSON 配置:
${currentOrigin}?config=0
JSON 配置:
${currentOrigin}?config=1
Base58 编码订阅:
${currentOrigin}?config=1&encode=base58
JSON 配置 + 自定义中转API:
${currentOrigin}?config=1&prefix=自定义中转API