# 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
%s' % f.read() except IOError as e: return "Log file not found." ##### Settings ##### @cherrypy.expose def settings(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))] # Initialise blank passwords so we do not expose them in the html forms # but users are still able to clear them if plexpy.CONFIG.HTTP_PASSWORD != '': http_password = ' ' else: http_password = '' config = { "http_host": plexpy.CONFIG.HTTP_HOST, "http_username": plexpy.CONFIG.HTTP_USERNAME, "http_port": plexpy.CONFIG.HTTP_PORT, "http_password": http_password, "launch_browser": checked(plexpy.CONFIG.LAUNCH_BROWSER), "enable_https": checked(plexpy.CONFIG.ENABLE_HTTPS), "https_create_cert": checked(plexpy.CONFIG.HTTPS_CREATE_CERT), "https_cert": plexpy.CONFIG.HTTPS_CERT, "https_key": plexpy.CONFIG.HTTPS_KEY, "https_domain": plexpy.CONFIG.HTTPS_DOMAIN, "https_ip": plexpy.CONFIG.HTTPS_IP, "anon_redirect": plexpy.CONFIG.ANON_REDIRECT, "api_enabled": checked(plexpy.CONFIG.API_ENABLED), "api_key": plexpy.CONFIG.API_KEY, "update_db_interval": plexpy.CONFIG.UPDATE_DB_INTERVAL, "freeze_db": checked(plexpy.CONFIG.FREEZE_DB), "backup_dir": plexpy.CONFIG.BACKUP_DIR, "cache_dir": plexpy.CONFIG.CACHE_DIR, "log_dir": plexpy.CONFIG.LOG_DIR, "log_blacklist": checked(plexpy.CONFIG.LOG_BLACKLIST), "check_github": checked(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": checked(plexpy.CONFIG.PMS_SSL), "pms_use_bif": checked(plexpy.CONFIG.PMS_USE_BIF), "pms_uuid": plexpy.CONFIG.PMS_UUID, "date_format": plexpy.CONFIG.DATE_FORMAT, "time_format": plexpy.CONFIG.TIME_FORMAT, "get_file_sizes": checked(plexpy.CONFIG.GET_FILE_SIZES), "grouping_global_history": checked(plexpy.CONFIG.GROUPING_GLOBAL_HISTORY), "grouping_user_history": checked(plexpy.CONFIG.GROUPING_USER_HISTORY), "grouping_charts": checked(plexpy.CONFIG.GROUPING_CHARTS), "movie_notify_enable": checked(plexpy.CONFIG.MOVIE_NOTIFY_ENABLE), "tv_notify_enable": checked(plexpy.CONFIG.TV_NOTIFY_ENABLE), "music_notify_enable": checked(plexpy.CONFIG.MUSIC_NOTIFY_ENABLE), "tv_notify_on_start": checked(plexpy.CONFIG.TV_NOTIFY_ON_START), "movie_notify_on_start": checked(plexpy.CONFIG.MOVIE_NOTIFY_ON_START), "music_notify_on_start": checked(plexpy.CONFIG.MUSIC_NOTIFY_ON_START), "tv_notify_on_stop": checked(plexpy.CONFIG.TV_NOTIFY_ON_STOP), "movie_notify_on_stop": checked(plexpy.CONFIG.MOVIE_NOTIFY_ON_STOP), "music_notify_on_stop": checked(plexpy.CONFIG.MUSIC_NOTIFY_ON_STOP), "tv_notify_on_pause": checked(plexpy.CONFIG.TV_NOTIFY_ON_PAUSE), "movie_notify_on_pause": checked(plexpy.CONFIG.MOVIE_NOTIFY_ON_PAUSE), "music_notify_on_pause": checked(plexpy.CONFIG.MUSIC_NOTIFY_ON_PAUSE), "monitor_pms_updates": checked(plexpy.CONFIG.MONITOR_PMS_UPDATES), "monitor_remote_access": checked(plexpy.CONFIG.MONITOR_REMOTE_ACCESS), "monitoring_interval": plexpy.CONFIG.MONITORING_INTERVAL, "monitoring_use_websocket": checked(plexpy.CONFIG.MONITORING_USE_WEBSOCKET), "refresh_libraries_interval": plexpy.CONFIG.REFRESH_LIBRARIES_INTERVAL, "refresh_libraries_on_startup": checked(plexpy.CONFIG.REFRESH_LIBRARIES_ON_STARTUP), "refresh_users_interval": plexpy.CONFIG.REFRESH_USERS_INTERVAL, "refresh_users_on_startup": checked(plexpy.CONFIG.REFRESH_USERS_ON_STARTUP), "ip_logging_enable": checked(plexpy.CONFIG.IP_LOGGING_ENABLE), "movie_logging_enable": checked(plexpy.CONFIG.MOVIE_LOGGING_ENABLE), "tv_logging_enable": checked(plexpy.CONFIG.TV_LOGGING_ENABLE), "music_logging_enable": checked(plexpy.CONFIG.MUSIC_LOGGING_ENABLE), "logging_ignore_interval": plexpy.CONFIG.LOGGING_IGNORE_INTERVAL, "pms_is_remote": checked(plexpy.CONFIG.PMS_IS_REMOTE), "notify_consecutive": checked(plexpy.CONFIG.NOTIFY_CONSECUTIVE), "notify_upload_posters": checked(plexpy.CONFIG.NOTIFY_UPLOAD_POSTERS), "notify_recently_added": checked(plexpy.CONFIG.NOTIFY_RECENTLY_ADDED), "notify_recently_added_grandparent": checked(plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_GRANDPARENT), "notify_recently_added_delay": plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_DELAY, "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, "notify_on_created_subject_text": plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT, "notify_on_created_body_text": plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT, "notify_on_extdown_subject_text": plexpy.CONFIG.NOTIFY_ON_EXTDOWN_SUBJECT_TEXT, "notify_on_extdown_body_text": plexpy.CONFIG.NOTIFY_ON_EXTDOWN_BODY_TEXT, "notify_on_intdown_subject_text": plexpy.CONFIG.NOTIFY_ON_INTDOWN_SUBJECT_TEXT, "notify_on_intdown_body_text": plexpy.CONFIG.NOTIFY_ON_INTDOWN_BODY_TEXT, "notify_on_extup_subject_text": plexpy.CONFIG.NOTIFY_ON_EXTUP_SUBJECT_TEXT, "notify_on_extup_body_text": plexpy.CONFIG.NOTIFY_ON_EXTUP_BODY_TEXT, "notify_on_intup_subject_text": plexpy.CONFIG.NOTIFY_ON_INTUP_SUBJECT_TEXT, "notify_on_intup_body_text": plexpy.CONFIG.NOTIFY_ON_INTUP_BODY_TEXT, "notify_on_pmsupdate_subject_text": plexpy.CONFIG.NOTIFY_ON_PMSUPDATE_SUBJECT_TEXT, "notify_on_pmsupdate_body_text": plexpy.CONFIG.NOTIFY_ON_PMSUPDATE_BODY_TEXT, "notify_scripts_args_text": plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT, "home_stats_length": plexpy.CONFIG.HOME_STATS_LENGTH, "home_stats_type": checked(plexpy.CONFIG.HOME_STATS_TYPE), "home_stats_count": plexpy.CONFIG.HOME_STATS_COUNT, "home_stats_cards": json.dumps(plexpy.CONFIG.HOME_STATS_CARDS), "home_library_cards": json.dumps(plexpy.CONFIG.HOME_LIBRARY_CARDS), "buffer_threshold": plexpy.CONFIG.BUFFER_THRESHOLD, "buffer_wait": plexpy.CONFIG.BUFFER_WAIT, "group_history_tables": checked(plexpy.CONFIG.GROUP_HISTORY_TABLES), "git_token": plexpy.CONFIG.GIT_TOKEN } return serve_template(templatename="settings.html", title="Settings", config=config) @cherrypy.expose def configUpdate(self, **kwargs): # Handle the variable config options. Note - keys with False values aren't getting passed checked_configs = [ "launch_browser", "enable_https", "https_create_cert", "api_enabled", "freeze_db", "check_github", "grouping_global_history", "grouping_user_history", "grouping_charts", "pms_use_bif", "pms_ssl", "movie_notify_enable", "tv_notify_enable", "music_notify_enable", "monitoring_use_websocket", "tv_notify_on_start", "movie_notify_on_start", "music_notify_on_start", "tv_notify_on_stop", "movie_notify_on_stop", "music_notify_on_stop", "tv_notify_on_pause", "movie_notify_on_pause", "music_notify_on_pause", "refresh_libraries_on_startup", "refresh_users_on_startup", "ip_logging_enable", "movie_logging_enable", "tv_logging_enable", "music_logging_enable", "pms_is_remote", "home_stats_type", "group_history_tables", "notify_consecutive", "notify_upload_posters", "notify_recently_added", "notify_recently_added_grandparent", "monitor_pms_updates", "monitor_remote_access", "get_file_sizes", "log_blacklist" ] for checked_config in checked_configs: if checked_config not in kwargs: # checked items should be zero or one. if they were not sent then the item was not checked kwargs[checked_config] = 0 else: kwargs[checked_config] = 1 # If http password exists in config, do not overwrite when blank value received if kwargs.get('http_password'): if kwargs['http_password'] == ' ' and plexpy.CONFIG.HTTP_PASSWORD != '': kwargs['http_password'] = plexpy.CONFIG.HTTP_PASSWORD for plain_config, use_config in [(x[4:], x) for x in kwargs if x.startswith('use_')]: # the use prefix is fairly nice in the html, but does not match the actual config kwargs[plain_config] = kwargs[use_config] del kwargs[use_config] # Check if we should refresh our data server_changed = False reschedule = False https_changed = False refresh_libraries = False refresh_users = False # If we change any monitoring settings, make sure we reschedule tasks. if kwargs.get('check_github') != plexpy.CONFIG.CHECK_GITHUB or \ kwargs.get('monitoring_interval') != str(plexpy.CONFIG.MONITORING_INTERVAL) or \ kwargs.get('refresh_libraries_interval') != str(plexpy.CONFIG.REFRESH_LIBRARIES_INTERVAL) or \ kwargs.get('refresh_users_interval') != str(plexpy.CONFIG.REFRESH_USERS_INTERVAL) or \ kwargs.get('notify_recently_added') != plexpy.CONFIG.NOTIFY_RECENTLY_ADDED or \ kwargs.get('monitor_pms_updates') != plexpy.CONFIG.MONITOR_PMS_UPDATES or \ kwargs.get('monitor_remote_access') != plexpy.CONFIG.MONITOR_REMOTE_ACCESS: reschedule = True # If we change the SSL setting for PMS or PMS remote setting, make sure we grab the new url. if kwargs.get('pms_ssl') != plexpy.CONFIG.PMS_SSL or \ kwargs.get('pms_is_remote') != plexpy.CONFIG.PMS_IS_REMOTE: server_changed = True # If we change the HTTPS setting, make sure we generate a new certificate. if kwargs.get('enable_https') and kwargs.get('https_create_cert'): if kwargs.get('https_domain') != plexpy.CONFIG.HTTPS_DOMAIN or \ kwargs.get('https_ip') != plexpy.CONFIG.HTTPS_IP or \ kwargs.get('https_cert') != plexpy.CONFIG.HTTPS_CERT or \ kwargs.get('https_key') != plexpy.CONFIG.HTTPS_KEY: https_changed = True # Remove config with 'hscard-' prefix and change home_stats_cards to list if kwargs.get('home_stats_cards', ''): for k in kwargs.keys(): if k.startswith('hscard-'): del kwargs[k] kwargs['home_stats_cards'] = kwargs['home_stats_cards'].split(',') if kwargs['home_stats_cards'] == ['first_run_wizard']: kwargs['home_stats_cards'] = plexpy.CONFIG.HOME_STATS_CARDS # Remove config with 'hlcard-' prefix and change home_library_cards to list if kwargs.get('home_library_cards', ''): for k in kwargs.keys(): if k.startswith('hlcard-'): del kwargs[k] kwargs['home_library_cards'] = kwargs['home_library_cards'].split(',') if kwargs['home_library_cards'] == ['first_run_wizard']: refresh_libraries = True # If we change the server, make sure we grab the new url and refresh libraries and users lists. if kwargs.get('server_changed'): del kwargs['server_changed'] server_changed = True refresh_users = True refresh_libraries = True plexpy.CONFIG.process_kwargs(kwargs) # Write the config plexpy.CONFIG.write() # Get new server URLs for SSL communications and get new server friendly name if server_changed: plextv.get_real_pms_url() pmsconnect.get_server_friendly_name() web_socket.reconnect() # Reconfigure scheduler if intervals changed if reschedule: plexpy.initialize_scheduler() # Generate a new HTTPS certificate if https_changed: create_https_certificates(plexpy.CONFIG.HTTPS_CERT, plexpy.CONFIG.HTTPS_KEY) # Refresh users table if our server IP changes. if refresh_libraries: threading.Thread(target=pmsconnect.refresh_libraries).start() # Refresh users table if our server IP changes. if refresh_users: threading.Thread(target=plextv.refresh_users).start() raise cherrypy.HTTPRedirect("settings") @cherrypy.expose def get_scheduler_table(self, **kwargs): return serve_template(templatename="scheduler_table.html") @cherrypy.expose def backup_db(self): """ Creates a manual backup of the plexpy.db file """ result = database.make_backup() if result: cherrypy.response.headers['Content-type'] = 'application/json' return json.dumps({'message': 'Database backup successful.'}) else: cherrypy.response.headers['Content-type'] = 'application/json' return json.dumps({'message': 'Database backup failed.'}) @cherrypy.expose def get_notification_agent_config(self, agent_id, **kwargs): if agent_id.isdigit(): config = notifiers.get_notification_agent_config(agent_id=agent_id) agents = notifiers.available_notification_agents() for agent in agents: if int(agent_id) == agent['id']: this_agent = agent break else: this_agent = None else: return None checkboxes = {'email_tls': checked(plexpy.CONFIG.EMAIL_TLS)} return serve_template(templatename="notification_config.html", title="Notification Configuration", agent=this_agent, data=config, checkboxes=checkboxes) @cherrypy.expose def get_notification_agent_triggers(self, agent_id, **kwargs): if agent_id.isdigit(): agents = notifiers.available_notification_agents() for agent in agents: if int(agent_id) == agent['id']: this_agent = agent break else: this_agent = None else: return None return serve_template(templatename="notification_triggers_modal.html", title="Notification Triggers", data=this_agent) @cherrypy.expose @addtoapi('notify') def test_notifier(self, agent_id=None, subject='PlexPy', body='Test notification', **kwargs): cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" if agent_id.isdigit(): agents = notifiers.available_notification_agents() for agent in agents: if int(agent_id) == agent['id']: this_agent = agent break else: this_agent = None if this_agent: logger.debug(u"Sending test %s notification." % this_agent['name']) notifiers.send_notification(this_agent['id'], subject, body, 'test', **kwargs) return "Notification sent." else: logger.debug(u"Unable to send test notification, invalid notification agent ID %s." % agent_id) return "Invalid notification agent ID %s." % agent_id else: logger.debug(u"Unable to send test notification, no notification agent ID received.") return "No notification agent ID received." @cherrypy.expose def twitterStep1(self): cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" tweet = notifiers.TwitterNotifier() return tweet._get_authorization() @cherrypy.expose def twitterStep2(self, key): cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" tweet = notifiers.TwitterNotifier() result = tweet._get_credentials(key) # logger.info(u"result: " + str(result)) if result: return "Key verification successful" else: return "Unable to verify key" @cherrypy.expose def facebookStep1(self): cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" facebook = notifiers.FacebookNotifier() return facebook._get_authorization() @cherrypy.expose def facebookStep2(self, code): cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" facebook = notifiers.FacebookNotifier() result = facebook._get_credentials(code) # logger.info(u"result: " + str(result)) if result: return "Key verification successful, PlexPy can send notification to Facebook. You may close this page now." else: return "Unable to verify key" @cherrypy.expose def osxnotifyregister(self, app): cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" from osxnotify import registerapp as osxnotify result, msg = osxnotify.registerapp(app) if result: osx_notify = notifiers.OSX_NOTIFY() osx_notify.notify('Registered', result, 'Success :-)') # logger.info(u"Registered %s, to re-register a different app, delete this app first" % result) else: logger.warn(msg) return msg @cherrypy.expose def set_notification_config(self, **kwargs): for plain_config, use_config in [(x[4:], x) for x in kwargs if x.startswith('use_')]: # the use prefix is fairly nice in the html, but does not match the actual config kwargs[plain_config] = kwargs[use_config] del kwargs[use_config] plexpy.CONFIG.process_kwargs(kwargs) # Write the config plexpy.CONFIG.write() cherrypy.response.status = 200 @cherrypy.expose @addtoapi() def get_plexwatch_export_data(self, database_path=None, table_name=None, import_ignore_interval=0, **kwargs): from plexpy import plexwatch_import db_check_msg = plexwatch_import.validate_database(database=database_path, table_name=table_name) if db_check_msg == 'success': threading.Thread(target=plexwatch_import.import_from_plexwatch, kwargs={'database': database_path, 'table_name': table_name, 'import_ignore_interval': import_ignore_interval}).start() return 'Import has started. Check the PlexPy logs to monitor any problems.' else: return db_check_msg @cherrypy.expose def plexwatch_import(self, **kwargs): return serve_template(templatename="plexwatch_import.html", title="Import PlexWatch Database") @cherrypy.expose def get_pms_token(self): token = plextv.PlexTV() result = token.get_token() if result: return result else: logger.warn(u"Unable to retrieve Plex.tv token.") return False @cherrypy.expose @addtoapi() def get_server_id(self, hostname=None, port=None, identifier=None, ssl=0, remote=0, **kwargs): from plexpy import http_handler # Attempt to get the pms_identifier from plex.tv if the server is published # Works for all PMS SSL settings if not identifier and hostname and port: plex_tv = plextv.PlexTV() servers = plex_tv.discover() ip_address = get_ip(hostname) for server in servers: if (server['ip'] == hostname or server['ip'] == ip_address) and server['port'] == port: identifier = server['clientIdentifier'] break # Fallback to checking /identity endpoint is server is unpublished # Cannot set SSL settings on the PMS if unpublished so 'http' is okay if not identifier: request_handler = http_handler.HTTPHandler(host=hostname, port=port, token=None) uri = '/identity' request = request_handler.make_request(uri=uri, proto='http', request_type='GET', output_format='xml', no_token=True, timeout=10) if request: xml_head = request.getElementsByTagName('MediaContainer')[0] identifier = xml_head.getAttribute('machineIdentifier') if identifier: cherrypy.response.headers['Content-type'] = 'application/json' return json.dumps(identifier) else: logger.warn('Unable to retrieve the PMS identifier.') return None @cherrypy.expose @addtoapi() def get_server_pref(self, pref=None, **kwargs): """ Return a specified server preference. Args: pref(string): 'name of preference' Returns: String: '' """ pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_server_pref(pref=pref) if result: return result else: logger.warn(u"Unable to retrieve data for get_server_pref.") @cherrypy.expose def generateAPI(self): apikey = hashlib.sha224(str(random.getrandbits(256))).hexdigest()[0:32] logger.info(u"New API key generated.") return apikey @cherrypy.expose def checkGithub(self): from plexpy import versioncheck versioncheck.checkGithub() raise cherrypy.HTTPRedirect("home") @cherrypy.expose def do_state_change(self, signal, title, timer): message = title quote = self.random_arnold_quotes() plexpy.SIGNAL = signal return serve_template(templatename="shutdown.html", title=title, message=message, timer=timer, quote=quote) @cherrypy.expose def shutdown(self): return self.do_state_change('shutdown', 'Shutting Down', 15) @cherrypy.expose def restart(self): return self.do_state_change('restart', 'Restarting', 30) @cherrypy.expose def update(self): return self.do_state_change('update', 'Updating', 120) ##### Info ##### @cherrypy.expose def info(self, rating_key=None, source=None, query=None, **kwargs): metadata = None config = { "pms_identifier": plexpy.CONFIG.PMS_IDENTIFIER } if source == 'history': data_factory = datafactory.DataFactory() metadata = data_factory.get_metadata_details(rating_key=rating_key) poster_url = data_factory.get_poster_url(metadata=metadata) metadata['poster_url'] = poster_url else: pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_metadata_details(rating_key=rating_key, get_media_info=True) if result: metadata = result['metadata'] data_factory = datafactory.DataFactory() poster_url = data_factory.get_poster_url(metadata=metadata) metadata['poster_url'] = poster_url if metadata: return serve_template(templatename="info.html", data=metadata, title="Info", config=config, source=source) else: return self.update_metadata(rating_key, query) @cherrypy.expose def get_item_children(self, rating_key='', **kwargs): pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_item_children(rating_key) if result: return serve_template(templatename="info_children_list.html", data=result, title="Children List") else: logger.warn(u"Unable to retrieve data for get_item_children.") return serve_template(templatename="info_children_list.html", data=None, title="Children List") @cherrypy.expose def pms_image_proxy(self, img='', width='0', height='0', fallback=None, **kwargs): try: pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_image(img, width, height) cherrypy.response.headers['Content-type'] = result[1] return result[0] except: logger.warn(u"Image proxy queried but errors occurred.") if fallback == 'poster': logger.info(u"Trying fallback image...") try: fallback_image = open(self.interface_dir + common.DEFAULT_POSTER_THUMB, 'rb') cherrypy.response.headers['Content-type'] = 'image/png' return fallback_image except IOError, e: logger.error(u"Unable to read fallback %s image: %s" % (fallback, e)) elif fallback == 'cover': logger.info(u"Trying fallback image...") try: fallback_image = open(self.interface_dir + common.DEFAULT_COVER_THUMB, 'rb') cherrypy.response.headers['Content-type'] = 'image/png' return fallback_image except IOError, e: logger.error(u"Unable to read fallback %s image: %s" % (fallback, e)) return None @cherrypy.expose def delete_poster_url(self, poster_url=''): if poster_url: data_factory = datafactory.DataFactory() result = data_factory.delete_poster_url(poster_url=poster_url) else: result = None if result: cherrypy.response.headers['Content-type'] = 'application/json' return json.dumps({'message': result}) else: cherrypy.response.headers['Content-type'] = 'application/json' return json.dumps({'message': 'no data received'}) ##### Search ##### @cherrypy.expose def search(self, query=''): return serve_template(templatename="search.html", title="Search", query=query) @cherrypy.expose @addtoapi('search') def search_results(self, query, **kwargs): pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_search_results(query) if result: cherrypy.response.headers['Content-type'] = 'application/json' return json.dumps(result) else: logger.warn(u"Unable to retrieve data for search_results.") @cherrypy.expose def get_search_results_children(self, query, media_type=None, season_index=None, **kwargs): pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_search_results(query) if media_type: result['results_list'] = {media_type: result['results_list'][media_type]} if media_type == 'season' and season_index: result['results_list']['season'] = [season for season in result['results_list']['season'] if season['media_index'] == season_index] if result: return serve_template(templatename="info_search_results_list.html", data=result, title="Search Result List") else: logger.warn(u"Unable to retrieve data for get_search_results_children.") return serve_template(templatename="info_search_results_list.html", data=None, title="Search Result List") ##### Update Metadata ##### @cherrypy.expose def update_metadata(self, rating_key=None, query=None, update=False, **kwargs): query_string = query update = True if update == 'True' else False data_factory = datafactory.DataFactory() query = data_factory.get_search_query(rating_key=rating_key) if query and query_string: query['query_string'] = query_string if query: return serve_template(templatename="update_metadata.html", query=query, update=update, title="Info") else: logger.warn(u"Unable to retrieve data for update_metadata.") return serve_template(templatename="update_metadata.html", query=query, update=update, title="Info") @cherrypy.expose @addtoapi() def update_metadata_details(self, old_rating_key, new_rating_key, media_type, **kwargs): data_factory = datafactory.DataFactory() pms_connect = pmsconnect.PmsConnect() if new_rating_key: old_key_list = data_factory.get_rating_keys_list(rating_key=old_rating_key, media_type=media_type) new_key_list = pms_connect.get_rating_keys_list(rating_key=new_rating_key, media_type=media_type) result = data_factory.update_metadata(old_key_list=old_key_list, new_key_list=new_key_list, media_type=media_type) if result: cherrypy.response.headers['Content-type'] = 'application/json' return json.dumps({'message': result}) else: cherrypy.response.headers['Content-type'] = 'application/json' return json.dumps({'message': 'no data received'}) # test code @cherrypy.expose @addtoapi() def get_new_rating_keys(self, rating_key='', media_type='', **kwargs): """ Grap the new rating keys Args: rating_key(string): '', media_type(string): '' Returns: json: '' """ pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_rating_keys_list(rating_key=rating_key, media_type=media_type) if result: cherrypy.response.headers['Content-type'] = 'application/json' return json.dumps(result) else: logger.warn(u"Unable to retrieve data for get_new_rating_keys.") @cherrypy.expose @addtoapi() def get_old_rating_keys(self, rating_key='', media_type='', **kwargs): """ Grap the old rating keys Args: rating_key(string): '', media_type(string): '' Returns: json: '' """ data_factory = datafactory.DataFactory() result = data_factory.get_rating_keys_list(rating_key=rating_key, media_type=media_type) if result: cherrypy.response.headers['Content-type'] = 'application/json' return json.dumps(result) else: logger.warn(u"Unable to retrieve data for get_old_rating_keys.") @cherrypy.expose @addtoapi('get_sessions') def get_pms_sessions_json(self, **kwargs): pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_sessions('json') if result: cherrypy.response.headers['Content-type'] = 'application/json' return result else: logger.warn(u"Unable to retrieve data for get_pms_sessions_json.") return False @cherrypy.expose @addtoapi('get_metadata') def get_metadata_json(self, rating_key='', **kwargs): pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_metadata(rating_key, 'json') if result: cherrypy.response.headers['Content-type'] = 'application/json' return result else: logger.warn(u"Unable to retrieve data for get_metadata_json.") @cherrypy.expose def get_metadata_xml(self, rating_key='', **kwargs): pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_metadata(rating_key) if result: cherrypy.response.headers['Content-type'] = 'application/xml' return result else: logger.warn(u"Unable to retrieve data for get_metadata_xml.") @cherrypy.expose @addtoapi('get_recently_added') def get_recently_added_json(self, count='0', **kwargs): """ Get all items that where recelty added to plex Args: count(string): Number of items Returns: dict: of all added items """ pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_recently_added(count, 'json') if result: cherrypy.response.headers['Content-type'] = 'application/json' return result else: logger.warn(u"Unable to retrieve data for get_recently_added_json.") @cherrypy.expose @addtoapi() def get_friends_list(self, **kwargs): """ Gets the friends list of the server owner for plex.tv """ plex_tv = plextv.PlexTV() result = plex_tv.get_plextv_friends('json') if result: cherrypy.response.headers['Content-type'] = 'application/json' return result else: logger.warn(u"Unable to retrieve data for get_friends_list.") @cherrypy.expose @addtoapi() def get_user_details(self, **kwargs): """ Get all details about a user from plextv """ plex_tv = plextv.PlexTV() result = plex_tv.get_plextv_user_details('json') if result: cherrypy.response.headers['Content-type'] = 'application/json' return result else: logger.warn(u"Unable to retrieve data for get_user_details.") @cherrypy.expose @addtoapi() def get_server_list(self, **kwargs): """ Find all servers published on plextv""" plex_tv = plextv.PlexTV() result = plex_tv.get_plextv_server_list('json') if result: cherrypy.response.headers['Content-type'] = 'application/json' return result else: logger.warn(u"Unable to retrieve data for get_server_list.") @cherrypy.expose @addtoapi() def get_sync_lists(self, machine_id='', **kwargs): plex_tv = plextv.PlexTV() result = plex_tv.get_plextv_sync_lists(machine_id=machine_id, output_format='json') if result: cherrypy.response.headers['Content-type'] = 'application/json' return result else: logger.warn(u"Unable to retrieve data for get_sync_lists.") @cherrypy.expose @addtoapi() def get_servers(self, **kwargs): """ All servers Returns: json: ``` {"MediaContainer": {"@size": "1", "Server": {"@name": "dude-PC", "@host": "10.0.0.97", "@address": "10.0.0.97", "@port": "32400", "@machineIdentifier": "1234", "@version": "0.9.15.2.1663-7efd046"}}} ``` """ pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_server_list(output_format='json') if result: cherrypy.response.headers['Content-type'] = 'application/json' return result else: logger.warn(u"Unable to retrieve data for get_servers.") @cherrypy.expose @addtoapi() def get_servers_info(self, **kwargs): """ Grabs list of info about the servers Returns: json: ``` [{"port": "32400", "host": "10.0.0.97", "version": "0.9.15.2.1663-7efd046", "name": "dude-PC", "machine_identifier": "1234" } ] ``` """ pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_servers_info() if result: cherrypy.response.headers['Content-type'] = 'application/json' return json.dumps(result) else: logger.warn(u"Unable to retrieve data for get_servers_info.") @cherrypy.expose @addtoapi() def get_server_identity(self, **kwargs): """ Grabs info about the local server Returns: json: ``` [{"machine_identifier": "1234", "version": "0.9.15.x.xxx-xxxxxxx" } ] ``` """ pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_server_identity() if result: cherrypy.response.headers['Content-type'] = 'application/json' return json.dumps(result) else: logger.warn(u"Unable to retrieve data for get_server_identity.") @cherrypy.expose @addtoapi() def get_server_friendly_name(self, **kwargs): result = pmsconnect.get_server_friendly_name() if result: cherrypy.response.headers['Content-type'] = 'application/json' return result else: logger.warn(u"Unable to retrieve data for get_server_friendly_name.") @cherrypy.expose @addtoapi() def get_server_prefs(self, pref=None, **kwargs): if pref: pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_server_pref(pref=pref) else: result = None if result: cherrypy.response.headers['Content-type'] = 'application/json' return result else: logger.warn(u"Unable to retrieve data for get_server_prefs.") @cherrypy.expose @addtoapi() def get_activity(self, **kwargs): """ Return processed and validated session list. Returns: json: ``` {stream_count: 1, session: [{dict}] } ``` """ pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_current_activity() if result: cherrypy.response.headers['Content-type'] = 'application/json' return json.dumps(result) else: logger.warn(u"Unable to retrieve data for get_activity.") @cherrypy.expose @addtoapi() def get_full_users_list(self, **kwargs): """ Get a list all users that has access to your server Returns: json: ``` [{"username": "Hellowlol", "user_id": "1345", "thumb": "https://plex.tv/users/123aa/avatar", "is_allow_sync": null, "is_restricted": "0", "is_home_user": "0", "email": "John.Doe@email.com"}] ``` """ plex_tv = plextv.PlexTV() result = plex_tv.get_full_users_list() if result: cherrypy.response.headers['Content-type'] = 'application/json' return json.dumps(result) else: logger.warn(u"Unable to retrieve data for get_full_users_list.") @cherrypy.expose @addtoapi() def get_sync_item(self, sync_id, **kwargs): """ Return sync item details. Args: sync_id(string): unique sync id for item output_format(string, optional): 'xml/json' Returns: List: ``` {"data": [ {"username": "username", "item_downloaded_percent_complete": 100, "user_id": "134", "failure": "", "title": "Some Movie", "total_size": "747195119", "root_title": "Movies", "music_bitrate": "128", "photo_quality": "49", "friendly_name": "username", "device_name": "Username iPad", "platform": "iOS", "state": "complete", "item_downloaded_count": "1", "content_type": "video", "metadata_type": "movie", "video_quality": "49", "item_count": "1", "rating_key": "59207", "item_complete_count": "1", "sync_id": "1234"} ] } ``` """ pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_sync_item(sync_id, output_format='json') if result: cherrypy.response.headers['Content-type'] = 'application/json' return result else: logger.warn(u"Unable to retrieve data for get_sync_item.") @cherrypy.expose @addtoapi() def get_sync_transcode_queue(self, **kwargs): pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_sync_transcode_queue(output_format='json') if result: cherrypy.response.headers['Content-type'] = 'application/json' return result else: logger.warn(u"Unable to retrieve data for get_sync_transcode_queue.") @cherrypy.expose @addtoapi() def random_arnold_quotes(self, **kwargs): from random import randint quote_list = ['To crush your enemies, see them driven before you, and to hear the lamentation of their women!', 'Your clothes, give them to me, now!', 'Do it!', 'If it bleeds, we can kill it', 'See you at the party Richter!', 'Let off some steam, Bennett', 'I\'ll be back', 'Get to the chopper!', 'Hasta La Vista, Baby!', 'It\'s not a tumor!', 'Dillon, you son of a bitch!', 'Benny!! Screw you!!', 'Stop whining! You kids are soft. You lack discipline.', 'Nice night for a walk.', 'Stick around!', 'I need your clothes, your boots and your motorcycle.', 'No, it\'s not a tumor. It\'s not a tumor!', 'I LIED!', 'Are you Sarah Connor?', 'I\'m a cop you idiot!', 'Come with me if you want to live.', 'Who is your daddy and what does he do?', 'Oh, cookies! I can\'t wait to toss them.', 'Can you hurry up. My horse is getting tired.', 'What killed the dinosaurs? The Ice Age!', 'That\'s for sleeping with my wife!', 'Remember when I said I’d kill you last... I lied!', 'You want to be a farmer? Here\'s a couple of acres', 'Now, this is the plan. Get your ass to Mars.', 'I just had a terrible thought... What if this is a dream?' ] random_number = randint(0, len(quote_list) - 1) return quote_list[int(random_number)] ### API ### @cherrypy.expose def api(self, *args, **kwargs): if args and 'v2' in args[0]: return API2()._api_run(**kwargs) else: from plexpy.api import Api a = Api() a.checkParams(*args, **kwargs) return a.fetchData() @cherrypy.expose def check_pms_updater(self): pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_update_staus() return json.dumps(result)