Merge pull request #1636 from croneter/fix-streams

Large refactoring of playlist and playqueue code
This commit is contained in:
croneter 2021-09-24 17:27:21 +02:00 committed by GitHub
commit f4a0789fc0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 111 additions and 87 deletions

View file

@ -4,19 +4,13 @@ import sqlite3
from functools import wraps from functools import wraps
from . import variables as v, app from . import variables as v, app
from .exceptions import LockedDatabase
DB_WRITE_ATTEMPTS = 100 DB_WRITE_ATTEMPTS = 100
DB_WRITE_ATTEMPTS_TIMEOUT = 1 # in seconds DB_WRITE_ATTEMPTS_TIMEOUT = 1 # in seconds
DB_CONNECTION_TIMEOUT = 10 DB_CONNECTION_TIMEOUT = 10
class LockedDatabase(Exception):
"""
Dedicated class to make sure we're not silently catching locked DBs.
"""
pass
def catch_operationalerrors(method): def catch_operationalerrors(method):
""" """
sqlite.OperationalError is raised immediately if another DB connection sqlite.OperationalError is raised immediately if another DB connection

View file

@ -0,0 +1,32 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, unicode_literals
class PlaylistError(Exception):
"""
Exception for our playlist constructs
"""
pass
class LockedDatabase(Exception):
"""
Dedicated class to make sure we're not silently catching locked DBs.
"""
pass
class SubtitleError(Exception):
"""
Exceptions relating to subtitles
"""
pass
class ProcessingNotDone(Exception):
"""
Exception to detect whether we've completed our sync and did not have to
abort or suspend.
"""
pass

View file

@ -20,6 +20,7 @@ from .downloadutils import DownloadUtils as DU
from . import utils, timing, plex_functions as PF from . import utils, timing, plex_functions as PF
from . import json_rpc as js, playqueue as PQ, playlist_func as PL from . import json_rpc as js, playqueue as PQ, playlist_func as PL
from . import backgroundthread, app, variables as v from . import backgroundthread, app, variables as v
from . import exceptions
LOG = getLogger('PLEX.kodimonitor') LOG = getLogger('PLEX.kodimonitor')
@ -30,7 +31,7 @@ class KodiMonitor(xbmc.Monitor):
""" """
def __init__(self): def __init__(self):
self._already_slept = False self._already_slept = False
self._switch_to_plex_streams = None self._switched_to_plex_streams = True
xbmc.Monitor.__init__(self) xbmc.Monitor.__init__(self)
for playerid in app.PLAYSTATE.player_states: for playerid in app.PLAYSTATE.player_states:
app.PLAYSTATE.player_states[playerid] = copy.deepcopy(app.PLAYSTATE.template) app.PLAYSTATE.player_states[playerid] = copy.deepcopy(app.PLAYSTATE.template)
@ -68,7 +69,7 @@ class KodiMonitor(xbmc.Monitor):
self.PlayBackStart(data) self.PlayBackStart(data)
elif method == 'Player.OnAVChange': elif method == 'Player.OnAVChange':
with app.APP.lock_playqueues: with app.APP.lock_playqueues:
self.on_av_change() self._on_av_change(data)
elif method == "Player.OnStop": elif method == "Player.OnStop":
with app.APP.lock_playqueues: with app.APP.lock_playqueues:
_playback_cleanup(ended=data.get('end')) _playback_cleanup(ended=data.get('end'))
@ -181,7 +182,7 @@ class KodiMonitor(xbmc.Monitor):
try: try:
for i, item in enumerate(items): for i, item in enumerate(items):
PL.add_item_to_plex_playqueue(playqueue, i + 1, kodi_item=item) PL.add_item_to_plex_playqueue(playqueue, i + 1, kodi_item=item)
except PL.PlaylistError: except exceptions.PlaylistError:
LOG.info('Could not build Plex playlist for: %s', items) LOG.info('Could not build Plex playlist for: %s', items)
def _json_item(self, playerid): def _json_item(self, playerid):
@ -318,7 +319,7 @@ class KodiMonitor(xbmc.Monitor):
return return
try: try:
item = PL.init_plex_playqueue(playqueue, plex_id=plex_id) item = PL.init_plex_playqueue(playqueue, plex_id=plex_id)
except PL.PlaylistError: except exceptions.PlaylistError:
LOG.info('Could not initialize the Plex playlist') LOG.info('Could not initialize the Plex playlist')
return return
item.file = path item.file = path
@ -343,8 +344,7 @@ class KodiMonitor(xbmc.Monitor):
container_key = '/library/metadata/%s' % plex_id container_key = '/library/metadata/%s' % plex_id
# Mechanik for Plex skip intro feature # Mechanik for Plex skip intro feature
if utils.settings('enableSkipIntro') == 'true': if utils.settings('enableSkipIntro') == 'true':
api = API(item.xml) status['intro_markers'] = item.api.intro_markers()
status['intro_markers'] = api.intro_markers()
# Remember the currently playing item # Remember the currently playing item
app.PLAYSTATE.item = item app.PLAYSTATE.item = item
# Remember that this player has been active # Remember that this player has been active
@ -359,32 +359,36 @@ class KodiMonitor(xbmc.Monitor):
status['plex_type'] = plex_type status['plex_type'] = plex_type
status['playmethod'] = item.playmethod status['playmethod'] = item.playmethod
status['playcount'] = item.playcount status['playcount'] = item.playcount
try:
status['external_player'] = app.APP.player.isExternalPlayer() == 1 status['external_player'] = app.APP.player.isExternalPlayer() == 1
except AttributeError:
# Kodi version < 17
pass
LOG.debug('Set the player state: %s', status) LOG.debug('Set the player state: %s', status)
# Workaround for the Kodi add-on Up Next # Workaround for the Kodi add-on Up Next
if not app.SYNC.direct_paths: if not app.SYNC.direct_paths:
_notify_upnext(item) _notify_upnext(item)
self._switch_to_plex_streams = item self._switched_to_plex_streams = False
def on_av_change(self): def _on_av_change(self, data):
""" """
Will be called when Kodi has a video, audio or subtitle stream. Also Will be called when Kodi has a video, audio or subtitle stream. Also
happens when the stream changes. happens when the stream changes.
Example data as returned by Kodi:
{'item': {'id': 5, 'type': 'movie'},
'player': {'playerid': 1, 'speed': 1}}
""" """
if self._switch_to_plex_streams is not None: if not self._switched_to_plex_streams:
self.switch_to_plex_streams(self._switch_to_plex_streams) self.switch_to_plex_streams()
self._switch_to_plex_streams = None self._switched_to_plex_streams = True
@staticmethod @staticmethod
def switch_to_plex_streams(item): def switch_to_plex_streams():
""" """
Override Kodi audio and subtitle streams with Plex PMS' selection Override Kodi audio and subtitle streams with Plex PMS' selection
""" """
item = app.PLAYSTATE.item
if item is None:
# Player might've quit
return
for typus in ('audio', 'subtitle'): for typus in ('audio', 'subtitle'):
try: try:
plex_index, language_tag = item.active_plex_stream_index(typus) plex_index, language_tag = item.active_plex_stream_index(typus)
@ -588,11 +592,10 @@ def _next_episode(current_api):
current_api.grandparent_title()) current_api.grandparent_title())
return return
try: try:
next_api = API(xml[counter + 1]) return API(xml[counter + 1])
except IndexError: except IndexError:
# Was the last episode # Was the last episode
return pass
return next_api
def _complete_artwork_keys(info): def _complete_artwork_keys(info):
@ -618,7 +621,7 @@ def _notify_upnext(item):
""" """
if not item.plex_type == v.PLEX_TYPE_EPISODE: if not item.plex_type == v.PLEX_TYPE_EPISODE:
return return
this_api = API(item.xml) this_api = item.api
next_api = _next_episode(this_api) next_api = _next_episode(this_api)
if next_api is None: if next_api is None:
return return

View file

@ -16,6 +16,7 @@ from .kodi_db import KodiVideoDB
from . import plex_functions as PF, playlist_func as PL, playqueue as PQ from . import plex_functions as PF, playlist_func as PL, playqueue as PQ
from . import json_rpc as js, variables as v, utils, transfer from . import json_rpc as js, variables as v, utils, transfer
from . import playback_decision, app from . import playback_decision, app
from . import exceptions
############################################################################### ###############################################################################
LOG = getLogger('PLEX.playback') LOG = getLogger('PLEX.playback')
@ -192,7 +193,7 @@ def _playback_init(plex_id, plex_type, playqueue, pos, resume):
# Special case - we already got a filled Kodi playqueue # Special case - we already got a filled Kodi playqueue
try: try:
_init_existing_kodi_playlist(playqueue, pos) _init_existing_kodi_playlist(playqueue, pos)
except PL.PlaylistError: except exceptions.PlaylistError:
LOG.error('Playback_init for existing Kodi playlist failed') LOG.error('Playback_init for existing Kodi playlist failed')
_ensure_resolve(abort=True) _ensure_resolve(abort=True)
return return
@ -312,7 +313,7 @@ def _init_existing_kodi_playlist(playqueue, pos):
kodi_items = js.playlist_get_items(playqueue.playlistid) kodi_items = js.playlist_get_items(playqueue.playlistid)
if not kodi_items: if not kodi_items:
LOG.error('No Kodi items returned') LOG.error('No Kodi items returned')
raise PL.PlaylistError('No Kodi items returned') raise exceptions.PlaylistError('No Kodi items returned')
item = PL.init_plex_playqueue(playqueue, kodi_item=kodi_items[pos]) item = PL.init_plex_playqueue(playqueue, kodi_item=kodi_items[pos])
item.force_transcode = app.PLAYSTATE.force_transcode item.force_transcode = app.PLAYSTATE.force_transcode
# playqueue.py will add the rest - this will likely put the PMS under # playqueue.py will add the rest - this will likely put the PMS under
@ -444,27 +445,26 @@ def _conclude_playback(playqueue, pos):
""" """
LOG.debug('Concluding playback for playqueue position %s', pos) LOG.debug('Concluding playback for playqueue position %s', pos)
item = playqueue.items[pos] item = playqueue.items[pos]
api = API(item.xml) if item.api.mediastream_number() is None:
if api.mediastream_number() is None:
# E.g. user could choose between several media streams and cancelled # E.g. user could choose between several media streams and cancelled
LOG.debug('Did not get a mediastream_number') LOG.debug('Did not get a mediastream_number')
_ensure_resolve() _ensure_resolve()
return return
api.part = item.part or 0 item.api.part = item.part or 0
playback_decision.set_pkc_playmethod(api, item) playback_decision.set_pkc_playmethod(item.api, item)
if not playback_decision.audio_subtitle_prefs(api, item): if not playback_decision.audio_subtitle_prefs(item.api, item):
LOG.info('Did not set audio subtitle prefs, aborting silently') LOG.info('Did not set audio subtitle prefs, aborting silently')
_ensure_resolve() _ensure_resolve()
return return
playback_decision.set_playurl(api, item) playback_decision.set_playurl(item.api, item)
if not item.file: if not item.file:
LOG.info('Did not get a playurl, aborting playback silently') LOG.info('Did not get a playurl, aborting playback silently')
_ensure_resolve() _ensure_resolve()
return return
listitem = api.listitem(listitem=transfer.PKCListItem, resume=False) listitem = item.api.listitem(listitem=transfer.PKCListItem, resume=False)
listitem.setPath(item.file.encode('utf-8')) listitem.setPath(item.file.encode('utf-8'))
if item.playmethod != v.PLAYBACK_METHOD_DIRECT_PATH: if item.playmethod != v.PLAYBACK_METHOD_DIRECT_PATH:
listitem.setSubtitles(api.cache_external_subs()) listitem.setSubtitles(item.api.cache_external_subs())
transfer.send(listitem) transfer.send(listitem)
LOG.debug('Done concluding playback') LOG.debug('Done concluding playback')

View file

@ -15,19 +15,13 @@ from . import utils
from . import json_rpc as js from . import json_rpc as js
from . import variables as v from . import variables as v
from . import app from . import app
from .exceptions import PlaylistError
from .subtitles import accessible_plex_subtitles from .subtitles import accessible_plex_subtitles
LOG = getLogger('PLEX.playlist_func') LOG = getLogger('PLEX.playlist_func')
class PlaylistError(Exception):
"""
Exception for our playlist constructs
"""
pass
class Playqueue_Object(object): class Playqueue_Object(object):
""" """
PKC object to represent PMS playQueues and Kodi playlist for queueing PKC object to represent PMS playQueues and Kodi playlist for queueing
@ -155,13 +149,14 @@ class PlaylistItem(object):
file = None [str] Path to the item's file. STRING!! file = None [str] Path to the item's file. STRING!!
uri = None [str] PMS path to item; will be auto-set with plex_id uri = None [str] PMS path to item; will be auto-set with plex_id
guid = None [str] Weird Plex guid guid = None [str] Weird Plex guid
xml = None [etree] XML from PMS, 1 lvl below <MediaContainer> api = None [API] API of xml 1 lvl below <MediaContainer>
playmethod = None [str] either 'DirectPath', 'DirectStream', 'Transcode' playmethod = None [str] either 'DirectPath', 'DirectStream', 'Transcode'
playcount = None [int] how many times the item has already been played playcount = None [int] how many times the item has already been played
offset = None [int] the item's view offset UPON START in Plex time offset = None [int] the item's view offset UPON START in Plex time
part = 0 [int] part number if Plex video consists of mult. parts part = 0 [int] part number if Plex video consists of mult. parts
force_transcode [bool] defaults to False force_transcode [bool] defaults to False
""" """
def __init__(self): def __init__(self):
self.id = None self.id = None
self._plex_id = None self._plex_id = None
@ -171,7 +166,7 @@ class PlaylistItem(object):
self.file = None self.file = None
self._uri = None self._uri = None
self.guid = None self.guid = None
self.xml = None self.api = None
self.playmethod = None self.playmethod = None
self.playcount = None self.playcount = None
self.offset = None self.offset = None
@ -232,10 +227,10 @@ class PlaylistItem(object):
count = 0 count = 0
if kodi_stream_index == -1: if kodi_stream_index == -1:
# Kodi telling us "it's the last one" # Kodi telling us "it's the last one"
iterator = list(reversed(self.xml[0][self.part])) iterator = list(reversed(self.api.plex_media_streams()))
kodi_stream_index = 0 kodi_stream_index = 0
else: else:
iterator = self.xml[0][self.part] iterator = self.api.plex_media_streams()
# Kodi indexes differently than Plex # Kodi indexes differently than Plex
for stream in iterator: for stream in iterator:
if (stream.get('streamType') == stream_type and if (stream.get('streamType') == stream_type and
@ -276,7 +271,7 @@ class PlaylistItem(object):
Returns None if no stream has been selected Returns None if no stream has been selected
""" """
stream_type = v.PLEX_STREAM_TYPE_FROM_STREAM_TYPE[stream_type] stream_type = v.PLEX_STREAM_TYPE_FROM_STREAM_TYPE[stream_type]
for stream in self.xml[0][self.part]: for stream in self.api.plex_media_streams():
if stream.get('streamType') == stream_type \ if stream.get('streamType') == stream_type \
and stream.get('selected') == '1': and stream.get('selected') == '1':
return (utils.cast(int, stream.get('id')), return (utils.cast(int, stream.get('id')),
@ -293,9 +288,9 @@ class PlaylistItem(object):
if stream_type == '3': if stream_type == '3':
streams = accessible_plex_subtitles(self.playmethod, streams = accessible_plex_subtitles(self.playmethod,
self.file, self.file,
self.xml[0][self.part]) self.api.plex_media_streams())
else: else:
streams = [x for x in self.xml[0][self.part] streams = [x for x in self.api.plex_media_streams()
if x.get('streamType') == stream_type] if x.get('streamType') == stream_type]
return streams return streams
@ -421,14 +416,15 @@ def playlist_item_from_xml(xml_video_element, kodi_id=None, kodi_type=None):
item.guid = api.guid_html_escaped() item.guid = api.guid_html_escaped()
item.playcount = api.viewcount() item.playcount = api.viewcount()
item.offset = api.resume_point() item.offset = api.resume_point()
item.xml = xml_video_element item.api = api
LOG.debug('Created new playlist item from xml: %s', item) LOG.debug('Created new playlist item from xml: %s', item)
return item return item
def _get_playListVersion_from_xml(playlist, xml): def _update_playlist_version(playlist, xml):
""" """
Takes a PMS xml as input to overwrite the playlist version (e.g. Plex Takes a PMS xml (one level above the xml-depth where we're usually applying
API()) as input to overwrite the playlist version (e.g. Plex
playQueueVersion). playQueueVersion).
Raises PlaylistError if unsuccessful Raises PlaylistError if unsuccessful
@ -611,7 +607,7 @@ def add_item_to_plex_playqueue(playlist, pos, plex_id=None, kodi_item=None):
raise PlaylistError('Could not add item %s to playlist %s' raise PlaylistError('Could not add item %s to playlist %s'
% (kodi_item, playlist)) % (kodi_item, playlist))
api = API(xml[-1]) api = API(xml[-1])
item.xml = xml[-1] item.api = api
item.id = api.item_id() item.id = api.item_id()
item.guid = api.guid_html_escaped() item.guid = api.guid_html_escaped()
item.offset = api.resume_point() item.offset = api.resume_point()
@ -619,7 +615,7 @@ def add_item_to_plex_playqueue(playlist, pos, plex_id=None, kodi_item=None):
playlist.items.append(item) playlist.items.append(item)
if pos == len(playlist.items) - 1: if pos == len(playlist.items) - 1:
# Item was added at the end # Item was added at the end
_get_playListVersion_from_xml(playlist, xml) _update_playlist_version(playlist, xml)
else: else:
# Move the new item to the correct position # Move the new item to the correct position
move_playlist_item(playlist, move_playlist_item(playlist,
@ -663,7 +659,7 @@ def add_item_to_kodi_playlist(playlist, pos, kodi_id=None, kodi_type=None,
{'id': kodi_id, 'type': kodi_type, 'file': file}) {'id': kodi_id, 'type': kodi_type, 'file': file})
if item.plex_id is not None: if item.plex_id is not None:
xml = PF.GetPlexMetadata(item.plex_id) xml = PF.GetPlexMetadata(item.plex_id)
item.xml = xml[-1] item.api = API(xml[-1])
playlist.items.insert(pos, item) playlist.items.insert(pos, item)
return item return item
@ -687,9 +683,10 @@ def move_playlist_item(playlist, before_pos, after_pos):
playlist.id, playlist.id,
playlist.items[before_pos].id, playlist.items[before_pos].id,
playlist.items[after_pos - 1].id) playlist.items[after_pos - 1].id)
# We need to increment the playlistVersion # Tell the PMS that we're moving items around
_get_playListVersion_from_xml( xml = DU().downloadUrl(url, action_type="PUT")
playlist, DU().downloadUrl(url, action_type="PUT")) # We need to increment the playlist version for communicating with the PMS
_update_playlist_version(playlist, xml)
# Move our item's position in our internal playlist # Move our item's position in our internal playlist
playlist.items.insert(after_pos, playlist.items.pop(before_pos)) playlist.items.insert(after_pos, playlist.items.pop(before_pos))
LOG.debug('Done moving for %s', playlist) LOG.debug('Done moving for %s', playlist)
@ -737,7 +734,7 @@ def delete_playlist_item_from_PMS(playlist, pos):
playlist.repeat), playlist.repeat),
action_type="DELETE") action_type="DELETE")
del playlist.items[pos] del playlist.items[pos]
_get_playListVersion_from_xml(playlist, xml) _update_playlist_version(playlist, xml)
# Functions operating on the Kodi playlist objects ########## # Functions operating on the Kodi playlist objects ##########

View file

@ -15,13 +15,13 @@ from __future__ import absolute_import, division, unicode_literals
from logging import getLogger from logging import getLogger
from sqlite3 import OperationalError from sqlite3 import OperationalError
from .common import Playlist, PlaylistError, PlaylistObserver, \ from .common import Playlist, PlaylistObserver, kodi_playlist_hash
kodi_playlist_hash
from . import pms, db, kodi_pl, plex_pl from . import pms, db, kodi_pl, plex_pl
from ..watchdog import events from ..watchdog import events
from ..plex_api import API from ..plex_api import API
from .. import utils, path_ops, variables as v, app from .. import utils, path_ops, variables as v, app
from ..exceptions import PlaylistError
############################################################################### ###############################################################################
LOG = getLogger('PLEX.playlists') LOG = getLogger('PLEX.playlists')

View file

@ -12,6 +12,8 @@ from ..watchdog.observers import Observer
from ..watchdog.utils.bricks import OrderedSetQueue from ..watchdog.utils.bricks import OrderedSetQueue
from .. import path_ops, variables as v, app from .. import path_ops, variables as v, app
from ..exceptions import PlaylistError
############################################################################### ###############################################################################
LOG = getLogger('PLEX.playlists.common') LOG = getLogger('PLEX.playlists.common')
@ -20,13 +22,6 @@ SIMILAR_EVENTS = (events.EVENT_TYPE_CREATED, events.EVENT_TYPE_MODIFIED)
############################################################################### ###############################################################################
class PlaylistError(Exception):
"""
The one main exception thrown if anything goes awry
"""
pass
class Playlist(object): class Playlist(object):
""" """
Class representing a synced Playlist with info for both Kodi and Plex. Class representing a synced Playlist with info for both Kodi and Plex.

View file

@ -7,10 +7,11 @@ module
from __future__ import absolute_import, division, unicode_literals from __future__ import absolute_import, division, unicode_literals
from logging import getLogger from logging import getLogger
from .common import Playlist, PlaylistError from .common import Playlist
from ..plex_db import PlexDB from ..plex_db import PlexDB
from ..kodi_db import kodiid_from_filename from ..kodi_db import kodiid_from_filename
from .. import path_ops, utils, variables as v from .. import path_ops, utils, variables as v
from ..exceptions import PlaylistError
############################################################################### ###############################################################################
LOG = getLogger('PLEX.playlists.db') LOG = getLogger('PLEX.playlists.db')
@ -121,7 +122,7 @@ def m3u_to_plex_ids(playlist):
def playlist_file_to_plex_ids(playlist): def playlist_file_to_plex_ids(playlist):
""" """
Takes the playlist file located at path [unicode] and parses it. Takes the playlist file located at path [unicode] and parses it.
Returns a list of plex_ids (str) or raises PL.PlaylistError if a single Returns a list of plex_ids (str) or raises PlaylistError if a single
item cannot be parsed from Kodi to Plex. item cannot be parsed from Kodi to Plex.
""" """
if playlist.kodi_extension == 'm3u': if playlist.kodi_extension == 'm3u':

View file

@ -7,11 +7,13 @@ from __future__ import absolute_import, division, unicode_literals
from logging import getLogger from logging import getLogger
import re import re
from .common import Playlist, PlaylistError, kodi_playlist_hash from .common import Playlist, kodi_playlist_hash
from . import db, pms from . import db, pms
from ..plex_api import API from ..plex_api import API
from .. import utils, path_ops, variables as v from .. import utils, path_ops, variables as v
from ..exceptions import PlaylistError
############################################################################### ###############################################################################
LOG = getLogger('PLEX.playlists.kodi_pl') LOG = getLogger('PLEX.playlists.kodi_pl')
REGEX_FILE_NUMBERING = re.compile(r'''_(\d\d)\.\w+$''') REGEX_FILE_NUMBERING = re.compile(r'''_(\d\d)\.\w+$''')

View file

@ -6,8 +6,9 @@ Create and delete playlists on the Plex side of things
from __future__ import absolute_import, division, unicode_literals from __future__ import absolute_import, division, unicode_literals
from logging import getLogger from logging import getLogger
from .common import PlaylistError
from . import pms, db from . import pms, db
from ..exceptions import PlaylistError
############################################################################### ###############################################################################
LOG = getLogger('PLEX.playlists.plex_pl') LOG = getLogger('PLEX.playlists.plex_pl')
# Used for updating Plex playlists due to Kodi changes - Plex playlist # Used for updating Plex playlists due to Kodi changes - Plex playlist

View file

@ -7,11 +7,11 @@ manipulate playlists
from __future__ import absolute_import, division, unicode_literals from __future__ import absolute_import, division, unicode_literals
from logging import getLogger from logging import getLogger
from .common import PlaylistError
from ..plex_api import API from ..plex_api import API
from ..downloadutils import DownloadUtils as DU from ..downloadutils import DownloadUtils as DU
from .. import utils, app, variables as v from .. import utils, app, variables as v
from ..exceptions import PlaylistError
############################################################################### ###############################################################################
LOG = getLogger('PLEX.playlists.pms') LOG = getLogger('PLEX.playlists.pms')

View file

@ -12,6 +12,7 @@ import xbmc
from .plex_api import API from .plex_api import API
from . import playlist_func as PL, plex_functions as PF from . import playlist_func as PL, plex_functions as PF
from . import backgroundthread, utils, json_rpc as js, app, variables as v from . import backgroundthread, utils, json_rpc as js, app, variables as v
from . import exceptions
############################################################################### ###############################################################################
LOG = getLogger('PLEX.playqueue') LOG = getLogger('PLEX.playqueue')
@ -88,7 +89,7 @@ def init_playqueue_from_plex_children(plex_id, transient_token=None):
api = API(child) api = API(child)
try: try:
PL.add_item_to_playlist(playqueue, i, plex_id=api.plex_id) PL.add_item_to_playlist(playqueue, i, plex_id=api.plex_id)
except PL.PlaylistError: except exceptions.PlaylistError:
LOG.error('Could not add Plex item to our playlist: %s, %s', LOG.error('Could not add Plex item to our playlist: %s, %s',
child.tag, child.attrib) child.tag, child.attrib)
playqueue.plex_transient_token = transient_token playqueue.plex_transient_token = transient_token
@ -151,7 +152,7 @@ class PlayqueueMonitor(backgroundthread.KillableThread):
i + j, i) i + j, i)
try: try:
PL.move_playlist_item(playqueue, i + j, i) PL.move_playlist_item(playqueue, i + j, i)
except PL.PlaylistError: except exceptions.PlaylistError:
LOG.error('Could not modify playqueue positions') LOG.error('Could not modify playqueue positions')
LOG.error('This is likely caused by mixing audio and ' LOG.error('This is likely caused by mixing audio and '
'video tracks in the Kodi playqueue') 'video tracks in the Kodi playqueue')
@ -167,7 +168,7 @@ class PlayqueueMonitor(backgroundthread.KillableThread):
PL.add_item_to_plex_playqueue(playqueue, PL.add_item_to_plex_playqueue(playqueue,
i, i,
kodi_item=new_item) kodi_item=new_item)
except PL.PlaylistError: except exceptions.PlaylistError:
# Could not add the element # Could not add the element
pass pass
except KeyError: except KeyError:
@ -196,7 +197,7 @@ class PlayqueueMonitor(backgroundthread.KillableThread):
LOG.debug('Detected deletion of playqueue element at pos %s', i) LOG.debug('Detected deletion of playqueue element at pos %s', i)
try: try:
PL.delete_playlist_item_from_PMS(playqueue, i) PL.delete_playlist_item_from_PMS(playqueue, i)
except PL.PlaylistError: except exceptions.PlaylistError:
LOG.error('Could not delete PMS element from position %s', i) LOG.error('Could not delete PMS element from position %s', i)
LOG.error('This is likely caused by mixing audio and ' LOG.error('This is likely caused by mixing audio and '
'video tracks in the Kodi playqueue') 'video tracks in the Kodi playqueue')

View file

@ -21,6 +21,7 @@ from . import playqueue as PQ
from . import variables as v from . import variables as v
from . import backgroundthread from . import backgroundthread
from . import app from . import app
from . import exceptions
############################################################################### ###############################################################################
@ -51,7 +52,7 @@ def update_playqueue_from_PMS(playqueue,
with app.APP.lock_playqueues: with app.APP.lock_playqueues:
try: try:
xml = PL.get_PMS_playlist(playqueue, playqueue_id) xml = PL.get_PMS_playlist(playqueue, playqueue_id)
except PL.PlaylistError: except exceptions.PlaylistError:
LOG.error('Could now download playqueue %s', playqueue_id) LOG.error('Could now download playqueue %s', playqueue_id)
return return
if playqueue.id == playqueue_id: if playqueue.id == playqueue_id:
@ -64,7 +65,7 @@ def update_playqueue_from_PMS(playqueue,
# Get new metadata for the playqueue first # Get new metadata for the playqueue first
try: try:
PL.get_playlist_details_from_xml(playqueue, xml) PL.get_playlist_details_from_xml(playqueue, xml)
except PL.PlaylistError: except exceptions.PlaylistError:
LOG.error('Could not get playqueue ID %s', playqueue_id) LOG.error('Could not get playqueue ID %s', playqueue_id)
return return
playqueue.repeat = 0 if not repeat else int(repeat) playqueue.repeat = 0 if not repeat else int(repeat)

View file

@ -9,6 +9,7 @@ import xml.etree.ElementTree as etree
from . import app from . import app
from . import path_ops from . import path_ops
from . import variables as v from . import variables as v
from .exceptions import SubtitleError
LOG = getLogger('PLEX.subtitles') LOG = getLogger('PLEX.subtitles')
@ -467,7 +468,3 @@ def external_subs_from_filesystem(dirname, filename):
class DummySub(etree.Element): class DummySub(etree.Element):
def __init__(self): def __init__(self):
super(DummySub, self).__init__('Stream-subtitle-dummy') super(DummySub, self).__init__('Stream-subtitle-dummy')
class SubtitleError(Exception):
pass