Add Discord-hosted preview caching (C11)
This commit is contained in:
@@ -8,7 +8,7 @@ import { createHash } from "node:crypto";
|
||||
import { existsSync, mkdirSync, mkdtempSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { downloadOne } from "../src/download.js";
|
||||
import { downloadOne, downloadPreview, previewUrlFor } from "../src/download.js";
|
||||
import { ScrapeEngine, type FetchPage, type ScrapeBackend } from "../src/engine.js";
|
||||
import { extractMedia } from "../src/extract.js";
|
||||
import { PuppetBackend } from "../src/puppet-backend.js";
|
||||
@@ -85,6 +85,7 @@ function engineFor(root: string, backend: ScrapeBackend, extra: Record<string, u
|
||||
sleep: async () => {},
|
||||
random: () => 0,
|
||||
log: () => {},
|
||||
previews: false,
|
||||
...extra
|
||||
});
|
||||
}
|
||||
@@ -366,6 +367,7 @@ void (async () => {
|
||||
sleep: async () => {},
|
||||
random: () => 0,
|
||||
log: () => {},
|
||||
previews: false,
|
||||
download: {
|
||||
fetchImpl: async () =>
|
||||
new Response("png-bytes", { status: 200, headers: { "content-type": "image/png" } }),
|
||||
@@ -394,6 +396,77 @@ void (async () => {
|
||||
assert.equal(existsSync(join(root, started.id, row.file_path)), true);
|
||||
});
|
||||
|
||||
await test("preview urls are Discord-only resizes", () => {
|
||||
assert.equal(
|
||||
previewUrlFor({ url: "https://cdn.discordapp.com/attachments/1/2/pic.png", kind: "image" }),
|
||||
"https://media.discordapp.net/attachments/1/2/pic.png?width=320&height=320&format=webp"
|
||||
);
|
||||
assert.equal(previewUrlFor({ url: "https://www.youtube.com/watch?v=x", kind: "video" }), null);
|
||||
assert.equal(previewUrlFor({ url: "https://i.ytimg.com/vi/x/hq.jpg", kind: "image" }), null);
|
||||
});
|
||||
|
||||
await test("preview downloads are written by hash", async () => {
|
||||
const dir = join(root, "preview-test");
|
||||
mkdirSync(dir, { recursive: true });
|
||||
|
||||
const outcome = await downloadPreview(
|
||||
{ id: 9, url: "https://cdn.discordapp.com/attachments/1/2/pic.png", kind: "image" },
|
||||
dir,
|
||||
{
|
||||
fetchImpl: async () =>
|
||||
new Response("webp-bytes", { status: 200, headers: { "content-type": "image/webp" } })
|
||||
}
|
||||
);
|
||||
|
||||
assert.equal(outcome.state, "downloaded");
|
||||
assert.equal(outcome.path, `${outcome.hash}.webp`);
|
||||
assert.equal(existsSync(join(dir, `${outcome.hash}.webp`)), true);
|
||||
});
|
||||
|
||||
await test("engine caches previews in links mode", async () => {
|
||||
const backend = new FakeBackend([
|
||||
{
|
||||
messages: [
|
||||
message("600", {
|
||||
attachments: [attachment({ filename: "prev.png", contentType: "image/png" })]
|
||||
})
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
const engine = new ScrapeEngine({
|
||||
rootDir: root,
|
||||
pageSize: 2,
|
||||
pageMinMs: 0,
|
||||
pageMaxMs: 0,
|
||||
sleep: async () => {},
|
||||
random: () => 0,
|
||||
log: () => {},
|
||||
previews: true,
|
||||
download: {
|
||||
fetchImpl: async () =>
|
||||
new Response("webp-bytes", { status: 200, headers: { "content-type": "image/webp" } }),
|
||||
minGapMs: 0,
|
||||
maxGapMs: 0,
|
||||
sleep: async () => {}
|
||||
}
|
||||
});
|
||||
|
||||
const started = await engine.start({ channelId: "128", guildId: null, mode: "links", backend });
|
||||
await engine.processQueue();
|
||||
|
||||
const meta = engine.get(started.id);
|
||||
assert.equal(meta?.state, "done");
|
||||
assert.equal(meta?.previewed, 1);
|
||||
|
||||
const store = new ScrapeStore(join(root, started.id));
|
||||
const row = store.queryMedia({ kind: "image" })[0];
|
||||
assert.ok(row.preview_hash);
|
||||
assert.ok((row.preview_bytes ?? 0) > 0);
|
||||
store.close();
|
||||
assert.equal(existsSync(join(root, started.id, "thumbs", `${row.preview_hash}.webp`)), true);
|
||||
});
|
||||
|
||||
await test("retention marks the oldest completed scrapes up to the limit", () => {
|
||||
const scrapes = [
|
||||
{ id: "old", state: "done", createdAt: "2026-09-01T00:00:00.000Z", bytes: 600 },
|
||||
|
||||
Reference in New Issue
Block a user