/ linamp / widgets / track_info.py
track_info.py
 1  from textual.containers import Container
 2  from textual.app import ComposeResult
 3  from textual.widgets import Static
 4  
 5  from linamp.messages import PlayerStateUpdate
 6  
 7  
 8  class TrackInfo(Container):
 9      """Displays the currently playing track between controls and playlist.
10  
11      Priority: ICY stream title (artist - track) > media title > station name.
12      """
13  
14      DEFAULT_CSS = """
15      TrackInfo {
16          height: 4;
17          border: round #585b70;
18          padding: 0 1;
19      }
20      TrackInfo .track-label {
21          color: #585b70;
22          height: 1;
23      }
24      TrackInfo .track-title {
25          color: #f9e2af;
26          text-style: bold;
27          height: 1;
28      }
29      """
30  
31      def compose(self) -> ComposeResult:
32          yield Static("NOW PLAYING", classes="track-label", id="track-label")
33          yield Static("", classes="track-title", id="track-title")
34  
35      def _best_title(self, event: PlayerStateUpdate) -> str:
36          """Pick the best available title for the current track."""
37          # ICY title is the gold standard — real-time artist/track from the stream
38          if event.icy_title:
39              return event.icy_title
40          # media_title is mpv's synthesized title (may come from ytdl or stream)
41          # Only use it if it differs from the station name (otherwise it's redundant)
42          if event.media_title and event.station and event.media_title != event.station.name:
43              return event.media_title
44          # Fall back to station name
45          if event.station:
46              return event.station.name
47          return ""
48  
49      def on_player_state_update(self, event: PlayerStateUpdate) -> None:
50          label = self.query_one("#track-label", Static)
51          title = self.query_one("#track-title", Static)
52  
53          if event.is_playing:
54              label.update("NOW PLAYING")
55              title.update(self._best_title(event))
56          elif event.is_paused:
57              label.update("PAUSED")
58              title.update(self._best_title(event))
59          else:
60              label.update("NOW PLAYING")
61              title.update("")