from PyQt6.QtCore import QObject, QTimer, pyqtSlot as Slot from PyQt6.QtDBus import QDBusConnection, QDBusInterface, QDBusMessage, QDBusVariant, QDBusReply class MPRISMonitor(QObject): def __init__(self): super().__init__() self.updateTimer: QTimer = QTimer() self.updateTimer.timeout.connect(self.updatePosition) self.session = QDBusConnection.sessionBus() self.playerList: list[str] = self.getPlayers() self.playerInterface: QDBusInterface | None = None self.connectedService: str = "" if len(self.playerList) > 0: self.playerInterface = MPRISMonitor.getPlayerInterface(self.playerList[0]) self.session.connect( self.connectedService, "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "PropertiesChanged", self.handlePropertiesChanged ) self.metadata: dict = {} self.state: str = "" self.position: int = 0 self.updateTimer.start(5000) def getPlayers(self) -> list[str]: """Return a list of all active MPRIS player service names.""" reply = self.session.interface().registeredServiceNames() mediaPlayers: list[str] = [] for s in str(reply.value()).split("\', \'"): if s.startswith("org.mpris.MediaPlayer2."): mediaPlayers.append(s) return mediaPlayers @staticmethod def getPlayerInterface(serviceName: str): """Get a DBus interface for a given player.""" return QDBusInterface( serviceName, "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", QDBusConnection.sessionBus() ) def getMetadata(self): msg: QDBusMessage = self.playerInterface.call("Get", "org.mpris.MediaPlayer2.Player", "Metadata") if msg.arguments(): self.metadata = msg.arguments()[0].variant() return self.metadata def getState(self): msg = self.playerInterface.call("Get", "org.mpris.MediaPlayer2.Player", "PlaybackStatus") if msg.arguments(): return msg.arguments()[0].variant() return None def getPosition(self): if self.playerInterface is None: return 0 msg = self.playerInterface.call("Get", "org.mpris.MediaPlayer2.Player", "Position") if type(msg.arguments()[0]) is int: return msg.arguments()[0] / 1000000 # µs → s print(type(msg.arguments())) return 0 @Slot(QDBusMessage) def handlePropertiesChanged(self, msg: QDBusMessage): args = msg.arguments() if len(args) < 2: return changed = args[1] # dict of changed properties if not isinstance(changed, dict): return if "Metadata" in changed: cMetadata = changed["Metadata"] if cMetadata != self.metadata: self.metadata = cMetadata if "PlaybackStatus" in changed: cState = changed["PlaybackStatus"] if cState != self.state: print(f"▶️ Playback state: {cState}") self.state = cState print("Change detected! TBI") def updatePosition(self): pos = self.getPosition() if abs(pos - self.position) > 2: print(f"⏱️ Position: {pos:.1f}s") self.position = pos