mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-07 05:31:15 -07:00
Fix crash on user page if user no longer exists as friend.
Provide fallback images if we can't load the real one. Some sync table improvements.
This commit is contained in:
parent
aa700e2b63
commit
2aa833d127
6 changed files with 59 additions and 46 deletions
|
@ -46,9 +46,9 @@ DOCUMENTATION :: END
|
|||
<li>
|
||||
<span>
|
||||
<a href="info?rating_key=${a['rows'][0]['rating_key']}">
|
||||
% if a['rows'][0]['grandparent_thumb'] != '':
|
||||
% if a['rows'][0]['grandparent_thumb']:
|
||||
<img class="home-platforms-instance-poster"
|
||||
src="pms_image_proxy?img=${a['rows'][0]['grandparent_thumb']}&width=162&height=240">
|
||||
src="pms_image_proxy?img=${a['rows'][0]['grandparent_thumb']}&width=162&height=240&fallback=poster">
|
||||
% else:
|
||||
<img class="home-platforms-instance-poster" src="interfaces/default/images/poster.png">
|
||||
% endif
|
||||
|
@ -75,7 +75,7 @@ DOCUMENTATION :: END
|
|||
<a href="info?rating_key=${a['rows'][0]['rating_key']}">
|
||||
% if a['rows'][0]['grandparent_thumb'] != '':
|
||||
<img class="home-platforms-instance-poster"
|
||||
src="pms_image_proxy?img=${a['rows'][0]['grandparent_thumb']}&width=162&height=240">
|
||||
src="pms_image_proxy?img=${a['rows'][0]['grandparent_thumb']}&width=162&height=240&fallback=poster">
|
||||
% else:
|
||||
<img class="home-platforms-instance-poster" src="interfaces/default/images/poster.png">
|
||||
% endif
|
||||
|
|
|
@ -9,12 +9,14 @@ sync_table_options = {
|
|||
"pageLength": 25,
|
||||
"stateSave": true,
|
||||
"language": {
|
||||
"search":"Search: ",
|
||||
"lengthMenu":"Show _MENU_ lines per page",
|
||||
"emptyTable": "No synced items",
|
||||
"info":"Showing _START_ to _END_ of _TOTAL_ lines",
|
||||
"infoEmpty":"Showing 0 to 0 of 0 lines",
|
||||
"infoFiltered":"(filtered from _MAX_ total lines)"},
|
||||
"search":"Search: ",
|
||||
"lengthMenu":"Show _MENU_ lines per page",
|
||||
"emptyTable": "No synced items",
|
||||
"info":"Showing _START_ to _END_ of _TOTAL_ lines",
|
||||
"infoEmpty":"Showing 0 to 0 of 0 lines",
|
||||
"infoFiltered":"(filtered from _MAX_ total lines)",
|
||||
"loadingRecords":'<i class="fa fa-refresh fa-spin"></i> Loading items...</div>'
|
||||
},
|
||||
"columnDefs": [
|
||||
{
|
||||
"targets": [0],
|
||||
|
@ -91,11 +93,10 @@ sync_table_options = {
|
|||
},
|
||||
{
|
||||
"targets": [10],
|
||||
"data": null,
|
||||
"data": "item_downloaded_percent_complete",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (rowData['item_count'] > 0 ) {
|
||||
percent_complete = Math.round((rowData['item_downloaded_count']/rowData['item_count']*100),0);
|
||||
$(td).html('<span class="badge">' + percent_complete + '%</span>');
|
||||
$(td).html('<span class="badge">' + cellData + '%</span>');
|
||||
} else {
|
||||
$(td).html('<span class="badge">0%</span>');
|
||||
}
|
||||
|
|
|
@ -25,10 +25,10 @@ import re
|
|||
|
||||
from plexpy import version
|
||||
|
||||
#Identify Our Application
|
||||
# Identify Our Application
|
||||
USER_AGENT = 'PlexPy/-' + version.PLEXPY_VERSION + ' (' + platform.system() + ' ' + platform.release() + ')'
|
||||
|
||||
### Notification Types
|
||||
# Notification Types
|
||||
NOTIFY_SNATCH = 1
|
||||
NOTIFY_DOWNLOAD = 2
|
||||
|
||||
|
@ -36,13 +36,5 @@ notifyStrings = {}
|
|||
notifyStrings[NOTIFY_SNATCH] = "Started Download"
|
||||
notifyStrings[NOTIFY_DOWNLOAD] = "Download Finished"
|
||||
|
||||
### Release statuses
|
||||
UNKNOWN = -1 # should never happen
|
||||
UNAIRED = 1 # releases that haven't dropped yet
|
||||
SNATCHED = 2 # qualified with quality
|
||||
WANTED = 3 # releases we don't have but want to get
|
||||
DOWNLOADED = 4 # qualified with quality
|
||||
SKIPPED = 5 # releases we don't want
|
||||
ARCHIVED = 6 # releases that you don't have locally (counts toward download completion stats)
|
||||
IGNORED = 7 # releases that you don't want included in your download stats
|
||||
SNATCHED_PROPER = 9 # qualified with quality
|
||||
DEFAULT_USER_THUMB = "interfaces/default/images/gravatar-default-80x80.png"
|
||||
DEFAULT_POSTER_THUMB = "interfaces/default/images/poster.png"
|
|
@ -17,17 +17,9 @@ from plexpy import logger, helpers, plexwatch
|
|||
|
||||
from xml.dom import minidom
|
||||
from httplib import HTTPSConnection
|
||||
from urlparse import parse_qsl
|
||||
from urllib import urlencode
|
||||
|
||||
import base64
|
||||
import cherrypy
|
||||
import urllib
|
||||
import urllib2
|
||||
import plexpy
|
||||
import os.path
|
||||
import subprocess
|
||||
import json
|
||||
|
||||
|
||||
class PlexTV(object):
|
||||
|
@ -346,6 +338,8 @@ class PlexTV(object):
|
|||
status_item_ready_count = self.get_xml_attr(status, 'itemsReadyCount')
|
||||
status_item_successful_count = self.get_xml_attr(status, 'itemsSuccessfulCount')
|
||||
status_total_size = self.get_xml_attr(status, 'totalSize')
|
||||
status_item_download_percent_complete = helpers.get_percent(
|
||||
status_item_downloaded_count, status_item_count)
|
||||
|
||||
for settings in item.getElementsByTagName('MediaSettings'):
|
||||
settings_audio_boost = self.get_xml_attr(settings, 'audioBoost')
|
||||
|
@ -376,6 +370,7 @@ class PlexTV(object):
|
|||
"item_count": status_item_count,
|
||||
"item_complete_count": status_item_complete_count,
|
||||
"item_downloaded_count": status_item_downloaded_count,
|
||||
"item_downloaded_percent_complete": status_item_download_percent_complete,
|
||||
"music_bitrate": settings_music_bitrate,
|
||||
"photo_quality": settings_photo_quality,
|
||||
"video_quality": settings_video_quality,
|
||||
|
|
|
@ -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, datatables, db
|
||||
from plexpy import logger, helpers, datatables, db, common
|
||||
from xml.dom import minidom
|
||||
import sys
|
||||
if sys.version_info < (2, 7):
|
||||
|
@ -100,8 +100,8 @@ class PlexWatch(object):
|
|||
|
||||
rows = []
|
||||
for item in users:
|
||||
if not item['thumb']:
|
||||
user_thumb = 'interfaces/default/images/gravatar-default-80x80.png'
|
||||
if not item['thumb'] or item['thumb'] == '':
|
||||
user_thumb = common.DEFAULT_USER_THUMB
|
||||
else:
|
||||
user_thumb = item['thumb']
|
||||
|
||||
|
@ -710,8 +710,8 @@ class PlexWatch(object):
|
|||
return None
|
||||
|
||||
for item in result:
|
||||
if not item['thumb']:
|
||||
user_thumb = 'interfaces/default/images/gravatar-default-80x80.png'
|
||||
if not item['thumb'] or item['thumb'] == '':
|
||||
user_thumb = common.DEFAULT_USER_THUMB
|
||||
else:
|
||||
user_thumb = item[4]
|
||||
|
||||
|
@ -948,10 +948,20 @@ class PlexWatch(object):
|
|||
def get_user_details(self, user=None, user_id=None):
|
||||
try:
|
||||
myDB = db.DBConnection()
|
||||
t = self.get_history_table_name()
|
||||
|
||||
if user:
|
||||
query = 'select user_id, username, friendly_name, email, thumb, ' \
|
||||
'is_home_user, is_allow_sync, is_restricted FROM plexpy_users WHERE username = ? LIMIT 1'
|
||||
result = myDB.select(query, args=[user])
|
||||
query = 'SELECT user_id, username, friendly_name, email, ' \
|
||||
'thumb, is_home_user, is_allow_sync, is_restricted ' \
|
||||
'FROM plexpy_users ' \
|
||||
'WHERE username = ? ' \
|
||||
'UNION ALL ' \
|
||||
'SELECT null, user, null, null, null, null, null, null ' \
|
||||
'FROM %s ' \
|
||||
'WHERE user = ? ' \
|
||||
'GROUP BY user ' \
|
||||
'LIMIT 1' % t
|
||||
result = myDB.select(query, args=[user, user])
|
||||
elif user_id:
|
||||
query = 'select user_id, username, friendly_name, email, thumb, ' \
|
||||
'is_home_user, is_allow_sync, is_restricted FROM plexpy_users WHERE user_id = ? LIMIT 1'
|
||||
|
@ -962,12 +972,16 @@ class PlexWatch(object):
|
|||
friendly_name = item['username']
|
||||
else:
|
||||
friendly_name = item['friendly_name']
|
||||
if not item['thumb'] or item['thumb'] == '':
|
||||
user_thumb = common.DEFAULT_USER_THUMB
|
||||
else:
|
||||
user_thumb = item['thumb']
|
||||
|
||||
user_details = {"user_id": item['user_id'],
|
||||
"username": item['username'],
|
||||
"friendly_name": friendly_name,
|
||||
"email": item['email'],
|
||||
"thumb": item['thumb'],
|
||||
"thumb": user_thumb,
|
||||
"is_home_user": item['is_home_user'],
|
||||
"is_allow_sync": item['is_allow_sync'],
|
||||
"is_restricted": item['is_restricted']
|
||||
|
|
|
@ -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, db
|
||||
from plexpy import logger, notifiers, plextv, pmsconnect, plexwatch, db, common
|
||||
from plexpy.helpers import checked, radio
|
||||
|
||||
from mako.lookup import TemplateLookup
|
||||
|
@ -50,6 +50,10 @@ def serve_template(templatename, **kwargs):
|
|||
|
||||
|
||||
class WebInterface(object):
|
||||
|
||||
def __init__(self):
|
||||
self.interface_dir = os.path.join(str(plexpy.PROG_DIR), 'data/')
|
||||
|
||||
@cherrypy.expose
|
||||
def index(self):
|
||||
raise cherrypy.HTTPRedirect("home")
|
||||
|
@ -108,7 +112,6 @@ class WebInterface(object):
|
|||
user_details = plex_watch.get_user_details(user)
|
||||
except:
|
||||
logger.warn("Unable to retrieve friendly name for user %s " % user)
|
||||
friendly_name = user
|
||||
|
||||
return serve_template(templatename="user.html", title="User", data=user_details)
|
||||
|
||||
|
@ -532,7 +535,7 @@ class WebInterface(object):
|
|||
logger.warn('Unable to retrieve data.')
|
||||
|
||||
@cherrypy.expose
|
||||
def pms_image_proxy(self, img='', width='0', height='0', **kwargs):
|
||||
def pms_image_proxy(self, img='', width='0', height='0', fallback=None, **kwargs):
|
||||
if img != '':
|
||||
try:
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
|
@ -541,10 +544,18 @@ class WebInterface(object):
|
|||
return result[1]
|
||||
except:
|
||||
logger.warn('Image proxy queried but errors occured.')
|
||||
return 'No image'
|
||||
if fallback == 'poster':
|
||||
logger.info('Trying fallback image...')
|
||||
try:
|
||||
fallback_image = open(self.interface_dir + common.DEFAULT_POSTER_THUMB, 'rb')
|
||||
cherrypy.response.headers['Content-type'] = 'image/png'
|
||||
return fallback_image
|
||||
except IOError, e:
|
||||
logger.error('Unable to read fallback image. %s' % e)
|
||||
return None
|
||||
else:
|
||||
logger.warn('Image proxy queried but no parameters received.')
|
||||
return 'No image'
|
||||
return None
|
||||
|
||||
@cherrypy.expose
|
||||
def info(self, rating_key='', **kwargs):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue