195 lines
5.0 KiB
TypeScript
195 lines
5.0 KiB
TypeScript
/**
|
|
* 路由模块 (Deno 版本)
|
|
* 定义所有 API 路由
|
|
*/
|
|
|
|
import { Hono } from "hono";
|
|
import { cors } from "cors";
|
|
import { ConnectionManager } from "./websocket_manager.ts";
|
|
import { getMusicStatus, controlMusic } from "./apple_music.ts";
|
|
import { getLyricsData, searchLyrics, saveLyrics, deleteLyrics } from "./lyrics.ts";
|
|
|
|
export interface ControlRequest {
|
|
action: "playpause" | "previous" | "next" | "seek";
|
|
position?: number;
|
|
}
|
|
|
|
export interface SearchLyricsRequest {
|
|
track_name: string;
|
|
artist: string;
|
|
}
|
|
|
|
export interface GetLyricsFromIdRequest {
|
|
title: string;
|
|
artist: string;
|
|
}
|
|
|
|
export interface SaveLyricsRequest {
|
|
track_name: string;
|
|
artist: string;
|
|
lyrics: string;
|
|
}
|
|
|
|
export interface DeleteLyricsRequest {
|
|
track_name: string;
|
|
artist: string;
|
|
}
|
|
|
|
/**
|
|
* 注册所有路由
|
|
*/
|
|
export function registerRoutes(app: Hono, manager: ConnectionManager): void {
|
|
// 添加中间件
|
|
app.use("*", async (c, next) => {
|
|
if (c.req.path !== "/ws") {
|
|
console.log("[CORS middleware triggered]", c.req.method, c.req.path)
|
|
return await cors({
|
|
origin: "*",
|
|
allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
|
allowHeaders: ["Content-Type", "Authorization"],
|
|
})(c, next);
|
|
} else {
|
|
return await next();
|
|
}
|
|
});
|
|
|
|
// 健康检查
|
|
app.get("/health", (c) => {
|
|
return c.json({
|
|
status: "ok",
|
|
timestamp: Date.now(),
|
|
connections: manager.getConnectionCount(),
|
|
});
|
|
});
|
|
|
|
// 获取音乐状态
|
|
app.get("/music/status", async (c) => {
|
|
try {
|
|
const status = await getMusicStatus();
|
|
return c.json(status);
|
|
} catch (error) {
|
|
return c.json({ status: "error", error: String(error) }, 500);
|
|
}
|
|
});
|
|
|
|
// 控制音乐播放
|
|
app.post("/music/control", async (c) => {
|
|
try {
|
|
const body = (await c.req.json()) as ControlRequest;
|
|
|
|
if (!body.action) {
|
|
return c.json({ status: "error", message: "缺少 action 参数" }, 400);
|
|
}
|
|
|
|
const result = await controlMusic(body.action, body.position);
|
|
return c.json(result);
|
|
} catch (error) {
|
|
return c.json({ status: "error", message: String(error) }, 500);
|
|
}
|
|
});
|
|
|
|
// 获取歌词
|
|
app.get("/lyrics", async (c) => {
|
|
try {
|
|
const status = await getMusicStatus();
|
|
const lyricsData = await getLyricsData(status);
|
|
return c.json(lyricsData);
|
|
} catch (error) {
|
|
return c.json({ status: "error", error: String(error) }, 500);
|
|
}
|
|
});
|
|
|
|
app.delete("/lyrics", async (c) => {
|
|
try {
|
|
const body = (await c.req.json()) as DeleteLyricsRequest;
|
|
const { track_name, artist } = body;
|
|
await deleteLyrics(track_name, artist);
|
|
return c.json({ status: "success", message: "歌词删除成功" });
|
|
} catch (error) {
|
|
return c.json({ status: "error", error: String(error) }, 500);
|
|
}
|
|
});
|
|
|
|
// 搜索歌词
|
|
app.post("/lyrics/search", async (c) => {
|
|
try {
|
|
const body = (await c.req.json()) as SearchLyricsRequest;
|
|
|
|
const { track_name, artist } = body;
|
|
const lyricsData = await searchLyrics(track_name, artist);
|
|
return c.json({
|
|
status: "success",
|
|
songs: [{
|
|
name: track_name,
|
|
artist: artist,
|
|
lyrics: lyricsData,
|
|
}],
|
|
message: "歌词搜索成功",
|
|
});
|
|
} catch (error) {
|
|
return c.json({ status: "error", error: String(error) }, 500);
|
|
}
|
|
});
|
|
|
|
// 保存歌词
|
|
app.post("/lyrics/save", async (c) => {
|
|
try {
|
|
const body = (await c.req.json()) as SaveLyricsRequest;
|
|
const { track_name, artist, lyrics } = body;
|
|
await saveLyrics(track_name, artist, lyrics, "search");
|
|
return c.json({ status: "success", message: "歌词保存成功" });
|
|
} catch (error) {
|
|
return c.json({ status: "error", error: String(error) }, 500);
|
|
}
|
|
});
|
|
|
|
// 根据歌曲信息获取歌词
|
|
app.post("/lyrics/get", async (c) => {
|
|
try {
|
|
const body = (await c.req.json()) as GetLyricsFromIdRequest;
|
|
|
|
if (!body.title) {
|
|
return c.json({ status: "error", message: "缺少 title 参数" }, 400);
|
|
}
|
|
|
|
// 构造音乐状态对象
|
|
const mockStatus = {
|
|
status: "playing" as const,
|
|
track_name: body.title,
|
|
artist: body.artist || "",
|
|
position: 0,
|
|
duration: 0,
|
|
};
|
|
|
|
const lyricsData = await getLyricsData(mockStatus);
|
|
return c.json(lyricsData);
|
|
} catch (error) {
|
|
return c.json({ status: "error", error: String(error) }, 500);
|
|
}
|
|
});
|
|
|
|
// WebSocket 连接端点
|
|
app.get("/ws", (c) => {
|
|
const upgrade = c.req.header("upgrade");
|
|
|
|
if (upgrade !== "websocket") {
|
|
return c.text("Expected websocket", 400);
|
|
}
|
|
|
|
const { socket, response } = Deno.upgradeWebSocket(c.req.raw);
|
|
const connectionId = `conn_${Date.now()}_${Math.random()
|
|
.toString(36)
|
|
.substr(2, 9)}`;
|
|
|
|
// 添加连接到管理器
|
|
manager.addConnection(connectionId, socket);
|
|
|
|
return response;
|
|
});
|
|
|
|
// 404 处理
|
|
app.notFound((c) => {
|
|
return c.json({ status: "error", message: "Not Found" }, 404);
|
|
});
|
|
}
|