AssesPhoto 键盘切换图片 + 下载原图
AssesPhoto Keyboard Navigation & Download
A Tampermonkey (or scriptcat) userscript that adds keyboard controls and an original-image download button to the lightbox (presentation mode) on assesphoto.com.
Features
- ← / → arrow keys — navigate to the previous / next image in the lightbox (wraps around at both ends, same as clicking the on-screen arrows)
- Esc — close the lightbox
- D key or ⬇ button — download the currently displayed original image, with content validation so you never save a corrupt file
- A floating download button rendered in the bottom-right corner of the lightbox, positioned to avoid overlapping the thumbnail strip and navigation arrows; it shows ⏳ / ✓ / ⚠ states during and after each download
- Downloaded files are named
<gallery title> - <filename>.jpg, so images from different galleries never collide
Keys are only intercepted while the lightbox is open, and never while focus is in an input field (e.g. the site's search box) — normal page browsing is unaffected.
Installation
- Install Tampermonkey (or Violentmonkey) for your browser.
- Create a new script in the Tampermonkey dashboard (
+icon). - Paste the full contents of
assesphoto-keyboard-nav.user.jsand save (Ctrl+S). - Open any gallery page, e.g.
https://www.assesphoto.com/granny-exposing-her-asshole.shtml, click a photo to enter presentation mode, and use the keyboard.
Key Bindings
| Key | Action |
|---|---|
← |
Previous image |
→ |
Next image |
Esc |
Close lightbox |
D |
Download current image (plain D only — not Ctrl+D/Cmd+D/Alt+D) |
How It Works
The site's lightbox is driven by plain global functions (prevImage(), nextImage(), closeModal()) attached to onclick handlers. The script:
- Listens for
keydownondocumentin the capture phase, so it runs before any page-level handlers. - Checks whether the lightbox (
#myModal) is open before acting. - Calls the site's own navigation functions directly (falling back to clicking the arrow buttons if the functions are ever renamed), which keeps the thumbnail highlighting in sync.
Why GM.xmlHttpRequest + content validation?
The images are served from a separate host (img.assesphoto.com) behind Cloudflare that sends no CORS headers. Both fetch() and the <a download> attribute are therefore useless from the page context — the browser either blocks the request or ignores the download attribute for cross-origin URLs.
The script fetches the image as a Blob via Tampermonkey's GM.xmlHttpRequest (with the corresponding @connect img.assesphoto.com declaration), which bypasses page CORS. Before saving, it validates the blob's magic bytes (JPEG/PNG/GIF/WebP) — if Cloudflare occasionally serves an HTML challenge page instead of the image, the download is aborted and the image opens in a new tab as a fallback, so you never end up with a corrupt .jpg file on disk.
Two further guards against corrupt downloads:
- Modifier keys are ignored:
Ctrl+D/Cmd+D/Alt+Dbelong to the browser (bookmark dialog) and no longer trigger a download at the same time. - Key repeat + double-press protection: holding
Dor pressing it twice quickly can no longer start two concurrent downloads of the same file, which would race Chrome's.crdownloadhandling and leave a broken file. Adownloadingflag gates concurrent requests, and the button shows ⏳ / ✓ / ⚠ states.
Site Quirk: Duplicated Images
The gallery's images array lists every image twice (and the thumbnail strip renders matching duplicate pairs), so the array has 20 entries for 10 actual photos. This means a single keypress sometimes lands on the "same" photo twice before advancing to a new one — this mirrors the on-screen arrows exactly, since the script reuses the site's own navigation logic.
Troubleshooting
"Sometimes the downloaded file is not a valid image." (Fixed in v1.2.0)
This was traced to three separate causes, all now handled:
- Browser-shortcut collision — pressing
Ctrl+Dused to trigger a download and open the browser's bookmark dialog at the same time; the focus steal could interrupt the download mid-write. Downloads now only fire on a plainDpress. - Concurrent same-name downloads — key auto-repeat (holding
D) or double-pressing started parallel downloads of the same file, racing Chrome's.crdownloadhandling and leaving a broken file. Adownloadingflag now serializes downloads. - Cloudflare HTML responses — the image host occasionally serves an HTML challenge page instead of the image. Every response is now magic-byte-validated before saving; invalid responses fall back to opening the image in a new tab instead of writing a corrupt
.jpg.
If a download still fails, check the browser console for [kb-nav] warnings, which log the response status and headers of rejected downloads.
Compatibility
Tested with Tampermonkey on Chrome. The script uses GM.xmlHttpRequest, which is supported by Violentmonkey and Greasemonkey 4 (GM.xmlHttpRequest) as well.
Changelog
- 1.2.0 — Download hardening: magic-byte content validation (JPEG/PNG/GIF/WebP),
GM.xmlHttpRequestblob fetch replacesGM_download, modifier-key (Ctrl/Cmd/Alt+D) and key-repeat guards, concurrent-download lock, button progress states, filename trailing-dot/space sanitization. Fixes intermittent corrupt downloads. - 1.1.0 — Added original-image download:
Dkey and floating ⬇ button,GM_download-based,<gallery title> - <filename>naming. - 1.0.0 — Initial release:
←/→lightbox navigation,Escto close.
License
MIT