def to_events(cls, session, info): # Validate `state` state = info.get('state') if not state: log.warn('Event has an invalid state %r', state) return [] if state in IGNORED_EVENTS: log.debug('Ignored "%s" event: %r', state, info) return [] # Validate `view_offset` view_offset = to_integer(info.get('viewOffset')) if view_offset is None: log.info('Event has an invalid view offset %r', view_offset) return [] # Check for session `view_offset` jump if cls.session_jumped(session, info.get('viewOffset')): return [] # Build event return [(state, { 'rating_key': to_integer(info.get('ratingKey')), 'view_offset': view_offset })]
def to_events(cls, session, info): # Validate `state` state = info.get('state') if not state: log.warn('Event has an invalid state %r', state) return [] if state in IGNORED_EVENTS: log.debug('Ignored "%s" event: %r', state, info) return [] # Check for session `view_offset` jump if cls.session_jumped(session, info.get('viewOffset')): return [] # Retrieve event parameters view_offset = to_integer(info.get('viewOffset')) # Calculate current part number # TODO handle null values from session? part, _ = UpdateSession.get_part(session.duration, view_offset, session.part_count) # Build event return [(state, { 'part': part, 'rating_key': to_integer(info.get('ratingKey')), 'view_offset': view_offset })]
def to_events(cls, session, info): # Validate `state` state = info.get('state') if not state: log.warn('Event has an invalid state %r', state) return [] if state in IGNORED_EVENTS: log.debug('Ignored "%s" event: %r', state, info) return [] # Check for session `view_offset` jump if cls.session_jumped(session, info.get('viewOffset')): return [] # Retrieve event parameters view_offset = to_integer(info.get('viewOffset')) # Calculate current part number # TODO handle null values from session? part, _ = UpdateSession.get_part(session.duration, view_offset, session.part_count) # Build event return [ (state, { 'part': part, 'rating_key': to_integer(info.get('ratingKey')), 'view_offset': view_offset }) ]
def to_events(cls, session, info): # Validate `state` state = info.get('state') if not state: log.warn('Event has an invalid state %r', state) return [] if state in IGNORED_EVENTS: log.debug('Ignored "%s" event: %r', state, info) return [] # Validate `view_offset` view_offset = to_integer(info.get('viewOffset')) if view_offset is None: log.info('Event has an invalid view offset %r', view_offset) return [] # Check for session `view_offset` jump if cls.session_jumped(session, info.get('viewOffset')): return [] # Build event return [ (state, { 'rating_key': to_integer(info.get('ratingKey')), 'view_offset': view_offset }) ]
def to_dict(self, obj, info, fetch=False): view_offset = to_integer(info.get('time')) rating_key = info.get('ratingKey') result = { 'view_offset': view_offset, 'updated_at': datetime.utcnow() } if not fetch: # Return simple update return merge(result, { 'progress': self.get_progress(obj.duration, view_offset) }) # Retrieve session # Retrieve metadata and guid p_metadata, guid = self.get_metadata(rating_key) if not p_metadata: log.warn('Unable to retrieve metadata for rating_key %r', rating_key) return result if not guid or not guid.valid: return merge(result, { 'duration': p_metadata.duration, 'progress': self.get_progress(p_metadata.duration, view_offset) }) try: # Create/Retrieve `Client` for session result['client'] = ClientManager.get.or_create({ 'key': info.get('machineIdentifier'), 'title': info.get('client') }, fetch=True) # Create/Retrieve `User` for session result['user'] = UserManager.get.or_create({ 'key': to_integer(info.get('user_id')), 'title': info.get('user_name') }, fetch=True) # Pick account from `client` or `user` objects result['account'] = self.get_account(result) except FilteredException: log.debug('Activity has been filtered') result['client'] = None result['user'] = None result['account'] = None return merge(result, { 'duration': p_metadata.duration, 'progress': self.get_progress(p_metadata.duration, view_offset) })
def on_playing(self, info): if InterfaceMessages.critical: return # Create or retrieve existing session session = WSessionManager.get.or_create(info, fetch=True) # Validate session if session.updated_at is None or ( datetime.utcnow() - session.updated_at) > timedelta(minutes=5): log.info('Updating session, last update was over 5 minutes ago') WSessionManager.update(session, info, fetch=True) return if session.duration is None or session.view_offset is None: # Update session WSessionManager.update( session, info, fetch=lambda s, i: (s.rating_key != to_integer( i.get('ratingKey')) or s.duration is None)) return # Parse `info` to events events = self.to_events(session, info) if not events: return # Check for changed media media_changed = session.rating_key != to_integer(info.get('ratingKey')) # Parse `events` actions = self.engine.process(session, events) for action, payload in actions: # Build request for the event request = self.build_request( session, part=payload.get('part', 1), rating_key=payload.get('rating_key'), view_offset=payload.get('view_offset')) if not request: log.info('No request returned for action %r (payload: %r)', action, payload) continue # Queue request to be sent ActionManager.queue('/'.join(['scrobble', action]), request, session) # Update session WSessionManager.update(session, info, fetch=media_changed)
def on_playing(self, info): if InterfaceMessages.critical: return # Create or retrieve existing session session = WSessionManager.get.or_create(info, fetch=True) # Validate session if session.updated_at is None or (datetime.utcnow() - session.updated_at) > timedelta(minutes=5): log.info('Updating session, last update was over 5 minutes ago') WSessionManager.update(session, info, fetch=True) return if session.duration is None or session.view_offset is None: # Update session WSessionManager.update(session, info, fetch=lambda s, i: ( s.rating_key != to_integer(i.get('ratingKey')) or s.duration is None )) return # Parse `info` to events events = self.to_events(session, info) if not events: return # Check for changed media media_changed = session.rating_key != to_integer(info.get('ratingKey')) # Parse `events` actions = self.engine.process(session, events) for action, payload in actions: # Build request for the event request = self.build_request( session, part=payload.get('part', 1), rating_key=payload.get('rating_key'), view_offset=payload.get('view_offset') ) if not request: log.info('No request returned for action %r (payload: %r)', action, payload) continue # Queue request to be sent ActionManager.queue('/'.join(['scrobble', action]), request, session) # Update session WSessionManager.update(session, info, fetch=media_changed)
def or_create(self, user, fetch=False, match=False, filtered_exception=False): user = self.manager.parse_user(user) if not user: return None try: # Create new user obj = self.manager.create(key=to_integer(user['key'])) # Update newly created object self.manager.update(obj, user, fetch=fetch, match=match, filtered_exception=filtered_exception) return obj except (apsw.ConstraintError, peewee.IntegrityError): # Return existing user obj = self(user) if fetch or match: # Update existing `User` self.manager.update(obj, user, fetch=fetch, match=match, filtered_exception=filtered_exception) return obj
def or_create(self, info, fetch=False): machine_identifier = info.get('machineIdentifier') if not machine_identifier: log.info( 'No machine identifier available, unable to create session') return None try: # Create new session obj = self.manager.create(rating_key=to_integer( info.get('ratingKey')), session_key=machine_identifier, state='create') # Update newly created object self.manager.update(obj, info, fetch) # Update active sessions ModuleManager['sessions'].on_created(obj) return obj except (apsw.ConstraintError, peewee.IntegrityError): # Return existing object return self(info)
def or_create(self, info, fetch=False): machine_identifier = info.get('machineIdentifier') if not machine_identifier: log.info('No machine identifier available, unable to create session') return None try: # Create new session obj = self.manager.create( rating_key=to_integer(info.get('ratingKey')), session_key=machine_identifier, state='create' ) # Update newly created object self.manager.update(obj, info, fetch) # Update active sessions ModuleManager['sessions'].on_created(obj) return obj except (apsw.ConstraintError, peewee.IntegrityError): # Return existing object return self(info)
def __call__(self, user): user = self.manager.parse_user(user) if not user: return None return super(GetUser, self).__call__(User.key == to_integer(user['key']))
def __call__(self, user): user = self.manager.parse_user(user) if not user: return None return super(GetUser, self).__call__( User.key == to_integer(user['key']) )
def to_events(cls, session, info): # Validate `state` state = info.get('state') if not state: log.warn('Event has an invalid state %r', state) return [] # Check for session `view_offset` jump if cls.session_jumped(session, info.get('viewOffset')): return [] # Build event return [ (state, { 'rating_key': to_integer(info.get('ratingKey')), 'view_offset': to_integer(info.get('viewOffset')) }) ]
def or_create(self, info, fetch=False): session_key = to_integer(info.get('sessionKey')) try: # Create new session obj = self.manager.create( rating_key=to_integer(info.get('ratingKey')), session_key=self.build_session_key(session_key), state='create') # Update newly created object self.manager.update(obj, info, fetch) # Update active sessions ModuleManager['sessions'].on_created(obj) return obj except (apsw.ConstraintError, peewee.IntegrityError): # Return existing object return self(info)
def or_create(self, info, fetch=False): session_key = to_integer(info.get('sessionKey')) try: # Create new session obj = self.manager.create( rating_key=to_integer(info.get('ratingKey')), session_key=self.build_session_key(session_key), state='create' ) # Update newly created object self.manager.update(obj, info, fetch) # Update active sessions ModuleManager['sessions'].on_created(obj) return obj except (apsw.ConstraintError, peewee.IntegrityError): # Return existing object return self(info)
def or_create(self, user, fetch=False, match=False, filtered_exception=False): user = self.manager.parse_user(user) if not user: return None try: # Create new user obj = self.manager.create( key=to_integer(user['key']) ) # Update newly created object self.manager.update( obj, user, fetch=fetch, match=match, filtered_exception=filtered_exception ) return obj except (apsw.ConstraintError, peewee.IntegrityError): # Return existing user obj = self(user) if fetch or match: # Update existing `User` self.manager.update( obj, user, fetch=fetch, match=match, filtered_exception=filtered_exception ) return obj
def __call__(self, info): session_key = to_integer(info.get('sessionKey')) return super(GetWSession, self).__call__( Session.session_key == self.build_session_key(session_key))
def to_dict(self, obj, info, fetch=False): fetch = resolve(fetch, obj, info) view_offset = to_integer(info.get('viewOffset')) result = { 'rating_key': to_integer(info.get('ratingKey')), 'view_offset': view_offset, 'updated_at': datetime.utcnow() } if not fetch: # Return simple update return merge(result, { 'progress': self.get_progress( obj.duration, view_offset, obj.part, obj.part_count, obj.part_duration ) }) # Retrieve session key session_key = to_integer(info.get('sessionKey')) if not session_key: log.info('Missing session key, unable to fetch session details') return result # Retrieve active sessions log.debug('Fetching details for session #%s', session_key) p_sessions = Plex['status'].sessions() if not p_sessions: log.info('Unable to retrieve active sessions') return result # Find session matching `session_key` p_item = p_sessions.get(session_key) if not p_item: log.info('Unable to find session with key %r', session_key) return result # Retrieve metadata and guid p_metadata, guid = self.get_metadata(p_item.rating_key) if not p_metadata: log.info('Unable to retrieve metadata for rating_key %r', p_item.rating_key) return result if not guid or not guid.valid: return merge(result, { 'duration': p_metadata.duration, 'progress': self.get_progress(p_metadata.duration, view_offset) }) # Retrieve media parts part, part_count, part_duration = self.match_parts(p_metadata, guid, view_offset) log.debug('Part: %s (part_count: %s, part_duration: %s)', part, part_count, part_duration) # Find matching client + user for session try: # Create/Retrieve `Client` for session result['client'] = ClientManager.get.or_create( p_item.session.player, fetch=True, match=True, filtered_exception=True ) # Create/Retrieve `User` for session result['user'] = UserManager.get.or_create( p_item.session.user, fetch=True, match=True, filtered_exception=True ) # Pick account from `client` or `user` objects result['account'] = self.get_account(result) except FilteredException: log.debug('Activity has been filtered') result['client'] = None result['user'] = None result['account'] = None return merge(result, { 'part': part, 'part_count': part_count, 'part_duration': part_duration, 'duration': p_metadata.duration, 'progress': self.get_progress( p_metadata.duration, view_offset, part, part_count, part_duration ) })
def to_dict(self, obj, info, fetch=False): fetch = resolve(fetch, obj, info) view_offset = to_integer(info.get('viewOffset')) result = { 'rating_key': to_integer(info.get('ratingKey')), 'view_offset': view_offset, 'updated_at': datetime.utcnow() } if not fetch: # Return simple update return merge( result, {'progress': self.get_progress(obj.duration, view_offset)}) # Retrieve session key session_key = to_integer(info.get('sessionKey')) if not session_key: log.info('Missing session key, unable to fetch session details') return result # Retrieve active sessions log.debug('Fetching details for session #%s', session_key) p_sessions = Plex['status'].sessions() if not p_sessions: log.info('Unable to retrieve active sessions') return result # Find session matching `session_key` p_item = p_sessions.get(session_key) if not p_item: log.info('Unable to find session with key %r', session_key) return result # Retrieve metadata and guid p_metadata, guid = self.get_metadata(p_item.rating_key) if not p_metadata: log.info('Unable to retrieve metadata for rating_key %r', p_item.rating_key) return result if not guid: return merge( result, { 'duration': p_metadata.duration, 'progress': self.get_progress(p_metadata.duration, view_offset) }) try: # Create/Retrieve `Client` for session result['client'] = ClientManager.get.or_create( p_item.session.player, fetch=True, match=True, filtered_exception=True) # Create/Retrieve `User` for session result['user'] = UserManager.get.or_create(p_item.session.user, fetch=True, match=True, filtered_exception=True) # Pick account from `client` or `user` objects result['account'] = self.get_account(result) except FilteredException: log.debug('Activity has been filtered') result['client'] = None result['user'] = None result['account'] = None return merge( result, { 'duration': p_metadata.duration, 'progress': self.get_progress(p_metadata.duration, view_offset) })
def __call__(self, info): session_key = to_integer(info.get('sessionKey')) return super(GetWSession, self).__call__( Session.session_key == self.build_session_key(session_key) )