Commit Graph
17 Commits
Author SHA1 Message Date
beefcarver 6eb0c6b6fe fix(artwork): ignore TMUX/ZELLIJ/STY values that mean 'not set'
Some shells and wrappers export ZELLIJ=0 or TMUX=0 outside a multiplexer.
A plain truthiness check treated that as 'inside tmux/zellij' and
downgraded iTerm2/Kitty to the ANSI mosaic, so real artwork silently
disappeared. Only meaningful values now count.
2026-10-30 18:43:16 -04:00
beefcarver 69b46b9035 feat(spectrum): capture macOS output with an avfoundation loopback
SYNC mode was Linux-only: it shelled out to parec. On macOS there is no
PulseAudio, so the analyser always fell back to the drifting stream tap.

Capture with 'ffmpeg -f avfoundation' from a loopback input instead
(BlackHole, Loopback, Soundflower, Multi-Output/Aggregate devices are
auto-detected; SOMAFM_SPECTRUM_DEVICE accepts a name or index). Plain
microphones are never auto-selected.

A loopback that nothing is routed into delivers endless digital silence,
so treat ~6 s of all-zero blocks as a dead monitor and fall back to the
stream tap rather than showing frozen bars. parec handling is unchanged.
2026-10-30 18:43:10 -04:00
beefcarver 9c722c5f61 feat(macos): drive the system Now Playing session through mpv
macOS has no D-Bus/MPRIS: the audio engine is what the OS media UI talks
to. mpv's Cocoa backend registers with MPRemoteCommandCenter and
MPNowPlayingInfoCenter, so it already publishes the live ICY title and
receives the media keys.

Add a platform-neutral media session (mediasession.py) so the app keeps a
single interface: MprisService on D-Bus platforms, NowPlayingSession on
macOS. Map mpv's NEXT/PREV/PLAY/PLAYONLY/PAUSEONLY/STOP keys onto
script-messages and read them back as client-message IPC events, so the
hardware media keys and Control Center drive the TUI (station changes,
play/pause/stop) instead of fighting it.

--no-mpris (now also --no-media) disables the media keys too. macOS-only
mpv options are gated on sys.platform so the Linux command line is
unchanged; mpv aborts on unknown flags.
2026-10-30 18:43:03 -04:00
beefcarver d83a9ef03d fix(mpris): keep the service importable without dbus-next
The stub dbus_property() returned a bare function, so the read/write
properties (@Volume.setter and friends) raised AttributeError at import
time. That made any host without dbus-next -- macOS, Windows, minimal
containers -- crash before the TUI could start, because app.py imports
this module unconditionally.

Replace the stub with a descriptor that supports .getter()/.setter(), and
give the service a short label for the status bar.
2026-10-30 18:42:50 -04:00
beefcarver 876057bf68 docs(readme): show demo gif without asciinema link 2026-10-30 15:27:26 +00:00
beefcarver 8393432f97 docs(readme): document Bandcamp track links 2026-10-30 15:12:37 +00:00
beefcarver 66729c7542 feat(stage): show Bandcamp link in ON AIR 2026-10-30 15:12:37 +00:00
beefcarver 8e1c0a64eb feat(bandcamp): add Bandcamp track lookup 2026-10-30 15:12:36 +00:00
beefcarver b2eab64d12 docs(readme): use autoplaying demo gif 2026-10-30 04:45:44 +00:00
beefcarver 5ca93e60fb docs(readme): add asciicast demo near top 2026-10-30 04:40:12 +00:00
beefcarver 662fdf69f4 test(header): cover flush-right clock, date and volume block 2026-10-30 04:31:52 +00:00
beefcarver 59fc4dd7fd fix(header): right-align clock, date and volume in the top bar 2026-10-30 04:31:51 +00:00
beefcarver 44cc36a470 docs(readme): document distro install path and demote NixOS to optional aside 2026-10-30 04:24:53 +00:00
beefcarver 3866f0277c docs(readme): document installation, keybindings and features 2026-10-30 04:17:55 +00:00
beefcarver 8eb22ea52c test: add test suite for player, api and widgets 2026-10-30 04:17:54 +00:00
beefcarver 237de2efe9 feat(tui): implement SomaFM terminal radio player 2026-10-30 04:17:53 +00:00
beefcarver 941e45a20f chore(project): add repository scaffolding and build config 2026-10-30 04:17:48 +00:00