Commit graph

42 commits

Author SHA1 Message Date
Natalie
ee3da4e101 perf(watch-history): stop the background poll freezing the main thread
The 8s watch-history poll ran refresh() on the main actor, which read and
JSON-decoded the unioned watch log THREE times (playedPaths, resumePositions,
episodeProgress each re-read) and called MediaPaths.toRemote() per event — and
every toRemote rebuilt ProcessInfo.environment (~22µs each, the whole env dict
is reconstructed on every access) plus a homeDirectory lookup. A live sample
caught the main thread 100% in this path; the app sat at 78–113% CPU.

- Cache MediaPaths.remoteRoot / mappings (process-constant) → kills the
  per-call env-dictionary rebuild storm.
- WatchHistory.derivedState(): read+decode the log ONCE, feed all three
  derived computations → 3× fewer reads/decodes per refresh.
- WatchHistoryController.refreshAsync(): the background poll now parses off the
  main thread on a utility task and only assigns the small results on main.

Settled CPU drops from ~78% sustained to ~0% idle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 01:44:06 -04:00
Natalie
e532fe14bc feat(offline): star in place — keep files in their show group
Starring no longer relocates a file into a separate 'Starred' section; every
item stays in its own show group and the row's star button just toggles on/off
(filled-yellow vs outline) as the keep-from-cull indicator. Show headers show a
'★N' badge for how many in that group are starred. Drops the leading star-swap
and the now-unused nonPinnedGrouped grouping.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 01:12:11 -04:00
Natalie
40188f85a9 feat(offline): ⤴︎ priority download lane — user picks jump the warmup
On-demand downloads (e.g. goon clips picked in the Adult collection list) now
take priority over the background warmup plan instead of waiting behind it or
starting a competing rsync:

- new priority lane (priorityEpisodes/priorityCount/enqueuePriority) drained
  before each plan item and immediately when the cache is idle
- fetchFile routes through the lane when a warmup is already running (was: a
  second concurrent rsync that also stomped the queue UI), and awaits completion
- per-episode fetch extracted to fetchOne(), shared by plan + priority drains
- status line shows '⤴︎N prioritized'; prioritizeFetch()/awaitDownload() expose
  it for callers

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 01:06:46 -04:00
Natalie
3c67b547c6 fix(adult): 🔒 terminate ffprobe options with -- in duration probe
Defense-in-depth against option injection: a library path beginning with '-'
could be parsed as an ffprobe flag. Paths are always absolute today so it isn't
reachable, but '--' makes it safe regardless. Not command injection: $p is a
double-quoted expansion (contents not re-evaluated) and paths arrive as stdin
data, never on a command line — documented inline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 01:00:02 -04:00
Natalie
eb0d75a126 feat(adult): ⏱ show clip length in collection detail list
Each clip row in the adult collection detail view now shows its runtime, and
the header shows total runtime of the queued set (for planning a session of a
given length). Durations are probed in one background SSH batch via ffprobe on
black (NUL-delimited paths over stdin, so the eporner filenames with spaces/
quotes/brackets pass verbatim), debounced on filter and capped at 400 per batch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 00:56:59 -04:00
Natalie
ee7efad888 feat(adult): 🍿 collection detail view — clip checklist + offline download
Tapping a collection card on the Adult page now opens a detail view listing
every clip in that collection (goon, pmv, etc) instead of silently firing the
whole set at a host with nothing cached. Each row shows:
- queued state as a tickable checklist (build a session clip by clip)
- freshness / last-played
- offline-cached state, with a per-clip download-to-offline button

Plus a title filter (find e.g. a specific 'brain rot'/gooner clip), queue-all-
fresh, download-all-queued-offline, and play-queued. Downloads land in the
offline cache where the new star/trash row controls manage them. Quick-play the
old fire path stays on the card context menu.

Core: PornCollectionService.clips()/title() expose the full per-collection clip
list with freshness; PlaylistController gains single-item checklist queue ops
(isQueued/addToQueue/removeFromQueue) and pornClips().

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 00:50:05 -04:00
Natalie
4a2ceb9781 feat(offline): inline star-to-keep and trash-to-cull on cache rows
Surface the existing pin (keep-from-cull) and per-file delete actions as
visible inline buttons on each offline cache row instead of context-menu-only:
a star toggles protection from auto-cull (and restore-if-missing), a trash
culls that file early. Aligns wording/icons to the star metaphor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 00:12:41 -04:00
Natalie
1d01adda2d feat(@applications/tv-anarchy): add black-watchlog sync for in-app playback tracking
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-10 04:00:48 -07:00
Natalie
e447f0a8f6 feat(@applications): add bridge deployment scripts
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-09 22:22:56 -07:00
Natalie
83a21ca105 feat(library): optimize scan merging with cached metadata
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-09 22:16:25 -07:00
Natalie
0a4cde36d1 feat(devices): add dependency issue warnings
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-09 21:57:08 -07:00
Natalie
ca1871f5dd feat(@applications/tv-anarchy): add roku device support
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-09 21:37:34 -07:00
Natalie
4466ff72cd feat(@applications/tv-anarchy): implement parallel fleet completion modules
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-09 21:30:14 -07:00
Natalie
a86e68c525 feat(apps): add fleet engine mesh core integration
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-09 21:23:36 -07:00
Natalie
7ff780fe56 feat(apps/tv-anarchy): add restart command support
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-09 21:17:10 -07:00
Natalie
8f12f470b7 feat(metadata): add local llm title refiner integration
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-09 21:10:47 -07:00
Natalie
b44b5a2d1a feat(@applications): add adult content browsing tab
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-09 19:51:12 -07:00
Natalie
68e107b03a feat(devices): per-device system-load badge (low/med/high) on Devices list
Sample every HostStatsProvider target's load while the Devices tab is
visible (gated like the existing detailed/detailVisible pollers), keyed
by device id in PlayerController.hostStatsByID. DevicesView renders a
capsule badge from load1/cores: <0.6/core low, <1.0/core med, else high.
Only SSH/mpv devices report stats; others show no badge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 14:07:45 -07:00
Natalie
17cf518418 feat(ios): downloads (DownloadManager/DownloadsView), remote control view + bridge/player refinements
(cherry picked from commit a1f7e44e17bb41f48976b69f4dbe5278cbad06b2)
2026-06-09 06:38:45 -07:00
Natalie
f0669f1ca8 feat(ios): TVAnarchyiOS app target + UI tests
(cherry picked from commit 7f8f4b0dd92358ba687f8230a922d8f316cb06e9)
2026-06-09 05:50:26 -07:00
Natalie
6366a841f4 feat(app): app icon asset catalog + make-icon tool
(cherry picked from commit 14d34d98c5)
2026-06-09 05:50:20 -07:00
Natalie
b78a57906a feat(ui): root/setup/home/downloads/library view updates for device+grouping model 2026-06-09 05:50:02 -07:00
Natalie
9e38cf9f48 feat(core): player/playlist/porn-service rework + repo paths 2026-06-09 05:50:02 -07:00
Natalie
117e234a3c feat(core): offline cache, bandwidth policy, now-playing, notifications + torrent rework 2026-06-09 05:50:01 -07:00
Natalie
d8bc6c621e feat(library): show grouping, local-LLM grouper, content IDs, watch state + registry ingest 2026-06-09 05:50:01 -07:00
Natalie
6e9bccb992 refactor(fleet): rename Host→Device — DeviceConfig model + Devices UI, drop HostConfig/HostsView 2026-06-09 05:50:01 -07:00
Natalie
7ea1dad7b6 feat(vpn): VPN subsystem — OVPN profile/credential stores, controller, settings UI + parser tests 2026-06-09 05:50:01 -07:00
Natalie
0cc33e30b6 feat(queue): add test-isolated queue state directory
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-08 22:49:38 -07:00
Natalie
b8b148b788 feat(library): add queue context menu for shows
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-08 22:40:53 -07:00
Natalie
92b38b1bae refactor(tv-anarchy): rename PlumTV→TVAnarchy and land session work
Renames Sources/PlumTV→TVAnarchy and PlumTVCore→TVAnarchyCore (the rename
the auto-commit service couldn't stage — it git-add'd the old, now-gone
paths and aborted every cycle), and commits the accumulated work:

- Library: black-built index fast path (LibraryIndex + scanFromIndex) with
  NFS-walk fallback; incremental --add on download-complete; mtime staleness
  gate; loose-file series-collapse fix; determinate scan/index progress.
- Cover art: keyless TVmaze cartoon-vs-live-action disambiguation (type/year).
- Player: sleep timer (timed + end-of-episode); visibility-gated polling.
- Home: Continue Watching cover art + live refresh; Recently Added; adult gate.
- Logs: multi-line selection + copy; truncated giant tx-list errors.
- Hover previews (opt-in) via black ffmpeg + scp.

Also gitignores foreign project trees (governor/mcp/fleet/recommender) that
sit in this directory but belong to their own repos.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 22:04:22 -07:00
Natalie
4a5b82fbd4 feat(@applications/plum-tv): add mpv target integration
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-08 00:09:30 -07:00
Natalie
fead8ec227 feat(plum-tv): improve transfer list display with new row view
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-07 23:35:39 -07:00
Natalie
8b58c27f15 feat(library): update episode count display with summary
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-07 23:24:09 -07:00
Natalie
64effb6033 feat(process): update zsh shell to interactive mode for full PATH access
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-07 23:13:49 -07:00
Natalie
f03f9f0809 fix(@applications/plum-tv): 🐛 improve volume snap behavior with awaited command
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-07 22:33:31 -07:00
Natalie
65f3cb1e4e feat(plum-tv): add async poster loading for shows
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-07 22:06:27 -07:00
Natalie
b804d52bc5 feat(plum-tv): add torrent search and download interface
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-07 21:56:40 -07:00
Natalie
ff6f881648 feat(@applications/plum-tv): add library browsing UI and core library logic
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-07 21:52:49 -07:00
Natalie
f5a3adb58c fix: crash — quality picker binding subscripted empty releases mid-transition
SwiftUI evaluates the Picker binding getter during target switches when
releases is briefly empty; releases[0] trapped (EXC_BREAKPOINT). Use .first?.id ?? "".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 21:02:31 -07:00
Natalie
ba1a3f24b8 feat(plum-tv): add cpu load and history chart to player view
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-07 20:52:42 -07:00
Natalie
10f2abd022 feat(plum-tv): add quality picker UI and switching support
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-07 20:41:37 -07:00
Natalie
e2977041aa feat: PlumTV — native macOS player with config-driven hosts
Phase 0/1: SwiftUI app (XcodeGen), PlumTVCore framework, player MVP.
- PlayerTarget protocol + VLCTarget (HTTP) and BlackTVTarget (ssh black-tv)
- config-driven hosts (~/.config/plumtv/hosts.json), seeded plum-vlc + black
- reliability: SSH ControlMaster (5s->~1s/poll), endpoint pinning (LAN->overlay),
  single-flight polling, keep-last-known on transient failure, debounced volume
- Hosts pane shows live connection state; Player has target picker + transport
- unit tests for status decoding

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 20:24:55 -07:00