def test_client_dlna_inverted(): Environment.prefs['scrobble_clients'] = '-#dlna' assert Filters.is_valid_client({'title': 'PC-One'}) is True assert Filters.is_valid_client({ 'title': 'PC-Two', 'product': 'DLNA' }) is False
def test_client_basic_positive(): Environment.prefs['scrobble_clients'] = 'pcone' assert Filters.is_valid_client({'title': 'PC-One'}) is True assert Filters.is_valid_client({ 'title': 'PC-Two', 'product': 'DLNA' }) is False
def test_client_wildcard(): Environment.prefs['scrobble_clients'] = '*' assert Filters.is_valid_client({'title': 'PC-One'}) is True assert Filters.is_valid_client({ 'title': 'PC-Two', 'product': 'DLNA' }) is True
def test_client_basic_inverted(): Environment.prefs['scrobble_clients'] = 'pcone, -pctwo' assert Filters.is_valid_client({'title': 'PC-One'}) is True assert Filters.is_valid_client({'title': 'PC-Two'}) is False assert Filters.is_valid_client({ 'title': 'PC-Three', 'product': 'DLNA' }) is False
def test_address_basic(): # Filter Address Environment.prefs['filter_networks'] = '10.20.30.40' assert Filters.is_valid_address({'address': '10.20.30.40'}) is True # Filter Subnet Environment.prefs['filter_networks'] = '10.20.30.0/24' assert Filters.is_valid_address({'address': '10.20.30.40'}) is True
def test_address_invalid_client(): # Empty Address Environment.prefs['filter_networks'] = '10.20.30.40' assert Filters.is_valid_address({'address': None}) is False # Malformed Address Environment.prefs['filter_networks'] = '10.20.30.40' assert Filters.is_valid_address({'address': '10.20.30'}) is False
def test_address_invalid_filter(): # Empty Filter Environment.prefs['filter_networks'] = ',' assert Filters.is_valid_address({'address': '10.20.30.40'}) is False # Malformed Filter Environment.prefs['filter_networks'] = '10.20.30/24' assert Filters.is_valid_address({'address': '10.20.30.40'}) is False
def test_address_invalid_filter(): # Empty Filter Environment.prefs["filter_networks"] = "," assert Filters.is_valid_address({"address": "10.20.30.40"}) is False # Malformed Filter Environment.prefs["filter_networks"] = "10.20.30/24" assert Filters.is_valid_address({"address": "10.20.30.40"}) is False
def test_address_invalid_client(): # Empty Address Environment.prefs["filter_networks"] = "10.20.30.40" assert Filters.is_valid_address({"address": None}) is False # Malformed Address Environment.prefs["filter_networks"] = "10.20.30.40" assert Filters.is_valid_address({"address": "10.20.30"}) is False
def test_address_basic(): # Filter Address Environment.prefs["filter_networks"] = "10.20.30.40" assert Filters.is_valid_address({"address": "10.20.30.40"}) is True # Filter Subnet Environment.prefs["filter_networks"] = "10.20.30.0/24" assert Filters.is_valid_address({"address": "10.20.30.40"}) is True
def match(cls, result, user): # Apply global filters if not Filters.is_valid_user(user): # User didn't pass filters, update `account` attribute and return result['account'] = None return True, result # Find matching `UserRule` rule = (UserRule.select().where((UserRule.name == user['title']) | (UserRule.name == '*') | (UserRule.name == None)).order_by( UserRule.priority.asc()).first()) log.debug('Activity matched against rule: %r', rule) if rule: # Process rule if rule.account_function is not None: result['account'] = cls.account_function(user, rule) elif rule.account_id is not None: result['account'] = rule.account_id else: return True, result else: result['account'] = None return False, result
def build_request(cls, session, part=None, rating_key=None, view_offset=None): # Retrieve metadata for session if part is None: part = session.part if rating_key is None: rating_key = session.rating_key # Retrieve metadata metadata = Metadata.get(rating_key) # Validate metadata if not metadata: log.warn('Unable to retrieve metadata for rating_key %r', rating_key) return None if metadata.type not in ['movie', 'episode']: log.info('Ignoring session with type %r for rating_key %r', metadata.type, rating_key) return None # Apply library/section filter if not Filters.is_valid_metadata_section(metadata): log.info('Ignoring session in filtered section: %r', metadata.section.title) return None # Parse guid guid = Guid.parse(metadata.guid, strict=True) if not guid or not guid.valid: log_unsupported_guid(log, guid) return None # Build request from guid/metadata if type(metadata) is Movie: result = cls.build_movie(metadata, guid, part) elif type(metadata) is Episode: result = cls.build_episode(metadata, guid, part) else: log.warn('Unknown metadata type: %r', type(metadata)) return None if not result: log.info('Unable to build request for session: %r', session) return None # Retrieve media progress if view_offset is not None: # Calculate progress from `view_offset` parameter progress = UpdateSession.get_progress( metadata.duration, view_offset, part, session.part_count, session.part_duration ) else: # Use session progress progress = session.progress # Merge progress into request return merge(result, { 'progress': progress })
def sections(self, section_type=None): # Retrieve "section" for current task section_key = self.current.kwargs.get('section', None) # Fetch sections from server p_sections = Plex['library'].sections() if p_sections is None: return None # Filter sections, map to dictionary result = {} for section in p_sections.filter(section_type, section_key): # Apply section name filter if not Filters.is_valid_section_name(section.title): continue try: key = int(section.key) except Exception, ex: log.warn('Unable to cast section key %r to integer: %s', section.key, ex, exc_info=True) continue result[key] = section.uuid
def match(result, client, player): # Apply global filters if not Filters.is_valid_client(player) or\ not Filters.is_valid_address(client): # Client didn't pass filters, update `account` attribute and return result['account'] = None return True, result # Find matching `ClientRule` address = client['address'] if client else None rule = (ClientRule .select() .where( (ClientRule.key == player['key']) | (ClientRule.key == '*') | (ClientRule.key == None), (ClientRule.name == player['title']) | (ClientRule.name == '*') | (ClientRule.name == None), (ClientRule.address == address) | (ClientRule.address == '*') | (ClientRule.address == None) ) .order_by( ClientRule.priority.asc() ) .first() ) log.debug('Activity matched against rule: %r', rule) if rule: # Process rule if rule.account_id is not None: result['account'] = rule.account_id else: return True, result else: result['account'] = None return False, result
def build_request(cls, session, rating_key=None, view_offset=None): # Retrieve metadata for session if rating_key is None: rating_key = session.rating_key # Retrieve metadata metadata = Metadata.get(rating_key) # Queue a flush for the metadata cache Metadata.cache.flush_queue() # Validate metadata if not metadata: log.warn('Unable to retrieve metadata for rating_key %r', rating_key) return None if metadata.type not in ['movie', 'episode']: log.info('Ignoring session with type %r for rating_key %r', metadata.type, rating_key) return None # Apply library/section filter if not Filters.is_valid_metadata_section(metadata): return None # Parse guid guid = Guid.parse(metadata.guid) # Build request from guid/metadata if type(metadata) is Movie: result = cls.build_movie(metadata, guid) elif type(metadata) is Episode: result = cls.build_episode(metadata, guid) else: return None if not result: return None # Retrieve media progress if view_offset is not None: # Calculate progress from `view_offset` parameter progress = UpdateSession.get_progress(metadata.duration, view_offset) else: # Use session progress progress = session.progress # Merge progress into request return merge(result, {'progress': progress})
def build_request(cls, session, rating_key=None, view_offset=None): # Retrieve metadata for session if rating_key is None: rating_key = session.rating_key # Retrieve metadata metadata = Metadata.get(rating_key) # Queue a flush for the metadata cache Metadata.cache.flush_queue() # Validate metadata if not metadata: log.warn('Unable to retrieve metadata for rating_key %r', rating_key) return None if metadata.type not in ['movie', 'episode']: log.info('Ignoring session with type %r for rating_key %r', metadata.type, rating_key) return None # Apply library/section filter if not Filters.is_valid_metadata_section(metadata): return None # Parse guid guid = Guid.parse(metadata.guid) # Build request from guid/metadata if type(metadata) is Movie: result = cls.build_movie(metadata, guid) elif type(metadata) is Episode: result = cls.build_episode(metadata, guid) else: return None if not result: return None # Retrieve media progress if view_offset is not None: # Calculate progress from `view_offset` parameter progress = UpdateSession.get_progress(metadata.duration, view_offset) else: # Use session progress progress = session.progress # Merge progress into request return merge(result, { 'progress': progress })
def match(cls, result, user): # Apply global filters if not Filters.is_valid_user(user): # User didn't pass filters, update `account` attribute and return result['account'] = None return True, result # Find matching `UserRule` rule = (UserRule .select() .where( (UserRule.name == user['title']) | (UserRule.name == '*') | (UserRule.name == None) ) .order_by( UserRule.priority.asc() ) .first() ) log.debug('Activity matched against rule: %r', rule) if rule: # Process rule if rule.account_function is not None: result['account'] = cls.account_function(user, rule) elif rule.account_id is not None: result['account'] = rule.account_id else: return True, result else: result['account'] = None return False, result
def test_client_basic_positive(): Environment.prefs["scrobble_clients"] = "pcone" assert Filters.is_valid_client({"title": "PC-One"}) is True assert Filters.is_valid_client({"title": "PC-Two", "product": "DLNA"}) is False
def test_client_basic_inverted(): Environment.prefs["scrobble_clients"] = "pcone, -pctwo" assert Filters.is_valid_client({"title": "PC-One"}) is True assert Filters.is_valid_client({"title": "PC-Two"}) is False assert Filters.is_valid_client({"title": "PC-Three", "product": "DLNA"}) is False
def test_client_dlna_inverted(): Environment.prefs["scrobble_clients"] = "-#dlna" assert Filters.is_valid_client({"title": "PC-One"}) is True assert Filters.is_valid_client({"title": "PC-Two", "product": "DLNA"}) is False
else: message = str(ex.message or ex) # Redirect to error message log.warn('Unable to retrieve account libraries/sections: %s', message, exc_info=True) return redirect('/sync', account_id=account_id, title='Error', message=message, message_only=True ) section_keys = [] f_allow, f_deny = Filters.get('filter_sections') for section in sections.filter(['show', 'movie'], titles=f_allow): oc.add(DirectoryObject( key=Callback(Push, account_id=account.id, section=section.key, refresh=timestamp()), title=pad_title('%s "%s" to trakt' % (SyncMode.title(SyncMode.Push), section.title)), summary=Status.build(account, SyncMode.Push, section.key), thumb=R("icon-sync_up.png"), art=function_path('Cover.png', account_id=account.id, refresh=account.refreshed_ts) )) section_keys.append(section.key) if len(section_keys) > 1: oc.add(DirectoryObject( key=Callback(Push, account_id=account.id, refresh=timestamp()),
def test_metadata_section_basic(): # Basic Environment.prefs["filter_sections"] = "one (movies)" assert Filters.is_valid_metadata_section(LibraryMetadata(section=LibrarySection(title="One (Movies)"))) is True
def test_section_name_invalid_name(): # Basic Environment.prefs["filter_sections"] = "one (movies)" assert Filters.is_valid_section_name("") is True
def test_user_empty(): Environment.prefs["scrobble_names"] = "" assert Filters.is_valid_user({"title": "one"}) is True
def test_client_dlna_invalid(): Environment.prefs["scrobble_clients"] = "#, pcone" assert Filters.is_valid_client({"title": "PC-One"}) is True
def test_missing_preference(): Environment.prefs["scrobble_names"] = None assert Filters.is_valid_user({"title": "one"}) is True
def ControlsMenu(account_id=1, title=None, message=None, refresh=None, message_only=False, *args, **kwargs): account = AccountManager.get(Account.id == account_id) # Build sync controls menu oc = ObjectContainer( title2=_("Sync (%s)") % account.name, no_cache=True, art=function_path('Cover.png', account_id=account.id, refresh=account.refreshed_ts) ) # Start result message if title and message: oc.add(DirectoryObject( key=Callback(ControlsMenu, account_id=account.id, refresh=timestamp()), title=pad_title(title), summary=message )) if message_only: return oc # Active sync status Active.create( oc, callback=Callback(ControlsMenu, account_id=account.id, refresh=timestamp()), account=account ) # # Full # oc.add(DirectoryObject( key=Trigger.callback(Synchronize, account), title=pad_title(SyncMode.title(SyncMode.Full)), summary=Status.build(account, SyncMode.Full), thumb=R("icon-sync.png"), art=function_path('Cover.png', account_id=account.id, refresh=account.refreshed_ts) )) # # Pull # oc.add(DirectoryObject( key=Trigger.callback(Pull, account), title=pad_title(_('%s from Trakt.tv') % SyncMode.title(SyncMode.Pull)), summary=Status.build(account, SyncMode.Pull), thumb=R("icon-sync_down.png"), art=function_path('Cover.png', account_id=account.id, refresh=account.refreshed_ts) )) oc.add(DirectoryObject( key=Trigger.callback(FastPull, account), title=pad_title(_('%s from Trakt.tv') % SyncMode.title(SyncMode.FastPull)), summary=Status.build(account, SyncMode.FastPull), thumb=R("icon-sync_down.png"), art=function_path('Cover.png', account_id=account.id, refresh=account.refreshed_ts) )) # # Push # p_account = account.plex try: # Retrieve account libraries/sections with p_account.authorization(): sections = Plex['library'].sections() except Exception as ex: # Build message if p_account is None: message = _("Plex account hasn't been authenticated") else: message = str(ex.message or ex) # Redirect to error message log.warn('Unable to retrieve account libraries/sections: %s', message, exc_info=True) return redirect('/sync', account_id=account_id, title=_('Error'), message=message, message_only=True ) section_keys = [] f_allow, f_deny = Filters.get('filter_sections') for section in sections.filter(['show', 'movie'], titles=f_allow): oc.add(DirectoryObject( key=Trigger.callback(Push, account, section), title=pad_title(_('%s "%s" to Trakt.tv') % (SyncMode.title(SyncMode.Push), section.title)), summary=Status.build(account, SyncMode.Push, section.key), thumb=R("icon-sync_up.png"), art=function_path('Cover.png', account_id=account.id, refresh=account.refreshed_ts) )) section_keys.append(section.key) if len(section_keys) > 1: oc.add(DirectoryObject( key=Trigger.callback(Push, account), title=pad_title(_('%s all to Trakt.tv') % SyncMode.title(SyncMode.Push)), summary=Status.build(account, SyncMode.Push), thumb=R("icon-sync_up.png"), art=function_path('Cover.png', account_id=account.id, refresh=account.refreshed_ts) )) return oc
message = str(ex.message or ex) # Redirect to error message log.warn('Unable to retrieve account libraries/sections: %s', message, exc_info=True) return redirect('/sync', account_id=account_id, title=_('Error'), message=message, message_only=True) section_keys = [] f_allow, f_deny = Filters.get('filter_sections') for section in sections.filter(['show', 'movie'], titles=f_allow): oc.add( DirectoryObject( key=Trigger.callback(Push, account, section), title=pad_title( _('%s "%s" to Trakt.tv') % (SyncMode.title(SyncMode.Push), section.title)), summary=Status.build(account, SyncMode.Push, section.key), thumb=R("icon-sync_up.png"), art=function_path('Cover.png', account_id=account.id, refresh=account.refreshed_ts))) section_keys.append(section.key)
def test_user_inverted(): Environment.prefs['scrobble_names'] = 'one, -two' assert Filters.is_valid_user({'title': 'one'}) is True assert Filters.is_valid_user({'title': 'two'}) is False
def test_missing_preference(): Environment.prefs['scrobble_names'] = None assert Filters.is_valid_user({'title': 'one'}) is True
def test_user_empty(): Environment.prefs['scrobble_names'] = '' assert Filters.is_valid_user({'title': 'one'}) is True
def test_client_invalid(): Environment.prefs['scrobble_clients'] = 'pcone' assert Filters.is_valid_client({}) is False
def test_user_inverted(): Environment.prefs["scrobble_names"] = "one, -two" assert Filters.is_valid_user({"title": "one"}) is True assert Filters.is_valid_user({"title": "two"}) is False
def test_metadata_section_basic(): # Basic Environment.prefs['filter_sections'] = 'one (movies)' assert Filters.is_valid_metadata_section( LibraryMetadata(section=LibrarySection(title='One (Movies)'))) is True
def test_client_dlna_invalid(): Environment.prefs['scrobble_clients'] = '#, pcone' assert Filters.is_valid_client({'title': 'PC-One'}) is True
def test_section_name_invalid_name(): # Basic Environment.prefs['filter_sections'] = 'one (movies)' assert Filters.is_valid_section_name('') is True
def build_request(cls, session, part=None, rating_key=None, view_offset=None): # Retrieve metadata for session if part is None: part = session.part if rating_key is None: rating_key = session.rating_key # Retrieve metadata metadata = Metadata.get(rating_key) # Validate metadata if not metadata: log.warn('Unable to retrieve metadata for rating_key %r', rating_key) return None if metadata.type not in ['movie', 'episode']: log.info('Ignoring session with type %r for rating_key %r', metadata.type, rating_key) return None # Apply library/section filter if not Filters.is_valid_metadata_section(metadata): log.info('Ignoring session in filtered section: %r', metadata.section.title) return None # Parse guid guid = Guid.parse(metadata.guid, strict=True) if not guid or not guid.valid: log_unsupported_guid(log, guid) return None # Build request from guid/metadata if type(metadata) is Movie: result = cls.build_movie(metadata, guid, part) elif type(metadata) is Episode: result = cls.build_episode(metadata, guid, part) else: log.warn('Unknown metadata type: %r', type(metadata)) return None if not result: log.info('Unable to build request for session: %r', session) return None # Retrieve media progress if view_offset is not None: # Calculate progress from `view_offset` parameter progress = UpdateSession.get_progress(metadata.duration, view_offset, part, session.part_count, session.part_duration) else: # Use session progress progress = session.progress # Merge progress into request return merge(result, {'progress': progress})
def test_client_empty(): Environment.prefs["scrobble_clients"] = "" assert Filters.is_valid_client({"title": "PC-One"}) is True assert Filters.is_valid_client({"title": "PC-Two", "product": "DLNA"}) is True
def ControlsMenu(account_id=1, title=None, message=None, refresh=None, message_only=False, *args, **kwargs): account = AccountManager.get(Account.id == account_id) # Build sync controls menu oc = ObjectContainer(title2=_("Sync (%s)") % account.name, no_cache=True, art=function_path('Cover.png', account_id=account.id, refresh=account.refreshed_ts)) # Start result message if title and message: oc.add( DirectoryObject(key=Callback(ControlsMenu, account_id=account.id, refresh=timestamp()), title=pad_title(title), summary=message)) if message_only: return oc # Active sync status Active.create(oc, callback=Callback(ControlsMenu, account_id=account.id, refresh=timestamp()), account=account) # # Full # oc.add( DirectoryObject(key=Trigger.callback(Synchronize, account), title=pad_title(SyncMode.title(SyncMode.Full)), summary=Status.build(account, SyncMode.Full), thumb=R("icon-sync.png"), art=function_path('Cover.png', account_id=account.id, refresh=account.refreshed_ts))) # # Pull # oc.add( DirectoryObject(key=Trigger.callback(Pull, account), title=pad_title( _('%s from Trakt.tv') % SyncMode.title(SyncMode.Pull)), summary=Status.build(account, SyncMode.Pull), thumb=R("icon-sync_down.png"), art=function_path('Cover.png', account_id=account.id, refresh=account.refreshed_ts))) oc.add( DirectoryObject(key=Trigger.callback(FastPull, account), title=pad_title( _('%s from Trakt.tv') % SyncMode.title(SyncMode.FastPull)), summary=Status.build(account, SyncMode.FastPull), thumb=R("icon-sync_down.png"), art=function_path('Cover.png', account_id=account.id, refresh=account.refreshed_ts))) # # Push # p_account = account.plex try: # Retrieve account libraries/sections with p_account.authorization(): sections = Plex['library'].sections() except Exception as ex: # Build message if p_account is None: message = _("Plex account hasn't been authenticated") else: message = str(ex.message or ex) # Redirect to error message log.warn('Unable to retrieve account libraries/sections: %s', message, exc_info=True) return redirect('/sync', account_id=account_id, title=_('Error'), message=message, message_only=True) section_keys = [] f_allow, f_deny = Filters.get('filter_sections') for section in sections.filter(['show', 'movie'], titles=f_allow): oc.add( DirectoryObject( key=Trigger.callback(Push, account, section), title=pad_title( _('%s "%s" to Trakt.tv') % (SyncMode.title(SyncMode.Push), section.title)), summary=Status.build(account, SyncMode.Push, section.key), thumb=R("icon-sync_up.png"), art=function_path('Cover.png', account_id=account.id, refresh=account.refreshed_ts))) section_keys.append(section.key) if len(section_keys) > 1: oc.add( DirectoryObject(key=Trigger.callback(Push, account), title=pad_title( _('%s all to Trakt.tv') % SyncMode.title(SyncMode.Push)), summary=Status.build(account, SyncMode.Push), thumb=R("icon-sync_up.png"), art=function_path('Cover.png', account_id=account.id, refresh=account.refreshed_ts))) return oc
def test_client_invalid(): Environment.prefs["scrobble_clients"] = "pcone" assert Filters.is_valid_client({}) is False