| .. | ||
| src | ||
| tools | ||
| bun.lock | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
portable-net-tv
Follows VLC playback, tracks every show you watch, and prefetches the next few episodes of whatever's on into a local buffer.
One profile-less service handles all shows: it reads the currently-playing file from VLC's HTTP interface, and that file's own directory is the show's source — no per-show configuration.
The watch service
portable-net-tv watch
Runs a daemon that, every 30 s:
- Reads the currently-playing file from VLC's HTTP playlist.
- Appends episode changes to the cross-show watch log.
- Prefetches the next N episodes sitting in the playing file's directory into the buffer dir (single rsync at a time; honors a disk floor).
- Garbage-collects the buffer down to exactly that prefetch window.
Files with a sibling <episode>.broken marker are skipped at every step.
next
portable-net-tv next
Reads the watch log and prints, per show, the episode watched through and the
next one. Only genuine play/resume events count toward progress — queued
-but-unwatched episodes do not.
Watch log
Append-only JSONL at ~/.local/state/plum-control-mcp/watched.jsonl (shared
with plum-control-mcp). One event per line: ts, event, show, season, episode, label, path. The show name is parsed from the filename (everything
before the SxxEyy marker).
Config
~/.config/portable-net-tv/config.json:
{
"vlcHttp": { "host": "127.0.0.1", "port": 8080, "password": "<password>" },
"buffer": { "dir": "/Users/natalie/Movies/net-tv-buffer", "ahead": 3, "minFreeGB": 2 }
}
buffer is optional — it defaults to ~/Movies/net-tv-buffer, ahead 3,
minFreeGB 2.
VLC HTTP interface
The service reads VLC over HTTP (requests/playlist.json), not AppleScript —
so it works as a launchd background agent, where Apple Events to VLC are
blocked by macOS Automation (TCC). Enable it once:
defaults write org.videolan.vlc extraintf -string http
defaults write org.videolan.vlc http-host -string 127.0.0.1
defaults write org.videolan.vlc http-port -int 8080
defaults write org.videolan.vlc http-password -string <password>
If the interface or config is missing, the service treats VLC as unreachable and idles rather than failing.
Run at login
launchd keeps the service alive across reboots —
~/Library/LaunchAgents/com.quinn.portable-net-tv.watch.plist, RunAtLoad +
KeepAlive. Put Homebrew's bin first on the plist's PATH: the service
needs a modern rsync (--append-verify), not the ancient /usr/bin/rsync.
Broken media
A corrupt source file is flagged by touching a sibling marker next to it:
touch "/path/to/Show.S01E07.broken"
The watch service excludes any episode with a .broken marker — it won't
prefetch it, and episodesInDir skips it. Mark a file whenever it refuses to
play (e.g. VLC opens it but the time stays frozen at 0:00).
Constraints
- macOS only — reads VLC's macOS HTTP interface; paths assume the local media mount.
- VLC is the only supported player, and must be running with HTTP enabled.
Legacy
keep, play, check, and the per-show profiles under
~/.config/portable-net-tv/profiles/ predate the unified watch service and
are being retired. New use should rely on watch + next only.