def on_start(self): if self.is_valid_session() and self.get_live_session(): logger.debug(u"PlexPy ActivityHandler :: Session %s has started." % str(self.get_session_key())) session = self.get_live_session() # Check if any notification agents have notifications enabled if any(d['on_play'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread(target=notification_handler.notify, kwargs=dict(stream_data=session, notify_action='play')).start() # Write the new session to our temp session table self.update_db_session(session=session) # Check if any notification agents have notifications enabled if any(d['on_concurrent'] for d in notifiers.available_notification_agents()): # Check if any concurrent streams by the user ip = True if plexpy.CONFIG.NOTIFY_CONCURRENT_BY_IP else None ap = activity_processor.ActivityProcessor() user_sessions = ap.get_session_by_user_id(user_id=session['user_id'], ip_address=ip) if len(user_sessions) >= plexpy.CONFIG.NOTIFY_CONCURRENT_THRESHOLD: # Push any notifications - Push it on it's own thread so we don't hold up our db actions threading.Thread(target=notification_handler.notify, kwargs=dict(stream_data=session, notify_action='concurrent')).start() # Check if any notification agents have notifications enabled if any(d['on_newdevice'] for d in notifiers.available_notification_agents()): # Check if any concurrent streams by the user data_factory = datafactory.DataFactory() user_devices = data_factory.get_user_devices(user_id=session['user_id']) if session['machine_id'] not in user_devices: # Push any notifications - Push it on it's own thread so we don't hold up our db actions threading.Thread(target=notification_handler.notify, kwargs=dict(stream_data=session, notify_action='newdevice')).start()
def on_buffer(self): if self.is_valid_session(): logger.debug(u"PlexPy ActivityHandler :: Session %s is buffering." % self.get_session_key()) ap = activity_processor.ActivityProcessor() db_stream = ap.get_session_by_key(session_key=self.get_session_key()) # Increment our buffer count ap.increment_session_buffer_count(session_key=self.get_session_key()) # Get our current buffer count current_buffer_count = ap.get_session_buffer_count(self.get_session_key()) logger.debug(u"PlexPy ActivityHandler :: Session %s buffer count is %s." % (self.get_session_key(), current_buffer_count)) # Get our last triggered time buffer_last_triggered = ap.get_session_buffer_trigger_time(self.get_session_key()) time_since_last_trigger = 0 if buffer_last_triggered: logger.debug(u"PlexPy ActivityHandler :: Session %s buffer last triggered at %s." % (self.get_session_key(), buffer_last_triggered)) time_since_last_trigger = int(time.time()) - int(buffer_last_triggered) if plexpy.CONFIG.BUFFER_THRESHOLD > 0 and (current_buffer_count >= plexpy.CONFIG.BUFFER_THRESHOLD and \ time_since_last_trigger == 0 or time_since_last_trigger >= plexpy.CONFIG.BUFFER_WAIT): ap.set_session_buffer_trigger_time(session_key=self.get_session_key()) # Check if any notification agents have notifications enabled if any(d['on_buffer'] for d in notifiers.available_notification_agents()): threading.Thread(target=notification_handler.notify, kwargs=dict(stream_data=db_stream, notify_action='buffer')).start()
def check_server_updates(): with monitor_lock: logger.info(u"PlexPy Monitor :: Checking for PMS updates...") pms_connect = pmsconnect.PmsConnect() server_identity = pms_connect.get_server_identity() update_status = pms_connect.get_update_staus() if server_identity and update_status: version = server_identity['version'] logger.info(u"PlexPy Monitor :: Current PMS version: %s", version) if update_status['state'] == 'available': update_version = update_status['version'] logger.info( u"PlexPy Monitor :: PMS update available version: %s", update_version) # Check if any notification agents have notifications enabled if any(d['on_pmsupdate'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread( target=notification_handler.notify_timeline, kwargs=dict(notify_action='pmsupdate')).start() else: logger.info(u"PlexPy Monitor :: No PMS update available.")
def check_server_updates(): with monitor_lock: logger.info(u"PlexPy Monitor :: Checking for PMS updates...") plex_tv = plextv.PlexTV() download_info = plex_tv.get_plex_downloads() if download_info: logger.info(u"PlexPy Monitor :: Current PMS version: %s", plexpy.CONFIG.PMS_VERSION) if download_info['update_available']: logger.info( u"PlexPy Monitor :: PMS update available version: %s", download_info['version']) # Check if any notification agents have notifications enabled if any(d['on_pmsupdate'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread( target=notification_handler.notify_timeline, kwargs=dict(notify_action='pmsupdate')).start() else: logger.info(u"PlexPy Monitor :: No PMS update available.")
def on_stop(self, force_stop=False): if self.is_valid_session(): logger.debug(u"PlexPy ActivityHandler :: Session %s has stopped." % str(self.get_session_key())) # Set the session last_paused timestamp ap = activity_processor.ActivityProcessor() ap.set_session_last_paused(session_key=self.get_session_key(), timestamp=None) # Update the session state and viewOffset # Set force_stop to true to disable the state set if not force_stop: ap.set_session_state(session_key=self.get_session_key(), state=self.timeline['state'], view_offset=self.timeline['viewOffset'], stopped=int(time.time())) # Retrieve the session data from our temp table db_session = ap.get_session_by_key(session_key=self.get_session_key()) # Check if any notification agents have notifications enabled if any(d['on_stop'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread(target=notification_handler.notify, kwargs=dict(stream_data=db_session, notify_action='stop')).start() # Write it to the history table monitor_proc = activity_processor.ActivityProcessor() monitor_proc.write_session_history(session=db_session) # Remove the session from our temp session table logger.debug(u"PlexPy ActivityHandler :: Removing session %s from session queue" % str(self.get_session_key())) ap.delete_session(session_key=self.get_session_key())
def on_resume(self): if self.is_valid_session(): logger.debug( u"PlexPy ActivityHandler :: Session %s has been resumed." % str(self.get_session_key())) # Set the session last_paused timestamp ap = activity_processor.ActivityProcessor() ap.set_session_last_paused(session_key=self.get_session_key(), timestamp=None) # Update the session state and viewOffset ap.set_session_state(session_key=self.get_session_key(), state=self.timeline['state'], view_offset=self.timeline['viewOffset']) # Retrieve the session data from our temp table db_session = ap.get_session_by_key( session_key=self.get_session_key()) # Check if any notification agents have notifications enabled if any(d['on_resume'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread(target=notification_handler.notify, kwargs=dict(stream_data=db_session, notify_action='resume')).start()
def check_server_updates(): with monitor_lock: logger.info(u"PlexPy Monitor :: Checking for PMS updates...") pms_connect = pmsconnect.PmsConnect() server_identity = pms_connect.get_server_identity() update_status = pms_connect.get_update_staus() if server_identity and update_status: version = server_identity['version'] logger.info(u"PlexPy Monitor :: Current PMS version: %s", version) if update_status['state'] == 'available': update_version = update_status['version'] logger.info(u"PlexPy Monitor :: PMS update available version: %s", update_version) # Check if any notification agents have notifications enabled if any(d['on_pmsupdate'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread(target=notification_handler.notify_timeline, kwargs=dict(notify_action='pmsupdate')).start() else: logger.info(u"PlexPy Monitor :: No PMS update available.")
def check_server_response(): with monitor_lock: pms_connect = pmsconnect.PmsConnect() server_response = pms_connect.get_server_response() global ext_ping_count # Check for remote access if server_response: mapping_state = server_response['mapping_state'] mapping_error = server_response['mapping_error'] # Check if the port is mapped if not mapping_state == 'mapped': ext_ping_count += 1 logger.warn(u"PlexPy Monitor :: Plex remote access port not mapped, ping attempt %s." \ % str(ext_ping_count)) # Check if the port is open elif mapping_error == 'unreachable': ext_ping_count += 1 logger.warn(u"PlexPy Monitor :: Plex remote access port mapped, but mapping failed, ping attempt %s." \ % str(ext_ping_count)) # Reset external ping counter else: if ext_ping_count >= 3: logger.info( u"PlexPy Monitor :: Plex remote access is back up.") # Check if any notification agents have notifications enabled if any(d['on_extup'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread( target=notification_handler.notify_timeline, kwargs=dict(notify_action='extup')).start() ext_ping_count = 0 if ext_ping_count == 3: # Check if any notification agents have notifications enabled if any(d['on_extdown'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread(target=notification_handler.notify_timeline, kwargs=dict(notify_action='extdown')).start()
def process(self): if self.is_valid_session(): ap = activity_processor.ActivityProcessor() db_session = ap.get_session_by_key(session_key=self.get_session_key()) this_state = self.timeline['state'] this_key = str(self.timeline['ratingKey']) # If we already have this session in the temp table, check for state changes if db_session: last_state = db_session['state'] last_key = str(db_session['rating_key']) # Make sure the same item is being played if this_key == last_key: # Update the session state and viewOffset if this_state == 'playing': ap.set_session_state(session_key=self.get_session_key(), state=this_state, view_offset=self.timeline['viewOffset']) # Start our state checks if this_state != last_state: if this_state == 'paused': self.on_pause() elif last_state == 'paused' and this_state == 'playing': self.on_resume() elif this_state == 'stopped': self.on_stop() elif this_state == 'buffering': self.on_buffer() # If a client doesn't register stop events (I'm looking at you PHT!) check if the ratingKey has changed else: # Manually stop and start # Set force_stop so that we don't overwrite our last viewOffset self.on_stop(force_stop=True) self.on_start() # Monitor if the stream has reached the watch percentage for notifications # The only purpose of this is for notifications # Check if any notification agents have notifications enabled notify_agents = [d['id'] for d in notifiers.available_notification_agents() if d['on_watched']] # Get the current states for notifications from our db notified_agents = [d['agent_id'] for d in notification_handler.get_notify_state(session=db_session) if d['notify_action'] == 'watched'] if notify_agents else [] if any(a not in notified_agents for a in notify_agents): progress_percent = helpers.get_percent(self.timeline['viewOffset'], db_session['duration']) if progress_percent >= plexpy.CONFIG.NOTIFY_WATCHED_PERCENT and this_state != 'buffering': # Rather not put this on it's own thread so we know it completes before our next event. notification_handler.notify(stream_data=db_session, notify_action='watched') else: # We don't have this session in our table yet, start a new one. if this_state != 'buffering': self.on_start()
def check_server_response(): with monitor_lock: pms_connect = pmsconnect.PmsConnect() server_response = pms_connect.get_server_response() global ext_ping_count # Check for remote access if server_response: mapping_state = server_response['mapping_state'] mapping_error = server_response['mapping_error'] # Check if the port is mapped if not mapping_state == 'mapped': ext_ping_count += 1 logger.warn(u"PlexPy Monitor :: Plex remote access port not mapped, ping attempt %s." \ % str(ext_ping_count)) # Check if the port is open elif mapping_error == 'unreachable': ext_ping_count += 1 logger.warn(u"PlexPy Monitor :: Plex remote access port mapped, but mapping failed, ping attempt %s." \ % str(ext_ping_count)) # Reset external ping counter else: if ext_ping_count >= 3: logger.info(u"PlexPy Monitor :: Plex remote access is back up.") # Check if any notification agents have notifications enabled if any(d['on_extup'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread(target=notification_handler.notify_timeline, kwargs=dict(notify_action='extup')).start() ext_ping_count = 0 if ext_ping_count == 3: # Check if any notification agents have notifications enabled if any(d['on_extdown'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread(target=notification_handler.notify_timeline, kwargs=dict(notify_action='extdown')).start()
def on_start(self): if self.is_valid_session() and self.get_live_session(): logger.debug(u"PlexPy ActivityHandler :: Session %s has started." % str(self.get_session_key())) # Check if any notification agents have notifications enabled if any(d['on_play'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread(target=notification_handler.notify, kwargs=dict(stream_data=self.get_live_session(), notify_action='play')).start() # Write the new session to our temp session table self.update_db_session()
def on_start(self): if self.is_valid_session() and self.get_live_session(): logger.debug(u"PlexPy ActivityHandler :: Session %s has started." % str(self.get_session_key())) # Check if any notification agents have notifications enabled if any(d['on_play'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread(target=notification_handler.notify, kwargs=dict( stream_data=self.get_live_session(), notify_action='play')).start() # Write the new session to our temp session table self.update_db_session()
def on_resume(self): if self.is_valid_session(): logger.debug(u"PlexPy ActivityHandler :: Session %s has been resumed." % str(self.get_session_key())) # Set the session last_paused timestamp ap = activity_processor.ActivityProcessor() ap.set_session_last_paused(session_key=self.get_session_key(), timestamp=None) # Update the session state and viewOffset ap.set_session_state(session_key=self.get_session_key(), state=self.timeline['state'], view_offset=self.timeline['viewOffset']) # Retrieve the session data from our temp table db_session = ap.get_session_by_key(session_key=self.get_session_key()) # Check if any notification agents have notifications enabled if any(d['on_resume'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread(target=notification_handler.notify, kwargs=dict(stream_data=db_session, notify_action='resume')).start()
def check_server_updates(): with monitor_lock: logger.info(u"PlexPy Monitor :: Checking for PMS updates...") plex_tv = plextv.PlexTV() download_info = plex_tv.get_plex_downloads() if download_info: logger.info(u"PlexPy Monitor :: Current PMS version: %s", plexpy.CONFIG.PMS_VERSION) if download_info['update_available']: logger.info(u"PlexPy Monitor :: PMS update available version: %s", download_info['version']) # Check if any notification agents have notifications enabled if any(d['on_pmsupdate'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread(target=notification_handler.notify_timeline, kwargs=dict(notify_action='pmsupdate')).start() else: logger.info(u"PlexPy Monitor :: No PMS update available.")
def write_session(self, session=None, notify=True): if session: values = { 'session_key': session['session_key'], 'transcode_key': session['transcode_key'], 'section_id': session['section_id'], 'rating_key': session['rating_key'], 'media_type': session['media_type'], 'state': session['state'], 'user_id': session['user_id'], 'user': session['user'], 'machine_id': session['machine_id'], 'title': session['title'], 'parent_title': session['parent_title'], 'grandparent_title': session['grandparent_title'], 'full_title': session['full_title'], 'media_index': session['media_index'], 'parent_media_index': session['parent_media_index'], 'thumb': session['thumb'], 'parent_thumb': session['parent_thumb'], 'grandparent_thumb': session['grandparent_thumb'], 'year': session['year'], 'friendly_name': session['friendly_name'], #'ip_address': session['ip_address'], 'player': session['player'], 'platform': session['platform'], 'parent_rating_key': session['parent_rating_key'], 'grandparent_rating_key': session['grandparent_rating_key'], 'view_offset': session['view_offset'], 'duration': session['duration'], 'video_decision': session['video_decision'], 'audio_decision': session['audio_decision'], 'transcode_decision': session['transcode_decision'], 'width': session['width'], 'height': session['height'], 'container': session['container'], 'video_codec': session['video_codec'], 'audio_codec': session['audio_codec'], 'bitrate': session['bitrate'], 'video_resolution': session['video_resolution'], 'video_framerate': session['video_framerate'], 'aspect_ratio': session['aspect_ratio'], 'audio_channels': session['audio_channels'], 'transcode_protocol': session['transcode_protocol'], 'transcode_container': session['transcode_container'], 'transcode_video_codec': session['transcode_video_codec'], 'transcode_audio_codec': session['transcode_audio_codec'], 'transcode_audio_channels': session['transcode_audio_channels'], 'transcode_width': session['transcode_width'], 'transcode_height': session['transcode_height'], 'stopped': None } # Add ip_address back into values if session['ip_address']: values.update({'ip_address': session['ip_address']}) keys = { 'session_key': session['session_key'], 'rating_key': session['rating_key'] } result = self.db.upsert('sessions', values, keys) if result == 'insert': # Check if any notification agents have notifications enabled if notify and any( d['on_play'] for d in notifiers.available_notification_agents()): values.update({'ip_address': session['ip_address']}) # Push any notifications - Push it on it's own thread so we don't hold up our db actions threading.Thread(target=notification_handler.notify, kwargs=dict( stream_data=values, notify_action='play')).start() # If it's our first write then time stamp it. started = int(time.time()) timestamp = {'started': started} self.db.upsert('sessions', timestamp, keys) # Try and grab IP address from logs (fallback if not on PMS 0.9.14 and above) if not session['ip_address']: if plexpy.CONFIG.IP_LOGGING_ENABLE and plexpy.CONFIG.PMS_LOGS_FOLDER: ip_address = self.find_session_ip( rating_key=session['rating_key'], machine_id=session['machine_id']) ip_address = {'ip_address': ip_address} self.db.upsert('sessions', ip_address, keys) # Check if any notification agents have notifications enabled if notify and any( d['on_concurrent'] for d in notifiers.available_notification_agents()): # Check if any concurrent streams by the user user_sessions = self.get_session_by_user_id( user_id=session['user_id'], ip_address=plexpy.CONFIG.NOTIFY_CONCURRENT_BY_IP) if len(user_sessions ) >= plexpy.CONFIG.NOTIFY_CONCURRENT_THRESHOLD: # Push any notifications - Push it on it's own thread so we don't hold up our db actions concurrent_users = "" for session in user_sessions: if session: concurrent_users += session['user'] + ", " values.update({'concurrent_users': concurrent_users}) values.update( {'concurrent_users_streams': len(user_sessions)}) #logger.info("concurrent_users = %s", values['concurrent_users']) #logger.info("concurrent users count = %s", values['concurrent_users_streams']) # Push any notifications - Push it on it's own thread so we don't hold up our db actions threading.Thread( target=notification_handler.notify, kwargs=dict(stream_data=values, notify_action='concurrent')).start() # Check if any notification agents have notifications enabled if notify and any( d['on_newdevice'] for d in notifiers.available_notification_agents()): # Check if any concurrent streams by the user data_factory = datafactory.DataFactory() user_devices = data_factory.get_user_devices( user_id=session['user_id']) if session['machine_id'] not in user_devices: # Push any notifications - Push it on it's own thread so we don't hold up our db actions threading.Thread( target=notification_handler.notify, kwargs=dict(stream_data=values, notify_action='newdevice')).start() return True
def write_session(self, session=None, notify=True): if session: values = { 'session_key': session['session_key'], 'transcode_key': session['transcode_key'], 'section_id': session['section_id'], 'rating_key': session['rating_key'], 'media_type': session['media_type'], 'state': session['state'], 'user_id': session['user_id'], 'user': session['user'], 'machine_id': session['machine_id'], 'title': session['title'], 'parent_title': session['parent_title'], 'grandparent_title': session['grandparent_title'], 'friendly_name': session['friendly_name'], #'ip_address': session['ip_address'], 'player': session['player'], 'platform': session['platform'], 'parent_rating_key': session['parent_rating_key'], 'grandparent_rating_key': session['grandparent_rating_key'], 'view_offset': session['view_offset'], 'duration': session['duration'], 'video_decision': session['video_decision'], 'audio_decision': session['audio_decision'], 'width': session['width'], 'height': session['height'], 'container': session['container'], 'video_codec': session['video_codec'], 'audio_codec': session['audio_codec'], 'bitrate': session['bitrate'], 'video_resolution': session['video_resolution'], 'video_framerate': session['video_framerate'], 'aspect_ratio': session['aspect_ratio'], 'audio_channels': session['audio_channels'], 'transcode_protocol': session['transcode_protocol'], 'transcode_container': session['transcode_container'], 'transcode_video_codec': session['transcode_video_codec'], 'transcode_audio_codec': session['transcode_audio_codec'], 'transcode_audio_channels': session['transcode_audio_channels'], 'transcode_width': session['transcode_width'], 'transcode_height': session['transcode_height'] } # Add ip_address back into values if session['ip_address']: values.update({'ip_address': session['ip_address']}) keys = { 'session_key': session['session_key'], 'rating_key': session['rating_key'] } result = self.db.upsert('sessions', values, keys) if result == 'insert': # Check if any notification agents have notifications enabled if notify and any( d['on_play'] for d in notifiers.available_notification_agents()): values.update({'ip_address': session['ip_address']}) # Push any notifications - Push it on it's own thread so we don't hold up our db actions threading.Thread(target=notification_handler.notify, kwargs=dict( stream_data=values, notify_action='play')).start() # If it's our first write then time stamp it. started = int(time.time()) timestamp = {'started': started} self.db.upsert('sessions', timestamp, keys) # Try and grab IP address from logs (fallback if not on PMS 0.9.14 and above) if not session['ip_address']: if plexpy.CONFIG.IP_LOGGING_ENABLE and plexpy.CONFIG.PMS_LOGS_FOLDER: ip_address = self.find_session_ip( rating_key=session['rating_key'], machine_id=session['machine_id']) ip_address = {'ip_address': ip_address} self.db.upsert('sessions', ip_address, keys) return True
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') library_data = libraries.Libraries() if recently_added_list: recently_added = recently_added_list['recently_added'] for item in recently_added: library_details = library_data.get_details( section_id=item['section_id']) if not library_details['do_notify_created']: continue 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: library_details = library_data.get_details( section_id=item['section_id']) 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'])) # Check if any notification agents have notifications enabled if any(d['on_created'] for d in notifiers. available_notification_agents()): # 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'])) # Check if any notification agents have notifications enabled if any(d['on_created'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread( target=notification_handler. notify_timeline, kwargs=dict( timeline_data=item, notify_action='created')).start()
def check_active_sessions(ws_request=False): with monitor_lock: pms_connect = pmsconnect.PmsConnect() session_list = pms_connect.get_current_activity() monitor_db = database.MonitorDatabase() monitor_process = activity_processor.ActivityProcessor() # logger.debug(u"PlexPy Monitor :: Checking for active streams.") global int_ping_count if session_list: if int_ping_count >= 3: logger.info( u"PlexPy Monitor :: The Plex Media Server is back up.") # Check if any notification agents have notifications enabled if any(d['on_intup'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread( target=notification_handler.notify_timeline, kwargs=dict(notify_action='intup')).start() int_ping_count = 0 media_container = session_list['sessions'] # Check our temp table for what we must do with the new streams db_streams = monitor_db.select('SELECT * FROM sessions') for stream in db_streams: if any(d['session_key'] == str(stream['session_key']) and d['rating_key'] == str(stream['rating_key']) for d in media_container): # The user's session is still active for session in media_container: if session['session_key'] == str(stream['session_key']) and \ session['rating_key'] == str(stream['rating_key']): # The user is still playing the same media item # Here we can check the play states if session['state'] != stream['state']: if session['state'] == 'paused': logger.debug( u"PlexPy Monitor :: Session %s has been paused." % stream['session_key']) # Check if any notification agents have notifications enabled if any(d['on_pause'] for d in notifiers. available_notification_agents()): # Push any notifications - # Push it on it's own thread so we don't hold up our db actions threading.Thread( target=notification_handler.notify, kwargs=dict(stream_data=stream, notify_action='pause' )).start() if session['state'] == 'playing' and stream[ 'state'] == 'paused': logger.debug( u"PlexPy Monitor :: Session %s has been resumed." % stream['session_key']) # Check if any notification agents have notifications enabled if any(d['on_resume'] for d in notifiers. available_notification_agents()): # Push any notifications - # Push it on it's own thread so we don't hold up our db actions threading.Thread( target=notification_handler.notify, kwargs=dict(stream_data=stream, notify_action='resume' )).start() if stream['state'] == 'paused' and not ws_request: # The stream is still paused so we need to increment the paused_counter # Using the set config parameter as the interval, probably not the most accurate but # it will have to do for now. If it's a websocket request don't use this method. paused_counter = int( stream['paused_counter'] ) + plexpy.CONFIG.MONITORING_INTERVAL monitor_db.action( 'UPDATE sessions SET paused_counter = ? ' 'WHERE session_key = ? AND rating_key = ?', [ paused_counter, stream['session_key'], stream['rating_key'] ]) if session[ 'state'] == 'buffering' and plexpy.CONFIG.BUFFER_THRESHOLD > 0: # The stream is buffering so we need to increment the buffer_count # We're going just increment on every monitor ping, # would be difficult to keep track otherwise monitor_db.action( 'UPDATE sessions SET buffer_count = buffer_count + 1 ' 'WHERE session_key = ? AND rating_key = ?', [ stream['session_key'], stream['rating_key'] ]) # Check the current buffer count and last buffer to determine if we should notify buffer_values = monitor_db.select( 'SELECT buffer_count, buffer_last_triggered ' 'FROM sessions ' 'WHERE session_key = ? AND rating_key = ?', [ stream['session_key'], stream['rating_key'] ]) if buffer_values[0][ 'buffer_count'] >= plexpy.CONFIG.BUFFER_THRESHOLD: # Push any notifications - # Push it on it's own thread so we don't hold up our db actions # Our first buffer notification if buffer_values[0][ 'buffer_count'] == plexpy.CONFIG.BUFFER_THRESHOLD: logger.info( u"PlexPy Monitor :: User '%s' has triggered a buffer warning." % stream['user']) # Set the buffer trigger time monitor_db.action( 'UPDATE sessions ' 'SET buffer_last_triggered = strftime("%s","now") ' 'WHERE session_key = ? AND rating_key = ?', [ stream['session_key'], stream['rating_key'] ]) # Check if any notification agents have notifications enabled if any(d['on_buffer'] for d in notifiers. available_notification_agents( )): # Push any notifications - # Push it on it's own thread so we don't hold up our db actions threading.Thread( target=notification_handler. notify, kwargs=dict( stream_data=stream, notify_action='buffer' )).start() else: # Subsequent buffer notifications after wait time if int(time.time()) > buffer_values[0]['buffer_last_triggered'] + \ plexpy.CONFIG.BUFFER_WAIT: logger.info( u"PlexPy Monitor :: User '%s' has triggered multiple buffer warnings." % stream['user']) # Set the buffer trigger time monitor_db.action( 'UPDATE sessions ' 'SET buffer_last_triggered = strftime("%s","now") ' 'WHERE session_key = ? AND rating_key = ?', [ stream['session_key'], stream['rating_key'] ]) # Check if any notification agents have notifications enabled if any(d['on_buffer'] for d in notifiers. available_notification_agents( )): # Push any notifications - # Push it on it's own thread so we don't hold up our db actions threading.Thread( target=notification_handler .notify, kwargs=dict( stream_data=stream, notify_action='buffer' )).start() logger.debug( u"PlexPy Monitor :: Session %s is buffering. Count is now %s. Last triggered %s." % (stream['session_key'], buffer_values[0]['buffer_count'], buffer_values[0]['buffer_last_triggered']) ) # Check if the user has reached the offset in the media we defined as the "watched" percent # Don't trigger if state is buffer as some clients push the progress to the end when # buffering on start. if session['view_offset'] and session[ 'duration'] and session[ 'state'] != 'buffering': if helpers.get_percent( session['view_offset'], session['duration'] ) > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT: # Check if any notification agents have notifications enabled if any(d['on_watched'] for d in notifiers. available_notification_agents()): # Push any notifications - # Push it on it's own thread so we don't hold up our db actions threading.Thread( target=notification_handler.notify, kwargs=dict(stream_data=stream, notify_action='watched' )).start() else: # The user has stopped playing a stream if stream['state'] != 'stopped': logger.debug( u"PlexPy Monitor :: Session %s has stopped." % stream['session_key']) # Set the stream stop time stream['stopped'] = int(time.time()) monitor_db.action( 'UPDATE sessions SET stopped = ?, state = ? ' 'WHERE session_key = ? AND rating_key = ?', [ stream['stopped'], 'stopped', stream['session_key'], stream['rating_key'] ]) # Check if the user has reached the offset in the media we defined as the "watched" percent if stream['view_offset'] and stream['duration']: if helpers.get_percent( stream['view_offset'], stream['duration'] ) > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT: # Check if any notification agents have notifications enabled if any(d['on_watched'] for d in notifiers. available_notification_agents()): # Push any notifications - # Push it on it's own thread so we don't hold up our db actions threading.Thread( target=notification_handler.notify, kwargs=dict( stream_data=stream, notify_action='watched')).start() # Check if any notification agents have notifications enabled if any(d['on_stop'] for d in notifiers.available_notification_agents()): # Push any notifications - Push it on it's own thread so we don't hold up our db actions threading.Thread( target=notification_handler.notify, kwargs=dict(stream_data=stream, notify_action='stop')).start() # Write the item history on playback stop success = monitor_process.write_session_history( session=stream) if success: # If session is written to the databaase successfully, remove the session from the session table logger.debug( u"PlexPy Monitor :: Removing sessionKey %s ratingKey %s from session queue" % (stream['session_key'], stream['rating_key'])) monitor_db.action( 'DELETE FROM sessions WHERE session_key = ? AND rating_key = ?', [stream['session_key'], stream['rating_key']]) else: stream['write_attempts'] += 1 if stream[ 'write_attempts'] < plexpy.CONFIG.SESSION_DB_WRITE_ATTEMPTS: logger.warn(u"PlexPy Monitor :: Failed to write sessionKey %s ratingKey %s to the database. " \ "Will try again on the next pass. Write attempt %s." % (stream['session_key'], stream['rating_key'], str(stream['write_attempts']))) monitor_db.action( 'UPDATE sessions SET write_attempts = ? ' 'WHERE session_key = ? AND rating_key = ?', [ stream['write_attempts'], stream['session_key'], stream['rating_key'] ]) else: logger.warn(u"PlexPy Monitor :: Failed to write sessionKey %s ratingKey %s to the database. " \ "Removing session from the database. Write attempt %s." % (stream['session_key'], stream['rating_key'], str(stream['write_attempts']))) logger.debug( u"PlexPy Monitor :: Removing sessionKey %s ratingKey %s from session queue" % (stream['session_key'], stream['rating_key'])) monitor_db.action( 'DELETE FROM sessions WHERE session_key = ? AND rating_key = ?', [stream['session_key'], stream['rating_key']]) # Process the newly received session data for session in media_container: new_session = monitor_process.write_session(session) if new_session: logger.debug( u"PlexPy Monitor :: Session %s has started with ratingKey %s." % (session['session_key'], session['rating_key'])) else: logger.debug(u"PlexPy Monitor :: Unable to read session list.") int_ping_count += 1 logger.warn(u"PlexPy Monitor :: Unable to get an internal response from the server, ping attempt %s." \ % str(int_ping_count)) if int_ping_count == 3: # Check if any notification agents have notifications enabled if any(d['on_intdown'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread(target=notification_handler.notify_timeline, kwargs=dict(notify_action='intdown')).start()
def write_session(self, session=None, notify=True): if session: values = {'session_key': session['session_key'], 'transcode_key': session['transcode_key'], 'section_id': session['section_id'], 'rating_key': session['rating_key'], 'media_type': session['media_type'], 'state': session['state'], 'user_id': session['user_id'], 'user': session['user'], 'machine_id': session['machine_id'], 'title': session['title'], 'parent_title': session['parent_title'], 'grandparent_title': session['grandparent_title'], 'friendly_name': session['friendly_name'], #'ip_address': session['ip_address'], 'player': session['player'], 'platform': session['platform'], 'parent_rating_key': session['parent_rating_key'], 'grandparent_rating_key': session['grandparent_rating_key'], 'view_offset': session['view_offset'], 'duration': session['duration'], 'video_decision': session['video_decision'], 'audio_decision': session['audio_decision'], 'width': session['width'], 'height': session['height'], 'container': session['container'], 'video_codec': session['video_codec'], 'audio_codec': session['audio_codec'], 'bitrate': session['bitrate'], 'video_resolution': session['video_resolution'], 'video_framerate': session['video_framerate'], 'aspect_ratio': session['aspect_ratio'], 'audio_channels': session['audio_channels'], 'transcode_protocol': session['transcode_protocol'], 'transcode_container': session['transcode_container'], 'transcode_video_codec': session['transcode_video_codec'], 'transcode_audio_codec': session['transcode_audio_codec'], 'transcode_audio_channels': session['transcode_audio_channels'], 'transcode_width': session['transcode_width'], 'transcode_height': session['transcode_height'] } # Add ip_address back into values if session['ip_address']: values.update({'ip_address': session['ip_address']}) keys = {'session_key': session['session_key'], 'rating_key': session['rating_key']} result = self.db.upsert('sessions', values, keys) if result == 'insert': # Check if any notification agents have notifications enabled if notify and any(d['on_play'] for d in notifiers.available_notification_agents()): values.update({'ip_address': session['ip_address']}) # Push any notifications - Push it on it's own thread so we don't hold up our db actions threading.Thread(target=notification_handler.notify, kwargs=dict(stream_data=values, notify_action='play')).start() # If it's our first write then time stamp it. started = int(time.time()) timestamp = {'started': started} self.db.upsert('sessions', timestamp, keys) # Try and grab IP address from logs (fallback if not on PMS 0.9.14 and above) if not session['ip_address']: if plexpy.CONFIG.IP_LOGGING_ENABLE and plexpy.CONFIG.PMS_LOGS_FOLDER: ip_address = self.find_session_ip(rating_key=session['rating_key'], machine_id=session['machine_id']) ip_address = {'ip_address': ip_address} self.db.upsert('sessions', ip_address, keys) return True
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') library_data = libraries.Libraries() if recently_added_list: recently_added = recently_added_list['recently_added'] for item in recently_added: library_details = library_data.get_details(section_id=item['section_id']) if not library_details['do_notify_created']: continue 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: library_details = library_data.get_details(section_id=item['section_id']) 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'])) # Check if any notification agents have notifications enabled if any(d['on_created'] for d in notifiers.available_notification_agents()): # 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'])) # Check if any notification agents have notifications enabled if any(d['on_created'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread(target=notification_handler.notify_timeline, kwargs=dict(timeline_data=item, notify_action='created')).start()
def check_active_sessions(ws_request=False): with monitor_lock: pms_connect = pmsconnect.PmsConnect() session_list = pms_connect.get_current_activity() monitor_db = database.MonitorDatabase() monitor_process = activity_processor.ActivityProcessor() # logger.debug(u"PlexPy Monitor :: Checking for active streams.") global int_ping_count if session_list: if int_ping_count >= 3: logger.info(u"PlexPy Monitor :: The Plex Media Server is back up.") # Check if any notification agents have notifications enabled if any(d['on_intup'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread(target=notification_handler.notify_timeline, kwargs=dict(notify_action='intup')).start() int_ping_count = 0 media_container = session_list['sessions'] # Check our temp table for what we must do with the new streams db_streams = monitor_db.select('SELECT * FROM sessions') for stream in db_streams: if any(d['session_key'] == str(stream['session_key']) and d['rating_key'] == str(stream['rating_key']) for d in media_container): # The user's session is still active for session in media_container: if session['session_key'] == str(stream['session_key']) and \ session['rating_key'] == str(stream['rating_key']): # The user is still playing the same media item # Here we can check the play states if session['state'] != stream['state']: if session['state'] == 'paused': logger.debug(u"PlexPy Monitor :: Session %s has been paused." % stream['session_key']) # Check if any notification agents have notifications enabled if any(d['on_pause'] for d in notifiers.available_notification_agents()): # Push any notifications - # Push it on it's own thread so we don't hold up our db actions threading.Thread(target=notification_handler.notify, kwargs=dict(stream_data=stream, notify_action='pause')).start() if session['state'] == 'playing' and stream['state'] == 'paused': logger.debug(u"PlexPy Monitor :: Session %s has been resumed." % stream['session_key']) # Check if any notification agents have notifications enabled if any(d['on_resume'] for d in notifiers.available_notification_agents()): # Push any notifications - # Push it on it's own thread so we don't hold up our db actions threading.Thread(target=notification_handler.notify, kwargs=dict(stream_data=stream, notify_action='resume')).start() if stream['state'] == 'paused' and not ws_request: # The stream is still paused so we need to increment the paused_counter # Using the set config parameter as the interval, probably not the most accurate but # it will have to do for now. If it's a websocket request don't use this method. paused_counter = int(stream['paused_counter']) + plexpy.CONFIG.MONITORING_INTERVAL monitor_db.action('UPDATE sessions SET paused_counter = ? ' 'WHERE session_key = ? AND rating_key = ?', [paused_counter, stream['session_key'], stream['rating_key']]) if session['state'] == 'buffering' and plexpy.CONFIG.BUFFER_THRESHOLD > 0: # The stream is buffering so we need to increment the buffer_count # We're going just increment on every monitor ping, # would be difficult to keep track otherwise monitor_db.action('UPDATE sessions SET buffer_count = buffer_count + 1 ' 'WHERE session_key = ? AND rating_key = ?', [stream['session_key'], stream['rating_key']]) # Check the current buffer count and last buffer to determine if we should notify buffer_values = monitor_db.select('SELECT buffer_count, buffer_last_triggered ' 'FROM sessions ' 'WHERE session_key = ? AND rating_key = ?', [stream['session_key'], stream['rating_key']]) if buffer_values[0]['buffer_count'] >= plexpy.CONFIG.BUFFER_THRESHOLD: # Push any notifications - # Push it on it's own thread so we don't hold up our db actions # Our first buffer notification if buffer_values[0]['buffer_count'] == plexpy.CONFIG.BUFFER_THRESHOLD: logger.info(u"PlexPy Monitor :: User '%s' has triggered a buffer warning." % stream['user']) # Set the buffer trigger time monitor_db.action('UPDATE sessions ' 'SET buffer_last_triggered = strftime("%s","now") ' 'WHERE session_key = ? AND rating_key = ?', [stream['session_key'], stream['rating_key']]) # Check if any notification agents have notifications enabled if any(d['on_buffer'] for d in notifiers.available_notification_agents()): # Push any notifications - # Push it on it's own thread so we don't hold up our db actions threading.Thread(target=notification_handler.notify, kwargs=dict(stream_data=stream, notify_action='buffer')).start() else: # Subsequent buffer notifications after wait time if int(time.time()) > buffer_values[0]['buffer_last_triggered'] + \ plexpy.CONFIG.BUFFER_WAIT: logger.info(u"PlexPy Monitor :: User '%s' has triggered multiple buffer warnings." % stream['user']) # Set the buffer trigger time monitor_db.action('UPDATE sessions ' 'SET buffer_last_triggered = strftime("%s","now") ' 'WHERE session_key = ? AND rating_key = ?', [stream['session_key'], stream['rating_key']]) # Check if any notification agents have notifications enabled if any(d['on_buffer'] for d in notifiers.available_notification_agents()): # Push any notifications - # Push it on it's own thread so we don't hold up our db actions threading.Thread(target=notification_handler.notify, kwargs=dict(stream_data=stream, notify_action='buffer')).start() logger.debug(u"PlexPy Monitor :: Session %s is buffering. Count is now %s. Last triggered %s." % (stream['session_key'], buffer_values[0]['buffer_count'], buffer_values[0]['buffer_last_triggered'])) # Check if the user has reached the offset in the media we defined as the "watched" percent # Don't trigger if state is buffer as some clients push the progress to the end when # buffering on start. if session['view_offset'] and session['duration'] and session['state'] != 'buffering': if helpers.get_percent(session['view_offset'], session['duration']) > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT: # Check if any notification agents have notifications enabled if any(d['on_watched'] for d in notifiers.available_notification_agents()): # Push any notifications - # Push it on it's own thread so we don't hold up our db actions threading.Thread(target=notification_handler.notify, kwargs=dict(stream_data=stream, notify_action='watched')).start() else: # The user has stopped playing a stream if stream['state'] != 'stopped': logger.debug(u"PlexPy Monitor :: Session %s has stopped." % stream['session_key']) # Set the stream stop time stream['stopped'] = int(time.time()) monitor_db.action('UPDATE sessions SET stopped = ?, state = ? ' 'WHERE session_key = ? AND rating_key = ?', [stream['stopped'], 'stopped', stream['session_key'], stream['rating_key']]) # Check if the user has reached the offset in the media we defined as the "watched" percent if stream['view_offset'] and stream['duration']: if helpers.get_percent(stream['view_offset'], stream['duration']) > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT: # Check if any notification agents have notifications enabled if any(d['on_watched'] for d in notifiers.available_notification_agents()): # Push any notifications - # Push it on it's own thread so we don't hold up our db actions threading.Thread(target=notification_handler.notify, kwargs=dict(stream_data=stream, notify_action='watched')).start() # Check if any notification agents have notifications enabled if any(d['on_stop'] for d in notifiers.available_notification_agents()): # Push any notifications - Push it on it's own thread so we don't hold up our db actions threading.Thread(target=notification_handler.notify, kwargs=dict(stream_data=stream, notify_action='stop')).start() # Write the item history on playback stop success = monitor_process.write_session_history(session=stream) if success: # If session is written to the databaase successfully, remove the session from the session table logger.debug(u"PlexPy Monitor :: Removing sessionKey %s ratingKey %s from session queue" % (stream['session_key'], stream['rating_key'])) monitor_db.action('DELETE FROM sessions WHERE session_key = ? AND rating_key = ?', [stream['session_key'], stream['rating_key']]) else: stream['write_attempts'] += 1 if stream['write_attempts'] < plexpy.CONFIG.SESSION_DB_WRITE_ATTEMPTS: logger.warn(u"PlexPy Monitor :: Failed to write sessionKey %s ratingKey %s to the database. " \ "Will try again on the next pass. Write attempt %s." % (stream['session_key'], stream['rating_key'], str(stream['write_attempts']))) monitor_db.action('UPDATE sessions SET write_attempts = ? ' 'WHERE session_key = ? AND rating_key = ?', [stream['write_attempts'], stream['session_key'], stream['rating_key']]) else: logger.warn(u"PlexPy Monitor :: Failed to write sessionKey %s ratingKey %s to the database. " \ "Removing session from the database. Write attempt %s." % (stream['session_key'], stream['rating_key'], str(stream['write_attempts']))) logger.debug(u"PlexPy Monitor :: Removing sessionKey %s ratingKey %s from session queue" % (stream['session_key'], stream['rating_key'])) monitor_db.action('DELETE FROM sessions WHERE session_key = ? AND rating_key = ?', [stream['session_key'], stream['rating_key']]) # Process the newly received session data for session in media_container: new_session = monitor_process.write_session(session) if new_session: logger.debug(u"PlexPy Monitor :: Session %s has started." % session['session_key']) else: logger.debug(u"PlexPy Monitor :: Unable to read session list.") int_ping_count += 1 logger.warn(u"PlexPy Monitor :: Unable to get an internal response from the server, ping attempt %s." \ % str(int_ping_count)) if int_ping_count == 3: # Check if any notification agents have notifications enabled if any(d['on_intdown'] for d in notifiers.available_notification_agents()): # Fire off notifications threading.Thread(target=notification_handler.notify_timeline, kwargs=dict(notify_action='intdown')).start()