mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 04:52:50 +08:00
feat(api): /api/bot/:id/avatar GET/PUT/DELETE
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
2dd6a9e20d
commit
935656dc4f
3 files changed
+81
-3
No files matched your search
@@ -74,6 +74,7 @@ async function main() {
|
||||
qqProvider,
|
||||
bilibiliProvider,
|
||||
database: db,
|
||||
avatarStore,
|
||||
config,
|
||||
configPath: CONFIG_PATH,
|
||||
logger,
|
||||
|
||||
+69
-1
@@ -3,12 +3,16 @@ import type { BotManager } from "../../bot/manager.js";
|
||||
import type { BotConfig } from "../../data/config.js";
|
||||
import { saveConfig } from "../../data/config.js";
|
||||
import type { Logger } from "../../logger.js";
|
||||
import type { BotDatabase } from "../../data/database.js";
|
||||
import type { AvatarStore } from "../../data/avatars.js";
|
||||
|
||||
export function createBotRouter(
|
||||
botManager: BotManager,
|
||||
config: BotConfig,
|
||||
configPath: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
botDb: BotDatabase,
|
||||
avatarStore: AvatarStore,
|
||||
): Router {
|
||||
const router = Router();
|
||||
|
||||
@@ -36,6 +40,70 @@ export function createBotRouter(
|
||||
res.json(saved);
|
||||
});
|
||||
|
||||
router.get("/:id/avatar", (req, res) => {
|
||||
const path = botDb.getCustomAvatarPath(req.params.id);
|
||||
if (!path) {
|
||||
res.status(404).end();
|
||||
return;
|
||||
}
|
||||
const buf = avatarStore.read(path);
|
||||
if (!buf) {
|
||||
res.status(404).end();
|
||||
return;
|
||||
}
|
||||
const ext = path.split(".").pop() ?? "";
|
||||
const mime = ext === "png"
|
||||
? "image/png"
|
||||
: ext === "webp"
|
||||
? "image/webp"
|
||||
: "image/jpeg";
|
||||
res.set("Content-Type", mime);
|
||||
res.set("Cache-Control", "no-cache");
|
||||
res.send(buf);
|
||||
});
|
||||
|
||||
router.put("/:id/avatar", (req, res) => {
|
||||
const exists =
|
||||
botManager.getBot(req.params.id) ||
|
||||
botDb.getBotInstances().some((b) => b.id === req.params.id);
|
||||
if (!exists) {
|
||||
res.status(404).json({ error: "Bot not found" });
|
||||
return;
|
||||
}
|
||||
const { dataUrl } = req.body as { dataUrl?: string };
|
||||
if (typeof dataUrl !== "string") {
|
||||
res.status(400).json({ error: "dataUrl required" });
|
||||
return;
|
||||
}
|
||||
const m = /^data:(image\/(?:png|jpeg|webp));base64,(.+)$/.exec(dataUrl);
|
||||
if (!m) {
|
||||
res.status(400).json({ error: "dataUrl must be image/png|jpeg|webp base64" });
|
||||
return;
|
||||
}
|
||||
const mime = m[1] as string;
|
||||
const buf = Buffer.from(m[2] ?? "", "base64");
|
||||
if (buf.length === 0) {
|
||||
res.status(400).json({ error: "empty image" });
|
||||
return;
|
||||
}
|
||||
if (buf.length > 200 * 1024) {
|
||||
res.status(413).json({ error: "avatar exceeds 200KB limit" });
|
||||
return;
|
||||
}
|
||||
const rel = avatarStore.write(req.params.id, mime, buf);
|
||||
botDb.setCustomAvatarPath(req.params.id, rel);
|
||||
botManager.getBot(req.params.id)?.getProfileManager().setCustomAvatar(buf);
|
||||
res.json({ path: rel });
|
||||
});
|
||||
|
||||
router.delete("/:id/avatar", (req, res) => {
|
||||
const path = botDb.getCustomAvatarPath(req.params.id);
|
||||
if (path) avatarStore.remove(path);
|
||||
botDb.setCustomAvatarPath(req.params.id, null);
|
||||
botManager.getBot(req.params.id)?.getProfileManager().setCustomAvatar(null);
|
||||
res.status(204).end();
|
||||
});
|
||||
|
||||
router.post("/", async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
|
||||
+11
-2
@@ -8,6 +8,7 @@ import type { BotDatabase } from "../data/database.js";
|
||||
import type { BotConfig } from "../data/config.js";
|
||||
import type { Logger } from "../logger.js";
|
||||
import type { CookieStore } from "../music/auth.js";
|
||||
import type { AvatarStore } from "../data/avatars.js";
|
||||
import { createBotRouter } from "./api/bot.js";
|
||||
import { createMusicRouter } from "./api/music.js";
|
||||
import { createPlayerRouter } from "./api/player.js";
|
||||
@@ -25,6 +26,7 @@ export interface WebServerOptions {
|
||||
configPath: string;
|
||||
logger: Logger;
|
||||
cookieStore?: CookieStore;
|
||||
avatarStore: AvatarStore;
|
||||
staticDir?: string;
|
||||
}
|
||||
|
||||
@@ -43,7 +45,7 @@ export function createWebServer(options: WebServerOptions): WebServer {
|
||||
app.set("trust proxy", true);
|
||||
}
|
||||
|
||||
app.use(express.json());
|
||||
app.use(express.json({ limit: "400kb" }));
|
||||
|
||||
app.get("/api/config/public-url", (_req, res) => {
|
||||
const raw = (options.config.publicUrl ?? "").trim();
|
||||
@@ -52,7 +54,14 @@ export function createWebServer(options: WebServerOptions): WebServer {
|
||||
|
||||
app.use(
|
||||
"/api/bot",
|
||||
createBotRouter(options.botManager, options.config, options.configPath, logger)
|
||||
createBotRouter(
|
||||
options.botManager,
|
||||
options.config,
|
||||
options.configPath,
|
||||
logger,
|
||||
options.database,
|
||||
options.avatarStore,
|
||||
)
|
||||
);
|
||||
app.use(
|
||||
"/api/music",
|
||||
|
||||
Reference in new issue
Block a user