def test_media_changed(): engine = SessionEngine() session = Session(duration=50 * 1000, rating_key=100, state='create', view_offset=0) # playing assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 1 * 1000})], [('start',)]) assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 3 * 1000})], []) assert_events(engine, session, [('playing', {'rating_key': 101, 'view_offset': 1 * 1000})], [ ('stop', {'rating_key': 100, 'view_offset': 3 * 1000}), ('start', {'rating_key': 101, 'view_offset': 1 * 1000}) ])
def test_simple(): engine = SessionEngine() session = Session(rating_key=100, state='create', duration=50 * 1000, view_offset=0, part=1) # playing assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 1 * 1000, 'part': 1})], [('start',)]) assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 3 * 1000, 'part': 1})], []) assert_events(engine, session, [('playing', {'rating_key': 101, 'view_offset': 1 * 1000, 'part': 1})], [ ('stop', {'rating_key': 100, 'view_offset': 3 * 1000, 'part': 1}), ('start', {'rating_key': 101, 'view_offset': 1 * 1000, 'part': 1}) ])
def test_finished_duplication(): engine = SessionEngine() session = Session(duration=50 * 1000, rating_key=100, state='create', view_offset=0) # playing assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 1000})], [('start',)]) assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 2000})], []) # stopped assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 50 * 1000})], [('stop',)]) assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 51 * 1000})], []) assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 52 * 1000})], []) assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 53 * 1000})], []) assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 54 * 1000})], [])
def test_unplayed(): engine = SessionEngine() session = Session(rating_key=100, state='create', duration=50 * 1000, view_offset=0, part=1) assert_events(engine, session, [('paused', { 'rating_key': 100, 'view_offset': 50000, 'part': 1 })], []) assert_events(engine, session, [('stopped', { 'rating_key': 100, 'view_offset': 50000, 'part': 1 })], [])
def test_stopped_duplication(): engine = SessionEngine() session = Session(duration=50 * 1000, rating_key=100, state='create', view_offset=0) # Start watching item assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 1000})], [('start',)]) assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 10000})], []) assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 20000})], []) assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 30000})], []) assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 40000})], []) # Ensure "stop" actions aren't duplicated assert_events(engine, session, [('stopped', {'rating_key': 100, 'view_offset': 50000})], [('stop',)]) assert_events(engine, session, [('paused', {'rating_key': 100, 'view_offset': 50000})], []) assert_events(engine, session, [('stopped', {'rating_key': 100, 'view_offset': 50000})], []) # Ensure item can be restarted assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 10000})], [('start',)]) assert_events(engine, session, [('stopped', {'rating_key': 100, 'view_offset': 50000})], [('stop',)])
def test_event_duplication(): engine = SessionEngine() session = Session(duration=50 * 1000, rating_key=100, state='create', view_offset=0) # playing assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 1000})], [('start',)]) assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 3000})], []) # paused assert_events(engine, session, [('paused', {'rating_key': 100, 'view_offset': 3000})], [('pause',)]) assert_events(engine, session, [('paused', {'rating_key': 100, 'view_offset': 3000})], []) # playing assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 4000})], [('start',)]) assert_events(engine, session, [('playing', {'rating_key': 100, 'view_offset': 4000})], []) # stopped assert_events(engine, session, [('stopped', {'rating_key': 100, 'view_offset': 5000})], [('stop',)]) assert_events(engine, session, [('stopped', {'rating_key': 100, 'view_offset': 5000})], []) # media change assert_events(engine, session, [('playing', {'rating_key': 101, 'view_offset': 1000})], [('start',)])
def __init__(self): Activity.on('logging.playing', self.on_playing) self.engine = SessionEngine()
class Logging(Base): name = 'logging' def __init__(self): Activity.on('logging.playing', self.on_playing) self.engine = SessionEngine() def on_playing(self, info): if InterfaceMessages.critical: return # Create or retrieve existing session session = LSessionManager.get.or_create(info, fetch=True) if not session: return # 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') LSessionManager.update(session, info, fetch=True) return if session.duration is None or session.view_offset is None: # Update session LSessionManager.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 # Parse `events` actions = self.engine.process(session, events) for action, payload in actions: # Build request for the event request = self.build_request( session, rating_key=payload.get('rating_key'), view_offset=payload.get('view_offset')) if not request: continue # Queue request to be sent ActionManager.queue('/'.join(['scrobble', action]), request, session) # Update session LSessionManager.update(session, info) @classmethod 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 })] @classmethod def test(cls): return True
class Logging(Base): name = 'logging' def __init__(self): Activity.on('logging.playing', self.on_playing) self.engine = SessionEngine() def on_playing(self, info): # Create or retrieve existing session session = LSessionManager.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') LSessionManager.update(session, info, fetch=True) return if session.duration is None or session.view_offset is None: # Update session LSessionManager.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 # Parse `events` actions = self.engine.process(session, events) for action, payload in actions: # Build request for the event request = self.build_request( session, rating_key=payload.get('rating_key'), view_offset=payload.get('view_offset') ) if not request: continue # Queue request to be sent ActionManager.queue('/'.join(['scrobble', action]), request, session) # Update session LSessionManager.update(session, info) @classmethod 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 }) ] @classmethod def test(cls): return True
def test_paused(): engine = SessionEngine() session = Session(rating_key=100, state='create', duration=50 * 1000, view_offset=0, part=1) # playing assert_events(engine, session, [('playing', { 'rating_key': 100, 'view_offset': 1 * 1000, 'part': 1 })], [('start', )]) assert_events(engine, session, [('playing', { 'rating_key': 100, 'view_offset': 3 * 1000, 'part': 1 })], []) assert_events(engine, session, [('playing', { 'rating_key': 100, 'view_offset': 5 * 1000, 'part': 1 })], []) # paused assert_events(engine, session, [('paused', { 'rating_key': 100, 'view_offset': 37 * 1000, 'part': 1 })], [('pause', )]) # playing assert_events(engine, session, [('playing', { 'rating_key': 100, 'view_offset': 38 * 1000, 'part': 1 })], [('start', )]) assert_events(engine, session, [('playing', { 'rating_key': 100, 'view_offset': 39 * 1000, 'part': 1 })], []) # paused assert_events(engine, session, [('paused', { 'rating_key': 100, 'view_offset': 40 * 1000, 'part': 1 })], [('pause', )]) # finished assert_events(engine, session, [('paused', { 'rating_key': 100, 'view_offset': 49 * 1000, 'part': 1 })], [('stop', )]) assert_events(engine, session, [('paused', { 'rating_key': 100, 'view_offset': 50 * 1000, 'part': 1 })], []) # stopped assert_events(engine, session, [('stopped', { 'rating_key': 100, 'view_offset': 50 * 1000, 'part': 1 })], [])