Merge pull request #1626 from croneter/py3-streams

Large refactoring of playlist and playqueue code
This commit is contained in:
croneter 2021-09-13 13:37:19 +02:00 committed by GitHub
commit bce51224f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 112 additions and 93 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,31 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
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

@ -19,6 +19,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')
@ -29,7 +30,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)
@ -67,7 +68,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'))
@ -180,7 +181,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):
@ -317,7 +318,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
@ -342,8 +343,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
@ -358,32 +358,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)
@ -587,11 +591,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):
@ -617,7 +620,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

@ -5,6 +5,7 @@ from . import additional_metadata_tmdb
from ..plex_db import PlexDB from ..plex_db import PlexDB
from .. import backgroundthread, utils from .. import backgroundthread, utils
from .. import variables as v, app from .. import variables as v, app
from ..exceptions import ProcessingNotDone
logger = getLogger('PLEX.sync.metadata') logger = getLogger('PLEX.sync.metadata')
@ -22,12 +23,6 @@ SUPPORTED_METADATA = {
} }
class ProcessingNotDone(Exception):
"""Exception to detect whether we've completed our sync and did not have to
abort or suspend."""
pass
def processing_is_activated(item_getter): def processing_is_activated(item_getter):
"""Checks the PKC settings whether processing is even activated.""" """Checks the PKC settings whether processing is even activated."""
if item_getter == 'missing_fanart': if item_getter == 'missing_fanart':

View file

@ -15,6 +15,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')
@ -191,7 +192,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
@ -311,7 +312,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
@ -443,27 +444,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) listitem.setPath(item.file)
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

@ -14,19 +14,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
@ -150,13 +144,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
@ -166,7 +161,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
@ -224,10 +219,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
@ -268,7 +263,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')),
@ -285,9 +280,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
@ -413,14 +408,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
@ -603,7 +599,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()
@ -611,7 +607,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,
@ -655,7 +651,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
@ -679,9 +675,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)
@ -729,7 +726,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

@ -14,13 +14,13 @@
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

@ -11,6 +11,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')
@ -19,13 +21,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

@ -6,10 +6,12 @@ module
""" """
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 utils, variables as v from .. import utils, variables as v
from ..exceptions import PlaylistError
############################################################################### ###############################################################################
LOG = getLogger('PLEX.playlists.db') LOG = getLogger('PLEX.playlists.db')
@ -120,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

@ -6,11 +6,13 @@ Create and delete playlists on the Kodi side of things
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

@ -5,8 +5,9 @@ Create and delete playlists on the Plex side of things
""" """
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

@ -6,11 +6,11 @@ manipulate playlists
""" """
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

@ -11,6 +11,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')
@ -87,7 +88,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
@ -150,7 +151,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')
@ -166,7 +167,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:
@ -195,7 +196,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

@ -20,6 +20,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
############################################################################### ###############################################################################
@ -50,7 +51,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:
@ -63,7 +64,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

@ -8,6 +8,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')
@ -466,7 +467,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