feat(hls): persistent fMP4 segment cache + integrity + stats (0.9.7)
Some checks failed
Release / release (push) Failing after 0s
Release / docker (push) Has been skipped
Release / virustotal (push) Failing after 0s

Cache keyed by sha256(absPath|quality|audioIdx)[:8] with .complete marker;
LRU + size-budget eviction; per-key writer-lock; pinned during play;
startup orphan reap; integrity verify on HIT; subtitle-completeness gate;
hit/miss counters + daily log line. New [downloads.hls_cache] block in
config.toml (enabled/size_gb/dir, default 5GB).

Smoke test: 2nd play of same source+quality is 23-31× faster (HIT path
skips ffmpeg entirely).
This commit is contained in:
Deivid Soto 2026-05-26 23:39:02 +02:00
parent 834c58c25a
commit 7e96976257
10 changed files with 1295 additions and 9 deletions

View file

@ -343,6 +343,58 @@ unarr self-update --force # reinstall even if up to date
`unarr doctor` checks: config file, API key, server connectivity (with latency), agent registration, download directory, disk space, and version.
### Updating unarr
unarr supports three update paths. Pick whichever fits your workflow.
**1. Manual self-update (always available).**
```bash
unarr self-update # interactive update to latest
unarr self-update --force # reinstall same version
unarr self-update --allow-unsigned # accept releases without checksum signature
```
The CLI downloads the new release archive over HTTPS (from
`torrentclaw.com/releases/download/v<ver>/`), verifies SHA-256, swaps the
binary in place (`.backup` kept next to it), and restarts the systemd
user unit if the daemon is running.
**2. Auto-apply on server signal (default, since 0.9.6).**
When you press **"Force update now"** on the web (Settings → Agent → Force
update), the server sets a flag your daemon polls every sync (~3 s). On
the next sync the daemon downloads the new binary, replaces itself, and
exits — `systemd Restart=always` respawns on the new version. No SSH, no
terminal access required. Works headless on NAS / Docker.
The button shows an amber warning if your agent is below 0.9.6 (older
daemons see the signal but only log "run unarr update" — the operator
must run the command manually that one time).
**Opt out of auto-apply.** Some users prefer reviewing CHANGELOG before
applying. Disable in `config.toml`:
```toml
[daemon]
auto_upgrade = false
```
With `auto_upgrade = false`, pressing the web button still flags your
agent (so the daemon logs the new version on next sync), but the daemon
will not download / replace anything — you run `unarr self-update` when
you're ready.
**3. Docker auto-restart with a new tag.**
```bash
docker pull torrentclaw/unarr:latest
docker compose up -d
```
Tags published: `latest`, `0.9`, `0.9.7`, ... — pin to a minor (`0.9`)
for opt-in patch updates without surprises.
## Clean
Remove temporary files, logs, resume data, and other artifacts generated by unarr. Shows what will be removed and asks for confirmation before deleting.
@ -424,6 +476,7 @@ tv_shows_dir = "~/Media/TV Shows"
[daemon]
poll_interval = "30s"
heartbeat_interval = "30s"
auto_upgrade = true # apply server-flagged upgrades in-place (since 0.9.6)
[notifications]
enabled = true
@ -466,6 +519,40 @@ If `transcode.enabled = true` but `ffmpeg` / `ffprobe` aren't on PATH, the
daemon logs a warning at startup and HLS sessions are rejected at runtime
with a clear error — install ffmpeg or set `enabled = false`.
#### `[downloads.hls_cache]` — persistent HLS segment cache
```toml
[downloads.hls_cache]
enabled = true # on by default
size_gb = 5 # disk budget; LRU eviction once exceeded
dir = "" # custom path; empty = ~/.cache/unarr/hls-cache
```
| Key | Type | Default | Notes |
|-----|------|---------|-------|
| `enabled` | bool | `true` | Persists finished HLS encodes per `(source, quality, audio_index)`. A second play of the same file at the same quality reuses the segments — no ffmpeg, near-zero CPU, instant playback. Set to `false` to delete segments on session close (original behavior). |
| `size_gb` | int | `5` | Cache budget in gigabytes. When exceeded the LRU sweeper evicts the least-recently-used cached encodes hourly. Minimum 1 GB (smaller values are clamped up). |
| `dir` | string | `""` | Custom storage path. Empty defaults to `~/.cache/unarr/hls-cache` (Linux/macOS) or the user cache dir (Windows). |
**What it does.** First play encodes normally (ffmpeg writes segments).
On session close, if every segment is on disk and ffmpeg exited cleanly,
the directory is sealed with a `.complete` marker and kept. Next time the
same source + quality combo is requested, the daemon serves segments
straight from disk — no transcode, no warm-up, no CPU cost.
**Why per (source, quality, audio).** Renaming the file or switching
quality invalidates the entry: the segments are tied to the exact source
bytes and the exact ffmpeg parameters. Re-encoding generates a new key.
**Eviction.** A background goroutine wakes every hour. If total cache size
exceeds `size_gb`, it deletes the oldest entries (by mtime) until under
budget. Active sessions are pinned — they never get evicted mid-play.
**Disable.** Either edit the TOML to set `enabled = false`, or remove the
cache directory manually (it'll be recreated as needed). Disabling does
not delete existing cached segments — drop `dir` (or `~/.cache/unarr/hls-cache`)
to reclaim the space.
#### `[downloads.vpn]`
| Key | Type | Default | Notes |