Skip to content

pglira/blink

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

blink

A small Linux daemon that silently takes a screenshot every N seconds and appends it to a compressed H.264/Matroska video. Designed to keep running in the background, survive crashes without corrupting the archive, and stay out of the way — visible only as a tray icon.

Features

  • Periodic multi-monitor capture via xcap (X11 primary, Wayland best-effort). Monitors are composited side-by-side into one canvas per frame.
  • Continuous H.264 encoding into MKV segments via linked libav (no ffmpeg subprocess). MKV is chosen because truncated files remain playable.
  • Automatic segment rotation when the monitor layout changes (resolution or connect/disconnect of a display), when segment_minutes elapses, or at local midnight (so each MKV covers a single calendar day by default).
  • Crash resilience: staged JPEGs are only deleted once the corresponding frame is flushed and fsynced; MKV muxer runs with flush_packets=1. Any orphan JPEGs from a prior run are drained into recovery_*.mkv at startup.
  • System tray icon with Pause / Resume / Quit. Icon shows current status (blue open eye = recording, gray closed eye = paused).
  • Single TOML config at ~/.config/blink/config.toml (written on first run).

Build

The project targets Linux (X11 + GTK). It currently assumes the versions of libav that ship with Ubuntu 24.04 (libav*.so.60).

Using the devcontainer

The .devcontainer here installs the full toolchain:

Reopen in Container  →  cargo build --release

Building manually

Install native dependencies (apt package names for Ubuntu 24.04):

pkg-config
libavformat-dev libavcodec-dev libavutil-dev libswscale-dev
libavfilter-dev libavdevice-dev
libgtk-3-dev libayatana-appindicator3-dev
libxcb1-dev libxrandr-dev libxfixes-dev libxext-dev libxdo-dev
libssl-dev

Then install a stable Rust toolchain via rustup and:

cargo build --release

The binary is target/release/blink (~4 MB stripped).

Run

blink              # start the daemon (same as `blink run`)
blink config-path  # print path to config.toml
blink help

Start blink once and leave it sitting in the tray; pause/resume from there.

To launch it automatically on login, drop the bundled desktop entry into the XDG autostart directory:

install -Dm644 config/blink.desktop ~/.config/autostart/blink.desktop

The session manager (GNOME, KDE, XFCE, …) will then start blink as part of your graphical session — independent of any terminal — and it will reappear in the tray after every login.

First run writes a default config to ~/.config/blink/config.toml. Default paths:

  • Frames staging: ~/.cache/blink/staging/ (each frame as a timestamped JPEG until it has been successfully encoded; normally empty)
  • Video output: ~/Videos/blink/ (blink_YYYYMMDD-HHMMSS_WxH.mkv)
  • PID lock: ~/.cache/blink/blink.pid

The tray menu offers:

  • Pause / Resume — toggles capture. Icon changes to reflect status.
  • Quit — clean shutdown: flush encoder, write MKV trailer, remove PID file, exit.

The daemon also handles SIGINT and SIGTERM as graceful shutdown, so system shutdown or a kill <pid> from a terminal leaves properly finalized files.

Config reference

~/.config/blink/config.toml:

[capture]
interval_seconds = 60      # one frame per minute
monitors = "all"           # "all" | "primary"

[video]
codec = "h264"             # h264 | h265 | av1
crf = 28                   # lower = higher quality, larger files
segment_minutes = 60       # roll over to a new MKV every hour
daily_split = true         # also roll over at local midnight (one MKV per day)

[staging]
jpeg_quality = 85
keep_after_encode = false  # keep the JPEGs on disk after encoding
                           # (enable to feed a future OCR pass)

[output]
dir = ""                   # empty → ~/Videos/blink

[daemon]
pid_file = ""              # empty → ~/.cache/blink/blink.pid
log_file = ""              # (reserved; current build logs to stderr)

What the daemon does on shutdown

Scenario Resulting file Frame loss
Quit from tray, SIGINT, SIGTERM, logout Properly finalized MKV with trailer None
SIGKILL, kernel panic, power cut Valid MKV without trailer (plays fine up to last flushed cluster) ≤ 1 in-flight frame
Daemon exits then restarts with JPEGs left in staging Drained into recovery_*.mkv on next startup None

Project layout

.
├── .devcontainer/          VS Code devcontainer (Rust + libav + GTK + X11)
├── config/default.toml     Embedded default config, written on first run
├── config/blink.desktop    XDG autostart entry (copy to ~/.config/autostart/)
├── Cargo.toml
└── src/
    ├── main.rs             CLI, thread orchestration, signal handling
    ├── config.rs           TOML loader, XDG path resolution
    ├── state.rs            Shared AtomicBool flags + PID file guard
    ├── staging.rs          Atomic JPEG writes + pending_frames scan
    ├── capture.rs          xcap screenshot loop, monitor composite
    ├── encoder.rs          libav MKV muxer, segment rotation, recovery
    └── tray.rs             AppIndicator tray icon + GTK menu

Planned / hook points

  • Text journal: OCR each frame and write timestamped text entries. The code already names staged JPEGs <unix_millis>.jpg and retains them when keep_after_encode = true, so a future blink ocr subcommand can iterate them in timestamp order without touching the capture/encode pipeline.

Licence

MIT

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors