Skip to content

Redirects & compatibility

Some video URLs don’t map cleanly to a single thumbnail path. Rather than break them, Vumbnail canonicalizes them with HTTP redirects so the eventual cached URL is consistent. The repo keeps a single source-of-truth Redirect Inventory in the root README.md; this page is its product-level description.

A request to /playlist or /playlist/ carrying a known list= value is redirected to the mapped video’s thumbnail.

  • GET /playlist?list=PLzc4VjwEUvFg928S7nLEABR9qzd-tdsSK.jpg307 to /<mappedVideoId>.jpg, cached public, max-age=3600.
  • Unknown playlists are instead resolved (not redirected) to their first video via YouTube oEmbed, falling back to an external resolver service.

Vimeo legacy password canonicalization (Worker)

Section titled “Vimeo legacy password canonicalization (Worker)”

Older embeds pass the Vimeo password as a ?h= query parameter. Vumbnail moves it into the canonical :password path form.

  • GET /637615910?h=27057b8971.jpg&foo=bar302 to /637615910:27057b8971.jpg?foo=bar.
  • Unrelated query parameters are preserved; only h is removed. Cached public, max-age=3600.

The legacy artifact path /.jpg (a full URL accidentally pasted into the path) is caught at the edge.

  • GET /.jpg308 to https://cache.vumbnail.com/thumbnails/_shared/error.jpg.

Borås WordPress loop escape (edge Snippet)

Section titled “Borås WordPress loop escape (edge Snippet)”

A specific WordPress site re-requests its own thumbnails in a self-referential loop. A tightly-scoped rule breaks the loop by redirecting those exact requests to the watermarked image. All conditions must match: video ID in the Borås set, path /<id>.jpg, the exact WordPress user-agent, a self-referrer, and origin ASN 14061.

  • Matching request → 307 to https://cache.vumbnail.com/thumbnails/<id>/wm.jpg.

This case is deliberately narrow: a path-only rule would match ~267k requests where the scoped predicate matches ~134k, so the scope is the spec.

Inputs: request path, query string, and (for the Snippet rules) User-Agent, Referer, and Cloudflare’s ASN signal.

Outputs: a 302, 307, or 308 Location redirect with a Cache-Control header, or pass-through to normal resolution when no rule matches.

  • Unknown playlist — no hardcoded mapping, so the Worker resolves the first video live; if resolution fails, it negative-caches a playlist-resolve-failed reason and serves the error fallback.
  • ?h= with extra query params — preserved across the redirect except h.
  • Near-miss on the Borås rule (wrong UA, missing referrer, different ASN) — intentionally not redirected; falls through to normal handling to avoid over-redirecting unrelated traffic.
  • Redirect consolidation — these rules live in Worker code and the edge Snippet; the standalone Cloudflare dynamic-redirect deployer has been retired in favor of consolidating in the Snippet (decision recorded 2026-05-26).
// Hardcoded YouTube playlist → first-video mapping (Worker)
type PlaylistRedirect = { listId: string; videoId: string }
// Borås loop-escape predicate (edge Snippet) — every field must match
type BorasEscapeRule = {
videoIds: string[] // e.g. ["1173997793", "1173997754"]
userAgent: string // exact: "WordPress/6.1.1; https://www.borasdjurpark.se"
referrerHostMatches: "self"
asn: 14061
redirectTo: "https://cache.vumbnail.com/thumbnails/{videoId}/wm.jpg"
status: 307
}
  • Where new redirects live. The current decision is to consolidate edge redirects in the Snippet rather than Cloudflare Single Redirects / dynamic rules. Whether any future case justifies reintroducing a separate redirect surface is open.
  • Playlist mapping growth. The hardcoded playlist map is maintained by hand; whether to back it with a resolver cache instead is undecided. See the global Open questions.