diff --git a/data/interfaces/default/css/plexpy.css b/data/interfaces/default/css/plexpy.css index 587bee7b..38ae1dde 100644 --- a/data/interfaces/default/css/plexpy.css +++ b/data/interfaces/default/css/plexpy.css @@ -1350,40 +1350,27 @@ a .season-episodes-card-overlay:hover { list-style: none; margin: 0; } -.home-platforms-instance-poster { - margin-left: 0px; +.home-platforms-instance { + background-color: #282828; + position: relative; + float: left; + width: 300px; + padding: 10px; + margin-right: 20px; + margin-bottom: 20px; + webkit-box-sizing: content-box; + box-sizing: content-box; + z-index: 0; } -.home-platforms-instance-poster .poster-face { +.home-platforms-instance li { + position: relative; +} +.home-platforms-instance-info { + float: left; + position: relative; + padding-left: 80px; + width: 100%; height: 120px; - width: 80px; -} -.home-platforms-instance-box { - background-size: contain; - position: absolute; - left: 10px; - bottom: 35px; - height: 80px; - width: 80px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); - -moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); - box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); -} -.home-platforms-instance-oval { - background-size: contain; - position: absolute; - left: 10px; - bottom: 35px; - height: 80px; - width: 80px; - -webkit-border-radius: 50%; - -moz-border-radius: 50%; - border-radius: 50%; - webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); - -moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); - box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); } .home-platforms-instance-name { float: left; @@ -1395,64 +1382,214 @@ a .season-episodes-card-overlay:hover { line-height: 15px; font-weight: bold; width: 100%; - padding: 10px 0 0 10px; + padding: 0 0 0 20px; +} +.home-platforms-instance-name h5 { + font-size: 16px; + margin: 20px 0 2px 0; } .home-platforms-instance-playcount { float: left; - width: 180px; -} -.home-platforms-instance-mediainfo { - float: left; - background-color: #282828; - position: absolute; - bottom: 0; - left: 0; - padding-left: 170px; - width: 100%; - height: 175px; -} -.home-platforms-instance-media { position: relative; - float: left; - width: 375px; - height: 225px; - padding-bottom: 10px; - margin-right: 25px; - margin-bottom: 25px; - webkit-box-sizing: content-box; - box-sizing: content-box; + padding: 6px 0 0 20px; + width: 100%; } -.home-platforms-instance-info { - float: left; - background-color: #282828; - position: absolute; +.home-platforms-instance-playcount h3 { + font-size: 30px; + font-weight: bold; + color: #F9AA03; + line-height: 22px; + position: relative; top: 5px; - left: 0; - padding-left: 100px; - width: 100%; - height: 120px; -} -.home-platforms-instance { - background-color: #282828; - position: relative; + margin: 0 5px 0 0; float: left; - width: 300px; +} +.home-platforms-instance-playcount p { + color: #aaa; + font-size: 12px; + float: left; + position: relative; + top: 14px; + left: 0px; + margin-right: 5px; +} +.home-platforms-instance-poster { + margin-left: 0px; + position: absolute; +} +.home-platforms-instance-poster .home-platforms-poster-face { + background-position: center; + background-size: cover; height: 120px; - padding: 10px; - margin-right: 20px; - margin-bottom: 20px; - webkit-box-sizing: content-box; - box-sizing: content-box; + width: 80px; } -a .home-platforms-instance-oval:hover { +.home-platforms-instance-box { + background-position: center; + background-size: cover; + margin: 20px 0 0 0px; + height: 80px; + width: 80px; + position: relative; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); + -moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); + box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); + overflow: hidden; +} +.home-platforms-instance-oval { + background-position: center; + background-size: cover; + margin: 20px 0 0 0px; + height: 80px; + width: 80px; + position: relative; + -webkit-border-radius: 50%; + -moz-border-radius: 50%; + border-radius: 50%; + webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); + -moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); + box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); + overflow: hidden; +} +.home-platforms-instance-list { + float: left; + position: relative; + width: 100%; + padding: 0 10px 20px 10px; +} +.home-platforms-instance-list li { + margin-top: 25px; + position: relative; + height: 60px; +} +.home-platforms-instance-list-number { + background-color: #e9a049; + float: left; + position: absolute; + top: -10px; + left: 10px; + height: 20px; + width: 20px; + display: block; + text-align: center; + padding-top: 1px; + -webkit-border-radius: 50%; + -moz-border-radius: 50%; + border-radius: 50%; +} +.home-platforms-instance-list-number h4 { + color: #000; + font-size: 15px; + font-weight: bold; + margin: 0; +} +.home-platforms-instance-list-info { + float: left; + position: relative; + padding-left: 75px; + width: 100%; + height: 60px; +} +.home-platforms-instance-list-name { + float: left; + color: #fff; + text-overflow: ellipsis; + overflow: hidden; + position: relative; + font-size: 13px; + line-height: 15px; + font-weight: bold; + width: 100%; + padding: 2px 0 0 10px; +} +.home-platforms-instance-list-name h5 { + margin: 5px 0px; +} +.home-platforms-instance-list-playcount { + float: left; + position: relative; + padding: 4px 0 0 10px; + width: 100%; +} +.home-platforms-instance-list-playcount h3 { + font-size: 20px; + font-weight: bold; + color: #F9AA03; + line-height: 22px; + position: relative; + margin: 0 5px 0 0; + float: left; +} +.home-platforms-instance-list-playcount p { + color: #aaa; + font-size: 12px; + float: left; + position: relative; + top: 5px; + left: 0px; + margin-right: 5px; +} +.home-platforms-instance-list-poster { + position: absolute; + left: 20px; +} +.home-platforms-instance-list-poster .home-platforms-list-poster-face { + background-position: center; + background-size: cover; + height: 60px; + width: 40px; +} +.home-platforms-instance-list-box { + background-position: center; + background-size: cover; + margin: 10px 0 0 20px; + height: 40px; + width: 40px; + position: relative; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); + -moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); + box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); + overflow: hidden; +} +.home-platforms-instance-list-oval { + background-position: center; + background-size: cover; + margin: 10px 0 0 20px; + height: 40px; + width: 40px; + position: relative; + -webkit-border-radius: 50%; + -moz-border-radius: 50%; + border-radius: 50%; + webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); + -moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); + box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); + overflow: hidden; +} +a .home-platforms-instance-box:hover, +a .home-platforms-instance-oval:hover, +a .home-platforms-instance-list-box:hover, +a .home-platforms-instance-list-oval:hover, +.home-platforms-poster-face:hover, +.home-platforms-list-poster-face:hover + { webkit-box-shadow: inset 0 0 0 2px #e9a049; -moz-box-shadow: inset 0 0 0 2px #e9a049; box-shadow: inset 0 0 0 2px #e9a049; } -a .home-platforms-instance-box:hover { - webkit-box-shadow: inset 0 0 0 2px #e9a049; - -moz-box-shadow: inset 0 0 0 2px #e9a049; - box-shadow: inset 0 0 0 2px #e9a049; +.home-platforms-instance .slider { + background-color: #282828; + width: 320px; + display: none; + position: absolute; + top: 130px; + left: -10px; + z-index: 2; } .history-table-title { text-overflow: ellipsis; diff --git a/data/interfaces/default/home_stats.html b/data/interfaces/default/home_stats.html index 2a05ca34..c6a99149 100644 --- a/data/interfaces/default/home_stats.html +++ b/data/interfaces/default/home_stats.html @@ -48,7 +48,7 @@ DOCUMENTATION :: END def hd(minutes): if int(minutes) > 60: hours = int(helpers.cast_to_float(minutes) / 60) - minutes = int(helpers.cast_to_float(minutes) % hours) + minutes = int(helpers.cast_to_float(minutes) % 60 ) if minutes > 0: return "

" + str(hours) + "

hrs

" + str(minutes) + "

mins

" else: @@ -58,199 +58,479 @@ DOCUMENTATION :: END %> % if data: -% if data[0]['rows'] or data[2]['rows']: +% if data[0]['rows'] or data[1]['rows'] or data[2]['rows'] or data[3]['rows'] or data[4]['rows'] or data[5]['rows']: + % else:
No stats for selected period.

% endif diff --git a/data/interfaces/default/index.html b/data/interfaces/default/index.html index 9e221a9d..8a31845c 100644 --- a/data/interfaces/default/index.html +++ b/data/interfaces/default/index.html @@ -45,12 +45,12 @@ diff --git a/plexpy/config.py b/plexpy/config.py index 5fe59e29..51145685 100644 --- a/plexpy/config.py +++ b/plexpy/config.py @@ -1,4 +1,4 @@ -import plexpy.logger +import plexpy.logger import itertools import os import re @@ -84,6 +84,7 @@ _CONFIG_DEFINITIONS = { 'GROWL_ON_WATCHED': (int, 'Growl', 0), 'HOME_STATS_LENGTH': (int, 'General', 30), 'HOME_STATS_TYPE': (int, 'General', 0), + 'HOME_STATS_COUNT': (int, 'General', 5), 'HTTPS_CERT': (str, 'General', ''), 'HTTPS_KEY': (str, 'General', ''), 'HTTP_HOST': (str, 'General', '0.0.0.0'), diff --git a/plexpy/datafactory.py b/plexpy/datafactory.py index b60c654b..5257f5ae 100644 --- a/plexpy/datafactory.py +++ b/plexpy/datafactory.py @@ -129,7 +129,7 @@ class DataFactory(object): return dict - def get_home_stats(self, time_range='30', stat_type='0'): + def get_home_stats(self, time_range='30', stat_type='0', stat_count='5'): monitor_db = database.MonitorDatabase() if not time_range.isdigit(): @@ -137,6 +137,9 @@ class DataFactory(object): sort_type = 'total_plays' if stat_type == '0' else 'total_duration' + if not time_range.isdigit(): + stat_count = '5' + # This actually determines the output order in the home page stats_queries = ["top_tv", "popular_tv", "top_movies", "popular_movies", "top_users", "top_platforms"] home_stats = [] @@ -161,7 +164,7 @@ class DataFactory(object): '>= datetime("now", "-%s days", "localtime") ' \ 'AND session_history_metadata.media_type = "episode" ' \ 'GROUP BY session_history_metadata.grandparent_title ' \ - 'ORDER BY %s DESC LIMIT 10' % (time_range, sort_type) + 'ORDER BY %s DESC LIMIT %s' % (time_range, sort_type, stat_count) result = monitor_db.select(query) except: logger.warn("Unable to execute database query.") @@ -207,7 +210,7 @@ class DataFactory(object): '>= datetime("now", "-%s days", "localtime") ' \ 'AND session_history_metadata.media_type = "movie" ' \ 'GROUP BY session_history_metadata.full_title ' \ - 'ORDER BY %s DESC LIMIT 10' % (time_range, sort_type) + 'ORDER BY %s DESC LIMIT %s' % (time_range, sort_type, stat_count) result = monitor_db.select(query) except: logger.warn("Unable to execute database query.") @@ -251,7 +254,7 @@ class DataFactory(object): 'AND session_history_metadata.media_type = "episode" ' \ 'GROUP BY session_history_metadata.grandparent_title ' \ 'ORDER BY users_watched DESC, total_plays DESC ' \ - 'LIMIT 10' % time_range + 'LIMIT %s' % (time_range, stat_count) result = monitor_db.select(query) except: logger.warn("Unable to execute database query.") @@ -293,7 +296,7 @@ class DataFactory(object): 'AND session_history_metadata.media_type = "movie" ' \ 'GROUP BY session_history_metadata.full_title ' \ 'ORDER BY users_watched DESC, total_plays DESC ' \ - 'LIMIT 10' % time_range + 'LIMIT %s' % (time_range, stat_count) result = monitor_db.select(query) except: logger.warn("Unable to execute database query.") @@ -338,7 +341,7 @@ class DataFactory(object): 'WHERE datetime(session_history.stopped, "unixepoch", "localtime") >= ' \ 'datetime("now", "-%s days", "localtime") '\ 'GROUP BY session_history.user_id ' \ - 'ORDER BY %s DESC LIMIT 10' % (time_range, sort_type) + 'ORDER BY %s DESC LIMIT %s' % (time_range, sort_type, stat_count) result = monitor_db.select(query) except: logger.warn("Unable to execute database query.") @@ -386,7 +389,7 @@ class DataFactory(object): 'WHERE datetime(session_history.stopped, "unixepoch", "localtime") ' \ '>= datetime("now", "-%s days", "localtime") ' \ 'GROUP BY session_history.platform ' \ - 'ORDER BY total_plays DESC' % time_range + 'ORDER BY total_plays DESC LIMIT %s' % (time_range, stat_count) result = monitor_db.select(query) except: logger.warn("Unable to execute database query.") diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 54fc8d9f..3c0bf770 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -1,4 +1,4 @@ -# This file is part of PlexPy. +# This file is part of PlexPy. # # PlexPy is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -66,7 +66,8 @@ class WebInterface(object): def home(self): config = { "home_stats_length": plexpy.CONFIG.HOME_STATS_LENGTH, - "home_stats_type": plexpy.CONFIG.HOME_STATS_TYPE + "home_stats_type": plexpy.CONFIG.HOME_STATS_TYPE, + "home_stats_count": plexpy.CONFIG.HOME_STATS_COUNT } return serve_template(templatename="index.html", title="Home", config=config) @@ -119,9 +120,9 @@ class WebInterface(object): return json.dumps(formats) @cherrypy.expose - def home_stats(self, time_range='30', stat_type='0', **kwargs): + def home_stats(self, time_range='30', stat_type='0', stat_count='5', **kwargs): data_factory = datafactory.DataFactory() - stats_data = data_factory.get_home_stats(time_range=time_range, stat_type=stat_type) + stats_data = data_factory.get_home_stats(time_range=time_range, stat_type=stat_type, stat_count=stat_count) return serve_template(templatename="home_stats.html", title="Stats", data=stats_data) @@ -453,6 +454,7 @@ class WebInterface(object): "notify_on_watched_body_text": plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT, "home_stats_length": plexpy.CONFIG.HOME_STATS_LENGTH, "home_stats_type": checked(plexpy.CONFIG.HOME_STATS_TYPE), + "home_stats_count": checked(plexpy.CONFIG.HOME_STATS_COUNT), "buffer_threshold": plexpy.CONFIG.BUFFER_THRESHOLD, "buffer_wait": plexpy.CONFIG.BUFFER_WAIT }