Skip to content

Commit

Permalink
handle malformed MPRIS xml (#12)
Browse files Browse the repository at this point in the history
patch dbus_next to handle malformed xml

issue noticed with https://github.com/alexdelorenzo/cast_control

this allows ovos-media to recover and still support some of the player functionality

tested with chromecast and cast_control

Co-authored-by: JarbasAi <[email protected]>
  • Loading branch information
NeonJarbas and JarbasAl authored Feb 7, 2024
1 parent 6cd564e commit b1846d6
Showing 1 changed file with 57 additions and 12 deletions.
69 changes: 57 additions & 12 deletions ovos_media/mpris.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,53 @@
from threading import Thread, Event
from time import sleep


def patch_dbus_next():
# Patch dbus_next to handle malformed XML
from dbus_next.errors import InvalidIntrospectionError
import dbus_next.introspection

def from_xml(element):
"""Convert a :class:`xml.etree.ElementTree.Element` into a
:class:`Interface`.
The element must be valid DBus introspection XML for an ``interface``.
:param element: The parsed XML element.
:type element: :class:`xml.etree.ElementTree.Element`
:raises:
- :class:`InvalidIntrospectionError <dbus_next.InvalidIntrospectionError>` - If the XML tree is not valid introspection data.
"""
name = element.attrib.get('name')
if not name:
raise InvalidIntrospectionError('interfaces must have a "name" attribute')

interface = dbus_next.introspection.Interface(name)

for child in element:
try:
if child.tag == 'method':
interface.methods.append(dbus_next.introspection.Method.from_xml(child))
elif child.tag == 'signal':
interface.signals.append(dbus_next.introspection.Signal.from_xml(child))
elif child.tag == 'property':
interface.properties.append(dbus_next.introspection.Property.from_xml(child))
except:
continue
return interface

dbus_next.introspection.Interface.from_xml = from_xml


patch_dbus_next()

from dbus_next.aio import MessageBus as DbusMessageBus
from dbus_next.constants import BusType
from dbus_next.message import Message as DbusMessage, MessageType as DbusMessageType
from dbus_next.service import ServiceInterface, method, dbus_property, PropertyAccess
from ovos_bus_client.message import Message

from ovos_media.gui import OCPGUIState
from ovos_bus_client.message import Message
from ovos_utils.log import LOG
from ovos_utils.ocp import TrackState, PlaybackType, PlayerState, LoopState, MediaState

Expand Down Expand Up @@ -101,11 +141,11 @@ def _update_ocp(self):

state = data.get("loop_state") or 0
if state == 1:
self._ocp_player.loop_state = data["loop_state"] = LoopState.REPEAT
self._ocp_player.loop_state = data["loop_state"] = LoopState.REPEAT
elif state == 2:
self._ocp_player.loop_state = data["loop_state"] = LoopState.REPEAT_TRACK
self._ocp_player.loop_state = data["loop_state"] = LoopState.REPEAT_TRACK
else:
self._ocp_player.loop_state = data["loop_state"] = LoopState.NONE
self._ocp_player.loop_state = data["loop_state"] = LoopState.NONE

self._ocp_player.shuffle = data.get("shuffle") or self._ocp_player.shuffle
self._ocp_player.playback_type = PlaybackType.MPRIS
Expand Down Expand Up @@ -395,12 +435,17 @@ async def scan_players(self):
name in self.ignored_players:
continue
await self.handle_new_player({"name": name})
introspection = await self.dbus.introspect(
name, '/org/mpris/MediaPlayer2')
self.players[name] = self.dbus.get_proxy_object(
name, '/org/mpris/MediaPlayer2', introspection)
self._create_player_handler(name)
await self.query_player(name)

try:
introspection = await self.dbus.introspect(
name, '/org/mpris/MediaPlayer2')
self.players[name] = self.dbus.get_proxy_object(
name, '/org/mpris/MediaPlayer2', introspection)
self._create_player_handler(name)
await self.query_player(name)
except:
LOG.exception(f"Failed to introspect player: {name}")

return players

def _create_player_handler(self, name):
Expand Down Expand Up @@ -559,7 +604,7 @@ async def event_loop(self):
self.resume_event.clear()

if self.shuffle_event.is_set():
if self.player_meta[self.main_player].get("shuffle", self._ocp_player.shuffle):
if self.player_meta[self.main_player].get("shuffle", self._ocp_player.shuffle):
await self._shuffle_enable(self.main_player)
else:
await self._shuffle_disable(self.main_player)
Expand Down

0 comments on commit b1846d6

Please sign in to comment.