mirror of
https://github.com/beetbox/beets.git
synced 2025-12-08 09:34:23 +01:00
get rid of module level options variable
Conflicts: beetsplug/lastgenre/__init__.py
This commit is contained in:
parent
4e5bb262a7
commit
2e8e55736d
2 changed files with 117 additions and 136 deletions
|
|
@ -94,47 +94,6 @@ def filter_tags(tags):
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def _is_allowed(genre):
|
|
||||||
"""Determine whether the genre is present in the whitelist,
|
|
||||||
returning a boolean.
|
|
||||||
"""
|
|
||||||
if genre is None:
|
|
||||||
return False
|
|
||||||
if not options['whitelist'] or genre in options['whitelist']:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def _strings_to_genre(tags):
|
|
||||||
"""Given a list of strings, return a genre by joining them into a
|
|
||||||
single string and (optionally) canonicalizing each.
|
|
||||||
"""
|
|
||||||
if not tags:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if options.get('c14n'):
|
|
||||||
# Use the canonicalization tree.
|
|
||||||
out = []
|
|
||||||
for tag in tags:
|
|
||||||
for parent in find_parents(tag, options['branches']):
|
|
||||||
if _is_allowed(parent):
|
|
||||||
out.append(parent)
|
|
||||||
break
|
|
||||||
tags = out
|
|
||||||
|
|
||||||
tags = [t.title() for t in tags]
|
|
||||||
return config['lastgenre']['separator'].get(unicode).join(
|
|
||||||
tags[:config['lastgenre']['count'].get(int)]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def fetch_genre(lastfm_obj):
|
|
||||||
"""Return the genre for a pylast entity or None if no suitable genre
|
|
||||||
can be found. Ex. 'Electronic, House, Dance'
|
|
||||||
"""
|
|
||||||
return _strings_to_genre(_tags_for(lastfm_obj))
|
|
||||||
|
|
||||||
|
|
||||||
# Canonicalization tree processing.
|
# Canonicalization tree processing.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -168,63 +127,8 @@ def find_parents(candidate, branches):
|
||||||
return [candidate]
|
return [candidate]
|
||||||
|
|
||||||
|
|
||||||
# Cached entity lookups.
|
|
||||||
|
|
||||||
_genre_cache = {}
|
|
||||||
|
|
||||||
|
|
||||||
def _cached_lookup(entity, method, *args):
|
|
||||||
"""Get a genre based on the named entity using the callable `method`
|
|
||||||
whose arguments are given in the sequence `args`. The genre lookup
|
|
||||||
is cached based on the entity name and the arguments.
|
|
||||||
"""
|
|
||||||
# Shortcut if we're missing metadata.
|
|
||||||
if any(not s for s in args):
|
|
||||||
return None
|
|
||||||
|
|
||||||
key = u'{0}.{1}'.format(entity, u'-'.join(unicode(a) for a in args))
|
|
||||||
if key in _genre_cache:
|
|
||||||
return _genre_cache[key]
|
|
||||||
else:
|
|
||||||
genre = fetch_genre(method(*args))
|
|
||||||
_genre_cache[key] = genre
|
|
||||||
return genre
|
|
||||||
|
|
||||||
|
|
||||||
def fetch_album_genre(obj):
|
|
||||||
"""Return the album genre for this Item or Album.
|
|
||||||
"""
|
|
||||||
return _cached_lookup(u'album', LASTFM.get_album, obj.albumartist,
|
|
||||||
obj.album)
|
|
||||||
|
|
||||||
|
|
||||||
def fetch_album_artist_genre(obj):
|
|
||||||
"""Return the album artist genre for this Item or Album.
|
|
||||||
"""
|
|
||||||
return _cached_lookup(u'artist', LASTFM.get_artist, obj.albumartist)
|
|
||||||
|
|
||||||
|
|
||||||
def fetch_artist_genre(item):
|
|
||||||
"""Returns the track artist genre for this Item.
|
|
||||||
"""
|
|
||||||
return _cached_lookup(u'artist', LASTFM.get_artist, item.artist)
|
|
||||||
|
|
||||||
|
|
||||||
def fetch_track_genre(obj):
|
|
||||||
"""Returns the track genre for this Item.
|
|
||||||
"""
|
|
||||||
return _cached_lookup(u'track', LASTFM.get_track, obj.artist, obj.title)
|
|
||||||
|
|
||||||
|
|
||||||
# Main plugin logic.
|
# Main plugin logic.
|
||||||
|
|
||||||
options = {
|
|
||||||
'whitelist': None,
|
|
||||||
'branches': None,
|
|
||||||
'c14n': False,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class LastGenrePlugin(plugins.BeetsPlugin):
|
class LastGenrePlugin(plugins.BeetsPlugin):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(LastGenrePlugin, self).__init__()
|
super(LastGenrePlugin, self).__init__()
|
||||||
|
|
@ -241,32 +145,35 @@ class LastGenrePlugin(plugins.BeetsPlugin):
|
||||||
'separator': u', ',
|
'separator': u', ',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
self.setup()
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
"""Setup plugin from config options
|
||||||
|
"""
|
||||||
if self.config['auto']:
|
if self.config['auto']:
|
||||||
self.import_stages = [self.imported]
|
self.import_stages = [self.imported]
|
||||||
|
|
||||||
|
self._genre_cache = {}
|
||||||
|
|
||||||
# Read the whitelist file.
|
# Read the whitelist file.
|
||||||
wl_filename = self.config['whitelist'].as_filename()
|
self.whitelist = set()
|
||||||
whitelist = set()
|
with open(self.config['whitelist'].as_filename()) as f:
|
||||||
with open(wl_filename) as f:
|
|
||||||
for line in f:
|
for line in f:
|
||||||
line = line.decode('utf8').strip().lower()
|
line = line.decode('utf8').strip().lower()
|
||||||
if line:
|
if line and not line.startswith(u'#'):
|
||||||
whitelist.add(line)
|
self.whitelist.add(line)
|
||||||
options['whitelist'] = whitelist
|
|
||||||
|
|
||||||
# Read the genres tree for canonicalization if enabled.
|
# Read the genres tree for canonicalization if enabled.
|
||||||
|
self.c14n_branches = []
|
||||||
c14n_filename = self.config['canonical'].get()
|
c14n_filename = self.config['canonical'].get()
|
||||||
if c14n_filename is not None:
|
if c14n_filename :
|
||||||
c14n_filename = c14n_filename.strip()
|
c14n_filename = c14n_filename.strip()
|
||||||
if not c14n_filename:
|
if not c14n_filename:
|
||||||
c14n_filename = C14N_TREE
|
c14n_filename = C14N_TREE
|
||||||
c14n_filename = normpath(c14n_filename)
|
c14n_filename = normpath(c14n_filename)
|
||||||
|
|
||||||
genres_tree = yaml.load(open(c14n_filename, 'r'))
|
genres_tree = yaml.load(open(c14n_filename, 'r'))
|
||||||
branches = []
|
flatten_tree(genres_tree, [], self.c14n_branches)
|
||||||
flatten_tree(genres_tree, [], branches)
|
|
||||||
options['branches'] = branches
|
|
||||||
options['c14n'] = True
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sources(self):
|
def sources(self):
|
||||||
|
|
@ -281,6 +188,86 @@ class LastGenrePlugin(plugins.BeetsPlugin):
|
||||||
elif source == 'artist':
|
elif source == 'artist':
|
||||||
return 'artist',
|
return 'artist',
|
||||||
|
|
||||||
|
def _strings_to_genre(self, tags):
|
||||||
|
"""Given a list of strings, return a genre by joining them into a
|
||||||
|
single string and (optionally) canonicalizing each.
|
||||||
|
"""
|
||||||
|
if not tags:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if self.c14n_branches:
|
||||||
|
# Use the canonicalization tree.
|
||||||
|
out = []
|
||||||
|
for tag in tags:
|
||||||
|
for parent in find_parents(tag, self.c14n_branches):
|
||||||
|
if self._is_allowed(parent):
|
||||||
|
out.append(parent)
|
||||||
|
break
|
||||||
|
tags = out
|
||||||
|
|
||||||
|
tags = [t.title() for t in tags]
|
||||||
|
return config['lastgenre']['separator'].get(unicode).join(
|
||||||
|
tags[:config['lastgenre']['count'].get(int)]
|
||||||
|
)
|
||||||
|
|
||||||
|
def fetch_genre(self, lastfm_obj):
|
||||||
|
"""Return the genre for a pylast entity or None if no suitable genre
|
||||||
|
can be found. Ex. 'Electronic, House, Dance'
|
||||||
|
"""
|
||||||
|
return self._strings_to_genre(_tags_for(lastfm_obj))
|
||||||
|
|
||||||
|
def _is_allowed(self, genre):
|
||||||
|
"""Determine whether the genre is present in the whitelist,
|
||||||
|
returning a boolean.
|
||||||
|
"""
|
||||||
|
if genre is None:
|
||||||
|
return False
|
||||||
|
if not self.whitelist or genre in self.whitelist:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Cached entity lookups.
|
||||||
|
|
||||||
|
def _cached_lookup(self, entity, method, *args):
|
||||||
|
"""Get a genre based on the named entity using the callable `method`
|
||||||
|
whose arguments are given in the sequence `args`. The genre lookup
|
||||||
|
is cached based on the entity name and the arguments.
|
||||||
|
"""
|
||||||
|
# Shortcut if we're missing metadata.
|
||||||
|
if any(not s for s in args):
|
||||||
|
return None
|
||||||
|
|
||||||
|
key = u'{0}.{1}'.format(entity, u'-'.join(unicode(a) for a in args))
|
||||||
|
if key in self._genre_cache:
|
||||||
|
return self._genre_cache[key]
|
||||||
|
else:
|
||||||
|
genre = fetch_genre(method(*args))
|
||||||
|
self._genre_cache[key] = genre
|
||||||
|
return genre
|
||||||
|
|
||||||
|
def fetch_album_genre(self, obj):
|
||||||
|
"""Return the album genre for this Item or Album.
|
||||||
|
"""
|
||||||
|
return self._cached_lookup(u'album', LASTFM.get_album, obj.albumartist,
|
||||||
|
obj.album)
|
||||||
|
|
||||||
|
def fetch_album_artist_genre(obj):
|
||||||
|
"""Return the album artist genre for this Item or Album.
|
||||||
|
"""
|
||||||
|
return self._cached_lookup(u'artist', LASTFM.get_artist,
|
||||||
|
obj.albumartist)
|
||||||
|
|
||||||
|
def fetch_artist_genre(item):
|
||||||
|
"""Returns the track artist genre for this Item.
|
||||||
|
"""
|
||||||
|
return self._cached_lookup(u'artist', LASTFM.get_artist, item.artist)
|
||||||
|
|
||||||
|
def fetch_track_genre(obj):
|
||||||
|
"""Returns the track genre for this Item.
|
||||||
|
"""
|
||||||
|
return self._cached_lookup(u'track', LASTFM.get_track, obj.artist,
|
||||||
|
obj.title)
|
||||||
|
|
||||||
def _get_genre(self, obj):
|
def _get_genre(self, obj):
|
||||||
"""Get the genre string for an Album or Item object based on
|
"""Get the genre string for an Album or Item object based on
|
||||||
self.sources. Return a `(genre, source)` pair. The
|
self.sources. Return a `(genre, source)` pair. The
|
||||||
|
|
@ -335,7 +322,7 @@ class LastGenrePlugin(plugins.BeetsPlugin):
|
||||||
|
|
||||||
# Filter the existing genre.
|
# Filter the existing genre.
|
||||||
if obj.genre:
|
if obj.genre:
|
||||||
result = _strings_to_genre([obj.genre])
|
result = self.strings_to_genre([obj.genre])
|
||||||
if result:
|
if result:
|
||||||
return result, 'original'
|
return result, 'original'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,45 +14,43 @@
|
||||||
|
|
||||||
"""Tests for the 'lastgenre' plugin."""
|
"""Tests for the 'lastgenre' plugin."""
|
||||||
|
|
||||||
|
import logging
|
||||||
from _common import unittest
|
from _common import unittest
|
||||||
from beetsplug import lastgenre
|
from beetsplug.lastgenre import LastGenrePlugin
|
||||||
from beets import config
|
from beets import config
|
||||||
|
|
||||||
|
log = logging.getLogger('beets')
|
||||||
|
|
||||||
|
lastGenrePlugin = LastGenrePlugin()
|
||||||
|
|
||||||
class LastGenrePluginTest(unittest.TestCase):
|
class LastGenrePluginTest(unittest.TestCase):
|
||||||
def setUp(self):
|
|
||||||
"""Set up configuration"""
|
|
||||||
lastgenre.LastGenrePlugin()
|
|
||||||
|
|
||||||
def _setup_config(self, _whitelist=set(), _branches=None, count=1):
|
|
||||||
|
|
||||||
if _whitelist:
|
|
||||||
lastgenre.options['whitelist'] = _whitelist
|
|
||||||
if branches:
|
|
||||||
lastgenre.options['branches'] = branches
|
|
||||||
lastgenre.options['c14n'] = True
|
|
||||||
else:
|
|
||||||
lastgenre.options['c14n'] = False
|
|
||||||
|
|
||||||
|
def _setup_config(self, whitelist=set(), canonical=None, count=1):
|
||||||
|
config['lastgenre']['canonical'] = canonical
|
||||||
config['lastgenre']['count'] = count
|
config['lastgenre']['count'] = count
|
||||||
|
|
||||||
|
if whitelist:
|
||||||
|
lastGenrePlugin.whitelist = whitelist
|
||||||
|
|
||||||
|
|
||||||
def test_c14n(self):
|
def test_c14n(self):
|
||||||
"""Resolve genres that belong to a canonicalization branch.
|
"""Resolve genres that belong to a canonicalization branch.
|
||||||
"""
|
"""
|
||||||
self._setup_config(whitelist=set(['blues']),
|
# default whitelist and c14n
|
||||||
branches=[['blues'], ['blues', 'country blues'],
|
self._setup_config(canonical='')
|
||||||
['blues', 'country blues',
|
self.assertEqual(lastGenrePlugin._strings_to_genre(['delta blues']), 'Blues')
|
||||||
'delta blues']])
|
self.assertEqual(lastGenrePlugin._strings_to_genre(['i got blues']), '')
|
||||||
|
|
||||||
self.assertEqual(lastgenre._strings_to_genre(['delta blues']), 'Blues')
|
# custom whitelist
|
||||||
self.assertEqual(lastgenre._strings_to_genre(['rhytm n blues']), '')
|
self._setup_config(canonical='', whitelist=set(['rock']))
|
||||||
|
self.assertEqual(lastGenrePlugin._strings_to_genre(['delta blues']), '')
|
||||||
|
|
||||||
def test_whitelist(self):
|
def test_whitelist(self):
|
||||||
"""Keep only genres that are in the whitelist.
|
"""Keep only genres that are in the whitelist.
|
||||||
"""
|
"""
|
||||||
self._setup_config(whitelist=set(['blues', 'rock', 'jazz']),
|
self._setup_config(whitelist=set(['blues', 'rock', 'jazz']),
|
||||||
count=2)
|
count=2)
|
||||||
self.assertEqual(lastgenre._strings_to_genre(['pop', 'blues']),
|
self.assertEqual(lastGenrePlugin._strings_to_genre(['pop', 'blues']),
|
||||||
'Blues')
|
'Blues')
|
||||||
|
|
||||||
def test_count(self):
|
def test_count(self):
|
||||||
|
|
@ -61,7 +59,7 @@ class LastGenrePluginTest(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
self._setup_config(whitelist=set(['blues', 'rock', 'jazz']),
|
self._setup_config(whitelist=set(['blues', 'rock', 'jazz']),
|
||||||
count=2)
|
count=2)
|
||||||
self.assertEqual(lastgenre._strings_to_genre(
|
self.assertEqual(lastGenrePlugin._strings_to_genre(
|
||||||
['jazz', 'pop', 'rock', 'blues']),
|
['jazz', 'pop', 'rock', 'blues']),
|
||||||
'Jazz, Rock')
|
'Jazz, Rock')
|
||||||
|
|
||||||
|
|
@ -69,16 +67,12 @@ class LastGenrePluginTest(unittest.TestCase):
|
||||||
"""Keep the n first genres, after having applied c14n when necessary
|
"""Keep the n first genres, after having applied c14n when necessary
|
||||||
"""
|
"""
|
||||||
self._setup_config(whitelist=set(['blues', 'rock', 'jazz']),
|
self._setup_config(whitelist=set(['blues', 'rock', 'jazz']),
|
||||||
branches=[['blues'], ['blues', 'country blues']],
|
canonical='',
|
||||||
count=2)
|
count=2)
|
||||||
self.assertEqual(lastgenre._strings_to_genre(
|
self.assertEqual(lastGenrePlugin._strings_to_genre(
|
||||||
['jazz', 'pop', 'country blues', 'rock']),
|
['jazz', 'pop', 'country blues', 'rock']),
|
||||||
'Jazz, Blues')
|
'Jazz, Blues')
|
||||||
|
|
||||||
def test_default_c14n(self):
|
|
||||||
"""c14n with default config files should work out-of-the-box
|
|
||||||
"""
|
|
||||||
|
|
||||||
def suite():
|
def suite():
|
||||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue