File size: 5,015 Bytes
15a4266
 
 
 
 
 
 
 
 
96ad82e
15a4266
 
 
 
 
 
 
 
96ad82e
 
15a4266
 
 
 
 
96ad82e
 
15a4266
 
 
 
 
 
 
 
 
 
 
 
 
96ad82e
15a4266
96ad82e
15a4266
 
 
 
96ad82e
15a4266
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96ad82e
15a4266
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96ad82e
 
 
15a4266
 
 
 
 
 
96ad82e
15a4266
 
 
 
 
 
 
 
 
96ad82e
15a4266
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96ad82e
15a4266
 
 
 
 
96ad82e
15a4266
96ad82e
15a4266
 
 
 
 
96ad82e
15a4266
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import { serve } from "https://deno.land/std/http/server.ts";

// Consts
const API_URL = "https://88.lxmusic.xn--fiqs8s";
const API_KEY = "lxmusic";

// Base64 编码函数
const handleBase64Encode = (data: string): string => {
  return btoa(data);
};

// 通用 HTTP Fetch 函数
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(); // 假设响应是 JSON 格式
};

// 获取音乐 URL
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; // 成功返回 URL
    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;

  // CORS 支持
  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) {
      // 区分JSON解析错误和其他错误
      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");