Improve error message when playback failes
This commit is contained in:
parent
63201db07d
commit
c7eab63960
4 changed files with 135 additions and 78 deletions
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue