Files
JellyPy/plexpy/plexwatch.py
Tim e1e3659eb3 Fix buggy behaviour if user sets friendly name as blank.
Hide "clear logs" button when viewing PMS logs (it has no impact on those).
Start major clean up of classes.
Initial work to allow SSL communication to Plex servers.
2015-07-04 23:18:06 +02:00

1055 lines
42 KiB
Python

# 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
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# PlexPy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# 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, common
from xml.dom import minidom
import sys
if sys.version_info < (2, 7):
from backport_collections import defaultdict, Counter
else:
from collections import defaultdict, Counter
import datetime
import plexpy
class PlexWatch(object):
"""
Retrieve and process data from the plexwatch database
"""
def __init__(self):
pass
@staticmethod
def get_history_table_name():
if plexpy.CONFIG.GROUPING_GLOBAL_HISTORY:
return "grouped"
else:
return "processed"
def get_user_list(self, start='', length='', kwargs=None):
data_tables = datatables.DataTables()
start = int(start)
length = int(length)
filtered = []
totalcount = 0
search_value = ""
search_regex = ""
order_column = 1
order_dir = "desc"
if 'order[0][dir]' in kwargs:
order_dir = kwargs.get('order[0][dir]', "desc")
if 'order[0][column]' in kwargs:
order_column = kwargs.get('order[0][column]', 1)
if 'search[value]' in kwargs:
search_value = kwargs.get('search[value]', "")
if 'search[regex]' in kwargs:
search_regex = kwargs.get('search[regex]', "")
t = self.get_history_table_name()
columns = [t + '.id',
'(case when plexpy_users.friendly_name is null then ' + t +
'.user else plexpy_users.friendly_name end) as friendly_name',
t + '.time',
t + '.ip_address',
'COUNT(' + t + '.title) as plays',
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,
start=start,
length=length,
order_column=int(order_column),
order_dir=order_dir,
search_value=search_value,
search_regex=search_regex,
custom_where='',
group_by=(t + '.user'),
join_type='LEFT OUTER JOIN',
join_table='plexpy_users',
join_evals=[t + '.user', 'plexpy_users.username'],
kwargs=kwargs)
except:
logger.warn("Unable to open PlexWatch database.")
return {'recordsFiltered': 0,
'recordsTotal': 0,
'data': 'null'},
users = query['result']
rows = []
for item in users:
if not item['thumb'] or item['thumb'] == '':
user_thumb = common.DEFAULT_USER_THUMB
else:
user_thumb = item['thumb']
row = {"plays": item['plays'],
"time": item['time'],
"friendly_name": item["friendly_name"],
"ip_address": item["ip_address"],
"thumb": user_thumb,
"user": item["user"],
"user_id": item['user_id']
}
rows.append(row)
dict = {'recordsFiltered': query['filteredCount'],
'recordsTotal': query['totalCount'],
'data': rows,
}
return dict
def get_user_unique_ips(self, start='', length='', kwargs=None, custom_where=''):
data_tables = datatables.DataTables()
start = int(start)
length = int(length)
filtered = []
totalcount = 0
search_value = ""
search_regex = ""
order_column = 0
order_dir = "desc"
if 'order[0][dir]' in kwargs:
order_dir = kwargs.get('order[0][dir]', "desc")
if 'order[0][column]' in kwargs:
order_column = kwargs.get('order[0][column]', 1)
if 'search[value]' in kwargs:
search_value = kwargs.get('search[value]', "")
if 'search[regex]' in kwargs:
search_regex = kwargs.get('search[regex]', "")
t = self.get_history_table_name()
columns = [t + '.time as last_seen',
t + '.user',
t + '.ip_address',
'COUNT(' + t + '.ip_address) as play_count',
t + '.platform',
t + '.title as last_watched'
]
try:
query = data_tables.ssp_query(table_name=self.get_history_table_name(),
columns=columns,
start=start,
length=length,
order_column=int(order_column),
order_dir=order_dir,
search_value=search_value,
search_regex=search_regex,
custom_where=custom_where,
group_by=(t + '.ip_address'),
join_type=None,
join_table=None,
join_evals=None,
kwargs=kwargs)
except:
logger.warn("Unable to open PlexWatch database.")
return {'recordsFiltered': 0,
'recordsTotal': 0,
'data': 'null'},
results = query['result']
rows = []
for item in results:
row = {"last_seen": item['last_seen'],
"ip_address": item['ip_address'],
"play_count": item['play_count'],
"platform": item['platform'],
"last_watched": item['last_watched']
}
rows.append(row)
dict = {'recordsFiltered': query['filteredCount'],
'recordsTotal': query['totalCount'],
'data': rows,
}
return dict
def get_history(self, start='', length='', kwargs=None, custom_where=''):
data_tables = datatables.DataTables()
start = int(start)
length = int(length)
filtered = []
totalcount = 0
search_value = ""
search_regex = ""
order_column = 1
order_dir = "desc"
t = self.get_history_table_name()
if 'order[0][dir]' in kwargs:
order_dir = kwargs.get('order[0][dir]', "desc")
if 'order[0][column]' in kwargs:
order_column = kwargs.get('order[0][column]', "1")
if 'search[value]' in kwargs:
search_value = kwargs.get('search[value]', "")
if 'search[regex]' in kwargs:
search_regex = kwargs.get('search[regex]', "")
columns = [t + '.id',
t + '.time as date',
'(case when plexpy_users.friendly_name is null then ' + t +
'.user else plexpy_users.friendly_name end) as friendly_name',
t + '.platform',
t + '.ip_address',
t + '.title',
t + '.time as started',
t + '.paused_counter',
t + '.stopped',
'round((julianday(datetime(' + t + '.stopped, "unixepoch", "localtime")) - \
julianday(datetime(' + t + '.time, "unixepoch", "localtime"))) * 86400) - \
(case when ' + t + '.paused_counter is null then 0 else ' + t + '.paused_counter end) as duration',
t + '.ratingKey as rating_key',
t + '.xml',
t + '.user',
t + '.grandparentRatingKey as grandparent_rating_key'
]
try:
query = data_tables.ssp_query(table_name=t,
columns=columns,
start=start,
length=length,
order_column=int(order_column),
order_dir=order_dir,
search_value=search_value,
search_regex=search_regex,
custom_where=custom_where,
group_by='',
join_type='LEFT OUTER JOIN',
join_table='plexpy_users',
join_evals=[t + '.user', 'plexpy_users.username'],
kwargs=kwargs)
except:
logger.warn("Unable to open PlexWatch database.")
return {'recordsFiltered': 0,
'recordsTotal': 0,
'data': 'null'},
history = query['result']
rows = []
# NOTE: We are adding in a blank xml field in order enable the Datatables "searchable" parameter
for item in history:
row = {"id": item['id'],
"date": item['date'],
"friendly_name": item['friendly_name'],
"platform": item["platform"],
"ip_address": item["ip_address"],
"title": item["title"],
"started": item["started"],
"paused_counter": item["paused_counter"],
"stopped": item["stopped"],
"rating_key": item["rating_key"],
"duration": item["duration"],
"percent_complete": 0,
"xml": "",
"user": item["user"]
}
if item['paused_counter'] > 0:
row['paused_counter'] = item['paused_counter']
else:
row['paused_counter'] = 0
if item['started']:
if item['stopped'] > 0:
stopped = item['stopped']
else:
stopped = 0
if item['paused_counter'] > 0:
paused_counter = item['paused_counter']
else:
paused_counter = 0
try:
xml_parse = minidom.parseString(helpers.latinToAscii(item['xml']))
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.")
for s in xml_head:
if s.getAttribute('duration') and s.getAttribute('viewOffset'):
view_offset = helpers.cast_to_float(s.getAttribute('viewOffset'))
duration = helpers.cast_to_float(s.getAttribute('duration'))
if duration > 0:
row['percent_complete'] = (view_offset / duration) * 100
else:
row['percent_complete'] = 0
rows.append(row)
dict = {'recordsFiltered': query['filteredCount'],
'recordsTotal': query['totalCount'],
'data': rows,
}
return dict
"""
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_stream_details(self, row_id=None):
myDB = db.DBConnection()
if row_id:
query = 'SELECT xml from %s where id = ?' % (self.get_history_table_name())
xml = myDB.select_single(query, args=[row_id])
xml_data = helpers.latinToAscii(xml)
else:
return None
try:
xml_parse = minidom.parseString(xml_data)
except:
logger.warn("Error parsing XML for Plex stream data.")
return None
xml_head = xml_parse.getElementsByTagName('opt')
if not xml_head:
logger.warn("Error parsing XML for Plex stream data.")
return None
stream_output = {}
for a in xml_head:
media_type = self.get_xml_attr(a, 'type')
title = self.get_xml_attr(a, 'title')
grandparent_title = self.get_xml_attr(a, 'grandparentTitle')
if a.getElementsByTagName('TranscodeSession'):
transcode_data = a.getElementsByTagName('TranscodeSession')
for transcode_session in transcode_data:
transcode_video_dec = self.get_xml_attr(transcode_session, 'videoDecision')
transcode_video_codec = self.get_xml_attr(transcode_session, 'videoCodec')
transcode_height = self.get_xml_attr(transcode_session, 'height')
transcode_width = self.get_xml_attr(transcode_session, 'width')
transcode_audio_dec = self.get_xml_attr(transcode_session, 'audioDecision')
transcode_audio_codec = self.get_xml_attr(transcode_session, 'audioCodec')
transcode_audio_channels = self.get_xml_attr(transcode_session, 'audioChannels')
else:
transcode_data = a.getElementsByTagName('Media')
for transcode_session in transcode_data:
transcode_video_dec = 'direct play'
transcode_video_codec = self.get_xml_attr(transcode_session, 'videoCodec')
transcode_height = self.get_xml_attr(transcode_session, 'height')
transcode_width = self.get_xml_attr(transcode_session, 'width')
transcode_audio_dec = 'direct play'
transcode_audio_codec = self.get_xml_attr(transcode_session, 'audioCodec')
transcode_audio_channels = self.get_xml_attr(transcode_session, 'audioChannels')
if a.getElementsByTagName('Media'):
stream_data = a.getElementsByTagName('Media')
for stream_item in stream_data:
stream_output = {'container': self.get_xml_attr(stream_item, 'container'),
'bitrate': self.get_xml_attr(stream_item, 'bitrate'),
'video_resolution': self.get_xml_attr(stream_item, 'videoResolution'),
'width': self.get_xml_attr(stream_item, 'width'),
'height': self.get_xml_attr(stream_item, 'height'),
'aspect_ratio': self.get_xml_attr(stream_item, 'aspectRatio'),
'video_framerate': self.get_xml_attr(stream_item, 'videoFrameRate'),
'video_codec': self.get_xml_attr(stream_item, 'videoCodec'),
'audio_codec': self.get_xml_attr(stream_item, 'audioCodec'),
'audio_channels': self.get_xml_attr(stream_item, 'audioChannels'),
'transcode_video_dec': transcode_video_dec,
'transcode_video_codec': transcode_video_codec,
'transcode_height': transcode_height,
'transcode_width': transcode_width,
'transcode_audio_dec': transcode_audio_dec,
'transcode_audio_codec': transcode_audio_codec,
'transcode_audio_channels': transcode_audio_channels,
'media_type': media_type,
'title': title,
'grandparent_title': grandparent_title
}
return stream_output
def get_recently_watched(self, user=None, limit='10'):
myDB = db.DBConnection()
recently_watched = []
if not limit.isdigit():
limit = '10'
try:
if user:
query = 'SELECT time, user, xml FROM %s WHERE user = ? ORDER BY time DESC LIMIT ?' % \
(self.get_history_table_name())
xml = myDB.select(query, args=[user, limit])
else:
query = 'SELECT time, user, xml FROM %s ORDER BY time DESC LIMIT ?' % \
(self.get_history_table_name())
xml = myDB.select(query, args=[limit])
except:
logger.warn("Unable to open PlexWatch database.")
return None
for row in xml:
xml_data = helpers.latinToAscii(row[2])
try:
xml_parse = minidom.parseString(xml_data)
except:
logger.warn("Error parsing XML for Plex stream data.")
return None
xml_head = xml_parse.getElementsByTagName('opt')
if not xml_head:
logger.warn("Error parsing XML for Plex stream data.")
return None
for a in xml_head:
if self.get_xml_attr(a, 'type') == 'episode':
thumb = self.get_xml_attr(a, 'parentThumb')
else:
thumb = self.get_xml_attr(a, 'thumb')
recent_output = {'type': self.get_xml_attr(a, 'type'),
'rating_key': self.get_xml_attr(a, 'ratingKey'),
'title': self.get_xml_attr(a, 'title'),
'thumb': thumb,
'index': self.get_xml_attr(a, 'index'),
'parentIndex': self.get_xml_attr(a, 'parentIndex'),
'year': self.get_xml_attr(a, 'year'),
'time': row[0],
'user': row[1]
}
recently_watched.append(recent_output)
return recently_watched
def get_user_watch_time_stats(self, user=None):
myDB = db.DBConnection()
time_queries = [1, 7, 30, 0]
user_watch_time_stats = []
for days in time_queries:
if days > 0:
query = 'SELECT (SUM(stopped - time) - ' \
'SUM(CASE WHEN paused_counter is null THEN 0 ELSE paused_counter END)) as total_time, ' \
'COUNT(id) AS total_plays ' \
'FROM %s ' \
'WHERE datetime(stopped, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") ' \
'AND user = ?' % (self.get_history_table_name(), days)
result = myDB.select(query, args=[user])
else:
query = 'SELECT (SUM(stopped - time) - ' \
'SUM(CASE WHEN paused_counter is null THEN 0 ELSE paused_counter END)) as total_time, ' \
'COUNT(id) AS total_plays ' \
'FROM %s ' \
'WHERE user = ?' % self.get_history_table_name()
result = myDB.select(query, args=[user])
for item in result:
if item[0]:
total_time = item[0]
total_plays = item[1]
else:
total_time = 0
total_plays = 0
row = {'query_days': days,
'total_time': total_time,
'total_plays': total_plays
}
user_watch_time_stats.append(row)
return user_watch_time_stats
def get_user_platform_stats(self, user=None):
myDB = db.DBConnection()
platform_stats = []
result_id = 0
try:
query = 'SELECT platform, COUNT(platform) as platform_count, xml ' \
'FROM grouped ' \
'WHERE user = ? ' \
'GROUP BY platform ' \
'ORDER BY platform_count DESC'
result = myDB.select(query, args=[user])
except:
logger.warn("Unable to open PlexWatch database.")
return None
for item in result:
xml_data = helpers.latinToAscii(item[2])
try:
xml_parse = minidom.parseString(xml_data)
except:
logger.warn("Error parsing XML for Plex stream data.")
return None
xml_head = xml_parse.getElementsByTagName('Player')
if not xml_head:
logger.warn("Error parsing XML for Plex stream data.")
return None
for a in xml_head:
platform_type = self.get_xml_attr(a, 'platform')
row = {'platform_name': item[0],
'platform_type': platform_type,
'total_plays': item[1],
'result_id': result_id
}
platform_stats.append(row)
result_id += 1
return platform_stats
def get_user_gravatar_image(self, user=None):
myDB = db.DBConnection()
user_info = None
try:
query = 'SELECT xml ' \
'FROM %s ' \
'WHERE user = ? ' \
'ORDER BY id DESC LIMIT 1' % self.get_history_table_name()
result = myDB.select_single(query, args=[user])
except:
logger.warn("Unable to open PlexWatch database.")
return None
xml_data = helpers.latinToAscii(result)
try:
xml_parse = minidom.parseString(xml_data)
except:
logger.warn("Error parsing XML for Plexwatch Database.")
return None
xml_head = xml_parse.getElementsByTagName('User')
if not xml_head:
logger.warn("Error parsing XML for Plexwatch Database.")
return None
for a in xml_head:
user_id = self.get_xml_attr(a, 'id')
user_thumb = self.get_xml_attr(a, 'thumb')
user_info = {'user_id': user_id,
'user_thumb': user_thumb}
return user_info
def get_home_stats(self, time_range='30'):
myDB = db.DBConnection()
if not time_range.isdigit():
time_range = '30'
stats_queries = ["top_tv", "popular_tv", "top_users", "top_platforms"]
home_stats = []
for stat in stats_queries:
if 'top_tv' in stat:
top_tv = []
try:
query = 'SELECT orig_title, COUNT(orig_title) as total_plays, ' \
'grandparentRatingKey, MAX(time) as last_watch, xml ' \
'FROM %s ' \
'WHERE datetime(stopped, "unixepoch", "localtime") ' \
'>= datetime("now", "-%s days", "localtime") ' \
'AND episode != "" ' \
'GROUP BY orig_title ' \
'ORDER BY total_plays DESC LIMIT 10' % (self.get_history_table_name(), time_range)
result = myDB.select(query)
except:
logger.warn("Unable to open PlexWatch database.")
return None
for item in result:
xml_data = helpers.latinToAscii(item[4])
try:
xml_parse = minidom.parseString(xml_data)
except:
logger.warn("Error parsing XML for Plexwatch database.")
return None
xml_head = xml_parse.getElementsByTagName('opt')
if not xml_head:
logger.warn("Error parsing XML for Plexwatch database.")
return None
for a in xml_head:
grandparent_thumb = self.get_xml_attr(a, 'grandparentThumb')
row = {'title': item[0],
'total_plays': item[1],
'users_watched': '',
'rating_key': item[2],
'last_play': item[3],
'grandparent_thumb': grandparent_thumb,
'thumb': '',
'user': '',
'friendly_name': '',
'platform_type': '',
'platform': ''
}
top_tv.append(row)
home_stats.append({'stat_id': stat,
'rows': top_tv})
elif 'popular_tv' in stat:
popular_tv = []
try:
query = 'SELECT orig_title, COUNT(DISTINCT user) as users_watched, grandparentRatingKey, ' \
'MAX(time) as last_watch, xml, COUNT(id) as total_plays ' \
'FROM %s ' \
'WHERE datetime(stopped, "unixepoch", "localtime") ' \
'>= datetime("now", "-%s days", "localtime") ' \
'AND episode != "" ' \
'GROUP BY orig_title ' \
'ORDER BY users_watched DESC, total_plays DESC ' \
'LIMIT 10' % (self.get_history_table_name(), time_range)
result = myDB.select(query)
except:
logger.warn("Unable to open PlexWatch database.")
return None
for item in result:
xml_data = helpers.latinToAscii(item[4])
try:
xml_parse = minidom.parseString(xml_data)
except:
logger.warn("Error parsing XML for Plexwatch database.")
return None
xml_head = xml_parse.getElementsByTagName('opt')
if not xml_head:
logger.warn("Error parsing XML for Plexwatch database.")
return None
for a in xml_head:
grandparent_thumb = self.get_xml_attr(a, 'grandparentThumb')
row = {'title': item[0],
'users_watched': item[1],
'rating_key': item[2],
'last_play': item[3],
'total_plays': item[5],
'grandparent_thumb': grandparent_thumb,
'thumb': '',
'user': '',
'friendly_name': '',
'platform_type': '',
'platform': ''
}
popular_tv.append(row)
home_stats.append({'stat_id': stat,
'rows': popular_tv})
elif 'top_users' in stat:
top_users = []
try:
s = self.get_history_table_name()
query = 'SELECT user, ' \
'(case when friendly_name is null then user else friendly_name end) as friendly_name,' \
'COUNT(' + s + '.id) as total_plays, MAX(time) as last_watch, thumb ' \
'FROM ' + s + ' ' \
'LEFT OUTER JOIN plexpy_users ON ' + s + '.user = plexpy_users.username ' \
'WHERE datetime(stopped, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime") '\
'GROUP BY ' + s + '.user ' \
'ORDER BY total_plays DESC LIMIT 10'
result = myDB.select(query)
except:
logger.warn("Unable to open PlexWatch database.")
return None
for item in result:
if not item['thumb'] or item['thumb'] == '':
user_thumb = common.DEFAULT_USER_THUMB
else:
user_thumb = item[4]
thumb = self.get_user_gravatar_image(item[0])
row = {'user': item[0],
'friendly_name': item[1],
'total_plays': item[2],
'last_play': item[3],
'thumb': user_thumb,
'grandparent_thumb': '',
'users_watched': '',
'rating_key': '',
'title': '',
'platform_type': '',
'platform': ''
}
top_users.append(row)
home_stats.append({'stat_id': stat,
'rows': top_users})
elif 'top_platforms' in stat:
top_platform = []
try:
query = 'SELECT platform, COUNT(id) as total_plays, MAX(time) as last_watch, xml ' \
'FROM %s ' \
'WHERE datetime(stopped, "unixepoch", "localtime") ' \
'>= datetime("now", "-%s days", "localtime") ' \
'GROUP BY platform ' \
'ORDER BY total_plays DESC' % (self.get_history_table_name(), time_range)
result = myDB.select(query)
except:
logger.warn("Unable to open PlexWatch database.")
return None
for item in result:
xml_data = helpers.latinToAscii(item[3])
try:
xml_parse = minidom.parseString(xml_data)
except:
logger.warn("Error parsing XML for Plexwatch database.")
return None
xml_head = xml_parse.getElementsByTagName('Player')
if not xml_head:
logger.warn("Error parsing XML for Plexwatch database.")
return None
for a in xml_head:
platform_type = self.get_xml_attr(a, 'platform')
row = {'platform': item[0],
'total_plays': item[1],
'last_play': item[2],
'platform_type': platform_type,
'title': '',
'thumb': '',
'grandparent_thumb': '',
'users_watched': '',
'rating_key': '',
'user': '',
'friendly_name': ''
}
top_platform.append(row)
top_platform_aggr = self.group_and_sum_dataset(
top_platform, 'platform_type', ['total_plays'], 'total_plays')
home_stats.append({'stat_id': stat,
'rows': top_platform_aggr})
return home_stats
def get_total_plays_per_day(self, time_range='30'):
myDB = db.DBConnection()
if not time_range.isdigit():
time_range = '30'
try:
query = 'SELECT date(time, "unixepoch", "localtime") as date_played, ' \
'SUM(case when episode = "" then 0 else 1 end) as tv_count, ' \
'SUM(case when episode = "" then 1 else 0 end) as movie_count ' \
'FROM %s ' \
'WHERE datetime(stopped, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") ' \
'GROUP BY date_played ' \
'ORDER BY time ASC' % (self.get_history_table_name(), time_range)
result = myDB.select(query)
except:
logger.warn("Unable to open PlexWatch database.")
return None
# create our date range as some days may not have any data
# but we still want to display them
base = datetime.date.today()
date_list = [base - datetime.timedelta(days=x) for x in range(0, int(time_range))]
categories = []
series_1 = []
series_2 = []
for date_item in sorted(date_list):
date_string = date_item.strftime('%Y-%m-%d')
categories.append(date_string)
series_1_value = 0
series_2_value = 0
for item in result:
if date_string == item[0]:
series_1_value = item[1]
series_2_value = item[2]
break
else:
series_1_value = 0
series_2_value = 0
series_1.append(series_1_value)
series_2.append(series_2_value)
series_1_output = {'name': 'TV',
'data': series_1}
series_2_output = {'name': 'Movies',
'data': series_2}
output = {'categories': categories,
'series': [series_1_output, series_2_output]}
return output
def get_total_plays_per_dayofweek(self, time_range='30'):
myDB = db.DBConnection()
if not time_range.isdigit():
time_range = '30'
query = 'SELECT strftime("%w", datetime(time, "unixepoch", "localtime")) as daynumber, ' \
'case cast (strftime("%w", datetime(time, "unixepoch", "localtime")) as integer) ' \
'when 0 then "Sunday" ' \
'when 1 then "Monday" ' \
'when 2 then "Tuesday" ' \
'when 3 then "Wednesday" ' \
'when 4 then "Thursday" ' \
'when 5 then "Friday" ' \
'else "Saturday" end as dayofweek, ' \
'COUNT(id) as total_plays ' \
'from ' + self.get_history_table_name() + ' ' + \
'WHERE datetime(stopped, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime") ' \
'GROUP BY dayofweek ' \
'ORDER BY daynumber'
result = myDB.select(query)
days_list = ['Sunday', 'Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday', 'Saturday']
categories = []
series_1 = []
for day_item in days_list:
categories.append(day_item)
series_1_value = 0
for item in result:
if day_item == item[1]:
series_1_value = item[2]
break
else:
series_1_value = 0
series_1.append(series_1_value)
series_1_output = {'name': 'Total plays',
'data': series_1}
output = {'categories': categories,
'series': [series_1_output]}
return output
def get_total_plays_per_hourofday(self, time_range='30'):
myDB = db.DBConnection()
if not time_range.isdigit():
time_range = '30'
query = 'select strftime("%H", datetime(time, "unixepoch", "localtime")) as hourofday, ' \
'COUNT(id) ' \
'FROM ' + self.get_history_table_name() + ' ' + \
'WHERE datetime(stopped, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime") ' \
'GROUP BY hourofday ' \
'ORDER BY hourofday'
result = myDB.select(query)
hours_list = ['00','01','02','03','04','05',
'06','07','08','09','10','11',
'12','13','14','15','16','17',
'18','19','20','21','22','23']
categories = []
series_1 = []
for hour_item in hours_list:
categories.append(hour_item)
series_1_value = 0
for item in result:
if hour_item == item[0]:
series_1_value = item[1]
break
else:
series_1_value = 0
series_1.append(series_1_value)
series_1_output = {'name': 'Total plays',
'data': series_1}
output = {'categories': categories,
'series': [series_1_output]}
return output
def set_user_friendly_name(self, user=None, friendly_name=None):
if user:
if friendly_name.strip() == '':
friendly_name = None
myDB = db.DBConnection()
control_value_dict = {"username": user}
new_value_dict = {"friendly_name": friendly_name}
myDB.upsert('plexpy_users', new_value_dict, control_value_dict)
def get_user_friendly_name(self, user=None):
if user:
try:
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
return None
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 = ? ' \
'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'
result = myDB.select(query, args=[user_id])
if result:
for item in result:
if not item['friendly_name']:
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": user_thumb,
"is_home_user": item['is_home_user'],
"is_allow_sync": item['is_allow_sync'],
"is_restricted": item['is_restricted']
}
return user_details
else:
return None
except:
return None
return None
# Taken from:
# https://stackoverflow.com/questions/18066269/group-by-and-aggregate-the-values-of-a-list-of-dictionaries-in-python
@staticmethod
def group_and_sum_dataset(dataset, group_by_key, sum_value_keys, sort_by_key):
container = defaultdict(Counter)
for item in dataset:
key = item[group_by_key]
values = dict((k, item[k]) for k in sum_value_keys)
container[key].update(values)
new_dataset = [
dict([(group_by_key, item[0])] + item[1].items())
for item in container.items()
]
new_dataset.sort(key=lambda item: item[sort_by_key], reverse=True)
return new_dataset
def check_db_tables():
try:
myDB = db.DBConnection()
query = '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)'
result = myDB.action(query)
except:
logger.debug(u"Unable to create users table.")