def getFilesFromLib(libs, sType): itemList = {} # Add from one library at a time for lib in libs: start = 0 # Start point of items baseUrl = misc.GetLoopBack( ) + '/library/sections/' + lib + '/all?type=' + str(MEDIATYPES[ ROOTNODES[sType]]) + '&' + EXCLUDE + '&X-Plex-Container-Start=' url = baseUrl + '0' + '&X-Plex-Container-Size=0' libInfo = XML.ElementFromURL(url) # Now get the amount of items we need to add totalSize = libInfo.get('totalSize') # Now get the UUID of the library librarySectionUUID = libInfo.get('librarySectionUUID') try: while int(start) < int(totalSize): url = baseUrl + str(start) + '&X-Plex-Container-Size=' + str( MEDIASTEPS) medias = XML.ElementFromURL(url) for media in medias: parts = media.xpath('//Media/Part') for part in parts: mediaInfo = {} item = {} mediaInfo = { 'fullFileName': part.get('file'), 'librarySectionUUID': librarySectionUUID } key = media.get('ratingKey') item[key] = [mediaInfo] itemList[os.path.basename(part.get('file'))] = item start += MEDIASTEPS except Exception, e: Log.Exception('exception in getFilesFromLib was: %s' % str(e))
def RESET(self, req, *args): """Reset WT to factory settings""" try: Log.Info('Factory Reset called') cachePath = Core.storage.join_path(Core.app_support_path, 'Plug-in Support', 'Caches', 'com.plexapp.plugins.' + NAME) dataPath = Core.storage.join_path(Core.app_support_path, 'Plug-in Support', 'Data', 'com.plexapp.plugins.' + NAME) shutil.rmtree(cachePath) shutil.rmtree(dataPath) try: Dict.Reset() except: Log.Critical('Fatal error in clearing dict during reset') # Restart system bundle HTTP.Request(misc.GetLoopBack() + '/:/plugins/com.plexapp.plugins.' + NAME + '/restart', cacheTime=0, immediate=True) req.clear() req.set_status(200) req.finish('WebTools has been reset') except Exception, e: Log.Exception('Fatal error happened in wt.reset: ' + str(e)) req.clear() req.set_status(e.code) req.finish('Fatal error happened in wt.reset: %s' % (str(e)))
def SearchMedia(self, req, watched, section, sectionType): Log.Info('Starting to search') returnJson = {} try: if sectionType == 'movie': MediaType = str(PLEX_MEDIATYPE['METADATA_MOVIE']) elif sectionType == 'Ged': pass url = misc.GetLoopBack() + '/library/sections/' + section url += '/all?type=' + MediaType url += '&X-Plex-Container-Start=0&X-Plex-Container-Size=1&' url += EXCLUDEELEMENTS + '&' + EXCLUDEFIELDS + '&title=' for title, key in watched.items(): SearchUrl = url + String.Quote(title) key = XML.ElementFromURL(SearchUrl).xpath( '//Video/@ratingKey')[0] returnJson[title] = key return returnJson except Exception, e: Log.Exception( 'Fatal exception happened in ViewState Search was %s' % str(e)) req.clear() req.set_status(500) req.finish( 'Exception happened in ViewState Search was: %s' % (str(e)))
def checkItemIsValid(key, title, sType): url = misc.GetLoopBack() + '/library/metadata/' + str(key) + '?' + EXCLUDE mediaTitle = None try: mediaTitle = XML.ElementFromURL(url).xpath( '//' + ROOTNODES[sType])[0].get('title') except: pass return (title == mediaTitle)
def getPrimaryAgent(self, section): # Get the primary agent for the library url = ''.join(( misc.GetLoopBack(), '/library/sections')) try: Scanner = XML.ElementFromURL(url).xpath( '//Directory[@key="' + section + '"]/@agent')[0] return Scanner except Exception, e: Log.Exception('Exception in PlayList orderList was %s' % (str(e)))
def doImport(jsonItems, playlistType, playlistTitle): # jsonItems = {} playlistSmart = (jsonItems.get('smart') == 1) # Make url for creation of playlist targetFirstUrl = misc.GetLoopBack() + '/playlists?type=' + playlistType + \ '&title=' + String.Quote(playlistTitle) + \ '&smart=0&uri=library://' counter = 0 for lib in jsonItems: if counter < 1: targetFirstUrl += lib + '/directory//library/metadata/' medias = ','.join( map(str, (item['id'] for item in jsonItems[lib]))) targetFirstUrl += String.Quote(medias) # First url for the post created, so send it, and grab the response try: response = HTTP.Request(targetFirstUrl, cacheTime=0, immediate=True, method="POST") ratingKey = XML.ElementFromString(response).xpath( 'Playlist/@ratingKey')[0] except Exception, e: Log.Exception( 'Exception creating first part of playlist was: %s' % (str(e))) counter += 1 else: # Remaining as put medias = ','.join( map(str, (item['id'] for item in jsonItems[lib]))) targetSecondUrl = misc.GetLoopBack() + '/playlists/' + ratingKey + '/items?uri=library://' + \ lib + '/directory//library/metadata/' + \ String.Quote(medias) HTTP.Request(targetSecondUrl, cacheTime=0, immediate=True, method="PUT")
def setWatched(self, req, watched, user, users): url = misc.GetLoopBack( ) + '/:/scrobble?identifier=com.plexapp.plugins.library&key=' for key, value in watched.items(): target = url + str(value) if not user: httpResponse = HTTP.Request(target, immediate=True, timeout=5) else: print 'Ged do alternative http get' # TODO Change to native framework call, when Plex allows token in header opener = urllib2.build_opener(urllib2.HTTPHandler) request = urllib2.Request(target) request.add_header('X-Plex-Token', users[user]['accessToken']) response = opener.open(request).read()
def orderPlaylist(playlistId, orgPlaylist, sType): try: rootNode = ROOTNODES[sType] # Now get the import list as it is now url = misc.GetLoopBack( ) + '/playlists/' + playlistId + '/items' + '?' + EXCLUDE playListXML = XML.ElementFromURL(url) newList = {} # Grap the original one, and sort by ListId for lib in orgPlaylist: for item in orgPlaylist[lib]: newList[item['ListId']] = item['title'] # Need a counter here, since HTTP url differs from first to last ones counter = 0 for item in sorted(newList): # get playListItemId of item xPathStr = "//" + rootNode + \ "[@title='" + newList[item] + "']/@playlistItemID" itemToMove = str(playListXML.xpath(unicode(xPathStr))[0]) if counter == 0: url = misc.GetLoopBack() + '/playlists/' + playlistId + \ '/items/' + itemToMove + '/move' counter += 1 after = itemToMove else: url = misc.GetLoopBack() + '/playlists/' + playlistId + \ '/items/' + itemToMove + \ '/move?after=' + after after = itemToMove # Now move the darn thing HTTP.Request(url, cacheTime=0, immediate=True, method="PUT") except Exception, e: Log.Exception('Exception in PlayList orderList was %s' % (str(e)))
def getLibsOfType(sType): libsToSearch = [] if sType == 'audio': sType = 'artist' # Getting a list of all libraries try: url = misc.GetLoopBack() + '/library/sections/all' xPathStr = 'Directory[@type="' + sType + '"]' libs = XML.ElementFromURL(url).xpath(xPathStr) for lib in libs: libsToSearch.append(lib.get('key')) Log.Info('Need to serch the following libraries: %s' % str(libsToSearch)) return libsToSearch except Exception, e: Log.Exception('Exception in playList getLibsOfType was %s' % str(e))
def deletePlayLIstforUsr(req, key, token): url = misc.GetLoopBack() + '/playlists/' + key try: # TODO Change to native framework call, when Plex allows token in header opener = urllib2.build_opener(urllib2.HTTPHandler) request = urllib2.Request(url) request.add_header('X-Plex-Token', token) request.get_method = lambda: 'DELETE' url = opener.open(request) except Ex.HTTPError, e: Log.Exception( 'HTTP exception when deleting a playlist for the owner was: %s' % (e)) req.clear() req.set_status(e.code) req.finish(str(e))
def DELETE(self, req, *args): try: user = None if args != None: # We got additional arguments if len(args) > 0: # Get them in lower case arguments = [item.lower() for item in list(args)[0]] if 'user' in arguments: # Get key of the user user = arguments[arguments.index('user') + 1] # So now user is either none (Owner) or a keyId of a user # Now lets get the key of the playlist if 'key' in arguments: # Get key of the user key = arguments[arguments.index('key') + 1] url = misc.GetLoopBack() + '/playlists/' + key else: Log.Error('Missing key of playlist') req.clear() req.set_status(412) req.finish('Missing key of playlist') if user == None: try: # Delete playlist from the owner Log.Info('Deleting playlist with ID: %s' % key) HTTP.Request(url, cacheTime=0, immediate=True, method="DELETE") except Ex.HTTPError, e: Log.Exception( 'HTTP exception when deleting a playlist for the owner was: %s' % (e)) req.clear() req.set_status(e.code) req.finish(str(e)) except Exception, e: Log.Exception( 'Exception happened when deleting a playlist for the owner was: %s' % (str(e))) req.clear() req.set_status(500) req.finish( 'Exception happened when deleting a playlist for the owner was: %s' % (str(e)))
def __init__(self): global retMsg global MediaChuncks global CoreUrl try: # Only init once during the lifetime of this if not findMedia.init_already: findMedia.init_already = True retMsg = ['WebTools'] self.populatePrefs() Log.Debug('******* Starting findMedia *******') Log.Debug('********* Prefs are ***********') Log.Debug(Dict['findMedia']) self.MediaChuncks = 40 self.CoreUrl = misc.GetLoopBack() + '/library/sections/' except exception, e: Log.Critical('Exception in FM Init was %s' % (e))
def phraseOurs(lines): # Placeholder for items to import items = {} Log.Debug('Import file was ours') ourLine = lines[2][1:].replace('None', '"None"') jsonLine = JSON.ObjectFromString(ourLine) sName = jsonLine['title'] Log.Debug('Playlist name internally is %s' % sName) sType = jsonLine['playlistType'] Log.Debug('Playlist type is %s' % sType) sSrvId = jsonLine['ServerID'] smart = jsonLine['smart'] Log.Debug('Playlist smart is %s' % smart) Log.Debug('ServerId this playlist belongs to is %s' % sSrvId) thisServerID = XML.ElementFromURL( misc.GetLoopBack() + '/identity').get('machineIdentifier') Log.Debug('Current Server id is %s' % thisServerID) bSameSrv = (thisServerID == sSrvId) lineNo = 5 try: for line in lines[5:len(lines):3]: if not line: break myLine = str(line[1:]) myLine = myLine.replace("None", str(-1)) media = JSON.ObjectFromString(myLine) id = media['Id'] item = {} item['ListId'] = media['ListId'] item['LibraryUUID'] = media['LibraryUUID'] lineNo += 1 media = lines[lineNo][8:].split(',', 1) item['title'] = media[1].split(' - ', 1)[1] lineNo += 1 item['fileName'] = lines[lineNo] items[id] = item lineNo += 1 return items except IndexError: pass except Exception, e: Log.Exception('Exception happened in phraseOurs was %s' % (str(e))) pass
def searchForItemKey(title, sType): try: result = [] # TODO: Fix for other types # Are we talking about a video here? url = misc.GetLoopBack() + '/search?type=10&query=' + \ String.Quote(title) + '&' + EXCLUDE found = XML.ElementFromURL(url) ratingKey = found.xpath('//' + ROOTNODES[sType] + '/@ratingKey')[0] result.append(ratingKey) librarySectionUUID = found.xpath('//' + ROOTNODES[sType] + '/@librarySectionUUID')[0] result.append(librarySectionUUID) Log.Info('Item named %s was located as item with key %s' % (title, ratingKey)) return result except Exception, e: pass
def GETSECTIONSLIST(self, req, *args): Log.Debug('getSectionsList requested') try: rawSections = XML.ElementFromURL( misc.GetLoopBack() + '/library/sections') Sections = [] for directory in rawSections: if directory.get('type') in SUPPORTEDSECTIONS: Section = { 'key': directory.get('key'), 'title': directory.get('title'), 'type': directory.get('type')} Sections.append(Section) req.clear() req.set_status(200) req.set_header('Content-Type', 'application/json; charset=utf-8') req.finish(json.dumps(Sections)) except Exception, e: Log.Exception( 'Fatal error happened in getSectionsList: %s' % (str(e))) req.clear() req.set_status(500) req.finish('Fatal error happened in getSectionsList')
def scanItems(self, req, sectionNumber, Agent, Force=False): print 'Ged Force', Force """Scan db. Must run as a thread""" try: # Let's find out the info of section here url = misc.GetLoopBack() + '/library/sections/' response = XML.ElementFromURL(url).xpath( '//Directory[@key=' + sectionNumber + ']') sectionTitle = response[0].get('title') sectionType = response[0].get('type') strMsg = ''.join(( 'Going to scan section', sectionNumber, ' with a title of ', sectionTitle, ' and a type of ', sectionType)) Log.Debug(strMsg) if runningState in [0, 99]: Thread.Create( scanMedias, globalize=True, sectionNumber=sectionNumber, sectionType=sectionType, agent=Agent, Force=Force, req=req) else: req.clear() req.set_status(409) req.finish('Scanning already in progress') except Exception, ex: Log.Exception('Fatal error happened in scanItems: ' + str(ex)) req.clear() req.set_status(500) req.finish('Fatal error happened in scanItems: ' + str(ex)) return req
def DOWNLOAD(self, req, *args): try: user = None if args != None: # We got additional arguments if len(args) > 0: # Get them in lower case arguments = [item.lower() for item in list(args)[0]] if 'user' in arguments: # Get key of the user user = arguments[arguments.index('user') + 1] # So now user is either none (Owner) or a keyId of a user # Now lets get the key of the playlist if 'key' in arguments: # Get key of the user key = arguments[arguments.index('key') + 1] url = misc.GetLoopBack( ) + '/playlists/' + key + '/items' + '?' + EXCLUDE else: Log.Error('Missing key of playlist') req.clear() req.set_status(412) req.finish('Missing key of playlist') try: Log.Info('downloading playlist with ID: %s' % key) try: title, playList = getPlayListItems(user, key) # Replace invalid caracters for a filename with underscore fileName = re.sub('[\/[:#*?"<>|]', '_', title).strip() + '.m3u8' req.set_header( 'Content-Disposition', 'attachment; filename="' + fileName + '"') req.set_header('Cache-Control', 'no-cache') req.set_header('Pragma', 'no-cache') req.set_header('Content-Type', 'application/text/plain') # start writing for line in playList: #print line req.write(unicode(line)) req.set_status(200) req.finish() except Exception, e: Log.Exception( 'Exception when downloading a playlist as the owner was %s' % str(e)) Log.Debug('Trying to get more info here') req.clear() req.set_status(500) req.finish(str(e)) except Ex.HTTPError, e: Log.Exception( 'HTTP exception when downloading a playlist for the owner was: %s' % (e)) req.clear() req.set_status(500) req.finish(str(e)) except Exception, e: Log.Exception( 'Exception happened when downloading a playlist for the owner was: %s' % (str(e))) req.clear() req.set_status(500) req.finish( 'Exception happened when downloading a playlist for the owner was: %s' % (str(e)))
def scanMovieDb(sectionNumber=0, agent=None): """Get a list of all files in a Movie Library from the database""" global AmountOfMediasInDatabase global statusMsg global runningState try: Log.Debug( 'Starting scanMovieDb for section %s' % (sectionNumber)) runningState = -1 strStatus = ( 'Starting to scan database for section %s' % sectionNumber) statusMsg = ( wtV3().GETTRANSLATE( None, Internal=True, String=strStatus)) # Start by getting the totals of this section totalSize = XML.ElementFromURL( misc.GetLoopBack() + '/library/sections/' + sectionNumber + '/all?X-Plex-Container-Start=1&X-Plex-Container-Size=0')\ .get('totalSize') AmountOfMediasInDatabase = totalSize print 'Ged51 episodes', str(totalSize) Log.Debug('Total size of medias are %s' % (totalSize)) iStart = 0 iCount = 0 strMsg = 'Scanning database: item %s of %s : \ Working' % (iCount, totalSize) statusMsg = wtV3().GETTRANSLATE( None, Internal=True, String=strMsg) # So let's walk the library while True: # Grap a chunk of videos from the server medias = XML.ElementFromURL( misc.GetLoopBack() + '/library/sections/' + sectionNumber + '/all?X-Plex-Container-Start=' + str(iStart) + '&X-Plex-Container-Size=' + str(MediaChuncks) + '&excludeElements=' + EXCLUDEELEMENTS + '&excludeFields=' + EXCLUDEFIELDS).xpath('//Video') for video in medias: iCount += 1 videoUrl = ''.join(( misc.GetLoopBack(), video.get('key'), '?excludeElements=' + EXCLUDEELEMENTS, '&excludeFields=' + EXCLUDEFIELDS )) guid = XML.ElementFromURL( videoUrl).xpath('//Video')[0].get('guid') if agent not in guid: Log.Info('Need to update media: %s' % video.get('title')) updateMediaAgent( video.get('ratingKey'), agent, video.get('year'), video.get('title')) # Did user abort? if bAbort: runningState = 0 raise ValueError('Aborted') break strMsg = 'Scanning database: item %s of %s : \ Working' % (iCount, totalSize) statusMsg = wtV3().GETTRANSLATE( None, Internal=True, String=strMsg) iStart += MediaChuncks if len(medias) == 0: statusMsg = 'Scanning database: %s : Done' % ( totalSize) Log.Info('***** Done scanning the database *****') runningState = 1 break return except Exception, e: Log.Exception( 'Exception Fatal error in scanMovieDb: ' + str(e)) runningState = 99
def init(self): self.getListsURL = misc.GetLoopBack() + '/playlists/all'
def COPY(self, req, *args): users = None # Start by getting the key of the PlayList if args != None: # We got additional arguments if len(args) > 0: # Get them in lower case arguments = [item.lower() for item in list(args)[0]] else: Log.Critical('Missing Arguments') req.clear() req.set_status(412) req.finish('Missing Arguments') # Get playlist Key if 'key' in arguments: # Get key of the user key = arguments[arguments.index('key') + 1] else: Log.Error('Missing key of playlist') req.clear() req.set_status(412) req.finish('Missing key of playlist') # Get UserFrom if 'userfrom' in arguments: # Get the userfrom userfrom = arguments[arguments.index('userfrom') + 1] else: # Copy from the Owner userfrom = None # Get UserTo if 'userto' in arguments: # Get the userto userto = arguments[arguments.index('userto') + 1] else: Log.Error('Missing target user of playlist') req.clear() req.set_status(412) req.finish('Missing targetuser of playlist') # Get user list, among with access token users = plexTV().getUserList() # Get the playlist that needs to be copied url = misc.GetLoopBack() + '/playlists/' + key + '/items' if userfrom == None: # Get it from the owner playlist = XML.ElementFromURL(url) else: # We need to logon as specified user try: # Get user playlist # TODO Change to native framework call, when Plex allows token in header opener = urllib2.build_opener(urllib2.HTTPHandler) request = urllib2.Request(url) request.add_header('X-Plex-Token', users[userfrom]['accessToken']) response = opener.open(request).read() playlist = XML.ElementFromString(response) except Ex.HTTPError, e: Log.Exception( 'HTTP exception when downloading a playlist for the owner was: %s' % (e)) req.clear() req.set_status(e.code) req.finish(str(e)) except Exception, e: Log.Exception( 'Exception happened when downloading a playlist for the user was: %s' % (str(e))) req.clear() req.set_status(500) req.finish( 'Exception happened when downloading a playlist for the user was: %s' % (str(e)))
return # So now user is either none or a keyId if not user: result['user'] = None result['username'] = '******' else: # Darn....Hard work ahead..We have to # logon as another user here :-( result['user'] = user # Get user list, among with their access tokens users = plexTV().getUserList() result['username'] = users[user]['username'] count = 0 # Add some export core info here result['section'] = section sectionTypeUrl = misc.GetLoopBack() + '/library/sections/' + str(section) + \ '/all?X-Plex-Container-Start=0&X-Plex-Container-Size=0' result['sectionType'] = XML.ElementFromURL( sectionTypeUrl).get('viewGroup') result['sectionTitle'] = XML.ElementFromURL( sectionTypeUrl).get('librarySectionTitle') result['serverId'] = XML.ElementFromURL( misc.GetLoopBack() + '/identity').get('machineIdentifier') # Get the type of items to get, based on section type if result['sectionType'] == 'show': Type = PLEX_MEDIATYPE['METADATA_EPISODE'] elif result['sectionType'] == 'movie': Type = PLEX_MEDIATYPE['METADATA_MOVIE'] elif result['sectionType'] == 'artist': Type = PLEX_MEDIATYPE['METADATA_TRACK'] # Url to grap
Log.Exception( 'Exception happened when downloading a playlist for the user was: %s' % (str(e))) req.clear() req.set_status(500) req.finish( 'Exception happened when downloading a playlist for the user was: %s' % (str(e))) # Now walk the playlist, and do a lookup for the items, in order to grab the librarySectionUUID jsonItems = {} playlistType = playlist.get('playlistType') playlistTitle = playlist.get('title') playlistSmart = (playlist.get('smart') == 1) for item in playlist: itemKey = item.get('ratingKey') xmlUrl = misc.GetLoopBack( ) + '/library/metadata/' + itemKey + '?' + EXCLUDE UUID = XML.ElementFromURL(misc.GetLoopBack() + '/library/metadata/' + itemKey).get('librarySectionUUID') if UUID in jsonItems: jsonItems[UUID].append(itemKey) else: jsonItems[UUID] = [] jsonItems[UUID].append(itemKey) Log.Debug('Got a playlist that looks like:') Log.Debug(json.dumps(jsonItems)) # So we got all the info needed now from the source user, now time for the target user try: # TODO Change to native framework call, when Plex allows token in header urltoPlayLists = misc.GetLoopBack() + '/playlists' opener = urllib2.build_opener(urllib2.HTTPHandler)
def scanShowDB(sectionNumber=0): global AmountOfMediasInDatabase global mediasFromDB global statusMsg global runningState try: Log.Debug('Starting scanShowDB for section %s' % (sectionNumber)) runningState = -1 statusMsg = 'Starting to scan database for section %s' % ( sectionNumber) # Start by getting the totals of this section totalSize = XML.ElementFromURL( self.CoreUrl + sectionNumber + '/all?X-Plex-Container-Start=1&X-Plex-Container-Size=0' ).get('totalSize') AmountOfMediasInDatabase = totalSize Log.Debug('Total size of medias are %s' % (totalSize)) iShow = 0 iCShow = 0 statusShows = 'Scanning database show %s of %s : ' % ( iShow, totalSize) statusMsg = statusShows # So let's walk the library while True: # Grap shows shows = XML.ElementFromURL( self.CoreUrl + sectionNumber + '/all?X-Plex-Container-Start=' + str(iCShow) + '&X-Plex-Container-Size=' + str(self.MediaChuncks) + '&excludeElements=' + excludeElements + '&excludeFields=' + excludeFields).xpath('//Directory') # Grap individual show for show in shows: statusShow = show.get('title') statusMsg = statusShows + statusShow iSeason = 0 iCSeason = 0 # Grap seasons while True: seasons = XML.ElementFromURL( misc.GetLoopBack() + show.get('key') + '?X-Plex-Container-Start=' + str(iCSeason) + '&X-Plex-Container-Size=' + str(self.MediaChuncks) + '&excludeElements=' + excludeElements + '&excludeFields=' + excludeFields).xpath('//Directory') # Grap individual season for season in seasons: if season.get('title') == 'All episodes': iSeason += 1 continue statusSeason = ' ' + season.get('title') statusMsg = statusShows + statusShow + statusSeason iSeason += 1 # Grap Episodes iEpisode = 0 iCEpisode = 0 while True: episodes = XML.ElementFromURL( misc.GetLoopBack() + season.get('key') + '?X-Plex-Container-Start=' + str(iCEpisode) + '&X-Plex-Container-Size=' + str(self.MediaChuncks) + '&excludeElements=' + excludeElements + '&excludeFields=' + excludeFields).xpath('//Part') for episode in episodes: if bAbort: raise ValueError('Aborted') filename = episode.get('file') filename = String.Unquote( filename).encode('utf8', 'ignore') mediasFromDB.append(filename) iEpisode += 1 # Inc Episodes counter iCEpisode += self.MediaChuncks if len(episodes) == 0: break # Inc Season counter iCSeason += self.MediaChuncks if len(seasons) == 0: break iShow += 1 statusShows = 'Scanning database show %s of %s : ' % ( iShow, totalSize) # Inc. Shows counter iCShow += self.MediaChuncks if len(shows) == 0: statusMsg = 'Scanning database: %s : Done' % ( totalSize) Log.Debug('***** Done scanning the database *****') if DEBUGMODE: Log.Debug(mediasFromDB) runningState = 1 break return except ValueError: statusMsg = 'Idle' runningState = 99 Log.Info('Aborted in ScanShowDB') except Exception, e: Log.Exception('Fatal error in scanShowDB: ' + str(e)) runningState = 99
class viewstate(object): @classmethod def init(self): return ''' This metode will import a viewlist file * Param: localFile (In the payload) * Param: User (In param, optional, and if missing, is the uwner) * Param: Section (In param, and mandentory) ''' @classmethod def IMPORT(self, req, *args): print '*********** GED ***********' print 'Ged logon as not owner', 'Check access denied', 'Make it a thread', 'Make a method to grap status', 'Make it possible to abort' Log.Info('ViewState Import called') # Payload Upload file present? if not 'localFile' in req.request.files: req.clear() req.set_status(412) req.finish( 'Missing upload file parameter named \ localFile from the payload') else: localFile = req.request.files['localFile'][0]['body'] # Get parameters from url try: user = None if args is not None: # We got additional arguments if len(args) > 0: # Get them in lower case arguments = [item.lower() for item in list(args)[0]] if 'user' in arguments: # Get key of the user user = arguments[arguments.index('user') + 1] if 'section' in arguments: # Get Section Number section = arguments[arguments.index('section') + 1] else: section = None if not section: req.clear() req.set_status(412) req.finish('Missing import file parameter named Section') except Exception, e: Log.Exception( 'Exception happened in ViewState Import was: %s' % (str(e))) req.clear() req.set_status(500) req.finish( 'Exception happened in ViewState Import was: %s' % (str(e))) # So now user is either none or a keyId if user: # Darn....Hard work ahead..We have # to logon as another user here :-( result['user'] = user # Get user list, among with their access tokens users = plexTV().getUserList() print 'Ged Users', users else: print 'User is the owner' try: ViewState = json.loads(localFile) Log.Info('Import returned %s' % (json.dumps(ViewState, ensure_ascii=False))) watched = ViewState['watched'] print 'Ged Watched', watched ServerId = ViewState['serverId'] sectionType = ViewState['sectionType'] CurrentServerId = XML.ElementFromURL( misc.GetLoopBack() + '/identity').get('machineIdentifier') print 'Ged ServedID', CurrentServerId, ServerId self.ImportFile(ServerId == CurrentServerId) ''' if ServerId == CurrentServerId: # Same Server, so no need to search here :) print 'Ged Same server detected' Log.Debug('Same Server detected, so no need to search here') self.setWatched(req, watched, user, None) else: # We need to search sadly Log.Debug( 'New server, so we need to search here, limited to selected section key') print 'Ged do stuff but search first' watched = self.SearchMedia(req, watched, section, sectionType) self.setWatched(req, watched, user, None) ''' except Exception, e: Log.Exception( 'Exception happened in ViewState Import was: %s' % (str(e))) req.clear() req.set_status(500) req.finish( 'Exception happened in ViewState Import was: %s' % (str(e)))
def updateMediaAgent(key, agent, year, title): global ChangedErr global ChangedOK url = ''.join(( misc.GetLoopBack(), '/library/metadata/', key, '/matches?agent=', agent, '&manual=0' )) try: result = False print 'ged 101', url SearchResults = XML.ElementFromURL(url).xpath('//SearchResult') print 'ged 102' Log.Info( 'Found %s possibillities for %s' % (len(SearchResults), title)) # for SearchResult in SearchResults: SearchResult = SearchResults[0] print 'ged 103' # Check if there's an year in the title, and if so, remove it match = re.match(r'.*([1-2][0-9]{3})', title) if match is not None: # Then it found a match! title = title.replace(match.group(1), '') title = re.sub("\(|\)|\[|\]", "", title).strip() print 'Ged 104' if year == SearchResult.get('year'): if title == SearchResult.get('name'): if int(SearchResult.get('score')) >= MinScore: print 'ged 55', String.Quote(SearchResult.get('guid')) updateurl = ''.join(( misc.GetLoopBack(), '/library/metadata/', key, '/match?guid=', String.Quote(SearchResult.get('guid')), '&name=', String.Quote(SearchResult.get('name')) )) try: result = HTTP.Request( url=updateurl, method='PUT', immediate=True, timeout=5) ChangedOK.append(unicode(title, "utf-8")) result = True print 'Ged 105' break except Exception, e: Log.Exception( 'Exception happened in \ updateMediaAgent was %s' % str(e)) ChangedErr.append(unicode(title, "utf-8")) result = False else: Log.Info( 'Updating failed, since a score of %s %' % SearchResult.get('score')) Log.Info('is below the minimum of %s %' % MinScore) if not result: Log.Info('Could not find any match for: %s', title) ChangedErr.append(title)
def scanShowDB(sectionNumber=0, agent=None, Force=False): """Scan Episodes from the database""" global statusMsg global runningState try: Log.Debug( 'Starting scanShowDB for section %s' % ( sectionNumber)) runningState = -1 statusMsg = wtV3().GETTRANSLATE( None, Internal=True, String='Starting to scan database for section %s')\ % (sectionNumber) # Start by getting the totals of episodes for this section urlSize = ''.join(( misc.GetLoopBack(), '/library/sections/', sectionNumber, '/all?X-Plex-Container-Start=1', '&X-Plex-Container-Size=0', '&type=', str(MEDIATYPE['Episode']) )) totalSize = XML.ElementFromURL(urlSize).get('totalSize') AmountOfMediasInDatabase = totalSize Log.Debug('Total size of medias are %s' % (totalSize)) iEpisode = 0 iCEpisode = 0 statusEpisodes = wtV3().GETTRANSLATE( None, Internal=True, String='Scanning database episodes %s of %s :')\ % (iEpisode, totalSize) statusMsg = statusEpisodes # So let's walk the library while True: # Grap Episodes urlEpisodes = ''.join(( misc.GetLoopBack(), '/library/sections/', sectionNumber, '/all?excludeElements=', EXCLUDEELEMENTS, '&excludeFields=', EXCLUDEFIELDS, '&X-Plex-Container-Start=', str(iCEpisode), '&X-Plex-Container-Size=', str(MediaChuncks), '&type=', str(MEDIATYPE['Episode']) )) print 'Ged 61 urlEpisodes', urlEpisodes episodes = XML.ElementFromURL(urlEpisodes).xpath('//Video') # Grap individual shows for episode in episodes: urlEpisode = ''.join(( misc.GetLoopBack(), '/library/metadata/', episode.get('ratingKey'), '?excludeElements=', EXCLUDEELEMENTS, '&excludeFields=', EXCLUDEFIELDS )) print 'Ged 81', urlEpisode currentEpisode = XML.ElementFromURL( urlEpisode).xpath('//Video')[0] title = currentEpisode.get('title') guid = currentEpisode.get('guid') # year = currentShow.get('year') # key = currentShow.get('ratingKey') statusMsg = 'investigating episode: %s' % ( title) Log.Info(statusMsg) key = episode.get('ratingKey') year = episode.get('year') print 'GED KIG HER' # Store show id in a list. and afterwards, fix each show one by one statusMsg = 'Updating show: %s' % ( title) if agent not in guid: Log.Info(statusMsg) print 'Ged updating', title # key = show.get('ratingKey') # year = show.get('year') updateMediaAgent(key, agent, year, title) elif Force: Log.Info(statusMsg) print 'Ged Key', key print 'Ged Agent', agent print 'Ged Year', year print 'Ged Title', title updateMediaAgent(key, agent, year, title) else: Log.Info('Episode: %s is okay' % title) iCEpisode += MediaChuncks if len(episodes) == 0: strMsg = ( 'Scanning database: %s : Done' % (str(totalSize))) statusMsg = wtV3().GETTRANSLATE( None, Internal=True, String=strMsg) Log.Debug('***** Done scanning the database *****') runningState = 1 break return except ValueError: statusMsg = wtV3().GETTRANSLATE( None, Internal=True, String='Idle') runningState = 99 Log.Info('Aborted in ScanShowDB') except Exception, e: Log.Exception('Fatal error in scanShowDB: ' + str(e)) runningState = 99
def get_thisPMSIdentity(self): return XML.ElementFromURL(misc.GetLoopBack() + '/identity').get('machineIdentifier')
def auth2myPlex(self): return 'ok' == XML.ElementFromURL( misc.GetLoopBack()).get('myPlexSigninState')
def GETINFO(self, req, *args): Log.Debug('Starting getInfo') try: techInfo = {} try: id = XML.ElementFromURL(misc.GetLoopBack() + '/identity') except: pass # Get File system encoding Log.Info('File System Encoding: %s' % str(sys.getfilesystemencoding())) techInfo['File System Encoding'] = str(sys.getfilesystemencoding()) Log.Info( '********************** INFO from API **********************') try: Log.Info('OS is: %s' % Platform.OS) techInfo['Platform'] = Platform.OS except: pass try: Log.Info('CPU is: %s' % Platform.CPU) techInfo['CPU'] = Platform.CPU except: pass try: Log.Info('Python version is: %s' % sys.version) techInfo['Python'] = sys.version except: pass try: Log.Info('Support Silverlight: %s' % Platform.HasSilverlight) techInfo['Silverlight'] = Platform.HasSilverlight except: pass try: Log.Info('Locale is: %s' % locale.getdefaultlocale()) techInfo['Locale'] = str(locale.getdefaultlocale()) except: pass try: Log.Info('Machine Identifier: %s' % id.get('machineIdentifier')) techInfo['MachineID'] = id.get('machineIdentifier') except: pass try: Log.Info('PMS Version: %s' % id.get('version')) techInfo['PMSVersion'] = id.get('version') except: pass try: Log.Info('PMS App Support path: %s' % Core.app_support_path) techInfo['AppSupportPath_FrameWork'] = Core.app_support_path except: pass Log.Info( '********************** INFO from ENV *********************') try: Log.Info( 'PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR: %s' % os.environ['PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR']) techInfo['AppSupportPath_OS'] = os.environ[ 'PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR'] except: pass try: Log.Info('PYTHONDONTWRITEBYTECODE: %s' % os.environ['PYTHONDONTWRITEBYTECODE']) techInfo['PythonDontWriteByteCode'] = os.environ[ 'PYTHONDONTWRITEBYTECODE'] except: pass try: Log.Info('USER: %s' % os.environ['USER']) techInfo['User'] = os.environ['USER'] except: pass try: dirUsr = getpwuid(os.stat(Core.bundle_path).st_uid).pw_name Log.Info('User BundleDir: %s' % dirUsr) techInfo['WebTools directory owner'] = dirUsr except: pass try: dirGroup = getgrgid(os.stat(Core.bundle_path).st_gid).gr_name Log.Info('Group BundleDir: %s' % dirGroup) techInfo['WebTools directory group'] = dirGroup except: pass try: Log.Info('HOME: %s' % os.environ['HOME']) techInfo['Home'] = os.environ['HOME'] except: pass try: Log.Info('LD_LIBRARY_PATH: %s' % os.environ['LD_LIBRARY_PATH']) techInfo['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH'] except: pass try: Log.Info('LANG: %s' % os.environ['LANG']) techInfo['LANG'] = os.environ['LANG'] except: pass try: Log.Info('LANGUAGE: %s' % os.environ['LANGUAGE']) techInfo['LANGUAGE'] = os.environ['LANGUAGE'] except: pass try: Log.Info('TMPDIR: %s' % os.environ['TMPDIR']) techInfo['TMPDIR'] = os.environ['TMPDIR'] except: pass try: Log.Info('PLEXLOCALAPPDATA: %s' % os.environ['PLEXLOCALAPPDATA']) techInfo['PLEXLOCALAPPDATA'] = os.environ['PLEXLOCALAPPDATA'] except: pass try: Log.Info('LC_ALL: %s' % os.environ['LC_ALL']) techInfo['LC_ALL'] = os.environ['LC_ALL'] except: pass try: Log.Info('Executable: %s' % os.environ['_']) techInfo['Executable'] = os.environ['_'] except: pass try: Log.Info('PLEXBUNDLEDEXTS: %s' % os.environ['PLEXBUNDLEDEXTS']) techInfo['PLEXBUNDLEDEXTS'] = os.environ['PLEXBUNDLEDEXTS'] except: pass try: Log.Info('PYTHONHOME: %s' % os.environ['PYTHONHOME']) techInfo['PYTHONHOME'] = os.environ['PYTHONHOME'] except: pass try: Log.Info('PWD: %s' % os.environ['PWD']) techInfo['PWD'] = os.environ['PWD'] except: pass try: Log.Info('PLEXBUNDLEDPLUGINSPATH: ' % os.environ['PLEXBUNDLEDPLUGINSPATH']) techInfo['PLEXBUNDLEDPLUGINSPATH'] = os.environ[ 'PLEXBUNDLEDPLUGINSPATH'] except: pass try: Log.Info('PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS: ' % os.environ['PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS']) techInfo['PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS'] = os.environ[ 'PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS'] except: pass try: Log.Info('PLEXTOKEN: **** SCRAMBLED ****') StringKey = 'PLEXTOKEN *********' StringValue = wtV3().GETTRANSLATE( None, None, Internal=True, String='DO NOT SHARE THIS IN ANY PUBLIC WEBSITE!!!') techInfo[StringKey] = StringValue techInfo['PLEXTOKEN'] = os.environ['PLEXTOKEN'] except: pass try: Log.Info('PLEX_MEDIA_SERVER_INFO_VENDOR: ' % os.environ['PLEX_MEDIA_SERVER_INFO_VENDOR']) techInfo['PLEX_MEDIA_SERVER_INFO_VENDOR'] = os.environ[ 'PLEX_MEDIA_SERVER_INFO_VENDOR'] except: pass try: Log.Info('PLEX_MEDIA_SERVER_INFO_DEVICE: ' % os.environ['PLEX_MEDIA_SERVER_INFO_DEVICE']) techInfo['PLEX_MEDIA_SERVER_INFO_DEVICE'] = os.environ[ 'PLEX_MEDIA_SERVER_INFO_DEVICE'] except: pass try: Log.Info('PLEX_MEDIA_SERVER_INFO_MODEL: ' % os.environ['PLEX_MEDIA_SERVER_INFO_MODEL']) techInfo['PLEX_MEDIA_SERVER_INFO_MODEL'] = os.environ[ 'PLEX_MEDIA_SERVER_INFO_MODEL'] except: pass try: Log.Info('PLEX_MEDIA_SERVER_INFO_PLATFORM_VERSION: ' % os.environ['PLEX_MEDIA_SERVER_INFO_PLATFORM_VERSION']) techInfo[ 'PLEX_MEDIA_SERVER_INFO_PLATFORM_VERSION'] = os.environ[ 'PLEX_MEDIA_SERVER_INFO_PLATFORM_VERSION'] except: pass Log.Info('********************** INFO End ******************') techInfo['Log Directory'] = LOG_DIR req.clear() req.set_status(200) req.set_header('Content-Type', 'application/json; charset=utf-8') req.finish(json.dumps(techInfo, sort_keys=True)) except Exception, e: Log.Exception('Exception in getInfo: ' + str(e)) req.clear() req.set_status(500) req.finish('Fatal error happened in getInfo: ' + str(e)) return req
def GETINFO(self, req, *args): Log.Debug('Starting getInfo') try: techInfo = {} try: id = XML.ElementFromURL(misc.GetLoopBack() + '/identity') except: pass Log.Info( '************************** INFO from API **************************' ) try: Log.Info('OS is: ' + Platform.OS) techInfo['Platform'] = Platform.OS except: pass try: Log.Info('CPU is: ' + Platform.CPU) techInfo['CPU'] = Platform.CPU except: pass try: Log.Info('Python version is: ' + sys.version) techInfo['Python'] = sys.version except: pass try: Log.Info('Support Silverlight: ' + Platform.HasSilverlight) techInfo['Silverlight'] = Platform.HasSilverlight except: pass try: Log.Info('Locale is: ' + str(locale.getdefaultlocale())) techInfo['Locale'] = str(locale.getdefaultlocale()) except: pass try: Log.Info('Machine Identifier: ' + id.get('machineIdentifier')) techInfo['MachineID'] = id.get('machineIdentifier') except: pass try: Log.Info('PMS Version: ' + id.get('version')) techInfo['PMSVersion'] = id.get('version') except: pass try: Log.Info('PMS App Support path: ' + Core.app_support_path) techInfo['AppSupportPath_FrameWork'] = Core.app_support_path except: pass Log.Info( '************************** INFO from ENV **************************' ) try: Log.Info( 'PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR: ' + os.environ['PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR']) techInfo['AppSupportPath_OS'] = os.environ[ 'PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR'] except: pass try: Log.Info('PYTHONDONTWRITEBYTECODE: ' + os.environ['PYTHONDONTWRITEBYTECODE']) techInfo['PythonDontWriteByteCode'] = os.environ[ 'PYTHONDONTWRITEBYTECODE'] except: pass try: Log.Info('USER: '******'USER']) techInfo['User'] = os.environ['USER'] except: pass try: Log.Info('HOME: ' + os.environ['HOME']) techInfo['Home'] = os.environ['HOME'] except: pass try: Log.Info('LD_LIBRARY_PATH: ' + os.environ['LD_LIBRARY_PATH']) techInfo['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH'] except: pass try: Log.Info('LANG: ' + os.environ['LANG']) techInfo['LANG'] = os.environ['LANG'] except: pass try: Log.Info('LANGUAGE: ' + os.environ['LANGUAGE']) techInfo['LANGUAGE'] = os.environ['LANGUAGE'] except: pass try: Log.Info('TMPDIR: ' + os.environ['TMPDIR']) techInfo['TMPDIR'] = os.environ['TMPDIR'] except: pass try: Log.Info('PLEXLOCALAPPDATA: ' + os.environ['PLEXLOCALAPPDATA']) techInfo['PLEXLOCALAPPDATA'] = os.environ['PLEXLOCALAPPDATA'] except: pass try: Log.Info('LC_ALL: ' + os.environ['LC_ALL']) techInfo['LC_ALL'] = os.environ['LC_ALL'] except: pass try: Log.Info('Executable: ' + os.environ['_']) techInfo['Executable'] = os.environ['_'] except: pass try: Log.Info('PLEXBUNDLEDEXTS: ' + os.environ['PLEXBUNDLEDEXTS']) techInfo['PLEXBUNDLEDEXTS'] = os.environ['PLEXBUNDLEDEXTS'] except: pass try: Log.Info('PYTHONHOME: ' + os.environ['PYTHONHOME']) techInfo['PYTHONHOME'] = os.environ['PYTHONHOME'] except: pass try: Log.Info('PWD: ' + os.environ['PWD']) techInfo['PWD'] = os.environ['PWD'] except: pass try: Log.Info('PLEXBUNDLEDPLUGINSPATH: ' + os.environ['PLEXBUNDLEDPLUGINSPATH']) techInfo['PLEXBUNDLEDPLUGINSPATH'] = os.environ[ 'PLEXBUNDLEDPLUGINSPATH'] except: pass try: Log.Info('PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS: ' + os.environ['PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS']) techInfo['PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS'] = os.environ[ 'PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS'] except: pass try: Log.Info('PLEXTOKEN: **** SCRAMBLED ****') StringKey = 'PLEXTOKEN *********' StringValue = wtV3().GETTRANSLATE( None, None, Internal=True, String='DO NOT SHARE THIS IN ANY PUBLIC WEBSITE!!!') techInfo[StringKey] = StringValue techInfo['PLEXTOKEN'] = os.environ['PLEXTOKEN'] except: pass Log.Info( '************************** INFO End **********************') try: if 'PLEX_MEDIA_SERVER_LOG_DIR' in os.environ: LOGDIR = os.environ['PLEX_MEDIA_SERVER_LOG_DIR'] elif sys.platform.find( 'linux') == 0 and 'PLEXLOCALAPPDATA' in os.environ: LOGDIR = os.path.join(os.environ['PLEXLOCALAPPDATA'], 'Plex Media Server', 'Logs') elif sys.platform == 'win32': if 'PLEXLOCALAPPDATA' in os.environ: key = 'PLEXLOCALAPPDATA' else: key = 'LOCALAPPDATA' LOGDIR = os.path.join(os.environ[key], 'Plex Media Server', 'Logs') else: LOGDIR = os.path.join(os.environ['HOME'], 'Library', 'Logs', 'Plex Media Server') if not os.path.isdir(self.LOGDIR): LOGDIR = os.path.join(Core.app_support_path, 'Logs') except Exception, e: Log.Exception( 'Fatal error happened in getting the Log Directory: ' + str(e)) req.clear() req.set_status(500) req.finish( 'Fatal error happened in TechInfo getting the Log Dir list: ' + str(e)) techInfo['Log Directory'] = LOGDIR req.clear() req.set_status(200) req.set_header('Content-Type', 'application/json; charset=utf-8') req.finish(json.dumps(techInfo, sort_keys=True))