Add sort and exclusion filters to the media grid
This commit is contained in:
+51
-83
@@ -177,6 +177,54 @@ function startAudioSocket(server: http.Server | https.Server, deps: WebUiDeps):
|
||||
});
|
||||
}
|
||||
|
||||
/** Shared parsing for the media grid filters, used by /api/media and /api/media/stats. */
|
||||
function parseMediaFilters(query: Record<string, unknown>) {
|
||||
const list = (value: unknown) =>
|
||||
value
|
||||
? String(value)
|
||||
.split(",")
|
||||
.map(entry => entry.trim().toLowerCase())
|
||||
.filter(Boolean)
|
||||
: undefined;
|
||||
const amount = (value: unknown) => {
|
||||
if (value === undefined || value === "") return undefined;
|
||||
const number = Number(value);
|
||||
return Number.isFinite(number) && number >= 0 ? number : undefined;
|
||||
};
|
||||
|
||||
return {
|
||||
kind: ["image", "gif", "video", "audio"].includes(String(query.kind ?? ""))
|
||||
? (String(query.kind) as "image" | "gif" | "video" | "audio")
|
||||
: undefined,
|
||||
source: ["attachment", "sticker", "embed"].includes(String(query.source ?? ""))
|
||||
? String(query.source)
|
||||
: undefined,
|
||||
channelId: query.channelId ? String(query.channelId) : undefined,
|
||||
authorIds: list(query.authorId),
|
||||
origin:
|
||||
query.origin === "dm" || query.origin === "guild"
|
||||
? (String(query.origin) as "dm" | "guild")
|
||||
: undefined,
|
||||
cachedOnly: query.cachedOnly === "1" || query.cachedOnly === "true",
|
||||
exts: list(query.ext),
|
||||
excludeHosts: list(query.excludeHosts),
|
||||
excludeExts: list(query.excludeExt),
|
||||
excludeProviders: list(query.excludeProviders),
|
||||
excludeSources: list(query.excludeSources),
|
||||
sizeLessThan: amount(query.sizeLt),
|
||||
sizeGreaterThan: amount(query.sizeGt),
|
||||
lengthLessThan: amount(query.lenLt),
|
||||
lengthGreaterThan: amount(query.lenGt),
|
||||
aspect: query.aspect ? String(query.aspect) : undefined,
|
||||
resolution: query.resolution ? String(query.resolution) : undefined,
|
||||
after: query.after ? String(query.after) : undefined,
|
||||
before: query.before ? String(query.before) : undefined,
|
||||
sort: ["newest", "oldest", "user", "size", "length"].includes(String(query.sort ?? ""))
|
||||
? (String(query.sort) as "newest" | "oldest" | "user" | "size" | "length")
|
||||
: undefined
|
||||
};
|
||||
}
|
||||
|
||||
export function startWebUi(deps: WebUiDeps): WebUiHandle {
|
||||
const app = express();
|
||||
app.use(express.json({ limit: "64kb" }));
|
||||
@@ -901,58 +949,14 @@ export function startWebUi(deps: WebUiDeps): WebUiHandle {
|
||||
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 source = ["attachment", "sticker", "embed"].includes(String(req.query.source ?? ""))
|
||||
? String(req.query.source)
|
||||
: undefined;
|
||||
const channelId = req.query.channelId ? String(req.query.channelId) : undefined;
|
||||
const authorIds = req.query.authorId
|
||||
? String(req.query.authorId)
|
||||
.split(",")
|
||||
.map(value => value.trim())
|
||||
.filter(Boolean)
|
||||
: undefined;
|
||||
const origin =
|
||||
req.query.origin === "dm" || req.query.origin === "guild"
|
||||
? (String(req.query.origin) as "dm" | "guild")
|
||||
: undefined;
|
||||
const cachedOnly = req.query.cachedOnly === "1" || req.query.cachedOnly === "true";
|
||||
const exts = req.query.ext
|
||||
? String(req.query.ext)
|
||||
.split(",")
|
||||
.map(value => value.trim().toLowerCase())
|
||||
.filter(Boolean)
|
||||
: undefined;
|
||||
const excludeHosts = req.query.excludeHosts
|
||||
? String(req.query.excludeHosts)
|
||||
.split(",")
|
||||
.map(value => value.trim().toLowerCase())
|
||||
.filter(Boolean)
|
||||
: undefined;
|
||||
const aspect = req.query.aspect ? String(req.query.aspect) : undefined;
|
||||
const resolution = req.query.resolution ? String(req.query.resolution) : undefined;
|
||||
const after = req.query.after ? String(req.query.after) : undefined;
|
||||
const before = req.query.before ? String(req.query.before) : undefined;
|
||||
const filters = parseMediaFilters(req.query);
|
||||
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,
|
||||
source,
|
||||
channelId,
|
||||
authorIds,
|
||||
origin,
|
||||
cachedOnly,
|
||||
exts,
|
||||
excludeHosts,
|
||||
aspect,
|
||||
resolution,
|
||||
after,
|
||||
before,
|
||||
...filters,
|
||||
limit,
|
||||
offset
|
||||
})
|
||||
@@ -970,46 +974,10 @@ export function startWebUi(deps: WebUiDeps): WebUiHandle {
|
||||
app.get(
|
||||
"/api/media/stats",
|
||||
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 authorIds = req.query.authorId
|
||||
? String(req.query.authorId)
|
||||
.split(",")
|
||||
.map(value => value.trim())
|
||||
.filter(Boolean)
|
||||
: undefined;
|
||||
const origin =
|
||||
req.query.origin === "dm" || req.query.origin === "guild"
|
||||
? (String(req.query.origin) as "dm" | "guild")
|
||||
: undefined;
|
||||
const exts = req.query.ext
|
||||
? String(req.query.ext)
|
||||
.split(",")
|
||||
.map(value => value.trim().toLowerCase())
|
||||
.filter(Boolean)
|
||||
: undefined;
|
||||
const excludeHosts = req.query.excludeHosts
|
||||
? String(req.query.excludeHosts)
|
||||
.split(",")
|
||||
.map(value => value.trim().toLowerCase())
|
||||
.filter(Boolean)
|
||||
: undefined;
|
||||
|
||||
res.json({
|
||||
ok: true,
|
||||
result: deps.media.stats({
|
||||
kind,
|
||||
source: req.query.source ? String(req.query.source) : undefined,
|
||||
channelId: req.query.channelId ? String(req.query.channelId) : undefined,
|
||||
authorIds,
|
||||
origin,
|
||||
cachedOnly: req.query.cachedOnly === "1" || req.query.cachedOnly === "true",
|
||||
exts,
|
||||
excludeHosts,
|
||||
aspect: req.query.aspect ? String(req.query.aspect) : undefined,
|
||||
resolution: req.query.resolution ? String(req.query.resolution) : undefined,
|
||||
...parseMediaFilters(req.query),
|
||||
after: req.query.after ? String(req.query.after) : undefined,
|
||||
before: req.query.before ? String(req.query.before) : undefined
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user