fix(ui): keep Bandcamp link across history refreshes

This commit is contained in:
beefcarver committed 2026-11-01 08:58:46 -05:00
1 parent 3ae4dc3dab
commit d2b4f1bf64
2 files changed
+76 -1

No files matched your search

+19 -1
View File
@@ -139,6 +139,7 @@ class SomaFMApp(App[None]):
self.artwork_bytes: bytes | None = None
self._art_track_key = ""
self._bandcamp_key = ""
self._bandcamp_urls: dict[str, str] = {}
self._http: httpx.AsyncClient | None = None
self._closed = False
self._tick_timer = None
@@ -376,6 +377,10 @@ class SomaFMApp(App[None]):
previous = station.now_playing
station.history = songs
station.now_playing = songs[0]
if previous is not None and previous.key() == songs[0].key():
# History refreshes replace the Song object even when the track has
# not changed. Keep the asynchronously discovered Bandcamp link.
songs[0].bandcamp_url = previous.bandcamp_url
changed = previous is None or previous.key() != songs[0].key()
if self.current is not None and self.current.id == station_id:
if changed:
@@ -432,13 +437,24 @@ class SomaFMApp(App[None]):
def _update_bandcamp(self) -> None:
"""Find a Bandcamp track link once per now-playing track."""
station = self.current
if station is None or self.offline or self._http is None:
if station is None:
return
song = station.now_playing
if song is None or not (song.artist.strip() or song.title.strip()):
return
track_key = f"{station.id}|{song.key()}"
cached_url = self._bandcamp_urls.get(track_key)
if cached_url:
self._bandcamp_key = track_key
if song.bandcamp_url != cached_url:
song.bandcamp_url = cached_url
with contextlib.suppress(NoMatches):
self.query_one(StagePanel).refresh_stage()
return
if self.offline or self._http is None:
return
if track_key == self._bandcamp_key:
return
self._bandcamp_key = track_key
@@ -461,6 +477,7 @@ class SomaFMApp(App[None]):
if not url:
return
self._bandcamp_urls[f"{station_id}|{song_key}"] = url
station = next((s for s in self.stations if s.id == station_id), None)
if station is None or self.current is None or self.current.id != station_id:
return
@@ -822,6 +839,7 @@ class SomaFMApp(App[None]):
def action_refresh(self) -> None:
self._last_history_fetch = 0.0
self._bandcamp_key = ""
self._bandcamp_urls.clear()
self._set_notice("refreshing…", 2)
if self.offline:
self._set_notice("offline mode — nothing to refresh", 3)
+57
View File
@@ -159,6 +159,63 @@ async def test_stage_shows_bandcamp_link_only_when_present() -> None:
assert "Bandcamp" not in rendered_text(app)
@pytest.mark.asyncio
async def test_bandcamp_link_survives_history_refresh(monkeypatch) -> None:
app = SomaFMApp(autoplay=False, offline=True, audio=False)
async with app.run_test(size=(110, 40)) as pilot:
await pilot.pause()
station = app.current
assert station is not None
url = "https://jensbuchert.bandcamp.com/track/rauschebart"
old_song = Song(
title="Rauschebart",
artist="Jens Buchert",
album="Gravity",
bandcamp_url=url,
)
station.now_playing = old_song
station.history = [old_song]
async def fake_fetch_history(client, station_id):
assert station_id == station.id
return [
Song(
title="Rauschebart",
artist="Jens Buchert",
album="Gravity",
)
]
monkeypatch.setattr("somafm_tui.app.api.fetch_history", fake_fetch_history)
worker = app._fetch_history(station.id)
await worker.wait()
await pilot.pause()
assert station.now_playing is not None
assert station.now_playing is not old_song
assert station.now_playing.bandcamp_url == url
assert "Bandcamp" in rendered_text(app)
@pytest.mark.asyncio
async def test_cached_bandcamp_link_is_reapplied_to_new_song() -> None:
app = SomaFMApp(autoplay=False, offline=True, audio=False)
async with app.run_test(size=(110, 40)) as pilot:
await pilot.pause()
station = app.current
assert station is not None
url = "https://jensbuchert.bandcamp.com/track/rauschebart"
song = Song(title="Rauschebart", artist="Jens Buchert", album="Gravity")
app._bandcamp_urls[f"{station.id}|{song.key()}"] = url
station.now_playing = song
app._update_bandcamp()
await pilot.pause()
assert song.bandcamp_url == url
assert "Bandcamp" in rendered_text(app)
@pytest.mark.asyncio
async def test_media_session_commands_drive_the_app() -> None:
app = SomaFMApp(autoplay=False, offline=True, audio=False)