Add panel script for media player status via mpris
This commit is contained in:
parent
55c60257c1
commit
382884f420
101
.config/xfce4/panel/scripts/mpris-status.py
Executable file
101
.config/xfce4/panel/scripts/mpris-status.py
Executable file
@ -0,0 +1,101 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from textwrap import shorten
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from dbus.exceptions import DBusException
|
||||||
|
from mpris2 import Player, get_players_uri
|
||||||
|
from mpris2.types import Metadata_Map
|
||||||
|
from mpris2.utils import get_player_id_from_uri
|
||||||
|
|
||||||
|
MAX_OUTPUT = 80
|
||||||
|
|
||||||
|
|
||||||
|
class MagicMetadata:
|
||||||
|
_metadata: Metadata_Map
|
||||||
|
|
||||||
|
def __init__(self, metadata: Metadata_Map):
|
||||||
|
self._metadata = metadata
|
||||||
|
|
||||||
|
def __getattr__(self, attr: str):
|
||||||
|
"""lookup attributes via pre-defined constants in Metadata_Map"""
|
||||||
|
return self._metadata.get(getattr(self._metadata, attr.upper()))
|
||||||
|
|
||||||
|
|
||||||
|
def format_duration(duration: Optional[int]):
|
||||||
|
if duration is None:
|
||||||
|
return "?"
|
||||||
|
|
||||||
|
hours, rem = divmod(duration // 1000 // 1000, 3600)
|
||||||
|
minutes, seconds = divmod(rem, 60)
|
||||||
|
if hours:
|
||||||
|
return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
|
||||||
|
else:
|
||||||
|
return f"{minutes:02d}:{seconds:02d}"
|
||||||
|
|
||||||
|
|
||||||
|
def format_player(player: Player, short: bool = False) -> str:
|
||||||
|
metadata = MagicMetadata(player.Metadata)
|
||||||
|
try:
|
||||||
|
position = player.Position.real
|
||||||
|
except DBusException:
|
||||||
|
position = None
|
||||||
|
|
||||||
|
if position is None and metadata.length is None:
|
||||||
|
position_and_length = ""
|
||||||
|
else:
|
||||||
|
position_and_length = f" <tt>{format_duration(position) }/{ format_duration(metadata.length) }</tt>"
|
||||||
|
|
||||||
|
if short:
|
||||||
|
status = ""
|
||||||
|
else:
|
||||||
|
status = {
|
||||||
|
"Playing": "▶",
|
||||||
|
"Paused": "⏸️",
|
||||||
|
"Stopped": "⏹️",
|
||||||
|
}.get(player.PlaybackStatus, "❓") + " "
|
||||||
|
|
||||||
|
artist = ",".join(metadata.artist)
|
||||||
|
album = metadata.album
|
||||||
|
title = metadata.title
|
||||||
|
if short:
|
||||||
|
# TODO: could be a bit more clever here to use the whole space
|
||||||
|
artist = shorten(artist, 40, placeholder="…")
|
||||||
|
album = shorten(album, 40, placeholder="…")
|
||||||
|
title = shorten(title, 60, placeholder="…")
|
||||||
|
|
||||||
|
if album:
|
||||||
|
album = f" / <i>{ album }</i>"
|
||||||
|
|
||||||
|
return f"{status}{ artist }{ album } | { title }{ position_and_length }"
|
||||||
|
|
||||||
|
|
||||||
|
def status_key(player: Player) -> int:
|
||||||
|
return {
|
||||||
|
"Playing": 0,
|
||||||
|
"Paused": 1,
|
||||||
|
"Stopped": 2,
|
||||||
|
}.get(player.PlaybackStatus, 100)
|
||||||
|
|
||||||
|
|
||||||
|
def status_icon(player: Player) -> str:
|
||||||
|
return {
|
||||||
|
"Playing": "exaile-play",
|
||||||
|
"Paused": "exaile-pause",
|
||||||
|
"Stopped": "media-player-banshee-stopped",
|
||||||
|
}.get(player.PlaybackStatus, "unknown")
|
||||||
|
|
||||||
|
|
||||||
|
players = [Player(dbus_interface_info={"dbus_uri": uri}) for uri in get_players_uri()]
|
||||||
|
|
||||||
|
players.sort(key=status_key)
|
||||||
|
active_player_id = get_player_id_from_uri(players[0]._dbus_interface_info.uri)
|
||||||
|
print(
|
||||||
|
"<txt>"
|
||||||
|
+ (f"[{ len(players) }] " if len(players) > 1 else "")
|
||||||
|
+ format_player(players[0], short=True)
|
||||||
|
+ "</txt>"
|
||||||
|
)
|
||||||
|
print(f"<txtclick>playerctl --player={ active_player_id } play-pause</txtclick>")
|
||||||
|
print(f"<icon>{ status_icon(players[0]) }</icon>")
|
||||||
|
print("<tool>" + "\n".join(format_player(player) for player in players) + "</tool>")
|
Loading…
Reference in New Issue
Block a user