Wire the media archive into the daemon: command, service, and API

This commit is contained in:
Fisto
2026-09-16 08:08:12 +02:00
parent 91782f0b80
commit 8b7b5b675d
13 changed files with 421 additions and 18 deletions
+62
View File
@@ -20,6 +20,7 @@ import type { AuthService, AuthStatus } from "./auth-service.js";
import type { AudioService } from "./audio-service.js";
import { CoreError, type CoreClient } from "./core-client.js";
import type { CoreProcess } from "./core-process.js";
import type { MediaService } from "./media.js";
import { dedupe, getQueryCount, paced, pacedSend, pacedVoice } from "./pacing.js";
import type { PreferencesStore, WebPreferences } from "./preferences.js";
import type { Puppet } from "./puppet.js";
@@ -72,6 +73,7 @@ export interface WebUiDeps {
audio: AudioService;
transcripts: TranscriptStore;
preferences: PreferencesStore;
media: MediaService;
connectAudioDevices: () => Promise<{ connected: boolean; message: string }>;
}
@@ -713,6 +715,66 @@ export function startWebUi(deps: WebUiDeps): WebUiHandle {
})
);
app.get(
"/api/media/scrapes",
wrap(async (_req, res) => {
res.json({ ok: true, result: deps.media.listScrapes() });
})
);
app.get(
"/api/media/status",
wrap(async (_req, res) => {
res.json({ ok: true, result: deps.media.status() });
})
);
app.get(
"/api/media",
wrap(async (req, res) => {
const kind = ["image", "gif", "video", "audio"].includes(String(req.query.kind ?? ""))
? (String(req.query.kind) as "image" | "gif" | "video" | "audio")
: undefined;
const limit = clampLimit(req.query.limit, 60, 500);
const offset = Math.max(0, Number(req.query.offset ?? 0) || 0);
res.json({ ok: true, result: deps.media.queryMedia({ kind, limit, offset }) });
})
);
app.post(
"/api/media/scrape",
wrap(async (req, res) => {
const channelId = String(req.body?.channelId ?? "");
if (!channelId) throw new HttpError(400, "channelId is required");
const mode = req.body?.mode === "download" ? "download" : "links";
const guildId = req.body?.guildId ? String(req.body.guildId) : null;
const scrape = await deps.media.startScrape({ channelId, guildId, mode });
deps.getPuppet()?.appendAction({
type: "media",
action: "scrape",
channelId,
mode,
scrapeId: scrape.id
});
res.json({ ok: true, result: scrape });
})
);
app.post(
"/api/media/scrape/stop",
wrap(async (req, res) => {
const id = String(req.body?.id ?? "");
if (!id) throw new HttpError(400, "id is required");
deps.media.stopScrape(id);
deps.getPuppet()?.appendAction({ type: "media", action: "stop", scrapeId: id });
res.json({ ok: true, result: { stopped: id } });
})
);
app.get("/api/logs", (req, res) => {
const puppet = requirePuppet();
const limit = clampLimit(req.query.limit, 100, 500);