Commit Graph

385 Commits

Author SHA1 Message Date
bjarneo 2885f4dfff fix(macos): ensure media key handlers run on main OS thread
Lock the main goroutine to OS thread 1 in init() and defer
MediaKeysInit to RunMainLoop so MPRemoteCommandCenter handlers
are registered on the correct thread for CFRunLoop delivery.
2026-04-06 09:12:29 +02:00
Bjarne Øverli fbbb6969d0 Add mediactl controller interface with macOS media keys support
Extract a platform-agnostic MediaController interface from the MPRIS
integration so that media key support can be added per-platform without
modifying the core TUI code.

- mediactl/ package: Controller interface (Update, EmitSeeked, Close),
  MainLoopRunner interface for controllers that need the main OS thread,
  and a self-registration registry via init()
- MPRIS refactored to implement mediactl.Controller, self-registers via
  init() with blank import in main.go
- TrackInfo and SetPositionMsg moved to shared packages (mediactl and
  internal/control) so platform code doesn't cross-import
- Model uses []mediactl.Controller instead of *mpris.Service, with
  notifyMediaControllers() and emitSeeked() helpers replacing direct
  mpris calls
- prog.Run() moved to a goroutine with mediactl.RunMainLoop() on the
  main thread, enabling macOS NSRunLoop (no-op on Linux)
- Full macOS CGo scaffold: MPRemoteCommandCenter for receiving media
  key events, MPNowPlayingInfoCenter for Now Playing info, with change
  detection to skip redundant CGo calls on the per-second tick
- Key handlers upgraded from notifyMPRIS() to notifyAll() so Lua
  plugins also receive state updates on keyboard actions
- Notification hot path uses cached position/duration instead of
  re-acquiring the speaker lock
2026-04-06 09:04:38 +02:00
Bjarne Øverli 2b5d3aa505 Use hours spent and not total sessions for the visualization 2026-04-05 11:17:59 +02:00
Mark Tran de0794dde1 fix(ui): return stream seek cmds from arrow keys (#169)
Release / build (amd64, darwin, macos-latest) (push) Has been cancelled
Release / build (amd64, linux, ubuntu-latest) (push) Has been cancelled
Release / build (amd64, windows, windows-latest) (push) Has been cancelled
Release / build (arm64, darwin, macos-latest) (push) Has been cancelled
Release / build (arm64, linux, ubuntu-latest) (push) Has been cancelled
Release / release (push) Has been cancelled
Release / update-homebrew (push) Has been cancelled
Arrow-key seeking for HTTP podcast streams never ran because the key handlers called m.doSeek(...) without returning its command. That meant seek-by-reconnect worked via IPC and jump-to-time, but not via Left/Right in the TUI.

Return the command from the arrow-key handlers and add a regression test for the HTTP stream seek path.
v1.34.1
2026-04-05 10:19:04 +02:00
36e5d6431c Update keymap to respect responsive height (#167)
* Update keymap to respect responsive height

* Use 'ctrl+x' for expand/collapse height (was 'x') to avoid conflicts with typed filter/search input

* Simplify keymap overlay: deduplicate visible-row calc, remove global scroll state, drop j/k/g/G bindings that conflict with search filter

* Update docs for Ctrl+X expand/collapse keybinding

---------

Co-authored-by: Bjarne Øverli <bjarne.oeverli@gmail.com>
2026-04-05 09:42:37 +02:00
Bjarne Øverli 6782a8c3ca Update dependencies 2026-04-04 21:12:01 +02:00
Bjarne Øverli cca2a21937 Update docs 2026-04-04 20:58:45 +02:00
zambetti 50e8c3493f Feature: Responsive Height (#157)
Release / build (amd64, darwin, macos-latest) (push) Has been cancelled
Release / build (amd64, linux, ubuntu-latest) (push) Has been cancelled
Release / build (amd64, windows, windows-latest) (push) Has been cancelled
Release / build (arm64, darwin, macos-latest) (push) Has been cancelled
Release / build (arm64, linux, ubuntu-latest) (push) Has been cancelled
Release / release (push) Has been cancelled
Release / update-homebrew (push) Has been cancelled
* Merge responsive height feature

* Inline some single use helpers

* Simplify responsive height: remove dead code, deduplicate helpers

- Remove unused renderedLineCount() and defaultPlVisible()
- Fix space key representation to match bubbletea v2 convention
- Replace rowsFrom closure with existing providerRowsFromScroll()
- Extract applyHeightMode() to unify repeated height expansion logic
- Extract resetProviderNav() to deduplicate provider state resets
- Cache fbVisible()/providerScrollStep() to avoid redundant probe renders

---------

Co-authored-by: Bjarne Øverli <bjarne.oeverli@gmail.com>
v1.34.0
2026-04-04 20:48:00 +02:00
Tom di Mino c4ed834e03 feat: add dracula, ember, and neon-blade-runner themes (#164)
Three new built-in themes filling gaps in the hue spectrum:
- dracula: canonical purple palette (draculatheme.com), 265° accent
- ember: deep warm hearth with copper-to-crimson spectrum, 20° accent
- neon-blade-runner: Cronenweth's 1982 neon noir — hot pink neon signs,
  teal rain reflections, amber CRT readouts, 334° accent

Updates docs/themes.md count from 17 to 20 and changes the custom
theme example from Dracula (now built-in) to Solarized.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 20:36:02 +02:00
Bjarne Øverli b4109482be Add community plugin page 2026-04-04 17:04:56 +02:00
Bjarne Øverli e74f6629a8 Fix silent token refresh wiping OAuth2 refresh token
Release / build (amd64, darwin, macos-latest) (push) Has been cancelled
Release / build (amd64, linux, ubuntu-latest) (push) Has been cancelled
Release / build (amd64, windows, windows-latest) (push) Has been cancelled
Release / build (arm64, darwin, macos-latest) (push) Has been cancelled
Release / build (arm64, linux, ubuntu-latest) (push) Has been cancelled
Release / release (push) Has been cancelled
Release / update-homebrew (push) Has been cancelled
When silent token refresh failed in the silentOnly path, credentials
were re-saved without the RefreshToken field, permanently losing the
ability to refresh silently. This caused a death spiral where every
subsequent launch fell back to the spclient token, which gets
rate-limited on Web API calls.

Preserve the original refresh token so the next launch can retry.
v1.33.9
2026-04-04 16:55:40 +02:00
Marcelo Mandolesi f77917f0a8 Align playlist track number, artist name, track title (#165)
Release / build (amd64, darwin, macos-latest) (push) Has been cancelled
Release / build (amd64, linux, ubuntu-latest) (push) Has been cancelled
Release / build (amd64, windows, windows-latest) (push) Has been cancelled
Release / build (arm64, darwin, macos-latest) (push) Has been cancelled
Release / build (arm64, linux, ubuntu-latest) (push) Has been cancelled
Release / release (push) Has been cancelled
Release / update-homebrew (push) Has been cancelled
v1.33.8
2026-04-04 08:08:38 +02:00
Bjarne Øverli 5defccbbe1 Fix .SRCINFO containing pacman output
Release / build (amd64, darwin, macos-latest) (push) Has been cancelled
Release / build (amd64, linux, ubuntu-latest) (push) Has been cancelled
Release / build (amd64, windows, windows-latest) (push) Has been cancelled
Release / build (arm64, darwin, macos-latest) (push) Has been cancelled
Release / build (arm64, linux, ubuntu-latest) (push) Has been cancelled
Release / release (push) Has been cancelled
Release / update-homebrew (push) Has been cancelled
Redirect pacman install output to stderr so only makepkg
--printsrcinfo output ends up in .SRCINFO.
v1.33.7
2026-04-03 22:49:49 +02:00
Bjarne Øverli 0937cd7812 Fix AUR workflow permission issue with Docker volume
Release / build (amd64, darwin, macos-latest) (push) Has been cancelled
Release / build (amd64, linux, ubuntu-latest) (push) Has been cancelled
Release / build (amd64, windows, windows-latest) (push) Has been cancelled
Release / build (arm64, darwin, macos-latest) (push) Has been cancelled
Release / build (arm64, linux, ubuntu-latest) (push) Has been cancelled
Release / release (push) Has been cancelled
Release / update-homebrew (push) Has been cancelled
Mount only the PKGBUILD read-only instead of the entire git repo
to avoid Docker's chown breaking .git directory permissions.
v1.33.6
2026-04-03 22:38:03 +02:00
Bjarne Øverli b634a3613d Tab should go in the correct order, EQ, SRC, SPD
Release / build (amd64, darwin, macos-latest) (push) Has been cancelled
Release / build (amd64, linux, ubuntu-latest) (push) Has been cancelled
Release / build (amd64, windows, windows-latest) (push) Has been cancelled
Release / build (arm64, darwin, macos-latest) (push) Has been cancelled
Release / build (arm64, linux, ubuntu-latest) (push) Has been cancelled
Release / release (push) Has been cancelled
Release / update-homebrew (push) Has been cancelled
v1.33.5
2026-04-03 22:28:49 +02:00
Bjarne Øverli bcfd83fad8 Replace third-party AUR action with inline workflow
The KSXGitHub/github-actions-deploy-aur action broke due to an Arch
Linux util-linux update. Replace it with a self-contained workflow
that handles SSH setup, AUR clone, .SRCINFO generation, and push
directly.
2026-04-03 22:28:01 +02:00
Bjarne Øverli 02fbd1d593 Do the aur release ourselves
Release / build (amd64, darwin, macos-latest) (push) Has been cancelled
Release / build (amd64, linux, ubuntu-latest) (push) Has been cancelled
Release / build (amd64, windows, windows-latest) (push) Has been cancelled
Release / build (arm64, darwin, macos-latest) (push) Has been cancelled
Release / build (arm64, linux, ubuntu-latest) (push) Has been cancelled
Release / release (push) Has been cancelled
Release / update-homebrew (push) Has been cancelled
v1.33.4
2026-04-03 22:21:20 +02:00
Bjarne Øverli 85e816b4e7 Cache Spotify playlist list to reduce API calls
Release / build (amd64, darwin, macos-latest) (push) Has been cancelled
Release / build (amd64, linux, ubuntu-latest) (push) Has been cancelled
Release / build (amd64, windows, windows-latest) (push) Has been cancelled
Release / build (arm64, darwin, macos-latest) (push) Has been cancelled
Release / build (arm64, linux, ubuntu-latest) (push) Has been cancelled
Release / release (push) Has been cancelled
Release / update-homebrew (push) Has been cancelled
Playlists() results are cached for 5 minutes to avoid redundant
API calls when switching providers. Mutations (add track, create
playlist) invalidate the cache.
v1.33.3
2026-04-03 21:22:16 +02:00
Bjarne Øverli 235f348840 Route spotify stderr messages to in-app log footer
Replace fmt.Fprintf(os.Stderr) calls in the spotify provider with
applog.Printf() so messages appear styled in the TUI footer instead
of corrupting the alternate screen buffer. Log entries auto-expire
after 6 seconds.
2026-04-03 18:59:49 +02:00
Bjarne Øverli e9c1adc181 Add context of where you are 2026-04-03 17:14:34 +02:00
Bjarne Øverli f63825732d Stop deleting Spotify credentials before interactive reconnect
ReconnectInteractive was deleting the credentials file before
attempting the new OAuth flow. If that flow failed (e.g. port in use),
credentials were lost permanently, causing every subsequent silent
reconnect to fail with "no stored credentials". Since
newInteractiveSession overwrites the file on success via saveCreds,
the pre-delete was unnecessary and destructive.
2026-04-03 14:58:41 +02:00
Bjarne Øverli aff224201c Update docs 2026-04-03 14:52:51 +02:00
Bjarne Øverli 644f7db6de Add more tests
Release / build (amd64, darwin, macos-latest) (push) Has been cancelled
Release / build (amd64, linux, ubuntu-latest) (push) Has been cancelled
Release / build (amd64, windows, windows-latest) (push) Has been cancelled
Release / build (arm64, darwin, macos-latest) (push) Has been cancelled
Release / build (arm64, linux, ubuntu-latest) (push) Has been cancelled
Release / release (push) Has been cancelled
Release / update-homebrew (push) Has been cancelled
v1.33.1
2026-04-03 14:41:37 +02:00
Bjarne Øverli d22d933066 Update docs 2026-04-03 14:35:33 +02:00
Bjarne Øverli 8992285a73 Only allow track favorites on persistable local playlists 2026-04-03 14:33:34 +02:00
Bjarne Øverli 12478d66ef Fix silent reconnect discarding valid spclient session
When the OAuth2 refresh token is expired but the spclient session is
valid, continue without a Web API token source instead of failing
entirely. The Web API layer already falls back to the spclient token
when tokenSource is nil, so this avoids unnecessary interactive
reconnect (and the port 19872 binding issue that comes with it).
2026-04-03 14:30:27 +02:00
Bjarne Øverli 820a41541b Style help keys as pills and replace play/pause icon
Render keybinding hints with a background-highlighted pill style
instead of dim brackets for a cleaner, modern look. Replace the ⏯
icon with ▶❚❚ for better visual clarity.
2026-04-03 14:21:40 +02:00
Bjarne Øverli bdeecdea43 Extract player.Engine interface and ConfigSaver to decouple TUI model
Release / build (amd64, darwin, macos-latest) (push) Has been cancelled
Release / build (amd64, linux, ubuntu-latest) (push) Has been cancelled
Release / build (amd64, windows, windows-latest) (push) Has been cancelled
Release / build (arm64, darwin, macos-latest) (push) Has been cancelled
Release / build (arm64, linux, ubuntu-latest) (push) Has been cancelled
Release / release (push) Has been cancelled
Release / update-homebrew (push) Has been cancelled
The Model held a concrete *player.Player and called config.Save()
  directly, making it untestable without a live audio backend and
  real filesystem. This extracts two interfaces:

  - player.Engine: 30-method interface covering all Player methods the
    TUI uses. The Model now accepts player.Engine, enabling mock-based
    testing of the playback state machine.

  - model.ConfigSaver: single-method interface for config persistence.
    All 11 config.Save() calls in ui/model/ now go through
    m.configSaver, removing the direct filesystem dependency.
v1.33.0
2026-04-02 20:49:26 +02:00
Bjarne Øverli 73a040c270 Extract player.Engine interface and ConfigSaver to decouple TUI model
The Model held a concrete *player.Player and called config.Save()
  directly, making it untestable without a live audio backend and
  real filesystem. This extracts two interfaces:

  - player.Engine: 30-method interface covering all Player methods the
    TUI uses. The Model now accepts player.Engine, enabling mock-based
    testing of the playback state machine.

  - model.ConfigSaver: single-method interface for config persistence.
    All 11 config.Save() calls in ui/model/ now go through
    m.configSaver, removing the direct filesystem dependency.
2026-04-02 20:47:24 +02:00
Bjarne Øverli 01fe7eb5c6 Update docs 2026-04-02 20:27:15 +02:00
Bjarne Øverli d89186f371 Fix lint issues 2026-04-02 20:25:56 +02:00
Bjarne Øverli 16c818696c Add Makefile, Navidrome tests, and project polish
- Makefile with build, test, vet, lint, check, clean, install targets
  - Navidrome client tests (22 tests covering API, caching, auth, scrobble)
  - install.sh: prefer ~/.local/bin, verify SHA256 checksums
  - README: link to cliamp.stream
  - docs/plugins.md: expand sandbox security docs
  - site: add robots.txt and sitemap.xml
2026-04-02 20:22:59 +02:00
Bjarne Øverli 24126eaf87 Add Makefile, Navidrome tests, and project polish
- Makefile with build, test, vet, lint, check, clean, install targets
  - Navidrome client tests (22 tests covering API, caching, auth, scrobble)
  - install.sh: prefer ~/.local/bin, verify SHA256 checksums
  - README: link to cliamp.stream
  - docs/plugins.md: expand sandbox security docs
  - site: add robots.txt and sitemap.xml
2026-04-02 20:21:55 +02:00
Bjarne Øverli 4f731c3ac7 Simplify tests 2026-04-02 19:49:41 +02:00
Bjarne Øverli 197e6d5d76 Add core tests 2026-04-02 19:43:44 +02:00
Bjarne Øverli 616e568e0e Update 2026-04-02 19:43:21 +02:00
Bjarne Øverli b132e2937d Add social and favicon 2026-04-02 19:38:12 +02:00
Bjarne Øverli 8d38a0c149 Remove the cliamp logo 2026-04-02 19:32:37 +02:00
Bjarne Øverli d490338891 Update the release workflow to add the author info
Release / build (amd64, darwin, macos-latest) (push) Has been cancelled
Release / build (amd64, linux, ubuntu-latest) (push) Has been cancelled
Release / build (amd64, windows, windows-latest) (push) Has been cancelled
Release / build (arm64, darwin, macos-latest) (push) Has been cancelled
Release / build (arm64, linux, ubuntu-latest) (push) Has been cancelled
Release / release (push) Has been cancelled
Release / update-homebrew (push) Has been cancelled
v1.32.4
2026-04-02 17:32:18 +02:00
Bjarne Øverli 06975e2248 Fix truncation
Release / build (amd64, darwin, macos-latest) (push) Has been cancelled
Release / build (amd64, linux, ubuntu-latest) (push) Has been cancelled
Release / build (amd64, windows, windows-latest) (push) Has been cancelled
Release / build (arm64, darwin, macos-latest) (push) Has been cancelled
Release / build (arm64, linux, ubuntu-latest) (push) Has been cancelled
Release / release (push) Has been cancelled
Release / update-homebrew (push) Has been cancelled
v1.32.3
2026-04-02 17:04:31 +02:00
Bjarne Øverli 434cbd8ca4 Move the album name after the song name to save one row
Release / build (amd64, darwin, macos-latest) (push) Has been cancelled
Release / build (amd64, linux, ubuntu-latest) (push) Has been cancelled
Release / build (amd64, windows, windows-latest) (push) Has been cancelled
Release / build (arm64, darwin, macos-latest) (push) Has been cancelled
Release / build (arm64, linux, ubuntu-latest) (push) Has been cancelled
Release / release (push) Has been cancelled
Release / update-homebrew (push) Has been cancelled
v1.32.2
2026-04-02 16:59:44 +02:00
Bjarne Øverli 743c57d885 Update the design of the site
Release / build (amd64, darwin, macos-latest) (push) Has been cancelled
Release / build (amd64, linux, ubuntu-latest) (push) Has been cancelled
Release / build (amd64, windows, windows-latest) (push) Has been cancelled
Release / build (arm64, darwin, macos-latest) (push) Has been cancelled
Release / build (arm64, linux, ubuntu-latest) (push) Has been cancelled
Release / release (push) Has been cancelled
Release / update-homebrew (push) Has been cancelled
v1.32.1
2026-04-02 16:54:13 +02:00
Bjarne Øverli a30a4704c1 Add ascii visualizer and remove glitch and lightning 2026-04-02 16:53:55 +02:00
Bjarne Øverli a10e2d4562 Fix the album UI 2026-04-02 16:45:10 +02:00
Bjarne Øverli 4a6104f996 Fix PanelWidth not restoring correctly when exiting full visualizer
Release / build (amd64, darwin, macos-latest) (push) Has been cancelled
Release / build (amd64, linux, ubuntu-latest) (push) Has been cancelled
Release / build (amd64, windows, windows-latest) (push) Has been cancelled
Release / build (arm64, darwin, macos-latest) (push) Has been cancelled
Release / build (arm64, linux, ubuntu-latest) (push) Has been cancelled
Release / release (push) Has been cancelled
Release / update-homebrew (push) Has been cancelled
ESC/backspace exit path never restored PanelWidth, leaving the layout
  at full terminal width. Shift+V exit path always capped at 80 columns
  regardless of compact mode. Extract restorePanelWidth() so all paths
  use the same compact-aware logic.
v1.32.0
2026-04-02 16:26:14 +02:00
Bjarne Øverli a3f9611189 Update webpage 2026-04-02 16:16:14 +02:00
Bjarne Øverli 9c076fb811 Add CLI remote control for shuffle, repeat, mono, speed, EQ, and audio device
Runtime control of playback settings that were previously only
  accessible via UI keybindings. All commands use the existing IPC
  Unix socket protocol.

  New commands:
    cliamp shuffle [on|off|toggle]
    cliamp repeat [off|all|one|cycle]
    cliamp mono [on|off|toggle]
    cliamp speed <ratio>
    cliamp eq <preset> / cliamp eq --band <0-9> <dB>
    cliamp device <name|list>

  Status response now includes shuffle, repeat, mono, speed, and EQ
  preset fields. Site and docs updated with new remote control section.
2026-04-02 16:12:57 +02:00
Bjarne Øverli f0518edf44 Update docs 2026-04-02 15:56:49 +02:00
Gjermund Garaba b6deffe92b chore(deps): bump to charm.land v2 dependencies (#161)
Co-authored-by: bjarneo <bjarneo@users.noreply.github.com>
2026-04-02 15:49:51 +02:00
bjarneo 32cb03c687 Pr 158 review (#160)
* feat: CLI playlist management, Unix socket IPC, and SSH streaming

Three features that make cliamp agent-native and scriptable:

1. `cliamp playlist {list,create,add,show,remove,delete}` — manage TOML
   playlists from the CLI with --json output and --ssh HOST for remote
   directory walking

2. Unix socket IPC at ~/.config/cliamp/cliamp.sock — play/pause/next/prev/
   stop/status/volume/seek/load/queue commands over JSON-RPC, following
   the MPRIS prog.Send() pattern

3. SSH streaming via ssh:// URL scheme — pipe audio from remote machines
   through the existing decoder pipeline, zero filesystem mounts needed

Zero new Go dependencies. All existing tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(ui): SSH track glyph + duration metadata fallback

- Show ↗ prefix on SSH-streamed tracks in the playlist view
- Store/read duration_secs in local TOML playlists
- Fall back to track metadata duration when player reports 0
  (piped SSH streams can't determine total length from audio frames)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: album separators, favorites, playlist resume, enrich command

- Album group separators in playlist view (triggers on album field change)
- Favorites system: * key toggles ★, [★ N] count in header, CLI `playlist favorite`
- [67/123] position counter in playlist header
- Playlist resume: saves and restores playlist + track + position across sessions
- `cliamp playlist enrich` probes duration via afinfo and derives album from path
- `ConnectTimeout=5` on all SSH commands to prevent stale hangs
- `SavePlaylist()` exported on local provider
- `*` added to keymap overlay and bottom help bar

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: persist TUI favorites to disk, fix truncation, add cross-playlist favorites view

- TUI * key now persists favorites to TOML via FavoriteSetter interface
- ★ prefix deducted from truncation budget (prevents line overflow)
- JSON output includes duration_secs and favorite fields
- `cliamp playlist favorites` lists all ★ tracks across all playlists
- FavoriteSetter interface in provider/interfaces.go
- Bottom help bar: [*]Fav (no extra ★ symbol)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: accent-color favorites, atomic TOML writes, strict --index parsing

Kotharat design review + silent failure audit fixes:
- ★ renders in accent color (yellow) independently from line style — scannable in long playlists
- savePlaylist uses atomic write (tmp + rename) — no data loss on crash
- --index parsing uses strconv.Atoi — rejects fractional/malformed input
- Bounds check on PlaylistFavorite re-read — no panic on concurrent modification
- Help bar priority 80 → 75 for [*]Fav — yields to navigation hints

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(ipc): remote theme switching via cliamp theme <name>

- `cliamp theme list` — list all available themes (built-in + custom)
- `cliamp theme <name>` — change theme in running TUI via IPC
- ThemeMsg with reply channel for error reporting ("theme not found")
- TUI handler reloads themes from disk before applying (picks up new custom themes)
- Added Name field to IPC Request for theme name

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(theme): clean up theme CLI UX from review findings

- `cliamp theme` (no args) prints usage cleanly instead of printing playback state
- `theme list` matching is case-insensitive (prevents routing confusion)
- Documented LoadAll() precedent in ThemeMsg handler (matches openThemePicker pattern)
- Updated CLAUDE.md and agent docs with theme commands

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: Blade Runner visualizers, theme-conditional UI chrome, IPC vis command

Two new visualizer modes inspired by the film's on-screen electronics:
- Esper: phosphor grid scan with CRT afterglow decay (4-level persistence)
- VoightKampff: concentric iris rings with bass-driven bellows indicator

Theme-conditional UI chrome (active when neon-blade-runner theme is set):
- Seek bar: ▰▱ blocks with ◆ thumb (Voight-Kampff analog meter)
- Album separators: ── ◈ ALBUM ◈ ── (LAPD terminal data headers)
- SSH track glyph: ◉ (replicant eye) instead of ↗
- Time format: T+MM:SS (mission elapsed time)
- Position counter: [SUBJ 003/123] (interrogation notation)
- Loading spinner: cycles ENHANCE / SCANNING / PROCESSING
- Title flicker: 2% chance per frame of 2-3 char CRT glitch cluster
- Track transition: 4-frame ░▒▓█ static burst

IPC visualizer command:
- cliamp vis <name>  — switch visualizer by name
- cliamp vis next    — cycle to next mode (same as v key)
- cliamp vis list    — list all modes with * active marker

Also adds neon-blade-runner-amber theme (1982 LAPD terminal amber phosphor).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Refactor PR: urfave/cli v3, consolidate duplications, fix SSH+ffmpeg bug

CLI framework:
- Replace hand-rolled flag parser with urfave/cli v3 command tree
- Move command definitions to commands.go, keep main.go focused on TUI startup
- Rename --volume/--theme flags to --vol/--start-theme to avoid subcommand collisions
- Hide unhelpful (default: 0) on int flags where 0 means auto/config

Code consolidation (cmd/playlist.go):
- Use player.SupportedExts instead of duplicate audioExtensions (adds 4 missing formats)
- Use resolve.CollectAudioFiles instead of duplicate walkDir
- Use playlist.TrackFromFilename instead of local copy (includes sanitizeTag)
- Add bulk AddTracks() to avoid N+1 file open/close per track
- Add provider.Exists() using os.Stat instead of parsing all TOML files
- Extract newProvider() and collectLocalAudio() helpers

Architecture fixes:
- Unify MPRIS/IPC message types via internal/control package with type aliases
- Remove ~30 lines of duplicated handler cases in update.go
- Add SSH+ffmpeg guard in pipeline.go (was silently passing ssh:// to ffmpeg)
- Create internal/sshurl for proper URL parsing with port support
- Replace macOS-only afinfo with cross-platform ffprobe for remote duration probing
- Add consistent StrictHostKeyChecking=yes to all SSH call sites
- Fix StrictHostKeyChecking docs to match code (yes, not accept-new)

IPC fixes:
- Remove TOCTOU os.Stat before DialTimeout in ipc/client.go
- Remove unnecessary 64KB scanner buffer in ipc/server.go
- Add nil-guards on msg.Reply for ThemeMsg and StatusRequestMsg
- Change ipcSend/overridesFromFlags to return errors instead of os.Exit

Removals:
- Remove CLAUDE.md
- Remove Esper and Voight-Kampff visualizers
- Remove neon-blade-runner theme-conditional chrome
- Delete hand-rolled ParseFlags and helpers from config/flags.go

* Remove review file

* Add Local provider pill, L keybinding, default radio startup

- Register Local as a provider pill tab (after Radio)
- Add L keybinding to switch to Local provider for browsing TOML playlists
- Load 3 cliamp radio streams directly on default startup (no async M3U)
- Skip playlist resume on default startup so radio streams aren't replaced
- Only allow position resume (SetResume) when CLI args given, never ResumePlaylist
- Update keybinding docs, keymap overlay, and site

---------

Co-authored-by: Tom di Mino <contact@tomdimino.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:46:17 +02:00