From 11a66a84653ea1e4af0064c903a0db5f1d326c20 Mon Sep 17 00:00:00 2001 From: croneter Date: Sun, 5 Aug 2018 14:44:24 +0200 Subject: [PATCH] Fix playback sometimes not starting and UnicodeEncodeError for logging - Fixes #520 --- resources/lib/loghandler.py | 4 +- resources/lib/playlist_func.py | 109 +++++++++++++++------------------ resources/lib/plex_api.py | 29 ++++++--- 3 files changed, 74 insertions(+), 68 deletions(-) diff --git a/resources/lib/loghandler.py b/resources/lib/loghandler.py index 69666c3c..2106b1dc 100644 --- a/resources/lib/loghandler.py +++ b/resources/lib/loghandler.py @@ -38,9 +38,11 @@ def config(): class LogHandler(logging.StreamHandler): def __init__(self): logging.StreamHandler.__init__(self) - self.setFormatter(logging.Formatter(fmt="%(name)s: %(message)s")) + self.setFormatter(logging.Formatter(fmt=b"%(name)s: %(message)s")) def emit(self, record): + if isinstance(record.msg, unicode): + record.msg = record.msg.encode('utf-8') try: xbmc.log(self.format(record), level=LEVELS[record.levelno]) except UnicodeEncodeError: diff --git a/resources/lib/playlist_func.py b/resources/lib/playlist_func.py index cd1999f7..3a7a51a4 100644 --- a/resources/lib/playlist_func.py +++ b/resources/lib/playlist_func.py @@ -33,36 +33,7 @@ class PlaylistError(Exception): pass -class PlaylistObjectBaseclase(object): - """ - Base class - """ - def __init__(self): - self.id = None - self.type = None - - def __repr__(self): - """ - Print the playlist, e.g. to log. Returns unicode - """ - answ = '{\'%s\': {\'id\': %s, ' % (self.__class__.__name__, self.id) - # For some reason, can't use dir directly - for key in self.__dict__: - if key in ('id', 'kodi_pl'): - continue - if isinstance(getattr(self, key), str): - answ += '\'%s\': \'%s\', ' % (key, - utils.try_decode(getattr(self, - key))) - elif isinstance(getattr(self, key), unicode): - answ += '\'%s\': \'%s\', ' % (key, getattr(self, key)) - else: - # e.g. int - answ += '\'%s\': %s, ' % (key, unicode(getattr(self, key))) - return answ + '}}' - - -class Playqueue_Object(PlaylistObjectBaseclase): +class Playqueue_Object(object): """ PKC object to represent PMS playQueues and Kodi playlist for queueing @@ -85,6 +56,8 @@ class Playqueue_Object(PlaylistObjectBaseclase): kind = 'playQueue' def __init__(self): + self.id = None + self.type = None self.playlistid = None self.kodi_pl = None self.items = [] @@ -104,7 +77,25 @@ class Playqueue_Object(PlaylistObjectBaseclase): # To keep track if Kodi playback was initiated from a Kodi playlist # There are a couple of pitfalls, unfortunately... self.kodi_playlist_playback = False - PlaylistObjectBaseclase.__init__(self) + + def __repr__(self): + answ = ("{{" + "'playlistid': {self.playlistid}, " + "'id': {self.id}, " + "'version': {self.version}, " + "'type': '{self.type}', " + "'selectedItemID': {self.selectedItemID}, " + "'selectedItemOffset': {self.selectedItemOffset}, " + "'shuffled': {self.shuffled}, " + "'repeat': {self.repeat}, " + "'kodi_playlist_playback': {self.kodi_playlist_playback}, " + "'pkc_edit': {self.pkc_edit}, ".format(self=self)) + answ = answ.encode('utf-8') + # Since list.__repr__ will return string, not unicode + return answ + b"'items': {self.items}}}".format(self=self) + + def __str__(self): + return self.__repr__() def is_pkc_clear(self): """ @@ -181,28 +172,27 @@ class Playlist_Item(object): self.force_transcode = False def __repr__(self): - """ - Print the playlist item, e.g. to log. Returns unicode - """ - answ = ('{\'%s\': {\'id\': \'%s\', \'plex_id\': \'%s\', ' - % (self.__class__.__name__, self.id, self.plex_id)) - for key in self.__dict__: - if key in ('id', 'plex_id', 'xml'): - continue - if isinstance(getattr(self, key), str): - answ += '\'%s\': \'%s\', ' % (key, - utils.try_decode(getattr(self, - key))) - elif isinstance(getattr(self, key), unicode): - answ += '\'%s\': \'%s\', ' % (key, getattr(self, key)) - else: - # e.g. int - answ += '\'%s\': %s, ' % (key, unicode(getattr(self, key))) - if self.xml is None: - answ += '\'xml\': None}}' - else: - answ += '\'xml\': \'%s\'}}' % self.xml.tag - return answ + answ = ("{{" + "'id': {self.id}, " + "'plex_id': {self.plex_id}, " + "'plex_type': '{self.plex_type}', " + "'plex_uuid': '{self.plex_uuid}', " + "'kodi_id': {self.kodi_id}, " + "'kodi_type': '{self.kodi_type}', " + "'file': '{self.file}', " + "'uri': '{self.uri}', " + "'guid': '{self.guid}', " + "'playmethod': '{self.playmethod}', " + "'playcount': {self.playcount}, " + "'offset': {self.offset}, " + "'force_transcode': {self.force_transcode}, " + "'part': {self.part}, ".format(self=self)) + answ = answ.encode('utf-8') + # etree xml.__repr__() could return string, not unicode + return answ + b"'xml': \"{self.xml}\"}}".format(self=self) + + def __str__(self): + return self.__repr__() def plex_stream_index(self, kodi_stream_index, stream_type): """ @@ -412,12 +402,13 @@ def get_playlist_details_from_xml(playlist, xml): Raises PlaylistError if something went wrong. """ - playlist.id = xml.get('%sID' % playlist.kind) - playlist.version = xml.get('%sVersion' % playlist.kind) - playlist.shuffled = xml.get('%sShuffled' % playlist.kind) - playlist.selectedItemID = xml.get('%sSelectedItemID' % playlist.kind) + playlist.id = xml.get('%sID' % playlist.kind).decode('utf-8') + playlist.version = xml.get('%sVersion' % playlist.kind).decode('utf-8') + playlist.shuffled = xml.get('%sShuffled' % playlist.kind).decode('utf-8') + playlist.selectedItemID = xml.get( + '%sSelectedItemID' % playlist.kind).decode('utf-8') playlist.selectedItemOffset = xml.get( - '%sSelectedItemOffset' % playlist.kind) + '%sSelectedItemOffset' % playlist.kind).decode('utf-8') LOG.debug('Updated playlist from xml: %s', playlist) @@ -781,4 +772,4 @@ def get_plextype_from_xml(xml): except (TypeError, IndexError, AttributeError): LOG.error('Could not get plex metadata for plex id %s', plex_id) return - return new_xml[0].attrib.get('type') + return new_xml[0].attrib.get('type').decode('utf-8') diff --git a/resources/lib/plex_api.py b/resources/lib/plex_api.py index e04d8ed7..7e3e5331 100644 --- a/resources/lib/plex_api.py +++ b/resources/lib/plex_api.py @@ -53,6 +53,19 @@ LOG = getLogger('PLEX.plex_api') ############################################################################### +def _unicode_or_none(value): + """ + Tries to decode value to unicode. Returns None if this fails + """ + try: + return value.decode('utf-8') + except TypeError: + # e.g. Android TV's Python + return value.decode() + except AttributeError: + pass + + class API(object): """ API(item) @@ -77,9 +90,10 @@ class API(object): def plex_type(self): """ - Returns the type of media, e.g. 'movie' or 'clip' for trailers + Returns the type of media, e.g. 'movie' or 'clip' for trailers as + Unicode or None. """ - return self.item.get('type') + return _unicode_or_none(self.item.get('type')) def playlist_type(self): """ @@ -104,9 +118,9 @@ class API(object): def plex_id(self): """ - Returns the Plex ratingKey such as '246922' as a string or None + Returns the Plex ratingKey such as '246922' as Unicode or None """ - return self.item.get('ratingKey') + return _unicode_or_none(self.item.get('ratingKey')) def path(self, force_first_media=True, force_addon=False, direct_paths=None): @@ -664,12 +678,11 @@ class API(object): def item_id(self): """ Returns current playQueueItemID or if unsuccessful the playListItemID + as Unicode. If not found, None is returned """ - answ = self.item.get('playQueueItemID') - if answ is None: - answ = self.item.get('playListItemID') - return answ + return _unicode_or_none(self.item.get('playQueueItemID') or + self.item.get('playListItemID')) def _data_from_part_or_media(self, key): """