def write(self): if self.ID: key_dict = {'id': self.ID} elif self.PMS_IDENTIFIER: key_dict = {'PMS_IDENTIFIER': self.PMS_IDENTIFIER} else: return values_dict = {} for key in self._CONFIG_DEFINITIONS.keys(): values_dict[key.lower()] = super(ServerConfig, self).__getattr__(key) if 'id' in values_dict: values_dict.pop('id') try: logger.info( "Tautulli ServerConfig :: %s: Writing configuration to database" % self.PMS_NAME) monitor_db = database.MonitorDatabase() result = monitor_db.upsert('servers', key_dict=key_dict, value_dict=values_dict) if result == 'insert': super(ServerConfig, self).__setattr__('ID', monitor_db.last_insert_id()) except Exception as e: logger.error( "Tautulli ServerConfig :: %s: Error writing configuration: %s" % (self.PMS_NAME, e))
def set_notify_state(session, state, agent_info): if session and state and agent_info: monitor_db = database.MonitorDatabase() if state == "play": values = {"on_play": int(time.time())} elif state == "stop": values = {"on_stop": int(time.time())} elif state == "pause": values = {"on_pause": int(time.time())} elif state == "resume": values = {"on_resume": int(time.time())} elif state == "buffer": values = {"on_buffer": int(time.time())} elif state == "watched": values = {"on_watched": int(time.time())} else: return keys = { "session_key": session["session_key"], "rating_key": session["rating_key"], "user_id": session["user_id"], "user": session["user"], "agent_id": agent_info["id"], "agent_name": agent_info["name"], } monitor_db.upsert(table_name="notify_log", key_dict=keys, value_dict=values) else: logger.error("PlexPy Notifier :: Unable to set notify state.")
def notify(self, artist, album, albumartpath): hosts = [x.strip() for x in self.hosts.split(',')] header = "PlexPy" message = "%s - %s added to your library" % (artist, album) time = "3000" # in ms for host in hosts: logger.info('Sending notification command to XMBC @ ' + host) try: version = self._sendjson(host, 'Application.GetProperties', {'properties': ['version']})['version']['major'] if version < 12: #Eden notification = header + "," + message + "," + time + "," + albumartpath notifycommand = {'command': 'ExecBuiltIn', 'parameter': 'Notification(' + notification + ')'} request = self._sendhttp(host, notifycommand) else: #Frodo params = {'title': header, 'message': message, 'displaytime': int(time), 'image': albumartpath} request = self._sendjson(host, 'GUI.ShowNotification', params) if not request: raise Exception except Exception: logger.error('Error sending notification request to XBMC')
def uploadToImgur(imgPath, imgTitle=''): from plexpy import logger client_id = '743b1a443ccd2b0' img_url = '' try: with open(imgPath, 'rb') as imgFile: img = imgFile.read() except IOError as e: logger.error(u"PlexPy Helpers :: Unable to read image file for Imgur: %s" % e) return img_url headers = {'Authorization': 'Client-ID %s' % client_id} data = {'type': 'base64', 'image': base64.b64encode(img)} if imgTitle: data['title'] = imgTitle data['name'] = imgTitle + '.jpg' request = urllib2.Request('https://api.imgur.com/3/image', headers=headers, data=urllib.urlencode(data)) response = urllib2.urlopen(request) response = json.loads(response.read()) if response.get('status') == 200: logger.debug(u"PlexPy Helpers :: Image uploaded to Imgur.") img_url = response.get('data').get('link', '') elif response.get('status') >= 400 and response.get('status') < 500: logger.warn(u"PlexPy Helpers :: Unable to upload image to Imgur: %s" % response.reason) else: logger.warn(u"PlexPy Helpers :: Unable to upload image to Imgur.") return img_url
def write(self): """ Make a copy of the stored config and write it to the configured file """ new_config = ConfigObj(encoding="UTF-8") new_config.filename = self._config_file # first copy over everything from the old config, even if it is not # correctly defined to keep from losing data for key, subkeys in self._config.items(): if key not in new_config: new_config[key] = {} for subkey, value in subkeys.items(): new_config[key][subkey] = value # next make sure that everything we expect to have defined is so for key in self._CONFIG_DEFINITIONS.keys(): key, definition_type, section, ini_key, default = self._define(key) self.check_setting(key) if section not in new_config: new_config[section] = {} new_config[section][ini_key] = self._config[section][ini_key] # Write it to file logger.info(u"Tautulli Config :: Writing configuration to file") try: new_config.write() except IOError as e: logger.error( u"Tautulli Config :: Error writing configuration file: %s", e) self._blacklist()
def notify(self, subject=None, message=None): hosts = [x.strip() for x in self.hosts.split(",")] header = subject message = message time = "3000" # in ms for host in hosts: logger.info("Sending notification command to XMBC @ " + host) try: version = self._sendjson(host, "Application.GetProperties", {"properties": ["version"]})["version"][ "major" ] if version < 12: # Eden notification = header + "," + message + "," + time notifycommand = {"command": "ExecBuiltIn", "parameter": "Notification(" + notification + ")"} request = self._sendhttp(host, notifycommand) else: # Frodo params = {"title": header, "message": message, "displaytime": int(time)} request = self._sendjson(host, "GUI.ShowNotification", params) if not request: raise Exception except Exception: logger.error("Error sending notification request to XBMC")
def notify(self, subject=None, message=None): title = "PlexPy" api = plexpy.CONFIG.NMA_APIKEY nma_priority = plexpy.CONFIG.NMA_PRIORITY logger.debug(u"NMA title: " + title) logger.debug(u"NMA API: " + api) logger.debug(u"NMA Priority: " + str(nma_priority)) event = subject logger.debug(u"NMA event: " + event) logger.debug(u"NMA message: " + message) batch = False p = pynma.PyNMA() keys = api.split(",") p.addkey(keys) if len(keys) > 1: batch = True response = p.push(title, event, message, priority=nma_priority, batch_mode=batch) if not response[api][u"code"] == u"200": logger.error(u"Could not send notification to NotifyMyAndroid") return False else: return True
def notify(self, subject=None, message=None): hosts = [x.strip() for x in self.hosts.split(',')] header = subject message = message time = "3000" # in ms for host in hosts: logger.info('Sending notification command to XMBC @ ' + host) try: version = self._sendjson(host, 'Application.GetProperties', {'properties': ['version']})['version']['major'] if version < 12: #Eden notification = header + "," + message + "," + time notifycommand = {'command': 'ExecBuiltIn', 'parameter': 'Notification(' + notification + ')'} request = self._sendhttp(host, notifycommand) else: #Frodo params = {'title': header, 'message': message, 'displaytime': int(time)} request = self._sendjson(host, 'GUI.ShowNotification', params) if not request: raise Exception except Exception: logger.error('Error sending notification request to XBMC')
def pms_image_proxy(self, img='', width='0', height='0', fallback=None, **kwargs): if img != '': 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('Image proxy queried but errors occured.') if fallback == 'poster': logger.info('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('Unable to read fallback image. %s' % e) return None
def notify(self, subject=None, message=None): if not subject or not message: return title = 'PlexPy' api = plexpy.CONFIG.NMA_APIKEY nma_priority = plexpy.CONFIG.NMA_PRIORITY # logger.debug(u"NMA title: " + title) # logger.debug(u"NMA API: " + api) # logger.debug(u"NMA Priority: " + str(nma_priority)) event = subject # logger.debug(u"NMA event: " + event) # logger.debug(u"NMA message: " + message) batch = False p = pynma.PyNMA() keys = api.split(',') p.addkey(keys) if len(keys) > 1: batch = True response = p.push(title, event, message, priority=nma_priority, batch_mode=batch) if not response[api][u'code'] == u'200': logger.error(u'Could not send notification to NotifyMyAndroid') return False else: return True
def upload_to_cloudinary(img_data, img_title='', rating_key='', fallback=''): """ Uploads an image to Cloudinary """ img_url = '' if not plexpy.CONFIG.CLOUDINARY_CLOUD_NAME or not plexpy.CONFIG.CLOUDINARY_API_KEY or not plexpy.CONFIG.CLOUDINARY_API_SECRET: logger.error( u"Tautulli Helpers :: Cannot upload image to Cloudinary. Cloudinary settings not specified in the settings." ) return img_url cloudinary.config(cloud_name=plexpy.CONFIG.CLOUDINARY_CLOUD_NAME, api_key=plexpy.CONFIG.CLOUDINARY_API_KEY, api_secret=plexpy.CONFIG.CLOUDINARY_API_SECRET) try: response = upload(b'data:image/png;base64,%b' % base64.b64encode(img_data), public_id='{}_{}'.format(fallback, rating_key), tags=[fallback, str(rating_key)], context={ 'title': img_title, 'rating_key': str(rating_key), 'fallback': fallback }) logger.debug( u"Tautulli Helpers :: Image '{}' ({}) uploaded to Cloudinary.". format(img_title, fallback)) img_url = response.get('url', '') except Exception as e: logger.error( u"Tautulli Helpers :: Unable to upload image '{}' ({}) to Cloudinary: {}" .format(img_title, fallback, e)) return img_url
def cache_image(url, image=None): """ Saves an image to the cache directory. If no image is provided, tries to return the image from the cache directory. """ # Create image directory if it doesn't exist imgdir = os.path.join(plexpy.CONFIG.CACHE_DIR, 'images/') if not os.path.exists(imgdir): logger.debug( u"Tautulli Helpers :: Creating image cache directory at %s" % imgdir) os.makedirs(imgdir) # Create a hash of the url to use as the filename imghash = hashlib.md5(url).hexdigest() imagefile = os.path.join(imgdir, imghash) # If an image is provided, save it to the cache directory if image: try: with open(imagefile, 'wb') as cache_file: cache_file.write(image) except IOError as e: logger.error(u"Tautulli Helpers :: Failed to cache image %s: %s" % (imagefile, e)) # Try to return the image from the cache directory if os.path.isfile(imagefile): imagetype = 'image/' + imghdr.what(os.path.abspath(imagefile)) else: imagefile = None imagetype = 'image/jpeg' return imagefile, imagetype
def create_https_certificates(ssl_cert, ssl_key): """ Create a self-signed HTTPS certificate and store in it in 'ssl_cert' and 'ssl_key'. Method assumes pyOpenSSL is installed. This code is stolen from SickBeard (http://github.com/midgetspy/Sick-Beard). """ from OpenSSL import crypto from certgen import createKeyPair, createSelfSignedCertificate, TYPE_RSA serial = int(time.time()) domains = [ 'DNS:' + d.strip() for d in plexpy.CONFIG.HTTPS_DOMAIN.split(',') if d ] ips = ['IP:' + d.strip() for d in plexpy.CONFIG.HTTPS_IP.split(',') if d] altNames = ','.join(domains + ips) # Create the self-signed Tautulli certificate logger.debug(u"Generating self-signed SSL certificate.") pkey = createKeyPair(TYPE_RSA, 2048) cert = createSelfSignedCertificate(("Tautulli", pkey), serial, (0, 60 * 60 * 24 * 365 * 10), altNames) # ten years # Save the key and certificate to disk try: with open(ssl_cert, "w") as fp: fp.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) with open(ssl_key, "w") as fp: fp.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)) except IOError as e: logger.error("Error creating SSL key and certificate: %s", e) return False return True
def run(): from websocket import create_connection if plexpy.CONFIG.PMS_SSL and plexpy.CONFIG.PMS_URL[:5] == 'https': uri = plexpy.CONFIG.PMS_URL.replace('https://', 'wss://') + '/:/websockets/notifications' secure = ' secure' else: uri = 'ws://%s:%s/:/websockets/notifications' % ( plexpy.CONFIG.PMS_IP, plexpy.CONFIG.PMS_PORT ) secure = '' # Set authentication token (if one is available) if plexpy.CONFIG.PMS_TOKEN: uri += '?X-Plex-Token=' + plexpy.CONFIG.PMS_TOKEN ws_connected = False reconnects = 0 # Try an open the websocket connection - if it fails after 15 retries fallback to polling while not ws_connected and reconnects <= 15: try: logger.info(u'PlexPy WebSocket :: Opening%s websocket, connection attempt %s.' % (secure, str(reconnects + 1))) ws = create_connection(uri) reconnects = 0 ws_connected = True logger.info(u'PlexPy WebSocket :: Ready') except IOError, e: logger.error(u'PlexPy WebSocket :: %s.' % e) reconnects += 1 time.sleep(5)
def import_from_tautulli(import_database=None, import_ignore_interval=0): logger.info(u"Tautulli Importer :: Data import from %s in progress..." % import_database) try: import_db = sqlite3.connect(import_database, timeout=20) import_db.row_factory = database.dict_factory tautulli_db = database.MonitorDatabase() account_list = import_users(import_db, tautulli_db) import_servers(import_db, tautulli_db, import_ignore_interval) notifier_lookup = import_notifiers(import_db, tautulli_db) import_newsletters(import_db, tautulli_db, notifier_lookup) logger.info( u"Tautulli Importer :: Tautulli data import complete successfully." ) import_db.close() for user_id in account_list: account = plexpy.PLEXTV_ACCOUNTS.reinit_account(user_id=user_id) account.refresh_servers() account.refresh_users() plexpy.PMS_SERVERS.update_unowned_servers() except Exception as e: logger.error( u"Tautulli Importer :: Failed to import tautulli database: %s" % e)
def import_session_history_media_info(import_db, tautulli_db, old_server_id, new_server_id, session_history_lookup): logger.info( u"Tautulli Importer :: Importing session_history_media_info table for ServerID: %s" % old_server_id) try: query = 'SELECT * FROM session_history_media_info WHERE server_id = %s' % old_server_id session_history_media_info_result = import_db.execute(query).fetchall() for session_history_media_info in session_history_media_info_result: if session_history_media_info['id'] in session_history_lookup: session_history_media_info['id'] = session_history_lookup[ session_history_media_info['id']] session_history_media_info['server_id'] = new_server_id query = ("INSERT INTO session_history_media_info (" + ", ".join(session_history_media_info.keys()) + ")" + " VALUES (" + ", ".join( ["?"] * len(session_history_media_info.keys())) + ")") tautulli_db.action(query, list(session_history_media_info.values())) logger.info( u"Tautulli Importer :: session_history_media_info imported.") except sqlite3.IntegrityError: logger.error(u"Tautulli Import_Tautulli :: Queries failed: %s", query) except Exception as e: raise Exception('Session History Media Info Import failed: %s' % e)
def notify(self, artist=None, album=None, snatched=None): title = 'PlexPy' api = plexpy.CONFIG.NMA_APIKEY nma_priority = plexpy.CONFIG.NMA_PRIORITY logger.debug(u"NMA title: " + title) logger.debug(u"NMA API: " + api) logger.debug(u"NMA Priority: " + str(nma_priority)) if snatched: event = snatched + " snatched!" message = "PlexPy has snatched: " + snatched else: event = artist + ' - ' + album + ' complete!' message = "PlexPy has downloaded and postprocessed: " + artist + ' [' + album + ']' logger.debug(u"NMA event: " + event) logger.debug(u"NMA message: " + message) batch = False p = pynma.PyNMA() keys = api.split(',') p.addkey(keys) if len(keys) > 1: batch = True response = p.push(title, event, message, priority=nma_priority, batch_mode=batch) if not response[api][u'code'] == u'200': logger.error(u'Could not send notification to NotifyMyAndroid') return False else: return True
def get_plexpy_pms_token(self, force=False): if force: logger.debug( u"Tautulli PlexTV :: Forcing refresh of Plex.tv token.") devices_list = self.get_devices_list() device_id = next( (d for d in devices_list if d['device_identifier'] == plexpy.CONFIG.PMS_UUID), {}).get('device_id', None) if device_id: logger.debug( u"Tautulli PlexTV :: Removing Tautulli from Plex.tv devices." ) try: self.delete_plextv_device(device_id=device_id) except: logger.error( u"Tautulli PlexTV :: Failed to remove Tautulli from Plex.tv devices." ) return None else: logger.warn( u"Tautulli PlexTV :: No existing Tautulli device found.") logger.info( u"Tautulli PlexTV :: Fetching a new Plex.tv token for Tautulli.") user = self.get_token() if user: token = user['auth_token'] plexpy.CONFIG.__setattr__('PMS_TOKEN', token) plexpy.CONFIG.write() logger.info( u"Tautulli PlexTV :: Updated Plex.tv token for Tautulli.") return token
def wait(): logger.info("Tautulli is ready!") # Wait endlessly for a signal to happen while True: if not plexpy.SIGNAL: try: time.sleep(1) except KeyboardInterrupt: plexpy.SIGNAL = 'shutdown' else: logger.info('Received signal: %s', plexpy.SIGNAL) if plexpy.SIGNAL == 'shutdown': plexpy.shutdown() elif plexpy.SIGNAL == 'restart': plexpy.shutdown(restart=True) elif plexpy.SIGNAL == 'checkout': plexpy.shutdown(restart=True, checkout=True) elif plexpy.SIGNAL == 'reset': plexpy.shutdown(restart=True, reset=True) elif plexpy.SIGNAL == 'update': plexpy.shutdown(restart=True, update=True) else: logger.error('Unknown signal. Shutting down...') plexpy.shutdown() plexpy.SIGNAL = None
def action(self, query, args=None, return_last_id=False): if query is None: return with db_lock: sql_result = None attempts = 0 while attempts < 5: try: with self.connection as c: if args is None: sql_result = c.execute(query) else: sql_result = c.execute(query, args) # Our transaction was successful, leave the loop break except sqlite3.OperationalError, e: if "unable to open database file" in e.message or "database is locked" in e.message: logger.warn('Database Error: %s', e) attempts += 1 time.sleep(1) else: logger.error('Database error: %s', e) raise except sqlite3.DatabaseError, e: logger.error('Fatal Error executing %s :: %s', query, e) raise
def notify(self, subject=None, message=None): title = 'PlexPy' api = plexpy.CONFIG.NMA_APIKEY nma_priority = plexpy.CONFIG.NMA_PRIORITY logger.debug(u"NMA title: " + title) logger.debug(u"NMA API: " + api) logger.debug(u"NMA Priority: " + str(nma_priority)) event = subject logger.debug(u"NMA event: " + event) logger.debug(u"NMA message: " + message) batch = False p = pynma.PyNMA() keys = api.split(',') p.addkey(keys) if len(keys) > 1: batch = True response = p.push(title, event, message, priority=nma_priority, batch_mode=batch) if not response[api][u'code'] == u'200': logger.error(u'Could not send notification to NotifyMyAndroid') return False else: return True
def set_notify_state(session, state, agent_info): if session and state and agent_info: monitor_db = database.MonitorDatabase() if state == 'play': values = {'on_play': int(time.time())} elif state == 'stop': values = {'on_stop': int(time.time())} elif state == 'pause': values = {'on_pause': int(time.time())} elif state == 'resume': values = {'on_resume': int(time.time())} elif state == 'buffer': values = {'on_buffer': int(time.time())} elif state == 'watched': values = {'on_watched': int(time.time())} else: return keys = {'session_key': session['session_key'], 'rating_key': session['rating_key'], 'user_id': session['user_id'], 'user': session['user'], 'agent_id': agent_info['id'], 'agent_name': agent_info['name']} monitor_db.upsert(table_name='notify_log', key_dict=keys, value_dict=values) else: logger.error('PlexPy Notifier :: Unable to set notify state.')
def create_https_certificates(ssl_cert, ssl_key): """ Create a self-signed HTTPS certificate and store in it in 'ssl_cert' and 'ssl_key'. Method assumes pyOpenSSL is installed. This code is stolen from SickBeard (http://github.com/midgetspy/Sick-Beard). """ from plexpy import logger from OpenSSL import crypto from certgen import createKeyPair, createSelfSignedCertificate, TYPE_RSA serial = int(time.time()) domains = ['DNS:' + d.strip() for d in plexpy.CONFIG.HTTPS_DOMAIN.split(',') if d] ips = ['IP:' + d.strip() for d in plexpy.CONFIG.HTTPS_IP.split(',') if d] altNames = ','.join(domains + ips) # Create the self-signed PlexPy certificate logger.debug(u"Generating self-signed SSL certificate.") pkey = createKeyPair(TYPE_RSA, 2048) cert = createSelfSignedCertificate(("PlexPy", pkey), serial, (0, 60 * 60 * 24 * 365 * 10), altNames) # ten years # Save the key and certificate to disk try: with open(ssl_cert, "w") as fp: fp.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) with open(ssl_key, "w") as fp: fp.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)) except IOError as e: logger.error("Error creating SSL key and certificate: %s", e) return False return True
def request_json(url, **kwargs): """ Wrapper for `request_response', which will decode the response as JSON object and return the result, if no exceptions are raised. As an option, a validator callback can be given, which should return True if the result is valid. """ validator = kwargs.pop("validator", None) response = request_response(url, **kwargs) if response is not None: try: result = response.json() if validator and not validator(result): logger.error("JSON validation result failed") else: return result except ValueError: logger.error("Response returned invalid JSON data") # Debug response if plexpy.VERBOSE: server_message(response)
def set_mobile_device_config(mobile_device_id=None, **kwargs): if str(mobile_device_id).isdigit(): mobile_device_id = int(mobile_device_id) else: logger.error( u"Tautulli MobileApp :: Unable to set exisiting mobile device: invalid mobile_device_id %s." % mobile_device_id) return False keys = {'id': mobile_device_id} values = {} if kwargs.get('friendly_name'): values['friendly_name'] = kwargs['friendly_name'] db = database.MonitorDatabase() try: db.upsert(table_name='mobile_devices', key_dict=keys, value_dict=values) logger.info( u"Tautulli MobileApp :: Updated mobile device agent: mobile_device_id %s." % mobile_device_id) return True except Exception as e: logger.warn( u"Tautulli MobileApp :: Unable to update mobile device: %s." % e) return False
def import_notify_log(import_db, monitor_db, old_notifier_id, new_notifier_id): logger.info( u"Tautulli Importer :: Importing Notifier_log table entries for notifier ID %s" % old_notifier_id) try: query = 'SELECT * FROM notify_log WHERE notifier_id = %s' % old_notifier_id notify_log_result = import_db.execute(query).fetchall() for notify_log in notify_log_result: old_notify_log_id = notify_log.pop('id') notify_log['notifier_id'] = new_notifier_id query = ("INSERT INTO notify_log (" + ", ".join(notify_log.keys()) + ")" + " VALUES (" + ", ".join(["?"] * len(notify_log.keys())) + ")") monitor_db.action(query, list(notify_log.values())) logger.info( u"Tautulli Importer :: Notify_log imported for notifier ID %s." % old_notifier_id) except sqlite3.IntegrityError: logger.error(u"Tautulli Import_Tautulli :: Queries failed: %s", query) except Exception as e: raise Exception('Notify Log Import failed: %s' % e)
def import_recently_added(import_db, monitor_db, old_server_id, new_server_id): logger.info( u"Tautulli Importer :: Importing recently_added table for ServerID: %s" % old_server_id) try: query = 'SELECT * FROM recently_added WHERE server_id = %s' % old_server_id recently_added_result = import_db.execute(query).fetchall() for recently_added in recently_added_result: old_recently_added_id = recently_added.pop('id') recently_added['server_id'] = new_server_id key_dict = {} key_dict['server_id'] = recently_added.pop('server_id') key_dict['rating_key'] = recently_added.pop('rating_key') key_dict['added_at'] = recently_added.pop('added_at') result = monitor_db.upsert('recently_added', key_dict=key_dict, value_dict=recently_added) logger.info(u"Tautulli Importer :: recently_added imported.") except sqlite3.IntegrityError: logger.error(u"Tautulli Import_Tautulli :: Queries failed: %s", query) except Exception as e: raise Exception('Recently Added Import failed: %s' % e)
def import_tvmaze_lookup(import_db, monitor_db, old_server_id, new_server_id): logger.info( u"Tautulli Importer :: Importing tvmaze_lookup table for ServerID: %s" % old_server_id) try: query = 'SELECT * FROM tvmaze_lookup WHERE server_id = %s' % old_server_id tvmaze_lookup_result = import_db.execute(query).fetchall() for tvmaze_lookup in tvmaze_lookup_result: old_tvmaze_lookup_id = tvmaze_lookup.pop('id') tvmaze_lookup['server_id'] = new_server_id key_dict = {} key_dict['server_id'] = tvmaze_lookup.pop('server_id') key_dict['rating_key'] = tvmaze_lookup.pop('rating_key') result = monitor_db.upsert('tvmaze_lookup', key_dict=key_dict, value_dict=tvmaze_lookup) logger.info(u"Tautulli Importer :: tvmaze_lookup imported.") except sqlite3.IntegrityError: logger.error(u"Tautulli Import_Tautulli :: Queries failed: %s", query) except Exception as e: raise Exception('TVMaze Lookup Import failed: %s' % e)
def import_session_history_metadata(import_db, monitor_db, old_server_id, new_server_id, session_history_lookup): logger.info( u"Tautulli Importer :: Importing session_history_metadata table for ServerID: %s" % old_server_id) try: query = 'SELECT * FROM session_history_metadata WHERE server_id = %s' % old_server_id session_history_metadata_result = import_db.execute(query).fetchall() for session_history_metadata in session_history_metadata_result: if session_history_metadata['id'] in session_history_lookup: session_history_metadata['id'] = session_history_lookup[ session_history_metadata['id']] session_history_metadata['server_id'] = new_server_id session_history_metadata[ 'library_id'] = plexpy.libraries.get_section_index( new_server_id, session_history_metadata['section_id']) query = ("INSERT INTO session_history_metadata (" + ", ".join(session_history_metadata.keys()) + ")" + " VALUES (" + ", ".join( ["?"] * len(session_history_metadata.keys())) + ")") monitor_db.action(query, list(session_history_metadata.values())) logger.info(u"Tautulli Importer :: session_history_metadata imported.") except sqlite3.IntegrityError: logger.error(u"Tautulli Import_Tautulli :: Queries failed: %s", query) except Exception as e: raise Exception('Session History Metadata Import failed: %s' % e)
def import_library_sections(import_db, monitor_db, old_server_id, new_server_id): logger.info( u"Tautulli Importer :: Importing library_sections table for ServerID: %s" % old_server_id) try: query = 'SELECT * FROM library_sections WHERE server_id = %s' % old_server_id library_sections = import_db.execute(query).fetchall() for library_section in library_sections: old_library_section_id = library_section.pop('id') library_section['server_id'] = new_server_id key_dict = {} key_dict['server_id'] = library_section.pop('server_id') key_dict['section_id'] = library_section.pop('section_id') result = monitor_db.upsert('library_sections', key_dict=key_dict, value_dict=library_section) logger.info(u"Tautulli Importer :: library_sections imported.") except sqlite3.IntegrityError: logger.error(u"Tautulli Import_Tautulli :: Queries failed: %s", query) except Exception as e: raise Exception('Library Sections Import failed: %s' % e)
def create_https_certificates(ssl_cert, ssl_key): """ Create a pair of self-signed HTTPS certificares and store in them in 'ssl_cert' and 'ssl_key'. Method assumes pyOpenSSL is installed. This code is stolen from SickBeard (http://github.com/midgetspy/Sick-Beard). """ from plexpy import logger from OpenSSL import crypto from certgen import createKeyPair, createCertRequest, createCertificate, \ TYPE_RSA, serial # Create the CA Certificate cakey = createKeyPair(TYPE_RSA, 2048) careq = createCertRequest(cakey, CN="Certificate Authority") cacert = createCertificate(careq, (careq, cakey), serial, (0, 60 * 60 * 24 * 365 * 10)) # ten years pkey = createKeyPair(TYPE_RSA, 2048) req = createCertRequest(pkey, CN="PlexPy") cert = createCertificate(req, (cacert, cakey), serial, (0, 60 * 60 * 24 * 365 * 10)) # ten years # Save the key and certificate to disk try: with open(ssl_key, "w") as fp: fp.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)) with open(ssl_cert, "w") as fp: fp.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) except IOError as e: logger.error("Error creating SSL key and certificate: %s", e) return False return True
def set_notify_state(session, state, agent_info): if session and state and agent_info: monitor_db = database.MonitorDatabase() if state == 'play': values = {'on_play': int(time.time())} elif state == 'stop': values = {'on_stop': int(time.time())} elif state == 'pause': values = {'on_pause': int(time.time())} elif state == 'resume': values = {'on_resume': int(time.time())} elif state == 'buffer': values = {'on_buffer': int(time.time())} elif state == 'watched': values = {'on_watched': int(time.time())} else: return keys = { 'session_key': session['session_key'], 'rating_key': session['rating_key'], 'user_id': session['user_id'], 'user': session['user'], 'agent_id': agent_info['id'], 'agent_name': agent_info['name'] } monitor_db.upsert(table_name='notify_log', key_dict=keys, value_dict=values) else: logger.error('PlexPy Notifier :: Unable to set notify state.')
def get_server_urls(self, include_https=True): if plexpy.CONFIG.PMS_IDENTIFIER: server_id = plexpy.CONFIG.PMS_IDENTIFIER else: logger.error(u"PlexPy PlexTV :: Unable to retrieve server identity.") return [] plextv_resources = self.get_plextv_resources(include_https=include_https) server_urls = [] try: xml_parse = minidom.parseString(plextv_resources) except Exception as e: logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_server_urls: %s" % e) return [] except: logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_server_urls.") return [] try: xml_head = xml_parse.getElementsByTagName('Device') except Exception as e: logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_server_urls: %s." % e) return [] for a in xml_head: if helpers.get_xml_attr(a, 'clientIdentifier') == server_id: connections = a.getElementsByTagName('Connection') for connection in connections: server_details = {"protocol": helpers.get_xml_attr(connection, 'protocol'), "address": helpers.get_xml_attr(connection, 'address'), "port": helpers.get_xml_attr(connection, 'port'), "uri": helpers.get_xml_attr(connection, 'uri'), "local": helpers.get_xml_attr(connection, 'local') } server_urls.append(server_details) # Else try to match the PMS_IP and PMS_PORT else: connections = a.getElementsByTagName('Connection') for connection in connections: if helpers.get_xml_attr(connection, 'address') == plexpy.CONFIG.PMS_IP and \ int(helpers.get_xml_attr(connection, 'port')) == plexpy.CONFIG.PMS_PORT: plexpy.CONFIG.PMS_IDENTIFIER = helpers.get_xml_attr(a, 'clientIdentifier') logger.info(u"PlexPy PlexTV :: PMS identifier changed from %s to %s." % \ (server_id, plexpy.CONFIG.PMS_IDENTIFIER)) server_details = {"protocol": helpers.get_xml_attr(connection, 'protocol'), "address": helpers.get_xml_attr(connection, 'address'), "port": helpers.get_xml_attr(connection, 'port'), "uri": helpers.get_xml_attr(connection, 'uri'), "local": helpers.get_xml_attr(connection, 'local') } break return server_urls
def import_session_history(import_db, monitor_db, old_server_id, new_server_id, import_ignore_interval): logger.info( u"Tautulli Importer :: Importing session_history table for ServerID: %s" % old_server_id) import_ignore_interval = (int(import_ignore_interval) if import_ignore_interval.isdigit() else 0) try: session_history_lookup = {} query = 'SELECT * FROM session_history WHERE server_id = %s' % old_server_id session_history_result = import_db.execute(query).fetchall() for session_history in session_history_result: old_session_history_id = session_history.pop('id') query = 'select sum(stopped - started) as play_time from session_history WHERE reference_id = %s' % old_session_history_id result = import_db.execute(query).fetchone() if result['play_time'] and result[ 'play_time'] >= import_ignore_interval: session_history['server_id'] = new_server_id key_dict = {} key_dict['started'] = session_history.pop('started') key_dict['server_id'] = session_history.pop('server_id') key_dict['rating_key'] = session_history.pop('rating_key') key_dict['user_id'] = session_history.pop('user_id') result = monitor_db.upsert('session_history', key_dict=key_dict, value_dict=session_history) if result == 'insert': new_session_history_id = monitor_db.last_insert_id() session_history_lookup[ old_session_history_id] = new_session_history_id query = 'SELECT id, reference_id FROM session_history WHERE server_id = %s' % new_server_id session_history_result = monitor_db.select(query) for session_history in session_history_result: key_dict = {'id': session_history.pop('id')} if session_history['reference_id'] in session_history_lookup: session_history['reference_id'] = session_history_lookup[ session_history['reference_id']] result = monitor_db.upsert('session_history', key_dict=key_dict, value_dict=session_history) import_session_history_media_info(import_db, monitor_db, old_server_id, new_server_id, session_history_lookup) import_session_history_metadata(import_db, monitor_db, old_server_id, new_server_id, session_history_lookup) logger.info(u"Tautulli Importer :: session_history imported.") except sqlite3.IntegrityError: logger.error(u"Tautulli Import_Tautulli :: Queries failed: %s", query) except Exception as e: raise Exception('Session History Import failed: %s' % e)
def read_changelog(): changelog_file = os.path.join(plexpy.PROG_DIR, 'CHANGELOG.md') try: logfile = open(changelog_file, "r") except IOError, e: logger.error('PlexPy Version Checker :: Unable to open changelog file. %s' % e) return None
def read_changelog(): changelog_file = os.path.join(plexpy.PROG_DIR, "CHANGELOG.md") try: logfile = open(changelog_file, "r") except IOError, e: logger.error("PlexPy Version Checker :: Unable to open changelog file. %s" % e) return None
def read_changelog(): changelog_file = os.path.join(plexpy.PROG_DIR, 'CHANGELOG.md') try: logfile = open(changelog_file, "r") except IOError, e: logger.error('PlexPy Version Checker :: Unable to open changelog file. %s' % e) return '<h4>Unable to open changelog file</h4>'
def cloudinary_transform(rating_key=None, width=1000, height=1500, opacity=100, background='000000', blur=0, img_format='png', img_title='', fallback=None): url = '' if not plexpy.CONFIG.CLOUDINARY_CLOUD_NAME or not plexpy.CONFIG.CLOUDINARY_API_KEY or not plexpy.CONFIG.CLOUDINARY_API_SECRET: logger.error( u"Tautulli Helpers :: Cannot transform image on Cloudinary. Cloudinary settings not specified in the settings." ) return url cloudinary.config(cloud_name=plexpy.CONFIG.CLOUDINARY_CLOUD_NAME, api_key=plexpy.CONFIG.CLOUDINARY_API_KEY, api_secret=plexpy.CONFIG.CLOUDINARY_API_SECRET) img_options = { 'format': img_format, 'fetch_format': 'auto', 'quality': 'auto', 'version': int(time.time()), 'secure': True } if width != 1000: img_options['width'] = str(width) img_options['crop'] = 'fill' if height != 1500: img_options['height'] = str(height) img_options['crop'] = 'fill' if opacity != 100: img_options['opacity'] = opacity if background != '000000': img_options['background'] = 'rgb:{}'.format(background) if blur != 0: img_options['effect'] = 'blur:{}'.format(blur * 100) try: url, options = cloudinary_url('{}_{}'.format(fallback, rating_key), **img_options) logger.debug( u"Tautulli Helpers :: Image '{}' ({}) transformed on Cloudinary.". format(img_title, fallback)) except Exception as e: logger.error( u"Tautulli Helpers :: Unable to transform image '{}' ({}) on Cloudinary: {}" .format(img_title, fallback, e)) return url
def get_ip(host): ip_address = '' if is_valid_ip(host): return host else: try: ip_address = socket.getaddrinfo(host, None)[0][4][0] logger.debug(u"IP Checker :: Resolved %s to %s." % (host, ip_address)) except: logger.error(u"IP Checker :: Bad IP or hostname provided.") return ip_address
def get_log_tail(window=20, parsed=True): if plexpy.CONFIG.PMS_LOGS_FOLDER: log_file = os.path.join(plexpy.CONFIG.PMS_LOGS_FOLDER, 'Plex Media Server.log') else: return [] try: logfile = open(log_file, "r") except IOError, e: logger.error('Unable to open Plex Log file. %s' % e) return []
def get_log_tail(window=20): if plexpy.CONFIG.PMS_LOGS_FOLDER: log_file = os.path.join(plexpy.CONFIG.PMS_LOGS_FOLDER, 'Plex Media Server.log') else: return [] try: logfile = open(log_file, "r") except IOError, e: logger.error('Unable to open Plex Log file. %s' % e) return []
def launch_browser(host, port, root): if host == '0.0.0.0': host = 'localhost' if CONFIG.ENABLE_HTTPS: protocol = 'https' else: protocol = 'http' try: webbrowser.open('%s://%s:%i%s' % (protocol, host, port, root)) except Exception as e: logger.error('Could not launch browser: %s', e)
def get_mobile_device_config(mobile_device_id=None): if str(mobile_device_id).isdigit(): mobile_device_id = int(mobile_device_id) else: logger.error( u"Tautulli MobileApp :: Unable to retrieve mobile device config: invalid mobile_device_id %s." % mobile_device_id) return None db = database.MonitorDatabase() result = db.select_single('SELECT * FROM mobile_devices WHERE id = ?', args=[mobile_device_id]) return result
def get_ip(host): from plexpy import logger ip_address = '' try: socket.inet_aton(host) ip_address = host except socket.error: try: ip_address = socket.gethostbyname(host) logger.debug(u"IP Checker :: Resolved %s to %s." % (host, ip_address)) except: logger.error(u"IP Checker :: Bad IP or hostname provided.") return ip_address
def build_server_notify_text(state=None): # Get time formats date_format = plexpy.CONFIG.DATE_FORMAT.replace('Do','').replace('zz','') time_format = plexpy.CONFIG.TIME_FORMAT.replace('Do','').replace('zz','') # Get the server name server_name = plexpy.CONFIG.PMS_NAME # Get the server uptime plex_tv = plextv.PlexTV() server_times = plex_tv.get_server_times() if server_times: updated_at = server_times[0]['updated_at'] server_uptime = helpers.human_duration(int(time.time() - helpers.cast_to_int(updated_at))) else: logger.error(u"PlexPy NotificationHandler :: Unable to retrieve server uptime.") server_uptime = 'N/A' on_extdown_subject = plexpy.CONFIG.NOTIFY_ON_EXTDOWN_SUBJECT_TEXT on_extdown_body = plexpy.CONFIG.NOTIFY_ON_EXTDOWN_BODY_TEXT on_intdown_subject = plexpy.CONFIG.NOTIFY_ON_INTDOWN_SUBJECT_TEXT on_intdown_body = plexpy.CONFIG.NOTIFY_ON_INTDOWN_BODY_TEXT on_extup_subject = plexpy.CONFIG.NOTIFY_ON_EXTUP_SUBJECT_TEXT on_extup_body = plexpy.CONFIG.NOTIFY_ON_EXTUP_BODY_TEXT on_intup_subject = plexpy.CONFIG.NOTIFY_ON_INTUP_SUBJECT_TEXT on_intup_body = plexpy.CONFIG.NOTIFY_ON_INTUP_BODY_TEXT script_args_text = plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT available_params = {# Global paramaters 'server_name': server_name, 'server_uptime': server_uptime, 'action': state.title(), 'datestamp': arrow.now().format(date_format), 'timestamp': arrow.now().format(time_format)} # Default text subject_text = 'PlexPy (%s)' % server_name # Default scripts args script_args = [] if script_args_text: try: script_args = [unicode(arg).format(**available_params) for arg in script_args_text.split()] except LookupError as e: logger.error(u"PlexPy Notifier :: Unable to parse field %s in script argument. Using fallback." % e) except Exception as e: logger.error(u"PlexPy Notifier :: Unable to parse custom script arguments %s. Using fallback." % e) if state == 'extdown': # Default body text body_text = 'The Plex Media Server remote access is down.' if on_extdown_subject and on_extdown_body: try: subject_text = unicode(on_extdown_subject).format(**available_params) except LookupError, e: logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e) except:
def get_log_tail(window=20, parsed=True, log_type="server"): if plexpy.CONFIG.PMS_LOGS_FOLDER: log_file = "" if log_type == "server": log_file = os.path.join(plexpy.CONFIG.PMS_LOGS_FOLDER, 'Plex Media Server.log') elif log_type == "scanner": log_file = os.path.join(plexpy.CONFIG.PMS_LOGS_FOLDER, 'Plex Media Scanner.log') else: return [] try: logfile = open(log_file, "r") except IOError as e: logger.error('Unable to open Plex Log file. %s' % e) return [] log_lines = tail(logfile, window) if parsed: line_error = False clean_lines = [] for i in log_lines: try: log_time = i.split(' [')[0] log_level = i.split('] ', 1)[1].split(' - ', 1)[0] log_msg = str(i.split('] ', 1)[1].split(' - ', 1)[1], 'utf-8') full_line = [log_time, log_level, log_msg] clean_lines.append(full_line) except: line_error = True full_line = ['', '', 'Unable to parse log line.'] clean_lines.append(full_line) if line_error: logger.error( 'Tautulli was unable to parse some lines of the Plex Media Server log.' ) return clean_lines else: raw_lines = [] for i in log_lines: raw_lines.append(helpers.latinToAscii(i)) return raw_lines return log_lines
def getVersion(): if version.PLEXPY_VERSION.startswith('win32build'): plexpy.INSTALL_TYPE = 'win' # Don't have a way to update exe yet, but don't want to set VERSION to None return 'Windows Install', 'master' elif os.path.isdir(os.path.join(plexpy.PROG_DIR, '.git')): plexpy.INSTALL_TYPE = 'git' output, err = runGit('rev-parse HEAD') if not output: logger.error('Couldn\'t find latest installed version.') cur_commit_hash = None cur_commit_hash = str(output) if not re.match('^[a-z0-9]+$', cur_commit_hash): logger.error('Output doesn\'t look like a hash, not using it') cur_commit_hash = None if plexpy.CONFIG.DO_NOT_OVERRIDE_GIT_BRANCH and plexpy.CONFIG.GIT_BRANCH: branch_name = plexpy.CONFIG.GIT_BRANCH else: branch_name, err = runGit('rev-parse --abbrev-ref HEAD') branch_name = branch_name if not branch_name and plexpy.CONFIG.GIT_BRANCH: logger.error( 'Could not retrieve branch name from git. Falling back to %s' % plexpy.CONFIG.GIT_BRANCH) branch_name = plexpy.CONFIG.GIT_BRANCH if not branch_name: logger.error( 'Could not retrieve branch name from git. Defaulting to master' ) branch_name = 'master' return cur_commit_hash, branch_name else: plexpy.INSTALL_TYPE = 'source' version_file = os.path.join(plexpy.PROG_DIR, 'version.txt') if not os.path.isfile(version_file): return None, 'master' with open(version_file, 'r') as f: current_version = f.read().strip(' \n\r') if current_version: return current_version, plexpy.CONFIG.GIT_BRANCH else: return None, 'master'
def get_image(self, img=None, width=None, height=None): if img: if width.isdigit() and height.isdigit(): uri = "/photo/:/transcode?url=http://127.0.0.1:32400" + img + "&width=" + width + "&height=" + height else: uri = "/photo/:/transcode?url=http://127.0.0.1:32400" + img request, content_type = self.request_handler.make_request( uri=uri, proto=self.protocol, request_type="GET", return_type=True ) return [request, content_type] else: logger.error("Image proxy queries but no input received.") return None
def get_server_urls(self, include_https=True): if plexpy.CONFIG.PMS_IDENTIFIER: server_id = plexpy.CONFIG.PMS_IDENTIFIER else: logger.error("PlexPy PlexTV connector :: Unable to retrieve server identity.") return [] plextv_resources = self.get_plextv_resources(include_https=include_https) server_urls = [] try: xml_parse = minidom.parseString(plextv_resources) except Exception, e: logger.warn("Error parsing XML for Plex resources: %s" % e) return []
def get_log_tail(window=20, parsed=True, log_type="server"): if plexpy.CONFIG.PMS_LOGS_FOLDER: log_file = "" if log_type == "server": log_file = os.path.join(plexpy.CONFIG.PMS_LOGS_FOLDER, 'Plex Media Server.log') elif log_type == "scanner": log_file = os.path.join(plexpy.CONFIG.PMS_LOGS_FOLDER, 'Plex Media Scanner.log') else: return [] try: logfile = open(log_file, "r") except IOError, e: logger.error('Unable to open Plex Log file. %s' % e) return []
def getVersion(): if version.PLEXPY_VERSION.startswith("win32build"): plexpy.INSTALL_TYPE = "win" # Don't have a way to update exe yet, but don't want to set VERSION to None return "Windows Install", "master" elif os.path.isdir(os.path.join(plexpy.PROG_DIR, ".git")): plexpy.INSTALL_TYPE = "git" output, err = runGit("rev-parse HEAD") if not output: logger.error("Couldn't find latest installed version.") cur_commit_hash = None cur_commit_hash = str(output) if not re.match("^[a-z0-9]+$", cur_commit_hash): logger.error("Output doesn't look like a hash, not using it") cur_commit_hash = None if plexpy.CONFIG.DO_NOT_OVERRIDE_GIT_BRANCH and plexpy.CONFIG.GIT_BRANCH: branch_name = plexpy.CONFIG.GIT_BRANCH else: branch_name, err = runGit("rev-parse --abbrev-ref HEAD") branch_name = branch_name if not branch_name and plexpy.CONFIG.GIT_BRANCH: logger.error("Could not retrieve branch name from git. Falling back to %s" % plexpy.CONFIG.GIT_BRANCH) branch_name = plexpy.CONFIG.GIT_BRANCH if not branch_name: logger.error("Could not retrieve branch name from git. Defaulting to master") branch_name = "master" return cur_commit_hash, branch_name else: plexpy.INSTALL_TYPE = "source" version_file = os.path.join(plexpy.PROG_DIR, "version.txt") if not os.path.isfile(version_file): return None, "master" with open(version_file, "r") as f: current_version = f.read().strip(" \n\r") if current_version: return current_version, plexpy.CONFIG.GIT_BRANCH else: return None, "master"
def getVersion(): if version.PLEXPY_VERSION.startswith('win32build'): plexpy.INSTALL_TYPE = 'win' # Don't have a way to update exe yet, but don't want to set VERSION to None return 'Windows Install', 'master' elif os.path.isdir(os.path.join(plexpy.PROG_DIR, '.git')): plexpy.INSTALL_TYPE = 'git' output, err = runGit('rev-parse HEAD') if not output: logger.error('Couldn\'t find latest installed version.') cur_commit_hash = None cur_commit_hash = str(output) if not re.match('^[a-z0-9]+$', cur_commit_hash): logger.error('Output doesn\'t look like a hash, not using it') cur_commit_hash = None if plexpy.CONFIG.DO_NOT_OVERRIDE_GIT_BRANCH and plexpy.CONFIG.GIT_BRANCH: branch_name = plexpy.CONFIG.GIT_BRANCH else: branch_name, err = runGit('rev-parse --abbrev-ref HEAD') branch_name = branch_name if not branch_name and plexpy.CONFIG.GIT_BRANCH: logger.error('Could not retrieve branch name from git. Falling back to %s' % plexpy.CONFIG.GIT_BRANCH) branch_name = plexpy.CONFIG.GIT_BRANCH if not branch_name: logger.error('Could not retrieve branch name from git. Defaulting to master') branch_name = 'master' return cur_commit_hash, branch_name else: plexpy.INSTALL_TYPE = 'source' version_file = os.path.join(plexpy.PROG_DIR, 'version.txt') if not os.path.isfile(version_file): return None, 'master' with open(version_file, 'r') as f: current_version = f.read().strip(' \n\r') if current_version: return current_version, plexpy.CONFIG.GIT_BRANCH else: return None, 'master'
def pms_image_proxy(self, img='', width='0', height='0', fallback=None, **kwargs): if img != '': 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('Image proxy queried but errors occured.') if fallback == 'poster': logger.info('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('Unable to read fallback image. %s' % e) return None
def action(self, query, args=None): if query is None: return sqlResult = None try: with self.connection as c: if args is None: sqlResult = c.execute(query) else: sqlResult = c.execute(query, args) except sqlite3.OperationalError, e: if "unable to open database file" in e.message or "database is locked" in e.message: logger.warn('Database Error: %s', e) else: logger.error('Database error: %s', e) raise
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 check_recently_added(): with monitor_lock: # add delay to allow for metadata processing delay = plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_DELAY time_threshold = int(time.time()) - delay time_interval = plexpy.CONFIG.MONITORING_INTERVAL pms_connect = pmsconnect.PmsConnect() recently_added_list = pms_connect.get_recently_added_details(count='10') if recently_added_list: recently_added = recently_added_list['recently_added'] for item in recently_added: metadata = [] if 0 < time_threshold - int(item['added_at']) <= time_interval: if item['media_type'] == 'movie': metadata_list = pms_connect.get_metadata_details(item['rating_key']) if metadata_list: metadata = [metadata_list['metadata']] else: logger.error(u"PlexPy Monitor :: Unable to retrieve metadata for rating_key %s" \ % str(item['rating_key'])) else: metadata_list = pms_connect.get_metadata_children_details(item['rating_key']) if metadata_list: metadata = metadata_list['metadata'] else: logger.error(u"PlexPy Monitor :: Unable to retrieve children metadata for rating_key %s" \ % str(item['rating_key'])) if metadata: if not plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_GRANDPARENT: for item in metadata: if 0 < time_threshold - int(item['added_at']) <= time_interval: logger.debug(u"PlexPy Monitor :: Library item %s has been added to Plex." % str(item['rating_key'])) # Fire off notifications threading.Thread(target=notification_handler.notify_timeline, kwargs=dict(timeline_data=item, notify_action='created')).start() else: item = max(metadata, key=lambda x:x['added_at']) if 0 < time_threshold - int(item['added_at']) <= time_interval: if item['media_type'] == 'episode' or item['media_type'] == 'track': metadata_list = pms_connect.get_metadata_details(item['grandparent_rating_key']) if metadata_list: item = metadata_list['metadata'] else: logger.error(u"PlexPy Monitor :: Unable to retrieve grandparent metadata for grandparent_rating_key %s" \ % str(item['rating_key'])) logger.debug(u"PlexPy Monitor :: Library item %s has been added to Plex." % str(item['rating_key'])) # Fire off notifications threading.Thread(target=notification_handler.notify_timeline, kwargs=dict(timeline_data=item, notify_action='created')).start()