"""
# standard library import
+import logging
import random
# third parties components
from musicpd import CommandError
# local import
-from ...lib.plugin import Plugin
-from ...lib.track import Track
+from ...lib.plugin import AdvancedPlugin
+from ...lib.meta import Artist, MetaContainer
from ...utils.utils import PluginException
+def control_config(tags_config):
+ log = logging.getLogger('sima')
+ sup_tags = Tags.supported_tags
+ config_tags = {k for k, v in tags_config.items()
+ if (v and k in Tags.supported_tags)}
+ if not tags_config.get('filter', None) and \
+ config_tags.isdisjoint(sup_tags):
+ log.warning('Found no config for Tags plugin! '
+ 'Need at least "filter" or a supported tag')
+ log.info('Supported Tags are : %s', ', '.join(sup_tags))
+ # raise PluginException('plugin misconfiguration')
+ return False
+ if config_tags.difference(sup_tags):
+ log.error('Found unsupported tag in config: %s',
+ config_tags.difference(sup_tags))
+ # raise PluginException('plugin misconfiguration')
+ return False
+ return True
+
+
def forge_filter(cfg):
tags = set(cfg.keys()) & Tags.supported_tags
cfg_filter = cfg.get('filter', None)
else:
mpd_filter.append(f"({tag} == '{cfg[tag].strip()}')")
mpd_filter = ' AND '.join(mpd_filter)
- if 'AND' in mpd_filter:
- mpd_filter = f'({mpd_filter})'
+ # Ensure there is at least an artist name
+ mpd_filter = f"({mpd_filter} AND (artist != ''))"
return mpd_filter
-class Tags(Plugin):
+class Tags(AdvancedPlugin):
"""Add track based on tags content
"""
supported_tags = {'comment', 'date', 'genre', 'label', 'originaldate'}
+ # options = {'queue_mode', 'priority', 'filter', 'track_to_add',
+ # 'album_to_add'}
def __init__(self, daemon):
super().__init__(daemon)
- self.daemon = daemon
self._control_conf()
self.mpd_filter = forge_filter(self.plugin_conf)
self._setup_tagsneeded()
self.log.debug('mpd filter: %s', self.mpd_filter)
def _control_conf(self):
- sup_tags = Tags.supported_tags
- config_tags = {k for k, v in self.plugin_conf.items()
- if (v and k not in ['filter', 'priority', 'track_to_add'])}
- if not self.plugin_conf.get('filter', None) and \
- config_tags.isdisjoint(sup_tags):
- self.log.error('Found no config for %s plugin! '
- 'Need at least "filter" or a supported tag', self)
- self.log.info('Supported Tags are : %s', ', '.join(sup_tags))
- raise PluginException('plugin misconfiguration')
- if config_tags.difference(sup_tags):
- self.log.error('Found unsupported tag in config: %s',
- config_tags.difference(sup_tags))
+ if not control_config(self.plugin_conf):
raise PluginException('plugin misconfiguration')
def _setup_tagsneeded(self):
tags = config_tags & Tags.supported_tags
self.player.needed_tags |= tags
- def _get_history(self):
- """Constructs list of already played artists.
- """
- duration = self.daemon.config.getint('sima', 'history_duration')
- tracks_from_db = self.daemon.sdb.get_history(duration=duration)
- hist = [Track(file=tr[3], artist=tr[0]) for tr in tracks_from_db]
- return hist
-
def start(self):
if (0, 21, 0) > tuple(map(int, self.player.mpd_version.split('.'))):
self.log.warning('MPD protocol version: %s < 0.21.0',
# Check filter is valid
try:
if self.plugin_conf['filter']:
- self.player.find(self.plugin_conf['filter'])
+ # Use window to limit response size
+ self.player.find(self.plugin_conf['filter'], "window", (0, 1))
except CommandError:
raise PluginException('Badly formated filter in tags plugin configuration: "%s"'
% self.plugin_conf['filter'])
def callback_need_track(self):
candidates = []
- target = self.plugin_conf.getint('track_to_add')
- tracks = self.player.find(self.mpd_filter)
- random.shuffle(tracks)
- history = self._get_history()
- while tracks:
- trk = tracks.pop()
- if trk in self.player.queue or \
- trk in candidates:
- self.log.debug('%s already queued', trk)
+ queue_mode = self.plugin_conf.get('queue_mode', 'track')
+ target = self.plugin_conf.getint(f'{queue_mode}_to_add')
+ # look for artists acording to filter
+ artists = [Artist(name=a) for a in self.player.list('artist', self.mpd_filter)]
+ random.shuffle(artists)
+ artists = MetaContainer(artists)
+ if not artists:
+ self.log.info('Tags plugin found nothing to queue')
+ return candidates
+ artists = self.get_reorg_artists_list(artists)
+ self.log.debug('Tags plugin found: %s', ' / '.join(map(str, artists)))
+ for artist in artists:
+ self.log.debug('looking for %s', artist)
+ tracks = self.player.find_tracks(artist)
+ if not tracks:
continue
- if trk in history:
- self.log.debug('%s in history', trk)
+ trk = self.filter_track(tracks, candidates)
+ if not trk:
continue
- candidates.append(trk)
- self.log.info('Tags candidate: {}'.format(trk))
- if len(candidates) >= target:
- break
- if not candidates:
- self.log.info('Tags plugin failed to find some tracks')
+ if queue_mode == 'track':
+ self.log.info('Tags plugin chose: {}'.format(trk))
+ candidates.append(trk)
+ if len(candidates) == target:
+ break
+ else:
+ album = self.album_candidate(trk.Artist, unplayed=True)
+ if not album:
+ continue
+ candidates.extend(self.player.find_tracks(album))
+ if len({t.album for t in candidates}) == target:
+ break
return candidates
# VIM MODLINE