def get_user_details(self, user=None, user_id=None): from plexpy import plextv monitor_db = database.MonitorDatabase() if user: query = 'SELECT user_id, username, friendly_name, email, ' \ 'custom_avatar_url as thumb, is_home_user, is_allow_sync, is_restricted, do_notify ' \ 'FROM users ' \ 'WHERE username = ? ' \ 'UNION ALL ' \ 'SELECT null, user, null, null, null, null, null, null, null ' \ 'FROM session_history ' \ 'WHERE user = ? ' \ 'GROUP BY user ' \ 'LIMIT 1' result = monitor_db.select(query, args=[user, user]) elif user_id: query = 'SELECT user_id, username, friendly_name, email, ' \ 'custom_avatar_url as thumb, is_home_user, is_allow_sync, is_restricted, do_notify ' \ 'FROM users ' \ 'WHERE user_id = ? ' \ 'UNION ALL ' \ 'SELECT user_id, user, null, null, null, null, null, null, null ' \ 'FROM session_history ' \ 'WHERE user_id = ? ' \ 'GROUP BY user ' \ 'LIMIT 1' result = monitor_db.select(query, args=[user_id, user_id]) else: result = None if result: user_details = {} for item in result: if not item['friendly_name']: friendly_name = item['username'] else: friendly_name = item['friendly_name'] if not item['thumb'] or item['thumb'] == '': user_thumb = common.DEFAULT_USER_THUMB else: user_thumb = item['thumb'] user_details = { "user_id": item['user_id'], "username": item['username'], "friendly_name": friendly_name, "email": item['email'], "thumb": user_thumb, "is_home_user": item['is_home_user'], "is_allow_sync": item['is_allow_sync'], "is_restricted": item['is_restricted'], "do_notify": item['do_notify'] } return user_details else: logger.warn( u"PlexPy :: Unable to retrieve user from local database. Requesting user list refresh." ) # Let's first refresh the user list to make sure the user isn't newly added and not in the db yet if user: # Refresh users plextv.refresh_users() query = 'SELECT user_id, username, friendly_name, email, ' \ 'custom_avatar_url as thumb, is_home_user, is_allow_sync, is_restricted, do_notify ' \ 'FROM users ' \ 'WHERE username = ? ' \ 'UNION ALL ' \ 'SELECT null, user, null, null, null, null, null, null, null ' \ 'FROM session_history ' \ 'WHERE user = ? ' \ 'GROUP BY user ' \ 'LIMIT 1' result = monitor_db.select(query, args=[user, user]) elif user_id: # Refresh users plextv.refresh_users() query = 'SELECT user_id, username, friendly_name, email, ' \ 'custom_avatar_url as thumb, is_home_user, is_allow_sync, is_restricted, do_notify ' \ 'FROM users ' \ 'WHERE user_id = ? ' \ 'UNION ALL ' \ 'SELECT user_id, user, null, null, null, null, null, null, null ' \ 'FROM session_history ' \ 'WHERE user_id = ? ' \ 'GROUP BY user ' \ 'LIMIT 1' result = monitor_db.select(query, args=[user_id, user_id]) else: result = None if result: user_details = {} for item in result: if not item['friendly_name']: friendly_name = item['username'] else: friendly_name = item['friendly_name'] if not item['thumb'] or item['thumb'] == '': user_thumb = common.DEFAULT_USER_THUMB else: user_thumb = item['thumb'] user_details = { "user_id": item['user_id'], "username": item['username'], "friendly_name": friendly_name, "email": item['email'], "thumb": user_thumb, "is_home_user": item['is_home_user'], "is_allow_sync": item['is_allow_sync'], "is_restricted": item['is_restricted'], "do_notify": item['do_notify'] } return user_details else: # If there is no user data we must return something # Use "Local" user to retain compatibility with PlexWatch database value return { "user_id": None, "username": '******', "friendly_name": 'Local', "email": '', "thumb": '', "is_home_user": 0, "is_allow_sync": 0, "is_restricted": 0, "do_notify": 0 }
def initialize(config_file): with INIT_LOCK: global CONFIG global _INITIALIZED global CURRENT_VERSION global LATEST_VERSION global UMASK CONFIG = plexpy.config.Config(config_file) assert CONFIG is not None if _INITIALIZED: return False if CONFIG.HTTP_PORT < 21 or CONFIG.HTTP_PORT > 65535: plexpy.logger.warn('HTTP_PORT out of bounds: 21 < %s < 65535', CONFIG.HTTP_PORT) CONFIG.HTTP_PORT = 8181 if CONFIG.HTTPS_CERT == '': CONFIG.HTTPS_CERT = os.path.join(DATA_DIR, 'server.crt') if CONFIG.HTTPS_KEY == '': CONFIG.HTTPS_KEY = os.path.join(DATA_DIR, 'server.key') if not CONFIG.LOG_DIR: CONFIG.LOG_DIR = os.path.join(DATA_DIR, 'logs') if not os.path.exists(CONFIG.LOG_DIR): try: os.makedirs(CONFIG.LOG_DIR) except OSError: CONFIG.LOG_DIR = None if not QUIET: sys.stderr.write("Unable to create the log directory. " \ "Logging to screen only.\n") # Start the logger, disable console if needed logger.initLogger(console=not QUIET, log_dir=CONFIG.LOG_DIR, verbose=VERBOSE) if not CONFIG.CACHE_DIR: # Put the cache dir in the data dir for now CONFIG.CACHE_DIR = os.path.join(DATA_DIR, 'cache') if not os.path.exists(CONFIG.CACHE_DIR): try: os.makedirs(CONFIG.CACHE_DIR) except OSError as e: logger.error("Could not create cache dir '%s': %s", DATA_DIR, e) # Initialize the database logger.info('Checking to see if the database has all tables....') try: dbcheck() except Exception as e: logger.error("Can't connect to the database: %s", e) # Check if PlexPy has a uuid if CONFIG.PMS_UUID == '' or not CONFIG.PMS_UUID: my_uuid = generate_uuid() CONFIG.__setattr__('PMS_UUID', my_uuid) CONFIG.write() # Get the currently installed version. Returns None, 'win32' or the git # hash. CURRENT_VERSION, CONFIG.GIT_BRANCH = versioncheck.getVersion() # Write current version to a file, so we know which version did work. # This allowes one to restore to that version. The idea is that if we # arrive here, most parts of PlexPy seem to work. if CURRENT_VERSION: version_lock_file = os.path.join(DATA_DIR, "version.lock") try: with open(version_lock_file, "w") as fp: fp.write(CURRENT_VERSION) except IOError as e: logger.error( "Unable to write current version to file '%s': %s", version_lock_file, e) # Check for new versions if CONFIG.CHECK_GITHUB_ON_STARTUP and CONFIG.CHECK_GITHUB: try: LATEST_VERSION = versioncheck.checkGithub() except: logger.exception("Unhandled exception") LATEST_VERSION = CURRENT_VERSION else: LATEST_VERSION = CURRENT_VERSION # Get the real PMS urls for SSL and remote access if CONFIG.PMS_TOKEN and CONFIG.PMS_IP and CONFIG.PMS_PORT: plextv.get_real_pms_url() # Refresh the users list on startup if CONFIG.PMS_TOKEN and CONFIG.REFRESH_USERS_ON_STARTUP: plextv.refresh_users() # Store the original umask UMASK = os.umask(0) os.umask(UMASK) _INITIALIZED = True return True
def import_from_plexwatch(database=None, table_name=None, import_ignore_interval=0): try: connection = sqlite3.connect(database, timeout=20) connection.row_factory = sqlite3.Row except sqlite3.OperationalError: logger.error(u"PlexPy Importer :: Invalid filename.") return None except ValueError: logger.error(u"PlexPy Importer :: Invalid filename.") return None try: connection.execute('SELECT ratingKey from %s' % table_name) except sqlite3.OperationalError: logger.error( u"PlexPy Importer :: Database specified does not contain the required fields." ) return None logger.debug(u"PlexPy Importer :: PlexWatch data import in progress...") logger.debug( u"PlexPy Importer :: Disabling monitoring while import in progress.") plexpy.schedule_job(activity_pinger.check_active_sessions, 'Check for active sessions', hours=0, minutes=0, seconds=0) plexpy.schedule_job(activity_pinger.check_recently_added, 'Check for recently added items', hours=0, minutes=0, seconds=0) plexpy.schedule_job(activity_pinger.check_server_response, 'Check for server response', hours=0, minutes=0, seconds=0) ap = activity_processor.ActivityProcessor() user_data = users.Users() # Get the latest friends list so we can pull user id's try: plextv.refresh_users() except: logger.debug( u"PlexPy Importer :: Unable to refresh the users list. Aborting import." ) return None query = 'SELECT time AS started, ' \ 'stopped, ' \ 'cast(ratingKey as text) AS rating_key, ' \ 'null AS user_id, ' \ 'user, ' \ 'ip_address, ' \ 'paused_counter, ' \ 'platform AS player, ' \ 'null AS platform, ' \ 'null as machine_id, ' \ 'parentRatingKey as parent_rating_key, ' \ 'grandparentRatingKey as grandparent_rating_key, ' \ 'null AS media_type, ' \ 'null AS view_offset, ' \ 'xml, ' \ 'rating as content_rating,' \ 'summary,' \ 'title AS full_title,' \ '(case when orig_title_ep = "" then orig_title else ' \ 'orig_title_ep end) as title,' \ '(case when orig_title_ep != "" then orig_title else ' \ 'null end) as grandparent_title ' \ 'FROM ' + table_name + ' ORDER BY id' result = connection.execute(query) for row in result: # Extract the xml from the Plexwatch db xml field. extracted_xml = extract_plexwatch_xml(row['xml']) # If we get back None from our xml extractor skip over the record and log error. if not extracted_xml: logger.error( u"PlexPy Importer :: Skipping record with ratingKey %s due to malformed xml." % str(row['rating_key'])) continue # Skip line if we don't have a ratingKey to work with if not row['rating_key']: logger.error( u"PlexPy Importer :: Skipping record due to null ratingRey.") continue # If the user_id no longer exists in the friends list, pull it from the xml. if user_data.get_user_id(user=row['user']): user_id = user_data.get_user_id(user=row['user']) else: user_id = extracted_xml['user_id'] session_history = { 'started': row['started'], 'stopped': row['stopped'], 'rating_key': row['rating_key'], 'title': row['title'], 'parent_title': extracted_xml['parent_title'], 'grandparent_title': row['grandparent_title'], 'user_id': user_id, 'user': row['user'], 'ip_address': row['ip_address'], 'paused_counter': row['paused_counter'], 'player': row['player'], 'platform': extracted_xml['platform'], 'machine_id': extracted_xml['machine_id'], 'parent_rating_key': row['parent_rating_key'], 'grandparent_rating_key': row['grandparent_rating_key'], 'media_type': extracted_xml['media_type'], 'view_offset': extracted_xml['view_offset'], 'video_decision': extracted_xml['video_decision'], 'audio_decision': extracted_xml['audio_decision'], 'duration': extracted_xml['duration'], 'width': extracted_xml['width'], 'height': extracted_xml['height'], 'container': extracted_xml['container'], 'video_codec': extracted_xml['video_codec'], 'audio_codec': extracted_xml['audio_codec'], 'bitrate': extracted_xml['bitrate'], 'video_resolution': extracted_xml['video_resolution'], 'video_framerate': extracted_xml['video_framerate'], 'aspect_ratio': extracted_xml['aspect_ratio'], 'audio_channels': extracted_xml['audio_channels'], 'transcode_protocol': extracted_xml['transcode_protocol'], 'transcode_container': extracted_xml['transcode_container'], 'transcode_video_codec': extracted_xml['transcode_video_codec'], 'transcode_audio_codec': extracted_xml['transcode_audio_codec'], 'transcode_audio_channels': extracted_xml['transcode_audio_channels'], 'transcode_width': extracted_xml['transcode_width'], 'transcode_height': extracted_xml['transcode_height'] } session_history_metadata = { 'rating_key': helpers.latinToAscii(row['rating_key']), 'parent_rating_key': row['parent_rating_key'], 'grandparent_rating_key': row['grandparent_rating_key'], 'title': row['title'], 'parent_title': extracted_xml['parent_title'], 'grandparent_title': row['grandparent_title'], 'media_index': extracted_xml['media_index'], 'parent_media_index': extracted_xml['parent_media_index'], 'thumb': extracted_xml['thumb'], 'parent_thumb': extracted_xml['parent_thumb'], 'grandparent_thumb': extracted_xml['grandparent_thumb'], 'art': extracted_xml['art'], 'media_type': extracted_xml['media_type'], 'year': extracted_xml['year'], 'originally_available_at': extracted_xml['originally_available_at'], 'added_at': extracted_xml['added_at'], 'updated_at': extracted_xml['updated_at'], 'last_viewed_at': extracted_xml['last_viewed_at'], 'content_rating': row['content_rating'], 'summary': row['summary'], 'tagline': extracted_xml['tagline'], 'rating': extracted_xml['rating'], 'duration': extracted_xml['duration'], 'guid': extracted_xml['guid'], 'section_id': extracted_xml['section_id'], 'directors': extracted_xml['directors'], 'writers': extracted_xml['writers'], 'actors': extracted_xml['actors'], 'genres': extracted_xml['genres'], 'studio': extracted_xml['studio'], 'full_title': row['full_title'] } # On older versions of PMS, "clip" items were still classified as "movie" and had bad ratingKey values # Just make sure that the ratingKey is indeed an integer if session_history_metadata['rating_key'].isdigit(): ap.write_session_history( session=session_history, import_metadata=session_history_metadata, is_import=True, import_ignore_interval=import_ignore_interval) else: logger.debug(u"PlexPy Importer :: Item has bad rating_key: %s" % session_history_metadata['rating_key']) logger.debug(u"PlexPy Importer :: PlexWatch data import complete.") import_users() logger.debug(u"PlexPy Importer :: Re-enabling monitoring.") plexpy.initialize_scheduler()
def initialize(config_file): with INIT_LOCK: global CONFIG global _INITIALIZED global CURRENT_VERSION global LATEST_VERSION global UMASK global POLLING_FAILOVER CONFIG = plexpy.config.Config(config_file) assert CONFIG is not None if _INITIALIZED: return False if CONFIG.HTTP_PORT < 21 or CONFIG.HTTP_PORT > 65535: plexpy.logger.warn( 'HTTP_PORT out of bounds: 21 < %s < 65535', CONFIG.HTTP_PORT) CONFIG.HTTP_PORT = 8181 if CONFIG.HTTPS_CERT == '': CONFIG.HTTPS_CERT = os.path.join(DATA_DIR, 'server.crt') if CONFIG.HTTPS_KEY == '': CONFIG.HTTPS_KEY = os.path.join(DATA_DIR, 'server.key') if not CONFIG.LOG_DIR: CONFIG.LOG_DIR = os.path.join(DATA_DIR, 'logs') if not os.path.exists(CONFIG.LOG_DIR): try: os.makedirs(CONFIG.LOG_DIR) except OSError: CONFIG.LOG_DIR = None if not QUIET: sys.stderr.write("Unable to create the log directory. " \ "Logging to screen only.\n") # Start the logger, disable console if needed logger.initLogger(console=not QUIET, log_dir=CONFIG.LOG_DIR, verbose=VERBOSE) if not CONFIG.CACHE_DIR: # Put the cache dir in the data dir for now CONFIG.CACHE_DIR = os.path.join(DATA_DIR, 'cache') if not os.path.exists(CONFIG.CACHE_DIR): try: os.makedirs(CONFIG.CACHE_DIR) except OSError as e: logger.error("Could not create cache dir '%s': %s", DATA_DIR, e) # Initialize the database logger.info('Checking to see if the database has all tables....') try: dbcheck() except Exception as e: logger.error("Can't connect to the database: %s", e) # Check if PlexPy has a uuid if CONFIG.PMS_UUID == '' or not CONFIG.PMS_UUID: my_uuid = generate_uuid() CONFIG.__setattr__('PMS_UUID', my_uuid) CONFIG.write() # Get the currently installed version. Returns None, 'win32' or the git # hash. CURRENT_VERSION, CONFIG.GIT_BRANCH = versioncheck.getVersion() # Write current version to a file, so we know which version did work. # This allowes one to restore to that version. The idea is that if we # arrive here, most parts of PlexPy seem to work. if CURRENT_VERSION: version_lock_file = os.path.join(DATA_DIR, "version.lock") try: with open(version_lock_file, "w") as fp: fp.write(CURRENT_VERSION) except IOError as e: logger.error("Unable to write current version to file '%s': %s", version_lock_file, e) # Check for new versions if CONFIG.CHECK_GITHUB_ON_STARTUP and CONFIG.CHECK_GITHUB: try: LATEST_VERSION = versioncheck.checkGithub() except: logger.exception("Unhandled exception") LATEST_VERSION = CURRENT_VERSION else: LATEST_VERSION = CURRENT_VERSION # Get the real PMS urls for SSL and remote access if CONFIG.PMS_TOKEN and CONFIG.PMS_IP and CONFIG.PMS_PORT: plextv.get_real_pms_url() # Refresh the users list on startup if CONFIG.PMS_TOKEN and CONFIG.REFRESH_USERS_ON_STARTUP: plextv.refresh_users() # Store the original umask UMASK = os.umask(0) os.umask(UMASK) _INITIALIZED = True return True
def refresh_users_list(self, **kwargs): plextv.refresh_users() raise cherrypy.HTTPRedirect("users")
def get_details(self, user_id=None, user=None): from plexpy import plextv default_return = {'user_id': None, 'username': '******', 'friendly_name': 'Local', 'user_thumb': common.DEFAULT_USER_THUMB, 'email': '', 'is_home_user': 0, 'is_allow_sync': 0, 'is_restricted': 0, 'do_notify': 0, 'keep_history': 0 } if not user_id and not user: return default_return def get_user_details(user_id=user_id, user=user): monitor_db = database.MonitorDatabase() try: if str(user_id).isdigit(): query = 'SELECT user_id, username, friendly_name, thumb AS user_thumb, custom_avatar_url AS custom_thumb, ' \ 'email, is_home_user, is_allow_sync, is_restricted, do_notify, keep_history ' \ 'FROM users ' \ 'WHERE user_id = ? ' result = monitor_db.select(query, args=[user_id]) elif user: query = 'SELECT user_id, username, friendly_name, thumb AS user_thumb, custom_avatar_url AS custom_thumb, ' \ 'email, is_home_user, is_allow_sync, is_restricted, do_notify, keep_history ' \ 'FROM users ' \ 'WHERE username = ? ' result = monitor_db.select(query, args=[user]) else: result = [] except Exception as e: logger.warn(u"PlexPy Users :: Unable to execute database query for get_details: %s." % e) result = [] user_details = {} if result: for item in result: if item['friendly_name']: friendly_name = item['friendly_name'] else: friendly_name = item['username'] if item['custom_thumb'] and item['custom_thumb'] != item['user_thumb']: user_thumb = item['custom_thumb'] elif item['user_thumb']: user_thumb = item['user_thumb'] else: user_thumb = common.DEFAULT_USER_THUMB user_details = {'user_id': item['user_id'], 'username': item['username'], 'friendly_name': friendly_name, 'user_thumb': user_thumb, 'email': item['email'], 'is_home_user': item['is_home_user'], 'is_allow_sync': item['is_allow_sync'], 'is_restricted': item['is_restricted'], 'do_notify': item['do_notify'], 'keep_history': item['keep_history'] } return user_details user_details = get_user_details(user_id=user_id, user=user) if user_details: return user_details else: logger.warn(u"PlexPy Users :: Unable to retrieve user from local database. Requesting user list refresh.") # Let's first refresh the user list to make sure the user isn't newly added and not in the db yet plextv.refresh_users() user_details = get_user_details(user_id=user_id, user=user) if user_details: return user_details else: logger.warn(u"PlexPy Users :: Unable to retrieve user from local database. Returning 'Local' user.") # If there is no user data we must return something # Use "Local" user to retain compatibility with PlexWatch database value return default_return
def import_from_plexwatch(database=None, table_name=None, import_ignore_interval=0): try: connection = sqlite3.connect(database, timeout=20) connection.row_factory = sqlite3.Row except sqlite3.OperationalError: logger.error(u"PlexPy Importer :: Invalid filename.") return None except ValueError: logger.error(u"PlexPy Importer :: Invalid filename.") return None try: connection.execute('SELECT ratingKey from %s' % table_name) except sqlite3.OperationalError: logger.error(u"PlexPy Importer :: Database specified does not contain the required fields.") return None logger.debug(u"PlexPy Importer :: PlexWatch data import in progress...") logger.debug(u"PlexPy Importer :: Disabling monitoring while import in progress.") plexpy.schedule_job(activity_pinger.check_active_sessions, 'Check for active sessions', hours=0, minutes=0, seconds=0) plexpy.schedule_job(activity_pinger.check_recently_added, 'Check for recently added items', hours=0, minutes=0, seconds=0) plexpy.schedule_job(activity_pinger.check_server_response, 'Check for Plex remote access', hours=0, minutes=0, seconds=0) ap = activity_processor.ActivityProcessor() user_data = users.Users() # Get the latest friends list so we can pull user id's try: plextv.refresh_users() except: logger.debug(u"PlexPy Importer :: Unable to refresh the users list. Aborting import.") return None query = 'SELECT time AS started, ' \ 'stopped, ' \ 'cast(ratingKey as text) AS rating_key, ' \ 'null AS user_id, ' \ 'user, ' \ 'ip_address, ' \ 'paused_counter, ' \ 'platform AS player, ' \ 'null AS platform, ' \ 'null as machine_id, ' \ 'parentRatingKey as parent_rating_key, ' \ 'grandparentRatingKey as grandparent_rating_key, ' \ 'null AS media_type, ' \ 'null AS view_offset, ' \ 'xml, ' \ 'rating as content_rating,' \ 'summary,' \ 'title AS full_title,' \ '(case when orig_title_ep = "" then orig_title else ' \ 'orig_title_ep end) as title,' \ '(case when orig_title_ep != "" then orig_title else ' \ 'null end) as grandparent_title ' \ 'FROM ' + table_name + ' ORDER BY id' result = connection.execute(query) for row in result: # Extract the xml from the Plexwatch db xml field. extracted_xml = extract_plexwatch_xml(row['xml']) # If we get back None from our xml extractor skip over the record and log error. if not extracted_xml: logger.error(u"PlexPy Importer :: Skipping record with ratingKey %s due to malformed xml." % str(row['rating_key'])) continue # Skip line if we don't have a ratingKey to work with if not row['rating_key']: logger.error(u"PlexPy Importer :: Skipping record due to null ratingKey.") continue # If the user_id no longer exists in the friends list, pull it from the xml. if user_data.get_user_id(user=row['user']): user_id = user_data.get_user_id(user=row['user']) else: user_id = extracted_xml['user_id'] session_history = {'started': row['started'], 'stopped': row['stopped'], 'rating_key': row['rating_key'], 'title': row['title'], 'parent_title': extracted_xml['parent_title'], 'grandparent_title': row['grandparent_title'], 'user_id': user_id, 'user': row['user'], 'ip_address': row['ip_address'], 'paused_counter': row['paused_counter'], 'player': row['player'], 'platform': extracted_xml['platform'], 'machine_id': extracted_xml['machine_id'], 'parent_rating_key': row['parent_rating_key'], 'grandparent_rating_key': row['grandparent_rating_key'], 'media_type': extracted_xml['media_type'], 'view_offset': extracted_xml['view_offset'], 'video_decision': extracted_xml['video_decision'], 'audio_decision': extracted_xml['audio_decision'], 'duration': extracted_xml['duration'], 'width': extracted_xml['width'], 'height': extracted_xml['height'], 'container': extracted_xml['container'], 'video_codec': extracted_xml['video_codec'], 'audio_codec': extracted_xml['audio_codec'], 'bitrate': extracted_xml['bitrate'], 'video_resolution': extracted_xml['video_resolution'], 'video_framerate': extracted_xml['video_framerate'], 'aspect_ratio': extracted_xml['aspect_ratio'], 'audio_channels': extracted_xml['audio_channels'], 'transcode_protocol': extracted_xml['transcode_protocol'], 'transcode_container': extracted_xml['transcode_container'], 'transcode_video_codec': extracted_xml['transcode_video_codec'], 'transcode_audio_codec': extracted_xml['transcode_audio_codec'], 'transcode_audio_channels': extracted_xml['transcode_audio_channels'], 'transcode_width': extracted_xml['transcode_width'], 'transcode_height': extracted_xml['transcode_height'] } session_history_metadata = {'rating_key': helpers.latinToAscii(row['rating_key']), 'parent_rating_key': row['parent_rating_key'], 'grandparent_rating_key': row['grandparent_rating_key'], 'title': row['title'], 'parent_title': extracted_xml['parent_title'], 'grandparent_title': row['grandparent_title'], 'media_index': extracted_xml['media_index'], 'parent_media_index': extracted_xml['parent_media_index'], 'thumb': extracted_xml['thumb'], 'parent_thumb': extracted_xml['parent_thumb'], 'grandparent_thumb': extracted_xml['grandparent_thumb'], 'art': extracted_xml['art'], 'media_type': extracted_xml['media_type'], 'year': extracted_xml['year'], 'originally_available_at': extracted_xml['originally_available_at'], 'added_at': extracted_xml['added_at'], 'updated_at': extracted_xml['updated_at'], 'last_viewed_at': extracted_xml['last_viewed_at'], 'content_rating': row['content_rating'], 'summary': row['summary'], 'tagline': extracted_xml['tagline'], 'rating': extracted_xml['rating'], 'duration': extracted_xml['duration'], 'guid': extracted_xml['guid'], 'section_id': extracted_xml['section_id'], 'directors': extracted_xml['directors'], 'writers': extracted_xml['writers'], 'actors': extracted_xml['actors'], 'genres': extracted_xml['genres'], 'studio': extracted_xml['studio'], 'full_title': row['full_title'] } # On older versions of PMS, "clip" items were still classified as "movie" and had bad ratingKey values # Just make sure that the ratingKey is indeed an integer if session_history_metadata['rating_key'].isdigit(): ap.write_session_history(session=session_history, import_metadata=session_history_metadata, is_import=True, import_ignore_interval=import_ignore_interval) else: logger.debug(u"PlexPy Importer :: Item has bad rating_key: %s" % session_history_metadata['rating_key']) logger.debug(u"PlexPy Importer :: PlexWatch data import complete.") import_users() logger.debug(u"PlexPy Importer :: Re-enabling monitoring.") plexpy.initialize_scheduler()
def get_user_details(self, user=None, user_id=None): from plexpy import plextv monitor_db = database.MonitorDatabase() if user: query = 'SELECT user_id, username, friendly_name, email, ' \ 'custom_avatar_url as thumb, is_home_user, is_allow_sync, is_restricted, do_notify ' \ 'FROM users ' \ 'WHERE username = ? ' \ 'UNION ALL ' \ 'SELECT null, user, null, null, null, null, null, null, null ' \ 'FROM session_history ' \ 'WHERE user = ? ' \ 'GROUP BY user ' \ 'LIMIT 1' result = monitor_db.select(query, args=[user, user]) elif user_id: query = 'SELECT user_id, username, friendly_name, email, ' \ 'custom_avatar_url as thumb, is_home_user, is_allow_sync, is_restricted, do_notify ' \ 'FROM users ' \ 'WHERE user_id = ? ' \ 'UNION ALL ' \ 'SELECT user_id, user, null, null, null, null, null, null, null ' \ 'FROM session_history ' \ 'WHERE user_id = ? ' \ 'GROUP BY user ' \ 'LIMIT 1' result = monitor_db.select(query, args=[user_id, user_id]) else: result = None if result: user_details = {} for item in result: if not item['friendly_name']: friendly_name = item['username'] else: friendly_name = item['friendly_name'] if not item['thumb'] or item['thumb'] == '': user_thumb = common.DEFAULT_USER_THUMB else: user_thumb = item['thumb'] user_details = {"user_id": item['user_id'], "username": item['username'], "friendly_name": friendly_name, "email": item['email'], "thumb": user_thumb, "is_home_user": item['is_home_user'], "is_allow_sync": item['is_allow_sync'], "is_restricted": item['is_restricted'], "do_notify": item['do_notify'] } return user_details else: logger.warn(u"PlexPy :: Unable to retrieve user from local database. Requesting user list refresh.") # Let's first refresh the user list to make sure the user isn't newly added and not in the db yet if user: # Refresh users plextv.refresh_users() query = 'SELECT user_id, username, friendly_name, email, ' \ 'custom_avatar_url as thumb, is_home_user, is_allow_sync, is_restricted, do_notify ' \ 'FROM users ' \ 'WHERE username = ? ' \ 'UNION ALL ' \ 'SELECT null, user, null, null, null, null, null, null, null ' \ 'FROM session_history ' \ 'WHERE user = ? ' \ 'GROUP BY user ' \ 'LIMIT 1' result = monitor_db.select(query, args=[user, user]) elif user_id: # Refresh users plextv.refresh_users() query = 'SELECT user_id, username, friendly_name, email, ' \ 'custom_avatar_url as thumb, is_home_user, is_allow_sync, is_restricted, do_notify ' \ 'FROM users ' \ 'WHERE user_id = ? ' \ 'UNION ALL ' \ 'SELECT user_id, user, null, null, null, null, null, null, null ' \ 'FROM session_history ' \ 'WHERE user_id = ? ' \ 'GROUP BY user ' \ 'LIMIT 1' result = monitor_db.select(query, args=[user_id, user_id]) else: result = None if result: user_details = {} for item in result: if not item['friendly_name']: friendly_name = item['username'] else: friendly_name = item['friendly_name'] if not item['thumb'] or item['thumb'] == '': user_thumb = common.DEFAULT_USER_THUMB else: user_thumb = item['thumb'] user_details = {"user_id": item['user_id'], "username": item['username'], "friendly_name": friendly_name, "email": item['email'], "thumb": user_thumb, "is_home_user": item['is_home_user'], "is_allow_sync": item['is_allow_sync'], "is_restricted": item['is_restricted'], "do_notify": item['do_notify'] } return user_details else: # If there is no user data we must return something # Use "Local" user to retain compatibility with PlexWatch database value return {"user_id": None, "username": '******', "friendly_name": 'Local', "email": '', "thumb": '', "is_home_user": 0, "is_allow_sync": 0, "is_restricted": 0, "do_notify": 0 }
def import_from_plexwatch(database=None, table_name=None, import_ignore_interval=0): try: connection = sqlite3.connect(database, timeout=20) except sqlite3.OperationalError: logger.error('PlexPy Importer :: Invalid filename.') return None except ValueError: logger.error('PlexPy Importer :: Invalid filename.') return None try: connection.execute('SELECT ratingKey from %s' % table_name) except sqlite3.OperationalError: logger.error('PlexPy Importer :: Database specified does not contain the required fields.') return None logger.debug(u"PlexPy Importer :: PlexWatch data import in progress...") logger.debug(u"PlexPy Importer :: Disabling monitoring while import in progress.") plexpy.schedule_job(monitor.check_active_sessions, 'Check for active sessions', hours=0, minutes=0, seconds=0) monitor_processing = monitor.MonitorProcessing() data_factory = datafactory.DataFactory() # Get the latest friends list so we can pull user id's try: plextv.refresh_users() except: logger.debug(u"PlexPy Importer :: Unable to refresh the users list. Aborting import.") return None query = 'SELECT time AS started, ' \ 'stopped, ' \ 'ratingKey AS rating_key, ' \ 'null AS user_id, ' \ 'user, ' \ 'ip_address, ' \ 'paused_counter, ' \ 'platform AS player, ' \ 'null AS platform, ' \ 'null as machine_id, ' \ 'parentRatingKey as parent_rating_key, ' \ 'grandparentRatingKey as grandparent_rating_key, ' \ 'null AS media_type, ' \ 'null AS view_offset, ' \ 'xml, ' \ 'rating as content_rating,' \ 'summary,' \ 'title AS full_title,' \ 'orig_title AS title, ' \ 'orig_title_ep AS grandparent_title ' \ 'FROM ' + table_name + ' ORDER BY id' result = connection.execute(query) for row in result: # Extract the xml from the Plexwatch db xml field. extracted_xml = extract_plexwatch_xml(row[14]) # If the user_id no longer exists in the friends list, pull it from the xml. if data_factory.get_user_id(user=row[4]): user_id = data_factory.get_user_id(user=row[4]) else: user_id = extracted_xml['user_id'] session_history = {'started': row[0], 'stopped': row[1], 'rating_key': row[2], 'title': extracted_xml['title'], 'parent_title': extracted_xml['parent_title'], 'grandparent_title': extracted_xml['grandparent_title'], 'user_id': user_id, 'user': row[4], 'ip_address': row[5], 'paused_counter': row[6], 'player': row[7], 'platform': extracted_xml['platform'], 'machine_id': extracted_xml['machine_id'], 'parent_rating_key': row[10], 'grandparent_rating_key': row[11], 'media_type': extracted_xml['media_type'], 'view_offset': extracted_xml['view_offset'], 'video_decision': extracted_xml['video_decision'], 'audio_decision': extracted_xml['audio_decision'], 'duration': extracted_xml['duration'], 'width': extracted_xml['width'], 'height': extracted_xml['height'], 'container': extracted_xml['container'], 'video_codec': extracted_xml['video_codec'], 'audio_codec': extracted_xml['audio_codec'], 'bitrate': extracted_xml['bitrate'], 'video_resolution': extracted_xml['video_resolution'], 'video_framerate': extracted_xml['video_framerate'], 'aspect_ratio': extracted_xml['aspect_ratio'], 'audio_channels': extracted_xml['audio_channels'], 'transcode_protocol': extracted_xml['transcode_protocol'], 'transcode_container': extracted_xml['transcode_container'], 'transcode_video_codec': extracted_xml['transcode_video_codec'], 'transcode_audio_codec': extracted_xml['transcode_audio_codec'], 'transcode_audio_channels': extracted_xml['transcode_audio_channels'], 'transcode_width': extracted_xml['transcode_width'], 'transcode_height': extracted_xml['transcode_height'] } session_history_metadata = {'rating_key': row[2], 'parent_rating_key': row[10], 'grandparent_rating_key': row[11], 'title': extracted_xml['title'], 'parent_title': extracted_xml['parent_title'], 'grandparent_title': extracted_xml['grandparent_title'], 'index': extracted_xml['media_index'], 'parent_index': extracted_xml['parent_media_index'], 'thumb': extracted_xml['thumb'], 'parent_thumb': extracted_xml['parent_thumb'], 'grandparent_thumb': extracted_xml['grandparent_thumb'], 'art': extracted_xml['art'], 'media_type': extracted_xml['media_type'], 'year': extracted_xml['year'], 'originally_available_at': extracted_xml['originally_available_at'], 'added_at': extracted_xml['added_at'], 'updated_at': extracted_xml['updated_at'], 'last_viewed_at': extracted_xml['last_viewed_at'], 'content_rating': row[15], 'summary': row[16], 'rating': extracted_xml['rating'], 'duration': extracted_xml['duration'], 'guid': extracted_xml['guid'], 'directors': extracted_xml['directors'], 'writers': extracted_xml['writers'], 'actors': extracted_xml['actors'], 'genres': extracted_xml['genres'], 'studio': extracted_xml['studio'], 'full_title': row[17] } # On older versions of PMS, "clip" items were still classified as "movie" and had bad ratingKey values # Just make sure that the ratingKey is indeed an integer if str(row[2]).isdigit(): monitor_processing.write_session_history(session=session_history, import_metadata=session_history_metadata, is_import=True, import_ignore_interval=import_ignore_interval) else: logger.debug(u"PlexPy Importer :: Item has bad rating_key: %s" % str(row[2])) logger.debug(u"PlexPy Importer :: PlexWatch data import complete.") logger.debug(u"PlexPy Importer :: Re-enabling monitoring.") plexpy.initialize_scheduler()
def get_details(self, user_id=None, user=None): from plexpy import plextv default_return = {'user_id': 0, 'username': '******', 'friendly_name': 'Local', 'user_thumb': common.DEFAULT_USER_THUMB, 'email': '', 'is_home_user': 0, 'is_allow_sync': 0, 'is_restricted': 0, 'do_notify': 0, 'keep_history': 1 } if not user_id and not user: return default_return def get_user_details(user_id=user_id, user=user): monitor_db = database.MonitorDatabase() try: if str(user_id).isdigit(): query = 'SELECT user_id, username, friendly_name, thumb AS user_thumb, custom_avatar_url AS custom_thumb, ' \ 'email, is_home_user, is_allow_sync, is_restricted, do_notify, keep_history ' \ 'FROM users ' \ 'WHERE user_id = ? ' result = monitor_db.select(query, args=[user_id]) elif user: query = 'SELECT user_id, username, friendly_name, thumb AS user_thumb, custom_avatar_url AS custom_thumb, ' \ 'email, is_home_user, is_allow_sync, is_restricted, do_notify, keep_history ' \ 'FROM users ' \ 'WHERE username = ? ' result = monitor_db.select(query, args=[user]) else: result = [] except Exception as e: logger.warn(u"PlexPy Users :: Unable to execute database query for get_details: %s." % e) result = [] user_details = {} if result: for item in result: if item['friendly_name']: friendly_name = item['friendly_name'] else: friendly_name = item['username'] if item['custom_thumb'] and item['custom_thumb'] != item['user_thumb']: user_thumb = item['custom_thumb'] elif item['user_thumb']: user_thumb = item['user_thumb'] else: user_thumb = common.DEFAULT_USER_THUMB user_details = {'user_id': item['user_id'], 'username': item['username'], 'friendly_name': friendly_name, 'user_thumb': user_thumb, 'email': item['email'], 'is_home_user': item['is_home_user'], 'is_allow_sync': item['is_allow_sync'], 'is_restricted': item['is_restricted'], 'do_notify': item['do_notify'], 'keep_history': item['keep_history'] } return user_details user_details = get_user_details(user_id=user_id, user=user) if user_details: return user_details else: logger.warn(u"PlexPy Users :: Unable to retrieve user %s from database. Requesting user list refresh." % user_id if user_id else user) # Let's first refresh the user list to make sure the user isn't newly added and not in the db yet plextv.refresh_users() user_details = get_user_details(user_id=user_id, user=user) if user_details: return user_details else: logger.warn(u"PlexPy Users :: Unable to retrieve user %s from database. Returning 'Local' user." % user_id if user_id else user) # If there is no user data we must return something # Use "Local" user to retain compatibility with PlexWatch database value return default_return
def import_from_plexwatch(database=None, table_name=None, import_ignore_interval=0): try: connection = sqlite3.connect(database, timeout=20) connection.row_factory = sqlite3.Row except sqlite3.OperationalError: logger.error("PlexPy Importer :: Invalid filename.") return None except ValueError: logger.error("PlexPy Importer :: Invalid filename.") return None try: connection.execute("SELECT ratingKey from %s" % table_name) except sqlite3.OperationalError: logger.error("PlexPy Importer :: Database specified does not contain the required fields.") return None logger.debug(u"PlexPy Importer :: PlexWatch data import in progress...") logger.debug(u"PlexPy Importer :: Disabling monitoring while import in progress.") plexpy.schedule_job( activity_pinger.check_active_sessions, "Check for active sessions", hours=0, minutes=0, seconds=0 ) ap = activity_processor.ActivityProcessor() user_data = users.Users() # Get the latest friends list so we can pull user id's try: plextv.refresh_users() except: logger.debug(u"PlexPy Importer :: Unable to refresh the users list. Aborting import.") return None query = ( "SELECT time AS started, " "stopped, " "cast(ratingKey as text) AS rating_key, " "null AS user_id, " "user, " "ip_address, " "paused_counter, " "platform AS player, " "null AS platform, " "null as machine_id, " "parentRatingKey as parent_rating_key, " "grandparentRatingKey as grandparent_rating_key, " "null AS media_type, " "null AS view_offset, " "xml, " "rating as content_rating," "summary," "title AS full_title," '(case when orig_title_ep = "" then orig_title else ' "orig_title_ep end) as title," '(case when orig_title_ep != "" then orig_title else ' "null end) as grandparent_title " "FROM " + table_name + " ORDER BY id" ) result = connection.execute(query) for row in result: # Extract the xml from the Plexwatch db xml field. extracted_xml = extract_plexwatch_xml(row["xml"]) # If we get back None from our xml extractor skip over the record and log error. if not extracted_xml: logger.error( u"PlexPy Importer :: Skipping line with ratingKey %s due to malformed xml." % str(row["rating_key"]) ) continue # If the user_id no longer exists in the friends list, pull it from the xml. if user_data.get_user_id(user=row["user"]): user_id = user_data.get_user_id(user=row["user"]) else: user_id = extracted_xml["user_id"] session_history = { "started": row["started"], "stopped": row["stopped"], "rating_key": row["rating_key"], "title": row["title"], "parent_title": extracted_xml["parent_title"], "grandparent_title": row["grandparent_title"], "user_id": user_id, "user": row["user"], "ip_address": row["ip_address"], "paused_counter": row["paused_counter"], "player": row["player"], "platform": extracted_xml["platform"], "machine_id": extracted_xml["machine_id"], "parent_rating_key": row["parent_rating_key"], "grandparent_rating_key": row["grandparent_rating_key"], "media_type": extracted_xml["media_type"], "view_offset": extracted_xml["view_offset"], "video_decision": extracted_xml["video_decision"], "audio_decision": extracted_xml["audio_decision"], "duration": extracted_xml["duration"], "width": extracted_xml["width"], "height": extracted_xml["height"], "container": extracted_xml["container"], "video_codec": extracted_xml["video_codec"], "audio_codec": extracted_xml["audio_codec"], "bitrate": extracted_xml["bitrate"], "video_resolution": extracted_xml["video_resolution"], "video_framerate": extracted_xml["video_framerate"], "aspect_ratio": extracted_xml["aspect_ratio"], "audio_channels": extracted_xml["audio_channels"], "transcode_protocol": extracted_xml["transcode_protocol"], "transcode_container": extracted_xml["transcode_container"], "transcode_video_codec": extracted_xml["transcode_video_codec"], "transcode_audio_codec": extracted_xml["transcode_audio_codec"], "transcode_audio_channels": extracted_xml["transcode_audio_channels"], "transcode_width": extracted_xml["transcode_width"], "transcode_height": extracted_xml["transcode_height"], } session_history_metadata = { "rating_key": helpers.latinToAscii(row["rating_key"]), "parent_rating_key": row["parent_rating_key"], "grandparent_rating_key": row["grandparent_rating_key"], "title": row["title"], "parent_title": extracted_xml["parent_title"], "grandparent_title": row["grandparent_title"], "index": extracted_xml["media_index"], "parent_index": extracted_xml["parent_media_index"], "thumb": extracted_xml["thumb"], "parent_thumb": extracted_xml["parent_thumb"], "grandparent_thumb": extracted_xml["grandparent_thumb"], "art": extracted_xml["art"], "media_type": extracted_xml["media_type"], "year": extracted_xml["year"], "originally_available_at": extracted_xml["originally_available_at"], "added_at": extracted_xml["added_at"], "updated_at": extracted_xml["updated_at"], "last_viewed_at": extracted_xml["last_viewed_at"], "content_rating": row["content_rating"], "summary": row["summary"], "tagline": extracted_xml["tagline"], "rating": extracted_xml["rating"], "duration": extracted_xml["duration"], "guid": extracted_xml["guid"], "directors": extracted_xml["directors"], "writers": extracted_xml["writers"], "actors": extracted_xml["actors"], "genres": extracted_xml["genres"], "studio": extracted_xml["studio"], "full_title": row["full_title"], } # On older versions of PMS, "clip" items were still classified as "movie" and had bad ratingKey values # Just make sure that the ratingKey is indeed an integer if session_history_metadata["rating_key"].isdigit(): ap.write_session_history( session=session_history, import_metadata=session_history_metadata, is_import=True, import_ignore_interval=import_ignore_interval, ) else: logger.debug(u"PlexPy Importer :: Item has bad rating_key: %s" % session_history_metadata["rating_key"]) logger.debug(u"PlexPy Importer :: PlexWatch data import complete.") import_users() logger.debug(u"PlexPy Importer :: Re-enabling monitoring.") plexpy.initialize_scheduler()