diff --git a/beetsplug/lastgenre/__init__.py b/beetsplug/lastgenre/__init__.py index 33fad7628..13b2be815 100644 --- a/beetsplug/lastgenre/__init__.py +++ b/beetsplug/lastgenre/__init__.py @@ -55,17 +55,30 @@ def _tags_for(obj): not found or another error occurs. """ try: - res = obj.get_top_tags() + if isinstance(obj, pylast.Album): + res = super(pylast.Album, obj).get_top_tags() + else: + res = obj.get_top_tags() except PYLAST_EXCEPTIONS as exc: log.debug(u'last.fm error: %s' % unicode(exc)) return [] tags = [] + min_weight = config['lastgenre']['min_weight'].get(int) + count = config['lastgenre']['count'].get(int) + + dbg = [] for el in res: - if isinstance(el, pylast.TopItem): - el = el.item - tags.append(el.get_name()) - log.debug(u'last.fm tags: %s' % unicode(tags)) + weight = int(el.weight) + tag = el.item.get_name().lower() + if _is_allowed(tag): + if min_weight > -1 and min_weight > weight and len(tags) > 0: + return tags + tags.append(tag) + dbg.append(u'{} [{}]'.format(tag, weight)) + if len(tags) == count: + break + log.debug(u'lastfm.tag (min. {}): {}'.format(min_weight, u', '.join(dbg))) return tags def _is_allowed(genre): @@ -74,24 +87,10 @@ def _is_allowed(genre): """ if genre is None: return False - if genre.lower() in options['whitelist']: + if not options['whitelist'] or genre in options['whitelist']: return True return False -def _find_allowed(genres): - """Given a list of candidate genres (strings), return an allowed - genre string. If `multiple` is on, then this may be a - comma-separated list; otherwise, it is one of the elements of - `genres`. - """ - allowed_genres = [g.title() for g in genres if _is_allowed(g)] - if not allowed_genres: - return - if config['lastgenre']['multiple']: - return u', '.join(allowed_genres) - else: - return allowed_genres[0] - def _strings_to_genre(tags): """Given a list of strings, return a genre. Returns the first string that is present in the genre whitelist (or the canonicalization @@ -99,16 +98,13 @@ def _strings_to_genre(tags): """ if not tags: return None - elif not options['whitelist']: - return tags[0].title() if options.get('c14n'): # Use the canonicalization tree. - for tag in tags: - return _find_allowed(find_parents(tag, options['branches'])) - else: - # Just use the flat whitelist. - return _find_allowed(tags) + tags = find_parents(tags[0], options['branches']) + + tags = [t.title() for t in tags] + return u', '.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 @@ -204,7 +200,8 @@ class LastGenrePlugin(plugins.BeetsPlugin): self.config.add({ 'whitelist': os.path.join(os.path.dirname(__file__), 'genres.txt'), - 'multiple': False, + 'min_weight': 10, + 'count': 1, 'fallback': None, 'canonical': None, 'source': 'album', diff --git a/docs/plugins/lastgenre.rst b/docs/plugins/lastgenre.rst index 37497fa40..1449bc385 100644 --- a/docs/plugins/lastgenre.rst +++ b/docs/plugins/lastgenre.rst @@ -86,13 +86,26 @@ Multiple Genres --------------- By default, the plugin chooses the most popular tag on Last.fm as a genre. If -you prefer to use a list of *all available* genre tags, turn on the -``multiple`` config option:: +you prefer to use a *list* of popular genre tags, you can increase the number +of the ``count`` config option:: lastgenre: - multiple: true + count: 3 -Comma-separated lists of genres will then be used instead of single genres. +Comma-separated lists of up to *count* genres will then be used instead of +single genres. + +`Last.fm`_ provides a popularity factor aka *weight* for each *tag* ranging +from 100 for the most popular *tag* down to 0 for the least popular *tags*. +The plugin uses this *weight* to discard unpopular *tags*. The default is to +ignore *tags*, with a *weight* less then *10*. You can change this, by setting +the ``min_weight`` config option:: + + lastgenre: + min_weight: 15 + +However, if no tag with a *weight* greater then ``min_weight`` is found, the +plugin uses the next best popular *tag*. Running Manually