mirror of
https://github.com/beetbox/beets.git
synced 2025-12-28 03:22:39 +01:00
commit
fb9834c4f8
4 changed files with 231 additions and 0 deletions
142
beetsplug/ihate.py
Normal file
142
beetsplug/ihate.py
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
# This file is part of beets.
|
||||
# Copyright 2012, Blemjhoo Tezoulbr <baobab@heresiarch.info>.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
"""Warns you about things you hate (or even blocks import)."""
|
||||
|
||||
import re
|
||||
import logging
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets import ui
|
||||
from beets.importer import action
|
||||
|
||||
|
||||
__author__ = 'baobab@heresiarch.info'
|
||||
__version__ = '1.0'
|
||||
|
||||
|
||||
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 __new__(cls, *args, **kwargs):
|
||||
if cls._instance is None:
|
||||
cls._instance = super(IHatePlugin,
|
||||
cls).__new__(cls, *args, **kwargs)
|
||||
return cls._instance
|
||||
|
||||
def __str__(self):
|
||||
return ('(\n warn_genre = {0}\n'
|
||||
' warn_artist = {1}\n'
|
||||
' warn_album = {2}\n'
|
||||
' warn_whitelist = {3}\n'
|
||||
' skip_genre = {4}\n'
|
||||
' skip_artist = {5}\n'
|
||||
' skip_album = {6}\n'
|
||||
' skip_whitelist = {7} )\n'
|
||||
.format(self.warn_genre, self.warn_artist, self.warn_album,
|
||||
self.warn_whitelist, self.skip_genre, self.skip_artist,
|
||||
self.skip_album, self.skip_whitelist))
|
||||
|
||||
def configure(self, config):
|
||||
if not config.has_section('ihate'):
|
||||
self._log.warn('[ihate] plugin is not configured')
|
||||
return
|
||||
self.warn_genre = ui.config_val(config, 'ihate', 'warn_genre',
|
||||
'').split()
|
||||
self.warn_artist = ui.config_val(config, 'ihate', 'warn_artist',
|
||||
'').split()
|
||||
self.warn_album = ui.config_val(config, 'ihate', 'warn_album',
|
||||
'').split()
|
||||
self.warn_whitelist = ui.config_val(config, 'ihate', 'warn_whitelist',
|
||||
'').split()
|
||||
self.skip_genre = ui.config_val(config, 'ihate', 'skip_genre',
|
||||
'').split()
|
||||
self.skip_artist = ui.config_val(config, 'ihate', 'skip_artist',
|
||||
'').split()
|
||||
self.skip_album = ui.config_val(config, 'ihate', 'skip_album',
|
||||
'').split()
|
||||
self.skip_whitelist = ui.config_val(config, 'ihate', 'skip_whitelist',
|
||||
'').split()
|
||||
|
||||
@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):
|
||||
"""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 IHatePlugin.match_patterns(genre, genre_patterns):
|
||||
hate = True
|
||||
if not hate and task.cur_album and album_patterns:
|
||||
if IHatePlugin.match_patterns(task.cur_album, album_patterns):
|
||||
hate = True
|
||||
if not hate and task.cur_artist and artist_patterns:
|
||||
if IHatePlugin.match_patterns(task.cur_artist, artist_patterns):
|
||||
hate = True
|
||||
if hate and whitelist_patterns:
|
||||
if IHatePlugin.match_patterns(task.cur_artist, whitelist_patterns):
|
||||
hate = False
|
||||
return hate
|
||||
|
||||
def job_to_do(self):
|
||||
"""Return True if at least one pattern is defined."""
|
||||
return any([self.warn_genre, self.warn_artist, self.warn_album,
|
||||
self.skip_genre, self.skip_artist, self.skip_album])
|
||||
|
||||
def import_task_choice_event(self, task, config):
|
||||
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.skip_genre, self.skip_artist,
|
||||
self.skip_album, self.skip_whitelist):
|
||||
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.warn_genre, self.warn_artist,
|
||||
self.warn_album, self.warn_whitelist):
|
||||
self._log.info(u'[ihate] you maybe hate this: {0} - {1}'
|
||||
.format(task.cur_artist, task.cur_album))
|
||||
else:
|
||||
self._log.debug('[ihate] nothing to do')
|
||||
else:
|
||||
self._log.debug('[ihate] user make a decision, nothing to do')
|
||||
|
||||
|
||||
@IHatePlugin.listen('import_task_choice')
|
||||
def ihate_import_task_choice(task, config):
|
||||
IHatePlugin().import_task_choice_event(task, config)
|
||||
35
docs/plugins/ihate.rst
Normal file
35
docs/plugins/ihate.rst
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
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.
|
||||
Also there is whitelist to avoid skipping bands you still like. There are two
|
||||
groups: warn and skip. Skip group is checked first. Whitelist overrides any
|
||||
other patterns.
|
||||
|
||||
To use plugin, enable it by including ``ihate`` into ``plugins`` line of
|
||||
your beets config::
|
||||
|
||||
[beets]
|
||||
plugins = ihate
|
||||
|
||||
You need to configure plugin before use, so add following section into config
|
||||
file and adjust it to your needs::
|
||||
|
||||
[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 genre in general, but accept some band playing it,
|
||||
# add exceptions here:
|
||||
warn_whitelist=hate\sexception
|
||||
# never import any of this:
|
||||
skip_genre=russian\srock polka
|
||||
skip_artist=manowar
|
||||
skip_album=christmas
|
||||
# but import this:
|
||||
skip_whitelist=
|
||||
|
||||
Note: plugin will trust you decision in 'as-is' mode.
|
||||
|
||||
|
|
@ -53,6 +53,7 @@ disabled by default, but you can turn them on as described above.
|
|||
the
|
||||
fuzzy_search
|
||||
zero
|
||||
ihate
|
||||
|
||||
Autotagger Extensions
|
||||
''''''''''''''''''''''
|
||||
|
|
@ -92,6 +93,7 @@ Miscellaneous
|
|||
* :doc:`rdm`: Randomly choose albums and tracks from your library.
|
||||
* :doc:`fuzzy_search`: Search albums and tracks with fuzzy string matching.
|
||||
* :doc:`mbcollection`: Maintain your MusicBrainz collection list.
|
||||
* :doc:`ihate`: Skip by defined patterns things you hate during import process.
|
||||
* :doc:`bpd`: A music player for your beets library that emulates `MPD`_ and is
|
||||
compatible with `MPD clients`_.
|
||||
|
||||
|
|
|
|||
52
test/test_ihate.py
Normal file
52
test/test_ihate.py
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
"""Tests for the 'ihate' plugin"""
|
||||
|
||||
from _common import unittest
|
||||
from beets.importer import ImportTask
|
||||
from beets.library import Item
|
||||
from beetsplug.ihate import IHatePlugin
|
||||
|
||||
|
||||
class IHatePluginTest(unittest.TestCase):
|
||||
|
||||
def test_hate(self):
|
||||
genre_p = []
|
||||
artist_p = []
|
||||
album_p = []
|
||||
white_p = []
|
||||
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 suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
Loading…
Reference in a new issue