Replace cPickle communication with JSON
This commit is contained in:
parent
67db141d73
commit
69cb09e009
9 changed files with 178 additions and 155 deletions
|
@ -40,9 +40,10 @@ def main():
|
|||
'kodi_id': kodi_id,
|
||||
'kodi_type': kodi_type
|
||||
}
|
||||
while window.getProperty('plex_command'):
|
||||
while window.getProperty('plexkodiconnect.command'):
|
||||
sleep(20)
|
||||
window.setProperty('plex_command', 'CONTEXT_menu?%s' % urlencode(args))
|
||||
window.setProperty('plexkodiconnect.command',
|
||||
'CONTEXT_menu?%s' % urlencode(args))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
77
default.py
77
default.py
|
@ -5,18 +5,18 @@ from __future__ import absolute_import, division, unicode_literals
|
|||
import logging
|
||||
from sys import argv
|
||||
from urlparse import parse_qsl
|
||||
from xbmc import sleep, executebuiltin
|
||||
from xbmcgui import ListItem, getCurrentWindowId
|
||||
from xbmcplugin import setResolvedUrl
|
||||
|
||||
from resources.lib import entrypoint, utils, pickler, pkc_listitem, \
|
||||
variables as v, loghandler
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
import xbmcplugin
|
||||
|
||||
from resources.lib import entrypoint, utils, transfer, variables as v, loghandler
|
||||
from resources.lib.tools import unicode_paths
|
||||
|
||||
###############################################################################
|
||||
|
||||
loghandler.config()
|
||||
log = logging.getLogger('PLEX.default')
|
||||
LOG = logging.getLogger('PLEX.default')
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -27,7 +27,7 @@ class Main():
|
|||
# MAIN ENTRY POINT
|
||||
# @utils.profiling()
|
||||
def __init__(self):
|
||||
log.debug('Full sys.argv received: %s', argv)
|
||||
LOG.debug('Full sys.argv received: %s', argv)
|
||||
# Parse parameters
|
||||
path = unicode_paths.decode(argv[0])
|
||||
arguments = unicode_paths.decode(argv[2])
|
||||
|
@ -73,23 +73,23 @@ class Main():
|
|||
# Hack so we can store this path in the Kodi DB
|
||||
handle = ('plugin://%s?mode=extras&plex_id=%s'
|
||||
% (v.ADDON_ID, params.get('plex_id')))
|
||||
if getCurrentWindowId() == 10025:
|
||||
if xbmcgui.getCurrentWindowId() == 10025:
|
||||
# Video Window
|
||||
executebuiltin('Container.Update(\"%s\")' % handle)
|
||||
xbmc.executebuiltin('Container.Update(\"%s\")' % handle)
|
||||
else:
|
||||
executebuiltin('ActivateWindow(videos, \"%s\")' % handle)
|
||||
xbmc.executebuiltin('ActivateWindow(videos, \"%s\")' % handle)
|
||||
|
||||
elif mode == 'extras':
|
||||
entrypoint.extras(plex_id=params.get('plex_id'))
|
||||
|
||||
elif mode == 'settings':
|
||||
executebuiltin('Addon.OpenSettings(%s)' % v.ADDON_ID)
|
||||
xbmc.executebuiltin('Addon.OpenSettings(%s)' % v.ADDON_ID)
|
||||
|
||||
elif mode == 'enterPMS':
|
||||
entrypoint.create_new_pms()
|
||||
|
||||
elif mode == 'reset':
|
||||
utils.plex_command('RESET-PKC')
|
||||
transfer.plex_command('RESET-PKC')
|
||||
|
||||
elif mode == 'togglePlexTV':
|
||||
entrypoint.toggle_plex_tv_sign_in()
|
||||
|
@ -102,15 +102,15 @@ class Main():
|
|||
|
||||
elif mode in ('manualsync', 'repair'):
|
||||
if mode == 'repair':
|
||||
log.info('Requesting repair lib sync')
|
||||
utils.plex_command('repair-scan')
|
||||
LOG.info('Requesting repair lib sync')
|
||||
transfer.plex_command('repair-scan')
|
||||
elif mode == 'manualsync':
|
||||
log.info('Requesting full library scan')
|
||||
utils.plex_command('full-scan')
|
||||
LOG.info('Requesting full library scan')
|
||||
transfer.plex_command('full-scan')
|
||||
|
||||
elif mode == 'texturecache':
|
||||
log.info('Requesting texture caching of all textures')
|
||||
utils.plex_command('textures-scan')
|
||||
LOG.info('Requesting texture caching of all textures')
|
||||
transfer.plex_command('textures-scan')
|
||||
|
||||
elif mode == 'chooseServer':
|
||||
entrypoint.choose_pms_server()
|
||||
|
@ -119,8 +119,8 @@ class Main():
|
|||
self.deviceid()
|
||||
|
||||
elif mode == 'fanart':
|
||||
log.info('User requested fanarttv refresh')
|
||||
utils.plex_command('fanart-scan')
|
||||
LOG.info('User requested fanarttv refresh')
|
||||
transfer.plex_command('fanart-scan')
|
||||
|
||||
elif '/extrafanart' in path:
|
||||
plexpath = arguments[1:]
|
||||
|
@ -150,51 +150,52 @@ class Main():
|
|||
"""
|
||||
request = '%s&handle=%s' % (argv[2], HANDLE)
|
||||
# Put the request into the 'queue'
|
||||
utils.plex_command('PLAY-%s' % request)
|
||||
transfer.plex_command('PLAY-%s' % request)
|
||||
if HANDLE == -1:
|
||||
# Handle -1 received, not waiting for main thread
|
||||
return
|
||||
# Wait for the result
|
||||
while not pickler.pickl_window('plex_result'):
|
||||
sleep(50)
|
||||
result = pickler.unpickle_me()
|
||||
# Wait for the result from the main PKC thread
|
||||
result = transfer.wait_for_transfer()
|
||||
if result is None:
|
||||
log.error('Error encountered, aborting')
|
||||
LOG.error('Error encountered, aborting')
|
||||
utils.dialog('notification',
|
||||
heading='{plex}',
|
||||
message=utils.lang(30128),
|
||||
icon='{error}',
|
||||
time=3000)
|
||||
setResolvedUrl(HANDLE, False, ListItem())
|
||||
elif result.listitem:
|
||||
listitem = pkc_listitem.convert_pkc_to_listitem(result.listitem)
|
||||
setResolvedUrl(HANDLE, True, listitem)
|
||||
xbmcplugin.setResolvedUrl(HANDLE, False, xbmcgui.ListItem())
|
||||
elif result is True:
|
||||
pass
|
||||
else:
|
||||
# Received a xbmcgui.ListItem()
|
||||
xbmcplugin.setResolvedUrl(HANDLE, True, result)
|
||||
|
||||
@staticmethod
|
||||
def deviceid():
|
||||
deviceId_old = pickler.pickl_window('plex_client_Id')
|
||||
window = xbmcgui.Window(10000)
|
||||
deviceId_old = window.getProperty('plex_client_Id')
|
||||
from resources.lib import clientinfo
|
||||
try:
|
||||
deviceId = clientinfo.getDeviceId(reset=True)
|
||||
except Exception as e:
|
||||
log.error('Failed to generate a new device Id: %s' % e)
|
||||
LOG.error('Failed to generate a new device Id: %s' % e)
|
||||
utils.messageDialog(utils.lang(29999), utils.lang(33032))
|
||||
else:
|
||||
log.info('Successfully removed old device ID: %s New deviceId:'
|
||||
LOG.info('Successfully removed old device ID: %s New deviceId:'
|
||||
'%s' % (deviceId_old, deviceId))
|
||||
# 'Kodi will now restart to apply the changes'
|
||||
utils.messageDialog(utils.lang(29999), utils.lang(33033))
|
||||
executebuiltin('RestartApp')
|
||||
xbmc.executebuiltin('RestartApp')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
log.info('%s started' % v.ADDON_ID)
|
||||
LOG.info('%s started' % v.ADDON_ID)
|
||||
try:
|
||||
v.database_paths()
|
||||
except RuntimeError as err:
|
||||
# Database does not exists
|
||||
log.error('The current Kodi version is incompatible')
|
||||
log.error('Error: %s', err)
|
||||
LOG.error('The current Kodi version is incompatible')
|
||||
LOG.error('Error: %s', err)
|
||||
else:
|
||||
Main()
|
||||
log.info('%s stopped' % v.ADDON_ID)
|
||||
LOG.info('%s stopped' % v.ADDON_ID)
|
||||
|
|
|
@ -14,6 +14,7 @@ from xbmcgui import ListItem
|
|||
|
||||
from . import utils
|
||||
from . import path_ops
|
||||
from . import transfer
|
||||
from .downloadutils import DownloadUtils as DU
|
||||
from .plex_api import API
|
||||
from . import plex_functions as PF
|
||||
|
@ -33,7 +34,7 @@ def choose_pms_server():
|
|||
Lets user choose from list of PMS
|
||||
"""
|
||||
LOG.info("Choosing PMS server requested, starting")
|
||||
utils.plex_command('choose_pms_server')
|
||||
transfer.plex_command('choose_pms_server')
|
||||
|
||||
|
||||
def toggle_plex_tv_sign_in():
|
||||
|
@ -42,7 +43,7 @@ def toggle_plex_tv_sign_in():
|
|||
Or signs in to plex.tv if the user was not logged in before.
|
||||
"""
|
||||
LOG.info('Toggle of Plex.tv sign-in requested')
|
||||
utils.plex_command('toggle_plex_tv_sign_in')
|
||||
transfer.plex_command('toggle_plex_tv_sign_in')
|
||||
|
||||
|
||||
def directory_item(label, path, folder=True):
|
||||
|
@ -128,7 +129,7 @@ def switch_plex_user():
|
|||
# position = 0
|
||||
# utils.window('EmbyAdditionalUserImage.%s' % position, clear=True)
|
||||
LOG.info("Plex home user switch requested")
|
||||
utils.plex_command('switch_plex_user')
|
||||
transfer.plex_command('switch_plex_user')
|
||||
|
||||
|
||||
def create_listitem(item, append_show_title=False, append_sxxexx=False):
|
||||
|
@ -905,4 +906,4 @@ def create_new_pms():
|
|||
Opens dialogs for the user the plug in the PMS details
|
||||
"""
|
||||
LOG.info('Request to manually enter new PMS address')
|
||||
utils.plex_command('enter_new_pms_address')
|
||||
transfer.plex_command('enter_new_pms_address')
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
from cPickle import dumps, loads
|
||||
from xbmcgui import Window
|
||||
from xbmc import log, LOGDEBUG
|
||||
|
||||
###############################################################################
|
||||
WINDOW = Window(10000)
|
||||
PREFIX = 'PLEX.pickler: '
|
||||
###############################################################################
|
||||
|
||||
|
||||
def try_encode(input_str, encoding='utf-8'):
|
||||
"""
|
||||
Will try to encode input_str (in unicode) to encoding. This possibly
|
||||
fails with e.g. Android TV's Python, which does not accept arguments for
|
||||
string.encode()
|
||||
|
||||
COPY to avoid importing utils on calling default.py
|
||||
"""
|
||||
if isinstance(input_str, str):
|
||||
# already encoded
|
||||
return input_str
|
||||
try:
|
||||
input_str = input_str.encode(encoding, "ignore")
|
||||
except TypeError:
|
||||
input_str = input_str.encode()
|
||||
return input_str
|
||||
|
||||
|
||||
def pickl_window(property, value=None, clear=False):
|
||||
"""
|
||||
Get or set window property - thread safe! For use with Pickle
|
||||
Property and value must be string
|
||||
"""
|
||||
if clear:
|
||||
WINDOW.clearProperty(property)
|
||||
elif value is not None:
|
||||
WINDOW.setProperty(property, value)
|
||||
else:
|
||||
return try_encode(WINDOW.getProperty(property))
|
||||
|
||||
|
||||
def pickle_me(obj, window_var='plex_result'):
|
||||
"""
|
||||
Pickles the obj to the window variable. Use to transfer Python
|
||||
objects between different PKC python instances (e.g. if default.py is
|
||||
called and you'd want to use the service.py instance)
|
||||
|
||||
obj can be pretty much any Python object. However, classes and
|
||||
functions won't work. See the Pickle documentation
|
||||
"""
|
||||
log('%sStart pickling' % PREFIX, level=LOGDEBUG)
|
||||
pickl_window(window_var, value=dumps(obj))
|
||||
log('%sSuccessfully pickled' % PREFIX, level=LOGDEBUG)
|
||||
|
||||
|
||||
def unpickle_me(window_var='plex_result'):
|
||||
"""
|
||||
Unpickles a Python object from the window variable window_var.
|
||||
Will then clear the window variable!
|
||||
"""
|
||||
result = pickl_window(window_var)
|
||||
pickl_window(window_var, clear=True)
|
||||
log('%sStart unpickling' % PREFIX, level=LOGDEBUG)
|
||||
obj = loads(result)
|
||||
log('%sSuccessfully unpickled' % PREFIX, level=LOGDEBUG)
|
||||
return obj
|
||||
|
||||
|
||||
class Playback_Successful(object):
|
||||
"""
|
||||
Used to communicate with another PKC Python instance
|
||||
"""
|
||||
listitem = None
|
|
@ -16,9 +16,8 @@ from .kodi_db import KodiVideoDB
|
|||
from . import playlist_func as PL
|
||||
from . import playqueue as PQ
|
||||
from . import json_rpc as js
|
||||
from . import pickler
|
||||
from . import transfer
|
||||
from .playutils import PlayUtils
|
||||
from .pkc_listitem import PKCListItem
|
||||
from . import variables as v
|
||||
from . import app
|
||||
|
||||
|
@ -261,11 +260,11 @@ def _ensure_resolve(abort=False):
|
|||
"""
|
||||
if RESOLVE:
|
||||
if not abort:
|
||||
result = pickler.Playback_Successful()
|
||||
pickler.pickle_me(result)
|
||||
# Releases the other Python thread without a ListItem
|
||||
transfer.send(True)
|
||||
else:
|
||||
# Shows PKC error message
|
||||
pickler.pickle_me(None)
|
||||
transfer.send(None)
|
||||
if abort:
|
||||
# Reset some playback variables
|
||||
app.PLAYSTATE.context_menu_play = False
|
||||
|
@ -383,8 +382,7 @@ def _conclude_playback(playqueue, pos):
|
|||
return PKC listitem attached to result
|
||||
"""
|
||||
LOG.info('Concluding playback for playqueue position %s', pos)
|
||||
result = pickler.Playback_Successful()
|
||||
listitem = PKCListItem()
|
||||
listitem = transfer.PKCListItem()
|
||||
item = playqueue.items[pos]
|
||||
if item.xml is not None:
|
||||
# Got a Plex element
|
||||
|
@ -399,7 +397,7 @@ def _conclude_playback(playqueue, pos):
|
|||
if not playurl:
|
||||
LOG.info('Did not get a playurl, aborting playback silently')
|
||||
app.PLAYSTATE.resume_playback = False
|
||||
pickler.pickle_me(result)
|
||||
transfer.send(True)
|
||||
return
|
||||
listitem.setPath(utils.try_encode(playurl))
|
||||
if item.playmethod == 'DirectStream':
|
||||
|
@ -427,8 +425,7 @@ def _conclude_playback(playqueue, pos):
|
|||
listitem.setProperty('StartOffset', str(item.offset))
|
||||
listitem.setProperty('resumetime', str(item.offset))
|
||||
# Reset the resumable flag
|
||||
result.listitem = listitem
|
||||
pickler.pickle_me(result)
|
||||
transfer.send(listitem)
|
||||
LOG.info('Done concluding playback')
|
||||
|
||||
|
||||
|
@ -447,7 +444,6 @@ def process_indirect(key, offset, resolve=True):
|
|||
key, offset, resolve)
|
||||
global RESOLVE
|
||||
RESOLVE = resolve
|
||||
result = pickler.Playback_Successful()
|
||||
if key.startswith('http') or key.startswith('{server}'):
|
||||
xml = DU().downloadUrl(key)
|
||||
elif key.startswith('/system/services'):
|
||||
|
@ -464,7 +460,7 @@ def process_indirect(key, offset, resolve=True):
|
|||
offset = int(v.PLEX_TO_KODI_TIMEFACTOR * float(offset))
|
||||
# Todo: implement offset
|
||||
api = API(xml[0])
|
||||
listitem = PKCListItem()
|
||||
listitem = transfer.PKCListItem()
|
||||
api.create_listitem(listitem)
|
||||
playqueue = PQ.get_playqueue_from_type(
|
||||
v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[api.plex_type()])
|
||||
|
@ -488,8 +484,7 @@ def process_indirect(key, offset, resolve=True):
|
|||
listitem.setPath(utils.try_encode(playurl))
|
||||
playqueue.items.append(item)
|
||||
if resolve is True:
|
||||
result.listitem = listitem
|
||||
pickler.pickle_me(result)
|
||||
transfer.send(listitem)
|
||||
else:
|
||||
thread = Thread(target=app.APP.player.play,
|
||||
args={'item': utils.try_encode(playurl),
|
||||
|
|
|
@ -7,7 +7,7 @@ from urlparse import parse_qsl
|
|||
|
||||
from . import playback
|
||||
from . import context_entry
|
||||
from . import pickler
|
||||
from . import transfer
|
||||
from . import backgroundthread
|
||||
|
||||
###############################################################################
|
||||
|
@ -33,7 +33,7 @@ class PlaybackTask(backgroundthread.Task):
|
|||
except ValueError:
|
||||
# E.g. other add-ons scanning for Extras folder
|
||||
LOG.debug('Detected 3rd party add-on call - ignoring')
|
||||
pickler.pickle_me(pickler.Playback_Successful())
|
||||
transfer.send(True)
|
||||
return
|
||||
params = dict(parse_qsl(params))
|
||||
mode = params.get('mode')
|
||||
|
|
|
@ -29,7 +29,7 @@ LOG = logging.getLogger("PLEX.service")
|
|||
WINDOW_PROPERTIES = (
|
||||
"plex_dbScan", "pms_token", "plex_token", "pms_server",
|
||||
"plex_authenticated", "plex_restricteduser", "plex_allows_mediaDeletion",
|
||||
"plex_command", "plex_result")
|
||||
"plexkodiconnect.command", "plex_result")
|
||||
|
||||
# "Start from beginning", "Play from beginning"
|
||||
STRINGS = (utils.try_encode(utils.lang(12021)),
|
||||
|
@ -393,11 +393,11 @@ class Service():
|
|||
break
|
||||
|
||||
# Check for PKC commands from other Python instances
|
||||
plex_command = utils.window('plex_command')
|
||||
plex_command = utils.window('plexkodiconnect.command')
|
||||
if plex_command:
|
||||
# Commands/user interaction received from other PKC Python
|
||||
# instances (default.py and context.py instead of service.py)
|
||||
utils.window('plex_command', clear=True)
|
||||
utils.window('plexkodiconnect.command', clear=True)
|
||||
task = None
|
||||
if plex_command.startswith('PLAY-'):
|
||||
# Add-on path playback!
|
||||
|
|
|
@ -1,9 +1,120 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Used to shovel data from separate Kodi Python instances to the main thread
|
||||
and vice versa.
|
||||
"""
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
from xbmcgui import ListItem
|
||||
from logging import getLogger
|
||||
import json
|
||||
|
||||
from . import utils
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
|
||||
LOG = getLogger('PLEX.transfer')
|
||||
MONITOR = xbmc.Monitor()
|
||||
WINDOW = xbmcgui.Window(10000)
|
||||
WINDOW_RESULT = 'plexkodiconnect.result'.encode('utf-8')
|
||||
WINDOW_COMMAND = 'plexkodiconnect.command'.encode('utf-8')
|
||||
|
||||
|
||||
def cast(func, value):
|
||||
"""
|
||||
Cast the specified value to the specified type (returned by func). Currently this
|
||||
only support int, float, bool. Should be extended if needed.
|
||||
Parameters:
|
||||
func (func): Calback function to used cast to type (int, bool, float).
|
||||
value (any): value to be cast and returned.
|
||||
"""
|
||||
if value is not None:
|
||||
if func == bool:
|
||||
return bool(int(value))
|
||||
elif func == unicode:
|
||||
if isinstance(value, (int, long, float)):
|
||||
return unicode(value)
|
||||
else:
|
||||
return value.decode('utf-8')
|
||||
elif func == str:
|
||||
if isinstance(value, (int, long, float)):
|
||||
return str(value)
|
||||
else:
|
||||
return value.encode('utf-8')
|
||||
elif func in (int, float):
|
||||
try:
|
||||
return func(value)
|
||||
except ValueError:
|
||||
return float('nan')
|
||||
return func(value)
|
||||
return value
|
||||
|
||||
|
||||
def kodi_window(property, value=None, clear=False):
|
||||
"""
|
||||
Get or set window property - thread safe! value must be string
|
||||
"""
|
||||
if clear:
|
||||
WINDOW.clearProperty(property)
|
||||
elif value is not None:
|
||||
WINDOW.setProperty(property, value)
|
||||
else:
|
||||
return WINDOW.getProperty(property)
|
||||
|
||||
|
||||
def plex_command(value):
|
||||
"""
|
||||
Used to funnel states between different Python instances. NOT really thread
|
||||
safe - let's hope the Kodi user can't click fast enough
|
||||
"""
|
||||
while kodi_window(WINDOW_COMMAND):
|
||||
if MONITOR.waitForAbort(20):
|
||||
return
|
||||
kodi_window(WINDOW_COMMAND, value=value)
|
||||
|
||||
|
||||
def serialize(obj):
|
||||
if isinstance(obj, PKCListItem):
|
||||
return {'type': 'PKCListItem', 'data': obj.data}
|
||||
else:
|
||||
return {'type': 'other', 'data': obj}
|
||||
return
|
||||
|
||||
|
||||
def de_serialize(answ):
|
||||
if answ['type'] == 'PKCListItem':
|
||||
result = PKCListItem()
|
||||
result.data = answ['data']
|
||||
return convert_pkc_to_listitem(result)
|
||||
elif answ['type'] == 'other':
|
||||
return answ['data']
|
||||
else:
|
||||
raise NotImplementedError('Not implemented: %s' % answ)
|
||||
|
||||
|
||||
def send(pkc_listitem):
|
||||
"""
|
||||
Pickles the obj to the window variable. Use to transfer Python
|
||||
objects between different PKC python instances (e.g. if default.py is
|
||||
called and you'd want to use the service.py instance)
|
||||
|
||||
obj can be pretty much any Python object. However, classes and
|
||||
functions won't work. See the Pickle documentation
|
||||
"""
|
||||
LOG.debug('Sending: %s', pkc_listitem)
|
||||
kodi_window(WINDOW_RESULT,
|
||||
value=json.dumps(serialize(pkc_listitem)))
|
||||
|
||||
|
||||
def wait_for_transfer():
|
||||
result = ''
|
||||
while not result:
|
||||
result = kodi_window(WINDOW_RESULT)
|
||||
if result:
|
||||
kodi_window(WINDOW_RESULT, clear=True)
|
||||
LOG.debug('Received')
|
||||
result = json.loads(result)
|
||||
return de_serialize(result)
|
||||
elif MONITOR.waitForAbort(0.05):
|
||||
return
|
||||
|
||||
|
||||
def convert_pkc_to_listitem(pkc_listitem):
|
||||
|
@ -11,9 +122,9 @@ def convert_pkc_to_listitem(pkc_listitem):
|
|||
Insert a PKCListItem() and you will receive a valid XBMC listitem
|
||||
"""
|
||||
data = pkc_listitem.data
|
||||
listitem = ListItem(label=data.get('label'),
|
||||
label2=data.get('label2'),
|
||||
path=data.get('path'))
|
||||
listitem = xbmcgui.ListItem(label=data.get('label'),
|
||||
label2=data.get('label2'),
|
||||
path=data.get('path'))
|
||||
if data['info']:
|
||||
listitem.setInfo(**data['info'])
|
||||
for stream in data['stream_info']:
|
||||
|
@ -23,7 +134,7 @@ def convert_pkc_to_listitem(pkc_listitem):
|
|||
if data['art']:
|
||||
listitem.setArt(data['art'])
|
||||
for key, value in data['property'].iteritems():
|
||||
listitem.setProperty(key, utils.cast(str, value))
|
||||
listitem.setProperty(key, cast(str, value))
|
||||
if data['subtitles']:
|
||||
listitem.setSubtitles(data['subtitles'])
|
||||
return listitem
|
|
@ -104,16 +104,6 @@ def window(prop, value=None, clear=False, windowid=10000):
|
|||
return try_decode(win.getProperty(prop))
|
||||
|
||||
|
||||
def plex_command(value):
|
||||
"""
|
||||
Used to funnel states between different Python instances. NOT really thread
|
||||
safe - let's hope the Kodi user can't click fast enough
|
||||
"""
|
||||
while window('plex_command'):
|
||||
xbmc.sleep(20)
|
||||
window('plex_command', value=value)
|
||||
|
||||
|
||||
def settings(setting, value=None):
|
||||
"""
|
||||
Get or add addon setting. Returns unicode
|
||||
|
|
Loading…
Reference in a new issue