Пример #1
0
    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))
Пример #2
0
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.")
Пример #3
0
    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')
Пример #4
0
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
Пример #5
0
    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()
Пример #6
0
    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")
Пример #7
0
    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
Пример #8
0
    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')
Пример #9
0
 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
Пример #10
0
    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
Пример #11
0
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
Пример #12
0
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
Пример #13
0
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
Пример #14
0
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)
Пример #15
0
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)
Пример #16
0
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)
Пример #17
0
    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
Пример #18
0
    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
Пример #19
0
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
Пример #20
0
    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
Пример #21
0
    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
Пример #22
0
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.')
Пример #23
0
    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
Пример #24
0
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
Пример #25
0
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)
Пример #26
0
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
Пример #27
0
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)
Пример #28
0
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)
Пример #29
0
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)
Пример #30
0
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)
Пример #31
0
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)
Пример #32
0
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
Пример #33
0
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.')
Пример #34
0
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)
Пример #35
0
    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
Пример #36
0
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)
Пример #37
0
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
Пример #38
0
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
Пример #39
0
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>'
Пример #40
0
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
Пример #41
0
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
Пример #42
0
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 []
Пример #43
0
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 []
Пример #44
0
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)
Пример #45
0
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)
Пример #46
0
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
Пример #47
0
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
Пример #48
0
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:
Пример #49
0
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
Пример #50
0
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'
Пример #51
0
    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
Пример #52
0
    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 []
Пример #53
0
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 []
Пример #54
0
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"
Пример #55
0
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'
Пример #56
0
 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
Пример #57
0
    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
Пример #58
0
    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))
Пример #59
0
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()