mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 08:39:17 +01:00
updated iHate plugin to replace hardcoded regex system in favour of more flexible queries
changed config layout of iHate plugin to a simpler system updated unit test for ihate plugin accordingly updated docs for ihate plugin accordingly
This commit is contained in:
parent
c82b31e750
commit
6836e9c725
3 changed files with 62 additions and 148 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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():
|
||||
|
|
|
|||
Loading…
Reference in a new issue