A specific ?src= asks for that source's images only, so a search that finds nothing
there now serves bad.webp (remembered for 24h) rather than the AI fallback.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brave errors (e.g. its spending limit being hit) now fall back to Bing
like empty results do, with the error in a Brave Unavailable alert. If
Bing fails too (HTTP error or a page without results, which for Bing
means it's blocking us), a new papercraft donate.webp is served instead
of an AI image, and nothing is cached so the query works once either
search is back.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A search's result URLs are kept in SurrealDB (results table) for 1 hour,
fetched in the same transaction as the rate limit. Other ?i= of the query
then skip the Brave/Bing search and don't count toward the daily limit.
The record also tracks which results worked (pos) and how far it got
(next), so an already-known ?i= downloads only its own image and a new one
carries on from where the last left off. free.* searches Openverse and
Wikimedia together so its whole list can be cached. Empty results aren't
cached, since they can mean Brave and Bing failed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
They were kept for 24h so a later search could replace them, but that
regenerated them daily for no real gain. Searches where the AI image also
fails are still remembered for 24h as bad.webp. With one TTL for all images
again, the per-image ttl stored in KV and R2 is no longer needed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ai.direct-img.link serves images from the AuroraIMG-6M API on our Dokploy
server (github.com/direct-img/AuroraIMG-6M) instead of searching. It takes
?src= (auroraimg-6m, case-insensitive, the default and only source for now)
and ?i=, where each i gets its own seed derived from the query, so it's a
different image of the same prompt. It has its own daily limit
(AI_DAILY_LIMIT) and AI: cache keys / ai/ R2 prefix. Failed generations
aren't cached, since they're likely temporary.
On direct-img.link and free.direct-img.link, a search that finds nothing (or
fewer than i working images) now serves an AI image of the query instead of
bad.webp. It's kept for 24h like failures were, so a later search can still
find a real image; bad.webp is only served if the AI image fails too. Its ttl
is stored in KV and R2 metadata so cache hits and deduped waiters send a
matching max-age.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two misses for the same query at once each ran their own search (ntfy
showed Search #24 and #25 for one image). An in-memory fix wouldn't
hold: a test of concurrent same-query requests on this project found
they share an isolate only ~25% of the time.
The rate-limit query is now one transaction that also claims a
per-query lock, so it's still a single SurrealDB round trip. Requests
that find the lock held write nothing (so aren't counted), poll until
it's released, then serve the image from R2. Write conflicts roll the
whole transaction back and are retried.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Limits change (e.g. 35 -> 25/day) and the README kept going stale, so it
now links to the homepage, which reads them live from rate-limit.js.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Free searches never spend Brave credits, so they no longer share the
main site's 35/day counter. Main-site rate ids are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Scanner probes like /userfiles?path=../../.env were treated as real
searches since extra params were ignored, wasting searches and rate limit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- free.direct-img.link serves only unrestricted (public domain/CC0) images
from Openverse (license=cc0,pdm) and Wikimedia Commons
(haslicense:unrestricted), with optional ?src=openverse|wikimedia
- ?i=1..20 picks the i-th working image on both sites; broken links are
skipped so every index is a different image
- Openverse OAuth token is cached in KV and refreshed automatically
- Skip Flickr "photo unavailable" placeholders (served with HTTP 200)
- Free/indexed cache keys use uppercase prefixes; plain main-site keys
are unchanged so existing cache entries stay valid
- Update README, homepage, privacy policy and terms
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- Update AI system prompt example (README + index)
- Add copy button for the prompt on the index page
- Add GoatCounter to homepage; report image hits server-side via
waitUntil (optional GOATCOUNTER_URL/GOATCOUNTER_TOKEN)
- Add TERMS.md and PRIVACY.md, linked in the index footer
- Remove dead c.planetrenox.com tracker
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>