mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-13 08:42:59 -07:00
commit
be4e8985b7
3 changed files with 471 additions and 142 deletions
57
API.md
57
API.md
|
@ -4,24 +4,77 @@ The API is still pretty new and needs some serious cleaning up on the backend bu
|
||||||
## General structure
|
## General structure
|
||||||
The API endpoint is `http://ip:port + HTTP_ROOT + /api?apikey=$apikey&cmd=$command`
|
The API endpoint is `http://ip:port + HTTP_ROOT + /api?apikey=$apikey&cmd=$command`
|
||||||
|
|
||||||
Data response in JSON formatted.
|
Response example
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"response": {
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"loglevel": "INFO",
|
||||||
|
"msg": "Signal 2 caught, saving and exiting...",
|
||||||
|
"thread": "MainThread",
|
||||||
|
"time": "22-sep-2015 01:42:56 "
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"message": null,
|
||||||
|
"result": "success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
General parameters:
|
||||||
|
out_type: 'xml',
|
||||||
|
callback: 'pong',
|
||||||
|
'debug': 1
|
||||||
|
|
||||||
|
|
||||||
## API methods
|
## API methods
|
||||||
|
|
||||||
### getLogs
|
### getLogs
|
||||||
Not working yet
|
Possible params: sort='', search='', order='desc', regex='', start=0, end=0
|
||||||
|
Returns the plexpy log
|
||||||
|
|
||||||
|
### getApikey
|
||||||
|
Possible params: username='', password='' (required if auth is enabled)
|
||||||
|
Returns the apikey
|
||||||
|
|
||||||
|
### getSettings
|
||||||
|
No params
|
||||||
|
Returns the config file
|
||||||
|
|
||||||
### getVersion
|
### getVersion
|
||||||
|
No params
|
||||||
Returns some version information: git_path, install_type, current_version, installed_version, commits_behind
|
Returns some version information: git_path, install_type, current_version, installed_version, commits_behind
|
||||||
|
|
||||||
|
### getHistory
|
||||||
|
possible params: user=None, user_id=None, ,rating_key='', parent_rating_key='', grandparent_rating_key='', start_date=''
|
||||||
|
Returns
|
||||||
|
|
||||||
|
### getMetadata
|
||||||
|
Required params: rating_key
|
||||||
|
Returns metadata about a file
|
||||||
|
|
||||||
|
### getSync
|
||||||
|
Possible params: machine_id=None, user_id=None,
|
||||||
|
Returns
|
||||||
|
|
||||||
|
### getUserips
|
||||||
|
Possible params: user_id=None, user=None
|
||||||
|
|
||||||
|
### getPlayby
|
||||||
|
Possible params: time_range=30, y_axis='plays', playtype='total_plays_per_month'
|
||||||
|
|
||||||
### checkGithub
|
### checkGithub
|
||||||
Updates the version information above and returns getVersion data
|
Updates the version information above and returns getVersion data
|
||||||
|
|
||||||
### shutdown
|
### shutdown
|
||||||
|
No params
|
||||||
Shut down plexpy
|
Shut down plexpy
|
||||||
|
|
||||||
### restart
|
### restart
|
||||||
|
No params
|
||||||
Restart plexpy
|
Restart plexpy
|
||||||
|
|
||||||
### update
|
### update
|
||||||
|
No params
|
||||||
Update plexpy - you may want to check the install type in get version and not allow this if type==exe
|
Update plexpy - you may want to check the install type in get version and not allow this if type==exe
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# This file is part of PlexPy.
|
# This file is part of PlexPy.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# PlexPy is free software: you can redistribute it and/or modify
|
||||||
|
|
554
plexpy/api.py
554
plexpy/api.py
|
@ -1,3 +1,6 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# This file is part of PlexPy.
|
# This file is part of PlexPy.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# PlexPy is free software: you can redistribute it and/or modify
|
||||||
|
@ -13,86 +16,143 @@
|
||||||
# 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 db, cache, versioncheck, logger, helpers
|
from plexpy import versioncheck, logger, plextv, pmsconnect, datafactory, graphs, users
|
||||||
|
import os
|
||||||
import plexpy
|
import plexpy
|
||||||
import json
|
import json
|
||||||
from xml.dom import minidom
|
import traceback
|
||||||
|
import cherrypy
|
||||||
|
import re
|
||||||
|
import hashlib
|
||||||
|
import random
|
||||||
|
import xmltodict
|
||||||
|
|
||||||
cmd_list = ['getHistory', 'getLogs', 'getVersion', 'checkGithub', 'shutdown', 'restart', 'update']
|
cmd_list = ['getLogs', 'getVersion', 'checkGithub', 'shutdown',
|
||||||
|
'getSettings', 'restart', 'update', 'getApikey', 'getHistory',
|
||||||
|
'getMetadata', 'getUserips', 'getPlayby', 'getSync']
|
||||||
|
|
||||||
|
|
||||||
class Api(object):
|
class Api(object):
|
||||||
|
def __init__(self, out='json'):
|
||||||
def __init__(self):
|
|
||||||
|
|
||||||
self.apikey = None
|
self.apikey = None
|
||||||
|
self.authenticated = False
|
||||||
self.cmd = None
|
self.cmd = None
|
||||||
self.id = None
|
|
||||||
|
|
||||||
self.kwargs = None
|
self.kwargs = None
|
||||||
|
# For the responses
|
||||||
self.data = None
|
self.data = None
|
||||||
|
self.msg = None
|
||||||
|
self.result_type = 'error'
|
||||||
|
# Possible general params
|
||||||
self.callback = None
|
self.callback = None
|
||||||
|
self.out_type = out
|
||||||
|
self.debug = None
|
||||||
|
|
||||||
def checkParams(self, *args, **kwargs):
|
def checkParams(self, *args, **kwargs):
|
||||||
|
|
||||||
if not plexpy.CONFIG.API_ENABLED:
|
if not plexpy.CONFIG.API_ENABLED:
|
||||||
self.data = 'API not enabled'
|
self.msg = 'API not enabled'
|
||||||
return
|
elif not plexpy.CONFIG.API_KEY:
|
||||||
if not plexpy.CONFIG.API_KEY:
|
self.msg = 'API key not generated'
|
||||||
self.data = 'API key not generated'
|
elif len(plexpy.CONFIG.API_KEY) != 32:
|
||||||
return
|
self.msg = 'API key not generated correctly'
|
||||||
if len(plexpy.CONFIG.API_KEY) != 32:
|
elif 'apikey' not in kwargs:
|
||||||
self.data = 'API key not generated correctly'
|
self.msg = 'Parameter apikey is required'
|
||||||
return
|
elif kwargs.get('apikey', '') != plexpy.CONFIG.API_KEY:
|
||||||
|
self.msg = 'Invalid apikey'
|
||||||
|
elif 'cmd' not in kwargs:
|
||||||
|
self.msg = 'Parameter %s required. possible commands are: %s' % ', '.join(cmd_list)
|
||||||
|
elif 'cmd' in kwargs and kwargs.get('cmd') not in cmd_list:
|
||||||
|
self.msg = 'Unknown command, %s possible commands are: %s' % (kwargs.get('cmd', ''), ', '.join(cmd_list))
|
||||||
|
|
||||||
if 'apikey' not in kwargs:
|
# Set default values or remove them from kwargs
|
||||||
self.data = 'Missing api key'
|
|
||||||
return
|
|
||||||
|
|
||||||
if kwargs['apikey'] != plexpy.CONFIG.API_KEY:
|
self.callback = kwargs.pop('callback', None)
|
||||||
self.data = 'Incorrect API key'
|
self.apikey = kwargs.pop('apikey', None)
|
||||||
return
|
self.cmd = kwargs.pop('cmd', None)
|
||||||
else:
|
self.debug = kwargs.pop('debug', False)
|
||||||
self.apikey = kwargs.pop('apikey')
|
# Allow override for the api.
|
||||||
|
self.out_type = kwargs.pop('out_type', 'json')
|
||||||
|
|
||||||
if 'cmd' not in kwargs:
|
if self.apikey == plexpy.CONFIG.API_KEY and plexpy.CONFIG.API_ENABLED and self.cmd in cmd_list:
|
||||||
self.data = 'Missing parameter: cmd'
|
self.authenticated = True
|
||||||
return
|
self.msg = None
|
||||||
|
elif self.cmd == 'getApikey' and plexpy.CONFIG.API_ENABLED:
|
||||||
if kwargs['cmd'] not in cmd_list:
|
self.authenticated = True
|
||||||
self.data = 'Unknown command: %s' % kwargs['cmd']
|
# Remove the old error msg
|
||||||
return
|
self.msg = None
|
||||||
else:
|
|
||||||
self.cmd = kwargs.pop('cmd')
|
|
||||||
|
|
||||||
self.kwargs = kwargs
|
self.kwargs = kwargs
|
||||||
self.data = 'OK'
|
|
||||||
|
def _responds(self, result_type='success', data=None, msg=''):
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
data = {}
|
||||||
|
return {"response": {"result": result_type, "message": msg, "data": data}}
|
||||||
|
|
||||||
|
def _out_as(self, out):
|
||||||
|
|
||||||
|
if self.out_type == 'json':
|
||||||
|
cherrypy.response.headers['Content-Type'] = 'application/json;charset=UTF-8'
|
||||||
|
try:
|
||||||
|
out = json.dumps(out, indent=4, sort_keys=True)
|
||||||
|
if self.callback is not None:
|
||||||
|
cherrypy.response.headers['Content-Type'] = 'application/javascript'
|
||||||
|
# wrap with JSONP call if requested
|
||||||
|
out = self.callback + '(' + out + ');'
|
||||||
|
# if we fail to generate the output fake an error
|
||||||
|
except Exception as e:
|
||||||
|
logger.info(u"API :: " + traceback.format_exc())
|
||||||
|
out['message'] = traceback.format_exc()
|
||||||
|
out['result'] = 'error'
|
||||||
|
if self.out_type == 'xml':
|
||||||
|
cherrypy.response.headers['Content-Type'] = 'application/xml'
|
||||||
|
try:
|
||||||
|
out = xmltodict.unparse(out, pretty=True)
|
||||||
|
except ValueError as e:
|
||||||
|
logger.error('Failed to parse xml result')
|
||||||
|
try:
|
||||||
|
out['message'] = e
|
||||||
|
out['result'] = 'error'
|
||||||
|
out = xmltodict.unparse(out, pretty=True)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error('Failed to parse xml result error message')
|
||||||
|
out = '''<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<response>
|
||||||
|
<message>%s</message>
|
||||||
|
<data></data>
|
||||||
|
<result>error</result>
|
||||||
|
</response>
|
||||||
|
''' % e
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
||||||
def fetchData(self):
|
def fetchData(self):
|
||||||
|
|
||||||
if self.data == 'OK':
|
logger.info('Recieved API command: %s' % self.cmd)
|
||||||
logger.info('Recieved API command: %s', self.cmd)
|
if self.cmd and self.authenticated:
|
||||||
methodToCall = getattr(self, "_" + self.cmd)
|
methodtocall = getattr(self, "_" + self.cmd)
|
||||||
methodToCall(**self.kwargs)
|
# Let the traceback hit cherrypy so we can
|
||||||
if 'callback' not in self.kwargs:
|
# see the traceback there
|
||||||
if isinstance(self.data, basestring):
|
if self.debug:
|
||||||
return self.data
|
methodtocall(**self.kwargs)
|
||||||
else:
|
|
||||||
return json.dumps(self.data)
|
|
||||||
else:
|
else:
|
||||||
self.callback = self.kwargs['callback']
|
try:
|
||||||
self.data = json.dumps(self.data)
|
methodtocall(**self.kwargs)
|
||||||
self.data = self.callback + '(' + self.data + ');'
|
except Exception as e:
|
||||||
return self.data
|
logger.error(traceback.format_exc())
|
||||||
else:
|
|
||||||
return self.data
|
# Im just lazy, fix me plx
|
||||||
|
if self.data or isinstance(self.data, (dict, list)):
|
||||||
|
if len(self.data):
|
||||||
|
self.result_type = 'success'
|
||||||
|
|
||||||
|
return self._out_as(self._responds(result_type=self.result_type, msg=self.msg, data=self.data))
|
||||||
|
|
||||||
def _dic_from_query(self, query):
|
def _dic_from_query(self, query):
|
||||||
|
|
||||||
myDB = db.DBConnection()
|
myDB = database.DBConnection()
|
||||||
rows = myDB.select(query)
|
rows = myDB.select(query)
|
||||||
|
|
||||||
rows_as_dic = []
|
rows_as_dic = []
|
||||||
|
@ -103,104 +163,115 @@ class Api(object):
|
||||||
|
|
||||||
return rows_as_dic
|
return rows_as_dic
|
||||||
|
|
||||||
def _getHistory(self, iDisplayStart=0, iDisplayLength=100, sSearch="", iSortCol_0='0', sSortDir_0='asc', **kwargs):
|
def _getApikey(self, username='', password=''):
|
||||||
iDisplayStart = int(iDisplayStart)
|
""" Returns api key, requires username and password is active """
|
||||||
iDisplayLength = int(iDisplayLength)
|
|
||||||
filtered = []
|
|
||||||
totalcount = 0
|
|
||||||
myDB = db.DBConnection()
|
|
||||||
db_table = db.DBConnection().get_history_table_name()
|
|
||||||
|
|
||||||
sortcolumn = 'time'
|
apikey = hashlib.sha224(str(random.getrandbits(256))).hexdigest()[0:32]
|
||||||
sortbyhavepercent = False
|
if plexpy.CONFIG.HTTP_USERNAME and plexpy.CONFIG.HTTP_PASSWORD:
|
||||||
if iSortCol_0 == '1':
|
if username == plexpy.HTTP_USERNAME and password == plexpy.CONFIG.HTTP_PASSWORD:
|
||||||
sortcolumn = 'user'
|
if plexpy.CONFIG.API_KEY:
|
||||||
if iSortCol_0 == '2':
|
self.data = plexpy.CONFIG.API_KEY
|
||||||
sortcolumn = 'platform'
|
else:
|
||||||
elif iSortCol_0 == '3':
|
self.data = apikey
|
||||||
sortcolumn = 'ip_address'
|
plexpy.CONFIG.API_KEY = apikey
|
||||||
elif iSortCol_0 == '4':
|
plexpy.CONFIG.write()
|
||||||
sortcolumn = 'title'
|
|
||||||
elif iSortCol_0 == '5':
|
|
||||||
sortcolumn = 'time'
|
|
||||||
elif iSortCol_0 == '6':
|
|
||||||
sortcolumn = 'paused_counter'
|
|
||||||
elif iSortCol_0 == '7':
|
|
||||||
sortcolumn = 'stopped'
|
|
||||||
elif iSortCol_0 == '8':
|
|
||||||
sortbyhavepercent = True
|
|
||||||
|
|
||||||
if sSearch == "":
|
|
||||||
query = 'SELECT * from %s order by %s COLLATE NOCASE %s' % (db_table, sortcolumn, sSortDir_0)
|
|
||||||
filtered = myDB.select(query)
|
|
||||||
totalcount = len(filtered)
|
|
||||||
else:
|
|
||||||
query = 'SELECT * from ' + db_table + ' WHERE user LIKE "%' + sSearch + \
|
|
||||||
'%" OR title LIKE "%' + sSearch + '%"' + 'ORDER BY %s COLLATE NOCASE %s' % (sortcolumn, sSortDir_0)
|
|
||||||
filtered = myDB.select(query)
|
|
||||||
totalcount = myDB.select('SELECT COUNT(*) from processed')[0][0]
|
|
||||||
|
|
||||||
history = filtered[iDisplayStart:(iDisplayStart + iDisplayLength)]
|
|
||||||
rows = []
|
|
||||||
for item in history:
|
|
||||||
row = {"date": item['time'],
|
|
||||||
"user": item["user"],
|
|
||||||
"platform": item["platform"],
|
|
||||||
"ip_address": item["ip_address"],
|
|
||||||
"title": item["title"],
|
|
||||||
"started": item["time"],
|
|
||||||
"paused": item["paused_counter"],
|
|
||||||
"stopped": item["stopped"],
|
|
||||||
"duration": "",
|
|
||||||
"percent_complete": 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
if item['paused_counter'] > 0:
|
|
||||||
row['paused'] = item['paused_counter']
|
|
||||||
else:
|
else:
|
||||||
row['paused'] = 0
|
self.msg = 'Authentication is enabled, please add the correct username and password to the parameters'
|
||||||
|
else:
|
||||||
|
if plexpy.CONFIG.API_KEY:
|
||||||
|
self.data = plexpy.CONFIG.API_KEY
|
||||||
|
else:
|
||||||
|
# Make a apikey if the doesn't exist
|
||||||
|
self.data = apikey
|
||||||
|
plexpy.CONFIG.API_KEY = apikey
|
||||||
|
plexpy.CONFIG.write()
|
||||||
|
|
||||||
if item['time']:
|
return self.data
|
||||||
if item['stopped'] > 0:
|
|
||||||
stopped = item['stopped']
|
|
||||||
else:
|
|
||||||
stopped = 0
|
|
||||||
if item['paused_counter'] > 0:
|
|
||||||
paused_counter = item['paused_counter']
|
|
||||||
else:
|
|
||||||
paused_counter = 0
|
|
||||||
|
|
||||||
row['duration'] = stopped - item['time'] + paused_counter
|
def _getLogs(self, sort='', search='', order='desc', regex='', **kwargs):
|
||||||
|
"""
|
||||||
|
Returns the log
|
||||||
|
|
||||||
|
Returns [{"response":
|
||||||
|
{"msg": "Hey",
|
||||||
|
"result": "success"},
|
||||||
|
"data": [{"time": "29-sept.2015",
|
||||||
|
"thread: "MainThread",
|
||||||
|
"msg: "Called x from y",
|
||||||
|
"loglevel": "DEBUG"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
logfile = os.path.join(plexpy.CONFIG.LOG_DIR, 'plexpy.log')
|
||||||
|
templog = []
|
||||||
|
start = int(kwargs.get('start', 0))
|
||||||
|
end = int(kwargs.get('end', 0))
|
||||||
|
|
||||||
|
if regex:
|
||||||
|
logger.debug('Filtering log using regex %s' % regex)
|
||||||
|
reg = re.compile('u' + regex, flags=re.I)
|
||||||
|
|
||||||
|
for line in open(logfile, 'r').readlines():
|
||||||
|
temp_loglevel_and_time = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
xml_parse = minidom.parseString(helpers.latinToAscii(item['xml']))
|
temp_loglevel_and_time = line.split('- ')
|
||||||
except IOError, e:
|
loglvl = temp_loglevel_and_time[1].split(' :')[0].strip()
|
||||||
logger.warn("Error parsing XML in PlexWatch db: %s" % e)
|
tl_tread = line.split(' :: ')
|
||||||
|
if loglvl is None:
|
||||||
|
msg = line.replace('\n', '')
|
||||||
|
else:
|
||||||
|
msg = line.split(' : ')[1].replace('\n', '')
|
||||||
|
thread = tl_tread[1].split(' : ')[0]
|
||||||
|
except IndexError:
|
||||||
|
# We assume this is a traceback
|
||||||
|
tl = (len(templog) - 1)
|
||||||
|
templog[tl]['msg'] += line.replace('\n', '')
|
||||||
|
continue
|
||||||
|
|
||||||
xml_head = xml_parse.getElementsByTagName('opt')
|
if len(line) > 1 and temp_loglevel_and_time is not None and loglvl in line:
|
||||||
if not xml_head:
|
|
||||||
logger.warn("Error parsing XML in PlexWatch db: %s" % e)
|
|
||||||
|
|
||||||
for s in xml_head:
|
d = {
|
||||||
if s.getAttribute('duration') and s.getAttribute('viewOffset'):
|
'time': temp_loglevel_and_time[0],
|
||||||
view_offset = helpers.cast_to_float(s.getAttribute('viewOffset'))
|
'loglevel': loglvl,
|
||||||
duration = helpers.cast_to_float(s.getAttribute('duration'))
|
'msg': msg.replace('\n', ''),
|
||||||
if duration > 0:
|
'thread': thread
|
||||||
row['percent_complete'] = (view_offset / duration)*100
|
|
||||||
else:
|
|
||||||
row['percent_complete'] = 0
|
|
||||||
|
|
||||||
rows.append(row)
|
|
||||||
|
|
||||||
dict = {'iTotalDisplayRecords': len(filtered),
|
|
||||||
'iTotalRecords': totalcount,
|
|
||||||
'aaData': rows,
|
|
||||||
}
|
}
|
||||||
self.data = json.dumps(dict)
|
templog.append(d)
|
||||||
#cherrypy.response.headers['Content-type'] = 'application/json'
|
|
||||||
|
|
||||||
def _getLogs(self, **kwargs):
|
if end > 0:
|
||||||
pass
|
logger.debug('Slicing the log from %s to %s' % (start, end))
|
||||||
|
templog = templog[start:end]
|
||||||
|
|
||||||
|
if sort:
|
||||||
|
logger.debug('Sorting log based on %s' % sort)
|
||||||
|
templog = sorted(templog, key=lambda k: k[sort])
|
||||||
|
|
||||||
|
if search:
|
||||||
|
logger.debug('Searching log values for %s' % search)
|
||||||
|
tt = [d for d in templog for k, v in d.items() if search.lower() in v.lower()]
|
||||||
|
|
||||||
|
if len(tt):
|
||||||
|
templog = tt
|
||||||
|
|
||||||
|
if regex:
|
||||||
|
tt = []
|
||||||
|
for l in templog:
|
||||||
|
stringdict = ' '.join('{}{}'.format(k, v) for k, v in l.items())
|
||||||
|
if reg.search(stringdict):
|
||||||
|
tt.append(l)
|
||||||
|
|
||||||
|
if len(tt):
|
||||||
|
templog = tt
|
||||||
|
|
||||||
|
if order == 'desc':
|
||||||
|
templog = templog[::-1]
|
||||||
|
|
||||||
|
self.data = templog
|
||||||
|
return templog
|
||||||
|
|
||||||
def _getVersion(self, **kwargs):
|
def _getVersion(self, **kwargs):
|
||||||
self.data = {
|
self.data = {
|
||||||
|
@ -210,6 +281,7 @@ class Api(object):
|
||||||
'latest_version': plexpy.LATEST_VERSION,
|
'latest_version': plexpy.LATEST_VERSION,
|
||||||
'commits_behind': plexpy.COMMITS_BEHIND,
|
'commits_behind': plexpy.COMMITS_BEHIND,
|
||||||
}
|
}
|
||||||
|
self.result_type = 'success'
|
||||||
|
|
||||||
def _checkGithub(self, **kwargs):
|
def _checkGithub(self, **kwargs):
|
||||||
versioncheck.checkGithub()
|
versioncheck.checkGithub()
|
||||||
|
@ -217,9 +289,211 @@ class Api(object):
|
||||||
|
|
||||||
def _shutdown(self, **kwargs):
|
def _shutdown(self, **kwargs):
|
||||||
plexpy.SIGNAL = 'shutdown'
|
plexpy.SIGNAL = 'shutdown'
|
||||||
|
self.msg = 'Shutting down plexpy'
|
||||||
|
self.result_type = 'success'
|
||||||
|
|
||||||
def _restart(self, **kwargs):
|
def _restart(self, **kwargs):
|
||||||
plexpy.SIGNAL = 'restart'
|
plexpy.SIGNAL = 'restart'
|
||||||
|
self.msg = 'Restarting plexpy'
|
||||||
|
self.result_type = 'success'
|
||||||
|
|
||||||
def _update(self, **kwargs):
|
def _update(self, **kwargs):
|
||||||
plexpy.SIGNAL = 'update'
|
plexpy.SIGNAL = 'update'
|
||||||
|
self.msg = 'Updating plexpy'
|
||||||
|
self.result_type = 'success'
|
||||||
|
|
||||||
|
def _getHistory(self, user=None, user_id=None, rating_key='', parent_rating_key='', grandparent_rating_key='', start_date='', **kwargs):
|
||||||
|
|
||||||
|
custom_where = []
|
||||||
|
if user_id:
|
||||||
|
custom_where = [['user_id', user_id]]
|
||||||
|
elif user:
|
||||||
|
custom_where = [['user', user]]
|
||||||
|
if 'rating_key' in kwargs:
|
||||||
|
rating_key = kwargs.get('rating_key', "")
|
||||||
|
custom_where = [['rating_key', rating_key]]
|
||||||
|
if 'parent_rating_key' in kwargs:
|
||||||
|
rating_key = kwargs.get('parent_rating_key', "")
|
||||||
|
custom_where = [['parent_rating_key', rating_key]]
|
||||||
|
if 'grandparent_rating_key' in kwargs:
|
||||||
|
rating_key = kwargs.get('grandparent_rating_key', "")
|
||||||
|
custom_where = [['grandparent_rating_key', rating_key]]
|
||||||
|
if 'start_date' in kwargs:
|
||||||
|
start_date = kwargs.get('start_date', "")
|
||||||
|
custom_where = [['strftime("%Y-%m-%d", datetime(date, "unixepoch", "localtime"))', start_date]]
|
||||||
|
|
||||||
|
data_factory = datafactory.DataFactory()
|
||||||
|
history = data_factory.get_history(kwargs=kwargs, custom_where=custom_where)
|
||||||
|
|
||||||
|
self.data = history
|
||||||
|
return self.data
|
||||||
|
|
||||||
|
def _getSync(self, machine_id=None, user_id=None, **kwargs):
|
||||||
|
|
||||||
|
pms_connect = pmsconnect.PmsConnect()
|
||||||
|
server_id = pms_connect.get_server_identity()
|
||||||
|
|
||||||
|
plex_tv = plextv.PlexTV()
|
||||||
|
if not machine_id:
|
||||||
|
result = plex_tv.get_synced_items(machine_id=server_id['machine_identifier'], user_id=user_id)
|
||||||
|
else:
|
||||||
|
result = plex_tv.get_synced_items(machine_id=machine_id, user_id=user_id)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
self.data = result
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
self.msg = 'Unable to retrieve sync data for user'
|
||||||
|
logger.warn('Unable to retrieve sync data for user.')
|
||||||
|
|
||||||
|
def _getMetadata(self, rating_key='', **kwargs):
|
||||||
|
|
||||||
|
pms_connect = pmsconnect.PmsConnect()
|
||||||
|
result = pms_connect.get_metadata(rating_key, 'dict')
|
||||||
|
|
||||||
|
if result:
|
||||||
|
self.data = result
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
self.msg = 'Unable to retrive metadata %s' % rating_key
|
||||||
|
logger.warn('Unable to retrieve data.')
|
||||||
|
|
||||||
|
def _getSettings(self):
|
||||||
|
interface_dir = os.path.join(plexpy.PROG_DIR, 'data/interfaces/')
|
||||||
|
interface_list = [name for name in os.listdir(interface_dir) if
|
||||||
|
os.path.isdir(os.path.join(interface_dir, name))]
|
||||||
|
|
||||||
|
config = {
|
||||||
|
"http_host": plexpy.CONFIG.HTTP_HOST,
|
||||||
|
"http_username": plexpy.CONFIG.HTTP_USERNAME,
|
||||||
|
"http_port": plexpy.CONFIG.HTTP_PORT,
|
||||||
|
"http_password": plexpy.CONFIG.HTTP_PASSWORD,
|
||||||
|
"launch_browser": bool(plexpy.CONFIG.LAUNCH_BROWSER),
|
||||||
|
"enable_https": bool(plexpy.CONFIG.ENABLE_HTTPS),
|
||||||
|
"https_cert": plexpy.CONFIG.HTTPS_CERT,
|
||||||
|
"https_key": plexpy.CONFIG.HTTPS_KEY,
|
||||||
|
"api_enabled": plexpy.CONFIG.API_ENABLED,
|
||||||
|
"api_key": plexpy.CONFIG.API_KEY,
|
||||||
|
"update_db_interval": plexpy.CONFIG.UPDATE_DB_INTERVAL,
|
||||||
|
"freeze_db": bool(plexpy.CONFIG.FREEZE_DB),
|
||||||
|
"log_dir": plexpy.CONFIG.LOG_DIR,
|
||||||
|
"cache_dir": plexpy.CONFIG.CACHE_DIR,
|
||||||
|
"check_github": bool(plexpy.CONFIG.CHECK_GITHUB),
|
||||||
|
"interface_list": interface_list,
|
||||||
|
"cache_sizemb": plexpy.CONFIG.CACHE_SIZEMB,
|
||||||
|
"pms_identifier": plexpy.CONFIG.PMS_IDENTIFIER,
|
||||||
|
"pms_ip": plexpy.CONFIG.PMS_IP,
|
||||||
|
"pms_logs_folder": plexpy.CONFIG.PMS_LOGS_FOLDER,
|
||||||
|
"pms_port": plexpy.CONFIG.PMS_PORT,
|
||||||
|
"pms_token": plexpy.CONFIG.PMS_TOKEN,
|
||||||
|
"pms_ssl": bool(plexpy.CONFIG.PMS_SSL),
|
||||||
|
"pms_use_bif": bool(plexpy.CONFIG.PMS_USE_BIF),
|
||||||
|
"pms_uuid": plexpy.CONFIG.PMS_UUID,
|
||||||
|
"date_format": plexpy.CONFIG.DATE_FORMAT,
|
||||||
|
"time_format": plexpy.CONFIG.TIME_FORMAT,
|
||||||
|
"grouping_global_history": bool(plexpy.CONFIG.GROUPING_GLOBAL_HISTORY),
|
||||||
|
"grouping_user_history": bool(plexpy.CONFIG.GROUPING_USER_HISTORY),
|
||||||
|
"grouping_charts": bool(plexpy.CONFIG.GROUPING_CHARTS),
|
||||||
|
"tv_notify_enable": bool(plexpy.CONFIG.TV_NOTIFY_ENABLE),
|
||||||
|
"movie_notify_enable": bool(plexpy.CONFIG.MOVIE_NOTIFY_ENABLE),
|
||||||
|
"music_notify_enable": bool(plexpy.CONFIG.MUSIC_NOTIFY_ENABLE),
|
||||||
|
"tv_notify_on_start": bool(plexpy.CONFIG.TV_NOTIFY_ON_START),
|
||||||
|
"movie_notify_on_start": bool(plexpy.CONFIG.MOVIE_NOTIFY_ON_START),
|
||||||
|
"music_notify_on_start": bool(plexpy.CONFIG.MUSIC_NOTIFY_ON_START),
|
||||||
|
"tv_notify_on_stop": bool(plexpy.CONFIG.TV_NOTIFY_ON_STOP),
|
||||||
|
"movie_notify_on_stop": bool(plexpy.CONFIG.MOVIE_NOTIFY_ON_STOP),
|
||||||
|
"music_notify_on_stop": bool(plexpy.CONFIG.MUSIC_NOTIFY_ON_STOP),
|
||||||
|
"tv_notify_on_pause": bool(plexpy.CONFIG.TV_NOTIFY_ON_PAUSE),
|
||||||
|
"movie_notify_on_pause": bool(plexpy.CONFIG.MOVIE_NOTIFY_ON_PAUSE),
|
||||||
|
"music_notify_on_pause": bool(plexpy.CONFIG.MUSIC_NOTIFY_ON_PAUSE),
|
||||||
|
"monitoring_interval": plexpy.CONFIG.MONITORING_INTERVAL,
|
||||||
|
"refresh_users_interval": plexpy.CONFIG.REFRESH_USERS_INTERVAL,
|
||||||
|
"refresh_users_on_startup": bool(plexpy.CONFIG.REFRESH_USERS_ON_STARTUP),
|
||||||
|
"ip_logging_enable": bool(plexpy.CONFIG.IP_LOGGING_ENABLE),
|
||||||
|
"video_logging_enable": bool(plexpy.CONFIG.VIDEO_LOGGING_ENABLE),
|
||||||
|
"music_logging_enable": bool(plexpy.CONFIG.MUSIC_LOGGING_ENABLE),
|
||||||
|
"logging_ignore_interval": plexpy.CONFIG.LOGGING_IGNORE_INTERVAL,
|
||||||
|
"pms_is_remote": bool(plexpy.CONFIG.PMS_IS_REMOTE),
|
||||||
|
"notify_watched_percent": plexpy.CONFIG.NOTIFY_WATCHED_PERCENT,
|
||||||
|
"notify_on_start_subject_text": plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT,
|
||||||
|
"notify_on_start_body_text": plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT,
|
||||||
|
"notify_on_stop_subject_text": plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT,
|
||||||
|
"notify_on_stop_body_text": plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT,
|
||||||
|
"notify_on_pause_subject_text": plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT,
|
||||||
|
"notify_on_pause_body_text": plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT,
|
||||||
|
"notify_on_resume_subject_text": plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT,
|
||||||
|
"notify_on_resume_body_text": plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT,
|
||||||
|
"notify_on_buffer_subject_text": plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT,
|
||||||
|
"notify_on_buffer_body_text": plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT,
|
||||||
|
"notify_on_watched_subject_text": plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT,
|
||||||
|
"notify_on_watched_body_text": plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT,
|
||||||
|
"home_stats_length": plexpy.CONFIG.HOME_STATS_LENGTH,
|
||||||
|
"home_stats_type": bool(plexpy.CONFIG.HOME_STATS_TYPE),
|
||||||
|
"home_stats_count": plexpy.CONFIG.HOME_STATS_COUNT,
|
||||||
|
"home_stats_cards": plexpy.CONFIG.HOME_STATS_CARDS,
|
||||||
|
"home_library_cards": plexpy.CONFIG.HOME_LIBRARY_CARDS,
|
||||||
|
"buffer_threshold": plexpy.CONFIG.BUFFER_THRESHOLD,
|
||||||
|
"buffer_wait": plexpy.CONFIG.BUFFER_WAIT
|
||||||
|
}
|
||||||
|
|
||||||
|
self.data = config
|
||||||
|
return config
|
||||||
|
|
||||||
|
def _getUserips(self, user_id=None, user=None, **kwargs):
|
||||||
|
custom_where = []
|
||||||
|
if user_id:
|
||||||
|
custom_where = [['user_id', user_id]]
|
||||||
|
elif user:
|
||||||
|
custom_where = [['user', user]]
|
||||||
|
|
||||||
|
user_data = users.Users()
|
||||||
|
history = user_data.get_user_unique_ips(kwargs=kwargs,
|
||||||
|
custom_where=custom_where)
|
||||||
|
|
||||||
|
if history:
|
||||||
|
self.data = history
|
||||||
|
return history
|
||||||
|
else:
|
||||||
|
self.msg = 'Failed to find users ips'
|
||||||
|
|
||||||
|
def _getPlayby(self, time_range='30', y_axis='plays', playtype='total_plays_per_month', **kwargs):
|
||||||
|
|
||||||
|
graph = graphs.Graphs()
|
||||||
|
if playtype == 'total_plays_per_month':
|
||||||
|
result = graph.get_total_plays_per_month(y_axis=y_axis)
|
||||||
|
|
||||||
|
elif playtype == 'total_plays_per_day':
|
||||||
|
result = graph.get_total_plays_per_day(time_range=time_range, y_axis=y_axis)
|
||||||
|
|
||||||
|
elif playtype == 'total_plays_per_hourofday':
|
||||||
|
result = graph.get_total_plays_per_hourofday(time_range=time_range, y_axis=y_axis)
|
||||||
|
|
||||||
|
elif playtype == 'total_plays_per_dayofweek':
|
||||||
|
result = graph.get_total_plays_per_dayofweek(time_range=time_range, y_axis=y_axis)
|
||||||
|
|
||||||
|
elif playtype == 'stream_type_by_top_10_users':
|
||||||
|
result = graph.get_stream_type_by_top_10_users(time_range=time_range, y_axis=y_axis)
|
||||||
|
|
||||||
|
elif playtype == 'stream_type_by_top_10_platforms':
|
||||||
|
result = graph.get_stream_type_by_top_10_platforms(time_range=time_range, y_axis=y_axis)
|
||||||
|
|
||||||
|
elif playtype == 'total_plays_by_stream_resolution':
|
||||||
|
result = graph.get_total_plays_by_stream_resolution(time_range=time_range, y_axis=y_axis)
|
||||||
|
|
||||||
|
elif playtype == 'total_plays_by_source_resolution':
|
||||||
|
result = graph.get_total_plays_by_source_resolution(time_range=time_range, y_axis=y_axis)
|
||||||
|
|
||||||
|
elif playtype == 'total_plays_per_stream_type':
|
||||||
|
result = graph.get_total_plays_per_stream_type(time_range=time_range, y_axis=y_axis)
|
||||||
|
|
||||||
|
elif playtype == 'total_plays_by_top_10_users':
|
||||||
|
result = graph.get_total_plays_by_top_10_users(time_range=time_range, y_axis=y_axis)
|
||||||
|
|
||||||
|
elif playtype == 'total_plays_by_top_10_platforms':
|
||||||
|
result = graph.get_total_plays_by_top_10_platforms(time_range=time_range, y_axis=y_axis)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
self.data = result
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
logger.warn('Unable to retrieve %s from db' % playtype)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue