Switch Companion to use json_rpc.py
This commit is contained in:
parent
cceb110354
commit
843bedbee6
7 changed files with 119 additions and 309 deletions
|
@ -8,8 +8,8 @@ from urllib import urlencode
|
|||
from xbmc import sleep, executebuiltin
|
||||
|
||||
from utils import settings, thread_methods
|
||||
from plexbmchelper import listener, plexgdm, subscribers, functions, \
|
||||
httppersist, plexsettings
|
||||
from plexbmchelper import listener, plexgdm, subscribers, httppersist, \
|
||||
plexsettings
|
||||
from PlexFunctions import ParseContainerKey, GetPlexMetadata
|
||||
from PlexAPI import API
|
||||
from playlist_func import get_pms_playqueue, get_plextype_from_xml
|
||||
|
@ -196,9 +196,8 @@ class PlexCompanion(Thread):
|
|||
|
||||
# Start up instances
|
||||
requestMgr = httppersist.RequestMgr()
|
||||
jsonClass = functions.jsonClass(requestMgr, self.settings)
|
||||
subscriptionManager = subscribers.SubscriptionManager(
|
||||
jsonClass, requestMgr, self.player, self.mgr)
|
||||
requestMgr, self.player, self.mgr)
|
||||
|
||||
queue = Queue.Queue(maxsize=100)
|
||||
self.queue = queue
|
||||
|
@ -211,7 +210,6 @@ class PlexCompanion(Thread):
|
|||
httpd = listener.ThreadedHTTPServer(
|
||||
client,
|
||||
subscriptionManager,
|
||||
jsonClass,
|
||||
self.settings,
|
||||
queue,
|
||||
('', self.settings['myport']),
|
||||
|
|
|
@ -3,7 +3,7 @@ Collection of functions using the Kodi JSON RPC interface.
|
|||
See http://kodi.wiki/view/JSON-RPC_API
|
||||
"""
|
||||
from json import loads, dumps
|
||||
from utils import milliseconds_to_kodi_time
|
||||
from utils import millis_to_kodi_time
|
||||
from xbmc import executeJSONRPC
|
||||
|
||||
|
||||
|
@ -49,7 +49,7 @@ def get_players():
|
|||
'picture': ...
|
||||
}
|
||||
"""
|
||||
info = jsonrpc("Player.GetActivePlayers").execute()['result'] or []
|
||||
info = jsonrpc("Player.GetActivePlayers").execute()['result']
|
||||
ret = {}
|
||||
for player in info:
|
||||
player['playerid'] = int(player['playerid'])
|
||||
|
@ -152,7 +152,7 @@ def seek_to(offset):
|
|||
for playerid in get_player_ids():
|
||||
jsonrpc("Player.Seek").execute(
|
||||
{"playerid": playerid,
|
||||
"value": milliseconds_to_kodi_time(offset)})
|
||||
"value": millis_to_kodi_time(offset)})
|
||||
|
||||
|
||||
def smallforward():
|
||||
|
@ -240,6 +240,13 @@ def input_back():
|
|||
return jsonrpc("Input.Back").execute()
|
||||
|
||||
|
||||
def input_sendtext(text):
|
||||
"""
|
||||
Tells Kodi the user sent text [unicode]
|
||||
"""
|
||||
return jsonrpc("Input.SendText").execute({'test': text, 'done': False})
|
||||
|
||||
|
||||
def playlist_get_items(playlistid, properties):
|
||||
"""
|
||||
playlistid: [int] id of the Kodi playlist
|
||||
|
@ -350,6 +357,33 @@ def get_episodes(params):
|
|||
return ret
|
||||
|
||||
|
||||
def get_player_props(playerid):
|
||||
"""
|
||||
Returns a dict for the active Kodi player with the following values:
|
||||
{
|
||||
'type' [str] the Kodi player type, e.g. 'video'
|
||||
'time' The current item's time in Kodi time
|
||||
'totaltime' The current item's total length in Kodi time
|
||||
'speed' [int] playback speed, defaults to 0
|
||||
'shuffled' [bool] True if shuffled
|
||||
'repeat' [str] 'off', 'one', 'all'
|
||||
'position' [int] position in playlist (or -1)
|
||||
'playlistid' [int] the Kodi playlist id (or -1)
|
||||
}
|
||||
"""
|
||||
ret = jsonrpc('Player.GetProperties').execute({
|
||||
'playerid': playerid,
|
||||
'properties': ['type',
|
||||
'time',
|
||||
'totaltime',
|
||||
'speed',
|
||||
'shuffled',
|
||||
'repeat',
|
||||
'position',
|
||||
'playlistid']})
|
||||
return ret['result']
|
||||
|
||||
|
||||
def current_audiostream(playerid):
|
||||
"""
|
||||
Returns a dict of the active audiostream for playerid [int]:
|
||||
|
@ -402,3 +436,10 @@ def subtitle_enabled(playerid):
|
|||
except (KeyError, TypeError):
|
||||
ret = False
|
||||
return ret
|
||||
|
||||
|
||||
def ping():
|
||||
"""
|
||||
Pings the JSON RPC interface
|
||||
"""
|
||||
return jsonrpc('JSONRPC.Ping').execute()
|
||||
|
|
|
@ -1,244 +0,0 @@
|
|||
import logging
|
||||
import base64
|
||||
import json
|
||||
import string
|
||||
|
||||
import xbmc
|
||||
|
||||
import plexdb_functions as plexdb
|
||||
|
||||
###############################################################################
|
||||
|
||||
log = logging.getLogger("PLEX."+__name__)
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
||||
def xbmc_photo():
|
||||
return "photo"
|
||||
|
||||
|
||||
def xbmc_video():
|
||||
return "video"
|
||||
|
||||
|
||||
def xbmc_audio():
|
||||
return "audio"
|
||||
|
||||
|
||||
def plex_photo():
|
||||
return "photo"
|
||||
|
||||
|
||||
def plex_video():
|
||||
return "video"
|
||||
|
||||
|
||||
def plex_audio():
|
||||
return "music"
|
||||
|
||||
|
||||
def xbmc_type(plex_type):
|
||||
if plex_type == plex_photo():
|
||||
return xbmc_photo()
|
||||
elif plex_type == plex_video():
|
||||
return xbmc_video()
|
||||
elif plex_type == plex_audio():
|
||||
return xbmc_audio()
|
||||
|
||||
|
||||
def plex_type(xbmc_type):
|
||||
if xbmc_type == xbmc_photo():
|
||||
return plex_photo()
|
||||
elif xbmc_type == xbmc_video():
|
||||
return plex_video()
|
||||
elif xbmc_type == xbmc_audio():
|
||||
return plex_audio()
|
||||
|
||||
|
||||
def getXMLHeader():
|
||||
return '<?xml version="1.0" encoding="UTF-8"?>\n'
|
||||
|
||||
|
||||
def getOKMsg():
|
||||
return getXMLHeader() + '<Response code="200" status="OK" />'
|
||||
|
||||
|
||||
def timeToMillis(time):
|
||||
return (time['hours']*3600 +
|
||||
time['minutes']*60 +
|
||||
time['seconds'])*1000 + time['milliseconds']
|
||||
|
||||
|
||||
def millisToTime(t):
|
||||
millis = int(t)
|
||||
seconds = millis / 1000
|
||||
minutes = seconds / 60
|
||||
hours = minutes / 60
|
||||
seconds = seconds % 60
|
||||
minutes = minutes % 60
|
||||
millis = millis % 1000
|
||||
return {'hours': hours,
|
||||
'minutes': minutes,
|
||||
'seconds': seconds,
|
||||
'milliseconds': millis}
|
||||
|
||||
|
||||
def textFromXml(element):
|
||||
return element.firstChild.data
|
||||
|
||||
|
||||
class jsonClass():
|
||||
|
||||
def __init__(self, requestMgr, settings):
|
||||
self.settings = settings
|
||||
self.requestMgr = requestMgr
|
||||
|
||||
def jsonrpc(self, action, arguments={}):
|
||||
""" put some JSON together for the JSON-RPC APIv6 """
|
||||
if action.lower() == "sendkey":
|
||||
request = json.dumps({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "Input.SendText",
|
||||
"params": {
|
||||
"text": arguments[0],
|
||||
"done": False
|
||||
}
|
||||
})
|
||||
elif action.lower() == "ping":
|
||||
request = json.dumps({
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "JSONRPC.Ping"
|
||||
})
|
||||
elif arguments:
|
||||
request = json.dumps({
|
||||
"id": 1,
|
||||
"jsonrpc": "2.0",
|
||||
"method": action,
|
||||
"params": arguments})
|
||||
else:
|
||||
request = json.dumps({
|
||||
"id": 1,
|
||||
"jsonrpc": "2.0",
|
||||
"method": action
|
||||
})
|
||||
|
||||
result = self.parseJSONRPC(xbmc.executeJSONRPC(request))
|
||||
|
||||
if not result and self.settings['webserver_enabled']:
|
||||
# xbmc.executeJSONRPC appears to fail on the login screen, but
|
||||
# going through the network stack works, so let's try the request
|
||||
# again
|
||||
result = self.parseJSONRPC(self.requestMgr.post(
|
||||
"127.0.0.1",
|
||||
self.settings['port'],
|
||||
"/jsonrpc",
|
||||
request,
|
||||
{'Content-Type': 'application/json',
|
||||
'Authorization': 'Basic %s' % string.strip(
|
||||
base64.encodestring('%s:%s'
|
||||
% (self.settings['user'],
|
||||
self.settings['passwd'])))
|
||||
}))
|
||||
return result
|
||||
|
||||
def skipTo(self, plexId, typus):
|
||||
# playlistId = self.getPlaylistId(tryDecode(xbmc_type(typus)))
|
||||
# playerId = self.
|
||||
with plexdb.Get_Plex_DB() as plex_db:
|
||||
plexdb_item = plex_db.getItem_byId(plexId)
|
||||
try:
|
||||
dbid = plexdb_item[0]
|
||||
mediatype = plexdb_item[4]
|
||||
except TypeError:
|
||||
log.info('Couldnt find item %s in Kodi db' % plexId)
|
||||
return
|
||||
log.debug('plexid: %s, kodi id: %s, type: %s'
|
||||
% (plexId, dbid, mediatype))
|
||||
|
||||
def getPlexHeaders(self):
|
||||
h = {
|
||||
"Content-type": "text/xml",
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"X-Plex-Version": self.settings['version'],
|
||||
"X-Plex-Client-Identifier": self.settings['uuid'],
|
||||
"X-Plex-Provides": "client,controller,player",
|
||||
"X-Plex-Product": "PlexKodiConnect",
|
||||
"X-Plex-Device-Name": self.settings['client_name'],
|
||||
"X-Plex-Platform": "Kodi",
|
||||
"X-Plex-Model": self.settings['platform'],
|
||||
"X-Plex-Device": "PC",
|
||||
}
|
||||
if self.settings['myplex_user']:
|
||||
h["X-Plex-Username"] = self.settings['myplex_user']
|
||||
return h
|
||||
|
||||
def parseJSONRPC(self, jsonraw):
|
||||
if not jsonraw:
|
||||
log.debug("Empty response from Kodi")
|
||||
return {}
|
||||
else:
|
||||
parsed = json.loads(jsonraw)
|
||||
if parsed.get('error', False):
|
||||
log.error("Kodi returned an error: %s" % parsed.get('error'))
|
||||
return parsed.get('result', {})
|
||||
|
||||
def getPlayers(self):
|
||||
info = self.jsonrpc("Player.GetActivePlayers") or []
|
||||
ret = {}
|
||||
for player in info:
|
||||
player['playerid'] = int(player['playerid'])
|
||||
ret[player['type']] = player
|
||||
return ret
|
||||
|
||||
def getPlaylistId(self, typus):
|
||||
"""
|
||||
typus: one of the Kodi types, e.g. audio or video
|
||||
|
||||
Returns None if nothing was found
|
||||
"""
|
||||
for playlist in self.getPlaylists():
|
||||
if playlist.get('type') == typus:
|
||||
return playlist.get('playlistid')
|
||||
|
||||
def getPlaylists(self):
|
||||
"""
|
||||
Returns a list, e.g.
|
||||
[
|
||||
{u'playlistid': 0, u'type': u'audio'},
|
||||
{u'playlistid': 1, u'type': u'video'},
|
||||
{u'playlistid': 2, u'type': u'picture'}
|
||||
]
|
||||
"""
|
||||
return self.jsonrpc('Playlist.GetPlaylists')
|
||||
|
||||
def getPlayerIds(self):
|
||||
ret = []
|
||||
for player in self.getPlayers().values():
|
||||
ret.append(player['playerid'])
|
||||
return ret
|
||||
|
||||
def getVideoPlayerId(self, players=False):
|
||||
if players is None:
|
||||
players = self.getPlayers()
|
||||
return players.get(xbmc_video(), {}).get('playerid', None)
|
||||
|
||||
def getAudioPlayerId(self, players=False):
|
||||
if players is None:
|
||||
players = self.getPlayers()
|
||||
return players.get(xbmc_audio(), {}).get('playerid', None)
|
||||
|
||||
def getPhotoPlayerId(self, players=False):
|
||||
if players is None:
|
||||
players = self.getPlayers()
|
||||
return players.get(xbmc_photo(), {}).get('playerid', None)
|
||||
|
||||
def getVolume(self):
|
||||
answ = self.jsonrpc('Application.GetProperties',
|
||||
{
|
||||
"properties": ["volume", 'muted']
|
||||
})
|
||||
vol = str(answ.get('volume', 100))
|
||||
mute = ("0", "1")[answ.get('muted', False)]
|
||||
return (vol, mute)
|
|
@ -8,9 +8,9 @@ from urlparse import urlparse, parse_qs
|
|||
from xbmc import sleep
|
||||
from companion import process_command
|
||||
from utils import window
|
||||
|
||||
from functions import *
|
||||
|
||||
import json_rpc as js
|
||||
from clientinfo import getXArgsDeviceInfo
|
||||
import variables as v
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -82,7 +82,6 @@ class MyHandler(BaseHTTPRequestHandler):
|
|||
def answer_request(self, sendData):
|
||||
self.serverlist = self.server.client.getServerList()
|
||||
subMgr = self.server.subscriptionManager
|
||||
js = self.server.jsonClass
|
||||
settings = self.server.settings
|
||||
|
||||
try:
|
||||
|
@ -105,7 +104,7 @@ class MyHandler(BaseHTTPRequestHandler):
|
|||
% settings['version'])
|
||||
elif request_path == "verify":
|
||||
self.response("XBMC JSON connection test:\n" +
|
||||
js.jsonrpc("ping"))
|
||||
js.ping())
|
||||
elif "resources" == request_path:
|
||||
resp = ('%s'
|
||||
'<MediaContainer>'
|
||||
|
@ -121,15 +120,15 @@ class MyHandler(BaseHTTPRequestHandler):
|
|||
' deviceClass="pc"'
|
||||
'/>'
|
||||
'</MediaContainer>'
|
||||
% (getXMLHeader(),
|
||||
% (v.XML_HEADER,
|
||||
settings['client_name'],
|
||||
settings['uuid'],
|
||||
settings['platform'],
|
||||
settings['plexbmc_version']))
|
||||
log.debug("crafted resources response: %s" % resp)
|
||||
self.response(resp, js.getPlexHeaders())
|
||||
self.response(resp, getXArgsDeviceInfo())
|
||||
elif "/subscribe" in request_path:
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
self.response(v.COMPANION_OK_MESSAGE, getXArgsDeviceInfo())
|
||||
protocol = params.get('protocol', False)
|
||||
host = self.client_address[0]
|
||||
port = params.get('port', False)
|
||||
|
@ -147,7 +146,7 @@ class MyHandler(BaseHTTPRequestHandler):
|
|||
self.response(
|
||||
sub(r"INSERTCOMMANDID",
|
||||
str(commandID),
|
||||
subMgr.msg(js.getPlayers())),
|
||||
subMgr.msg(js.get_players())),
|
||||
{
|
||||
'X-Plex-Client-Identifier': settings['uuid'],
|
||||
'Access-Control-Expose-Headers':
|
||||
|
@ -156,14 +155,14 @@ class MyHandler(BaseHTTPRequestHandler):
|
|||
'Content-Type': 'text/xml'
|
||||
})
|
||||
elif "/unsubscribe" in request_path:
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
self.response(v.COMPANION_OK_MESSAGE, getXArgsDeviceInfo())
|
||||
uuid = self.headers.get('X-Plex-Client-Identifier', False) \
|
||||
or self.client_address[0]
|
||||
subMgr.removeSubscriber(uuid)
|
||||
else:
|
||||
# Throw it to companion.py
|
||||
process_command(request_path, params, self.server.queue)
|
||||
self.response('', js.getPlexHeaders())
|
||||
self.response('', getXArgsDeviceInfo())
|
||||
subMgr.notify()
|
||||
except:
|
||||
log.error('Error encountered. Traceback:')
|
||||
|
@ -174,17 +173,16 @@ class MyHandler(BaseHTTPRequestHandler):
|
|||
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
|
||||
daemon_threads = True
|
||||
|
||||
def __init__(self, client, subscriptionManager, jsonClass, settings,
|
||||
def __init__(self, client, subscriptionManager, settings,
|
||||
queue, *args, **kwargs):
|
||||
"""
|
||||
client: Class handle to plexgdm.plexgdm. We can thus ask for an up-to-
|
||||
date serverlist without instantiating anything
|
||||
|
||||
same for SubscriptionManager and jsonClass
|
||||
same for SubscriptionManager
|
||||
"""
|
||||
self.client = client
|
||||
self.subscriptionManager = subscriptionManager
|
||||
self.jsonClass = jsonClass
|
||||
self.settings = settings
|
||||
self.queue = queue
|
||||
HTTPServer.__init__(self, *args, **kwargs)
|
||||
|
|
|
@ -2,12 +2,15 @@ import logging
|
|||
import re
|
||||
import threading
|
||||
|
||||
from xbmc import sleep
|
||||
|
||||
import downloadutils
|
||||
from clientinfo import getXArgsDeviceInfo
|
||||
from utils import window
|
||||
from utils import window, kodi_time_to_millis
|
||||
import PlexFunctions as pf
|
||||
import state
|
||||
from functions import *
|
||||
import variables as v
|
||||
import json_rpc as js
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -17,7 +20,7 @@ log = logging.getLogger("PLEX."+__name__)
|
|||
|
||||
|
||||
class SubscriptionManager:
|
||||
def __init__(self, jsonClass, RequestMgr, player, mgr):
|
||||
def __init__(self, RequestMgr, player, mgr):
|
||||
self.serverlist = []
|
||||
self.subscribers = {}
|
||||
self.info = {}
|
||||
|
@ -30,8 +33,6 @@ class SubscriptionManager:
|
|||
'audio': {},
|
||||
'picture': {}
|
||||
}
|
||||
self.volume = 0
|
||||
self.mute = '0'
|
||||
self.server = ""
|
||||
self.protocol = "http"
|
||||
self.port = ""
|
||||
|
@ -40,7 +41,6 @@ class SubscriptionManager:
|
|||
self.xbmcplayer = player
|
||||
self.playqueue = mgr.playqueue
|
||||
|
||||
self.js = jsonClass
|
||||
self.RequestMgr = RequestMgr
|
||||
|
||||
def getServerByHost(self, host):
|
||||
|
@ -52,32 +52,34 @@ class SubscriptionManager:
|
|||
return server
|
||||
return {}
|
||||
|
||||
def getVolume(self):
|
||||
self.volume, self.mute = self.js.getVolume()
|
||||
|
||||
def msg(self, players):
|
||||
msg = getXMLHeader()
|
||||
log.debug('players: %s', players)
|
||||
msg = v.XML_HEADER
|
||||
msg += '<MediaContainer size="3" commandID="INSERTCOMMANDID"'
|
||||
msg += ' machineIdentifier="%s" location="fullScreenVideo">' % window('plex_client_Id')
|
||||
msg += self.getTimelineXML(self.js.getAudioPlayerId(players), plex_audio())
|
||||
msg += self.getTimelineXML(self.js.getPhotoPlayerId(players), plex_photo())
|
||||
msg += self.getTimelineXML(self.js.getVideoPlayerId(players), plex_video())
|
||||
msg += self.getTimelineXML(players.get(v.KODI_TYPE_AUDIO),
|
||||
v.PLEX_TYPE_AUDIO)
|
||||
msg += self.getTimelineXML(players.get(v.KODI_TYPE_PHOTO),
|
||||
v.PLEX_TYPE_PHOTO)
|
||||
msg += self.getTimelineXML(players.get(v.KODI_TYPE_VIDEO),
|
||||
v.PLEX_TYPE_VIDEO)
|
||||
msg += "\n</MediaContainer>"
|
||||
return msg
|
||||
|
||||
def getTimelineXML(self, playerid, ptype):
|
||||
if playerid is not None:
|
||||
def getTimelineXML(self, player, ptype):
|
||||
if player is None:
|
||||
status = 'stopped'
|
||||
time = 0
|
||||
else:
|
||||
playerid = player['playerid']
|
||||
info = self.getPlayerProperties(playerid)
|
||||
# save this info off so the server update can use it too
|
||||
self.playerprops[playerid] = info
|
||||
status = info['state']
|
||||
time = info['time']
|
||||
else:
|
||||
status = "stopped"
|
||||
time = 0
|
||||
ret = ('\n <Timeline state="%s" time="%s" type="%s"'
|
||||
% (status, time, ptype))
|
||||
if playerid is None:
|
||||
if player is None:
|
||||
ret += ' />'
|
||||
return ret
|
||||
|
||||
|
@ -89,10 +91,10 @@ class SubscriptionManager:
|
|||
keyid = None
|
||||
count = 0
|
||||
while not keyid:
|
||||
if count > 300:
|
||||
if count > 30:
|
||||
break
|
||||
keyid = window('plex_currently_playing_itemid')
|
||||
xbmc.sleep(100)
|
||||
sleep(100)
|
||||
count += 1
|
||||
if keyid:
|
||||
self.lastkey = "/library/metadata/%s" % keyid
|
||||
|
@ -119,7 +121,7 @@ class SubscriptionManager:
|
|||
ret += ' port="%s"' % serv.get('port', self.port)
|
||||
ret += ' volume="%s"' % info['volume']
|
||||
ret += ' shuffle="%s"' % info['shuffle']
|
||||
ret += ' mute="%s"' % self.mute
|
||||
ret += ' mute="%s"' % info['mute']
|
||||
ret += ' repeat="%s"' % info['repeat']
|
||||
ret += ' itemType="%s"' % ptype
|
||||
if state.PLEX_TRANSIENT_TOKEN:
|
||||
|
@ -145,7 +147,7 @@ class SubscriptionManager:
|
|||
if (not window('plex_currently_playing_itemid')
|
||||
and not self.lastplayers):
|
||||
return True
|
||||
players = self.js.getPlayers()
|
||||
players = js.get_players()
|
||||
# fetch the message, subscribers or not, since the server
|
||||
# will need the info anyway
|
||||
msg = self.msg(players)
|
||||
|
@ -233,27 +235,15 @@ class SubscriptionManager:
|
|||
# Get the playqueue
|
||||
playqueue = self.playqueue.playqueues[playerid]
|
||||
# get info from the player
|
||||
props = self.js.jsonrpc(
|
||||
"Player.GetProperties",
|
||||
{"playerid": playerid,
|
||||
"properties": ["type",
|
||||
"time",
|
||||
"totaltime",
|
||||
"speed",
|
||||
"shuffled",
|
||||
"repeat"]})
|
||||
props = js.get_player_props(playerid)
|
||||
info = {
|
||||
'time': timeToMillis(props['time']),
|
||||
'duration': timeToMillis(props['totaltime']),
|
||||
'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')),
|
||||
}
|
||||
# Get the playlist position
|
||||
pos = self.js.jsonrpc(
|
||||
"Player.GetProperties",
|
||||
{"playerid": playerid,
|
||||
"properties": ["position"]})['position']
|
||||
pos = props['position']
|
||||
try:
|
||||
info['playQueueItemID'] = playqueue.items[pos].ID or 'null'
|
||||
info['guid'] = playqueue.items[pos].guid or 'null'
|
||||
|
@ -274,8 +264,8 @@ class SubscriptionManager:
|
|||
}
|
||||
|
||||
# get the volume from the application
|
||||
info['volume'] = self.volume
|
||||
info['mute'] = self.mute
|
||||
info['volume'] = js.get_volume()
|
||||
info['mute'] = js.get_muted()
|
||||
|
||||
info['plex_transient_token'] = playqueue.plex_transient_token
|
||||
|
||||
|
|
|
@ -179,9 +179,15 @@ def dialog(typus, *args, **kwargs):
|
|||
return types[typus](*args, **kwargs)
|
||||
|
||||
|
||||
def milliseconds_to_kodi_time(milliseconds):
|
||||
def millis_to_kodi_time(milliseconds):
|
||||
"""
|
||||
Converts time in milliseconds to the time dict used by the Kodi JSON RPC
|
||||
Converts time in milliseconds to the time dict used by the Kodi JSON RPC:
|
||||
{
|
||||
'hours': [int],
|
||||
'minutes': [int],
|
||||
'seconds'[int],
|
||||
'milliseconds': [int]
|
||||
}
|
||||
Pass in the time in milliseconds as an int
|
||||
"""
|
||||
seconds = milliseconds / 1000
|
||||
|
@ -196,6 +202,22 @@ def milliseconds_to_kodi_time(milliseconds):
|
|||
'milliseconds': milliseconds}
|
||||
|
||||
|
||||
def kodi_time_to_millis(time):
|
||||
"""
|
||||
Converts the Kodi time dict
|
||||
{
|
||||
'hours': [int],
|
||||
'minutes': [int],
|
||||
'seconds'[int],
|
||||
'milliseconds': [int]
|
||||
}
|
||||
to milliseconds [int]
|
||||
"""
|
||||
return (time['hours']*3600 +
|
||||
time['minutes']*60 +
|
||||
time['seconds'])*1000 + time['milliseconds']
|
||||
|
||||
|
||||
def tryEncode(uniString, encoding='utf-8'):
|
||||
"""
|
||||
Will try to encode uniString (in unicode) to encoding. This possibly
|
||||
|
|
|
@ -361,3 +361,8 @@ SORT_METHODS_ALBUMS = (
|
|||
'SORT_METHOD_ARTIST',
|
||||
'SORT_METHOD_ALBUM',
|
||||
)
|
||||
|
||||
|
||||
XML_HEADER = '<?xml version="1.0" encoding="UTF-8"?>\n'
|
||||
|
||||
COMPANION_OK_MESSAGE = XML_HEADER + '<Response code="200" status="OK" />'
|
||||
|
|
Loading…
Reference in a new issue