diff --git a/beefy_player/widgets/stage.py b/beefy_player/widgets/stage.py index 2dd609f..1889ad0 100644 --- a/beefy_player/widgets/stage.py +++ b/beefy_player/widgets/stage.py @@ -140,11 +140,14 @@ class StageInfo(Widget): album = Text(no_wrap=True) if song.album: album.append(truncate(song.album, max(8, width - 22)), style="dim") - if station.dj: + presenter = station.presenter_label + if presenter: if song.album: album.append(" · ", style="dim") - album.append(f"dj {truncate(station.dj, 18)}", style="dim") - if song.art_url: + album.append(truncate(presenter, max(8, width - 22)), style="dim") + # The marker means "there is artwork", not "here is a lone box": + # without album or presenter there is nothing for it to mark. + if song.art_url and album.plain.strip(): album.append(" ▣", style="cyan") else: artist = Text("waiting for track data…", style="italic yellow") diff --git a/tests/test_presenter.py b/tests/test_presenter.py new file mode 100644 index 0000000..fd53a07 --- /dev/null +++ b/tests/test_presenter.py @@ -0,0 +1,115 @@ +"""The ON AIR metadata line: who is on the desk, and no lone artwork glyph.""" + +from __future__ import annotations + +import types + +import pytest + +from beefy_player.app import BeefyPlayerApp +from beefy_player.models import Song, Station +from beefy_player.providers.somafm import SomaFMProvider +from beefy_player.providers.tilderadio import TilderadioProvider, api +from beefy_player.widgets.stage import StageInfo + + +def details(station: Station, song: Song | None, width: int = 90) -> list[str]: + app = types.SimpleNamespace(playing_state="playing", notice="") + return [line.plain for line in StageInfo()._details(app, station, song, width)] + + +def test_somafm_still_prefixes_a_dj_name() -> None: + station = Station(id="gs", title="Groove Salad", dj="SomaFM", provider="somafm") + lines = details(station, Song(artist="A", title="T", album="Album")) + assert any("Album" in line and "dj SomaFM" in line for line in lines) + + +def test_lone_artwork_glyph_is_not_drawn() -> None: + """No album, no presenter: the ▣ would be a box with nothing to mark.""" + station = Station(id="x", title="X", provider="somafm") + lines = details(station, Song(artist="A", title="T", art_url="https://a/1.jpg")) + assert not any("▣" in line for line in lines) + + +def test_artwork_glyph_rides_along_with_real_information() -> None: + station = Station(id="x", title="X", dj="Someone", provider="somafm") + lines = details(station, Song(artist="A", title="T", art_url="https://a/1.jpg")) + assert any("dj Someone" in line and "▣" in line for line in lines) + + +def test_tilderadio_shows_the_rotation_when_nothing_is_live() -> None: + payload = { + "station": {"name": "tilderadio", "shortcode": "tilderadio"}, + "is_live": False, + } + station = api.station_from_now(payload) + assert station is not None + assert station.presenter_label == "auto dj · library rotation" + lines = details(station, Song(artist="A", title="T", art_url="https://a/1.jpg")) + assert any("auto dj · library rotation" in line for line in lines) + + +def test_tilderadio_shows_the_live_dj_instead() -> None: + payload = { + "station": {"name": "tilderadio", "shortcode": "tilderadio"}, + "is_live": True, + "dj": "dokuja", + } + station = api.station_from_now(payload) + assert station is not None + assert station.presenter_label == "dj dokuja" + assert "auto dj" not in station.presenter_label + + +def test_presenter_label_falls_back_to_the_dj_then_nothing() -> None: + assert Station(id="a", title="A").presenter_label == "" + assert Station(id="a", title="A", dj="kexp").presenter_label == "dj kexp" + assert ( + Station(id="a", title="A", dj="kexp", presenter="guest host").presenter_label + == "guest host" + ) + + +def test_tilderadio_opts_out_of_bandcamp_lookups() -> None: + assert TilderadioProvider().bandcamp is False + assert SomaFMProvider().bandcamp is True + + +@pytest.mark.asyncio +async def test_no_bandcamp_worker_is_started_for_tilderadio(monkeypatch) -> None: + calls: list[tuple] = [] + + async def fake_find(client, artist, album, title): + calls.append((artist, album, title)) + return "https://bandcamp.test/track" + + monkeypatch.setattr("beefy_player.bandcamp.find_track", fake_find) + + app = BeefyPlayerApp( + provider="tilderadio", autoplay=False, offline=True, audio=False + ) + async with app.run_test(size=(100, 40)) as pilot: + await pilot.pause() + station = app.current + assert station is not None + station.now_playing = Song(artist="A", title="T") + app._update_bandcamp() + await pilot.pause() + assert calls == [] + assert station.now_playing.bandcamp_url == "" + + +@pytest.mark.asyncio +async def test_a_stale_bandcamp_link_is_cleared_when_the_catalogue_does_not_want_one() -> None: + app = BeefyPlayerApp( + provider="tilderadio", autoplay=False, offline=True, audio=False + ) + async with app.run_test(size=(100, 40)) as pilot: + await pilot.pause() + station = app.current + assert station is not None + station.now_playing = Song( + artist="A", title="T", bandcamp_url="https://bandcamp.test/old" + ) + app._update_bandcamp() + assert station.now_playing.bandcamp_url == ""