feat(catalogue): tune a single-station catalogue on switch

This commit is contained in:
beefcarver committed 2026-11-03 20:31:18 -05:00
1 parent 0219df454c
commit 5eb60d378c
3 files changed
+78 -1

No files matched your search

+3 -1
View File
@@ -67,7 +67,9 @@ implemented here from public endpoints and open protocols.
- **Favourites** that float to the top, remembered between runs. - **Favourites** that float to the top, remembered between runs.
- **Pluggable catalogues** — one `providers` module per radio network, with a - **Pluggable catalogues** — one `providers` module per radio network, with a
`p` picker in the UI, `--provider` on the command line, and the choice `p` picker in the UI, `--provider` on the command line, and the choice
remembered per catalogue (including the last station you tuned). remembered per catalogue (including the last station you tuned). Switching to
a single-station catalogue tunes it straight away; a multi-station one waits
for `enter`.
- **A hero per catalogue** — the top-left art is the catalogue's own name in a - **A hero per catalogue** — the top-left art is the catalogue's own name in a
shared half-block font: SomaFM in the spectrum gradient, tilderadio in the shared half-block font: SomaFM in the spectrum gradient, tilderadio in the
terminal's default colour, Bassdrive in its two blues. Every hero is three terminal's default colour, Bassdrive in its two blues. Every hero is three
+6
View File
@@ -1035,6 +1035,12 @@ class BeefyPlayerApp(App[None]):
self.query_one(HeaderBar).refresh() self.query_one(HeaderBar).refresh()
self.query_one(StagePanel).refresh_stage() self.query_one(StagePanel).refresh_stage()
self.query_one(StatusBar).refresh() self.query_one(StatusBar).refresh()
if self.audio_enabled and len(stations) == 1 and self.current is not None:
# A catalogue with one station has nothing to choose between:
# switching to it is the same as tuning it.
self._tune(self.current)
else:
self._set_notice(f"catalogue: {provider.name}", 3) self._set_notice(f"catalogue: {provider.name}", 3)
if not self.offline: if not self.offline:
+69
View File
@@ -257,3 +257,72 @@ async def test_every_catalogue_header_is_the_same_height() -> None:
assert header.styles.height.value == 4, slug assert header.styles.height.value == 4, slug
lines = [line.plain for line in header.render().renderables] lines = [line.plain for line in header.render().renderables]
assert any("STOPPED" in line or "PLAYING" in line for line in lines), slug assert any("STOPPED" in line or "PLAYING" in line for line in lines), slug
class _StubPlayer:
"""Just enough Player for a tune: records what mpv would have played."""
def __init__(self) -> None:
import queue
self.events: queue.Queue = queue.Queue()
self.played: list[list[str]] = []
self.volume: int | None = None
self.backend: str | None = None
def play(self, urls) -> None:
self.played.append(list(urls))
def set_volume(self, value: int) -> None:
self.volume = value
def stop(self) -> None:
pass
def toggle_pause(self) -> None:
pass
async def _switch_to(app, pilot, slug: str) -> None:
slugs = available_providers()
steps = (slugs.index(slug) - slugs.index(app.provider.id)) % len(slugs)
await pilot.press("p")
await pilot.pause()
for _ in range(steps):
await pilot.press("down")
await pilot.press("enter")
await pilot.pause()
await pilot.pause()
@pytest.mark.asyncio
async def test_switching_to_a_single_station_catalogue_tunes_it() -> None:
app = _CatalogueApp("somafm").app
async with app.run_test(size=(110, 40)) as pilot:
await pilot.pause()
stub = _StubPlayer()
app.player = stub
app.audio_enabled = True
await _switch_to(app, pilot, "tilderadio")
assert app.provider.id == "tilderadio"
assert app.current is not None and app.current.id == "tilderadio"
assert stub.played, "a one-station catalogue should start playing"
assert app.playing_state != "stopped"
@pytest.mark.asyncio
async def test_switching_to_a_multi_station_catalogue_waits_for_enter() -> None:
app = _CatalogueApp("tilderadio").app
async with app.run_test(size=(110, 40)) as pilot:
await pilot.pause()
stub = _StubPlayer()
app.player = stub
app.audio_enabled = True
await _switch_to(app, pilot, "somafm")
assert app.provider.id == "somafm"
assert len(app.stations) > 1
assert stub.played == [], "multi-station catalogues wait for enter"