def _api_out_as(self, out): """ Formats the response to the desired output """ if self._api_cmd == 'docs_md': return out['response']['data'] elif self._api_cmd and self._api_cmd.startswith('download_'): return elif self._api_cmd == 'pms_image_proxy': if 'return_hash' not in self._api_kwargs: cherrypy.response.headers['Content-Type'] = 'image/jpeg' return out['response']['data'] if self._api_out_type == 'json': cherrypy.response.headers['Content-Type'] = 'application/json;charset=UTF-8' try: if self._api_debug: out = json.dumps(out, indent=4, sort_keys=True, ensure_ascii=False).encode('utf-8') else: out = json.dumps(out, ensure_ascii=False).encode('utf-8') if self._api_callback is not None: cherrypy.response.headers['Content-Type'] = 'application/javascript' # wrap with JSONP call if requested out = self._api_callback + '(' + out + ');' # if we fail to generate the output fake an error except Exception as e: logger.api_exception(u'Tautulli APIv2 :: ' + traceback.format_exc()) cherrypy.response.status = 500 out['message'] = traceback.format_exc() out['result'] = 'error' elif self._api_out_type == 'xml': cherrypy.response.headers['Content-Type'] = 'application/xml' try: out = xmltodict.unparse(out, pretty=True) except Exception as e: logger.api_error(u'Tautulli APIv2 :: Failed to parse xml result') cherrypy.response.status = 500 try: out['message'] = e out['result'] = 'error' out = xmltodict.unparse(out, pretty=True) except Exception as e: logger.api_error(u'Tautulli APIv2 :: Failed to parse xml result error message %s' % e) out = '''<?xml version="1.0" encoding="utf-8"?> <response> <message>%s</message> <data></data> <result>error</result> </response> ''' % e return out
def _api_run(self, *args, **kwargs): """ handles the stuff from the handler """ # Make sure the device ID is not shown in the logs if self._api_cmd == 'register_device': if kwargs.get('device_id'): logger._BLACKLIST_WORDS.add(kwargs['device_id']) if kwargs.get('onesignal_id'): logger._BLACKLIST_WORDS.add(kwargs['onesignal_id']) result = {} logger.api_debug('Tautulli APIv2 :: API called with kwargs: %s' % kwargs) self._api_validate(**kwargs) if self._api_cmd and self._api_authenticated: call = getattr(self, self._api_cmd) # Profile is written to console. if self._api_profileme: from profilehooks import profile call = profile(call, immediate=True) # We allow this to fail so we get a # traceback in the browser try: result = call(**self._api_kwargs) except Exception as e: logger.api_error( 'Tautulli APIv2 :: Failed to run %s with %s: %s' % (self._api_cmd, self._api_kwargs, e)) self._api_response_code = 500 if self._api_debug: cherrypy.request.show_tracebacks = True # Reraise the exception so the traceback hits the browser raise self._api_msg = 'Check the logs for errors' ret = None # The api decorated function can return different result types. # convert it to a list/dict before we change it to the users # wanted output try: if isinstance(result, (dict, list)): ret = result else: raise Exception except Exception: try: ret = json.loads(result) except (ValueError, TypeError): try: ret = xmltodict.parse(result, attr_prefix='') except: pass # Fallback if we cant "parse the response" if ret is None: ret = result if (ret is not None or self._api_result_type == 'success') and self._api_authenticated: # To allow override for restart etc # if the call returns some data we are gonna assume its a success self._api_result_type = 'success' self._api_response_code = 200 # Since some of them methods use a api like response for the ui # {result: error, message: 'Some shit happened'} if isinstance(ret, dict): if ret.get('message'): self._api_msg = ret.pop('message', None) if ret.get('result'): self._api_result_type = ret.pop('result', None) if self._api_result_type == 'success' and not self._api_response_code: self._api_response_code = 200 elif self._api_result_type == 'error' and not self._api_response_code: self._api_response_code = 400 if not self._api_response_code: self._api_response_code = 500 cherrypy.response.status = self._api_response_code return self._api_out_as( self._api_responds(result_type=self._api_result_type, msg=self._api_msg, data=ret))