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>
|
<li>
|
||||||
<span>
|
<span>
|
||||||
<a href="info?rating_key=${a['rows'][0]['rating_key']}">
|
<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"
|
<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:
|
% else:
|
||||||
<img class="home-platforms-instance-poster" src="interfaces/default/images/poster.png">
|
<img class="home-platforms-instance-poster" src="interfaces/default/images/poster.png">
|
||||||
% endif
|
% endif
|
||||||
|
@ -75,7 +75,7 @@ DOCUMENTATION :: END
|
||||||
<a href="info?rating_key=${a['rows'][0]['rating_key']}">
|
<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"
|
<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:
|
% else:
|
||||||
<img class="home-platforms-instance-poster" src="interfaces/default/images/poster.png">
|
<img class="home-platforms-instance-poster" src="interfaces/default/images/poster.png">
|
||||||
% endif
|
% endif
|
||||||
|
|
|
@ -14,7 +14,9 @@ sync_table_options = {
|
||||||
"emptyTable": "No synced items",
|
"emptyTable": "No synced items",
|
||||||
"info":"Showing _START_ to _END_ of _TOTAL_ lines",
|
"info":"Showing _START_ to _END_ of _TOTAL_ lines",
|
||||||
"infoEmpty":"Showing 0 to 0 of 0 lines",
|
"infoEmpty":"Showing 0 to 0 of 0 lines",
|
||||||
"infoFiltered":"(filtered from _MAX_ total lines)"},
|
"infoFiltered":"(filtered from _MAX_ total lines)",
|
||||||
|
"loadingRecords":'<i class="fa fa-refresh fa-spin"></i> Loading items...</div>'
|
||||||
|
},
|
||||||
"columnDefs": [
|
"columnDefs": [
|
||||||
{
|
{
|
||||||
"targets": [0],
|
"targets": [0],
|
||||||
|
@ -91,11 +93,10 @@ sync_table_options = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"targets": [10],
|
"targets": [10],
|
||||||
"data": null,
|
"data": "item_downloaded_percent_complete",
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (rowData['item_count'] > 0 ) {
|
if (rowData['item_count'] > 0 ) {
|
||||||
percent_complete = Math.round((rowData['item_downloaded_count']/rowData['item_count']*100),0);
|
$(td).html('<span class="badge">' + cellData + '%</span>');
|
||||||
$(td).html('<span class="badge">' + percent_complete + '%</span>');
|
|
||||||
} else {
|
} else {
|
||||||
$(td).html('<span class="badge">0%</span>');
|
$(td).html('<span class="badge">0%</span>');
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ from plexpy import version
|
||||||
# Identify Our Application
|
# Identify Our Application
|
||||||
USER_AGENT = 'PlexPy/-' + version.PLEXPY_VERSION + ' (' + platform.system() + ' ' + platform.release() + ')'
|
USER_AGENT = 'PlexPy/-' + version.PLEXPY_VERSION + ' (' + platform.system() + ' ' + platform.release() + ')'
|
||||||
|
|
||||||
### Notification Types
|
# Notification Types
|
||||||
NOTIFY_SNATCH = 1
|
NOTIFY_SNATCH = 1
|
||||||
NOTIFY_DOWNLOAD = 2
|
NOTIFY_DOWNLOAD = 2
|
||||||
|
|
||||||
|
@ -36,13 +36,5 @@ notifyStrings = {}
|
||||||
notifyStrings[NOTIFY_SNATCH] = "Started Download"
|
notifyStrings[NOTIFY_SNATCH] = "Started Download"
|
||||||
notifyStrings[NOTIFY_DOWNLOAD] = "Download Finished"
|
notifyStrings[NOTIFY_DOWNLOAD] = "Download Finished"
|
||||||
|
|
||||||
### Release statuses
|
DEFAULT_USER_THUMB = "interfaces/default/images/gravatar-default-80x80.png"
|
||||||
UNKNOWN = -1 # should never happen
|
DEFAULT_POSTER_THUMB = "interfaces/default/images/poster.png"
|
||||||
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
|
|
|
@ -17,17 +17,9 @@ from plexpy import logger, helpers, plexwatch
|
||||||
|
|
||||||
from xml.dom import minidom
|
from xml.dom import minidom
|
||||||
from httplib import HTTPSConnection
|
from httplib import HTTPSConnection
|
||||||
from urlparse import parse_qsl
|
|
||||||
from urllib import urlencode
|
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import cherrypy
|
|
||||||
import urllib
|
|
||||||
import urllib2
|
|
||||||
import plexpy
|
import plexpy
|
||||||
import os.path
|
|
||||||
import subprocess
|
|
||||||
import json
|
|
||||||
|
|
||||||
|
|
||||||
class PlexTV(object):
|
class PlexTV(object):
|
||||||
|
@ -346,6 +338,8 @@ class PlexTV(object):
|
||||||
status_item_ready_count = self.get_xml_attr(status, 'itemsReadyCount')
|
status_item_ready_count = self.get_xml_attr(status, 'itemsReadyCount')
|
||||||
status_item_successful_count = self.get_xml_attr(status, 'itemsSuccessfulCount')
|
status_item_successful_count = self.get_xml_attr(status, 'itemsSuccessfulCount')
|
||||||
status_total_size = self.get_xml_attr(status, 'totalSize')
|
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'):
|
for settings in item.getElementsByTagName('MediaSettings'):
|
||||||
settings_audio_boost = self.get_xml_attr(settings, 'audioBoost')
|
settings_audio_boost = self.get_xml_attr(settings, 'audioBoost')
|
||||||
|
@ -376,6 +370,7 @@ class PlexTV(object):
|
||||||
"item_count": status_item_count,
|
"item_count": status_item_count,
|
||||||
"item_complete_count": status_item_complete_count,
|
"item_complete_count": status_item_complete_count,
|
||||||
"item_downloaded_count": status_item_downloaded_count,
|
"item_downloaded_count": status_item_downloaded_count,
|
||||||
|
"item_downloaded_percent_complete": status_item_download_percent_complete,
|
||||||
"music_bitrate": settings_music_bitrate,
|
"music_bitrate": settings_music_bitrate,
|
||||||
"photo_quality": settings_photo_quality,
|
"photo_quality": settings_photo_quality,
|
||||||
"video_quality": settings_video_quality,
|
"video_quality": settings_video_quality,
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# 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
|
from xml.dom import minidom
|
||||||
import sys
|
import sys
|
||||||
if sys.version_info < (2, 7):
|
if sys.version_info < (2, 7):
|
||||||
|
@ -100,8 +100,8 @@ class PlexWatch(object):
|
||||||
|
|
||||||
rows = []
|
rows = []
|
||||||
for item in users:
|
for item in users:
|
||||||
if not item['thumb']:
|
if not item['thumb'] or item['thumb'] == '':
|
||||||
user_thumb = 'interfaces/default/images/gravatar-default-80x80.png'
|
user_thumb = common.DEFAULT_USER_THUMB
|
||||||
else:
|
else:
|
||||||
user_thumb = item['thumb']
|
user_thumb = item['thumb']
|
||||||
|
|
||||||
|
@ -710,8 +710,8 @@ class PlexWatch(object):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for item in result:
|
for item in result:
|
||||||
if not item['thumb']:
|
if not item['thumb'] or item['thumb'] == '':
|
||||||
user_thumb = 'interfaces/default/images/gravatar-default-80x80.png'
|
user_thumb = common.DEFAULT_USER_THUMB
|
||||||
else:
|
else:
|
||||||
user_thumb = item[4]
|
user_thumb = item[4]
|
||||||
|
|
||||||
|
@ -948,10 +948,20 @@ class PlexWatch(object):
|
||||||
def get_user_details(self, user=None, user_id=None):
|
def get_user_details(self, user=None, user_id=None):
|
||||||
try:
|
try:
|
||||||
myDB = db.DBConnection()
|
myDB = db.DBConnection()
|
||||||
|
t = self.get_history_table_name()
|
||||||
|
|
||||||
if user:
|
if user:
|
||||||
query = 'select user_id, username, friendly_name, email, thumb, ' \
|
query = 'SELECT user_id, username, friendly_name, email, ' \
|
||||||
'is_home_user, is_allow_sync, is_restricted FROM plexpy_users WHERE username = ? LIMIT 1'
|
'thumb, is_home_user, is_allow_sync, is_restricted ' \
|
||||||
result = myDB.select(query, args=[user])
|
'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:
|
elif user_id:
|
||||||
query = 'select user_id, username, friendly_name, email, thumb, ' \
|
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'
|
'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']
|
friendly_name = item['username']
|
||||||
else:
|
else:
|
||||||
friendly_name = item['friendly_name']
|
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'],
|
user_details = {"user_id": item['user_id'],
|
||||||
"username": item['username'],
|
"username": item['username'],
|
||||||
"friendly_name": friendly_name,
|
"friendly_name": friendly_name,
|
||||||
"email": item['email'],
|
"email": item['email'],
|
||||||
"thumb": item['thumb'],
|
"thumb": user_thumb,
|
||||||
"is_home_user": item['is_home_user'],
|
"is_home_user": item['is_home_user'],
|
||||||
"is_allow_sync": item['is_allow_sync'],
|
"is_allow_sync": item['is_allow_sync'],
|
||||||
"is_restricted": item['is_restricted']
|
"is_restricted": item['is_restricted']
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# 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 plexpy.helpers import checked, radio
|
||||||
|
|
||||||
from mako.lookup import TemplateLookup
|
from mako.lookup import TemplateLookup
|
||||||
|
@ -50,6 +50,10 @@ def serve_template(templatename, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
class WebInterface(object):
|
class WebInterface(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.interface_dir = os.path.join(str(plexpy.PROG_DIR), 'data/')
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
def index(self):
|
def index(self):
|
||||||
raise cherrypy.HTTPRedirect("home")
|
raise cherrypy.HTTPRedirect("home")
|
||||||
|
@ -108,7 +112,6 @@ class WebInterface(object):
|
||||||
user_details = plex_watch.get_user_details(user)
|
user_details = plex_watch.get_user_details(user)
|
||||||
except:
|
except:
|
||||||
logger.warn("Unable to retrieve friendly name for user %s " % user)
|
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)
|
return serve_template(templatename="user.html", title="User", data=user_details)
|
||||||
|
|
||||||
|
@ -532,7 +535,7 @@ class WebInterface(object):
|
||||||
logger.warn('Unable to retrieve data.')
|
logger.warn('Unable to retrieve data.')
|
||||||
|
|
||||||
@cherrypy.expose
|
@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 != '':
|
if img != '':
|
||||||
try:
|
try:
|
||||||
pms_connect = pmsconnect.PmsConnect()
|
pms_connect = pmsconnect.PmsConnect()
|
||||||
|
@ -541,10 +544,18 @@ class WebInterface(object):
|
||||||
return result[1]
|
return result[1]
|
||||||
except:
|
except:
|
||||||
logger.warn('Image proxy queried but errors occured.')
|
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:
|
else:
|
||||||
logger.warn('Image proxy queried but no parameters received.')
|
logger.warn('Image proxy queried but no parameters received.')
|
||||||
return 'No image'
|
return None
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
def info(self, rating_key='', **kwargs):
|
def info(self, rating_key='', **kwargs):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue