diff --git a/todo/README.md b/todo/README.md new file mode 100644 index 0000000..3144a15 --- /dev/null +++ b/todo/README.md @@ -0,0 +1,9 @@ +# Gostations TODO List + +This document provides a table of contents for all tasks and features currently tracked in the `todo/` directory. + +## Queued + +* [1] [per-station-volume.md](./queued/per-station-volume.md) : per-station volume savings + +## Completed diff --git a/todo/queued/TODO_ITEM.md b/todo/queued/TODO_ITEM.md new file mode 100644 index 0000000..f812abc --- /dev/null +++ b/todo/queued/TODO_ITEM.md @@ -0,0 +1,4 @@ +# TODO ITEM 1 +- [ ] 1 step one +- [ ] 2 step two +- [ ] 3 step three diff --git a/todo/queued/per-station-volume.md b/todo/queued/per-station-volume.md new file mode 100644 index 0000000..c4139b6 --- /dev/null +++ b/todo/queued/per-station-volume.md @@ -0,0 +1,71 @@ +# Per-station volume savings + +**Description**: Persist the last-used volume level on a per-station basis (keyed by stream URL), so that returning to a favorite or previously-played station restores the volume the user last set for *that specific station*, rather than always falling back to the global last-volume. + +## Problem It Solves + +Currently only a single global `player.last_volume` is saved in `radiostations.ini`. When a user fine-tunes the volume while listening to Station A (e.g. to 35), stops, then plays Station B, the volume is reset to whatever was last saved globally (or the default 70). Users have to re-adjust the volume every time they switch stations. + +## Benefits + +- **Natural UX**: Volume preference is station-specific (a quiet classical station vs. a loud rock station). +- **Seamless resumption**: Pick a favorite → volume is already where you left it. +- **Low friction**: No extra UI; the existing volume controls + persistence just become smarter. +- **Backward compatible**: Falls back to global last-volume when no per-station entry exists. +- **Leverages existing patterns**: Same atomic JSON storage + XDG path as `favorites.json`. + +## High-Level Implementation + +1. **New data store** (`internal/data/volumes.go`): + - `type Volumes struct { ... }` (map[url]volume, mutex, dirty flag, path to `volumes.json`). + - `NewVolumes()`, `Load()`, `Save()` (exact same atomic tmp+rename pattern as Favorites). + - `Get(url string) (int, bool)`, `Set(url string, vol int)`, `Remove(url string)`. + +2. **Wire into TUI / playback start** (in `internal/ui/ui.go`): + - On entering playback for a station: + - `if vol, ok := volumes.Get(station.Url); ok { desired = vol } else { desired = config.LastVolume() }` + - Pass `desired` as `--volume=...` extra arg (or call a new `player.SetVolume(desired)` once IPC is ready). + - On every volume change (in `volumeMsg` handler or on keypress): + - `volumes.Set(currentStation.Url, newVol)` + - `volumes.Save()` (or mark dirty and save on stop/quit for batching). + - On `s`/`x` stop or app quit: ensure pending volume for the current station is saved. + +3. **Player interface extension** (optional but clean): + - Add `SetVolume(v int) error` to `Player` interface. + - `mpvPlayer` implements it with `set_property volume X` + local cache update. + - `legacyPlayer` is a no-op (or could try command-line args on next Play). + +4. **Config / init**: + - Load volumes in `NewApp()` or lazily when first needed (same as favorites). + - On station removal from favorites (if desired): optionally prune the volume entry. + +5. **Persistence file**: `~/.config/gostations/volumes.json` (array of `{url, volume}` or map for simplicity). + +## Flags / Config + +| Key | Description | +|-----|-------------| +| (none yet) | Could add `player.per_station_volume=true` (default on) in future | + +## Implementation Notes + +- **Key choice**: Use the station's `Url` (same as Favorites). Stable enough for the use-case. +- **When to persist**: Save on every change (cheap) or only on stop/quit. Current global volume already saves on change; we can do the same for per-station or batch on exit. +- **mpv timing**: The `--volume=XX` extra arg passed to `Play()` is the simplest reliable way (command-line wins). IPC `set_property` after connect is a good fallback/override. +- **Legacy player**: Per-station volumes will be ignored for now (documented limitation). +- **First-time migration**: Existing global last-volume becomes the fallback; no automatic per-station entries are created until user actually changes volume on a station. +- **Tests**: Add to `stations_test.go` or new `volumes_test.go`; mock the volumes store. +- **Effort**: Medium (~200-300 LOC new + wiring). Mostly data layer + 3-4 call sites in the TUI. + +## ROI + +**High**. Volume is one of the most frequently adjusted controls in a radio player. Making it "stick" per station removes a constant micro-friction and makes the TUI feel more thoughtful and polished. + +| Stage | Covered | +|-------|---------| +| Global last-volume | ✓ (already shipped in 2.1) | +| Per-station | **new** | +| Favorites | ✓ (existing) | +| TUI playback | ✓ | + +Users will notice it immediately the second time they return to a station they previously tuned.