From efcb276c45f2fd39306241dd84162973b36d8114 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Thu, 14 Dec 2023 19:35:49 +0800 Subject: [PATCH] Add support for filtering files by gids in get_random_file() function --- db.ts | 17 +++++++++++++++-- routes/api/file/random.ts | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/db.ts b/db.ts index 9412fb4..cfa71e9 100644 --- a/db.ts +++ b/db.ts @@ -1062,12 +1062,24 @@ export class EhDb { get_random_file( is_nsfw: boolean | null = null, is_ad: boolean | null = null, + gids: Set | null = null, ) { const args = []; let join_sql = ""; + const with_sql = []; const where_sql = []; + if (gids) { + const gids_sql = []; + for (const gid of gids) { + gids_sql.push("(?)"); + args.push(gid); + } + with_sql.push(`WITH gids AS (VALUES ${gids_sql.join(",")})`); + join_sql += " INNER JOIN pmeta ON file.token = pmeta.token"; + where_sql.push("pmeta.gid IN gids"); + } if (is_nsfw !== null || is_ad !== null) { - join_sql = " LEFT JOIN filemeta ON file.token = filemeta.token"; + join_sql += " LEFT JOIN filemeta ON file.token = filemeta.token"; if (is_nsfw !== null) { where_sql.push("IFNULL(filemeta.is_nsfw, 0) = ?"); args.push(is_nsfw); @@ -1080,9 +1092,10 @@ export class EhDb { const wsql = where_sql.length ? ` WHERE ${where_sql.join(" AND ")}` : ""; + const wisql = with_sql.length ? `${with_sql.join(" ")} ` : ""; const s = this.convert_file( this.db.queryEntries( - `SELECT file.* FROM file${join_sql}${wsql} ORDER BY RANDOM() LIMIT 1;`, + `${wisql}SELECT file.* FROM file${join_sql}${wsql} ORDER BY RANDOM() LIMIT 1;`, args, ), ); diff --git a/routes/api/file/random.ts b/routes/api/file/random.ts index 38869cb..08c6be1 100644 --- a/routes/api/file/random.ts +++ b/routes/api/file/random.ts @@ -10,7 +10,40 @@ export const handler: Handlers = { const is_nsfw = await parse_bool(u.searchParams.get("is_nsfw"), null); const is_ad = await parse_bool(u.searchParams.get("is_ad"), null); const thumb = await parse_bool(u.searchParams.get("thumb"), false); - const f = m.db.get_random_file(is_nsfw, is_ad); + const tgids = u.searchParams.get("gids"); + let gids = tgids + ? new Set( + tgids.split(",").map((x) => parseInt(x)).filter((v) => + !isNaN(v) + ), + ) + : null; + const meili_query = u.searchParams.get("meili_query"); + const meili_filter = u.searchParams.get("meili_filter"); + if (meili_query || meili_filter) { + if (!m.meilisearch) { + return new Response("Meilisearch is not enabled.", { + status: 400, + }); + } + try { + const index = await m.meilisearch.gmeta; + const re = await index.search(meili_query, { + filter: meili_filter || undefined, + hitsPerPage: 1000, + attributesToRetrieve: ["gid"], + }); + if (gids === null) { + gids = new Set(); + } + re.hits.forEach((d) => { + gids?.add(d.gid); + }); + } catch (e) { + return new Response(e.message, { status: 400 }); + } + } + const f = m.db.get_random_file(is_nsfw, is_ad, gids); if (!f) return new Response("File not found.", { status: 404 }); const t = thumb ? "thumbnail" : "file"; return Response.redirect(`${get_host(req)}/api/${t}/${f.id}`);