No description
Find a file
Natalie dd7e94225e fix(node-types): 🐛 remove bun/node type dependencies
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-10 02:18:50 -07:00
.claude/worktrees fix(node-types): 🐛 remove bun/node type dependencies 2026-06-10 02:18:50 -07:00
.project/history fix(node-types): 🐛 remove bun/node type dependencies 2026-06-10 02:18:50 -07:00
src feat(apps): add ssh remote support for rsync 2026-06-04 01:59:15 -07:00
tools fix(node-types): 🐛 remove bun/node type dependencies 2026-06-10 02:18:50 -07:00
bun.lock chore: baseline before autonomous OSX-app task 2026-05-29 21:55:46 -06:00
package.json chore: baseline before autonomous OSX-app task 2026-05-29 21:55:46 -06:00
README.md chore: baseline before autonomous OSX-app task 2026-05-29 21:55:46 -06:00
tsconfig.json chore: baseline before autonomous OSX-app task 2026-05-29 21:55:46 -06:00

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:

  1. Reads the currently-playing file from VLC's HTTP playlist.
  2. Appends episode changes to the cross-show watch log.
  3. 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).
  4. 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.