diff --git a/data/interfaces/default/logs.html b/data/interfaces/default/logs.html index 4c4d88ae..fca7b4d0 100644 --- a/data/interfaces/default/logs.html +++ b/data/interfaces/default/logs.html @@ -23,7 +23,7 @@ from plexpy import helpers

Logs

-
Clear log +
Clear log
diff --git a/data/interfaces/default/users.html b/data/interfaces/default/users.html index 5b55da1f..ac4c3391 100644 --- a/data/interfaces/default/users.html +++ b/data/interfaces/default/users.html @@ -14,7 +14,12 @@ from plexpy import helpers
-

Users

+

Users

+
diff --git a/plexpy/__init__.py b/plexpy/__init__.py index 07141e9b..58b3b2c2 100644 --- a/plexpy/__init__.py +++ b/plexpy/__init__.py @@ -307,8 +307,35 @@ def sig_handler(signum=None, frame=None): def dbcheck(): conn = sqlite3.connect(plexpy.CONFIG.PLEXWATCH_DATABASE) c = conn.cursor() - c.execute('CREATE TABLE IF NOT EXISTS plexpy_users (id INTEGER PRIMARY KEY AUTOINCREMENT, ' - 'username TEXT NOT NULL UNIQUE, friendly_name TEXT)') + c.execute( + 'CREATE TABLE IF NOT EXISTS plexpy_users (id INTEGER PRIMARY KEY AUTOINCREMENT, ' + 'user_id INTEGER DEFAULT NULL UNIQUE, username TEXT NOT NULL UNIQUE, ' + 'friendly_name TEXT, thumb TEXT, email TEXT, is_home_user INTEGER DEFAULT NULL, ' + 'is_allow_sync INTEGER DEFAULT NULL, is_restricted INTEGER DEFAULT NULL)' + ) + + # Upgrade plexpy_users table from earlier versions + try: + c.execute('SELECT user_id from plexpy_users') + except sqlite3.OperationalError: + logger.debug(u"Altering database. Updating database table plexpy_users.") + c.execute( + 'CREATE TABLE tmp_table (id INTEGER PRIMARY KEY AUTOINCREMENT, ' + 'user_id INTEGER DEFAULT NULL UNIQUE, username TEXT NOT NULL UNIQUE, ' + 'friendly_name TEXT, thumb TEXT, email TEXT, is_home_user INTEGER DEFAULT NULL, ' + 'is_allow_sync INTEGER DEFAULT NULL, is_restricted INTEGER DEFAULT NULL)' + ) + c.execute( + 'INSERT INTO tmp_table SELECT id, NULL, username, friendly_name, NULL, NULL, NULL, NULL, NULL ' + 'FROM plexpy_users' + ) + c.execute( + 'DROP TABLE plexpy_users' + ) + c.execute( + 'ALTER TABLE tmp_table RENAME TO plexpy_users' + ) + conn.commit() c.close() diff --git a/plexpy/helpers.py b/plexpy/helpers.py index a8bcac49..8d402e49 100644 --- a/plexpy/helpers.py +++ b/plexpy/helpers.py @@ -81,11 +81,11 @@ def latinToAscii(unicrap): 0xfd: 'y', 0xfe: 'th', 0xff: 'y', 0xa1: '!', 0xa2: '{cent}', 0xa3: '{pound}', 0xa4: '{currency}', 0xa5: '{yen}', 0xa6: '|', 0xa7: '{section}', 0xa8: '{umlaut}', - 0xa9: '{C}', 0xaa: '{^a}', 0xab: '<<', 0xac: '{not}', + 0xa9: '{C}', 0xaa: '{^a}', 0xab: '<<', 0xac: '{not}', 0xad: '-', 0xae: '{R}', 0xaf: '_', 0xb0: '{degrees}', 0xb1: '{+/-}', 0xb2: '{^2}', 0xb3: '{^3}', 0xb4: "'", 0xb5: '{micro}', 0xb6: '{paragraph}', 0xb7: '*', 0xb8: '{cedilla}', - 0xb9: '{^1}', 0xba: '{^o}', 0xbb: '>>', + 0xb9: '{^1}', 0xba: '{^o}', 0xbb: '>>', 0xbc: '{1/4}', 0xbd: '{1/2}', 0xbe: '{3/4}', 0xbf: '?', 0xd7: '*', 0xf7: '/' } diff --git a/plexpy/plextv.py b/plexpy/plextv.py index c8a44f7a..1eb848a6 100644 --- a/plexpy/plextv.py +++ b/plexpy/plextv.py @@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with PlexPy. If not, see . -from plexpy import logger, helpers, common, request +from plexpy import logger, helpers from xml.dom import minidom from httplib import HTTPSConnection @@ -213,4 +213,73 @@ class PlexTV(object): logger.warn(u"Failed to access server list. Status code %r" % request_status) return None - return output \ No newline at end of file + return output + + """ + Validate xml keys to make sure they exist and return their attribute value, return blank value is none found + """ + @staticmethod + def get_xml_attr(xml_key, attribute, return_bool=False, default_return=''): + if xml_key.getAttribute(attribute): + if return_bool: + return True + else: + return xml_key.getAttribute(attribute) + else: + if return_bool: + return False + else: + return default_return + + def get_full_users_list(self): + friends_list = self.get_plextv_friends() + own_account = self.get_plextv_user_details() + users_list = [] + + try: + xml_parse = minidom.parseString(own_account) + except Exception, e: + logger.warn("Error parsing XML for Plex account details: %s" % e) + except: + logger.warn("Error parsing XML for Plex account details.") + + xml_head = xml_parse.getElementsByTagName('user') + if not xml_head: + logger.warn("Error parsing XML for Plex account details.") + else: + for a in xml_head: + own_details = {"user_id": self.get_xml_attr(a, 'id'), + "username": self.get_xml_attr(a, 'username'), + "thumb": self.get_xml_attr(a, 'thumb'), + "email": self.get_xml_attr(a, 'email'), + "is_home_user": self.get_xml_attr(a, 'home'), + "is_allow_sync": None, + "is_restricted": self.get_xml_attr(a, 'restricted') + } + + users_list.append(own_details) + + try: + xml_parse = minidom.parseString(friends_list) + except Exception, e: + logger.warn("Error parsing XML for Plex friends list: %s" % e) + except: + logger.warn("Error parsing XML for Plex friends list.") + + xml_head = xml_parse.getElementsByTagName('User') + if not xml_head: + logger.warn("Error parsing XML for Plex friends list.") + else: + for a in xml_head: + friend = {"user_id": self.get_xml_attr(a, 'id'), + "username": self.get_xml_attr(a, 'title'), + "thumb": self.get_xml_attr(a, 'thumb'), + "email": self.get_xml_attr(a, 'email'), + "is_home_user": self.get_xml_attr(a, 'home'), + "is_allow_sync": self.get_xml_attr(a, 'allowSync'), + "is_restricted": self.get_xml_attr(a, 'restricted') + } + + users_list.append(friend) + + return users_list \ No newline at end of file diff --git a/plexpy/plexwatch.py b/plexpy/plexwatch.py index 28819846..4c959070 100644 --- a/plexpy/plexwatch.py +++ b/plexpy/plexwatch.py @@ -72,7 +72,9 @@ class PlexWatch(object): t + '.time', t + '.ip_address', 'COUNT(' + t + '.title) as plays', - t + '.user'] + t + '.user', + 'plexpy_users.user_id as user_id', + 'plexpy_users.thumb as thumb'] try: query = data_tables.ssp_query(table_name=t, columns=columns, @@ -98,14 +100,18 @@ class PlexWatch(object): rows = [] for item in users: - thumb = self.get_user_gravatar_image(item['user']) + if not item['thumb']: + user_thumb = 'interfaces/default/images/gravatar-default-80x80.png' + else: + user_thumb = item['thumb'] row = {"plays": item['plays'], "time": item['time'], "friendly_name": item["friendly_name"], "ip_address": item["ip_address"], - "thumb": thumb['user_thumb'], - "user": item["user"] + "thumb": user_thumb, + "user": item["user"], + "user_id": item['user_id'] } rows.append(row) @@ -295,12 +301,12 @@ class PlexWatch(object): try: xml_parse = minidom.parseString(helpers.latinToAscii(item['xml'])) - except IOError, e: - logger.warn("Error parsing XML in PlexWatch db: %s" % e) + except: + logger.warn("Error parsing XML in PlexWatch db") xml_head = xml_parse.getElementsByTagName('opt') if not xml_head: - logger.warn("Error parsing XML in PlexWatch db: %s" % e) + logger.warn("Error parsing XML in PlexWatch db.") for s in xml_head: if s.getAttribute('duration') and s.getAttribute('viewOffset'): @@ -925,7 +931,10 @@ class PlexWatch(object): myDB = db.DBConnection() query = 'select friendly_name FROM plexpy_users WHERE username = ?' result = myDB.select_single(query, args=[user]) - return result + if result: + return result + else: + return user except: return user @@ -956,7 +965,9 @@ def check_db_tables(): try: myDB = db.DBConnection() query = 'CREATE TABLE IF NOT EXISTS plexpy_users (id INTEGER PRIMARY KEY AUTOINCREMENT, ' \ - 'username TEXT NOT NULL UNIQUE, friendly_name TEXT)' + 'user_id INTEGER DEFAULT NULL UNIQUE, username TEXT NOT NULL UNIQUE, ' \ + 'friendly_name TEXT, thumb TEXT, email TEXT, is_home_user INTEGER DEFAULT NULL, ' \ + 'is_allow_sync INTEGER DEFAULT NULL, is_restricted INTEGER DEFAULT NULL)' result = myDB.action(query) except: logger.debug(u"Unable to create users table.") diff --git a/plexpy/pmsconnect.py b/plexpy/pmsconnect.py index f5a5b703..64d599fe 100644 --- a/plexpy/pmsconnect.py +++ b/plexpy/pmsconnect.py @@ -212,6 +212,39 @@ class PmsConnect(object): return output + """ + Return the local servers preferences. + + Optional parameters: output_format { dict, json } + + Output: array + """ + def get_server_prefs(self, output_format=''): + url_command = '/:/prefs' + http_handler = HTTPConnection(self.host, self.port, timeout=10) + + try: + http_handler.request("GET", url_command + '?X-Plex-Token=' + self.token) + response = http_handler.getresponse() + request_status = response.status + request_content = response.read() + except IOError, e: + logger.warn(u"Failed to access metadata. %s" % e) + return None + + if request_status == 200: + if output_format == 'dict': + output = helpers.convert_xml_to_dict(request_content) + elif output_format == 'json': + output = helpers.convert_xml_to_json(request_content) + else: + output = request_content + else: + logger.warn(u"Failed to access metadata. Status code %r" % request_status) + return None + + return output + """ Return processed and validated list of recently added items. @@ -681,6 +714,41 @@ class PmsConnect(object): return output + """ + Return the local machine identifier. + + Output: string + """ + def get_servers_info(self): + recent = self.get_server_list() + + try: + xml_parse = minidom.parseString(recent) + except Exception, e: + logger.warn("Error parsing XML for Plex server prefs: %s" % e) + return None + except: + logger.warn("Error parsing XML for Plex server prefs.") + return None + + xml_head = xml_parse.getElementsByTagName('Server') + if not xml_head: + logger.warn("Error parsing XML for Plex server prefs.") + return None + + server_info = [] + for a in xml_head: + output = {"name": self.get_xml_attr(a, 'name'), + "machineIdentifier": self.get_xml_attr(a, 'machineIdentifier'), + "host": self.get_xml_attr(a, 'host'), + "port": self.get_xml_attr(a, 'port'), + "version": self.get_xml_attr(a, 'version') + } + + server_info.append(output) + + return server_info + """ Return image data as array. Array contains the image content type and image binary diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 1d11b6be..ba24b421 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with PlexPy. If not, see . -from plexpy import logger, notifiers, plextv, pmsconnect, plexwatch +from plexpy import logger, notifiers, plextv, pmsconnect, plexwatch, db from plexpy.helpers import checked, radio from mako.lookup import TemplateLookup @@ -833,3 +833,61 @@ class WebInterface(object): return result else: logger.warn('Unable to retrieve data.') + + @cherrypy.expose + def get_servers_info(self, **kwargs): + + pms_connect = pmsconnect.PmsConnect() + result = pms_connect.get_servers_info() + + if result: + cherrypy.response.headers['Content-type'] = 'application/json' + return json.dumps(result) + else: + logger.warn('Unable to retrieve data.') + + @cherrypy.expose + def get_server_prefs(self, **kwargs): + + pms_connect = pmsconnect.PmsConnect() + result = pms_connect.get_server_prefs(output_format='json') + + if result: + cherrypy.response.headers['Content-type'] = 'application/json' + return result + else: + logger.warn('Unable to retrieve data.') + + @cherrypy.expose + def get_full_users_list(self, **kwargs): + + plex_tv = plextv.PlexTV() + result = plex_tv.get_full_users_list() + + if result: + cherrypy.response.headers['Content-type'] = 'application/json' + return json.dumps(result) + else: + logger.warn('Unable to retrieve data.') + + @cherrypy.expose + def refresh_users_list(self, **kwargs): + plex_tv = plextv.PlexTV() + result = plex_tv.get_full_users_list() + myDB = db.DBConnection() + + for item in result: + control_value_dict = {"username": item['username']} + new_value_dict = {"user_id": item['user_id'], + "username": item['username'], + "thumb": item['thumb'], + "email": item['email'], + "is_home_user": item['is_home_user'], + "is_allow_sync": item['is_allow_sync'], + "is_restricted": item['is_restricted'] + } + + myDB.upsert('plexpy_users', new_value_dict, control_value_dict) + + logger.info("Users list refreshed.") + raise cherrypy.HTTPRedirect("users")