Upstream request caching and rate limiting, escaped output, a valid Atom feed, and a translated interface.
Fewer requests to DeviantArt
DeviantArt bans egress IPs that ask too often, so this release cuts what an instance asks for.
- In-memory cache of API responses with singleflight coalescing: repeat and concurrent views of one page cost one upstream call.
api-cache block, on by default, 64 MB, 5 minute TTL.
- Avatars and emotes are cached alongside media, and the media cache is on by default (
lifetime 1w, max-size 200).
Cache-Control on every response: a year on signed media, a day on avatars and static files, five minutes on pages and API JSON. Error responses carry none.
/robots.txt keeps crawlers off search, the API, profiles, media and pagination.
- A per-client token bucket for page, feed and API requests (
rate-limit: 60 per minute, burst 20; 0 disables). Media is exempt. Behind a reverse proxy the client comes from X-Forwarded-For, trusted only from a loopback or private connection.
- Comment threads load on request behind a "Comments (N)" link, so a post view is one upstream call instead of two.
/api/random picks from the cached daily deviations instead of firing random searches.
Fixes
- Every string rendered from user input or DeviantArt content is escaped; templates use
html/template.
- The Atom feed validates: feed id, updated and self link, IRI entry ids, RFC 3339 timestamps,
media:thumbnail.
- User About tabs render interests, social links and registration age again.
- Group search pagination no longer skips results 10 to 19.
- Emojitar returns after a 404 instead of writing a body over it.
skunkyart -x -c no longer panics.
- The 502 page shows one escaped line of the upstream error.
- Templates are parsed once at startup, per language; a broken template fails at boot.
Interface
- Every string is translated, including the ones the Go code used to hardcode; pages declare their language.
- Standard viewport meta and portrait CSS sized for it.
- Alt text on every image; the post title is a heading.
- The "Folders" option on profiles, which was a favourites search, is labelled as one.
Operating
config.json is optional when it is the default path; -c must point at a real file. Built-in nsfw default is now false.
- Working systemd unit (
DynamicUser, state directory for the cache, hardening).
Makefile: build, test, lint, dist. Tarballs for linux/amd64, linux/arm64, darwin/arm64 and freebsd/amd64 are attached here and to the GitHub mirror's release.
- CI on every push: build, vet, test with the race detector, golangci-lint. A daily job checks every listed instance.
- gitbay is the canonical forge; the GitHub mirror only builds the image.
- SETUP.md rewritten; API.md corrected (
t is tag search).
Upgrading
No config changes are required. New blocks api-cache and rate-limit take their defaults when absent. If your config omitted cache, the media cache is now on and writes to ./cache; set "cache": {"enabled": false} to keep the old behaviour.