feat: subscribe to all players

This commit is contained in:
2026-05-05 23:58:15 +02:00
parent cc3bac5ce7
commit 4adace6c4c

View File

@@ -1,3 +1,4 @@
import contextlib
import os import os
import urllib.parse import urllib.parse
import urllib.request import urllib.request
@@ -624,13 +625,13 @@ class PlayerSmall(Box):
self.mpris_manager = MprisPlayerManager() self.mpris_manager = MprisPlayerManager()
self.mpris_player = None self.mpris_player = None
self.current_index = 0 self._players = {}
self._player_handlers = {}
self._last_status = {}
players = self.mpris_manager.players for p in self.mpris_manager.players:
if players: self._track_player(p)
mp = MprisPlayer(players[self.current_index]) self._select_initial_player()
self.mpris_player = mp
self.mpris_player.connect("changed", self._on_mpris_changed)
self._apply_mpris_properties() self._apply_mpris_properties()
self.mpris_manager.connect("player-appeared", self.on_player_appeared) self.mpris_manager.connect("player-appeared", self.on_player_appeared)
@@ -805,25 +806,28 @@ class PlayerSmall(Box):
def _on_icon_button_press(self, widget, event): def _on_icon_button_press(self, widget, event):
if event.type != Gdk.EventType.BUTTON_PRESS: if event.type != Gdk.EventType.BUTTON_PRESS:
return True return True
players = self.mpris_manager.players
if not players:
return True
if event.button == 2: if event.button == 2:
if not self.mpris_player:
return True
self._display_index = (self._display_index + 1) % len(self._display_options) self._display_index = (self._display_index + 1) % len(self._display_options)
self._current_display = self._display_options[self._display_index] self._current_display = self._display_options[self._display_index]
self._apply_mpris_properties() self._apply_mpris_properties()
return True return True
players = list(self._players.values())
if not players:
return True
idx = players.index(self.mpris_player) if self.mpris_player in players else -1
if event.button == 1: if event.button == 1:
self.current_index = (self.current_index + 1) % len(players) idx = (idx + 1) % len(players)
elif event.button == 3: elif event.button == 3:
self.current_index = (self.current_index - 1) % len(players) idx = (idx - 1) % len(players)
else: else:
return True return True
self.mpris_player = MprisPlayer(players[self.current_index]) self.mpris_player = players[idx]
self.mpris_player.connect("changed", self._on_mpris_changed)
self._apply_mpris_properties() self._apply_mpris_properties()
return True return True
@@ -857,24 +861,71 @@ class PlayerSmall(Box):
) )
self._update_spin() self._update_spin()
def _on_mpris_changed(self, *args): def _track_player(self, playerctl_player):
mp = MprisPlayer(playerctl_player)
name = mp.player_name
handler_id = mp.connect("changed", self._on_any_player_changed)
self._players[name] = mp
self._player_handlers[name] = handler_id
self._last_status[name] = mp.playback_status
def _untrack_player(self, name):
mp = self._players.pop(name, None)
handler_id = self._player_handlers.pop(name, None)
self._last_status.pop(name, None)
if mp and handler_id is not None:
with contextlib.suppress(Exception):
mp.disconnect(handler_id)
def _select_initial_player(self):
for mp in self._players.values():
if mp.playback_status == "playing":
self.mpris_player = mp
return
if self._players:
self.mpris_player = next(iter(self._players.values()))
def _on_any_player_changed(self, player):
name = player.player_name
prev_status = self._last_status.get(name)
cur_status = player.playback_status
self._last_status[name] = cur_status
if player is self.mpris_player:
self._apply_mpris_properties()
return
# Auto-follow: only on a fresh transition into "playing", and only
# if the active player isn't already playing (so a manual selection
# of a paused player isn't overridden by the player it was already
# competing with).
if cur_status == "playing" and prev_status != "playing":
active_playing = (
self.mpris_player
and self.mpris_player.playback_status == "playing"
)
if not active_playing:
self.mpris_player = player
self._apply_mpris_properties() self._apply_mpris_properties()
def on_player_appeared(self, manager, player): def on_player_appeared(self, manager, player):
self._track_player(player)
if not self.mpris_player: if not self.mpris_player:
self.mpris_player = MprisPlayer(player) name = player.get_property("player-name")
self.mpris_player.connect("changed", self._on_mpris_changed) self.mpris_player = self._players.get(name)
self._apply_mpris_properties() self._apply_mpris_properties()
def on_player_vanished(self, manager, player_name): def on_player_vanished(self, manager, player_name):
players = self.mpris_manager.players was_active = (
if self.mpris_player and self.mpris_player.player_name == player_name: self.mpris_player and self.mpris_player.player_name == player_name
if players: )
self.current_index = self.current_index % len(players) self._untrack_player(player_name)
self.mpris_player = MprisPlayer(players[self.current_index]) if was_active:
self.mpris_player.connect("changed", self._on_mpris_changed) replacement = next(
else: (mp for mp in self._players.values() if mp.playback_status == "playing"),
self.mpris_player = None None,
elif not players: )
self.mpris_player = None if replacement is None and self._players:
replacement = next(iter(self._players.values()))
self.mpris_player = replacement
self._apply_mpris_properties() self._apply_mpris_properties()