From 8231521673c0bf3327137fb906e1e924f1bc2fdf Mon Sep 17 00:00:00 2001
From: blacktwin
Date: Wed, 13 Sep 2017 13:27:50 -0400
Subject: [PATCH] Create weekly_stats_reporting.py
---
notify/weekly_stats_reporting.py | 293 +++++++++++++++++++++++++++++++
1 file changed, 293 insertions(+)
create mode 100644 notify/weekly_stats_reporting.py
diff --git a/notify/weekly_stats_reporting.py b/notify/weekly_stats_reporting.py
new file mode 100644
index 0000000..24293b2
--- /dev/null
+++ b/notify/weekly_stats_reporting.py
@@ -0,0 +1,293 @@
+"""
+Pull library and user statistics of last week.
+
+Library stats can display total items in Shows, Seasons, Episodes, Artists, Albums, Tracks, and Movies
+
+User stats display username and hour, minutes, and seconds of view time
+
+PlexPy Settings > Extra Settings > Check - Calculate Total File Sizes [experimental] ...... wait
+
+"""
+
+import requests
+import sys
+import time
+import datetime
+import json
+from operator import itemgetter
+
+TODAY = int(time.time())
+LASTWEEK = int(TODAY - 7 * 24 * 60 * 60)
+START_DATE = (datetime.datetime.utcfromtimestamp(LASTWEEK).strftime("%Y-%m-%d")) # LASTWEEK as YYYY-MM-DD
+END_DATE = (datetime.datetime.utcfromtimestamp(TODAY).strftime("%Y-%m-%d")) # TODAY as YYYY-MM-DD
+
+# EDIT THESE SETTINGS #
+PLEXPY_APIKEY = 'xxxxxxx' # Your PlexPy API key
+PLEXPY_URL = 'http://localhost:8181/' # Your PlexPy URL
+SUBJECT_TEXT = "PlexPy Weekly Server, Library, and User Statistics"
+
+# Notification agent ID: https://github.com/JonnyWong16/plexpy/blob/master/API.md#notify
+AGENT_ID = 10 # The email notification agent ID for PlexPy
+
+# Remove library element you do not want shown. Logging before exclusion.
+# SHOW_STAT = 'Shows: {0}, Episodes: {2}'
+# SHOW_STAT = 'Episodes: {2}'
+# SHOW_STAT = ''
+SHOW_STAT = 'Shows: {0}, Seasons: {1}, Episodes: {2}'
+ARTIST_STAT = 'Artists: {0}, Albums: {1}, Songs: {2}'
+PHOTO_STAT = 'Folders: {0}, Subfolders: {1}, Photos: {2}'
+MOVIE_STAT = 'Movies: {0}'
+
+# Library names you do not want shown. Logging before exclusion.
+LIB_IGNORE = ['XXX']
+
+# Customize user stats display
+# User: USER1 -> 1 hr 32 min 00 sec
+USER_STAT = 'User: {0} -> {1}'
+
+# Usernames you do not want shown. Logging before exclusion.
+USER_IGNORE = ['User1']
+
+# Customize time display
+# {0:d} hr {1:02d} min {2:02d} sec --> 1 hr 32 min 00 sec
+# {0:d} hr {1:02d} min --> 1 hr 32 min
+# {0:02d} hr {1:02d} min --> 01 hr 32 min
+TIME_DISPLAY = "{0:d} hr {1:02d} min {2:02d} sec"
+
+# Customize BODY to your liking
+BODY_TEXT = """\
+
+
+
+ Hi!
+
Below are the server stats for the week of ({start} - {end})
+
+
Below are the user stats for the week of ({start} - {end})
+
+ {user_stats}
+
+
+
+
+"""
+
+# /EDIT THESE SETTINGS #
+
+def get_get_history(user_id):
+ # Get the PlexPy history.
+ payload = {'apikey': PLEXPY_APIKEY,
+ 'cmd': 'get_history',
+ 'user_id': user_id,
+ 'start_date': START_DATE}
+
+ try:
+ r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
+ response = r.json()
+ # print(json.dumps(response['response']['data'], indent=4, sort_keys=True))
+ res_data = response['response']['data']
+ return res_data
+
+ except Exception as e:
+ sys.stderr.write("PlexPy API 'get_history' request failed: {0}.".format(e))
+
+
+def get_get_user_names():
+ # Get a list of all user and user ids.
+ payload = {'apikey': PLEXPY_APIKEY,
+ 'cmd': 'get_user_names'}
+
+ try:
+ r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
+ response = r.json()
+ # print(json.dumps(response['response']['data'], indent=4, sort_keys=True))
+ res_data = response['response']['data']
+ return [d for d in res_data if d['friendly_name'] != 'Local']
+
+ except Exception as e:
+ sys.stderr.write("PlexPy API 'get_user_names' request failed: {0}.".format(e))
+
+
+def get_get_libraries():
+ # Get a list of all libraries on your server.
+ payload = {'apikey': PLEXPY_APIKEY,
+ 'cmd': 'get_libraries'}
+
+ try:
+ r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
+ response = r.json()
+ # print(json.dumps(response['response']['data'], indent=4, sort_keys=True))
+ res_data = response['response']['data']
+ return res_data
+
+ except Exception as e:
+ sys.stderr.write("PlexPy API 'get_libraries' request failed: {0}.".format(e))
+
+
+def get_get_library_media_info(section_id):
+ # Get a list of all libraries on your server.
+ payload = {'apikey': PLEXPY_APIKEY,
+ 'cmd': 'get_library_media_info',
+ 'section_id': section_id,
+ 'refresh': True}
+
+ try:
+ r = requests.get(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
+ response = r.json()
+ # print(json.dumps(response['response']['data'], indent=4, sort_keys=True))
+ res_data = response['response']['data']
+ return res_data['total_file_size']
+
+ except Exception as e:
+ sys.stderr.write("PlexPy API 'get_library_media_info' request failed: {0}.".format(e))
+
+
+def send_notification(body_text):
+ # Format notification text
+ try:
+ subject = SUBJECT_TEXT
+ body = body_text
+ except LookupError as e:
+ sys.stderr.write("Unable to substitute '{0}' in the notification subject or body".format(e))
+ return None
+ # Send the notification through PlexPy
+ payload = {'apikey': PLEXPY_APIKEY,
+ 'cmd': 'notify',
+ 'agent_id': AGENT_ID,
+ 'subject': subject,
+ 'body': body}
+
+ try:
+ r = requests.post(PLEXPY_URL.rstrip('/') + '/api/v2', params=payload)
+ response = r.json()
+
+ if response['response']['result'] == 'success':
+ sys.stdout.write("Successfully sent PlexPy notification.")
+ else:
+ raise Exception(response['response']['message'])
+ except Exception as e:
+ sys.stderr.write("PlexPy API 'notify' request failed: {0}.".format(e))
+ return None
+
+
+def add_to_dictlist(d, key, val):
+ if key not in d:
+ d[key] = [val]
+ else:
+ d[key].append(val)
+
+
+def sizeof_fmt(num, suffix='B'):
+ # Function found https://stackoverflow.com/a/1094933
+ for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']:
+ if abs(num) < 1024.0:
+ return "%3.1f%s%s" % (num, unit, suffix)
+ num /= 1024.0
+ return "%.1f%s%s" % (num, 'Yi', suffix)
+
+
+def get_user_stats(user_stats_lst, stat_logging, user_stats):
+ # Pull User stats and
+ user_duration = []
+
+ for users in get_get_user_names():
+ history = get_get_history(users['user_id'])
+ if history['filter_duration'] != '0':
+ user_name = users['friendly_name']
+ user_totals = sum([d['duration'] for d in history['data']])
+ user_duration.append([user_name, user_totals])
+ add_to_dictlist(stat_logging['data'], 'data', {'user': user_name, 'duration': user_totals})
+
+ user_duration = sorted(user_duration, key=itemgetter(1), reverse=True)
+
+ for user_stat in user_duration:
+ if user_stat[0] not in USER_IGNORE:
+ m, s = divmod(user_stat[1], 60)
+ h, m = divmod(m, 60)
+ easy_time = TIME_DISPLAY.format(h, m, s)
+ USER_STAT = user_stats.format(user_stat[0], easy_time)
+ # Html formating
+ user_stats_lst += ['{}'.format(USER_STAT)]
+ else:
+ pass
+
+ # print(user_stats)
+ return user_stats
+
+
+def get_sections_stats(sections_stats_lst, stat_logging):
+ section_count = ''
+ total_size = 0
+
+ for sections in get_get_libraries():
+
+ lib_size = get_get_library_media_info(sections['section_id'])
+ total_size += lib_size
+
+ if sections['section_type'] in ['artist', 'show', 'photo']:
+
+ stat_dict = {'section_type': sections['section_type'],
+ 'count': sections['count'],
+ 'parent_count': sections['parent_count'],
+ 'child_count': sections['child_count'],
+ 'size': lib_size,
+ 'friendly_size': sizeof_fmt(lib_size)}
+
+ add_to_dictlist(stat_logging['data'], sections['section_name'], stat_dict)
+
+ if sections['section_type'] == 'artist':
+ section_count = ARTIST_STAT.format(sections['count'], sections['parent_count'], sections['child_count'])
+
+ elif sections['section_type'] == 'show':
+ section_count = SHOW_STAT.format(sections['count'], sections['parent_count'], sections['child_count'])
+
+ elif sections['section_type'] == 'photo':
+ section_count = PHOTO_STAT.format(sections['count'], sections['parent_count'], sections['child_count'])
+
+ elif sections['section_type'] == 'movie':
+ section_count = MOVIE_STAT.format(sections['count'])
+
+ stat_dict = {'section_type': sections['section_type'],
+ 'count': sections['count'],
+ 'size': lib_size,
+ 'friendly_size': sizeof_fmt(lib_size)}
+
+ add_to_dictlist(stat_logging['data'], sections['section_name'], stat_dict)
+
+ else:
+ pass
+
+ if sections['section_name'] not in LIB_IGNORE and section_count:
+ # Html formating
+ sections_stats_lst += ['{}: {}'.format(sections['section_name'], section_count)]
+
+
+ stat_logging['total_size'] = total_size
+ stat_logging['total_size_friendly'] = sizeof_fmt(total_size)
+
+ # Html formating. Adding the Capacity to button of list.
+ sections_stats_lst += ['Capacity: {}'.format(sizeof_fmt(total_size))]
+ # print(sections_stats)
+ return sections_stats_lst
+
+
+user_stats_lst = []
+sections_stats_lst = []
+
+stat_logging = {'start_date': START_DATE, 'end_date': END_DATE, 'data': {}}
+
+users_stats = get_user_stats(user_stats_lst, stat_logging, USER_STAT)
+lib_stats = get_sections_stats(sections_stats_lst, stat_logging)
+
+# print(json.dumps(stat_logging, indent=4, sort_keys=True))
+
+end = time.ctime(float(TODAY))
+start = time.ctime(float(LASTWEEK))
+
+sections_stats = "\n".join(sections_stats_lst)
+user_stats = "\n".join(user_stats_lst)
+
+BODY_TEXT = BODY_TEXT.format(end=end, start=start, sections_stats=sections_stats, user_stats=user_stats)
+
+send_notification(BODY_TEXT)