Skip to content

Latest commit

 

History

59 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PondTV

A Raspberry Pi that boots into a fullscreen video channel. Plug in a USB drive, it plays. No apps, no accounts, no menus.

Your folder structure is the channel guide. Up/down arrows switch channels, left/right scrubs. Swap USB drives like tapes — each one carries its own watch state, so a drive works on any RPI running PondTV. Pull the power when you're done.

How it works

One long-lived mpv process, fullscreen over DRM/KMS — no desktop, no X11. Channel switches are a socket message, not a new process, so they're instant.

Channels from folders. The first folder under a top-level category is a channel; everything deeper collapses into it. Loose files in a category are one channel. Natural sort keeps episode ordering sane. The list is derived on every mount, never stored.

State on the USB. A .pondtv/ directory at the drive root holds resume positions and seen flags, keyed by relative path. Writes are atomic (temp → fsync → rename) and infrequent. The RPI's OS can run on a read-only overlay root, so hard power-off can't brick either side.

Full architecture in docs/PLAN.md.

Media layout

USB_DRIVE/
├── Movies/
│   └── The Film/
│       ├── The Film.mkv
│       └── The Film.srt          ← same name = auto-subtitles
├── TV_Shows/
│   └── ShowName/                 ← whole show = one channel
│       ├── Season 01/
│       │   ├── S01E01.mp4
│       │   └── S01E02.mp4
│       └── Specials/
├── Ripped YT/                    ← loose files = one channel
│   ├── Video 01.mp4
│   └── Video 02.mp4
└── Selections/                   ← hand-picked mix = one channel

Controls

Key Action
Space / Enter Play / Pause
← / → Seek 10s (hold = rewind / fast-forward)
A / D Previous / next video in channel
↑ / ↓ Change channel
Backspace Restart video
S Mark seen (skip to next)
T Trailer mode (skip to unwatched)
B Browser — channel & episode guide

In the browser: ↑/↓ move the cursor, → (or D / Space) drills into a channel or plays the highlighted episode, ← (or A / Backspace) goes back, S toggles seen, B closes. Watched items show a filled mark, the playing item is flagged, and each channel shows seen/total. Playback chrome is a typographic lower-third (title / seek / pause) — not a terminal menu. Pause shows a quiet one-line hint; scrub shows the hold-ramp step (10s → 30s → 60s). Enter motion: lower-thirds slide up, modals dim-fade, toasts pop (PONDTV_UI_MOTION=0 to disable).

Input is abstracted behind an action enum — HDMI-CEC or a GPIO rotary encoder can plug in later.

Setup

RPI 4, RPI OS Lite (64-bit), USB drive with media.

sudo apt install -y mpv python3 python3-venv python3-pip exfatprogs ntfs-3g
python3 -m venv .venv && . .venv/bin/activate && pip install -e .
sudo python3 -m pondtv

Install as a boot service:

sudo cp packaging/pondtv.service /etc/systemd/system/ && sudo systemctl enable --now pondtv

See docs/DEVELOPMENT.md for RPI setup details, running mpv from SSH, and testing without a real USB drive.

Desktop (macOS or Linux dev laptop)

Run PondTV on your laptop without a Pi — for testing, demoing, or just watching. The ./run launcher bootstraps its own isolated venv and installs PondTV in it so you never think about venvs, pip, or extras. One command:

brew install mpv                              # one-time system dep (or: sudo apt install mpv)
./run                                         # pops a folder picker on macOS
./run --root ~/fakedrive                      # scriptable; skips the picker

First run sets up behind the scenes and is slow once; later runs skip straight to launching. On macOS the OS prompts once for Accessibility permission — grant it so PondTV can read keys regardless of which window has focus (System Settings → Privacy & Security → Accessibility).

The chosen folder acts as the "USB drive", mpv renders to a desktop window, and the keyboard is read system-wide via pynput. Controls are identical to the appliance (Space play/pause, arrows to scrub/surf, B opens the browser, S marks seen, Esc/Q quits), watch state writes to a .pondtv/ folder at the chosen root, and the channel model / state persistence / browser / OSD are all the same code path as the Pi build.

By default the desktop window is app-like, not a video player: no title bar, no mpv bottom control bar, no filename OSD, the cursor hides over the video, and the window stays on top with a clean "PondTV" title. The only UI is PondTV's own ASS overlay. If you ever want the plain mpv window back (e.g. to debug), disable it:

PONDTV_DESKTOP_APP=0 ./run
# or set `desktop_app: false` in ~/.config/pondtv/config.yml

Both targets render the UI in one constant internal canvas (default 1920×1080, configurable via PONDTV_CANVAS=1080|720|1600x900) and let libass scale it to the physical output — the Pi's HDMI mode or the pinned desktop window — so lower-thirds and soft modals are identical everywhere and don't depend on window size or video resolution. See docs/PLAN.md (On-screen UI) for the hybrid ASS model.

Configuration

Optional config.yml, layered: defaults → machine (/etc/pondtv/ or ~/.config/pondtv/) → per-drive (.pondtv/config.yml on the USB) → env vars. Later wins. See packaging/config.example.yml.

trailer_default: false
seek_seconds: 10.0
allow_quit: true

Roadmap

  • OSD redesign (in progress) — Capsule TTX direction is locked in the browser prototype (tests/ux_screens.html, from tests/gen_ux_screens.py): capsule shells with teletext-style page grammar, context-rich surfaces, and microinteraction motion (scrub morph, browser expand, skip wipe). Nothing from it has landed in the app yet — iterate in the prototype first.
  • Sleep timer — clean shutdown on a timer
  • Smart-seen — auto-mark watched when leaving near the end ✓ (implemented)
  • HDMI-CEC input — use the TV's remote (input now pluggable via InputSource)
  • GPIO channel knob — rotary encoder as a physical channel dial
  • Prebuilt OS image — flashable SD card, ready to boot

Recently landed (2026 refactor): a central event queue + single dispatch thread, PlaybackController extraction, precomputed season metadata, state pruning on mount, playlist prefetch, accelerating hold-seek, debounced drive mount, a constant internal 1080p canvas, and a hybrid ASS OSD (typographic lower-thirds for playback; soft modals for browser/idle). See docs/REFACTOR_PLAN.md for the audit and status.

License

MIT

About

Pond: A minimalist, offline media player for Raspberry Pi. Turn your USB drive into a personal dumb-TV channel with instant playback and smart playlists.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages