mirror of
https://github.com/direct-img/direct-img.link.git
synced 2026-10-29 15:34:51 +00:00
A third of queries (by query hash) search Firecrawl first and the rest Brave, so Firecrawl's free 500 searches a month and Brave's ~1,000 run out together. Each falls back to the other on an error or no results. Searches that find nothing serve bad.webp, both providers failing serves donate.webp, and AI images only fill ?i= past a search's working images. A Firecrawl query's ?i= past 10 serves an AI image without searching. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
23 lines
1.2 KiB
JavaScript
23 lines
1.2 KiB
JavaScript
// Results per search. Firecrawl charges 2 credits per 10, so the free plan's 1,000 credits a month buy 500 searches
|
|
export const FIRECRAWL_RESULTS = 10;
|
|
|
|
// { urls } ([] if none found), or { error } if Firecrawl refused or failed, e.g. 402 once the month's credits run out,
|
|
// or 429 past the free plan's 10 searches a minute or 2 at once
|
|
export async function firecrawlImageSearch(query, apiKey) {
|
|
try {
|
|
const res = await fetch("https://api.firecrawl.dev/v2/search", {
|
|
method: "POST",
|
|
headers: { "Authorization": `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
// SafeSearch off, like Brave. It's off by default too, but set so a default change can't filter results
|
|
body: JSON.stringify({ query, sources: ["images"], limit: FIRECRAWL_RESULTS, safe: false }),
|
|
signal: AbortSignal.timeout(10000)
|
|
});
|
|
if (!res.ok) return { error: `HTTP ${res.status}: ${(await res.text()).slice(0, 300)}` };
|
|
const data = await res.json();
|
|
if (!data.success) return { error: JSON.stringify(data).slice(0, 300) };
|
|
return { urls: data.data?.images?.map(r => r.imageUrl).filter(url => !!url) || [] };
|
|
} catch (err) {
|
|
return { error: err.name === "TimeoutError" ? "Timeout" : err.message };
|
|
}
|
|
}
|