frobar-ng: Fix mpris issues

This commit is contained in:
Geoffrey Frogeye 2025-01-10 17:08:43 +01:00
parent 9916cb0170
commit 24dd070bd9
Signed by: geoffrey
GPG key ID: C72403E7F82E6AD8

View file

@ -709,6 +709,39 @@ class MprisProvider(MirrorProvider):
"mpv": "",
}
async def run(self) -> None:
await super().run()
self.status = self.sectionType(parent=self.module, color=self.color)
self.album = self.sectionType(parent=self.module, color=self.color)
self.artist = self.sectionType(parent=self.module, color=self.color)
self.title = self.sectionType(parent=self.module, color=self.color)
self.manager = gi.repository.Playerctl.PlayerManager()
self.manager.connect("name-appeared", self.on_name_appeared)
self.manager.connect("player-vanished", self.on_player_vanished)
self.playerctldName = gi.repository.Playerctl.PlayerName()
self.playerctldName.name = "playerctld"
self.playerctldName.source = gi.repository.Playerctl.Source.DBUS_SESSION
self.player: gi.repository.Playerctl.Player | None = None
self.playing = asyncio.Event()
for name in self.manager.props.player_names:
self.init_player(name)
self.update_sections()
while True:
await self.playing.wait()
self.update_title()
if self.player:
pos = self.player.props.position
rem = 1 - (pos % 1000000) / 1000000
await asyncio.sleep(rem)
else:
self.playing.clear()
@staticmethod
def get(
something: gi.overrides.GLib.Variant, key: str, default: typing.Any = None
@ -725,13 +758,41 @@ class MprisProvider(MirrorProvider):
else:
return str(datetime.timedelta(microseconds=ms))
def show_player(self, player_: gi.repository.Playerctl.Player) -> None:
player = player_.props.player_name
def find_current_player(self) -> None:
for name in [self.playerctldName] + self.manager.props.player_names:
# TODO Test what happens when playerctld is not available
self.player = gi.repository.Playerctl.Player.new_from_name(name)
if not self.player.props.can_play:
continue
break
else:
self.player = None
def update_sections(self) -> None:
self.find_current_player()
if self.player is None:
self.status.setText(None)
self.album.setText(None)
self.artist.setText(None)
self.title.setText(None)
self.playing.clear()
return
player = self.player.props.player_name
player = self.PROVIDERS.get(player, player)
status = self.STATUSES.get(player_.props.playback_status, "?")
status = self.STATUSES.get(self.player.props.playback_status, "?")
self.status.setText(f"{player} {status}")
metadata = player_.props.metadata
if (
self.player.props.playback_status
== gi.repository.Playerctl.PlaybackStatus.PLAYING
):
self.playing.set()
else:
self.playing.clear()
metadata = self.player.props.metadata
album = self.get(metadata, "xesam:album")
if album:
@ -746,8 +807,14 @@ class MprisProvider(MirrorProvider):
else:
self.artist.setText(None)
pos = player_.props.position # In µs
# FIXME Doesn't increment during play
self.update_title()
def update_title(self) -> None:
if self.player is None:
return
metadata = self.player.props.metadata
pos = self.player.props.position # In µs
text = f"{self.format_us(pos)}"
dur = self.get(metadata, "mpris:length")
if dur:
@ -757,38 +824,12 @@ class MprisProvider(MirrorProvider):
text += f" {clip(title)}"
self.title.setText(text)
def show_players(
self, manager: gi.repository.Playerctl.PlayerManager, exclude: str | None = None
) -> None:
# FIXME Opening and closing a chromium player, it will stay there (as default),
# which is not the behaviour of playerctl somehow
for name in manager.props.player_names:
if name == exclude: # DEBUG
continue
player = gi.repository.Playerctl.Player.new_from_name(name)
self.show_player(player)
break
else:
self.status.setText(None)
self.album.setText(None)
self.artist.setText(None)
self.title.setText(None)
def on_player_appear(
self,
manager: gi.repository.Playerctl.PlayerManager,
player: gi.repository.Playerctl.Player,
) -> None:
log.debug(f"Player appeared: {player.props.player_name}")
self.show_player(player)
def on_player_vanished(
self,
manager: gi.repository.Playerctl.PlayerManager,
player: gi.repository.Playerctl.Player,
) -> None:
log.debug(f"Player vanished: {player.props.player_name}")
self.show_player(player)
self.update_sections()
def on_event(
self,
@ -796,54 +837,25 @@ class MprisProvider(MirrorProvider):
_: typing.Any,
manager: gi.repository.Playerctl.PlayerManager,
) -> None:
log.debug(f"Player evented: {player.props.player_name}")
self.show_player(player)
self.update_sections()
def init_player(
self, manager: gi.repository.Playerctl.PlayerManager, name: str
) -> None:
def init_player(self, name: gi.repository.Playerctl.PlayerName) -> None:
player = gi.repository.Playerctl.Player.new_from_name(name)
# All events will cause the active player to change,
# so we listen on all events, even if the display won't change
player.connect("playback-status", self.on_event, manager)
player.connect("loop-status", self.on_event, manager)
player.connect("shuffle", self.on_event, manager)
player.connect("metadata", self.on_event, manager)
player.connect("volume", self.on_event, manager)
player.connect("seeked", self.on_event, manager)
manager.manage_player(player)
player.connect("playback-status", self.on_event, self.manager)
player.connect("loop-status", self.on_event, self.manager)
player.connect("shuffle", self.on_event, self.manager)
player.connect("metadata", self.on_event, self.manager)
player.connect("volume", self.on_event, self.manager)
player.connect("seeked", self.on_event, self.manager)
self.manager.manage_player(player)
def on_name_appeared(
self, manager: gi.repository.Playerctl.PlayerManager, name: str
) -> None:
log.debug(f"Player name appeared: {name}")
self.init_player(manager, name)
def on_name_vanished(
self,
manager: gi.repository.Playerctl.PlayerManager,
name: str,
) -> None:
log.debug(f"Player name vanished: {name}")
self.show_players(manager, exclude=name)
async def run(self) -> None:
await super().run()
self.status = self.sectionType(parent=self.module, color=self.color)
self.album = self.sectionType(parent=self.module, color=self.color)
self.artist = self.sectionType(parent=self.module, color=self.color)
self.title = self.sectionType(parent=self.module, color=self.color)
manager = gi.repository.Playerctl.PlayerManager()
manager.connect("name-appeared", self.on_name_appeared)
manager.connect("player-appeared", self.on_player_appear)
manager.connect("name-vanished", self.on_name_vanished)
manager.connect("player-vanished", self.on_player_vanished)
for name in manager.props.player_names:
self.init_player(manager, name)
self.show_players(manager)
self.init_player(name)
self.update_sections()
class AlertingProvider(Provider):