Files
scrot/README.md
T
Fredrik Johansson 4eee44f675 Initial scaffold: blob store server, CLI scripts, and PWA share target
Clipboard/screenshot sync across own devices via a single DEVICE_TOKEN-gated
blob store, plus a small installable web app so a phone can push/pull
clips and share screenshots via the OS share sheet.
2026-08-20 15:28:42 +02:00

3.9 KiB

scrot

Clipboard sync across your own devices, and screenshot → instant public link. One blob store, one small server, two thin CLI scripts.

Why

Two small itches, solved by the same mechanism — see PROPOSAL.md for the full design rationale, and why this isn't just wisp or flit again:

  • Clipboard sync: copy on one machine, pull it on another, without a cloud clipboard manager that might get paywalled or discontinued.
  • Screenshot → link: capture a region, get a shareable URL on your clipboard immediately, without an Imgur/CloudApp-style third-party uploader.

Model

A single blobs table with a kind:

  • clip — private, text. Pull-only — your other devices ask "what's the latest clip?" No public URL is ever minted.
  • shot — public, image. Upload returns a short link (/s/:id) anyone with the link can view — no auth required, same trust level as handing someone a photo link.

Single shared DEVICE_TOKEN gates every write and the private clip-read — this is single-user infrastructure across your own machines, not a multi-tenant service, so there's no per-device registry to manage.

No end-to-end encryption: unlike wisp (built for sharing with other people), this server is already fully trusted homelab infra, same trust level as keep/trace. Adding client-side crypto here would defend against a threat that doesn't apply.

Server

cd server
npm install
DEVICE_TOKEN=... npm run dev

See .env.example for the full config surface (CLIP_TTL_SECONDS, SHOT_TTL_SECONDS, MAX_UPLOAD_BYTES, ...).

CLI

Four scripts in cli/, each meant to sit behind a keybinding:

  • scrot-clip-push — pushes the current system clipboard as a clip.
  • scrot-clip-pull — fetches the latest clip into the system clipboard.
  • scrot-shot — captures a region screenshot, uploads it as a shot, copies the resulting public link to the clipboard.
  • scrot-onboard — prints (and, with qrencode installed, renders as a terminal QR code) the link that onboards a phone onto the PWA below.

Each needs SCROT_SERVER and DEVICE_TOKEN in the environment — source them from ~/.config/scrot/env (gitignored, not tracked here). Wayland (wl-paste/wl-copy/grim+slurp) and X11 (xclip/maim) are both supported, auto-detected via $WAYLAND_DISPLAY.

Mobile / PWA

The server also serves a small installable web app (server/public/) — paste-or-share text as a clip, upload/share an image as a shot, and pull the latest clip back down. No separate mobile client.

Onboarding a phone onto the shared DEVICE_TOKEN: run scrot-onboard and open the printed link (or scan the QR) on the phone. That saves the token into the page's localStorage and mirrors it into a cookie. Add the app to the home screen and reopen it once — that re-fetches /manifest.webmanifest with the token now baked into its share_target.action URL (see server/src/manifest.ts), which is what makes "Share to scrot" show up in the OS share sheet for photos and selected text. No service worker involved: the share sheet POSTs straight to /share (server/src/share.ts), which checks the token in the query string (custom headers aren't available to a share-target POST) and inserts the blob through the same path as POST /api/blobs.

Status

Scaffolded: server (routes, auth, TTL cleanup, SQLite, PWA share target) and CLI scripts written, not yet run against a real deployment or wired into keep. Next: npm install + smoke test locally, then a first deploy.

Deploy

Mirrors the rest of the project family — Dockerfile + docker-compose.yml, named volume for data/, env-driven config. Not yet migrated onto keep for secret delivery (tracked in goonk's FUTURE.md ops migration list alongside every other project still on hand-copied .env).