fix(ui): keep Bandcamp link across history refreshes
This commit is contained in:
1 parent
3ae4dc3dab
commit
d2b4f1bf64
2 files changed
+76
-1
No files matched your search
+19
-1
@@ -139,6 +139,7 @@ class SomaFMApp(App[None]):
|
|||||||
self.artwork_bytes: bytes | None = None
|
self.artwork_bytes: bytes | None = None
|
||||||
self._art_track_key = ""
|
self._art_track_key = ""
|
||||||
self._bandcamp_key = ""
|
self._bandcamp_key = ""
|
||||||
|
self._bandcamp_urls: dict[str, str] = {}
|
||||||
self._http: httpx.AsyncClient | None = None
|
self._http: httpx.AsyncClient | None = None
|
||||||
self._closed = False
|
self._closed = False
|
||||||
self._tick_timer = None
|
self._tick_timer = None
|
||||||
@@ -376,6 +377,10 @@ class SomaFMApp(App[None]):
|
|||||||
previous = station.now_playing
|
previous = station.now_playing
|
||||||
station.history = songs
|
station.history = songs
|
||||||
station.now_playing = songs[0]
|
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()
|
changed = previous is None or previous.key() != songs[0].key()
|
||||||
if self.current is not None and self.current.id == station_id:
|
if self.current is not None and self.current.id == station_id:
|
||||||
if changed:
|
if changed:
|
||||||
@@ -432,13 +437,24 @@ class SomaFMApp(App[None]):
|
|||||||
def _update_bandcamp(self) -> None:
|
def _update_bandcamp(self) -> None:
|
||||||
"""Find a Bandcamp track link once per now-playing track."""
|
"""Find a Bandcamp track link once per now-playing track."""
|
||||||
station = self.current
|
station = self.current
|
||||||
if station is None or self.offline or self._http is None:
|
if station is None:
|
||||||
return
|
return
|
||||||
song = station.now_playing
|
song = station.now_playing
|
||||||
if song is None or not (song.artist.strip() or song.title.strip()):
|
if song is None or not (song.artist.strip() or song.title.strip()):
|
||||||
return
|
return
|
||||||
|
|
||||||
track_key = f"{station.id}|{song.key()}"
|
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:
|
if track_key == self._bandcamp_key:
|
||||||
return
|
return
|
||||||
self._bandcamp_key = track_key
|
self._bandcamp_key = track_key
|
||||||
@@ -461,6 +477,7 @@ class SomaFMApp(App[None]):
|
|||||||
if not url:
|
if not url:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
self._bandcamp_urls[f"{station_id}|{song_key}"] = url
|
||||||
station = next((s for s in self.stations if s.id == station_id), None)
|
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:
|
if station is None or self.current is None or self.current.id != station_id:
|
||||||
return
|
return
|
||||||
@@ -822,6 +839,7 @@ class SomaFMApp(App[None]):
|
|||||||
def action_refresh(self) -> None:
|
def action_refresh(self) -> None:
|
||||||
self._last_history_fetch = 0.0
|
self._last_history_fetch = 0.0
|
||||||
self._bandcamp_key = ""
|
self._bandcamp_key = ""
|
||||||
|
self._bandcamp_urls.clear()
|
||||||
self._set_notice("refreshing…", 2)
|
self._set_notice("refreshing…", 2)
|
||||||
if self.offline:
|
if self.offline:
|
||||||
self._set_notice("offline mode — nothing to refresh", 3)
|
self._set_notice("offline mode — nothing to refresh", 3)
|
||||||
|
|||||||
@@ -159,6 +159,63 @@ async def test_stage_shows_bandcamp_link_only_when_present() -> None:
|
|||||||
assert "Bandcamp" not in rendered_text(app)
|
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
|
@pytest.mark.asyncio
|
||||||
async def test_media_session_commands_drive_the_app() -> None:
|
async def test_media_session_commands_drive_the_app() -> None:
|
||||||
app = SomaFMApp(autoplay=False, offline=True, audio=False)
|
app = SomaFMApp(autoplay=False, offline=True, audio=False)
|
||||||
|
|||||||
Reference in new issue
Block a user