feat(palette): sixteen ANSI colour ladders, cycled with c

This commit is contained in:
beefcarver committed 2026-11-04 08:55:51 -05:00
1 parent 253b462df1
commit 43ddd8666b
14 files changed
+622 -111

No files matched your search

+32 -1
View File
@@ -26,10 +26,12 @@ from textual.widgets import Input
from . import artwork, bandcamp, config
from .mediasession import create_media_session, media_actions_queue
from .models import Broadcast, Station, parse_last_playing
from .palettes import PALETTE_ORDER
from .player import Player
from .providers import get_provider
from .providers.base import is_direct_stream, make_client
from .spectrum import SpectrumEngine
from .widgets.art import ArtPane
from .widgets.header import HeaderBar
from .widgets.help import HelpScreen
from .widgets.providers import ProviderScreen
@@ -92,6 +94,7 @@ class BeefyPlayerApp(App[None]):
Binding("slash", "search", "filter"),
Binding("escape", "escape", "close", show=False),
Binding("v", "visualizer", "visualiser"),
Binding("c", "palette", "palette"),
Binding("r", "refresh", "refresh"),
Binding("p", "provider", "catalogue"),
Binding("question_mark", "help", "help"),
@@ -147,6 +150,8 @@ class BeefyPlayerApp(App[None]):
self.playing_state = "stopped"
self.volume = self.config.volume
self.visualizer = self.config.visualizer
#: Colour palette name (see :mod:`beefy_player.palettes`).
self.palette = self.config.palette
self.tick_count = 0
self.notice = ""
@@ -956,6 +961,20 @@ class BeefyPlayerApp(App[None]):
self._set_notice(f"visualiser: {self.visualizer}", 2)
self.query_one(SpectrumPanel).refresh()
def action_palette(self) -> None:
order = list(PALETTE_ORDER)
index = order.index(self.palette) if self.palette in order else 0
self.palette = order[(index + 1) % len(order)]
self.config.palette = self.palette
self._save_config()
self._set_notice(f"palette: {self.palette}", 2)
# Frames, spectrum, mosaic and wordmarks all read the palette live, so
# a repaint of every widget is all it takes. (``self.query`` is the
# station filter here, hence ``self.screen.query``.)
for widget in self.screen.query("*"):
with contextlib.suppress(Exception):
widget.refresh()
def action_refresh(self) -> None:
self._last_history_fetch = 0.0
self._bandcamp_key = ""
@@ -972,12 +991,23 @@ class BeefyPlayerApp(App[None]):
self._fetch_history(self.current.id)
def action_provider(self) -> None:
self._suspend_artwork()
self.push_screen(ProviderScreen(self.provider.id), self._provider_chosen)
def _provider_chosen(self, provider_id: str | None) -> None:
self._resume_artwork()
if provider_id:
self._switch_catalogue(provider_id)
def _suspend_artwork(self) -> None:
"""Hide the inline artwork: terminal images would sit over a menu."""
with contextlib.suppress(NoMatches):
self.query_one(ArtPane).suspend()
def _resume_artwork(self) -> None:
with contextlib.suppress(NoMatches):
self.query_one(ArtPane).resume()
def _cancel_workers(self) -> None:
for group in ("stream", "history", "stations", "schedule", "bandcamp", "artwork"):
with contextlib.suppress(Exception):
@@ -1051,7 +1081,8 @@ class BeefyPlayerApp(App[None]):
self._refresh_schedule()
def action_help(self) -> None:
self.push_screen(HelpScreen())
self._suspend_artwork()
self.push_screen(HelpScreen(), lambda _result: self._resume_artwork())
def action_quit(self) -> None:
self._cleanup()