def TREE_ADDXML(self, elem, child, src, srcXML, param): tag, leftover = self.getParam(src, param) key, leftover, dfltd = self.getKey(src, srcXML, leftover) if 'PlexConnectUDID' in self.options: UDID = self.options['PlexConnectUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, self.PMS_baseURL) auth_token = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'accesstoken') else: auth_token = '' PMS_baseURL = self.PMS_baseURL if key.startswith('//'): # local servers signature pathstart = key.find('/',3) PMS_baseURL= key[:pathstart] path = key[pathstart:] elif key.startswith('/'): # internal full path. path = key #elif key.startswith('http://'): # external address # path = key elif key == '': # internal path path = self.path[srcXML] else: # internal path, add-on path = self.path[srcXML] + '/' + key if PMS_baseURL.startswith('//'): PMS = PlexAPI.getXMLFromMultiplePMS(UDID, path, PMS_baseURL[2:], self.options) else: PMS = PlexAPI.getXMLFromPMS(self.PMS_baseURL, path, self.options, auth_token) self.PMSroot[tag] = PMS.getroot() # store additional PMS XML self.path[tag] = path # store base path return False # tree unchanged (well, source tree yes. but that doesn't count...)
def ATTRIB_MUSICURL(self, src, srcXML, param): key, leftover, dfltd = self.getKey(src, srcXML, param) UDID = self.options['PlexConnectUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, self.PMSaddress) AuthToken = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'accesstoken') scheme = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'scheme') # direct play res = PlexAPI.getDirectAudioPath(key, AuthToken) if res.startswith('/'): # internal full path. res = scheme + '://' + self.PMSaddress + res elif res.startswith('http://') or res.startswith('https://'): # external address hijack = g_param['HostToIntercept'] if hijack in res: dprint(__name__, 1, "twisting...") hijack_twisted = hijack[::-1] res = res.replace(hijack, hijack_twisted) dprint(__name__, 1, res) else: # internal path, add-on res = scheme + '://' + self.PMSaddress + self.path[srcXML] + '/' + res dprint(__name__, 1, 'MusicURL: {0}', res) return res
def getSubtitleJSON(PMS_address, path, options): """ # double check aTV UDID, redo from client IP if needed/possible if not 'PlexConnectUDID' in options: UDID = getATVFromIP(options['aTVAddress']) if UDID: options['PlexConnectUDID'] = UDID """ path = path + '?' if not '?' in path else '&' path = path + 'encoding=utf-8' if not 'PlexConnectUDID' in options: # aTV unidentified, UDID not known return False UDID = options['PlexConnectUDID'] # determine PMS_uuid, PMSBaseURL from IP (PMS_mark) xargs = {} PMS_uuid = PlexAPI.getPMSFromAddress(UDID, PMS_address) PMS_baseURL = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'baseURL') xargs['X-Plex-Token'] = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'accesstoken') dprint(__name__, 1, "subtitle URL: {0}{1}", PMS_baseURL, path) dprint(__name__, 1, "xargs: {0}", xargs) request = urllib2.Request(PMS_baseURL+path , None, xargs) try: response = urllib2.urlopen(request, timeout=20) except urllib2.URLError as e: dprint(__name__, 0, 'No Response from Plex Media Server') if hasattr(e, 'reason'): dprint(__name__, 0, "We failed to reach a server. Reason: {0}", e.reason) elif hasattr(e, 'code'): dprint(__name__, 0, "The server couldn't fulfill the request. Error code: {0}", e.code) return False except IOError: dprint(__name__, 0, 'Error loading response XML from Plex Media Server') return False # Todo: Deal with ANSI files. How to select used "codepage"? subtitleFile = response.read() print response.headers dprint(__name__, 1, "====== received Subtitle ======") dprint(__name__, 1, "{0} [...]", subtitleFile[:255]) dprint(__name__, 1, "====== Subtitle finished ======") if options['PlexConnectSubtitleFormat']=='srt': subtitle = parseSRT(subtitleFile) else: return False JSON = json.dumps(subtitle) dprint(__name__, 1, "====== generated subtitle aTV subtitle JSON ======") dprint(__name__, 1, "{0} [...]", JSON[:255]) dprint(__name__, 1, "====== aTV subtitle JSON finished ======") return(JSON)
def ATTRIB_IMAGEURL(self, src, srcXML, param): key, leftover, dfltd = self.getKey(src, srcXML, param) width, leftover = self.getParam(src, leftover) height, leftover = self.getParam(src, leftover) if height=='': height = width PMS_baseURL = self.PMS_baseURL cmd_start = key.find('PMS(') cmd_end = key.find(')', cmd_start) if cmd_start>-1 and cmd_end>-1 and cmd_end>cmd_start: PMS_baseURL = key[cmd_start+4:cmd_end] key = key[cmd_end+1:] UDID = self.options['PlexConnectUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, PMS_baseURL) AuthToken = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'accesstoken') if width=='': # direct play res = PlexAPI.getDirectImagePath(key, AuthToken) else: # request transcoding res = PlexAPI.getTranscodeImagePath(key, AuthToken, self.path[srcXML], width, height) if res.startswith('/'): # internal full path. res = PMS_baseURL + res elif res.startswith('http://') or key.startswith('https://'): # external address pass else: # internal path, add-on res = PMS_baseURL + self.path[srcXML] + '/' + res dprint(__name__, 1, 'ImageURL: {0}', res) return res
def TREE_ADDXML(self, elem, child, src, srcXML, param): tag, leftover = self.getParam(src, param) key, leftover, dfltd = self.getKey(src, srcXML, leftover) PMS_address = self.PMS_address if key.startswith('//'): # local servers signature pathstart = key.find('/', 3) PMS_address = key[:pathstart] path = key[pathstart:] elif key.startswith('/'): # internal full path. path = key #elif key.startswith('http://'): # external address # path = key elif key == '': # internal path path = self.path[srcXML] else: # internal path, add-on path = self.path[srcXML] + '/' + key if PMS_address[0].isalpha(): # owned, shared type = self.PMS_address PMS = PlexAPI.getXMLFromMultiplePMS(self.ATV_udid, path, type, self.options) else: # IP auth_token = PlexAPI.getPMSProperty(self.ATV_udid, self.PMS_uuid, 'accesstoken') PMS = PlexAPI.getXMLFromPMS(self.PMS_baseURL, path, self.options, auth_token) self.PMSroot[tag] = PMS.getroot() # store additional PMS XML self.path[tag] = path # store base path return False # tree unchanged (well, source tree yes. but that doesn't count...)
def ATTRIB_MUSICURL(self, src, srcXML, param): key, leftover, dfltd = self.getKey(src, srcXML, param) UDID = self.options['PlexConnectUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, self.PMS_baseURL) AuthToken = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'accesstoken') # direct play res = PlexAPI.getDirectAudioPath(key, AuthToken) if res.startswith('/'): # internal full path. res = self.PMS_baseURL + res elif res.startswith('http://') or key.startswith( 'https://'): # external address hijack = g_param['HostToIntercept'] if hijack in res: dprint(__name__, 1, "twisting...") hijack_twisted = hijack[::-1] res = res.replace(hijack, hijack_twisted) dprint(__name__, 1, res) else: # internal path, add-on res = self.PMS_baseURL + self.path[srcXML] + '/' + res dprint(__name__, 1, 'MusicURL: {0}', res) return res
def ATTRIB_IMAGEURL(self, src, srcXML, param): key, leftover, dfltd = self.getKey(src, srcXML, param) width, leftover = self.getParam(src, leftover) height, leftover = self.getParam(src, leftover) if height=='': height = width UDID = self.options['PlexConnectUDID'] AuthToken = g_ATVSettings.getSetting(UDID, 'myplex_auth') if width=='': # direct play res = PlexAPI.getDirectImagePath(key, AuthToken) else: # request transcoding res = PlexAPI.getTranscodeImagePath(key, AuthToken, self.path[srcXML], width, height) if res.startswith('/'): # internal full path. res = 'http://' + self.PMSaddress + res elif res.startswith('http://'): # external address hijack = g_param['HostToIntercept'] if hijack in res: dprint(__name__, 1, "twisting...") hijack_twisted = hijack[::-1] res = res.replace(hijack, hijack_twisted) dprint(__name__, 1, res) else: # internal path, add-on res = 'http://' + self.PMSaddress + self.path[srcXML] + '/' + res dprint(__name__, 1, 'ImageURL: {0}', res) return res
def TREE_ADDXML(self, elem, child, src, srcXML, param): tag, leftover = self.getParam(src, param) key, leftover, dfltd = self.getKey(src, srcXML, leftover) PMS_address = self.PMS_address if key.startswith('//'): # local servers signature pathstart = key.find('/',3) PMS_address= key[:pathstart] path = key[pathstart:] elif key.startswith('/'): # internal full path. path = key #elif key.startswith('http://'): # external address # path = key elif key == '': # internal path path = self.path[srcXML] else: # internal path, add-on path = self.path[srcXML] + '/' + key if PMS_address[0].isalpha(): # owned, shared type = self.PMS_address PMS = PlexAPI.getXMLFromMultiplePMS(self.ATV_udid, path, type, self.options) else: # IP auth_token = PlexAPI.getPMSProperty(self.ATV_udid, self.PMS_uuid, 'accesstoken') PMS = PlexAPI.getXMLFromPMS(self.PMS_baseURL, path, self.options, auth_token) self.PMSroot[tag] = PMS.getroot() # store additional PMS XML self.path[tag] = path # store base path return False # tree unchanged (well, source tree yes. but that doesn't count...)
def ATTRIB_IMAGEURL(self, src, srcXML, param): key, leftover, dfltd = self.getKey(src, srcXML, param) width, leftover = self.getParam(src, leftover) height, leftover = self.getParam(src, leftover) if height=='': height = width PMSaddress = self.PMSaddress cmd_start = key.find('PMS(') cmd_end = key.find(')', cmd_start) if cmd_start>-1 and cmd_end>-1 and cmd_end>cmd_start: PMSaddress = key[cmd_start+4:cmd_end] key = key[cmd_end+1:] UDID = self.options['PlexConnectUDID'] AuthToken = g_ATVSettings.getSetting(UDID, 'myplex_auth') if width=='': # direct play res = PlexAPI.getDirectImagePath(key, AuthToken) else: # request transcoding res = PlexAPI.getTranscodeImagePath(key, AuthToken, self.path[srcXML], width, height) if res.startswith('/'): # internal full path. res = 'http://' + PMSaddress + res elif res.startswith('http://'): # external address pass else: # internal path, add-on res = 'http://' + PMSaddress + self.path[srcXML] + '/' + res dprint(__name__, 1, 'ImageURL: {0}', res) return res
def TREE_ADDXML(self, elem, child, src, srcXML, param): tag, leftover = self.getParam(src, param) key, leftover, dfltd = self.getKey(src, srcXML, leftover) if 'PlexConnectUDID' in self.options: UDID = self.options['PlexConnectUDID'] auth_token = g_ATVSettings.getSetting(UDID, 'myplex_auth') else: auth_token = '' if key.startswith('//local'): # local servers signature path = key[len('//local'):] PMS = PlexAPI.getXMLFromMultiplePMS(UDID, path, self.options, auth_token) elif key.startswith('/'): # internal full path. path = key PMS = PlexAPI.getXMLFromPMS('http://'+self.PMSaddress, path, self.options, auth_token) #elif key.startswith('http://'): # external address # path = key # hijack = g_param['HostToIntercept'] # if hijack in path: # dprint(__name__, 1, "twisting...") # hijack_twisted = hijack[::-1] # path = path.replace(hijack, hijack_twisted) # dprint(__name__, 1, path) elif key == '': # internal path path = self.path[srcXML] PMS = PlexAPI.getXMLFromPMS('http://'+self.PMSaddress, path, self.options, auth_token) else: # internal path, add-on path = self.path[srcXML] + '/' + key PMS = PlexAPI.getXMLFromPMS('http://'+self.PMSaddress, path, self.options, auth_token) self.PMSroot[tag] = PMS.getroot() # store additional PMS XML self.path[tag] = path # store base path return False # tree unchanged (well, source tree yes. but that doesn't count...)
def getSubtitleJSON(PMS_baseURL, path, options): """ # double check aTV UDID, redo from client IP if needed/possible if not 'PlexConnectUDID' in options: UDID = getATVFromIP(options['aTVAddress']) if UDID: options['PlexConnectUDID'] = UDID """ path = path + '?' if not '?' in path else '&' path = path + 'encoding=utf-8' xargs = {} if 'PlexConnectUDID' in options: UDID = options['PlexConnectUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, PMS_baseURL) xargs['X-Plex-Token'] = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'accesstoken') dprint(__name__, 1, "subtitle URL: {0}{1}", PMS_baseURL, path) dprint(__name__, 1, "xargs: {0}", xargs) request = urllib2.Request(PMS_baseURL + path, None, xargs) try: response = urllib2.urlopen(request, timeout=20) except urllib2.URLError as e: dprint(__name__, 0, 'No Response from Plex Media Server') if hasattr(e, 'reason'): dprint(__name__, 0, "We failed to reach a server. Reason: {0}", e.reason) elif hasattr(e, 'code'): dprint(__name__, 0, "The server couldn't fulfill the request. Error code: {0}", e.code) return False except IOError: dprint(__name__, 0, 'Error loading response XML from Plex Media Server') return False # Todo: Deal with ANSI files. How to select used "codepage"? subtitleFile = response.read() print response.headers dprint(__name__, 1, "====== received Subtitle ======") dprint(__name__, 1, "{0} [...]", subtitleFile[:255]) dprint(__name__, 1, "====== Subtitle finished ======") if options['PlexConnectSubtitleFormat'] == 'srt': subtitle = parseSRT(subtitleFile) else: return False JSON = json.dumps(subtitle) dprint(__name__, 1, "====== generated subtitle aTV subtitle JSON ======") dprint(__name__, 1, "{0} [...]", JSON[:255]) dprint(__name__, 1, "====== aTV subtitle JSON finished ======") return (JSON)
def ATTRIB_PMSNAME(self, src, srcXML, param): UDID = self.options['PlexConnectUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, self.PMSaddress) PMS_name = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'name') if PMS_name == '': return "No Server in Proximity" else: return PMS_name
def ATTRIB_PMSNAME(self, src, srcXML, param): UDID = self.options["PlexNMTUDID"] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, self.PMS_baseURL) PMS_name = PlexAPI.getPMSProperty(UDID, PMS_uuid, "name") if PMS_name == "": return "No Server in Proximity" else: return PMS_name
def ATTRIB_PMSNAME(self, src, srcXML, param): UDID = self.options['PlexConnectUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, self.PMS_baseURL) PMS_name = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'name') if PMS_name=='': return "No Server in Proximity" else: return PMS_name
def __init__(self, options, PMSroot, PMS_address, path): self.options = options self.PMSroot = {'main': PMSroot} self.PMS_address = PMS_address # default PMS if nothing else specified self.path = {'main': path} self.ATV_udid = options['PlexConnectUDID'] self.PMS_uuid = PlexAPI.getPMSFromAddress(self.ATV_udid, PMS_address) self.PMS_baseURL = PlexAPI.getPMSProperty(self.ATV_udid, self.PMS_uuid, 'baseURL') self.variables = {}
def ATTRIB_MEDIAURL(self, src, srcXML, param): Video, leftover = self.getElement(src, srcXML, param) if Video!=None: Media = Video.find('Media') # check "Media" element and get key if Media!=None: UDID = self.options['PlexConnectUDID'] AuthToken = g_ATVSettings.getSetting(UDID, 'myplex_auth') if g_ATVSettings.getSetting(UDID, 'transcoderaction')=='DirectPlay' \ or \ g_ATVSettings.getSetting(UDID, 'transcoderaction')=='Auto' and \ Media.get('protocol','-') in ("hls") \ or \ g_ATVSettings.getSetting(UDID, 'transcoderaction')=='Auto' and \ Media.get('container','-') in ("mov", "mp4") and \ Media.get('videoCodec','-') in ("mpeg4", "h264", "drmi") and \ Media.get('audioCodec','-') in ("aac", "ac3", "drms"): # direct play for... # force direct play # or HTTP live stream # or native aTV media res, leftover, dfltd = self.getKey(Media, srcXML, 'Part/key') if Media.get('indirect', False): # indirect... todo: select suitable resolution, today we just take first Media PMS = PlexAPI.getXMLFromPMS(self.PMSaddress, res, self.options, AuthToken) # todo... check key for trailing '/' or even 'http' res, leftover, dfltd = self.getKey(PMS.getroot(), srcXML, 'Video/Media/Part/key') res = PlexAPI.getDirectVideoPath(res, AuthToken) else: # request transcoding res = Video.get('key','') res = PlexAPI.getTranscodeVideoPath(res, AuthToken, self.options, g_ATVSettings) else: dprint(__name__, 0, "MEDIAPATH - element not found: {0}", param) res = 'FILE_NOT_FOUND' # not found? if res.startswith('/'): # internal full path. res = 'http://' + self.PMSaddress + res elif res.startswith('http://'): # external address hijack = g_param['HostToIntercept'] if hijack in res: dprint(__name__, 1, "twisting...") hijack_twisted = hijack[::-1] res = res.replace(hijack, hijack_twisted) dprint(__name__, 1, res) else: # internal path, add-on res = 'http://' + self.PMSaddress + self.path[srcXML] + res dprint(__name__, 1, 'MediaURL: {0}', res) return res
def getKey(self, src, srcXML, param): attrib, leftover = self.getParam(src, param) default, leftover = self.getParam(src, leftover) el, srcXML, attrib = self.getBase(src, srcXML, attrib) # walk the path if neccessary while '/' in attrib and el != None: parts = attrib.split('/', 1) if parts[0].startswith('#'): # internal variable in path el = el.find(self.variables[parts[0][1:]]) elif parts[0].startswith('$'): # setting UDID = self.options['PlexConnectUDID'] el = el.find(g_ATVSettings.getSetting(UDID, parts[0][1:])) elif parts[0].startswith('%'): # PMS property UDID = self.options['PlexConnectUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, self.PMS_baseURL) el = el.find( PlexAPI.getPMSProperty(UDID, PMS_uuid, parts[0][1:])) else: el = el.find(parts[0]) attrib = parts[1] # check element and get attribute if attrib.startswith('#'): # internal variable res = self.variables[attrib[1:]] dfltd = False elif attrib.startswith('$'): # setting UDID = self.options['PlexConnectUDID'] res = g_ATVSettings.getSetting(UDID, attrib[1:]) dfltd = False elif attrib.startswith('%'): # PMS property UDID = self.options['PlexConnectUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, self.PMS_baseURL) res = PlexAPI.getPMSProperty(UDID, PMS_uuid, attrib[1:]) dfltd = False elif attrib.startswith('^'): # aTV property, http request options res = self.options[attrib[1:]] dfltd = False elif el != None and attrib in el.attrib: res = el.get(attrib) dfltd = False else: # path/attribute not found res = default dfltd = True dprint(__name__, 2, "CCmds_getKey: {0},{1},{2}", res, leftover, dfltd) return [res, leftover, dfltd]
def ATTRIB_IMAGEURL(self, src, srcXML, param): key, leftover, dfltd = self.getKey(src, srcXML, param) width, leftover = self.getParam(src, leftover) height, leftover = self.getParam(src, leftover) if height=='': height = width PMS_uuid = self.PMS_uuid PMS_baseURL = self.PMS_baseURL cmd_start = key.find('PMS(') cmd_end = key.find(')', cmd_start) if cmd_start>-1 and cmd_end>-1 and cmd_end>cmd_start: PMS_address = key[cmd_start+4:cmd_end] PMS_uuid = PlexAPI.getPMSFromAddress(self.ATV_udid, PMS_address) PMS_baseURL = PlexAPI.getPMSProperty(self.ATV_udid, PMS_uuid, 'baseURL') key = key[cmd_end+1:] AuthToken = PlexAPI.getPMSProperty(self.ATV_udid, PMS_uuid, 'accesstoken') # transcoder action transcoderAction = g_ATVSettings.getSetting(self.ATV_udid, 'phototranscoderaction') # aTV native filetypes parts = key.rsplit('.',1) photoATVNative = parts[-1].lower() in ['jpg','jpeg','tif','tiff','gif','png'] dprint(__name__, 2, "photo: ATVNative - {0}", photoATVNative) if width=='' and \ transcoderAction=='Auto' and \ photoATVNative: # direct play res = PlexAPI.getDirectImagePath(key, AuthToken) else: if width=='': width = 1920 # max for HDTV. Relate to aTV version? Increase for KenBurns effect? if height=='': height = 1080 # as above # request transcoding res = PlexAPI.getTranscodeImagePath(key, AuthToken, self.path[srcXML], width, height) if res.startswith('/'): # internal full path. res = PMS_baseURL + res elif res.startswith('http://') or key.startswith('https://'): # external address pass else: # internal path, add-on res = PMS_baseURL + self.path[srcXML] + '/' + res dprint(__name__, 1, 'ImageURL: {0}', res) return res
def getKey(self, src, srcXML, param): attrib, leftover = self.getParam(src, param) default, leftover = self.getParam(src, leftover) el, srcXML, attrib = self.getBase(src, srcXML, attrib) # walk the path if neccessary while '/' in attrib and el!=None: parts = attrib.split('/',1) if parts[0].startswith('#'): # internal variable in path el = el.find(self.variables[parts[0][1:]]) elif parts[0].startswith('$'): # setting UDID = self.options['PlexConnectUDID'] el = el.find(g_ATVSettings.getSetting(UDID, parts[0][1:])) elif parts[0].startswith('%'): # PMS property UDID = self.options['PlexConnectUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, self.PMS_baseURL) el = el.find(PlexAPI.getPMSProperty(UDID, PMS_uuid, parts[0][1:])) else: el = el.find(parts[0]) attrib = parts[1] # check element and get attribute if attrib.startswith('#'): # internal variable res = self.variables[attrib[1:]] dfltd = False elif attrib.startswith('$'): # setting UDID = self.options['PlexConnectUDID'] res = g_ATVSettings.getSetting(UDID, attrib[1:]) dfltd = False elif attrib.startswith('%'): # PMS property UDID = self.options['PlexConnectUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, self.PMS_baseURL) res = PlexAPI.getPMSProperty(UDID, PMS_uuid, attrib[1:]) dfltd = False elif attrib.startswith('^'): # aTV property, http request options res = self.options[attrib[1:]] dfltd = False elif el!=None and attrib in el.attrib: res = el.get(attrib) dfltd = False else: # path/attribute not found res = default dfltd = True dprint(__name__, 2, "CCmds_getKey: {0},{1},{2}", res, leftover,dfltd) return [res,leftover,dfltd]
def ATTRIB_URL(self, src, srcXML, param): key, leftover, dfltd = self.getKey(src, srcXML, param) # compare PMS_mark in PlexAPI/getXMLFromMultiplePMS() PMS_mark = '/PMS(' + PlexAPI.getPMSProperty(self.ATV_udid, self.PMS_uuid, 'ip') + ')' # overwrite with URL embedded PMS address cmd_start = key.find('PMS(') cmd_end = key.find(')', cmd_start) if cmd_start>-1 and cmd_end>-1 and cmd_end>cmd_start: PMS_mark = '/'+key[cmd_start:cmd_end+1] key = key[cmd_end+1:] res = g_param['baseURL'] # base address to PlexConnect if key.endswith('.js'): # link to PlexConnect owned .js stuff res = res + key elif key.startswith('http://') or key.startswith('https://'): # external server res = key """ parts = urlparse.urlsplit(key) # (scheme, networklocation, path, ...) key = urlparse.urlunsplit(('', '', parts[2], parts[3], parts[4])) # keep path only PMS_uuid = PlexAPI.getPMSFromIP(g_param['PMS_list'], parts.hostname) PMSaddress = PlexAPI.getAddress(g_param['PMS_list'], PMS_uuid) # get PMS address (might be local as well!?!) res = res + '/PMS(' + quote_plus(PMSaddress) + ')' + key """ elif key.startswith('/'): # internal full path. res = res + PMS_mark + key elif key == '': # internal path res = res + PMS_mark + self.path[srcXML] else: # internal path, add-on res = res + PMS_mark + self.path[srcXML] + '/' + key return res
def setUserPref(self): log.info('Setting user preferences') # Only try to get user avatar if there is a token if self.currToken: url = PlexAPI.PlexAPI().GetUserArtworkURL(self.currUser) if url: window('PlexUserImage', value=url)
def __init__(self, item): self.item = item self.API = PlexAPI.API(item) self.doUtils = DownloadUtils().downloadUrl self.machineIdentifier = window('plex_machineIdentifier')
def ATTRIB_MUSICURL(self, src, srcXML, param): key, leftover, dfltd = self.getKey(src, srcXML, param) AuthToken = PlexAPI.getPMSProperty(self.ATV_udid, self.PMS_uuid, 'accesstoken') # direct play res = PlexAPI.getDirectAudioPath(key, AuthToken) if res.startswith('/'): # internal full path. res = self.PMS_baseURL + res elif res.startswith('http://') or res.startswith('https://'): # external address pass else: # internal path, add-on res = self.PMS_baseURL + self.path[srcXML] + '/' + res dprint(__name__, 1, 'MusicURL: {0}', res) return res
def __init__(self, item): self.item = item self.API = PlexAPI.API(item) self.userid = window('currUserId') self.server = window('pms_server') self.machineIdentifier = window('plex_machineIdentifier')
def loadCurrUser(self, username, userId, usertoken, authenticated=False): log.debug('Loading current user') doUtils = self.doUtils self.currUserId = userId self.currToken = usertoken self.currServer = self.getServer() self.ssl = self.getSSLverify() self.sslcert = self.getSSL() if authenticated is False: log.debug('Testing validity of current token') res = PlexAPI.PlexAPI().CheckConnection(self.currServer, token=self.currToken, verifySSL=self.ssl) if res is False: # PMS probably offline return False elif res == 401: log.error('Token is no longer valid') return 401 elif res >= 400: log.error('Answer from PMS is not as expected. Retrying') return False # Set to windows property window('currUserId', value=userId) window('plex_username', value=username) # This is the token for the current PMS (might also be '') window('pms_token', value=self.currToken) # This is the token for plex.tv for the current user # Is only '' if user is not signed in to plex.tv window('plex_token', value=settings('plexToken')) window('plex_restricteduser', value=settings('plex_restricteduser')) window('pms_server', value=self.currServer) window('plex_machineIdentifier', value=self.machineIdentifier) window('plex_servername', value=self.servername) window('plex_authenticated', value='true') window('useDirectPaths', value='true' if settings('useDirectPaths') == "1" else 'false') window('plex_force_transcode_pix', value='true' if settings('force_transcode_pix') == "1" else 'false') # Start DownloadUtils session doUtils.startSession(reset=True) # self.getAdditionalUsers() # Set user preferences in settings self.currUser = username self.setUserPref() # Writing values to settings file settings('username', value=username) settings('userid', value=userId) settings('accessToken', value=usertoken) return True
def ATTRIB_MUSICURL(self, src, srcXML, param): key, leftover, dfltd = self.getKey(src, srcXML, param) AuthToken = PlexAPI.getPMSProperty(self.ATV_udid, self.PMS_uuid, 'accesstoken') # direct play res = PlexAPI.getDirectAudioPath(key, AuthToken) if res.startswith('/'): # internal full path. res = self.PMS_baseURL + res elif res.startswith('http://') or res.startswith( 'https://'): # external address pass else: # internal path, add-on res = self.PMS_baseURL + self.path[srcXML] + '/' + res dprint(__name__, 1, 'MusicURL: {0}', res) return res
def ATTRIB_MUSICURL(self, src, srcXML, param): key, leftover, dfltd = self.getKey(src, srcXML, param) UDID = self.options["PlexNMTUDID"] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, self.PMS_baseURL) AuthToken = PlexAPI.getPMSProperty(UDID, PMS_uuid, "accesstoken") # direct play res = PlexAPI.getDirectAudioPath(key, AuthToken) if res.startswith("/"): # internal full path. res = self.PMS_baseURL + res elif res.startswith("http://") or res.startswith("https://"): # external address pass else: # internal path, add-on res = self.PMS_baseURL + self.path[srcXML] + "/" + res dprint(__name__, 1, "MusicURL: {0}", res) return res
def __init__(self, item): self.item = item self.API = PlexAPI.API(item) self.clientInfo = clientinfo.ClientInfo() self.userid = utils.window('currUserId') self.server = utils.window('pms_server') self.machineIdentifier = utils.window('plex_machineIdentifier')
def addtoPlaylist_xbmc(self, playlist, item): path = "plugin://plugin.video.plexkodiconnect.movies/" params = {'mode': "play", 'dbid': 999999999} API = PlexAPI.API(item[0]) params['id'] = API.getRatingKey() params['filename'] = API.getKey() playurl = path + '?' + urlencode(params) listitem = xbmcgui.ListItem() playlist.add(playurl, listitem)
def __init__(self, item): self.item = item self.API = PlexAPI.API(item) self.userid = window('currUserId') self.server = window('pms_server') if self.API.getType() == 'track': self.pl = playlist.Playlist(typus='music') else: self.pl = playlist.Playlist(typus='video')
def TREE_ADDXML(self, elem, child, src, srcXML, param): tag, leftover = self.getParam(src, param) key, leftover, dfltd = self.getKey(src, srcXML, leftover) if "PlexNMTUDID" in self.options: UDID = self.options["PlexNMTUDID"] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, self.PMS_baseURL) auth_token = PlexAPI.getPMSProperty(UDID, PMS_uuid, "accesstoken") else: auth_token = "" if key.startswith("//"): # local servers signature pathstart = key.find("/", 3) type = key[2:pathstart] path = key[pathstart:] PMS = PlexAPI.getXMLFromMultiplePMS(UDID, path, type, self.options) elif key.startswith("/"): # internal full path. path = key PMS = PlexAPI.getXMLFromPMS(self.PMS_baseURL, path, self.options, auth_token) # elif key.startswith('http://'): # external address # path = key elif key == "": # internal path path = self.path[srcXML] PMS = PlexAPI.getXMLFromPMS(self.PMS_baseURL, path, self.options, auth_token) else: # internal path, add-on path = self.path[srcXML] + "/" + key PMS = PlexAPI.getXMLFromPMS(self.PMS_baseURL, path, self.options, auth_token) self.PMSroot[tag] = PMS.getroot() # store additional PMS XML self.path[tag] = path # store base path return False # tree unchanged (well, source tree yes. but that doesn't count...)
def TREE_ADDXML(self, elem, child, src, srcXML, param): tag, leftover = self.getParam(src, param) key, leftover, dfltd = self.getKey(src, srcXML, leftover) if 'PlexNMTUDID' in self.options: UDID = self.options['PlexNMTUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, self.PMS_baseURL) auth_token = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'accesstoken') else: auth_token = '' if key.startswith('//'): # local servers signature pathstart = key.find('/', 3) type = key[2:pathstart] path = key[pathstart:] PMS = PlexAPI.getXMLFromMultiplePMS(UDID, path, type, self.options) elif key.startswith('/'): # internal full path. path = key PMS = PlexAPI.getXMLFromPMS(self.PMS_baseURL, path, self.options, auth_token) #elif key.startswith('http://'): # external address # path = key elif key == '': # internal path path = self.path[srcXML] PMS = PlexAPI.getXMLFromPMS(self.PMS_baseURL, path, self.options, auth_token) else: # internal path, add-on path = self.path[srcXML] + '/' + key PMS = PlexAPI.getXMLFromPMS(self.PMS_baseURL, path, self.options, auth_token) self.PMSroot[tag] = PMS.getroot() # store additional PMS XML self.path[tag] = path # store base path return False # tree unchanged (well, source tree yes. but that doesn't count...)
def ATTRIB_URL(self, src, srcXML, param): key, leftover, dfltd = self.getKey(src, srcXML, param) res = 'http://' + g_param['HostOfPlexConnect'] # base address to PlexConnect if key.endswith('.js'): # link to PlexConnect owned .js stuff pass elif key.startswith('http://'): # external server parts = urlparse.urlsplit(key) # (scheme, networklocation, path, ...) key = urlparse.urlunsplit(('', '', parts[2], parts[3], parts[4])) # keep path only PMS_uuid = PlexAPI.getPMSFromIP(g_param['PMS_list'], parts.hostname) PMSaddress = PlexAPI.getAddress(g_param['PMS_list'], PMS_uuid) # get PMS address (might be local as well!?!) res = res + '/PMS(' + quote_plus(PMSaddress) + ')' else: # include current PMS address res = res + '/PMS(' + quote_plus(self.PMSaddress) + ')' if key.startswith('/'): # internal full path. res = res + key elif key == '': # internal path res = res + self.path[srcXML] else: # internal path, add-on res = res + self.path[srcXML] + '/' + key return res
def __init__(self, item): self.item = item self.API = PlexAPI.API(item) self.clientInfo = clientinfo.ClientInfo() self.addonName = self.clientInfo.getAddonName() self.userid = utils.window('currUserId') self.server = utils.window('pms_server') self.artwork = artwork.Artwork() self.emby = embyserver.Read_EmbyServer() self.pl = playlist.Playlist()
def addtoPlaylist_xbmc(self, playlist, item): API = PlexAPI.API(item[0]) params = { 'mode': "play", 'dbid': 999999999, 'id': API.getRatingKey(), 'filename': API.getKey() } playurl = "plugin://plugin.video.plexkodiconnect.movies/?%s" \ % urlencode(params) listitem = API.CreateListItemFromPlexItem() playbackutils.PlaybackUtils(item[0]).setArtwork(listitem) playlist.add(playurl, listitem)
def ATTRIB_MUSICURL(self, src, srcXML, param): key, leftover, dfltd = self.getKey(src, srcXML, param) UDID = self.options["PlexConnectUDID"] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, self.PMS_baseURL) AuthToken = PlexAPI.getPMSProperty(UDID, PMS_uuid, "accesstoken") # direct play res = PlexAPI.getDirectAudioPath(key, AuthToken) if res.startswith("/"): # internal full path. res = self.PMS_baseURL + res elif res.startswith("http://") or key.startswith("https://"): # external address hijack = g_param["HostToIntercept"] if hijack in res: dprint(__name__, 1, "twisting...") hijack_twisted = hijack[::-1] res = res.replace(hijack, hijack_twisted) dprint(__name__, 1, res) else: # internal path, add-on res = self.PMS_baseURL + self.path[srcXML] + "/" + res dprint(__name__, 1, "MusicURL: {0}", res) return res
def ATTRIB_BACKGROUNDURL(self, src, srcXML, param): key, leftover, dfltd = self.getKey(src, srcXML, param) if key.startswith('/'): # internal full path. key = self.PMS_baseURL + key elif key.startswith('http://') or key.startswith('https://'): # external address pass else: # internal path, add-on key = self.PMS_baseURL + self.path[srcXML] + key auth_token = PlexAPI.getPMSProperty(self.ATV_udid, self.PMS_uuid, 'accesstoken') dprint(__name__, 0, "Background (Source): {0}", key) res = g_param['baseURL'] # base address to PlexConnect res = res + PILBackgrounds.generate(self.PMS_uuid, key, auth_token, self.options['aTVScreenResolution'], g_ATVSettings.getSetting(self.ATV_udid, 'fanart_blur')) dprint(__name__, 0, "Background: {0}", res) return res
def __init__(self): log.debug('Entering initialsetup class') self.clientInfo = clientinfo.ClientInfo() self.addonId = self.clientInfo.getAddonId() self.doUtils = downloadutils.DownloadUtils().downloadUrl self.userClient = userclient.UserClient() self.plx = PlexAPI.PlexAPI() self.dialog = xbmcgui.Dialog() self.server = self.userClient.getServer() self.serverid = settings('plex_machineIdentifier') # Get Plex credentials from settings file, if they exist plexdict = self.plx.GetPlexLoginFromSettings() self.myplexlogin = plexdict['myplexlogin'] == 'true' self.plexLogin = plexdict['plexLogin'] self.plexToken = plexdict['plexToken'] self.plexid = plexdict['plexid'] if self.plexToken: log.debug('Found a plex.tv token in the settings')
def AddTrailers(self, xml): """ Adds trailers to a movie, if applicable. Returns True if trailers were added """ # Failure when downloading trailer playQueue if xml in (None, 401): return False # Failure when getting trailers, e.g. when no plex pass if xml.attrib.get('size') == '1': return False if settings('askCinema') == "true": resp = xbmcgui.Dialog().yesno(addonName, "Play trailers?") if not resp: # User selected to not play trailers log.info("Skip trailers.") return False # Playurl needs to point back so we can get metadata! path = "plugin://plugin.video.plexkodiconnect.movies/" params = { 'mode': "play", 'dbid': 999999999 } for counter, intro in enumerate(xml): # Don't process the last item - it's the original movie if counter == len(xml)-1: break # The server randomly returns intros, process them. # introListItem = xbmcgui.ListItem() # introPlayurl = putils.PlayUtils(intro).getPlayUrl() introAPI = PlexAPI.API(intro) params['id'] = introAPI.getRatingKey() params['filename'] = introAPI.getKey() introPlayurl = path + '?' + urlencode(params) log.info("Adding Intro: %s" % introPlayurl) self.pl.insertintoPlaylist(self.currentPosition, url=introPlayurl) self.currentPosition += 1 return True
def __init__(self): self.kodi_id = xbmc.getInfoLabel('ListItem.DBID').decode('utf-8') self.item_type = self._get_item_type() self.item_id = self._get_item_id(self.kodi_id, self.item_type) log.info("Found item_id: %s item_type: %s" % (self.item_id, self.item_type)) if not self.item_id: return self.item = GetPlexMetadata(self.item_id) self.api = PlexAPI.API(self.item) if self._select_menu(): self._action_menu() if self._selected_option in (OPTIONS['Delete'], OPTIONS['Refresh']): log.info("refreshing container") xbmc.sleep(500) xbmc.executebuiltin('Container.Refresh')
def ATTRIB_MUSICURL(self, src, srcXML, param): key, leftover, dfltd = self.getKey(src, srcXML, param) UDID = self.options['PlexConnectUDID'] AuthToken = g_ATVSettings.getSetting(UDID, 'myplex_auth') # direct play res = PlexAPI.getDirectAudioPath(key, AuthToken) if res.startswith('/'): # internal full path. res = 'http://' + self.PMSaddress + res elif res.startswith('http://'): # external address hijack = g_param['HostToIntercept'] if hijack in res: dprint(__name__, 1, "twisting...") hijack_twisted = hijack[::-1] res = res.replace(hijack, hijack_twisted) dprint(__name__, 1, res) else: # internal path, add-on res = 'http://' + self.PMSaddress + self.path[srcXML] + '/' + res dprint(__name__, 1, 'MusicURL: {0}', res) return res
def ATTRIB_MUSICURL(self, src, srcXML, param): Track, leftover = self.getElement(src, srcXML, param) AuthToken = PlexAPI.getPMSProperty(self.ATV_udid, self.PMS_uuid, 'accesstoken') if not Track: # not a complete audio/track structure - take key directly and build direct-play path key, leftover, dfltd = self.getKey(src, srcXML, param) res = PlexAPI.getDirectAudioPath(key, AuthToken) res = PlexAPI.getURL(self.PMS_baseURL, self.path[srcXML], res) dprint(__name__, 1, 'MusicURL - direct: {0}', res) return res # complete track structure - request transcoding if needed Media = Track.find('Media') # check "Media" element and get key if Media!=None: # transcoder action setting? # transcoder bitrate setting [kbps] - eg. 128, 256, 384, 512? maxAudioBitrate = '384' audioATVNative = \ Media.get('audioCodec','-') in ("mp3", "aac", "ac3", "drms", "alac", "aiff", "wav") # check Media.get('container') as well - mp3, m4a, ...? dprint(__name__, 2, "audio: ATVNative - {0}", audioATVNative) if audioATVNative and\ int(Media.get('bitrate','0')) < int(maxAudioBitrate): # direct play res, leftover, dfltd = self.getKey(Media, srcXML, 'Part/key') res = PlexAPI.getDirectAudioPath(res, AuthToken) else: # request transcoding res, leftover, dfltd = self.getKey(Track, srcXML, 'key') res = PlexAPI.getTranscodeAudioPath(res, AuthToken, self.options, maxAudioBitrate) else: dprint(__name__, 0, "MEDIAPATH - element not found: {0}", param) res = 'FILE_NOT_FOUND' # not found? res = PlexAPI.getURL(self.PMS_baseURL, self.path[srcXML], res) dprint(__name__, 1, 'MusicURL: {0}', res) return res
def _initiatePlaylist(self): log.info('Initiating playlist') playlist = None with embydb.GetEmbyDB() as emby_db: for item in self.items: itemid = item['plexId'] embydb_item = emby_db.getItem_byId(itemid) try: mediatype = embydb_item[4] except TypeError: log.info('Couldnt find item %s in Kodi db' % itemid) item = PlexFunctions.GetPlexMetadata(itemid) if item in (None, 401): log.info('Couldnt find item %s on PMS, trying next' % itemid) continue if PlexAPI.API(item[0]).getType() == 'track': playlist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC) log.info('Music playlist initiated') self.typus = 'music' else: playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) log.info('Video playlist initiated') self.typus = 'video' else: if mediatype == 'song': playlist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC) log.info('Music playlist initiated') self.typus = 'music' else: playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) log.info('Video playlist initiated') self.typus = 'video' break self.playlist = playlist if self.playlist is not None: self.playlistId = self.playlist.getPlayListId()
def TREE_ADDXML(self, elem, child, src, srcXML, param): tag, leftover = self.getParam(src, param) key, leftover, dfltd = self.getKey(src, srcXML, leftover) if 'PlexConnectUDID' in self.options: UDID = self.options['PlexConnectUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, self.PMSaddress) auth_token = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'accesstoken') scheme = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'scheme') else: auth_token = '' scheme = 'http' if key.startswith('//'): # local servers signature pathstart = key.find('/',3) type = key[2:pathstart] path = key[pathstart:] PMS = PlexAPI.getXMLFromMultiplePMS(UDID, path, type, self.options) elif key.startswith('/'): # internal full path. path = key PMS = PlexAPI.getXMLFromPMS(scheme+'://'+self.PMSaddress, path, self.options, auth_token) #elif key.startswith('http://'): # external address # path = key # hijack = g_param['HostToIntercept'] # if hijack in path: # dprint(__name__, 1, "twisting...") # hijack_twisted = hijack[::-1] # path = path.replace(hijack, hijack_twisted) # dprint(__name__, 1, path) elif key == '': # internal path path = self.path[srcXML] PMS = PlexAPI.getXMLFromPMS(scheme+'://'+self.PMSaddress, path, self.options, auth_token) else: # internal path, add-on path = self.path[srcXML] + '/' + key PMS = PlexAPI.getXMLFromPMS(scheme+'://'+self.PMSaddress, path, self.options, auth_token) self.PMSroot[tag] = PMS.getroot() # store additional PMS XML self.path[tag] = path # store base path return False # tree unchanged (well, source tree yes. but that doesn't count...)
def ATTRIB_URL(self, src, srcXML, param): key, leftover, dfltd = self.getKey(src, srcXML, param) # compare PMS_mark in PlexAPI/getXMLFromMultiplePMS() PMS_mark = '/PMS(' + PlexAPI.getPMSProperty(self.ATV_udid, self.PMS_uuid, 'ip') + ')' # overwrite with URL embedded PMS address cmd_start = key.find('PMS(') cmd_end = key.find(')', cmd_start) if cmd_start > -1 and cmd_end > -1 and cmd_end > cmd_start: PMS_mark = '/' + key[cmd_start:cmd_end + 1] key = key[cmd_end + 1:] res = g_param['baseURL'] # base address to PlexConnect if key.endswith('.js'): # link to PlexConnect owned .js stuff res = res + key elif key.startswith('http://') or key.startswith( 'https://'): # external server res = key """ parts = urlparse.urlsplit(key) # (scheme, networklocation, path, ...) key = urlparse.urlunsplit(('', '', parts[2], parts[3], parts[4])) # keep path only PMS_uuid = PlexAPI.getPMSFromIP(g_param['PMS_list'], parts.hostname) PMSaddress = PlexAPI.getAddress(g_param['PMS_list'], PMS_uuid) # get PMS address (might be local as well!?!) res = res + '/PMS(' + quote_plus(PMSaddress) + ')' + key """ elif key.startswith('/'): # internal full path. res = res + PMS_mark + key elif key == '': # internal path res = res + PMS_mark + self.path[srcXML] else: # internal path, add-on res = res + PMS_mark + self.path[srcXML] + '/' + key return res
def TREE_ADDXML(self, elem, child, src, srcXML, param): tag, leftover = self.getParam(src, param) key, leftover, dfltd = self.getKey(src, srcXML, leftover) if key.startswith('/'): # internal full path. path = key #elif key.startswith('http://'): # external address # path = key # hijack = g_param['HostToIntercept'] # if hijack in path: # dprint(__name__, 1, "twisting...") # hijack_twisted = hijack[::-1] # path = path.replace(hijack, hijack_twisted) # dprint(__name__, 1, path) elif key == '': # internal path path = self.path[srcXML] else: # internal path, add-on path = self.path[srcXML] + '/' + key PMS = PlexAPI.getXMLFromPMS(g_param['Addr_PMS'], path) self.PMSroot[tag] = PMS.getroot() # store additional PMS XML self.path[tag] = path # store base path return False # tree unchanged (well, source tree yes. but that doesn't count...)
def ATTRIB_MEDIAURL(self, src, srcXML, param): Video, leftover = self.getElement(src, srcXML, param) UDID = self.options['PlexConnectUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, self.PMSaddress) AuthToken = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'accesstoken') if not Video: # not a complete video structure - take key directly and build direct-play path key, leftover, dfltd = self.getKey(src, srcXML, param) res = PlexAPI.getDirectVideoPath(key, AuthToken) res = PlexAPI.getURL('http://' + self.PMSaddress, self.path[srcXML], res) return res # complete video structure - request transcoding if needed Media = Video.find('Media') # check "Media" element and get key if Media != None: if g_ATVSettings.getSetting(UDID, 'transcoderaction')=='DirectPlay' \ or \ g_ATVSettings.getSetting(UDID, 'transcoderaction')=='Auto' and \ Media.get('protocol','-') in ("hls") \ or \ g_ATVSettings.getSetting(UDID, 'transcoderaction')=='Auto' and \ Media.get('container','-') in ("mov", "mp4") and \ Media.get('videoCodec','-') in ("mpeg4", "h264", "drmi") and \ Media.get('audioCodec','-') in ("aac", "ac3", "drms"): # direct play for... # force direct play # or HTTP live stream # or native aTV media res, leftover, dfltd = self.getKey(Media, srcXML, 'Part/key') if Media.get( 'indirect', False ): # indirect... todo: select suitable resolution, today we just take first Media PMS = PlexAPI.getXMLFromPMS( 'http://' + self.PMSaddress, res, self.options, AuthToken ) # todo... check key for trailing '/' or even 'http' res, leftover, dfltd = self.getKey(PMS.getroot(), srcXML, 'Video/Media/Part/key') res = PlexAPI.getDirectVideoPath(res, AuthToken) else: # request transcoding res = Video.get('key', '') res = PlexAPI.getTranscodeVideoPath(res, AuthToken, self.options, g_ATVSettings) else: dprint(__name__, 0, "MEDIAPATH - element not found: {0}", param) res = 'FILE_NOT_FOUND' # not found? if res.startswith('/'): # internal full path. res = 'http://' + self.PMSaddress + res elif res.startswith('http://'): # external address hijack = g_param['HostToIntercept'] if hijack in res: dprint(__name__, 1, "twisting...") hijack_twisted = hijack[::-1] res = res.replace(hijack, hijack_twisted) dprint(__name__, 1, res) else: # internal path, add-on res = 'http://' + self.PMSaddress + self.path[srcXML] + res dprint(__name__, 1, 'MediaURL: {0}', res) return res
def XML_PMS2aTV(PMS_baseURL, path, options): # double check aTV UDID, redo from client IP if needed/possible if not 'PlexConnectUDID' in options: UDID = getATVFromIP(options['aTVAddress']) if UDID: options['PlexConnectUDID'] = UDID else: declareATV(options['PlexConnectUDID'], options['aTVAddress']) # update with latest info # check cmd to work on cmd = '' if 'PlexConnect' in options: cmd = options['PlexConnect'] dprint(__name__, 1, "PlexConnect Cmd: "+cmd) # check aTV language setting if not 'aTVLanguage' in options: dprint(__name__, 1, "no aTVLanguage - pick en") options['aTVLanguage'] = 'en' # XML Template selector # - PlexConnect command # - path # - PMS ViewGroup XMLtemplate = '' PMS = None PMSroot = None # XML direct request or # XMLtemplate defined by solely PlexConnect Cmd if path.endswith(".xml"): XMLtemplate = path.lstrip('/') path = '' # clear path - we don't need PMS-XML elif cmd=='Play': XMLtemplate = 'PlayVideo.xml' elif cmd=='PlayVideo_ChannelsV1': dprint(__name__, 1, "playing Channels XML Version 1: {0}".format(path)) UDID = options['PlexConnectUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, PMS_baseURL) auth_token = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'accesstoken') path = PlexAPI.getDirectVideoPath(path, auth_token) return XML_PlayVideo_ChannelsV1(PMS_baseURL, path) # direct link, no PMS XML available elif cmd=='PlayTrailer': trailerID = options['PlexConnectTrailerID'] info = urllib2.urlopen("http://youtube.com/get_video_info?video_id=" + trailerID).read() parsed = urlparse.parse_qs(info) key = 'url_encoded_fmt_stream_map' if not key in parsed: return XML_Error('PlexConnect', 'Youtube: No Trailer Info available') streams = parsed[key][0].split(',') url = '' for i in range(len(streams)): stream = urlparse.parse_qs(streams[i]) if stream['itag'][0] == '18': url = stream['url'][0] + '&signature=' + stream['sig'][0] if url == '': return XML_Error('PlexConnect','Youtube: ATV compatible Trailer not available') return XML_PlayVideo_ChannelsV1('', url.replace('&','&')) elif cmd=='ScrobbleMenu': XMLtemplate = 'ScrobbleMenu.xml' elif cmd=='ScrobbleMenuVideo': XMLtemplate = 'ScrobbleMenuVideo.xml' elif cmd=='ScrobbleMenuTVOnDeck': XMLtemplate = 'ScrobbleMenuTVOnDeck.xml' elif cmd=='ChangeShowArtwork': XMLtemplate = 'ChangeShowArtwork.xml' elif cmd=='ChangeSingleArtwork': XMLtemplate = 'ChangeSingleArtwork.xml' elif cmd=='ChangeSingleArtworkVideo': XMLtemplate = 'ChangeSingleArtworkVideo.xml' elif cmd=='PhotoBrowser': XMLtemplate = 'Photo_Browser.xml' elif cmd=='MoviePreview': XMLtemplate = 'MoviePreview.xml' elif cmd=='HomeVideoPrePlay': XMLtemplate = 'HomeVideoPrePlay.xml' elif cmd=='MoviePrePlay': XMLtemplate = 'MoviePrePlay.xml' elif cmd=='EpisodePrePlay': XMLtemplate = 'EpisodePrePlay.xml' elif cmd=='ChannelPrePlay': XMLtemplate = 'ChannelPrePlay.xml' elif cmd=='ChannelsVideo': XMLtemplate = 'ChannelsVideo.xml' elif cmd=='ByFolder': XMLtemplate = 'ByFolder.xml' elif cmd=='HomeVideoByFolder': XMLtemplate = 'HomeVideoByFolder.xml' elif cmd == 'HomeVideoDirectory': XMLtemplate = 'HomeVideoDirectory.xml' elif cmd=='MovieByFolder': XMLtemplate = 'MovieByFolder.xml' elif cmd == 'MovieDirectory': XMLtemplate = 'MovieDirectory.xml' elif cmd == 'MovieSection': XMLtemplate = 'MovieSection.xml' elif cmd == 'HomeVideoSection': XMLtemplate = 'HomeVideoSection.xml' elif cmd == 'TVSection': XMLtemplate = 'TVSection.xml' elif cmd.find('SectionPreview') != -1: XMLtemplate = cmd + '.xml' elif cmd == 'AllMovies': XMLtemplate = 'Movie_'+g_ATVSettings.getSetting(options['PlexConnectUDID'], 'movieview').replace(' ','')+'.xml' elif cmd == 'AllHomeVideos': XMLtemplate = 'HomeVideo_'+g_ATVSettings.getSetting(options['PlexConnectUDID'], 'homevideoview').replace(' ','')+'.xml' elif cmd == 'MovieSecondary': XMLtemplate = 'MovieSecondary.xml' elif cmd == 'AllShows': XMLtemplate = 'Show_'+g_ATVSettings.getSetting(options['PlexConnectUDID'], 'showview')+'.xml' elif cmd == 'TVSecondary': XMLtemplate = 'TVSecondary.xml' elif cmd == 'PhotoSecondary': XMLtemplate = 'PhotoSecondary.xml' elif cmd == 'Directory': XMLtemplate = 'Directory.xml' elif cmd == 'DirectoryWithPreview': XMLtemplate = 'DirectoryWithPreview.xml' elif cmd == 'DirectoryWithPreviewActors': XMLtemplate = 'DirectoryWithPreviewActors.xml' elif cmd=='Settings': XMLtemplate = 'Settings.xml' path = '' # clear path - we don't need PMS-XML elif cmd=='SettingsVideoOSD': XMLtemplate = 'Settings_VideoOSD.xml' path = '' # clear path - we don't need PMS-XML elif cmd=='SettingsMovies': XMLtemplate = 'Settings_Movies.xml' path = '' # clear path - we don't need PMS-XML elif cmd=='SettingsTVShows': XMLtemplate = 'Settings_TVShows.xml' path = '' # clear path - we don't need PMS-XML elif cmd=='SettingsHomeVideos': XMLtemplate = 'Settings_HomeVideos.xml' path = '' # clear path - we don't need PMS-XML elif cmd.startswith('SettingsToggle:'): opt = cmd[len('SettingsToggle:'):] # cut command: parts = opt.split('+') g_ATVSettings.toggleSetting(options['PlexConnectUDID'], parts[0].lower()) XMLtemplate = parts[1] + ".xml" dprint(__name__, 2, "ATVSettings->Toggle: {0} in template: {1}", parts[0], parts[1]) path = '' # clear path - we don't need PMS-XML elif cmd==('MyPlexLogin'): dprint(__name__, 2, "MyPlex->Logging In...") if not 'PlexConnectCredentials' in options: return XML_Error('PlexConnect', 'MyPlex Sign In called without Credentials.') parts = options['PlexConnectCredentials'].split(':',1) (username, auth_token) = PlexAPI.MyPlexSignIn(parts[0], parts[1], options) UDID = options['PlexConnectUDID'] g_ATVSettings.setSetting(UDID, 'myplex_user', username) g_ATVSettings.setSetting(UDID, 'myplex_auth', auth_token) XMLtemplate = 'Settings.xml' path = '' # clear path - we don't need PMS-XML elif cmd=='MyPlexLogout': dprint(__name__, 2, "MyPlex->Logging Out...") UDID = options['PlexConnectUDID'] auth_token = g_ATVSettings.getSetting(UDID, 'myplex_auth') PlexAPI.MyPlexSignOut(auth_token) g_ATVSettings.setSetting(UDID, 'myplex_user', '') g_ATVSettings.setSetting(UDID, 'myplex_auth', '') XMLtemplate = 'Settings.xml' path = '' # clear path - we don't need PMS-XML elif cmd.startswith('Discover'): UDID = options['PlexConnectUDID'] auth_token = g_ATVSettings.getSetting(UDID, 'myplex_auth') PlexAPI.discoverPMS(UDID, g_param['CSettings'], auth_token) return XML_Error('PlexConnect', 'Discover!') # not an error - but aTV won't care anyways. elif path.startswith('/search?'): XMLtemplate = 'Search_Results.xml' elif path=='/library/sections': # from PlexConnect.xml -> for //local, //myplex XMLtemplate = 'Library.xml' elif path=='/channels/all': XMLtemplate = 'Channel_'+g_ATVSettings.getSetting(options['PlexConnectUDID'], 'channelview')+'.xml' path = '' # request PMS XML if not path=='': if 'PlexConnectUDID' in options: UDID = options['PlexConnectUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, PMS_baseURL) auth_token = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'accesstoken') else: auth_token = '' if PMS_baseURL.startswith('//'): # //local, //myplex UDID = options['PlexConnectUDID'] type = PMS_baseURL[2:] PMS = PlexAPI.getXMLFromMultiplePMS(UDID, path, type, options) else: PMS = PlexAPI.getXMLFromPMS(PMS_baseURL, path, options, authtoken=auth_token) if PMS==False: return XML_Error('PlexConnect', 'No Response from Plex Media Server') PMSroot = PMS.getroot() dprint(__name__, 1, "viewGroup: "+PMSroot.get('ViewGroup','None')) # XMLtemplate defined by PMS XML content if path=='': pass # nothing to load elif not XMLtemplate=='': pass # template already selected elif PMSroot.get('viewGroup','')=="secondary" and (PMSroot.get('art','').find('video') != -1 or PMSroot.get('thumb','').find('video') != -1): XMLtemplate = 'HomeVideoSectionTopLevel.xml' elif PMSroot.get('viewGroup','')=="secondary" and (PMSroot.get('art','').find('movie') != -1 or PMSroot.get('thumb','').find('movie') != -1): XMLtemplate = 'MovieSectionTopLevel.xml' elif PMSroot.get('viewGroup','')=="secondary" and (PMSroot.get('art','').find('show') != -1 or PMSroot.get('thumb','').find('show') != -1): XMLtemplate = 'TVSectionTopLevel.xml' elif PMSroot.get('viewGroup','')=="secondary" and (PMSroot.get('art','').find('photo') != -1 or PMSroot.get('thumb','').find('photo') != -1): XMLtemplate = 'PhotoSectionTopLevel.xml' elif PMSroot.get('viewGroup','')=="secondary": XMLtemplate = 'Directory.xml' elif PMSroot.get('viewGroup','')=='show': if PMSroot.get('title2')=='By Folder': # By Folder View XMLtemplate = 'ByFolder.xml' else: # TV Show grid view XMLtemplate = 'Show_'+g_ATVSettings.getSetting(options['PlexConnectUDID'], 'showview')+'.xml' elif PMSroot.get('viewGroup','')=='season': # TV Season view XMLtemplate = 'Season_'+g_ATVSettings.getSetting(options['PlexConnectUDID'], 'seasonview')+'.xml' elif PMSroot.get('viewGroup','')=='movie' and PMSroot.get('thumb','').find('video') != -1: if PMSroot.get('title2')=='By Folder': # By Folder View XMLtemplate = 'HomeVideoByFolder.xml' else: # Home Video listing XMLtemplate = 'HomeVideo_'+g_ATVSettings.getSetting(options['PlexConnectUDID'], 'homevideoview').replace(' ','')+'.xml' elif PMSroot.get('viewGroup','')=='movie' and PMSroot.get('thumb','').find('movie') != -1: if PMSroot.get('title2')=='By Folder': # By Folder View XMLtemplate = 'MovieByFolder.xml' else: # Movie listing XMLtemplate = 'Movie_'+g_ATVSettings.getSetting(options['PlexConnectUDID'], 'homevideoview').replace(' ','')+'.xml' elif PMSroot.get('viewGroup','')=='track': XMLtemplate = 'Music_Track.xml' elif PMSroot.get('viewGroup','')=='episode': if PMSroot.get('title2')=='On Deck' or \ PMSroot.get('title2')=='Recently Viewed Episodes' or \ PMSroot.get('title2')=='Recently Aired' or \ PMSroot.get('title2')=='Recently Added': # TV On Deck View XMLtemplate = 'TV_OnDeck.xml' else: # TV Episode view XMLtemplate = 'Episode.xml' elif PMSroot.get('viewGroup','')=='photo': # Photo listing XMLtemplate = 'Photo.xml' else: XMLtemplate = 'Directory.xml' dprint(__name__, 1, "XMLTemplate: "+XMLtemplate) # get XMLtemplate aTVTree = etree.parse(sys.path[0]+'/assets/templates/'+XMLtemplate) aTVroot = aTVTree.getroot() # convert PMS XML to aTV XML using provided XMLtemplate global g_CommandCollection g_CommandCollection = CCommandCollection(options, PMSroot, PMS_baseURL, path) XML_ExpandTree(aTVroot, PMSroot, 'main') XML_ExpandAllAttrib(aTVroot, PMSroot, 'main') del g_CommandCollection dprint(__name__, 1, "====== generated aTV-XML ======") dprint(__name__, 1, prettyXML(aTVTree)) dprint(__name__, 1, "====== aTV-XML finished ======") return etree.tostring(aTVroot)
def ATTRIB_PMSCOUNT(self, src, srcXML, param): UDID = self.options['PlexConnectUDID'] return str(PlexAPI.getPMSCount(UDID))
def ATTRIB_MEDIAURL(self, src, srcXML, param): Video, leftover = self.getElement(src, srcXML, param) UDID = self.options['PlexConnectUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, self.PMS_baseURL) AuthToken = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'accesstoken') if not Video: # not a complete video structure - take key directly and build direct-play path key, leftover, dfltd = self.getKey(src, srcXML, param) res = PlexAPI.getDirectVideoPath(key, AuthToken) res = PlexAPI.getURL(self.PMS_baseURL, self.path[srcXML], res) return res # complete video structure - request transcoding if needed Media = Video.find('Media') # check "Media" element and get key if Media!=None: # transcoder action transcoderAction = g_ATVSettings.getSetting(UDID, 'transcoderaction') # video format # HTTP live stream # or native aTV media videoATVNative = \ Media.get('protocol','-') in ("hls") \ or \ Media.get('container','-') in ("mov", "mp4") and \ Media.get('videoCodec','-') in ("mpeg4", "h264", "drmi") and \ Media.get('audioCodec','-') in ("aac", "ac3", "drms") dprint(__name__, 2, "video: ATVNative - {0}", videoATVNative) # quality limits: quality=(resolution, quality, bitrate) qLookup = { '480p 2.0Mbps' :('720x480', '60', '2000'), \ '720p 3.0Mbps' :('1280x720', '75', '3000'), \ '720p 4.0Mbps' :('1280x720', '100', '4000'), \ '1080p 8.0Mbps' :('1920x1080', '60', '8000'), \ '1080p 10.0Mbps' :('1920x1080', '75', '10000'), \ '1080p 12.0Mbps' :('1920x1080', '90', '12000'), \ '1080p 20.0Mbps' :('1920x1080', '100', '20000'), \ '1080p 40.0Mbps' :('1920x1080', '100', '40000') } if PlexAPI.getPMSProperty(UDID, PMS_uuid, 'local')=='1': qLimits = qLookup[g_ATVSettings.getSetting(UDID, 'transcodequality')] else: qLimits = qLookup[g_ATVSettings.getSetting(UDID, 'remotebitrate')] # subtitle renderer, subtitle selection subtitleRenderer = g_ATVSettings.getSetting(UDID, 'subtitlerenderer') subtitleId = '' subtitleKey = '' subtitleFormat = '' for Stream in Media.find('Part').findall('Stream'): # Todo: check 'Part' existance, deal with multi part video if Stream.get('streamType','') == '3' and\ Stream.get('selected','0') == '1': subtitleId = Stream.get('id','') subtitleKey = Stream.get('key','') subtitleFormat = Stream.get('format','') break subtitleIOSNative = \ subtitleKey=='' and subtitleFormat=="tx3g" # embedded subtitlePlexConnect = \ subtitleKey!='' and subtitleFormat=="srt" # external # subtitle suitable for direct play? # no subtitle # or 'Auto' with subtitle by iOS or PlexConnect # or 'iOS,PMS' with subtitle by iOS subtitleDirectPlay = \ subtitleId=='' \ or \ subtitleRenderer=='Auto' and \ ( (videoATVNative and subtitleIOSNative) or subtitlePlexConnect ) \ or \ subtitleRenderer=='iOS, PMS' and \ (videoATVNative and subtitleIOSNative) dprint(__name__, 2, "subtitle: IOSNative - {0}, PlexConnect - {1}, DirectPlay - {2}", subtitleIOSNative, subtitlePlexConnect, subtitleDirectPlay) # determine video URL if transcoderAction=='DirectPlay' \ or \ transcoderAction=='Auto' and \ videoATVNative and \ int(Media.get('bitrate','0')) < int(qLimits[2]) and \ subtitleDirectPlay: # direct play for... # force direct play # or videoATVNative (HTTP live stream m4v/h264/aac...) # limited by quality setting # with aTV supported subtitle (iOS embedded tx3g, PlexConnext external srt) res, leftover, dfltd = self.getKey(Media, srcXML, 'Part/key') if Media.get('indirect', False): # indirect... todo: select suitable resolution, today we just take first Media PMS = PlexAPI.getXMLFromPMS(self.PMS_baseURL, res, self.options, AuthToken) # todo... check key for trailing '/' or even 'http' res, leftover, dfltd = self.getKey(PMS.getroot(), srcXML, 'Video/Media/Part/key') res = PlexAPI.getDirectVideoPath(res, AuthToken) else: # request transcoding res = Video.get('key','') # misc settings: subtitlesize, audioboost subtitle = { 'selected': '1' if subtitleId else '0', \ 'dontBurnIn': '1' if subtitleDirectPlay else '0', \ 'size': g_ATVSettings.getSetting(UDID, 'subtitlesize') } audio = { 'boost': g_ATVSettings.getSetting(UDID, 'audioboost') } res = PlexAPI.getTranscodeVideoPath(res, AuthToken, self.options, transcoderAction, qLimits, subtitle, audio) else: dprint(__name__, 0, "MEDIAPATH - element not found: {0}", param) res = 'FILE_NOT_FOUND' # not found? if res.startswith('/'): # internal full path. res = self.PMS_baseURL + res elif res.startswith('http://') or res.startswith('https://'): # external address pass else: # internal path, add-on res = self.PMS_baseURL + self.path[srcXML] + res dprint(__name__, 1, 'MediaURL: {0}', res) return res
def XML_PMS2NMT(PMS_baseURL, path, options): # double check NMT UDID, redo from client IP if needed/possible if not "PlexNMTUDID" in options: UDID = getNMTFromIP(options["NMTAddress"]) if UDID: options["PlexNMTUDID"] = UDID else: declareNMT(options["PlexNMTUDID"], options["NMTAddress"]) # update with latest info # check cmd to work on cmd = "" if "PlexNMT" in options: cmd = options["PlexNMT"] dprint(__name__, 1, "PlexNMT Cmd: " + cmd) # check NMT language setting if not "NMTLanguage" in options: dprint(__name__, 1, "no NMTLanguage - pick en") options["NMTLanguage"] = "en" # XML Template selector # - PlexNMT command # - path # - PMS ViewGroup XMLtemplate = "" PMS = None PMSroot = None # XML direct request or # XMLtemplate defined by solely PlexNMT Cmd if path.endswith(".xml"): XMLtemplate = path.lstrip("/") path = "" # clear path - we don't need PMS-XML """ elif cmd=='Play': XMLtemplate = 'PlayVideo.xml' elif cmd=='PlayVideo_ChannelsV1': dprint(__name__, 1, "playing Channels XML Version 1: {0}".format(path)) UDID = options['PlexNMTUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, PMS_baseURL) auth_token = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'accesstoken') path = PlexAPI.getDirectVideoPath(path, auth_token) return XML_PlayVideo_ChannelsV1(PMS_baseURL, path) # direct link, no PMS XML available elif cmd=='PlayTrailer': trailerID = options['PlexConnectTrailerID'] info = urllib2.urlopen("http://youtube.com/get_video_info?video_id=" + trailerID).read() parsed = urlparse.parse_qs(info) key = 'url_encoded_fmt_stream_map' if not key in parsed: return XML_Error('PlexConnect', 'Youtube: No Trailer Info available') streams = parsed[key][0].split(',') url = '' for i in range(len(streams)): stream = urlparse.parse_qs(streams[i]) if stream['itag'][0] == '18': url = stream['url'][0] + '&signature=' + stream['sig'][0] if url == '': return XML_Error('PlexConnect','Youtube: ATV compatible Trailer not available') return XML_PlayVideo_ChannelsV1('', url.replace('&','&')) elif cmd=='PhotoBrowser': XMLtemplate = 'Photo_Browser.xml' elif cmd=='MoviePreview': XMLtemplate = 'MoviePreview.xml' elif cmd=='MoviePrePlay': XMLtemplate = 'MoviePrePlay.xml' elif cmd=='EpisodePrePlay': XMLtemplate = 'EpisodePrePlay.xml' elif cmd=='ChannelPrePlay': XMLtemplate = 'ChannelPrePlay.xml' elif cmd=='ChannelsVideo': XMLtemplate = 'ChannelsVideo.xml' elif cmd=='ByFolder': XMLtemplate = 'ByFolder.xml' elif cmd == 'MovieSection': XMLtemplate = 'MovieSection.xml' elif cmd == 'TVSection': XMLtemplate = 'TVSection.xml' elif cmd.find('SectionPreview') != -1: XMLtemplate = cmd + '.xml' elif cmd == 'AllMovies': XMLtemplate = 'Movie_'+g_NMTSettings.getSetting(options['PlexNMTUDID'], 'movieview').replace(' ','')+'.xml' elif cmd == 'MovieSecondary': XMLtemplate = 'MovieSecondary.xml' elif cmd == 'AllShows': XMLtemplate = 'Show_'+g_NMTSettings.getSetting(options['PlexNMTUDID'], 'showview')+'.xml' elif cmd == 'TVSecondary': XMLtemplate = 'TVSecondary.xml' elif cmd == 'PhotoSecondary': XMLtemplate = 'PhotoSecondary.xml' elif cmd == 'Directory': XMLtemplate = 'Directory.xml' elif cmd == 'DirectoryWithPreview': XMLtemplate = 'DirectoryWithPreview.xml' elif cmd == 'DirectoryWithPreviewActors': XMLtemplate = 'DirectoryWithPreviewActors.xml' elif cmd=='Settings': XMLtemplate = 'Settings.xml' path = '' # clear path - we don't need PMS-XML elif cmd=='SettingsVideoOSD': XMLtemplate = 'Settings_VideoOSD.xml' path = '' # clear path - we don't need PMS-XML elif cmd=='SettingsMovies': XMLtemplate = 'Settings_Movies.xml' path = '' # clear path - we don't need PMS-XML elif cmd=='SettingsTVShows': XMLtemplate = 'Settings_TVShows.xml' path = '' # clear path - we don't need PMS-XML elif cmd.startswith('SettingsToggle:'): opt = cmd[len('SettingsToggle:'):] # cut command: parts = opt.split('+') g_NMTSettings.toggleSetting(options['PlexNMTUDID'], parts[0].lower()) XMLtemplate = parts[1] + ".xml" dprint(__name__, 2, "ATVSettings->Toggle: {0} in template: {1}", parts[0], parts[1]) path = '' # clear path - we don't need PMS-XML elif cmd==('MyPlexLogin'): dprint(__name__, 2, "MyPlex->Logging In...") if not 'PlexConnectCredentials' in options: return XML_Error('PlexConnect', 'MyPlex Sign In called without Credentials.') parts = options['PlexConnectCredentials'].split(':',1) (username, auth_token) = PlexAPI.MyPlexSignIn(parts[0], parts[1], options) UDID = options['PlexNMTUDID'] g_NMTSettings.setSetting(UDID, 'myplex_user', username) g_NMTSettings.setSetting(UDID, 'myplex_auth', auth_token) XMLtemplate = 'Settings.xml' path = '' # clear path - we don't need PMS-XML elif cmd=='MyPlexLogout': dprint(__name__, 2, "MyPlex->Logging Out...") UDID = options['PlexNMTUDID'] auth_token = g_NMTSettings.getSetting(UDID, 'myplex_auth') PlexAPI.MyPlexSignOut(auth_token) g_NMTSettings.setSetting(UDID, 'myplex_user', '') g_NMTSettings.setSetting(UDID, 'myplex_auth', '') XMLtemplate = 'Settings.xml' path = '' # clear path - we don't need PMS-XML elif cmd.startswith('Discover'): UDID = options['PlexNMTUDID'] auth_token = g_NMTSettings.getSetting(UDID, 'myplex_auth') PlexAPI.discoverPMS(UDID, g_param['CSettings'], auth_token) return XML_Error('PlexConnect', 'Discover!') # not an error - but aTV won't care anyways. elif path.startswith('/search?'): XMLtemplate = 'Search_Results.xml' elif path=='/library/sections': # from PlexConnect.xml -> for //local, //myplex XMLtemplate = 'Library.xml' elif path=='/channels/all': XMLtemplate = 'Channel_'+g_NMTSettings.getSetting(options['PlexNMTUDID'], 'channelview')+'.xml' path = '' """ # check options for XSL and start-page PSR if "PlexNMTXSL" in options: XSL = options["PlexNMTXSL"] else: XSL = "library.xsl" if "PlexNMTstart" in options: nmtstart = etree.XSLT.strparam(options["PlexNMTstart"]) else: nmtstart = etree.XSLT.strparam("1") if "PlexNMTview" in options: nmtview = etree.XSLT.strparam(options["PlexNMTview"]) else: nmtview = etree.XSLT.strparam("library") # request PMS XML if not path == "" or path == "": # PSR if "PlexNMTUDID" in options: UDID = options["PlexNMTUDID"] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, PMS_baseURL) auth_token = PlexAPI.getPMSProperty(UDID, PMS_uuid, "accesstoken") else: auth_token = "" if PMS_baseURL.startswith("//"): # //local, //myplex UDID = options["PlexNMTUDID"] type = PMS_baseURL[2:] PMS = PlexAPI.getXMLFromMultiplePMS(UDID, path, type, options) else: PMS = PlexAPI.getXMLFromPMS(PMS_baseURL, path, options, authtoken=auth_token) if PMS == False: return XML_Error("PlexNMT", "No Response from Plex Media Server") PMSroot = PMS.getroot() dprint(__name__, 1, "viewGroup: " + PMSroot.get("ViewGroup", "None")) # PSR - have PMS as XML content - move on. """ # XMLtemplate defined by PMS XML content if path=='': pass # nothing to load elif not XMLtemplate=='': pass # template already selected elif PMSroot.get('viewGroup','')=="secondary" and (PMSroot.get('art','').find('movie') != -1 or PMSroot.get('thumb','').find('movie') != -1): XMLtemplate = 'MovieSectionTopLevel.xml' elif PMSroot.get('viewGroup','')=="secondary" and (PMSroot.get('art','').find('show') != -1 or PMSroot.get('thumb','').find('show') != -1): XMLtemplate = 'TVSectionTopLevel.xml' elif PMSroot.get('viewGroup','')=="secondary" and (PMSroot.get('art','').find('photo') != -1 or PMSroot.get('thumb','').find('photo') != -1): XMLtemplate = 'PhotoSectionTopLevel.xml' elif PMSroot.get('viewGroup','')=="secondary": XMLtemplate = 'Directory.xml' elif PMSroot.get('viewGroup','')=='show': if PMSroot.get('title2')=='By Folder': # By Folder View XMLtemplate = 'ByFolder.xml' else: # TV Show grid view XMLtemplate = 'Show_'+g_NMTSettings.getSetting(options['PlexNMTUDID'], 'showview')+'.xml' elif PMSroot.get('viewGroup','')=='season': # TV Season view XMLtemplate = 'Season_'+g_NMTSettings.getSetting(options['PlexNMTUDID'], 'seasonview')+'.xml' elif PMSroot.get('viewGroup','')=='movie': if PMSroot.get('title2')=='By Folder': # By Folder View XMLtemplate = 'ByFolder.xml' else: # Movie listing XMLtemplate = 'Movie_'+g_NMTSettings.getSetting(options['PlexNMTUDID'], 'movieview').replace(' ','')+'.xml' elif PMSroot.get('viewGroup','')=='track': XMLtemplate = 'Music_Track.xml' elif PMSroot.get('viewGroup','')=='episode': if PMSroot.get('title2')=='On Deck' or \ PMSroot.get('title2')=='Recently Viewed Episodes' or \ PMSroot.get('title2')=='Recently Aired' or \ PMSroot.get('title2')=='Recently Added': # TV On Deck View XMLtemplate = 'TV_OnDeck.xml' else: # TV Episode view XMLtemplate = 'Episode.xml' elif PMSroot.get('viewGroup','')=='photo': # Photo listing XMLtemplate = 'Photo.xml' else: XMLtemplate = 'Directory.xml' dprint(__name__, 1, "XMLTemplate: "+XMLtemplate) """ # PSR # get XSL Transform dprint(__name__, 1, "XSL=" + XSL) try: XSLtree = etree.parse(sys.path[0] + "/assets/" + XSL) except Exception, e: dprint(__name__, 0, "Error parsing XSLT tree ", XSL, e) return
def ATTRIB_PMSCOUNT(self, src, srcXML, param): UDID = self.options["PlexNMTUDID"] return str(PlexAPI.getPMSCount(UDID))
def XML_PMS2aTV(PMSaddress, path, options): # double check aTV UDID, redo from client IP if needed/possible if not 'PlexConnectUDID' in options: UDID = getATVFromIP(options['aTVAddress']) if UDID: options['PlexConnectUDID'] = UDID else: declareATV(options['PlexConnectUDID'], options['aTVAddress']) # update with latest info # double check PMS IP address # the hope is: aTV sends either PMS address coded into URL or UDID in options if PMSaddress == '': if 'PlexConnectUDID' in options: UDID = options['PlexConnectUDID'] PMS_uuid = g_ATVSettings.getSetting(options['PlexConnectUDID'], 'pms_uuid') PMSaddress = PlexAPI.getPMSAddress(UDID, PMS_uuid) # this doesn't work any more, does it? is it really still used/needed? # check cmd to work on cmd = '' if 'PlexConnect' in options: cmd = options['PlexConnect'] dprint(__name__, 1, "PlexConnect Cmd: " + cmd) # check aTV language setting if not 'aTVLanguage' in options: dprint(__name__, 1, "no aTVLanguage - pick en") options['aTVLanguage'] = 'en' # discover! PlexGDM and MyPlex lookup - application just started on aTV UDID if path == '/PlexConnect.xml': UDID = options['PlexConnectUDID'] auth_token = g_ATVSettings.getSetting(UDID, 'myplex_auth') PlexAPI.discoverPMS(UDID, g_param['CSettings'], auth_token) # XML Template selector # - PlexConnect command # - path # - PMS ViewGroup XMLtemplate = '' PMS = None PMSroot = None # XML direct request or # XMLtemplate defined by solely PlexConnect Cmd if path.endswith(".xml"): XMLtemplate = path.lstrip('/') path = '' # clear path - we don't need PMS-XML elif cmd == 'Play': XMLtemplate = 'PlayVideo.xml' elif cmd == 'PlayVideo_ChannelsV1': dprint(__name__, 1, "playing Channels XML Version 1: {0}".format(path)) UDID = options['PlexConnectUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, PMSaddress) auth_token = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'accesstoken') path = PlexAPI.getDirectVideoPath(path, auth_token) return XML_PlayVideo_ChannelsV1( PMSaddress, path) # direct link, no PMS XML available elif cmd == 'PhotoBrowser': XMLtemplate = 'Photo_Browser.xml' elif cmd == 'MoviePreview': XMLtemplate = 'MoviePreview.xml' elif cmd == 'MoviePrePlay': XMLtemplate = 'MoviePrePlay.xml' elif cmd == 'EpisodePrePlay': XMLtemplate = 'EpisodePrePlay.xml' elif cmd == 'ChannelPrePlay': XMLtemplate = 'ChannelPrePlay.xml' elif cmd == 'ChannelsVideo': XMLtemplate = 'ChannelsVideo.xml' elif cmd == 'ByFolder': XMLtemplate = 'ByFolder.xml' elif cmd == 'MovieSection': XMLtemplate = 'MovieSection.xml' elif cmd == 'TVSection': XMLtemplate = 'TVSection.xml' elif cmd.find('SectionPreview') != -1: XMLtemplate = cmd + '.xml' elif cmd == 'AllMovies': XMLtemplate = 'Movie_' + g_ATVSettings.getSetting( options['PlexConnectUDID'], 'movieview') + '.xml' elif cmd == 'MovieSecondary': XMLtemplate = 'MovieSecondary.xml' elif cmd == 'AllShows': XMLtemplate = 'Show_' + g_ATVSettings.getSetting( options['PlexConnectUDID'], 'showview') + '.xml' elif cmd == 'TVSecondary': XMLtemplate = 'TVSecondary.xml' elif cmd == 'PhotoSecondary': XMLtemplate = 'PhotoSecondary.xml' elif cmd == 'Directory': XMLtemplate = 'Directory.xml' elif cmd == 'DirectoryWithPreview': XMLtemplate = 'DirectoryWithPreview.xml' elif cmd == 'DirectoryWithPreviewActors': XMLtemplate = 'DirectoryWithPreviewActors.xml' elif cmd == 'Settings': XMLtemplate = 'Settings.xml' path = '' # clear path - we don't need PMS-XML elif cmd == 'SettingsVideoOSD': XMLtemplate = 'Settings_VideoOSD.xml' path = '' # clear path - we don't need PMS-XML elif cmd == 'SettingsMovies': XMLtemplate = 'Settings_Movies.xml' path = '' # clear path - we don't need PMS-XML elif cmd == 'SettingsTVShows': XMLtemplate = 'Settings_TVShows.xml' path = '' # clear path - we don't need PMS-XML elif cmd.startswith('SettingsToggle:'): opt = cmd[len('SettingsToggle:'):] # cut command: parts = opt.split('+') g_ATVSettings.toggleSetting(options['PlexConnectUDID'], parts[0].lower()) XMLtemplate = parts[1] + ".xml" dprint(__name__, 2, "ATVSettings->Toggle: {0} in template: {1}", parts[0], parts[1]) path = '' # clear path - we don't need PMS-XML elif cmd == ('MyPlexLogin'): dprint(__name__, 2, "MyPlex->Logging In...") if not 'PlexConnectCredentials' in options: return XML_Error('PlexConnect', 'MyPlex Sign In called without Credentials.') parts = options['PlexConnectCredentials'].split(':', 1) (username, auth_token) = PlexAPI.MyPlexSignIn(parts[0], parts[1], options) UDID = options['PlexConnectUDID'] g_ATVSettings.setSetting(UDID, 'myplex_user', username) g_ATVSettings.setSetting(UDID, 'myplex_auth', auth_token) XMLtemplate = 'Settings.xml' path = '' # clear path - we don't need PMS-XML elif cmd == 'MyPlexLogout': dprint(__name__, 2, "MyPlex->Logging Out...") UDID = options['PlexConnectUDID'] auth_token = g_ATVSettings.getSetting(UDID, 'myplex_auth') PlexAPI.MyPlexSignOut(auth_token) g_ATVSettings.setSetting(UDID, 'myplex_user', '') g_ATVSettings.setSetting(UDID, 'myplex_auth', '') XMLtemplate = 'Settings.xml' path = '' # clear path - we don't need PMS-XML elif cmd.startswith('Discover'): UDID = options['PlexConnectUDID'] auth_token = g_ATVSettings.getSetting(UDID, 'myplex_auth') PlexAPI.discoverPMS(UDID, g_param['CSettings'], auth_token) XMLtemplate = 'Settings.xml' path = '' # clear path - we don't need PMS-XML elif path.startswith('/search?'): XMLtemplate = 'Search_Results.xml' elif path == '/library/sections': XMLtemplate = 'Library.xml' path = '' elif path == '/channels/all': XMLtemplate = 'Channels.xml' path = '' # request PMS XML if not path == '': if 'PlexConnectUDID' in options: UDID = options['PlexConnectUDID'] PMS_uuid = PlexAPI.getPMSFromAddress(UDID, PMSaddress) auth_token = PlexAPI.getPMSProperty(UDID, PMS_uuid, 'accesstoken') else: auth_token = '' PMS = PlexAPI.getXMLFromPMS('http://' + PMSaddress, path, options, authtoken=auth_token) if PMS == False: return XML_Error('PlexConnect', 'No Response from Plex Media Server') PMSroot = PMS.getroot() dprint(__name__, 1, "viewGroup: " + PMSroot.get('ViewGroup', 'None')) # XMLtemplate defined by PMS XML content if path == '': pass # nothing to load elif not XMLtemplate == '': pass # template already selected elif PMSroot.get('viewGroup', '') == "secondary" and ( PMSroot.get('art', '').find('movie') != -1 or PMSroot.get('thumb', '').find('movie') != -1): XMLtemplate = 'MovieSectionTopLevel.xml' elif PMSroot.get('viewGroup', '') == "secondary" and ( PMSroot.get('art', '').find('show') != -1 or PMSroot.get('thumb', '').find('show') != -1): XMLtemplate = 'TVSectionTopLevel.xml' elif PMSroot.get('viewGroup', '') == "secondary" and ( PMSroot.get('art', '').find('photo') != -1 or PMSroot.get('thumb', '').find('photo') != -1): XMLtemplate = 'PhotoSectionTopLevel.xml' elif PMSroot.get('viewGroup', '') == "secondary": XMLtemplate = 'Directory.xml' elif PMSroot.get('viewGroup', '') == 'show': if PMSroot.get('title2') == 'By Folder': # By Folder View XMLtemplate = 'ByFolder.xml' else: # TV Show grid view XMLtemplate = 'Show_' + g_ATVSettings.getSetting( options['PlexConnectUDID'], 'showview') + '.xml' elif PMSroot.get('viewGroup', '') == 'season': # TV Season view XMLtemplate = 'Season_' + g_ATVSettings.getSetting( options['PlexConnectUDID'], 'seasonview') + '.xml' elif PMSroot.get('viewGroup', '') == 'movie': if PMSroot.get('title2') == 'By Folder': # By Folder View XMLtemplate = 'ByFolder.xml' else: # Movie listing XMLtemplate = 'Movie_' + g_ATVSettings.getSetting( options['PlexConnectUDID'], 'movieview') + '.xml' elif PMSroot.get('viewGroup', '') == 'track': XMLtemplate = 'Music_Track.xml' elif PMSroot.get('viewGroup', '') == 'episode': if PMSroot.get('title2')=='On Deck' or \ PMSroot.get('title2')=='Recently Viewed Episodes' or \ PMSroot.get('title2')=='Recently Aired' or \ PMSroot.get('title2')=='Recently Added': # TV On Deck View XMLtemplate = 'TV_OnDeck.xml' else: # TV Episode view XMLtemplate = 'Episode.xml' elif PMSroot.get('viewGroup', '') == 'photo': # Photo listing XMLtemplate = 'Photo.xml' else: XMLtemplate = 'Directory.xml' dprint(__name__, 1, "XMLTemplate: " + XMLtemplate) # get XMLtemplate aTVTree = etree.parse(sys.path[0] + '/assets/templates/' + XMLtemplate) aTVroot = aTVTree.getroot() # convert PMS XML to aTV XML using provided XMLtemplate global g_CommandCollection g_CommandCollection = CCommandCollection(options, PMSroot, PMSaddress, path) XML_ExpandTree(aTVroot, PMSroot, 'main') XML_ExpandAllAttrib(aTVroot, PMSroot, 'main') del g_CommandCollection dprint(__name__, 1, "====== generated aTV-XML ======") dprint(__name__, 1, prettyXML(aTVTree)) dprint(__name__, 1, "====== aTV-XML finished ======") return etree.tostring(aTVroot)