diff --git a/beetsplug/ihate.py b/beetsplug/ihate.py index de14d4256..b4bc72b90 100644 --- a/beetsplug/ihate.py +++ b/beetsplug/ihate.py @@ -18,10 +18,14 @@ import re import logging from beets.plugins import BeetsPlugin from beets.importer import action +from beets.dbcore.query import AndQuery +from beets.library import query_from_strings +from beets.library import Item +from beets.library import Album __author__ = 'baobab@heresiarch.info' -__version__ = '1.0' +__version__ = '2.0' class IHatePlugin(BeetsPlugin): @@ -29,88 +33,46 @@ class IHatePlugin(BeetsPlugin): _instance = None _log = logging.getLogger('beets') - warn_genre = [] - warn_artist = [] - warn_album = [] - warn_whitelist = [] - skip_genre = [] - skip_artist = [] - skip_album = [] - skip_whitelist = [] - def __init__(self): super(IHatePlugin, self).__init__() self.register_listener('import_task_choice', self.import_task_choice_event) self.config.add({ - 'warn_genre': [], - 'warn_artist': [], - 'warn_album': [], - 'warn_whitelist': [], - 'skip_genre': [], - 'skip_artist': [], - 'skip_album': [], - 'skip_whitelist': [], + 'warn': {}, + 'skip': {}, }) - @classmethod - def match_patterns(cls, s, patterns): - """Check if string is matching any of the patterns in the list.""" - for p in patterns: - if re.findall(p, s, flags=re.IGNORECASE): - return True - return False - - @classmethod - def do_i_hate_this(cls, task, genre_patterns, artist_patterns, - album_patterns, whitelist_patterns): + def do_i_hate_this(cls, task, action_patterns): """Process group of patterns (warn or skip) and returns True if task is hated and not whitelisted. """ - hate = False - try: - genre = task.items[0].genre - except: - genre = u'' - if genre and genre_patterns: - if cls.match_patterns(genre, genre_patterns): - hate = True - if not hate and getattr(task, 'cur_album', None) and album_patterns: - if cls.match_patterns(task.cur_album, album_patterns): - hate = True - if not hate and getattr(task, 'cur_artist', None) and artist_patterns: - if cls.match_patterns(task.cur_artist, artist_patterns): - hate = True - if hate and whitelist_patterns: - if cls.match_patterns(task.cur_artist, whitelist_patterns): - hate = False - return hate + if action_patterns: + for queryString in action_patterns: + blockQuery = None + if task.is_album: + blockQuery = query_from_strings(AndQuery,Album,queryString) + else: + blockQuery = query_from_strings(AndQuery,Item,queryString) + if any(blockQuery.match(item) for item in task.items): + return True + return False + def job_to_do(self): """Return True if at least one pattern is defined.""" - return any(self.config[l].as_str_seq() for l in - ('warn_genre', 'warn_artist', 'warn_album', - 'skip_genre', 'skip_artist', 'skip_album')) + return any(self.config[l].as_str_seq() for l in ('warn', 'skip')) def import_task_choice_event(self, session, task): if task.choice_flag == action.APPLY: if self.job_to_do(): self._log.debug('[ihate] processing your hate') - if self.do_i_hate_this(task, - self.config['skip_genre'].as_str_seq(), - self.config['skip_artist'].as_str_seq(), - self.config['skip_album'].as_str_seq(), - self.config['skip_whitelist'].as_str_seq()): + if self.do_i_hate_this(task, self.config['skip']): task.choice_flag = action.SKIP self._log.info(u'[ihate] skipped: {0} - {1}' .format(task.cur_artist, task.cur_album)) return - if self.do_i_hate_this(task, - self.config['warn_genre'].as_str_seq(), - self.config['warn_artist'].as_str_seq(), - self.config['warn_album'].as_str_seq(), - self.config['warn_whitelist'].as_str_seq()): + if self.do_i_hate_this(task, self.config['warn']): self._log.info(u'[ihate] you maybe hate this: {0} - {1}' .format(task.cur_artist, task.cur_album)) else: diff --git a/docs/plugins/ihate.rst b/docs/plugins/ihate.rst index 9fd553e7a..fa32a6ba2 100644 --- a/docs/plugins/ihate.rst +++ b/docs/plugins/ihate.rst @@ -2,27 +2,26 @@ IHate Plugin ============ The ``ihate`` plugin allows you to automatically skip things you hate during -import or warn you about them. It supports album, artist and genre patterns. -There also is a whitelist to avoid skipping bands you still like. There are two -groups: warn and skip. The skip group is checked first. Whitelist overrides any -other patterns. +import or warn you about them. It supports any query, params will be checked +with OR chained logic, so as long as long as one element is satisfied the album +will be skipped. +There are two groups: warn and skip. The skip group is checked first. To use the plugin, enable it by including ``ihate`` in the ``plugins`` line of your beets config. Then, add an ``ihate:`` section to your configuration file:: ihate: - # you will be warned about these suspicious genres/artists (regexps): - warn_genre: rnb soul power\smetal - warn_artist: bad\band another\sbad\sband - warn_album: tribute\sto - # if you don't like a genre in general, but accept some band playing it, - # add exceptions here: - warn_whitelist: hate\sexception + # you will be warned about these suspicious genres/artists: + warn: + - artist:rnb + - genre: soul + #only warn about tribute albums in rock genre + - genre:rock album:tribute # never import any of this: - skip_genre: russian\srock polka - skip_artist: manowar - skip_album: christmas - # but import this: - skip_whitelist: '' + skip: + - genre:russian\srock + - genre:polka + - artist:manowar + - album:christmas Note: The plugin will trust your decision in 'as-is' mode. diff --git a/test/test_ihate.py b/test/test_ihate.py index 09533d194..4014834cb 100644 --- a/test/test_ihate.py +++ b/test/test_ihate.py @@ -8,80 +8,33 @@ from beetsplug.ihate import IHatePlugin class IHatePluginTest(unittest.TestCase): - def test_hate_album(self): - """ iHate tests for album """ + def test_hate(self): - genre_p = [] - artist_p = [] - album_p = [] - white_p = [] + match_pattern = {} + testItem = Item( + genre='TestGenre', + album = u'TestAlbum', + artist = u'TestArtist') task = ImportTask() - task.cur_artist = u'Test Artist' - task.cur_album = u'Test Album' - task.items = [Item(genre='Test Genre')] - self.assertFalse(IHatePlugin.do_i_hate_this(task, genre_p, artist_p, - album_p, white_p)) - genre_p = 'some_genre test\sgenre'.split() - self.assertTrue(IHatePlugin.do_i_hate_this(task, genre_p, artist_p, - album_p, white_p)) - genre_p = [] - artist_p = 'bad_artist test\sartist' - self.assertTrue(IHatePlugin.do_i_hate_this(task, genre_p, artist_p, - album_p, white_p)) - artist_p = [] - album_p = 'tribute christmas test'.split() - self.assertTrue(IHatePlugin.do_i_hate_this(task, genre_p, artist_p, - album_p, white_p)) - album_p = [] - white_p = 'goodband test\sartist another_band'.split() - genre_p = 'some_genre test\sgenre'.split() - self.assertFalse(IHatePlugin.do_i_hate_this(task, genre_p, artist_p, - album_p, white_p)) - genre_p = [] - artist_p = 'bad_artist test\sartist' - self.assertFalse(IHatePlugin.do_i_hate_this(task, genre_p, artist_p, - album_p, white_p)) - artist_p = [] - album_p = 'tribute christmas test'.split() - self.assertFalse(IHatePlugin.do_i_hate_this(task, genre_p, artist_p, - album_p, white_p)) - - def test_hate_singleton(self): - """ iHate tests for singleton """ - - genre_p = [] - artist_p = [] - album_p = [] - white_p = [] - task = ImportTask() - task.cur_artist = u'Test Artist' - task.items = [Item(genre='Test Genre')] - self.assertFalse(IHatePlugin.do_i_hate_this(task, genre_p, artist_p, - album_p, white_p)) - genre_p = 'some_genre test\sgenre'.split() - self.assertTrue(IHatePlugin.do_i_hate_this(task, genre_p, artist_p, - album_p, white_p)) - genre_p = [] - artist_p = 'bad_artist test\sartist' - self.assertTrue(IHatePlugin.do_i_hate_this(task, genre_p, artist_p, - album_p, white_p)) - artist_p = [] - album_p = 'tribute christmas test'.split() - self.assertFalse(IHatePlugin.do_i_hate_this(task, genre_p, artist_p, - album_p, white_p)) - album_p = [] - white_p = 'goodband test\sartist another_band'.split() - genre_p = 'some_genre test\sgenre'.split() - self.assertFalse(IHatePlugin.do_i_hate_this(task, genre_p, artist_p, - album_p, white_p)) - genre_p = [] - artist_p = 'bad_artist test\sartist' - self.assertFalse(IHatePlugin.do_i_hate_this(task, genre_p, artist_p, - album_p, white_p)) - artist_p = [] - album_p = 'tribute christmas test'.split() - self.assertFalse(IHatePlugin.do_i_hate_this(task, genre_p, artist_p, - album_p, white_p)) + task.items = [testItem] + task.is_album = False + #empty query should let it pass + self.assertFalse(IHatePlugin.do_i_hate_this(task, match_pattern)) + #1 query match + match_pattern = ["artist:bad_artist","artist:TestArtist"] + self.assertTrue(IHatePlugin.do_i_hate_this(task, match_pattern)) + #2 query matches, either should trigger + match_pattern = ["album:test","artist:testartist"] + self.assertTrue(IHatePlugin.do_i_hate_this(task, match_pattern)) + #query is blocked by AND clause + match_pattern = ["album:notthis genre:testgenre"] + self.assertFalse(IHatePlugin.do_i_hate_this(task, match_pattern)) + #both queries are blocked by AND clause with unmatched condition + match_pattern = ["album:notthis genre:testgenre","artist:testartist album:notthis"] + self.assertFalse(IHatePlugin.do_i_hate_this(task, match_pattern)) + #only one query should fire + match_pattern = ["album:testalbum genre:testgenre","artist:testartist album:notthis"] + self.assertTrue(IHatePlugin.do_i_hate_this(task, match_pattern)) def suite():