import logging import re import threading from xbmc import sleep import downloadutils from clientinfo import getXArgsDeviceInfo from utils import window, kodi_time_to_millis import PlexFunctions as pf import state import variables as v import json_rpc as js ############################################################################### log = logging.getLogger("PLEX."+__name__) ############################################################################### # What is Companion controllable? CONTROLLABLE = { v.PLEX_TYPE_PHOTO: 'skipPrevious,skipNext,stop', v.PLEX_TYPE_AUDIO: 'playPause,stop,volume,shuffle,repeat,seekTo,' \ 'skipPrevious,skipNext,stepBack,stepForward', v.PLEX_TYPE_VIDEO: 'playPause,stop,volume,audioStream,subtitleStream,' \ 'seekTo,skipPrevious,skipNext,stepBack,stepForward' } class SubscriptionManager: def __init__(self, RequestMgr, player, mgr): self.serverlist = [] self.subscribers = {} self.info = {} self.lastkey = "" self.containerKey = "" self.ratingkey = "" self.lastplayers = {} self.lastinfo = { 'video': {}, 'audio': {}, 'picture': {} } self.server = "" self.protocol = "http" self.port = "" self.playerprops = {} self.doUtils = downloadutils.DownloadUtils().downloadUrl self.xbmcplayer = player self.playqueue = mgr.playqueue self.RequestMgr = RequestMgr def getServerByHost(self, host): if len(self.serverlist) == 1: return self.serverlist[0] for server in self.serverlist: if (server.get('serverName') in host or server.get('server') in host): return server return {} def msg(self, players): log.debug('players: %s', players) msg = v.XML_HEADER msg += ' 30: sub.cleanup() del self.subscribers[sub.uuid] 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: 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' # get the volume from the application info['volume'] = js.get_volume() info['mute'] = js.get_muted() info['plex_transient_token'] = playqueue.plex_transient_token return info class Subscriber: def __init__(self, protocol, host, port, uuid, commandID, subMgr, RequestMgr): self.protocol = protocol or "http" self.host = host self.port = port or 32400 self.uuid = uuid or host self.commandID = int(commandID) or 0 self.navlocationsent = False self.age = 0 self.doUtils = downloadutils.DownloadUtils().downloadUrl self.subMgr = subMgr self.RequestMgr = RequestMgr def __eq__(self, other): return self.uuid == other.uuid def tostr(self): return "uuid=%s,commandID=%i" % (self.uuid, self.commandID) def cleanup(self): self.RequestMgr.closeConnection(self.protocol, self.host, self.port) def send_update(self, msg, is_nav): self.age += 1 if not is_nav: self.navlocationsent = False elif self.navlocationsent: return True else: self.navlocationsent = True msg = re.sub(r"INSERTCOMMANDID", str(self.commandID), msg) log.debug("sending xml to subscriber %s:\n%s" % (self.tostr(), msg)) url = self.protocol + '://' + self.host + ':' + self.port \ + "/:/timeline" t = threading.Thread(target=self.threadedSend, args=(url, msg)) t.start() def threadedSend(self, url, msg): """ Threaded POST request, because they stall due to PMS response missing the Content-Length header :-( """ response = self.doUtils(url, postBody=msg, action_type="POST") log.debug('response is: %s', response) if response in [False, None, 401]: self.subMgr.removeSubscriber(self.uuid)