|
|
import { serve } from "https://deno.land/std/http/server.ts"; |
|
|
|
|
|
|
|
|
const API_URL = "https://88.lxmusic.xn--fiqs8s"; |
|
|
const API_KEY = "lxmusic"; |
|
|
|
|
|
|
|
|
const handleBase64Encode = (data: string): string => { |
|
|
return btoa(data); |
|
|
}; |
|
|
|
|
|
|
|
|
const httpFetch = async (url: string, options?: RequestInit): Promise<any> => { |
|
|
const response = await fetch(url, options); |
|
|
if (!response.ok) { |
|
|
throw new Error(`HTTP error! status: ${response.status}`); |
|
|
} |
|
|
return response.json(); |
|
|
}; |
|
|
|
|
|
|
|
|
const handleGetMusicUrl = async (source: string, musicInfo: any, quality: string): Promise<string> => { |
|
|
if (source === "local") { |
|
|
if (!musicInfo.songmid.startsWith("server_")) { |
|
|
throw new Error("unsupported local file"); |
|
|
} |
|
|
|
|
|
const songId = musicInfo.songmid; |
|
|
const requestBody = { p: songId.replace("server_", "") }; |
|
|
const b = handleBase64Encode(JSON.stringify(requestBody)).replace(/\+/g, "-").replace(/\//g, "_"); |
|
|
|
|
|
const targetUrl = `${API_URL}/local/c?q=${b}`; |
|
|
const request = await httpFetch(targetUrl, { |
|
|
method: "GET", |
|
|
headers: { |
|
|
"Content-Type": "application/json", |
|
|
"User-Agent": "lx-music-request", |
|
|
"X-Request-Key": API_KEY, |
|
|
}, |
|
|
}); |
|
|
|
|
|
const { code, data } = request; |
|
|
|
|
|
if (code === 0 && data && data.file) { |
|
|
const b2 = handleBase64Encode(JSON.stringify(requestBody)).replace(/\+/g, "-").replace(/\//g, "_"); |
|
|
return `${API_URL}/local/u?q=${b2}`; |
|
|
} |
|
|
|
|
|
throw new Error("404 Not Found"); |
|
|
} |
|
|
|
|
|
const songId = musicInfo.hash ?? musicInfo.songmid; |
|
|
const request = await httpFetch(`${API_URL}/lxmusicv3/url/${source}/${songId}/${quality}`, { |
|
|
method: "GET", |
|
|
headers: { |
|
|
"Content-Type": "application/json", |
|
|
"User-Agent": "lx-music-request", |
|
|
"X-Request-Key": API_KEY, |
|
|
}, |
|
|
}); |
|
|
|
|
|
const body = request; |
|
|
console.log(body) |
|
|
|
|
|
if (!body || isNaN(Number(body.code))) { |
|
|
throw new Error("unknown error"); |
|
|
} |
|
|
|
|
|
switch (body.code) { |
|
|
case 0: |
|
|
return body.data; |
|
|
case 1: |
|
|
throw new Error("block ip"); |
|
|
case 2: |
|
|
throw new Error("get music url failed"); |
|
|
case 4: |
|
|
throw new Error("internal server error"); |
|
|
case 5: |
|
|
throw new Error("too many requests"); |
|
|
case 6: |
|
|
throw new Error("param error"); |
|
|
default: |
|
|
throw new Error(body.msg ?? "unknown error"); |
|
|
} |
|
|
}; |
|
|
|
|
|
|
|
|
const requestHandler = async (req: Request) => { |
|
|
const url = new URL(req.url); |
|
|
const method = req.method; |
|
|
|
|
|
|
|
|
const headers = new Headers(); |
|
|
headers.set("Access-Control-Allow-Origin", "*"); |
|
|
headers.set("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); |
|
|
headers.set("Access-Control-Allow-Headers", "Content-Type"); |
|
|
headers.set("Content-Type", "application/json"); |
|
|
|
|
|
if (method === "OPTIONS") { |
|
|
return new Response(null, { headers }); |
|
|
} |
|
|
|
|
|
if (url.pathname === "/search") { |
|
|
|
|
|
if (method !== "POST") { |
|
|
return new Response(JSON.stringify({ error: "Method not allowed" }), { |
|
|
status: 405, |
|
|
headers |
|
|
}); |
|
|
} |
|
|
|
|
|
try { |
|
|
|
|
|
const requestBody = await req.text(); |
|
|
if (!requestBody) { |
|
|
return new Response(JSON.stringify({ error: "Request body is empty" }), { |
|
|
status: 400, |
|
|
headers |
|
|
}); |
|
|
} |
|
|
|
|
|
const { action, source, musicInfo, quality } = JSON.parse(requestBody); |
|
|
|
|
|
|
|
|
if (!action) { |
|
|
return new Response(JSON.stringify({ error: "Missing action parameter" }), { |
|
|
status: 400, |
|
|
headers |
|
|
}); |
|
|
} |
|
|
|
|
|
let responseBody; |
|
|
|
|
|
switch (action) { |
|
|
case "musicUrl": |
|
|
if (!source || !musicInfo || !quality) { |
|
|
return new Response(JSON.stringify({ |
|
|
error: "Missing required parameters: source, musicInfo, or quality" |
|
|
}), { status: 400, headers }); |
|
|
} |
|
|
responseBody = await handleGetMusicUrl(source, musicInfo, quality); |
|
|
break; |
|
|
default: |
|
|
return new Response(JSON.stringify({ error: "action not supported" }), { |
|
|
status: 400, |
|
|
headers |
|
|
}); |
|
|
} |
|
|
|
|
|
return new Response(JSON.stringify({ success: true, data: responseBody }), { headers }); |
|
|
|
|
|
} catch (err) { |
|
|
|
|
|
if (err instanceof SyntaxError) { |
|
|
return new Response(JSON.stringify({ error: "Invalid JSON in request body" }), { |
|
|
status: 400, |
|
|
headers |
|
|
}); |
|
|
} |
|
|
return new Response(JSON.stringify({ error: err.message }), { |
|
|
status: 500, |
|
|
headers |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
return new Response(JSON.stringify({ error: "404 Not Found" }), { |
|
|
status: 404, |
|
|
headers |
|
|
}); |
|
|
}; |
|
|
|
|
|
serve(requestHandler, { port: 8000 }); |
|
|
console.log("HTTP server is running on http://localhost:8000"); |