def cleanup(): log.debug('Cleaning up stale or invalid sessions') sessions = WatchSession.all() if not len(sessions): return for key, ws in sessions: delete = False # Destroy invalid sessions if ws is None: delete = True elif not ws.last_updated or type(ws.last_updated) is not datetime: delete = True elif total_seconds(datetime.now() - ws.last_updated) / 60 / 60 > 24: # Destroy sessions last updated over 24 hours ago log.debug('Session %s was last updated over 24 hours ago, queued for deletion', key) delete = True # Delete session or flag for update if delete: log.info('Session %s looks stale or invalid, deleting it now', key) WatchSession.delete(key) elif not ws.update_required: log.info('Queueing session %s for update', key) ws.update_required = True ws.save() log.debug('Finished cleaning up')
def initialize(cls): cls.thread = Thread(target=cls.process) Activity.on('logging.action.played', cls.on_played)\ .on('logging.action.unplayed', cls.on_unplayed) WatchSession.configure(cls)
def create_session(self, info): if not info.get('ratingKey'): log.warn('Invalid ratingKey provided from activity info') return None # Metadata metadata = Metadata.get(info['ratingKey']) # Guid guid = Guid.parse(metadata.guid) if metadata else None ws = WatchSession.from_info(info, metadata, guid, info['ratingKey']) ws.skip = not metadata # Fetch client by `machineIdentifier` ws.client = Plex.clients().get(info['machineIdentifier']) if not ws.client: # Create dummy client from `info` ws.client = Client(Plex.client, 'clients') ws.client.name = info.get('client', None) ws.client.machine_identifier = info.get('machineIdentifier', None) ws.client.address = info.get('address', None) ws.client.port = info.get('port', None) # Create dummy user from `info` ws.user = User(Plex.client, 'accounts') ws.user.id = info['user_id'] ws.user.title = info['user_name'] ws.save() log.debug('created session: %s', ws) return ws
def get_session(self, session_key, state, view_offset): session = WatchSession.load(session_key) if session: if session.last_view_offset and session.last_view_offset > view_offset: Log.Debug('View offset has gone backwards (last: %s, cur: %s)' % ( session.last_view_offset, view_offset )) # First try update the session if the media hasn't changed # otherwise delete the session if self.update_session(session, view_offset): Log.Debug('Updated the current session') else: Log.Debug('Deleted the current session') session.delete() session = None if not session or session.skip: return None if state == 'playing' and session.update_required: self.update_session(session, view_offset) else: session = self.create_session(session_key, state) return session
def get_session(self, session_key, state, view_offset): session = WatchSession.load(session_key) if session: if session.last_view_offset and session.last_view_offset > view_offset: Log.Debug( 'View offset has gone backwards (last: %s, cur: %s)' % (session.last_view_offset, view_offset)) # First try update the session if the media hasn't changed # otherwise delete the session if self.update_session(session, view_offset): Log.Debug('Updated the current session') else: Log.Debug('Deleted the current session') session.delete() session = None if not session or session.skip: return None if state == 'playing' and session.update_required: self.update_session(session, view_offset) else: session = self.create_session(session_key, state) return session
def create_session(self, session_key, state): """ :type session_key: str :type state: str :rtype: WatchSession or None """ Log.Debug("Creating a WatchSession for the current media") video_section = PMS.get_video_session(session_key) if not video_section: return None player_section = video_section.findall("Player") if len(player_section): player_section = player_section[0] session = WatchSession.from_section( video_section, state, PMS.metadata(video_section.get("ratingKey")), PMS.client(player_section.get("machineIdentifier")), ) session.save() return session
def create_session(self, session_key, state): """ :type session_key: str :type state: str :rtype: WatchSession or None """ Log.Debug('Creating a WatchSession for the current media') video_section = PMS.get_video_session(session_key) if not video_section: return None player_section = video_section.findall('Player') if len(player_section): player_section = player_section[0] session = WatchSession.from_section( video_section, state, PlexMediaServer.metadata(video_section.get('ratingKey')), PlexMediaServer.client(player_section.get('machineIdentifier'))) session.save() return session
def get_session(self, session_key, state, view_offset): session = WatchSession.load(session_key) if session: if session.last_view_offset and session.last_view_offset > view_offset: Log.Debug( "View offset has gone backwards (last: %s, cur: %s)" % (session.last_view_offset, view_offset) ) # First try update the session if the media hasn't changed # otherwise delete the session if not self.update_session(session, view_offset): Log.Debug("Media changed, deleting the session") session.delete() return None if session.skip: return None if state == "playing" and session.update_required: Log.Debug("Session update required, updating the session...") if not self.update_session(session, view_offset): Log.Debug("Media changed, deleting the session") session.delete() return None else: session = self.create_session(session_key, state) return session
def create_session(self, session_key, state): """ :type session_key: str :type state: str :rtype: WatchSession or None """ log.debug('Creating a WatchSession for the current media') item = Plex['status'].sessions().get(session_key) if not item: log.warn('Unable to find session with key "%s"', session_key) return None # Metadata metadata = Metadata.get(item.rating_key) # Guid guid = Guid.parse(metadata.guid) if metadata else None # Create WatchSession ws = WatchSession.from_session(item.session, metadata, guid, item.rating_key, state) ws.skip = not metadata # Fetch client by `machineIdentifier` ws.client = Plex.clients().get(item.session.player.machine_identifier) ws.save() log.debug('created session: %s', ws) return ws
def create_session(self, session_key, state): """ :type session_key: str :type state: str :rtype: WatchSession or None """ Log.Debug('Creating a WatchSession for the current media') video_section = PMS.get_video_session(session_key) if not video_section: return None player_section = video_section.findall('Player') if len(player_section): player_section = player_section[0] session = WatchSession.from_section( video_section, state, PlexMediaServer.metadata(video_section.get('ratingKey')), PlexMediaServer.client(player_section.get('machineIdentifier')) ) session.save() return session
def check_sessions(self): sessions = WatchSession.all() if not len(sessions): return for key, session in sessions: self.check_paused(session)
class LoggingScrobbler(ScrobblerMethod): name = 'LoggingScrobbler' def __init__(self): super(LoggingScrobbler, self).__init__() EventManager.subscribe('scrobbler.logging.update', self.update) @classmethod def test(cls): # Try enable logging if not PlexPreferences.log_debug(True): log.warn('Unable to enable logging') # Test if logging is enabled if not PlexPreferences.log_debug(): log.warn( 'Debug logging not enabled, unable to use logging activity method.' ) return False return True def create_session(self, info): if not info.get('ratingKey'): log.warn('Invalid ratingKey provided from activity info') return None skip = False # Client client = None if info.get('machineIdentifier'): client = PlexMediaServer.get_client(info['machineIdentifier']) else: log.info( 'No machineIdentifier available, client filtering not available' ) # Metadata metadata = None try: metadata = PlexMetadata.get(info['ratingKey']) if metadata: metadata = metadata.to_dict() except NotImplementedError, e: # metadata not supported (music, etc..) log.debug('%s, ignoring session' % e.message) skip = True session = WatchSession.from_info(info, metadata, client) session.skip = skip session.save() return session
def is_watching(self, p_item): sessions = WatchSession.all(lambda s: s.get('metadata') and s['metadata'].get('rating_key') == p_item.rating_key ) for key, session in sessions: if session.watching: return True return False
def create_session(self, info): client = None if info.get('machineIdentifier'): client = PMS.client(info['machineIdentifier']) else: Log.Info('No machineIdentifier available, client filtering not available') return WatchSession.from_info( info, PMS.metadata(info['ratingKey']), client )
def check_sessions(self): sessions = WatchSession.all() if not len(sessions): return for key, ws in sessions: if getattr(ws, 'skip', True): continue try: self.check_paused(ws) except AttributeError, ex: log.warn("Unable to determine if session is paused, skipping invalid session - %s", ex, exc_info=True) ws.skip = True
def get_session(self, info): session = WatchSession.load('logging-%s' % info.get('client_id')) if session: if not self.session_valid(session, info): session.delete() session = None Log.Info('Session deleted') if not session or session.skip: return None else: session = self.create_session(info) return session
def get_session(self, session_key, state, view_offset): session = WatchSession.load(session_key) if not session: session = self.create_session(session_key, state) if not session: return None update_session = False # Update session when view offset goes backwards if session.last_view_offset and session.last_view_offset > view_offset: log.debug('View offset has gone backwards (last: %s, cur: %s)' % ( session.last_view_offset, view_offset )) update_session = True # Update session on missing metadata + session skip if not session.metadata and session.skip: update_session = True # First try update the session if the media hasn't changed # otherwise delete the session if update_session and not self.update_session(session, view_offset): log.debug('Media changed, deleting the session') session.delete_instance() return None # Delete session if invalid if not self.session_valid(session): session.delete_instance() return None if session.skip: return None if state == 'playing' and session.update_required: log.debug('Session update required, updating the session...') if not self.update_session(session, view_offset): log.debug('Media changed, deleting the session') session.delete_instance() return None return session
def from_event(cls, info): account_key = try_convert(info.get('account_key'), int) rating_key = info.get('rating_key') if account_key is None or rating_key is None: log.warn('Invalid action format: %s', info) return None if account_key != 1: log.debug('Ignoring action from shared account') return None if WatchSession.is_active(rating_key, lambda ws: not ws.update_required): log.debug('Ignoring action, item is currently being watched') return False metadata = Metadata.get(rating_key) if not metadata: log.debug('Ignoring action, unable to retrieve metadata') return False section = metadata.section.title.lower() f_allow, _ = get_filter('filter_sections') if f_allow is not None and section not in f_allow: log.debug('Ignoring action, section has been filtered') return False guid = Guid.parse(metadata.guid) request = {} if type(metadata) is Movie: request = cls.from_movie(metadata, guid) elif type(metadata) is Season: request = cls.from_season(metadata, guid) elif type(metadata) is Episode: request = cls.from_episode(metadata, guid) else: log.warn('Unsupported metadata type: %r', metadata) return None log.debug('request: %r', request) return request
def watch(self, key, p_items, t_item): if type(p_items) is not list: p_items = [p_items] # Ignore if trakt movie is already watched if t_item and t_item.is_watched: return True # Ignore if none of the plex items are watched if all([not x.seen for x in p_items]): return True # Ignore if we are currently watching this item if WatchSession.is_active(p_items[0].rating_key): log.trace("[P #%s] ignored - item is currently being watched", p_items[0].rating_key) return True # Build item which can be sent to trakt item = ActionHelper.plex.to_trakt(key, p_items[0]) if not item: log.warn('watch() - Ignored for unmatched media "%s" [%s]', p_items[0].title, key) return True # Check action against history history = ActionManager.history.get(p_items[0].rating_key, {}) if not ActionManager.valid_action("add", history): log.debug( 'watch() - Invalid action for "%s" [%s] (already scrobbled or duplicate action)', p_items[0].title, key ) return True # Mark item as added in `pts.action_manager` ActionManager.update_history(p_items[0].rating_key, "add", "add") # Set "watched_at" parameter (if available) watched_at = self.get_datetime(p_items[0], "last_viewed_at") if watched_at: item["watched_at"] = watched_at # Store item in "watched" collection self.store("watched", item) return True
def get_session(self, session_key, state, view_offset): session = WatchSession.load(session_key) if not session: session = self.create_session(session_key, state) if not session: return None update_session = False # Update session when view offset goes backwards if session.last_view_offset and session.last_view_offset > view_offset: log.debug('View offset has gone backwards (last: %s, cur: %s)' % (session.last_view_offset, view_offset)) update_session = True # Update session on missing metadata + session skip if not session.metadata and session.skip: update_session = True # First try update the session if the media hasn't changed # otherwise delete the session if update_session and not self.update_session(session, view_offset): log.debug('Media changed, deleting the session') session.delete() return None # Delete session if invalid if not self.session_valid(session): session.delete() return None if session.skip: return None if state == 'playing' and session.update_required: log.debug('Session update required, updating the session...') if not self.update_session(session, view_offset): log.debug('Media changed, deleting the session') session.delete() return None return session
def get_session(self, info): session = WatchSession.load('logging-%s' % info.get('machineIdentifier')) if session and not self.session_valid(session, info): session.delete_instance() session = None log.debug('Session deleted') if not session: session = self.create_session(info) if not session: return None if not session or session.skip: return None return session
def get_session(self, info): session = WatchSession.load('logging-%s' % info.get('machineIdentifier')) if not session: session = self.create_session(info) if not session: return None if not self.session_valid(session, info): session.delete() session = None log.debug('Session deleted') if not session or session.skip: return None return session
def create_session(self, info): return WatchSession.from_info( info, PlexMediaServer.metadata(info['ratingKey']), PlexMediaServer.client(info.get('client_id')) )
def create_session(self, info): return WatchSession.from_info( info, PlexMediaServer.metadata(info['ratingKey']), PlexMediaServer.client(info.get('client_id')))
class WebSocketScrobbler(ScrobblerMethod): name = 'WebSocketScrobbler' def __init__(self): super(WebSocketScrobbler, self).__init__() EventManager.subscribe('notifications.playing', self.update) @classmethod def test(cls): if PlexMediaServer.get_sessions() is None: log.info( "Error while retrieving sessions, assuming WebSocket method isn't available" ) return False server_info = PlexMediaServer.get_info() if server_info is None: log.info('Error while retrieving server info for testing') return False multi_user = bool(server_info.get('multiuser', 0)) if not multi_user: log.info( "Server info indicates multi-user support isn't available, WebSocket method not available" ) return False return True def create_session(self, session_key, state): """ :type session_key: str :type state: str :rtype: WatchSession or None """ log.debug('Creating a WatchSession for the current media') skip = False info = PlexMediaServer.get_session(session_key) if not info: return None # Client player_section = info.findall('Player') if len(player_section): player_section = player_section[0] client = PlexMediaServer.get_client( player_section.get('machineIdentifier')) # Metadata metadata = None try: metadata = PlexMetadata.get(info.get('ratingKey')) if metadata: metadata = metadata.to_dict() except NotImplementedError, e: # metadata not supported (music, etc..) log.debug('%s, ignoring session' % e.message) skip = True session = WatchSession.from_section(info, state, metadata, client) session.skip = skip session.save() return session