133 lines
5.0 KiB
Python
133 lines
5.0 KiB
Python
# Copyright 2022 (c) Anna Schumaker.
|
|
"""Our Mpris2 Player dbus Object."""
|
|
import pathlib
|
|
from gi.repository import GObject
|
|
from gi.repository import GLib
|
|
from .. import path
|
|
from . import dbus
|
|
|
|
PLAYER_XML = pathlib.Path(__file__).parent / "Player.xml"
|
|
OBJECT_PATH = "/com/nowheycreamery/emmental"
|
|
|
|
|
|
class Player(dbus.Object):
|
|
"""The mpris2 Player dbus object."""
|
|
|
|
PlaybackStatus = GObject.Property(type=str, default="Stopped")
|
|
LoopStatus = GObject.Property(type=str, default="None")
|
|
Rate = GObject.Property(type=float, default=1.0)
|
|
Shuffle = GObject.Property(type=bool, default=False)
|
|
Volume = GObject.Property(type=float, default=1.0)
|
|
Position = GObject.Property(type=float, default=0)
|
|
MinimumRate = GObject.Property(type=float, default=1.0)
|
|
MaximumRate = GObject.Property(type=float, default=1.0)
|
|
CanGoNext = GObject.Property(type=bool, default=False)
|
|
CanGoPrevious = GObject.Property(type=bool, default=False)
|
|
CanPlay = GObject.Property(type=bool, default=False)
|
|
CanPause = GObject.Property(type=bool, default=False)
|
|
CanSeek = GObject.Property(type=bool, default=False)
|
|
CanControl = GObject.Property(type=bool, default=True)
|
|
|
|
artist = GObject.Property(type=str)
|
|
album = GObject.Property(type=str)
|
|
album_artist = GObject.Property(type=str)
|
|
album_disc_number = GObject.Property(type=int)
|
|
title = GObject.Property(type=str)
|
|
track_number = GObject.Property(type=int)
|
|
duration = GObject.Property(type=float)
|
|
trackid = GObject.Property(type=int)
|
|
|
|
file = GObject.Property(type=GObject.TYPE_PYOBJECT)
|
|
|
|
def __init__(self):
|
|
"""Initialize the mpris2 application object."""
|
|
super().__init__(xml=PLAYER_XML)
|
|
|
|
def do_notify(self, property: str) -> None:
|
|
"""Notify DBus when tags change."""
|
|
match property:
|
|
case "artist" | "album" | "album-artist" | "album-disc-number" | \
|
|
"title" | "track-number" | "duration" | "trackid" | "uri":
|
|
changed = GLib.Variant("a{sv}", self.Metadata)
|
|
self.properties_changed({"Metadata": changed})
|
|
case "PlaybackStatus":
|
|
changed = GLib.Variant("s", self.PlaybackStatus)
|
|
self.properties_changed({property: changed})
|
|
case "CanPlay" | "CanPause" | "CanSeek":
|
|
changed = GLib.Variant("b", self.get_property(property))
|
|
self.properties_changed({property: changed})
|
|
|
|
def seeked(self, newpos: float) -> None:
|
|
"""Notify that the track position has changed."""
|
|
args = GLib.Variant.new_tuple(GLib.Variant("x", newpos))
|
|
self.dbus.emit_signal(None, dbus.OBJECT_PATH, self.interface.name,
|
|
"Seeked", args)
|
|
|
|
@GObject.Property
|
|
def Metadata(self) -> dict:
|
|
"""Metadata for the current Track."""
|
|
res = dict()
|
|
if self.file:
|
|
trackid = f"{OBJECT_PATH}/{self.trackid}"
|
|
res["mpris:trackid"] = GLib.Variant("o", trackid)
|
|
res["mpris:length"] = GLib.Variant("x", self.duration)
|
|
res["xesam:url"] = GLib.Variant("s", self.file.as_uri())
|
|
|
|
if len(self.artist) > 0:
|
|
res["xesam:artist"] = GLib.Variant("as", [self.artist])
|
|
if len(self.album) > 0:
|
|
res["xesam:album"] = GLib.Variant("s", self.album)
|
|
if len(self.album_artist) > 0:
|
|
res["xesam:albumArtist"] = GLib.Variant("as",
|
|
[self.album_artist])
|
|
if self.album_disc_number > 0:
|
|
res["xesam:discNumber"] = GLib.Variant("u",
|
|
self.album_disc_number)
|
|
if len(self.title) > 0:
|
|
res["xesam:title"] = GLib.Variant("s", self.title)
|
|
if self.track_number > 0:
|
|
res["xesam:trackNumber"] = GLib.Variant("u", self.track_number)
|
|
|
|
return res
|
|
|
|
@GObject.Signal
|
|
def Next(self) -> None:
|
|
"""Skip to the next track."""
|
|
|
|
@GObject.Signal
|
|
def Previous(self) -> None:
|
|
"""Skip to the previous track."""
|
|
|
|
@GObject.Signal
|
|
def Pause(self) -> None:
|
|
"""Pause playback."""
|
|
|
|
@GObject.Signal
|
|
def PlayPause(self) -> None:
|
|
"""Toggle playback status."""
|
|
|
|
@GObject.Signal
|
|
def Stop(self) -> None:
|
|
"""Stop playback."""
|
|
|
|
@GObject.Signal
|
|
def Play(self) -> None:
|
|
"""Start or resume playback."""
|
|
|
|
@GObject.Signal(arg_types=(float,))
|
|
def Seek(self, offset: float) -> None:
|
|
"""Seek forward or backward by the given offset."""
|
|
|
|
@GObject.Signal(arg_types=(str, float))
|
|
def SetPosition(self, trackid: str, position: float) -> None:
|
|
"""Set the current track position in microseconds."""
|
|
|
|
@GObject.Signal(arg_types=(str,))
|
|
def OpenUri(self, uri: str) -> None:
|
|
"""Open the given uri."""
|
|
self.emit("OpenPath", path.from_uri(uri))
|
|
|
|
@GObject.Signal(arg_types=(GObject.TYPE_PYOBJECT,))
|
|
def OpenPath(self, filepath: pathlib.Path) -> None:
|
|
"""Open the given path."""
|