mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-08 14:10:52 -07:00
Fix bug with xml and unicode conversion.
Fix some minor front-end issues. Initial work on new users table.
This commit is contained in:
parent
12331e1c4c
commit
2d822c8468
8 changed files with 256 additions and 18 deletions
|
@ -23,7 +23,7 @@ from plexpy import helpers
|
|||
<div class="span9"><h2><i class="fa fa-book"></i> Logs</h2></div>
|
||||
<div class="span3">
|
||||
<div class="pull-right">
|
||||
<h5><a id="menu_link_edit" href="clearLogs"><i class="fa fa-trash-o"></i> Clear log</a>
|
||||
<h5><a id="menu_link_edit" href="clearLogs"><i class="fa fa-trash-o"></i> Clear log</a></h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -14,7 +14,12 @@ from plexpy import helpers
|
|||
<div class="span12">
|
||||
<div class="wellheader-bg">
|
||||
<div class="dashboard-wellheader-no-chevron">
|
||||
<h2><i class="fa fa-group"></i> Users</h2>
|
||||
<div class="span9"><h2><i class="fa fa-group"></i> Users</h2></div>
|
||||
<div class="span3">
|
||||
<div class="pull-right">
|
||||
<h5><a href="refresh_users_list"><i class="fa fa-refresh"></i> Refresh users</a></h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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: '/'
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from plexpy import logger, helpers, common, request
|
||||
from plexpy import logger, helpers
|
||||
|
||||
from xml.dom import minidom
|
||||
from httplib import HTTPSConnection
|
||||
|
@ -214,3 +214,72 @@ class PlexTV(object):
|
|||
return None
|
||||
|
||||
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
|
|
@ -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])
|
||||
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.")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue