cache image, download log etc.

This commit is contained in:
Hellowlol 2016-05-09 00:44:02 +02:00
parent 21fcbd85d8
commit 9ae441b75a
7 changed files with 452 additions and 375 deletions

View file

@ -21,6 +21,7 @@
<span><i class="fa fa-list-alt"></i> Logs</span>
</div>
<div class="button-bar">
<button class="btn btn-dark" id="download-plexpylog"><i class="fa fa-download"></i> Download log</button>
<button class="btn btn-dark" id="clear-logs"><i class="fa fa-trash-o"></i> Clear log</button>
<button class="btn btn-dark" id="clear-notify-logs" style="display: none;"><i class="fa fa-trash-o"></i> Clear log</button>
</div>
@ -157,6 +158,7 @@
$("#plexpy-logs-btn").click(function () {
$("#clear-logs").show();
$("#download-plexpylog").show()
$("#clear-notify-logs").hide();
LoadPlexPyLogs();
clearSearchButton('log_table', log_table);
@ -164,6 +166,7 @@
$("#plex-logs-btn").click(function () {
$("#clear-logs").hide();
$("#download-plexpylog").hide()
$("#clear-notify-logs").hide();
LoadPlexLogs();
clearSearchButton('plex_log_table', plex_log_table);
@ -171,6 +174,7 @@
$("#plex-scanner-logs-btn").click(function () {
$("#clear-logs").hide();
$("#download-plexpylog").hide()
$("#clear-notify-logs").hide();
LoadPlexScannerLogs();
clearSearchButton('plex_scanner_log_table', plex_scanner_log_table);
@ -178,6 +182,7 @@
$("#notification-logs-btn").click(function () {
$("#clear-logs").hide();
$("#download-plexpylog").hide()
$("#clear-notify-logs").show();
LoadNotificationLogs();
clearSearchButton('notification_log_table', notification_log_table);
@ -190,6 +195,11 @@
}
});
$("#download-plexpylog").click(function () {
window.location.href = "download_log";
});
$("#clear-notify-logs").click(function () {
var r = confirm("Are you sure you want to clear the PlexPy notification log?");
if (r == true) {

View file

@ -67,8 +67,6 @@ CONFIG_FILE = None
DB_FILE = None
LOG_LIST = []
INSTALL_TYPE = None
CURRENT_VERSION = None
LATEST_VERSION = None
@ -134,7 +132,7 @@ def initialize(config_file):
try:
os.makedirs(CONFIG.BACKUP_DIR)
except OSError as e:
logger.error("Could not create backup dir '%s': %s", BACKUP_DIR, e)
logger.error("Could not create backup dir '%s': %s" % (BACKUP_DIR, e))
if not CONFIG.CACHE_DIR:
CONFIG.CACHE_DIR = os.path.join(DATA_DIR, 'cache')
@ -142,14 +140,14 @@ def initialize(config_file):
try:
os.makedirs(CONFIG.CACHE_DIR)
except OSError as e:
logger.error("Could not create cache dir '%s': %s", CACHE_DIR, e)
logger.error("Could not create cache dir '%s': %s" % (CACHE_DIR, e))
# Initialize the database
logger.info('Checking to see if the database has all tables....')
try:
dbcheck()
except Exception as e:
logger.error("Can't connect to the database: %s", e)
logger.error("Can't connect to the database: %s" % e)
# Check if PlexPy has a uuid
if CONFIG.PMS_UUID == '' or not CONFIG.PMS_UUID:
@ -171,8 +169,8 @@ def initialize(config_file):
with open(version_lock_file, "w") as fp:
fp.write(CURRENT_VERSION)
except IOError as e:
logger.error("Unable to write current version to file '%s': %s",
version_lock_file, e)
logger.error("Unable to write current version to file '%s': %s" %
(version_lock_file, e))
# Check for new versions
if CONFIG.CHECK_GITHUB_ON_STARTUP and CONFIG.CHECK_GITHUB:
@ -219,7 +217,7 @@ def daemonize():
pid = os.fork() # @UndefinedVariable - only available in UNIX
if pid != 0:
sys.exit(0)
except OSError, e:
except OSError as e:
raise RuntimeError("1st fork failed: %s [%d]", e.strerror, e.errno)
os.setsid()
@ -233,7 +231,7 @@ def daemonize():
pid = os.fork() # @UndefinedVariable - only available in UNIX
if pid != 0:
sys.exit(0)
except OSError, e:
except OSError as e:
raise RuntimeError("2nd fork failed: %s [%d]", e.strerror, e.errno)
dev_null = file('/dev/null', 'r')
@ -269,7 +267,7 @@ def launch_browser(host, port, root):
try:
webbrowser.open('%s://%s:%i%s' % (protocol, host, port, root))
except Exception as e:
logger.error('Could not launch browser: %s', e)
logger.error('Could not launch browser: %s' % e)
def initialize_scheduler():
@ -949,7 +947,7 @@ def shutdown(restart=False, update=False):
try:
versioncheck.update()
except Exception as e:
logger.warn('PlexPy failed to update: %s. Restarting.', e)
logger.warn('PlexPy failed to update: %s. Restarting.' % e)
if CREATEPID:
logger.info('Removing pidfile %s', PIDFILE)

View file

@ -443,6 +443,9 @@ General optional parameters:
if self._api_cmd == 'docs_md':
return out['response']['data']
elif self._api_cmd == 'download_log':
return
if self._api_out_type == 'json':
cherrypy.response.headers['Content-Type'] = 'application/json;charset=UTF-8'
try:

View file

@ -31,7 +31,7 @@ import helpers
# These settings are for file logging only
FILENAME = "plexpy.log"
MAX_SIZE = 1000000 # 1 MB
MAX_SIZE = 5000000 # 5 MB
MAX_FILES = 5
_BLACKLIST_WORDS = []
@ -42,18 +42,6 @@ logger = logging.getLogger("plexpy")
# Global queue for multiprocessing logging
queue = None
class LogListHandler(logging.Handler):
"""
Log handler for Web UI.
"""
def emit(self, record):
message = self.format(record)
message = message.replace("\n", "<br />")
plexpy.LOG_LIST.insert(0, (helpers.now(), message, record.levelname, record.threadName))
class NoThreadFilter(logging.Filter):
"""
Log filter for the current thread
@ -209,12 +197,6 @@ def initLogger(console=False, log_dir=False, verbose=False):
logger.propagate = False
logger.setLevel(logging.DEBUG if verbose else logging.INFO)
# Add list logger
loglist_handler = LogListHandler()
loglist_handler.setLevel(logging.DEBUG)
logger.addHandler(loglist_handler)
# Setup file logger
if log_dir:
filename = os.path.join(log_dir, FILENAME)

View file

@ -1890,7 +1890,7 @@ class PmsConnect(object):
return labels_list
def get_image(self, img=None, width=None, height=None, fallback=None):
def get_image(self, img=None, width=None, height=None):
"""
Return image data as array.
Array contains the image content type and image binary
@ -1900,51 +1900,24 @@ class PmsConnect(object):
height { the image height }
Output: array
"""
if not img:
logger.error(u"PlexPy Pmsconnect :: Image proxy queried but no input received.")
return None
# Remove the timestamp from PMS image uri
image_uri = img.rsplit('/', 1)[0]
# Try to retrieve the image from cache if it isn't a bif index.
if not 'indexes' in image_uri:
image_path, content_type = helpers.cache_image(image_uri)
if image_path and content_type:
return [open(image_path, 'rb'), content_type]
try:
if img:
uri = '/photo/:/transcode?url=http://127.0.0.1:32400%s' % img
if width.isdigit() and height.isdigit():
uri = '/photo/:/transcode?url=http://127.0.0.1:32400' + img + '&width=' + width + '&height=' + height
else:
logger.error(u"PlexPy Pmsconnect :: Image proxy queried but no width or height specified.")
raise Exception
uri += '&width=%s&height=%s' % (width, height)
request, content_type = self.request_handler.make_request(uri=uri,
result = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET',
return_type=True)
# Save the image to cache if it isn't a bif index.
if not 'indexes' in image_uri:
helpers.cache_image(image_uri, request)
return [request, content_type]
if result is None:
return
else:
return result[0], result[1]
except Exception as e:
if fallback:
logger.debug(u"PlexPy Pmsconnect :: Trying fallback %s image." % fallback)
try:
if fallback == 'poster':
return [open(common.DEFAULT_POSTER_THUMB, 'rb'), 'image/png']
elif fallback == 'cover':
return [open(common.DEFAULT_COVER_THUMB, 'rb'), 'image/png']
elif fallback == 'art':
return [open(common.DEFAULT_ART, 'rb'), 'image/png']
except IOError as e:
logger.error(u"PlexPy Pmsconnect :: Unable to read fallback %s image: %s" % (fallback, e))
return None
else:
logger.error(u"PlexPy Pmsconnect :: Image proxy queries but no input received.")
def get_search_results(self, query=''):
"""

View file

@ -20,6 +20,9 @@ import random
import threading
import cherrypy
from cherrypy.lib.static import serve_file, serve_download
from cherrypy._cperror import NotFound
from hashing_passwords import make_hash
from mako.lookup import TemplateLookup
from mako import exceptions
@ -296,7 +299,7 @@ class WebInterface(object):
try:
pms_connect = pmsconnect.PmsConnect()
result = pms_connect.get_recently_added_details(count=count)
except IOError, e:
except IOError as e:
return serve_template(templatename="recently_added.html", data=None)
if result:
@ -1227,7 +1230,7 @@ class WebInterface(object):
if delete_row:
return {'message': delete_row}
elif username:
delete_row = delete_user.undelete(username=username)
delete_row = user_data.undelete(username=username)
if delete_row:
return {'message': delete_row}
@ -1902,11 +1905,17 @@ class WebInterface(object):
##### Logs #####
@cherrypy.expose
def makeerror(self):
try:
1 / 0
except Exception as e:
logger.exception(e)
@cherrypy.expose
@requireAuth(member_of("admin"))
def logs(self):
return serve_template(templatename="logs.html", title="Log", lineList=plexpy.LOG_LIST)
return serve_template(templatename="logs.html", title="Log")
@cherrypy.expose
@requireAuth(member_of("admin"))
@ -1930,11 +1939,26 @@ class WebInterface(object):
if 'search[regex]' in kwargs:
search_regex = kwargs.get('search[regex]', "")
filt = []
fa = filt.append
with open(os.path.join(plexpy.CONFIG.LOG_DIR, 'plexpy.log')) as f:
for l in f.readlines():
try:
temp_loglevel_and_time = l.split('- ')
loglvl = temp_loglevel_and_time[1].split(' :')[0].strip()
msg = l.split(' : ')[1].replace('\n', '')
fa([temp_loglevel_and_time[0], loglvl, msg])
except IndexError:
# Add traceback message to previous msg..
tl = (len(filt) - 1)
filt[tl][2] += ' ' + l.replace('\n', '')
continue
filtered = []
if search_value == "":
filtered = plexpy.LOG_LIST[::]
if search_value == '':
filtered = filt
else:
filtered = [row for row in plexpy.LOG_LIST for column in row if search_value.lower() in column.lower()]
filtered = [row for row in filt for column in row if search_value.lower() in column.lower()]
sortcolumn = 0
if order_column == '1':
@ -1944,11 +1968,10 @@ class WebInterface(object):
filtered.sort(key=lambda x: x[sortcolumn], reverse=order_dir == "desc")
rows = filtered[start:(start + length)]
rows = [[row[0], row[2], row[1]] for row in rows]
return json.dumps({
'recordsFiltered': len(filtered),
'recordsTotal': len(plexpy.LOG_LIST),
'recordsTotal': len(filt),
'data': rows,
})
@ -2070,17 +2093,19 @@ class WebInterface(object):
"""
data_factory = datafactory.DataFactory()
result = data_factory.delete_notification_log()
result = result if result else 'no data received'
if result:
return {'message': result}
else:
return {'message': 'no data received'}
@cherrypy.expose
@requireAuth(member_of("admin"))
def clearLogs(self):
plexpy.LOG_LIST = []
logger.info(u"Web logs cleared")
try:
open(os.path.join(plexpy.CONFIG.LOG_DIR, 'plexpy.log'), 'w').close()
except Exception as e:
logger.exception(u'Failed to delete plexpy.log %s' % e)
logger.info(u'plexpy.log cleared')
raise cherrypy.HTTPRedirect("logs")
@cherrypy.expose
@ -2403,7 +2428,6 @@ class WebInterface(object):
else:
return {'message': 'Database backup failed.'}
@cherrypy.expose
@requireAuth(member_of("admin"))
def get_notification_agent_config(self, agent_id, **kwargs):
@ -2791,16 +2815,92 @@ class WebInterface(object):
@cherrypy.expose
@requireAuth()
def pms_image_proxy(self, img='', width='0', height='0', fallback=None, **kwargs):
def pms_image_proxy(self, img='', ratingkey=None, width='0', height='0', fallback=None, **kwargs):
""" Grabs the images from pms and saved them to disk """
if not img and not ratingkey:
logger.debug('No image input received')
return
if ratingkey and not img:
img = '/library/metadata/%s/thumb/1337' % ratingkey
img_string = img.rsplit('/', 1)[0]
img_string += '%s%s' % (width, height)
fp = hashlib.md5(img_string).hexdigest()
fp += '.jpg' # we want to be able to preview the thumbs
c_dir = os.path.join(plexpy.CONFIG.CACHE_DIR, 'images')
ffp = os.path.join(c_dir, fp)
if not os.path.exists(c_dir):
os.mkdir(c_dir)
try:
if 'indexes' in img:
raise
return serve_file(path=ffp, content_type='image/jpeg')
except NotFound:
# the image does not exist, download it from pms
try:
pms_connect = pmsconnect.PmsConnect()
result = pms_connect.get_image(img, width, height, fallback)
result = pms_connect.get_image(img, width, height)
if result:
if result and result[0]:
cherrypy.response.headers['Content-type'] = result[1]
if 'indexes' not in img:
with open(ffp, 'wb') as f:
f.write(result[0])
return result[0]
else:
return None
raise
except Exception as e:
logger.debug('Failed to get image %s file %s falling back to %s' % (img, fp, e))
fbi = None
if fallback == 'poster':
fbi = common.DEFAULT_POSTER_THUMB
elif fallback == 'cover':
fbi = common.DEFAULT_COVER_THUMB
elif fallback == 'art':
fbi = common.DEFAULT_ART
if fbi:
fp = os.path.join(plexpy.PROG_DIR, 'data', fbi)
return serve_file(path=fp, content_type='image/png')
@cherrypy.expose
@requireAuth(member_of("admin"))
@addtoapi()
def download_log(self):
try:
logger.logger.flush()
except:
pass
return serve_download(os.path.join(plexpy.CONFIG.LOG_DIR, 'plexpy.log'), name='plexpy.log')
@cherrypy.expose
@requireAuth(member_of("admin"))
@addtoapi()
def delete_image_cache(self):
""" Deletes the image cache dir and recreates it """
cache_dir = os.path.join(plexpy.CONFIG.CACHE_DIR, 'images')
try:
os.rmdir(cache_dir)
except OSError as e:
logger.exception('Failed to delete %s %s' % (cache_dir, e))
return
try:
os.makedirs(cache_dir)
except OSError as e:
logger.exception('Faild to make %s %s' % (cache_dir, e))
return
return {'result': 'success', 'message': 'Deleted image cache'}
@cherrypy.expose
@cherrypy.tools.json_out()

View file

@ -178,6 +178,17 @@ def initialize(options):
'tools.auth.on': False,
'tools.sessions.on': False
},
'/pms_image_proxy': {
'tools.staticdir.on': True,
'tools.staticdir.dir': os.path.join(plexpy.CONFIG.CACHE_DIR, 'images'),
'tools.caching.on': True,
'tools.caching.force': True,
'tools.caching.delay': 0,
'tools.expires.on': True,
'tools.expires.secs': 60 * 60 * 24 * 30, # 30 days
'tools.auth.on': False,
'tools.sessions.on': False
},
'/favicon.ico': {
'tools.staticfile.on': True,
'tools.staticfile.filename': os.path.abspath(os.path.join(plexpy.PROG_DIR, 'data/interfaces/default/images/favicon.ico')),