Resolve thumbnail-less embeds, including Discord CDN unfurls
This commit is contained in:
@@ -392,7 +392,8 @@ export class BackfillQueue {
|
||||
job.processed += progressed + result.ratelimited;
|
||||
|
||||
const elapsed = Math.max(1, this.now() - (job.startedAt ?? this.now()));
|
||||
job.perMinute = job.processed / (elapsed / 60_000);
|
||||
// Early in a run the measured rate is noise; report null until it settles.
|
||||
job.perMinute = elapsed >= 30_000 ? job.processed / (elapsed / 60_000) : null;
|
||||
|
||||
const after = this.engine.rateLimitStatus();
|
||||
if (after.active) this.limitedUntil = after.until ?? this.now() + after.remainingMs;
|
||||
|
||||
@@ -34,6 +34,11 @@ async function getText(url: string, options: DownloadOptions): Promise<string |
|
||||
signal: AbortSignal.timeout(TIMEOUT_MS)
|
||||
});
|
||||
if (!response.ok) return null;
|
||||
|
||||
// Never pull media bytes into memory just to look for an og:image.
|
||||
const type = response.headers.get("content-type") ?? "";
|
||||
if (type && !/text\/html|application\/xhtml|text\/plain/i.test(type)) return null;
|
||||
|
||||
return (await response.text()).slice(0, MAX_HTML_BYTES);
|
||||
} catch {
|
||||
return null;
|
||||
@@ -74,6 +79,16 @@ export async function resolveEmbedPreview(
|
||||
|
||||
const host = parsed.hostname.replace(/^www\./, "").toLowerCase();
|
||||
|
||||
// Discord unfurls a pasted attachment link into an embed. The URL is still a CDN file, so
|
||||
// the proxy can render a still (and a video frame) exactly like a plain attachment.
|
||||
if ((host === "cdn.discordapp.com" || host === "media.discordapp.net") && parsed.pathname.startsWith("/attachments/")) {
|
||||
parsed.hostname = "media.discordapp.net";
|
||||
parsed.searchParams.set("width", "320");
|
||||
parsed.searchParams.set("height", "320");
|
||||
parsed.searchParams.set("format", "webp");
|
||||
return parsed.toString();
|
||||
}
|
||||
|
||||
if (host === "youtube.com" || host === "m.youtube.com" || host === "youtu.be") {
|
||||
const data = await getJson(
|
||||
`https://www.youtube.com/oembed?url=${encodeURIComponent(media.url)}&format=json`,
|
||||
|
||||
@@ -356,9 +356,9 @@ export class ScrapeStore {
|
||||
pendingPreviews(limit = 5000, includeEmbeds = false): MediaRow[] {
|
||||
const local =
|
||||
"((source IS NULL OR source != 'embed') AND kind IN ('image', 'gif', 'video', 'audio'))";
|
||||
const condition = includeEmbeds
|
||||
? `(${local} OR (source = 'embed' AND preview_url IS NOT NULL))`
|
||||
: local;
|
||||
// With embeds on, a thumbnail-less embed still needs a pass: the engine resolves one
|
||||
// from the provider or the page (or the Discord proxy for CDN attachment embeds).
|
||||
const condition = includeEmbeds ? `(${local} OR source = 'embed')` : local;
|
||||
|
||||
return this.db
|
||||
.prepare(
|
||||
|
||||
Reference in New Issue
Block a user