# Library

**Job:** Know what media exists — scan, index, group, enrich — as a **catalog**
independent of *where* you press play.

One-liner: *What’s in the collection, how is it organized, what metadata does it have?*

Split from **Watch**, which owns playback UX (Home rails, Player, queue).

---

## Scope

| In | Out |
|----|-----|
| Library scan + `library.json` snapshot | Play/pause/seek (Watch) |
| Category rails, browse grids | Torrent add (Download) |
| Show grouping, franchises, `ContentID` | Device registry (Devices) |
| Metadata enrichment queue + sidecars | Custody / re-pin (Download) |
| Smart playlists, search-within-library | Net merge transport |
| **Canonical episode display names** | Raw filenames in UI |
| **Logical paths** on shared media volume | Physical placement (Devices) |
| Adult collection rotation (catalog side) | Adult Player queue UX (Watch) |

---

## User surfaces

| Surface | Pillar | Notes |
|---------|--------|-------|
| Library tab | Library | Browse, scan, refresh |
| Metadata tab | Library | Enrichment queue |
| Home rails (data) | Library → Watch | Continue / Recently Added **data** from Library |
| Search tab | Download | Torrent search — not library search |
| Adult collections grid | Library + Watch | Catalog in Library; play UX in Watch |

---

## Core modules (moved from Watch doc)

| Module | Path | Role |
|--------|------|------|
| `LibraryController` | `Library/` | Orchestration, home rails data |
| `LibraryScanner` | `Library/` | Index build |
| `LibraryIndex` | `Library/` | index on the always-on host |
| `LibraryStore` | `Library/` | `library.json` |
| `LibraryConfig` | `Library/` | Types, adult flags |
| `ShowGrouping` | `Library/` | Episode → show |
| `ContentID` | root | Stable keys — shared with Net, Devices placement |
| `FranchiseStore` | `Library/` | Prefix franchises |
| `MetadataController` | `Metadata/` | Enrichment UI backing |
| `EnrichService`, `MetaWriter`, `ArtworkService` | `Metadata/` | Sidecars |
| `FilenameParser`, `LocalLLMTitleRefiner` | `Metadata/` | Parse + refine |
| `LibraryDisplayNames` | `Library/` *(planned)* | Canonical `displayName` at scan — [library-display.md](./library-display.md) |
| `PornCollectionService` | root | Rotation catalog |
| `SmartPlaylist` | root | Helpers |
| `RegistryIngest` | `Library/` | `registry.md` offline titles |
| `PreviewService` | `Library/` | Hover previews (ffmpeg on the always-on host) |

**Watch keeps:** `WatchHistory`, `PlaylistController`, `PlayerController`,
`NowPlayingController`, Home **presentation**.

---

## Shared media volume (Devices)

Library catalog stores **logical paths** only. Physical bytes may live on:

- canonical tier (central always-on host)
- extension tier (laptop spare)

`LibraryScanner` primary source remains canonical `mediaRoot`; extension tiers
register completed placements into the same catalog via
[devices-storage.md](./devices-storage.md) placement index — no duplicate show
rows.

---

## Settings (Library pillar)

| Setting | Today |
|---------|-------|
| `combineSplitShows` | `settings.json` |
| `useLLMGrouper` | `settings.json` |
| `folderTypes`, `libraryTypes` | `settings.json` |

Future: scan schedule, default metadata providers, grouping aggressiveness, advanced quality-aware organization (duplicate detection, variant handling, safe automated moves with rollback from prior art in WatchTV-UWU project).

See [settings.md](./settings.md).

## Mining from Prior TV Project (WatchTV-UWU)

The other TV project (located deep in the always-on host's last Linux backup at applications/src/@uwuapps/watchtv/ – "WatchTV-UWU", a monorepo TS media progress tracker/streamer) provides battle-tested patterns for Library improvements:

- Advanced media organization: quality scoring (resolution/codec/source for variants/duplicates), duplicate detection, space optimization, analytics/recommendations, caching (TTL + persistent).
- AutomatedMover with transactions, rollback, backups, safety checks, retry (ideal for re-org or Devices re-pin without data loss).
- Activity logging, real-time monitoring, alerts.
- Performance: faster scans, lower memory (e.g., 67% faster, 43% less mem in their impl).
- See their ORGANIZATION_SYSTEM_SUMMARY.md, media-file-organization.md, quality-variant-organization.md for services (MediaOrganizer, QualityOrganizer, AutomatedMover, ActivityLogger) and DB schema enhancements.

Integrate selectively into LibraryScanner + new organization services. Complements Net `quality` part and Devices placement. Update plan Appendix D and correlation for adoption.

This aligns with v2 goal of canonical display + no raw filenames, while handling torrent realities (multiple qualities/releases).

---

## Net touchpoints

| Net part | Library consumer |
|----------|------------------|
| `grouping` | Merge hints in `ShowGrouping` |
| `quality` | Preferred release in catalog display |

Library **produces** grouping observations for Net.

---

## State

| Artifact | Path |
|----------|------|
| Library snapshot | `~/.local/state/tv-anarchy/library.json` |
| Metadata sidecars | `~/.local/state/tv-anarchy/meta/` |
| Title refinements | `~/.local/state/tv-anarchy/title-refinements.json` |
| Black index | remote `index.tsv` |

Placement index: Devices pillar — Library reads logical paths only.

---

## Episode display names (v2 requirement)

Library **standardizes** what users see for every episode — not the on-disk
release filename. Format: `S01E04 · Episode Title` with enrichment/parse
fallbacks.

| Doc | Topic |
|-----|-------|
| [library-display.md](./library-display.md) | `displayName` format + UI contract |
| [library-titles.md](./library-titles.md) | **Title Library** dataset, MLX M2, enrich-once |

---

## v2 phases

| Phase | Task |
|-------|------|
| Doc split | Watch.md slim; this file authoritative for catalog |
| **Title Library** | `TitleLibrary` + `contentKey` rows; MLX writes once |
| **Display names** | `LibraryDisplayNames` + scanner + Player consumers |
| Settings section | Library block in SetupView |
| Placement-aware index | `DownloadsIndex` + logical paths |
| Net grouping | Subscribe merge into scanner |