diff --git a/README.md b/README.md index 7dfd201..d5e9324 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Add `?i=` to serve a later search result instead of the first, e.g. when the fir https://direct-img.link/orange+cat?i=2 ``` -- `i` is `1`–`40`, default `1`. Invalid values serve `bad.webp` +- `i` is `1`–`40`, default `1`. Higher values serve `max-i.webp`, which lists each site's range, and other invalid values serve `bad.webp` - Leading zeros are ignored (`?i=02` = `?i=2`) - Only images that download count, so broken links and deleted photos are skipped and every `i` is a different image. `?i=2` is the 2nd working image - Higher `i` values take a little longer the first time, since the working images before it are downloaded to count them @@ -104,7 +104,7 @@ Need images you can publish? `free.direct-img.link` only serves images marked ** | `i` | `1`–`20` — works the same as [on the main site](#picking-a-result) | `1` | - Both are optional and can be used alone or together, in any order (`?i=2&src=wikimedia` = `?src=wikimedia&i=2`) -- Invalid values serve `bad.webp` +- `i` above `20` serves `max-i.webp`, which lists each site's range. Other invalid values serve `bad.webp` - With a `src`, only that source's images are served: if it has no image (or fewer than `i` working ones), `bad.webp` is served (remembered for 24h) instead of an AI image. Without one, an AI image is served like on the main site - Each `src` + `i` + query combination is cached separately. Like the main site, other `i` values within an hour of a search reuse its results and don't count as searches @@ -128,10 +128,10 @@ Licenses come from each source's metadata and can be wrong. Check the original b | Param | Values | Default | |---|---|---| | `src` | `auroraimg-6m` (case-insensitive) | `auroraimg-6m` | -| `i` | `1`–`20` — each is a different image of the same query | `1` | +| `i` | `1`–`1000` — each is a different image of the same query | `1` | - The same query, `src` and `i` always give the same image -- Invalid values serve `bad.webp` +- `i` above `1000` serves `max-i.webp`, which lists each site's range. Other invalid values serve `bad.webp` - Images come from [AuroraIMG-6M](https://github.com/direct-img/AuroraIMG-6M), a tiny 6.8M-parameter model running on our own server. They're 512px, soft and painterly: the right colors, setting and mood, but often not the exact object, and faces come out distorted - The same model makes the fallback images for searches that find nothing diff --git a/assets/max-i.webp b/assets/max-i.webp new file mode 100644 index 0000000..97a1132 Binary files /dev/null and b/assets/max-i.webp differ diff --git a/design/max-i.html b/design/max-i.html new file mode 100644 index 0000000..bb0c46b --- /dev/null +++ b/design/max-i.html @@ -0,0 +1,38 @@ + + + + + + + + + +
?i=
+
+

That ?i= is too high

+ + + + +
direct-img.link1–40
free.direct-img.link1–20
ai.direct-img.link1–1000
+
+ + diff --git a/functions/[[path]].js b/functions/[[path]].js index 0253571..0a84deb 100644 --- a/functions/[[path]].js +++ b/functions/[[path]].js @@ -6,8 +6,10 @@ import { aiImage, parseAiSource, DEFAULT_AI_SOURCE } from "./_utils/ai.js"; import * as LIMITS from "../assets/rate-limit.js"; const TTL_SECONDS = 90 * 24 * 60 * 60; -// Highest ?i= per site: 40 on the main site (100 Brave results), 20 on free.* (~50 Openverse + Wikimedia results) and ai.* -const MAX_INDEX = { "": 40, free: 20, ai: 20 }; +// Highest ?i= per site: 40 on the main site (100 Brave results), 20 on free.* (~50 Openverse + Wikimedia +// results) and 1000 on ai.* (each is a new image, so there's no list to run out). +// Higher values serve max-i.webp, which lists these, so redraw it from design/max-i.html when they change. +const MAX_INDEX = { "": 40, free: 20, ai: 1000 }; // How long a search may hold its query's lock; longer than the 20s image deadline plus the search itself const LOCK_SECONDS = 45; // How long a search's results are kept for the query's other ?i=, which then don't search again or count toward limits @@ -44,10 +46,11 @@ export async function onRequest(context) { const site = ["free", "ai"].find(s => url.hostname.startsWith(`${s}.`)) || ""; const free = site === "free", ai = site === "ai"; const label = { free: "Free ", ai: "AI " }[site] || ""; - const i = parseIndex(url.searchParams, MAX_INDEX[site]); + const i = parseIndex(url.searchParams); const src = free ? parseFreeSource(url.searchParams) : ai ? parseAiSource(url.searchParams) : null; const extra = [...url.searchParams.keys()].some(k => k !== "i" && !(site && k === "src")); if (!i || (site && !src) || extra) return asset("bad.webp"); + if (i > MAX_INDEX[site]) return asset("max-i.webp"); context.waitUntil(countHit(env, request, query, site)); @@ -279,10 +282,10 @@ COMMIT TRANSACTION;`; return job; } -// ?i=1..max (default 1). Returns null if invalid. -function parseIndex(searchParams, max) { +// ?i=1 or higher (default 1). Returns null if invalid. +function parseIndex(searchParams) { const i = searchParams.get("i") || "1"; - return /^\d+$/.test(i) && +i >= 1 && +i <= max ? +i : null; + return /^\d+$/.test(i) && +i >= 1 ? +i : null; } // Brave results, or Bing's if Brave has none or refuses (e.g. once its spending limit is hit). null if Bing fails too, diff --git a/index.html b/index.html index 0c5849d..4f37d43 100644 --- a/index.html +++ b/index.html @@ -110,7 +110,7 @@ Use images to complement your responses, powered by Brave. srcauroraimg-6mauroraimg-6m - i1–20 (a different image each)1 + i1–1000 (a different image each)1

* The same query always gives the same image. When a search on direct-img.link or free.direct-img.link (without src) finds nothing, an AI image is served instead. Made with AuroraIMG-6M.