frobar-ng: Fix mpris issues
This commit is contained in:
parent
9916cb0170
commit
24dd070bd9
|
@ -709,6 +709,39 @@ class MprisProvider(MirrorProvider):
|
||||||
"mpv": "",
|
"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
|
@staticmethod
|
||||||
def get(
|
def get(
|
||||||
something: gi.overrides.GLib.Variant, key: str, default: typing.Any = None
|
something: gi.overrides.GLib.Variant, key: str, default: typing.Any = None
|
||||||
|
@ -725,13 +758,41 @@ class MprisProvider(MirrorProvider):
|
||||||
else:
|
else:
|
||||||
return str(datetime.timedelta(microseconds=ms))
|
return str(datetime.timedelta(microseconds=ms))
|
||||||
|
|
||||||
def show_player(self, player_: gi.repository.Playerctl.Player) -> None:
|
def find_current_player(self) -> None:
|
||||||
player = player_.props.player_name
|
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)
|
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}")
|
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")
|
album = self.get(metadata, "xesam:album")
|
||||||
if album:
|
if album:
|
||||||
|
@ -746,8 +807,14 @@ class MprisProvider(MirrorProvider):
|
||||||
else:
|
else:
|
||||||
self.artist.setText(None)
|
self.artist.setText(None)
|
||||||
|
|
||||||
pos = player_.props.position # In µs
|
self.update_title()
|
||||||
# FIXME Doesn't increment during play
|
|
||||||
|
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)}"
|
text = f" {self.format_us(pos)}"
|
||||||
dur = self.get(metadata, "mpris:length")
|
dur = self.get(metadata, "mpris:length")
|
||||||
if dur:
|
if dur:
|
||||||
|
@ -757,38 +824,12 @@ class MprisProvider(MirrorProvider):
|
||||||
text += f" {clip(title)}"
|
text += f" {clip(title)}"
|
||||||
self.title.setText(text)
|
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(
|
def on_player_vanished(
|
||||||
self,
|
self,
|
||||||
manager: gi.repository.Playerctl.PlayerManager,
|
manager: gi.repository.Playerctl.PlayerManager,
|
||||||
player: gi.repository.Playerctl.Player,
|
player: gi.repository.Playerctl.Player,
|
||||||
) -> None:
|
) -> None:
|
||||||
log.debug(f"Player vanished: {player.props.player_name}")
|
self.update_sections()
|
||||||
self.show_player(player)
|
|
||||||
|
|
||||||
def on_event(
|
def on_event(
|
||||||
self,
|
self,
|
||||||
|
@ -796,54 +837,25 @@ class MprisProvider(MirrorProvider):
|
||||||
_: typing.Any,
|
_: typing.Any,
|
||||||
manager: gi.repository.Playerctl.PlayerManager,
|
manager: gi.repository.Playerctl.PlayerManager,
|
||||||
) -> None:
|
) -> None:
|
||||||
log.debug(f"Player evented: {player.props.player_name}")
|
self.update_sections()
|
||||||
self.show_player(player)
|
|
||||||
|
|
||||||
def init_player(
|
def init_player(self, name: gi.repository.Playerctl.PlayerName) -> None:
|
||||||
self, manager: gi.repository.Playerctl.PlayerManager, name: str
|
|
||||||
) -> None:
|
|
||||||
player = gi.repository.Playerctl.Player.new_from_name(name)
|
player = gi.repository.Playerctl.Player.new_from_name(name)
|
||||||
# All events will cause the active player to change,
|
# All events will cause the active player to change,
|
||||||
# so we listen on all events, even if the display won't change
|
# so we listen on all events, even if the display won't change
|
||||||
player.connect("playback-status", self.on_event, manager)
|
player.connect("playback-status", self.on_event, self.manager)
|
||||||
player.connect("loop-status", self.on_event, manager)
|
player.connect("loop-status", self.on_event, self.manager)
|
||||||
player.connect("shuffle", self.on_event, manager)
|
player.connect("shuffle", self.on_event, self.manager)
|
||||||
player.connect("metadata", self.on_event, manager)
|
player.connect("metadata", self.on_event, self.manager)
|
||||||
player.connect("volume", self.on_event, manager)
|
player.connect("volume", self.on_event, self.manager)
|
||||||
player.connect("seeked", self.on_event, manager)
|
player.connect("seeked", self.on_event, self.manager)
|
||||||
manager.manage_player(player)
|
self.manager.manage_player(player)
|
||||||
|
|
||||||
def on_name_appeared(
|
def on_name_appeared(
|
||||||
self, manager: gi.repository.Playerctl.PlayerManager, name: str
|
self, manager: gi.repository.Playerctl.PlayerManager, name: str
|
||||||
) -> None:
|
) -> None:
|
||||||
log.debug(f"Player name appeared: {name}")
|
self.init_player(name)
|
||||||
self.init_player(manager, name)
|
self.update_sections()
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
class AlertingProvider(Provider):
|
class AlertingProvider(Provider):
|
||||||
|
|
Loading…
Reference in a new issue