103 lines
3.2 KiB
Markdown
103 lines
3.2 KiB
Markdown
|
|
# 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
|
||
|
|
|
||
|
|
```sh
|
||
|
|
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`
|
||
|
|
|
||
|
|
```sh
|
||
|
|
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`:
|
||
|
|
|
||
|
|
```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:
|
||
|
|
|
||
|
|
```sh
|
||
|
|
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:
|
||
|
|
|
||
|
|
```sh
|
||
|
|
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.
|