diff --git a/plexpy/api.py b/plexpy/api.py deleted file mode 100644 index 82fdbf73..00000000 --- a/plexpy/api.py +++ /dev/null @@ -1,510 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# 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 . - -import json -import hashlib -import os -import random -import re -import traceback - -import cherrypy -import xmltodict - -import plexpy -import database -import datafactory -import graphs -import logger -import plextv -import pmsconnect -import users -import versioncheck - - -cmd_list = ['getLogs', 'getVersion', 'checkGithub', 'shutdown', - 'getSettings', 'restart', 'update', 'getApikey', 'getHistory', - 'getMetadata', 'getUserips', 'getPlayby', 'getSync'] - - -class Api(object): - def __init__(self, out='json'): - - self.apikey = None - self.authenticated = False - self.cmd = None - self.kwargs = None - # For the responses - self.data = None - self.msg = None - self.result_type = 'error' - # Possible general params - self.callback = None - self.out_type = out - self.debug = None - - def checkParams(self, *args, **kwargs): - - if not plexpy.CONFIG.API_ENABLED: - self.msg = 'API not enabled' - elif not plexpy.CONFIG.API_KEY: - self.msg = 'API key not generated' - elif len(plexpy.CONFIG.API_KEY) != 32: - self.msg = 'API key not generated correctly' - elif 'apikey' not in kwargs: - self.msg = 'Parameter apikey is required' - 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)) - - # Set default values or remove them from kwargs - - self.callback = kwargs.pop('callback', None) - self.apikey = kwargs.pop('apikey', None) - self.cmd = kwargs.pop('cmd', None) - self.debug = kwargs.pop('debug', False) - # Allow override for the api. - self.out_type = kwargs.pop('out_type', 'json') - - if self.apikey == plexpy.CONFIG.API_KEY and plexpy.CONFIG.API_ENABLED and self.cmd in cmd_list: - self.authenticated = True - self.msg = None - elif self.cmd == 'getApikey' and plexpy.CONFIG.API_ENABLED: - self.authenticated = True - # Remove the old error msg - self.msg = None - - self.kwargs = kwargs - - 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 = ''' - - %s - - error - - ''' % e - - return out - - def fetchData(self): - - logger.info('Recieved API command: %s' % self.cmd) - if self.cmd and self.authenticated: - methodtocall = getattr(self, "_" + self.cmd) - # Let the traceback hit cherrypy so we can - # see the traceback there - if self.debug: - methodtocall(**self.kwargs) - else: - try: - methodtocall(**self.kwargs) - except Exception as e: - logger.error(traceback.format_exc()) - - # 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): - - db = database.MonitorDatabase() - rows = db.select(query) - - rows_as_dic = [] - - for row in rows: - row_as_dic = dict(zip(row.keys(), row)) - rows_as_dic.append(row_as_dic) - - return rows_as_dic - - def _getApikey(self, username='', password=''): - """ Returns api key, requires username and password is active """ - - apikey = hashlib.sha224(str(random.getrandbits(256))).hexdigest()[0:32] - if plexpy.CONFIG.HTTP_USERNAME and plexpy.CONFIG.HTTP_PASSWORD: - if username == plexpy.HTTP_USERNAME and password == plexpy.CONFIG.HTTP_PASSWORD: - if plexpy.CONFIG.API_KEY: - self.data = plexpy.CONFIG.API_KEY - else: - self.data = apikey - plexpy.CONFIG.API_KEY = apikey - plexpy.CONFIG.write() - else: - 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() - - return self.data - - 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, logger.FILENAME) - 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: - temp_loglevel_and_time = line.split('- ') - loglvl = temp_loglevel_and_time[1].split(' :')[0].strip() - 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 - - if len(line) > 1 and temp_loglevel_and_time is not None and loglvl in line: - - d = { - 'time': temp_loglevel_and_time[0], - 'loglevel': loglvl, - 'msg': msg.replace('\n', ''), - 'thread': thread - } - templog.append(d) - - if end > 0: - 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): - self.data = { - 'git_path': plexpy.CONFIG.GIT_PATH, - 'install_type': plexpy.INSTALL_TYPE, - 'current_version': plexpy.CURRENT_VERSION, - 'latest_version': plexpy.LATEST_VERSION, - 'commits_behind': plexpy.COMMITS_BEHIND, - } - self.result_type = 'success' - - def _checkGithub(self, **kwargs): - versioncheck.checkGithub() - self._getVersion() - - def _shutdown(self, **kwargs): - plexpy.SIGNAL = 'shutdown' - self.msg = 'Shutting down plexpy' - self.result_type = 'success' - - def _restart(self, **kwargs): - plexpy.SIGNAL = 'restart' - self.msg = 'Restarting plexpy' - self.result_type = 'success' - - def _update(self, **kwargs): - 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_datatables_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), - "movie_notify_enable": bool(plexpy.CONFIG.MOVIE_NOTIFY_ENABLE), - "tv_notify_enable": bool(plexpy.CONFIG.TV_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), - "movie_logging_enable": bool(plexpy.CONFIG.MOVIE_LOGGING_ENABLE), - "tv_logging_enable": bool(plexpy.CONFIG.TV_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) diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 3bf6f234..226de21e 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -4339,9 +4339,8 @@ class WebInterface(object): if args and 'v2' in args[0]: return API2()._api_run(**kwargs) else: - a = Api() - a.checkParams(*args, **kwargs) - return a.fetchData() + return json.dumps(API2()._api_responds(result_type='error', + msg='Please use the /api/v2 endpoint.')) @cherrypy.expose @cherrypy.tools.json_out()