Merge pull request #708 from croneter/improve-playerror-messages

Improve error messages when playback failes
This commit is contained in:
croneter 2019-02-06 16:16:09 +01:00 committed by GitHub
commit 05a6700d55
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 135 additions and 78 deletions

View file

@ -1138,9 +1138,9 @@ msgctxt "#39211"
msgid "Watch later"
msgstr ""
# String attached at the end to get something like "PMS Name is offline"
# Error message pop-up if {0} cannot be contacted. {0} will be replaced by e.g. the PMS' name
msgctxt "#39213"
msgid "is offline"
msgid "{0} offline"
msgstr ""
msgctxt "#39215"

View file

@ -167,6 +167,7 @@ class DownloadUtils():
kwargs['timeout'] = timeout
# ACTUAL DOWNLOAD HAPPENING HERE
success = False
try:
r = self._doDownload(s, action_type, **kwargs)
@ -176,44 +177,37 @@ class DownloadUtils():
LOG.warn(e)
if reraise:
raise
except exceptions.ConnectionError as e:
# Connection error
LOG.warn("Server unreachable at: %s", url)
LOG.warn(e)
if reraise:
raise
except exceptions.Timeout as e:
LOG.warn("Server timeout at: %s", url)
LOG.warn(e)
if reraise:
raise
except exceptions.HTTPError as e:
LOG.warn('HTTP Error at %s', url)
LOG.warn(e)
if reraise:
raise
except exceptions.TooManyRedirects as e:
LOG.warn("Too many redirects connecting to: %s", url)
LOG.warn(e)
if reraise:
raise
except exceptions.RequestException as e:
LOG.warn("Unknown error connecting to: %s", url)
LOG.warn(e)
if reraise:
raise
except SystemExit:
LOG.info('SystemExit detected, aborting download')
self.stopSession()
if reraise:
raise
except Exception:
LOG.warn('Unknown error while downloading. Traceback:')
import traceback
@ -223,6 +217,7 @@ class DownloadUtils():
# THE RESPONSE #####
else:
success = True
# We COULD contact the PMS, hence it ain't dead
if authenticate is True:
self.count_error = 0
@ -300,12 +295,12 @@ class DownloadUtils():
url, r.status_code)
return True
# And now deal with the consequences of the exceptions
if authenticate is True:
finally:
if not success and authenticate:
# Deal with the consequences of the exceptions
# Make the addon aware of status
self.count_error += 1
if self.count_error >= self.connection_attempts:
LOG.warn('Failed to connect to %s too many times. '
'Declare PMS dead', url)
app.CONN.online = False
return

View file

@ -11,7 +11,6 @@ from .plex_api import API
from .plex_db import PlexDB
from . import plex_functions as PF
from . import utils
from .downloadutils import DownloadUtils as DU
from .kodi_db import KodiVideoDB
from . import playlist_func as PL
from . import playqueue as PQ
@ -50,7 +49,15 @@ def playback_triage(plex_id=None, plex_type=None, path=None, resolve=True):
global RESOLVE
# If started via Kodi context menu, we never resolve
RESOLVE = resolve if not app.PLAYSTATE.context_menu_play else False
if not app.ACCOUNT.authenticated:
if not app.CONN.online or not app.ACCOUNT.authenticated:
if not app.CONN.online:
LOG.error('PMS not online for playback')
# "{0} offline"
utils.dialog('notification',
utils.lang(29999),
utils.lang(39213).format(app.CONN.server_name),
icon='{plex}')
else:
LOG.error('Not yet authenticated for PMS, abort starting playback')
# "Unauthorized for PMS"
utils.dialog('notification', utils.lang(29999), utils.lang(30017))
@ -135,16 +142,8 @@ def _playlist_playback(plex_id, plex_type):
for the next item in line :-)
(by the way: trying to get active Kodi player id will return [])
"""
xml = PF.GetPlexMetadata(plex_id)
try:
xml[0].attrib
except (IndexError, TypeError, AttributeError):
LOG.error('Could not get a PMS xml for plex id %s', plex_id)
# "Play error"
utils.dialog('notification',
utils.lang(29999),
utils.lang(30128),
icon='{error}')
xml = PF.GetPlexMetadata(plex_id, reraise=True)
if xml in (None, 401):
_ensure_resolve(abort=True)
return
# Kodi bug: playqueue will ALWAYS be audio playqueue UNTIL playback
@ -164,16 +163,9 @@ def _playback_init(plex_id, plex_type, playqueue, pos):
Playback setup if Kodi starts playing an item for the first time.
"""
LOG.info('Initializing PKC playback')
xml = PF.GetPlexMetadata(plex_id)
try:
xml[0].attrib
except (IndexError, TypeError, AttributeError):
xml = PF.GetPlexMetadata(plex_id, reraise=True)
if xml in (None, 401):
LOG.error('Could not get a PMS xml for plex id %s', plex_id)
# "Play error"
utils.dialog('notification',
utils.lang(29999),
utils.lang(30128),
icon='{error}')
_ensure_resolve(abort=True)
return
if playqueue.kodi_pl.size() > 1:
@ -182,6 +174,11 @@ def _playback_init(plex_id, plex_type, playqueue, pos):
_init_existing_kodi_playlist(playqueue, pos)
except PL.PlaylistError:
LOG.error('Playback_init for existing Kodi playlist failed')
# "Play error"
utils.dialog('notification',
utils.lang(29999),
utils.lang(30128),
icon='{error}')
_ensure_resolve(abort=True)
return
# Now we need to use setResolvedUrl for the item at position ZERO
@ -259,12 +256,10 @@ def _ensure_resolve(abort=False):
will be destroyed.
"""
if RESOLVE:
if not abort:
# Releases the other Python thread without a ListItem
transfer.send(True)
else:
# Shows PKC error message
transfer.send(None)
# transfer.send(None)
if abort:
# Reset some playback variables
app.PLAYSTATE.context_menu_play = False
@ -418,7 +413,10 @@ def _conclude_playback(playqueue, pos):
LOG.info('Resuming playback at %s', item.offset)
if v.KODIVERSION >= 18 and api:
# Kodi 18 Alpha 3 broke StartOffset
try:
percent = item.offset / api.runtime() * 100.0
except ZeroDivisionError:
percent = 0.0
LOG.debug('Resuming at %s percent', percent)
listitem.setProperty('StartPercent', str(percent))
else:
@ -446,21 +444,20 @@ def process_indirect(key, offset, resolve=True):
key, offset, resolve)
global RESOLVE
RESOLVE = resolve
offset = int(v.PLEX_TO_KODI_TIMEFACTOR * float(offset)) if offset != '0' else None
if key.startswith('http') or key.startswith('{server}'):
xml = DU().downloadUrl(key)
xml = PF.get_playback_xml(key, app.CONN.server_name)
elif key.startswith('/system/services'):
xml = DU().downloadUrl('http://node.plexapp.com:32400%s' % key)
xml = PF.get_playback_xml('http://node.plexapp.com:32400%s' % key,
'plexapp.com',
authenticate=False,
token=app.ACCOUNT.plex_token)
else:
xml = DU().downloadUrl('{server}%s' % key)
try:
xml[0].attrib
except (TypeError, IndexError, AttributeError):
LOG.error('Could not download PMS metadata')
xml = PF.get_playback_xml('{server}%s' % key, app.CONN.server_name)
if xml is None:
_ensure_resolve(abort=True)
return
if offset != '0':
offset = int(v.PLEX_TO_KODI_TIMEFACTOR * float(offset))
# Todo: implement offset
api = API(xml[0])
listitem = transfer.PKCListItem()
api.create_listitem(listitem)
@ -469,19 +466,31 @@ def process_indirect(key, offset, resolve=True):
playqueue.clear()
item = PL.Playlist_Item()
item.xml = xml[0]
item.offset = int(offset)
item.offset = offset
item.plex_type = v.PLEX_TYPE_CLIP
item.playmethod = 'DirectStream'
# Need to get yet another xml to get the final playback url
xml = DU().downloadUrl('http://node.plexapp.com:32400%s'
% xml[0][0][0].attrib['key'])
try:
xml[0].attrib
xml = PF.get_playback_xml('http://node.plexapp.com:32400%s'
% xml[0][0][0].attrib['key'],
'plexapp.com',
authenticate=False,
token=app.ACCOUNT.plex_token)
except (TypeError, IndexError, AttributeError):
LOG.error('Could not download last xml for playurl')
LOG.error('XML malformed: %s', xml.attrib)
xml = None
if xml is None:
_ensure_resolve(abort=True)
return
try:
playurl = xml[0].attrib['key']
except (TypeError, IndexError, AttributeError):
LOG.error('Last xml malformed: %s', xml.attrib)
_ensure_resolve(abort=True)
return
item.file = playurl
listitem.setPath(utils.try_encode(playurl))
playqueue.items.append(item)

View file

@ -9,7 +9,7 @@ from copy import deepcopy
from time import time
from threading import Thread
from .downloadutils import DownloadUtils as DU
from .downloadutils import DownloadUtils as DU, exceptions
from . import backgroundthread, utils, plex_tv, variables as v, app
###############################################################################
@ -454,7 +454,7 @@ def _poke_pms(pms, queue):
url, pms['uuid'], xml.get('machineIdentifier'))
def GetPlexMetadata(key):
def GetPlexMetadata(key, reraise=False):
"""
Returns raw API metadata for key as an etree XML.
@ -481,20 +481,73 @@ def GetPlexMetadata(key):
# 'includeConcerts': 1
}
url = url + '?' + urlencode(arguments)
xml = DU().downloadUrl(url)
try:
xml = DU().downloadUrl(url, reraise=reraise)
except exceptions.RequestException:
# "PMS offline"
utils.dialog('notification',
utils.lang(29999),
utils.lang(39213).format(app.CONN.server_name),
icon='{plex}')
except Exception:
# "Error"
utils.dialog('notification',
utils.lang(29999),
utils.lang(30135),
icon='{error}')
else:
if xml == 401:
# Either unauthorized (taken care of by doUtils) or PMS under strain
return 401
# Did we receive a valid XML?
try:
xml.attrib
xml[0].attrib
# Nope we did not receive a valid XML
except AttributeError:
except (TypeError, IndexError, AttributeError):
LOG.error("Error retrieving metadata for %s", url)
xml = None
return xml
def get_playback_xml(url, server_name, authenticate=True, token=None):
"""
Returns None if something went wrong
"""
header_options = {'X-Plex-Token': token} if not authenticate else None
try:
xml = DU().downloadUrl(url,
authenticate=authenticate,
headerOptions=header_options,
reraise=True)
except exceptions.RequestException:
# "{0} offline"
utils.dialog('notification',
utils.lang(29999),
utils.lang(39213).format(server_name),
icon='{plex}')
except Exception as e:
LOG.error(e)
import traceback
LOG.error("Traceback:\n%s", traceback.format_exc())
# "Play error"
utils.dialog('notification',
utils.lang(29999),
utils.lang(30128),
icon='{error}')
else:
try:
xml[0].attrib
except (TypeError, IndexError, AttributeError):
LOG.error('Could not get a valid xml, unfortunately')
# "Play error"
utils.dialog('notification',
utils.lang(29999),
utils.lang(30128),
icon='{error}')
else:
return xml
def GetAllPlexChildren(key):
"""
Returns a list (raw xml API dump) of all Plex children for the key.