Major Plex Companion overhaul, part 1
This commit is contained in:
parent
c3b5054477
commit
b1e2791ca8
7 changed files with 165 additions and 146 deletions
|
@ -291,15 +291,6 @@ def init_plex_playqueue(itemid, librarySectionUUID, mediatype='movie',
|
||||||
return xml
|
return xml
|
||||||
|
|
||||||
|
|
||||||
def getPlexRepeat(kodiRepeat):
|
|
||||||
plexRepeat = {
|
|
||||||
'off': '0',
|
|
||||||
'one': '1',
|
|
||||||
'all': '2' # does this work?!?
|
|
||||||
}
|
|
||||||
return plexRepeat.get(kodiRepeat)
|
|
||||||
|
|
||||||
|
|
||||||
def PMSHttpsEnabled(url):
|
def PMSHttpsEnabled(url):
|
||||||
"""
|
"""
|
||||||
Returns True if the PMS can talk https, False otherwise.
|
Returns True if the PMS can talk https, False otherwise.
|
||||||
|
|
|
@ -360,6 +360,22 @@ def get_episodes(params):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def get_item(playerid):
|
||||||
|
"""
|
||||||
|
Returns the following for the currently playing item:
|
||||||
|
{
|
||||||
|
u'title': u'Okja',
|
||||||
|
u'type': u'movie',
|
||||||
|
u'id': 258,
|
||||||
|
u'file': u'smb://...movie.mkv',
|
||||||
|
u'label': u'Okja'
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
return jsonrpc('Player.GetItem').execute({
|
||||||
|
'playerid': playerid,
|
||||||
|
'properties': ['title', 'file']})['result']['item']
|
||||||
|
|
||||||
|
|
||||||
def get_player_props(playerid):
|
def get_player_props(playerid):
|
||||||
"""
|
"""
|
||||||
Returns a dict for the active Kodi player with the following values:
|
Returns a dict for the active Kodi player with the following values:
|
||||||
|
@ -367,14 +383,14 @@ def get_player_props(playerid):
|
||||||
'type' [str] the Kodi player type, e.g. 'video'
|
'type' [str] the Kodi player type, e.g. 'video'
|
||||||
'time' The current item's time in Kodi time
|
'time' The current item's time in Kodi time
|
||||||
'totaltime' The current item's total length in Kodi time
|
'totaltime' The current item's total length in Kodi time
|
||||||
'speed' [int] playback speed, defaults to 0
|
'speed' [int] playback speed, 0 is paused, 1 is playing
|
||||||
'shuffled' [bool] True if shuffled
|
'shuffled' [bool] True if shuffled
|
||||||
'repeat' [str] 'off', 'one', 'all'
|
'repeat' [str] 'off', 'one', 'all'
|
||||||
'position' [int] position in playlist (or -1)
|
'position' [int] position in playlist (or -1)
|
||||||
'playlistid' [int] the Kodi playlist id (or -1)
|
'playlistid' [int] the Kodi playlist id (or -1)
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
ret = jsonrpc('Player.GetProperties').execute({
|
return jsonrpc('Player.GetProperties').execute({
|
||||||
'playerid': playerid,
|
'playerid': playerid,
|
||||||
'properties': ['type',
|
'properties': ['type',
|
||||||
'time',
|
'time',
|
||||||
|
@ -383,8 +399,11 @@ def get_player_props(playerid):
|
||||||
'shuffled',
|
'shuffled',
|
||||||
'repeat',
|
'repeat',
|
||||||
'position',
|
'position',
|
||||||
'playlistid']})
|
'playlistid',
|
||||||
return ret['result']
|
'currentvideostream',
|
||||||
|
'currentaudiostream',
|
||||||
|
'subtitleenabled',
|
||||||
|
'currentsubtitle']})['result']
|
||||||
|
|
||||||
|
|
||||||
def current_audiostream(playerid):
|
def current_audiostream(playerid):
|
||||||
|
|
|
@ -13,7 +13,9 @@ from utils import window, settings, CatchExceptions, tryDecode, tryEncode, \
|
||||||
from PlexFunctions import scrobble
|
from PlexFunctions import scrobble
|
||||||
from kodidb_functions import get_kodiid_from_filename
|
from kodidb_functions import get_kodiid_from_filename
|
||||||
from PlexAPI import API
|
from PlexAPI import API
|
||||||
|
import json_rpc as js
|
||||||
import state
|
import state
|
||||||
|
import variables as v
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
@ -178,69 +180,48 @@ class KodiMonitor(Monitor):
|
||||||
|
|
||||||
def PlayBackStart(self, data):
|
def PlayBackStart(self, data):
|
||||||
"""
|
"""
|
||||||
Called whenever a playback is started
|
Called whenever a playback is started. Example data:
|
||||||
|
{
|
||||||
|
u'item': {u'type': u'movie', u'title': u''},
|
||||||
|
u'player': {u'playerid': 1, u'speed': 1}
|
||||||
|
}
|
||||||
"""
|
"""
|
||||||
# Get currently playing file - can take a while. Will be utf-8!
|
log.debug('PlayBackStart called with: %s', data)
|
||||||
try:
|
|
||||||
currentFile = self.xbmcplayer.getPlayingFile()
|
|
||||||
except:
|
|
||||||
currentFile = None
|
|
||||||
count = 0
|
|
||||||
while currentFile is None:
|
|
||||||
sleep(100)
|
|
||||||
try:
|
|
||||||
currentFile = self.xbmcplayer.getPlayingFile()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
if count == 50:
|
|
||||||
log.info("No current File, cancel OnPlayBackStart...")
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
count += 1
|
|
||||||
# Just to be on the safe side
|
|
||||||
currentFile = tryDecode(currentFile)
|
|
||||||
log.debug("Currently playing file is: %s" % currentFile)
|
|
||||||
|
|
||||||
# Get the type of media we're playing
|
# Get the type of media we're playing
|
||||||
try:
|
try:
|
||||||
typus = data['item']['type']
|
kodi_type = data['item']['type']
|
||||||
|
playerid = data['player']['playerid']
|
||||||
|
json_data = js.get_item(playerid)
|
||||||
except (TypeError, KeyError):
|
except (TypeError, KeyError):
|
||||||
log.info("Item is invalid for PMS playstate update.")
|
log.info('Aborting playback report - item is invalid for updates')
|
||||||
return
|
return
|
||||||
log.debug("Playing itemtype is (or appears to be): %s" % typus)
|
try:
|
||||||
|
kodi_id = json_data['id']
|
||||||
# Try to get a Kodi ID
|
kodi_type = json_data['type']
|
||||||
# If PKC was used - native paths, not direct paths
|
except KeyError:
|
||||||
plex_id = window('plex_%s.itemid' % tryEncode(currentFile))
|
log.info('Aborting playback report - no Kodi id for %s', json_data)
|
||||||
# Get rid of the '' if the window property was not set
|
return
|
||||||
plex_id = None if not plex_id else plex_id
|
# Get Plex' item id
|
||||||
kodiid = None
|
with plexdb.Get_Plex_DB() as plex_db:
|
||||||
if plex_id is None:
|
plex_dbitem = plex_db.getItem_byKodiId(kodi_id, kodi_type)
|
||||||
log.debug('Did not get Plex id from window properties')
|
try:
|
||||||
try:
|
plex_id = plex_dbitem[0]
|
||||||
kodiid = data['item']['id']
|
plex_type = plex_dbitem[2]
|
||||||
except (TypeError, KeyError):
|
except TypeError:
|
||||||
log.debug('Did not get a Kodi id from Kodi, darn')
|
# No plex id, hence item not in the library. E.g. clips
|
||||||
# For direct paths, if we're not streaming something
|
plex_id = None
|
||||||
# When using Widgets, Kodi doesn't tell us shit so we need this hack
|
plex_type = None
|
||||||
if (kodiid is None and plex_id is None and typus != 'song'
|
state.PLAYER_STATES[playerid].update(js.get_player_props(playerid))
|
||||||
and not currentFile.startswith('http')):
|
state.PLAYER_STATES[playerid]['file'] = json_data['file']
|
||||||
(kodiid, typus) = get_kodiid_from_filename(currentFile)
|
state.PLAYER_STATES[playerid]['kodi_id'] = kodi_id
|
||||||
if kodiid is None:
|
state.PLAYER_STATES[playerid]['kodi_type'] = kodi_type
|
||||||
return
|
state.PLAYER_STATES[playerid]['plex_id'] = plex_id
|
||||||
|
state.PLAYER_STATES[playerid]['plex_type'] = plex_type
|
||||||
if plex_id is None:
|
log.debug('Set the player state %s', state.PLAYER_STATES[playerid])
|
||||||
# Get Plex' item id
|
# Set other stuff like volume
|
||||||
with plexdb.Get_Plex_DB() as plexcursor:
|
state.PLAYER_STATES[playerid]['volume'] = js.get_volume()
|
||||||
plex_dbitem = plexcursor.getItem_byKodiId(kodiid, typus)
|
state.PLAYER_STATES[playerid]['muted'] = js.get_muted()
|
||||||
try:
|
return
|
||||||
plex_id = plex_dbitem[0]
|
|
||||||
except TypeError:
|
|
||||||
log.info("No Plex id returned for kodiid %s. Aborting playback"
|
|
||||||
" report" % kodiid)
|
|
||||||
return
|
|
||||||
log.debug("Found Plex id %s for Kodi id %s for type %s"
|
|
||||||
% (plex_id, kodiid, typus))
|
|
||||||
|
|
||||||
# Switch subtitle tracks if applicable
|
# Switch subtitle tracks if applicable
|
||||||
subtitle = window('plex_%s.subtitle' % tryEncode(currentFile))
|
subtitle = window('plex_%s.subtitle' % tryEncode(currentFile))
|
||||||
|
|
|
@ -37,6 +37,7 @@ class PKC_Player(Player):
|
||||||
Will be called when xbmc starts playing a file.
|
Will be called when xbmc starts playing a file.
|
||||||
Window values need to have been set in Kodimonitor.py
|
Window values need to have been set in Kodimonitor.py
|
||||||
"""
|
"""
|
||||||
|
return
|
||||||
self.stopAll()
|
self.stopAll()
|
||||||
|
|
||||||
# Get current file (in utf-8!)
|
# Get current file (in utf-8!)
|
||||||
|
|
|
@ -72,70 +72,62 @@ class SubscriptionManager:
|
||||||
msg += self.getTimelineXML(players.get(v.KODI_TYPE_VIDEO),
|
msg += self.getTimelineXML(players.get(v.KODI_TYPE_VIDEO),
|
||||||
v.PLEX_TYPE_VIDEO)
|
v.PLEX_TYPE_VIDEO)
|
||||||
msg += "\n</MediaContainer>"
|
msg += "\n</MediaContainer>"
|
||||||
|
log.debug('msg is: %s', msg)
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
def getTimelineXML(self, player, ptype):
|
def getTimelineXML(self, player, ptype):
|
||||||
if player is None:
|
if player is None:
|
||||||
status = 'stopped'
|
status = 'stopped'
|
||||||
time = 0
|
|
||||||
else:
|
else:
|
||||||
playerid = player['playerid']
|
playerid = player['playerid']
|
||||||
info = self.getPlayerProperties(playerid)
|
info = state.PLAYER_STATES[playerid]
|
||||||
# save this info off so the server update can use it too
|
# save this info off so the server update can use it too
|
||||||
self.playerprops[playerid] = info
|
# self.playerprops[playerid] = info
|
||||||
status = info['state']
|
status = ("paused", "playing")[info['speed']]
|
||||||
time = info['time']
|
|
||||||
ret = ('\n <Timeline state="%s" controllable="%s" type="%s" '
|
ret = ('\n <Timeline state="%s" controllable="%s" type="%s" '
|
||||||
'itemType="%s"' % (status, CONTROLLABLE[ptype], ptype, ptype))
|
'itemType="%s"' % (status, CONTROLLABLE[ptype], ptype, ptype))
|
||||||
if player is None:
|
if player is None:
|
||||||
ret += ' />'
|
ret += ' />'
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
ret += ' time="%s"' % time
|
ret += ' time="%s"' % kodi_time_to_millis(info['time'])
|
||||||
|
ret += ' duration="%s"' % kodi_time_to_millis(info['totaltime'])
|
||||||
|
ret += ' shuffle="%s"' % ("0", "1")[info['shuffled']]
|
||||||
|
ret += ' repeat="%s"' % v.PLEX_REPEAT_FROM_KODI_REPEAT[info['repeat']]
|
||||||
|
if ptype != v.KODI_TYPE_PHOTO:
|
||||||
|
ret += ' volume="%s"' % info['volume']
|
||||||
|
ret += ' mute="%s"' % ("0", "1")[info['muted']]
|
||||||
pbmc_server = window('pms_server')
|
pbmc_server = window('pms_server')
|
||||||
|
server = self.getServerByHost(self.server)
|
||||||
if pbmc_server:
|
if pbmc_server:
|
||||||
(self.protocol, self.server, self.port) = \
|
(self.protocol, self.server, self.port) = pbmc_server.split(':')
|
||||||
pbmc_server.split(':')
|
|
||||||
self.server = self.server.replace('/', '')
|
self.server = self.server.replace('/', '')
|
||||||
keyid = None
|
if info['plex_id']:
|
||||||
count = 0
|
self.lastkey = "/library/metadata/%s" % info['plex_id']
|
||||||
while not keyid:
|
self.ratingkey = info['plex_id']
|
||||||
if count > 30:
|
ret += ' key="/library/metadata/%s"' % info['plex_id']
|
||||||
break
|
ret += ' ratingKey="%s"' % info['plex_id']
|
||||||
keyid = window('plex_currently_playing_itemid')
|
# PlayQueue stuff
|
||||||
sleep(100)
|
playqueue = self.playqueue.playqueues[playerid]
|
||||||
count += 1
|
pos = info['position']
|
||||||
if keyid:
|
try:
|
||||||
self.lastkey = "/library/metadata/%s" % keyid
|
ret += ' playQueueItemID="%s"' % playqueue.items[pos].ID or 'null'
|
||||||
self.ratingkey = keyid
|
self.containerKey = "/playQueues/%s" % playqueue.ID or 'null'
|
||||||
ret += ' key="%s"' % self.lastkey
|
ret += ' playQueueID="%s"' % playqueue.ID or 'null'
|
||||||
ret += ' ratingKey="%s"' % self.ratingkey
|
ret += ' playQueueVersion="%s"' % playqueue.version or 'null'
|
||||||
serv = self.getServerByHost(self.server)
|
|
||||||
if info.get('playQueueID'):
|
|
||||||
self.containerKey = "/playQueues/%s" % info.get('playQueueID')
|
|
||||||
ret += ' playQueueID="%s"' % info.get('playQueueID')
|
|
||||||
ret += ' playQueueVersion="%s"' % info.get('playQueueVersion')
|
|
||||||
ret += ' playQueueItemID="%s"' % info.get('playQueueItemID')
|
|
||||||
ret += ' containerKey="%s"' % self.containerKey
|
ret += ' containerKey="%s"' % self.containerKey
|
||||||
ret += ' guid="%s"' % info['guid']
|
ret += ' guid="%s"' % playqueue.items[pos].guid or 'null'
|
||||||
elif keyid:
|
except IndexError:
|
||||||
self.containerKey = self.lastkey
|
pass
|
||||||
ret += ' containerKey="%s"' % self.containerKey
|
ret += ' machineIdentifier="%s"' % server.get('uuid', "")
|
||||||
|
ret += ' protocol="%s"' % server.get('protocol', 'http')
|
||||||
ret += ' duration="%s"' % info['duration']
|
ret += ' address="%s"' % server.get('server', self.server)
|
||||||
ret += ' machineIdentifier="%s"' % serv.get('uuid', "")
|
ret += ' port="%s"' % server.get('port', self.port)
|
||||||
ret += ' protocol="%s"' % serv.get('protocol', "http")
|
# Temp. token set?
|
||||||
ret += ' address="%s"' % serv.get('server', self.server)
|
|
||||||
ret += ' port="%s"' % serv.get('port', self.port)
|
|
||||||
ret += ' volume="%s"' % info['volume']
|
|
||||||
ret += ' shuffle="%s"' % info['shuffle']
|
|
||||||
ret += ' mute="%s"' % info['mute']
|
|
||||||
ret += ' repeat="%s"' % info['repeat']
|
|
||||||
ret += ' itemType="%s"' % ptype
|
|
||||||
if state.PLEX_TRANSIENT_TOKEN:
|
if state.PLEX_TRANSIENT_TOKEN:
|
||||||
ret += ' token="%s"' % state.PLEX_TRANSIENT_TOKEN
|
ret += ' token="%s"' % state.PLEX_TRANSIENT_TOKEN
|
||||||
elif info['plex_transient_token']:
|
elif playqueue.plex_transient_token:
|
||||||
ret += ' token="%s"' % info['plex_transient_token']
|
ret += ' token="%s"' % playqueue.plex_transient_token
|
||||||
# Might need an update in the future
|
# Might need an update in the future
|
||||||
if ptype == 'video':
|
if ptype == 'video':
|
||||||
ret += ' subtitleStreamID="-1"'
|
ret += ' subtitleStreamID="-1"'
|
||||||
|
@ -236,37 +228,26 @@ class SubscriptionManager:
|
||||||
del self.subscribers[sub.uuid]
|
del self.subscribers[sub.uuid]
|
||||||
|
|
||||||
def getPlayerProperties(self, playerid):
|
def getPlayerProperties(self, playerid):
|
||||||
|
# Get the playqueue
|
||||||
|
playqueue = self.playqueue.playqueues[playerid]
|
||||||
|
# get info from the player
|
||||||
|
props = state.PLAYER_STATES[playerid]
|
||||||
|
info = {
|
||||||
|
'time': kodi_time_to_millis(props['time']),
|
||||||
|
'duration': kodi_time_to_millis(props['totaltime']),
|
||||||
|
'state': ("paused", "playing")[int(props['speed'])],
|
||||||
|
'shuffle': ("0", "1")[props.get('shuffled', False)],
|
||||||
|
'repeat': v.PLEX_REPEAT_FROM_KODI_REPEAT[props.get('repeat')]
|
||||||
|
}
|
||||||
|
pos = props['position']
|
||||||
try:
|
try:
|
||||||
# Get the playqueue
|
info['playQueueItemID'] = playqueue.items[pos].ID or 'null'
|
||||||
playqueue = self.playqueue.playqueues[playerid]
|
info['guid'] = playqueue.items[pos].guid or 'null'
|
||||||
# get info from the player
|
info['playQueueID'] = playqueue.ID or 'null'
|
||||||
props = js.get_player_props(playerid)
|
info['playQueueVersion'] = playqueue.version or 'null'
|
||||||
info = {
|
info['itemType'] = playqueue.items[pos].plex_type or 'null'
|
||||||
'time': kodi_time_to_millis(props['time']),
|
|
||||||
'duration': kodi_time_to_millis(props['totaltime']),
|
|
||||||
'state': ("paused", "playing")[int(props['speed'])],
|
|
||||||
'shuffle': ("0", "1")[props.get('shuffled', False)],
|
|
||||||
'repeat': pf.getPlexRepeat(props.get('repeat')),
|
|
||||||
}
|
|
||||||
pos = props['position']
|
|
||||||
try:
|
|
||||||
info['playQueueItemID'] = playqueue.items[pos].ID or 'null'
|
|
||||||
info['guid'] = playqueue.items[pos].guid or 'null'
|
|
||||||
info['playQueueID'] = playqueue.ID or 'null'
|
|
||||||
info['playQueueVersion'] = playqueue.version or 'null'
|
|
||||||
info['itemType'] = playqueue.items[pos].plex_type or 'null'
|
|
||||||
except:
|
|
||||||
info['itemType'] = props.get('type') or 'null'
|
|
||||||
except:
|
except:
|
||||||
import traceback
|
info['itemType'] = props.get('type') or 'null'
|
||||||
log.error("Traceback:\n%s" % traceback.format_exc())
|
|
||||||
info = {
|
|
||||||
'time': 0,
|
|
||||||
'duration': 0,
|
|
||||||
'state': 'stopped',
|
|
||||||
'shuffle': False,
|
|
||||||
'repeat': 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# get the volume from the application
|
# get the volume from the application
|
||||||
info['volume'] = js.get_volume()
|
info['volume'] = js.get_volume()
|
||||||
|
@ -323,5 +304,6 @@ class Subscriber:
|
||||||
response = self.doUtils(url,
|
response = self.doUtils(url,
|
||||||
postBody=msg,
|
postBody=msg,
|
||||||
action_type="POST")
|
action_type="POST")
|
||||||
|
log.debug('response is: %s', response)
|
||||||
if response in [False, None, 401]:
|
if response in [False, None, 401]:
|
||||||
self.subMgr.removeSubscriber(self.uuid)
|
self.subMgr.removeSubscriber(self.uuid)
|
||||||
|
|
|
@ -75,8 +75,33 @@ PLEX_USER_ID = None
|
||||||
# another user playing something! Token identifies user
|
# another user playing something! Token identifies user
|
||||||
PLEX_TRANSIENT_TOKEN = None
|
PLEX_TRANSIENT_TOKEN = None
|
||||||
|
|
||||||
# Kodi player states
|
# Kodi player states - here, initial values are set
|
||||||
PLAYER_STATES = {}
|
PLAYER_STATES = {
|
||||||
|
1: {
|
||||||
|
'type': 'movie',
|
||||||
|
'time': 0,
|
||||||
|
'totaltime': 0,
|
||||||
|
'speed': 0,
|
||||||
|
'shuffled': False,
|
||||||
|
'repeat': '0',
|
||||||
|
'position': -1,
|
||||||
|
'playlistid': -1,
|
||||||
|
'currentvideostream': -1,
|
||||||
|
'currentaudiostream': -1,
|
||||||
|
'subtitleenabled': False,
|
||||||
|
'currentsubtitle': -1,
|
||||||
|
######
|
||||||
|
'file': '',
|
||||||
|
'kodi_id': None,
|
||||||
|
'kodi_type': None,
|
||||||
|
'plex_id': None,
|
||||||
|
'plex_type': None,
|
||||||
|
'volume': 100,
|
||||||
|
'muted': False
|
||||||
|
},
|
||||||
|
2: {},
|
||||||
|
3: {}
|
||||||
|
}
|
||||||
PLAYED_INFO = {}
|
PLAYED_INFO = {}
|
||||||
|
|
||||||
# Kodi webserver details
|
# Kodi webserver details
|
||||||
|
|
|
@ -214,6 +214,20 @@ KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
KODI_PLAYLIST_TYPE_FROM_KODI_TYPE = {
|
||||||
|
KODI_TYPE_VIDEO: KODI_TYPE_VIDEO,
|
||||||
|
KODI_TYPE_MOVIE: KODI_TYPE_VIDEO,
|
||||||
|
KODI_TYPE_EPISODE: KODI_TYPE_VIDEO,
|
||||||
|
KODI_TYPE_SEASON: KODI_TYPE_VIDEO,
|
||||||
|
KODI_TYPE_SHOW: KODI_TYPE_VIDEO,
|
||||||
|
KODI_TYPE_CLIP: KODI_TYPE_VIDEO,
|
||||||
|
KODI_TYPE_ARTIST: KODI_TYPE_AUDIO,
|
||||||
|
KODI_TYPE_ALBUM: KODI_TYPE_AUDIO,
|
||||||
|
KODI_TYPE_SONG: KODI_TYPE_AUDIO,
|
||||||
|
KODI_TYPE_AUDIO: KODI_TYPE_AUDIO,
|
||||||
|
KODI_TYPE_PHOTO: KODI_TYPE_PHOTO
|
||||||
|
}
|
||||||
|
|
||||||
REMAP_TYPE_FROM_PLEXTYPE = {
|
REMAP_TYPE_FROM_PLEXTYPE = {
|
||||||
PLEX_TYPE_MOVIE: 'movie',
|
PLEX_TYPE_MOVIE: 'movie',
|
||||||
PLEX_TYPE_CLIP: 'clip',
|
PLEX_TYPE_CLIP: 'clip',
|
||||||
|
@ -371,3 +385,9 @@ SORT_METHODS_ALBUMS = (
|
||||||
XML_HEADER = '<?xml version="1.0" encoding="UTF-8"?>\n'
|
XML_HEADER = '<?xml version="1.0" encoding="UTF-8"?>\n'
|
||||||
|
|
||||||
COMPANION_OK_MESSAGE = XML_HEADER + '<Response code="200" status="OK" />'
|
COMPANION_OK_MESSAGE = XML_HEADER + '<Response code="200" status="OK" />'
|
||||||
|
|
||||||
|
PLEX_REPEAT_FROM_KODI_REPEAT = {
|
||||||
|
'off': '0',
|
||||||
|
'one': '1',
|
||||||
|
'all': '2' # does this work?!?
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue