Add media storage limits, retention, and the near-limit flow
This commit is contained in:
+46
-3
@@ -20,7 +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 { MediaLimitError, 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";
|
||||
@@ -206,6 +206,16 @@ export function startWebUi(deps: WebUiDeps): WebUiHandle {
|
||||
return;
|
||||
}
|
||||
|
||||
if (error instanceof MediaLimitError) {
|
||||
res.status(409).json({
|
||||
ok: false,
|
||||
code: error.code,
|
||||
error: error.message,
|
||||
result: { usedBytes: error.usedBytes, limitBytes: error.limitBytes }
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const status = error instanceof HttpError ? error.status : 500;
|
||||
res.status(status).json({ ok: false, error: String(error?.message ?? error) });
|
||||
});
|
||||
@@ -403,7 +413,7 @@ export function startWebUi(deps: WebUiDeps): WebUiHandle {
|
||||
app.post(
|
||||
"/api/preferences",
|
||||
wrap(async (req, res) => {
|
||||
const { visibleGuilds, tts, audio, favourites } = req.body ?? {};
|
||||
const { visibleGuilds, tts, audio, favourites, media: mediaPrefs } = req.body ?? {};
|
||||
|
||||
if (visibleGuilds !== undefined && visibleGuilds !== null && !Array.isArray(visibleGuilds)) {
|
||||
throw new HttpError(400, "visibleGuilds must be an array of guild IDs or null");
|
||||
@@ -438,6 +448,21 @@ export function startWebUi(deps: WebUiDeps): WebUiHandle {
|
||||
};
|
||||
}
|
||||
|
||||
if (mediaPrefs !== undefined) {
|
||||
const current = deps.preferences.get().media;
|
||||
patch.media = {
|
||||
limitBytes: Number.isFinite(Number(mediaPrefs?.limitBytes))
|
||||
? Number(mediaPrefs.limitBytes)
|
||||
: current.limitBytes,
|
||||
warnPercent: Number.isFinite(Number(mediaPrefs?.warnPercent))
|
||||
? Number(mediaPrefs.warnPercent)
|
||||
: current.warnPercent,
|
||||
overrunPercent: Number.isFinite(Number(mediaPrefs?.overrunPercent))
|
||||
? Number(mediaPrefs.overrunPercent)
|
||||
: current.overrunPercent
|
||||
};
|
||||
}
|
||||
|
||||
if (audio !== undefined) {
|
||||
patch.audio = { duck: audio?.duck !== false };
|
||||
deps.audio.setDuckEnabled(patch.audio.duck);
|
||||
@@ -729,6 +754,23 @@ export function startWebUi(deps: WebUiDeps): WebUiHandle {
|
||||
})
|
||||
);
|
||||
|
||||
app.get(
|
||||
"/api/media/storage",
|
||||
wrap(async (_req, res) => {
|
||||
res.json({ ok: true, result: deps.media.refreshRetention() });
|
||||
})
|
||||
);
|
||||
|
||||
app.post(
|
||||
"/api/media/clean",
|
||||
wrap(async (req, res) => {
|
||||
const ids = Array.isArray(req.body?.ids) ? req.body.ids.map(String) : undefined;
|
||||
const deleted = deps.media.cleanMedia(ids);
|
||||
deps.getPuppet()?.appendAction({ type: "media", action: "clean", deleted });
|
||||
res.json({ ok: true, result: { deleted } });
|
||||
})
|
||||
);
|
||||
|
||||
app.get(
|
||||
"/api/media",
|
||||
wrap(async (req, res) => {
|
||||
@@ -750,8 +792,9 @@ export function startWebUi(deps: WebUiDeps): WebUiHandle {
|
||||
|
||||
const mode = req.body?.mode === "download" ? "download" : "links";
|
||||
const guildId = req.body?.guildId ? String(req.body.guildId) : null;
|
||||
const confirm = req.body?.confirm === true;
|
||||
|
||||
const scrape = await deps.media.startScrape({ channelId, guildId, mode });
|
||||
const scrape = await deps.media.startScrape({ channelId, guildId, mode, confirm });
|
||||
deps.getPuppet()?.appendAction({
|
||||
type: "media",
|
||||
action: "scrape",
|
||||
|
||||
Reference in New Issue
Block a user