mirror of
https://github.com/SoongNoonien/mpdevil.git
synced 2023-08-10 21:12:44 +03:00
migrated MPRISInterface to Gio
This commit is contained in:
parent
7ae0f1e216
commit
b6be0f0430
@ -61,7 +61,6 @@ Python modules:
|
||||
- gi (Gtk, Gio, Gdk, GdkPixbuf, Pango, GObject, GLib, Notify)
|
||||
- requests
|
||||
- bs4 (beautifulsoup)
|
||||
- dbus
|
||||
|
||||
Run:
|
||||
```bash
|
||||
|
406
bin/mpdevil
406
bin/mpdevil
@ -34,12 +34,6 @@ import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
# MPRIS modules
|
||||
import dbus
|
||||
import dbus.service
|
||||
from dbus.mainloop.glib import DBusGMainLoop
|
||||
DBusGMainLoop(set_as_default=True)
|
||||
|
||||
VERSION="0.9.7-dev" # sync with setup.py
|
||||
COVER_REGEX=r"^\.?(album|cover|folder|front).*\.(gif|jpeg|jpg|png)$"
|
||||
|
||||
@ -48,23 +42,134 @@ COVER_REGEX=r"^\.?(album|cover|folder|front).*\.(gif|jpeg|jpg|png)$"
|
||||
# MPRIS #
|
||||
#########
|
||||
|
||||
class MPRISInterface(dbus.service.Object): # TODO emit Seeked if needed
|
||||
class MPRISInterface: # TODO emit Seeked if needed
|
||||
"""
|
||||
based on 'mpDris2' (master 19.03.2020) by Jean-Philippe Braun <eon@patapon.info>, Mantas Mikulėnas <grawity@gmail.com>
|
||||
based on 'Lollypop' (master 22.12.2020) by Cedric Bellegarde <cedric.bellegarde@adishatz.org>
|
||||
and 'mpDris2' (master 19.03.2020) by Jean-Philippe Braun <eon@patapon.info>, Mantas Mikulėnas <grawity@gmail.com>
|
||||
"""
|
||||
_MPRIS_IFACE="org.mpris.MediaPlayer2"
|
||||
_MPRIS_PLAYER_IFACE="org.mpris.MediaPlayer2.Player"
|
||||
_MPRIS_NAME="org.mpris.MediaPlayer2.mpdevil"
|
||||
_MPRIS_PATH="/org/mpris/MediaPlayer2"
|
||||
_INTERFACES_XML="""
|
||||
<!DOCTYPE node PUBLIC
|
||||
"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.freedesktop.DBus.Introspectable">
|
||||
<method name="Introspect">
|
||||
<arg name="data" direction="out" type="s"/>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.freedesktop.DBus.Properties">
|
||||
<method name="Get">
|
||||
<arg name="interface" direction="in" type="s"/>
|
||||
<arg name="property" direction="in" type="s"/>
|
||||
<arg name="value" direction="out" type="v"/>
|
||||
</method>
|
||||
<method name="Set">
|
||||
<arg name="interface_name" direction="in" type="s"/>
|
||||
<arg name="property_name" direction="in" type="s"/>
|
||||
<arg name="value" direction="in" type="v"/>
|
||||
</method>
|
||||
<method name="GetAll">
|
||||
<arg name="interface" direction="in" type="s"/>
|
||||
<arg name="properties" direction="out" type="a{sv}"/>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.mpris.MediaPlayer2">
|
||||
<method name="Raise">
|
||||
</method>
|
||||
<method name="Quit">
|
||||
</method>
|
||||
<property name="CanQuit" type="b" access="read" />
|
||||
<property name="CanRaise" type="b" access="read" />
|
||||
<property name="HasTrackList" type="b" access="read"/>
|
||||
<property name="Identity" type="s" access="read"/>
|
||||
<property name="DesktopEntry" type="s" access="read"/>
|
||||
<property name="SupportedUriSchemes" type="as" access="read"/>
|
||||
<property name="SupportedMimeTypes" type="as" access="read"/>
|
||||
</interface>
|
||||
<interface name="org.mpris.MediaPlayer2.Player">
|
||||
<method name="Next"/>
|
||||
<method name="Previous"/>
|
||||
<method name="Pause"/>
|
||||
<method name="PlayPause"/>
|
||||
<method name="Stop"/>
|
||||
<method name="Play"/>
|
||||
<method name="Seek">
|
||||
<arg direction="in" name="Offset" type="x"/>
|
||||
</method>
|
||||
<method name="SetPosition">
|
||||
<arg direction="in" name="TrackId" type="o"/>
|
||||
<arg direction="in" name="Position" type="x"/>
|
||||
</method>
|
||||
<method name="OpenUri">
|
||||
<arg direction="in" name="Uri" type="s"/>
|
||||
</method>
|
||||
<signal name="Seeked">
|
||||
<arg name="Position" type="x"/>
|
||||
</signal>
|
||||
<property name="PlaybackStatus" type="s" access="read"/>
|
||||
<property name="LoopStatus" type="s" access="readwrite"/>
|
||||
<property name="Rate" type="d" access="readwrite"/>
|
||||
<property name="Shuffle" type="b" access="readwrite"/>
|
||||
<property name="Metadata" type="a{sv}" access="read"/>
|
||||
<property name="Volume" type="d" access="readwrite"/>
|
||||
<property name="Position" type="x" access="read"/>
|
||||
<property name="MinimumRate" type="d" access="read"/>
|
||||
<property name="MaximumRate" type="d" access="read"/>
|
||||
<property name="CanGoNext" type="b" access="read"/>
|
||||
<property name="CanGoPrevious" type="b" access="read"/>
|
||||
<property name="CanPlay" type="b" access="read"/>
|
||||
<property name="CanPause" type="b" access="read"/>
|
||||
<property name="CanSeek" type="b" access="read"/>
|
||||
<property name="CanControl" type="b" access="read"/>
|
||||
</interface>
|
||||
</node>
|
||||
"""
|
||||
def __init__(self, window, client, settings):
|
||||
super().__init__(dbus.SessionBus(), "/org/mpris/MediaPlayer2")
|
||||
self._name="org.mpris.MediaPlayer2.mpdevil"
|
||||
|
||||
def __init__(self, window, client, settings):
|
||||
# adding vars
|
||||
self._window=window
|
||||
self._client=client
|
||||
self._settings=settings
|
||||
self._metadata={}
|
||||
self._bus=dbus.SessionBus()
|
||||
|
||||
# MPRIS property mappings
|
||||
self._prop_mapping={
|
||||
self._MPRIS_IFACE:
|
||||
{"CanQuit": (GLib.Variant("b", False), None),
|
||||
"CanRaise": (GLib.Variant("b", True), None),
|
||||
"HasTrackList": (GLib.Variant("b", False), None),
|
||||
"Identity": (GLib.Variant("s", "mpdevil"), None),
|
||||
"DesktopEntry": (GLib.Variant("s", "mpdevil"), None),
|
||||
"SupportedUriSchemes": (GLib.Variant("s", "None"), None),
|
||||
"SupportedMimeTypes": (GLib.Variant("s", "None"), None)},
|
||||
self._MPRIS_PLAYER_IFACE:
|
||||
{"PlaybackStatus": (self._get_playback_status, None),
|
||||
"LoopStatus": (self._get_loop_status, self._set_loop_status),
|
||||
"Rate": (GLib.Variant("d", 1.0), None),
|
||||
"Shuffle": (self._get_shuffle, self._set_shuffle),
|
||||
"Metadata": (self._get_metadata, None),
|
||||
"Volume": (self._get_volume, self._set_volume),
|
||||
"Position": (self._get_position, None),
|
||||
"MinimumRate": (GLib.Variant("d", 1.0), None),
|
||||
"MaximumRate": (GLib.Variant("d", 1.0), None),
|
||||
"CanGoNext": (self._get_can_next_prev, None),
|
||||
"CanGoPrevious": (self._get_can_next_prev, None),
|
||||
"CanPlay": (self._get_can_play_pause_seek, None),
|
||||
"CanPause": (self._get_can_play_pause_seek, None),
|
||||
"CanSeek": (self._get_can_play_pause_seek, None),
|
||||
"CanControl": (GLib.Variant("b", True), None)},
|
||||
}
|
||||
|
||||
# start
|
||||
self._bus_name=dbus.service.BusName(self._name, bus=self._bus, allow_replacement=True, replace_existing=True) # TODO
|
||||
self._bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
|
||||
Gio.bus_own_name_on_connection(self._bus, self._MPRIS_NAME, Gio.BusNameOwnerFlags.NONE, None, None)
|
||||
self._node_info=Gio.DBusNodeInfo.new_for_xml(self._INTERFACES_XML)
|
||||
for interface in self._node_info.interfaces:
|
||||
self._bus.register_object(self._MPRIS_PATH, interface, self._handle_method_call, None, None)
|
||||
|
||||
# connect
|
||||
self._client.emitter.connect("state", self._on_state_changed)
|
||||
@ -76,26 +181,25 @@ class MPRISInterface(dbus.service.Object): # TODO emit Seeked if needed
|
||||
self._client.emitter.connect("connection_error", self._on_connection_error)
|
||||
self._client.emitter.connect("reconnected", self._on_reconnected)
|
||||
|
||||
# Interfaces
|
||||
__prop_interface=dbus.PROPERTIES_IFACE
|
||||
__root_interface="org.mpris.MediaPlayer2"
|
||||
__root_props={
|
||||
"CanQuit": (False, None),
|
||||
"CanRaise": (True, None),
|
||||
"DesktopEntry": ("mpdevil", None),
|
||||
"HasTrackList": (False, None),
|
||||
"Identity": ("mpdevil", None),
|
||||
"SupportedUriSchemes": (dbus.Array(signature="s"), None),
|
||||
"SupportedMimeTypes": (dbus.Array(signature="s"), None)
|
||||
}
|
||||
def _handle_method_call(self, connection, sender, object_path, interface_name, method_name, parameters, invocation):
|
||||
args=list(parameters.unpack())
|
||||
result=getattr(self, method_name)(*args)
|
||||
out_args=self._node_info.lookup_interface(interface_name).lookup_method(method_name).out_args
|
||||
if out_args == []:
|
||||
invocation.return_value(None)
|
||||
else:
|
||||
signature="("+"".join([arg.signature for arg in out_args])+")"
|
||||
variant=GLib.Variant(signature, (result,))
|
||||
invocation.return_value(variant)
|
||||
|
||||
def __get_playback_status(self):
|
||||
# setter and getter
|
||||
def _get_playback_status(self):
|
||||
if self._client.connected():
|
||||
status=self._client.wrapped_call("status")
|
||||
return {"play": "Playing", "pause": "Paused", "stop": "Stopped"}[status["state"]]
|
||||
return "Stopped"
|
||||
return GLib.Variant("s", {"play": "Playing", "pause": "Paused", "stop": "Stopped"}[status["state"]])
|
||||
return GLib.Variant("s", "Stopped")
|
||||
|
||||
def __set_loop_status(self, value):
|
||||
def _set_loop_status(self, value):
|
||||
if self._client.connected():
|
||||
if value == "Playlist":
|
||||
self._client.wrapped_call("repeat", 1)
|
||||
@ -106,177 +210,142 @@ class MPRISInterface(dbus.service.Object): # TODO emit Seeked if needed
|
||||
elif value == "None":
|
||||
self._client.wrapped_call("repeat", 0)
|
||||
self._client.wrapped_call("single", 0)
|
||||
else:
|
||||
raise dbus.exceptions.DBusException("Loop mode '{}' not supported".format(value))
|
||||
return
|
||||
|
||||
def __get_loop_status(self):
|
||||
def _get_loop_status(self):
|
||||
if self._client.connected():
|
||||
status=self._client.wrapped_call("status")
|
||||
if int(status["repeat"]) == 1:
|
||||
if int(status.get("single", 0)) == 1:
|
||||
return "Track"
|
||||
return GLib.Variant("s", "Track")
|
||||
else:
|
||||
return "Playlist"
|
||||
return GLib.Variant("s", "Playlist")
|
||||
else:
|
||||
return "None"
|
||||
return "None"
|
||||
return GLib.Variant("s", "None")
|
||||
return GLib.Variant("s", "None")
|
||||
|
||||
def __set_shuffle(self, value):
|
||||
def _set_shuffle(self, value):
|
||||
if self._client.connected():
|
||||
self._client.wrapped_call("random", value)
|
||||
return
|
||||
|
||||
def __get_shuffle(self):
|
||||
if self._client.connected():
|
||||
if int(self._client.wrapped_call("status")["random"]) == 1:
|
||||
return True
|
||||
if value:
|
||||
self._client.wrapped_call("random", "1")
|
||||
else:
|
||||
return False
|
||||
return False
|
||||
self._client.wrapped_call("random", "0")
|
||||
|
||||
def __get_metadata(self):
|
||||
return dbus.Dictionary(self._metadata, signature="sv")
|
||||
|
||||
def __get_volume(self):
|
||||
def _get_shuffle(self):
|
||||
if self._client.connected():
|
||||
return float(self._client.wrapped_call("status").get("volume", 0))/100
|
||||
return 0.0
|
||||
if self._client.wrapped_call("status")["random"] == "1":
|
||||
return GLib.Variant("b", True)
|
||||
else:
|
||||
return GLib.Variant("b", False)
|
||||
return GLib.Variant("b", False)
|
||||
|
||||
def __set_volume(self, value):
|
||||
def _get_metadata(self):
|
||||
return GLib.Variant("a{sv}", self._metadata)
|
||||
|
||||
def _get_volume(self):
|
||||
if self._client.connected():
|
||||
return GLib.Variant("d", float(self._client.wrapped_call("status").get("volume", 0))/100)
|
||||
return GLib.Variant("d", 0)
|
||||
|
||||
def _set_volume(self, value):
|
||||
if self._client.connected():
|
||||
if value >= 0 and value <= 1:
|
||||
self._client.wrapped_call("setvol", int(value * 100))
|
||||
return
|
||||
|
||||
def __get_position(self):
|
||||
def _get_position(self):
|
||||
if self._client.connected():
|
||||
status=self._client.wrapped_call("status")
|
||||
return dbus.Int64(float(status.get("elapsed", 0))*1000000)
|
||||
return dbus.Int64(0)
|
||||
return GLib.Variant("x", float(status.get("elapsed", 0))*1000000)
|
||||
return GLib.Variant("x", 0)
|
||||
|
||||
def __get_can_next_prev(self):
|
||||
def _get_can_next_prev(self):
|
||||
if self._client.connected():
|
||||
status=self._client.wrapped_call("status")
|
||||
if status["state"] == "stop":
|
||||
return False
|
||||
return GLib.Variant("b", False)
|
||||
else:
|
||||
return True
|
||||
return False
|
||||
return GLib.Variant("b", True)
|
||||
return GLib.Variant("b", False)
|
||||
|
||||
def __get_can_play_pause_seek(self):
|
||||
return self._client.connected()
|
||||
def _get_can_play_pause_seek(self):
|
||||
return GLib.Variant("b", self._client.connected())
|
||||
|
||||
__player_interface="org.mpris.MediaPlayer2.Player"
|
||||
__player_props={
|
||||
"PlaybackStatus": (__get_playback_status, None),
|
||||
"LoopStatus": (__get_loop_status, __set_loop_status),
|
||||
"Rate": (1.0, None),
|
||||
"Shuffle": (__get_shuffle, __set_shuffle),
|
||||
"Metadata": (__get_metadata, None),
|
||||
"Volume": (__get_volume, __set_volume),
|
||||
"Position": (__get_position, None),
|
||||
"MinimumRate": (1.0, None),
|
||||
"MaximumRate": (1.0, None),
|
||||
"CanGoNext": (__get_can_next_prev, None),
|
||||
"CanGoPrevious": (__get_can_next_prev, None),
|
||||
"CanPlay": (__get_can_play_pause_seek, None),
|
||||
"CanPause": (__get_can_play_pause_seek, None),
|
||||
"CanSeek": (__get_can_play_pause_seek, None),
|
||||
"CanControl": (True, None),
|
||||
}
|
||||
__prop_mapping={
|
||||
__player_interface: __player_props,
|
||||
__root_interface: __root_props,
|
||||
}
|
||||
# introspect methods
|
||||
def Introspect(self):
|
||||
return self._INTERFACES_XML
|
||||
|
||||
# Prop methods
|
||||
@dbus.service.signal(__prop_interface, signature="sa{sv}as")
|
||||
def PropertiesChanged(self, interface, changed_properties, invalidated_properties):
|
||||
pass
|
||||
|
||||
@dbus.service.method(__prop_interface, in_signature="ss", out_signature="v")
|
||||
def Get(self, interface, prop):
|
||||
getter, setter=self.__prop_mapping[interface][prop]
|
||||
# property methods
|
||||
def Get(self, interface_name, prop):
|
||||
getter, setter=self._prop_mapping[interface_name][prop]
|
||||
if callable(getter):
|
||||
return getter(self)
|
||||
return getter()
|
||||
return getter
|
||||
|
||||
@dbus.service.method(__prop_interface, in_signature="ssv", out_signature="")
|
||||
def Set(self, interface, prop, value):
|
||||
getter, setter=self.__prop_mapping[interface][prop]
|
||||
def Set(self, interface_name, prop, value):
|
||||
getter, setter=self._prop_mapping[interface_name][prop]
|
||||
if setter is not None:
|
||||
setter(self, value)
|
||||
setter(value)
|
||||
|
||||
@dbus.service.method(__prop_interface, in_signature="s", out_signature="a{sv}")
|
||||
def GetAll(self, interface):
|
||||
def GetAll(self, interface_name):
|
||||
read_props={}
|
||||
props=self.__prop_mapping[interface]
|
||||
for key, (getter, setter) in props.items():
|
||||
if callable(getter):
|
||||
getter=getter(self)
|
||||
read_props[key]=getter
|
||||
try:
|
||||
props=self._prop_mapping[interface_name]
|
||||
for key, (getter, setter) in props.items():
|
||||
if callable(getter):
|
||||
getter=getter()
|
||||
read_props[key]=getter
|
||||
except KeyError: # interface has no properties
|
||||
pass
|
||||
return read_props
|
||||
|
||||
# Root methods
|
||||
@dbus.service.method(__root_interface, in_signature="", out_signature="")
|
||||
def PropertiesChanged(self, interface_name, changed_properties, invalidated_properties):
|
||||
self._bus.emit_signal(
|
||||
None, self._MPRIS_PATH, "org.freedesktop.DBus.Properties", "PropertiesChanged",
|
||||
GLib.Variant.new_tuple(
|
||||
GLib.Variant("s", interface_name),
|
||||
GLib.Variant("a{sv}", changed_properties),
|
||||
GLib.Variant("as", invalidated_properties)
|
||||
)
|
||||
)
|
||||
|
||||
# root methods
|
||||
def Raise(self):
|
||||
self._window.present()
|
||||
return
|
||||
|
||||
@dbus.service.method(__root_interface, in_signature="", out_signature="")
|
||||
def Quit(self):
|
||||
return
|
||||
app_action_group=self._window.get_action_group("app")
|
||||
quit_action=app_action_group.lookup_action("quit")
|
||||
quit_action.activate()
|
||||
|
||||
# Player methods
|
||||
@dbus.service.signal(__player_interface, signature="x")
|
||||
def Seeked(self, position):
|
||||
return float(position)
|
||||
|
||||
@dbus.service.method(__player_interface, in_signature="", out_signature="")
|
||||
# player methods
|
||||
def Next(self):
|
||||
self._client.wrapped_call("next")
|
||||
return
|
||||
|
||||
@dbus.service.method(__player_interface, in_signature="", out_signature="")
|
||||
def Previous(self):
|
||||
self._client.wrapped_call("previous")
|
||||
return
|
||||
|
||||
@dbus.service.method(__player_interface, in_signature="", out_signature="")
|
||||
def Pause(self):
|
||||
self._client.wrapped_call("pause", 1)
|
||||
return
|
||||
|
||||
@dbus.service.method(__player_interface, in_signature="", out_signature="")
|
||||
def PlayPause(self):
|
||||
status=self._client.wrapped_call("status")
|
||||
if status["state"] == "play":
|
||||
self._client.wrapped_call("pause", 1)
|
||||
else:
|
||||
self._client.wrapped_call("play")
|
||||
return
|
||||
|
||||
@dbus.service.method(__player_interface, in_signature="", out_signature="")
|
||||
def Stop(self):
|
||||
self._client.wrapped_call("stop")
|
||||
return
|
||||
|
||||
@dbus.service.method(__player_interface, in_signature="", out_signature="")
|
||||
def Play(self):
|
||||
self._client.wrapped_call("play")
|
||||
return
|
||||
|
||||
@dbus.service.method(__player_interface, in_signature="x", out_signature="")
|
||||
def Seek(self, offset):
|
||||
if offset > 0:
|
||||
offset="+"+str(offset/1000000)
|
||||
else:
|
||||
offset=str(offset/1000000)
|
||||
self._client.wrapped_call("seekcur", offset)
|
||||
return
|
||||
|
||||
@dbus.service.method(__player_interface, in_signature="ox", out_signature="")
|
||||
def SetPosition(self, trackid, position):
|
||||
song=self._client.wrapped_call("currentsong")
|
||||
if str(trackid).split("/")[-1] != song["id"]:
|
||||
@ -284,29 +353,17 @@ class MPRISInterface(dbus.service.Object): # TODO emit Seeked if needed
|
||||
mpd_pos=position/1000000
|
||||
if mpd_pos >= 0 and mpd_pos <= float(song["duration"]):
|
||||
self._client.wrapped_call("seekcur", str(mpd_pos))
|
||||
return
|
||||
|
||||
@dbus.service.method(__player_interface, in_signature="s", out_signature="")
|
||||
def OpenUri(self, uri):
|
||||
return
|
||||
pass
|
||||
|
||||
# MPRIS implemented metadata tags (all: http://www.freedesktop.org/wiki/Specifications/mpris-spec/metadata)
|
||||
implemented_tags={
|
||||
"mpris:trackid": dbus.ObjectPath,
|
||||
"mpris:length": dbus.Int64,
|
||||
"mpris:artUrl": str,
|
||||
"xesam:album": str,
|
||||
"xesam:albumArtist": list,
|
||||
"xesam:artist": list,
|
||||
"xesam:composer": list,
|
||||
"xesam:contentCreated": str,
|
||||
"xesam:discNumber": int,
|
||||
"xesam:genre": list,
|
||||
"xesam:title": str,
|
||||
"xesam:trackNumber": int,
|
||||
"xesam:url": str,
|
||||
}
|
||||
def Seeked(self, position):
|
||||
self._bus.emit_signal(
|
||||
None, self._MPRIS_PATH, self._MPRIS_PLAYER_IFACE, "Seeked",
|
||||
GLib.Variant.new_tuple(GLib.Variant("x", position))
|
||||
)
|
||||
|
||||
# other methods
|
||||
def _update_metadata(self):
|
||||
"""
|
||||
Translate metadata returned by MPD to the MPRIS v2 syntax.
|
||||
@ -315,67 +372,64 @@ class MPRISInterface(dbus.service.Object): # TODO emit Seeked if needed
|
||||
mpd_meta=self._client.wrapped_call("currentsong") # raw values needed for cover
|
||||
song=ClientHelper.song_to_list_dict(mpd_meta)
|
||||
self._metadata={}
|
||||
for tag, xesam_tag in (("album","album"),("title","title"),("track","trackNumber"),("disc","discNumber"),("date","contentCreated")):
|
||||
for tag, xesam_tag in (("album","album"),("title","title"),("date","contentCreated")):
|
||||
if tag in song:
|
||||
self._metadata["xesam:{}".format(xesam_tag)]=song[tag][0]
|
||||
self._metadata["xesam:{}".format(xesam_tag)]=GLib.Variant("s", song[tag][0])
|
||||
for tag, xesam_tag in (("track","trackNumber"),("disc","discNumber")):
|
||||
if tag in song:
|
||||
self._metadata["xesam:{}".format(xesam_tag)]=GLib.Variant("i", int(song[tag][0]))
|
||||
for tag, xesam_tag in (("albumartist","albumArtist"),("artist","artist"),("composer","composer"),("genre","genre")):
|
||||
if tag in song:
|
||||
self._metadata["xesam:{}".format(xesam_tag)]=song[tag]
|
||||
self._metadata["xesam:{}".format(xesam_tag)]=GLib.Variant("as", song[tag])
|
||||
if "id" in song:
|
||||
self._metadata["mpris:trackid"]="/org/mpris/MediaPlayer2/Track/{}".format(song["id"][0])
|
||||
self._metadata["mpris:trackid"]=GLib.Variant("o", self._MPRIS_PATH+"/Track/{}".format(song["id"][0]))
|
||||
if "time" in song:
|
||||
self._metadata["mpris:length"]=float(song["duration"][0]) * 1000000
|
||||
self._metadata["mpris:length"]=GLib.Variant("x", float(song["duration"][0])*1000000)
|
||||
if "file" in song:
|
||||
song_file=song["file"][0]
|
||||
lib_path=self._settings.get_value("paths")[self._settings.get_int("active-profile")]
|
||||
self._metadata["xesam:url"]="file://{}".format(os.path.join(lib_path, song_file))
|
||||
self._metadata["xesam:url"]=GLib.Variant("s", "file://{}".format(os.path.join(lib_path, song_file)))
|
||||
cover=Cover(self._settings, mpd_meta)
|
||||
if cover.path is not None:
|
||||
self._metadata["mpris:artUrl"]="file://{}".format(cover.path)
|
||||
# Cast self._metadata to the correct type, or discard it
|
||||
for key, value in self._metadata.items():
|
||||
try:
|
||||
self._metadata[key]=self.implemented_tags[key](value)
|
||||
except:
|
||||
self._metadata[key]=""
|
||||
self._metadata["mpris:artUrl"]=GLib.Variant("s", "file://{}".format(cover.path))
|
||||
|
||||
def _update_property(self, interface, prop):
|
||||
getter, setter=self.__prop_mapping[interface][prop]
|
||||
def _update_property(self, interface_name, prop):
|
||||
getter, setter=self._prop_mapping[interface_name][prop]
|
||||
if callable(getter):
|
||||
value=getter(self)
|
||||
value=getter()
|
||||
else:
|
||||
value=getter
|
||||
self.PropertiesChanged(interface, {prop: value}, [])
|
||||
self.PropertiesChanged(interface_name, {prop: value}, [])
|
||||
return value
|
||||
|
||||
def _on_state_changed(self, *args):
|
||||
self._update_property("org.mpris.MediaPlayer2.Player", "PlaybackStatus")
|
||||
self._update_property("org.mpris.MediaPlayer2.Player", "CanGoNext")
|
||||
self._update_property("org.mpris.MediaPlayer2.Player", "CanGoPrevious")
|
||||
self._update_property(self._MPRIS_PLAYER_IFACE, "PlaybackStatus")
|
||||
self._update_property(self._MPRIS_PLAYER_IFACE, "CanGoNext")
|
||||
self._update_property(self._MPRIS_PLAYER_IFACE, "CanGoPrevious")
|
||||
|
||||
def _on_song_changed(self, *args):
|
||||
self._update_metadata()
|
||||
self._update_property("org.mpris.MediaPlayer2.Player", "Metadata")
|
||||
self._update_property(self._MPRIS_PLAYER_IFACE, "Metadata")
|
||||
|
||||
def _on_volume_changed(self, *args):
|
||||
self._update_property("org.mpris.MediaPlayer2.Player", "Volume")
|
||||
self._update_property(self._MPRIS_PLAYER_IFACE, "Volume")
|
||||
|
||||
def _on_loop_changed(self, *args):
|
||||
self._update_property("org.mpris.MediaPlayer2.Player", "LoopStatus")
|
||||
self._update_property(self._MPRIS_PLAYER_IFACE, "LoopStatus")
|
||||
|
||||
def _on_random_changed(self, *args):
|
||||
self._update_property("org.mpris.MediaPlayer2.Player", "Shuffle")
|
||||
self._update_property(self._MPRIS_PLAYER_IFACE, "Shuffle")
|
||||
|
||||
def _on_reconnected(self, *args):
|
||||
properties=("CanPlay","CanPause","CanSeek")
|
||||
for p in properties:
|
||||
self._update_property("org.mpris.MediaPlayer2.Player", p)
|
||||
self._update_property(self._MPRIS_PLAYER_IFACE, p)
|
||||
|
||||
def _on_connection_error(self, *args):
|
||||
self._metadata={}
|
||||
properties=("PlaybackStatus","CanGoNext","CanGoPrevious","Metadata","Volume","LoopStatus","Shuffle","CanPlay","CanPause","CanSeek")
|
||||
for p in properties:
|
||||
self._update_property("org.mpris.MediaPlayer2.Player", p)
|
||||
self._update_property(self._MPRIS_PLAYER_IFACE, p)
|
||||
|
||||
######################
|
||||
# MPD client wrapper #
|
||||
|
Loading…
Reference in New Issue
Block a user