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