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.
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 aclip.scrot-clip-pull— fetches the latestclipinto the system clipboard.scrot-shot— captures a region screenshot, uploads it as ashot, copies the resulting public link to the clipboard.scrot-onboard— prints (and, withqrencodeinstalled, 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).