# 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/tv-anarchy/watched.jsonl` (legacy
`tv-anarchy-mcp` path auto-migrated by the shared media package). One event per
line (see the main docs for full schema + clients + `finished` + `durationSeconds`).
`ts, event` ("play"|"resume"|"reset"), `show`, `season`, `episode`, `label`, `path`,
`resumeSeconds`, `durationSeconds`, `client`. The show name is parsed from the
filename (everything before the `SxxEyy` marker) when not supplied. "play" (or
>=92 % position) advances per-show progress.

## 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).

The TVAnarchy Mac app also offers "Mark as broken (governor skip)" in library episode
context menus (right-click an episode in Library or Continue Watching). It SSHes to
storage and touches the sibling marker for you. (Unmark is available via the same
DevicesConfig helper if you need to re-enable a file.)

## 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.
