- current = artist
- simafm = SimaFM()
- # initialize artists deque list to construct from DB
- as_art = deque()
- as_artists = simafm.get_similar(artist=current.artist)
- self.log.debug('Requesting last.fm for "{0.artist}"'.format(current))
- try:
- [as_art.append((a, m)) for a, m in as_artists]
- except XmlFMHTTPError as err:
- self.log.warning('last.fm http error: %s' % err)
- except XmlFMNotFound as err:
- self.log.warning("last.fm: %s" % err)
- except XmlFMError as err:
- self.log.warning('last.fm module error: %s' % err)
- if as_art:
- self.log.debug('Fetched %d artist(s) from last.fm' % len(as_art))
- return as_art
-
- def get_recursive_similar_artist(self):
- ret_extra = list()
- history = deque(self.history)
- history.popleft()
- depth = 0
- current = self.player.current
- extra_arts = list()
- while depth < self.plugin_conf.getint('depth'):
- if len(history) == 0:
- break
- trk = history.popleft()
- if (trk.artist in [trk.artist for trk in extra_arts]
- or trk.artist == current.artist):
- continue
- extra_arts.append(trk)
- depth += 1
- self.log.info('EXTRA ARTS: {}'.format(
- '/'.join([trk.artist for trk in extra_arts])))
- for artist in extra_arts:
- self.log.debug('Looking for artist similar to "{0.artist}" as well'.format(artist))
- similar = self.lfm_similar_artists(artist=artist)
- if not similar:
- return ret_extra
- similar = sorted(similar, key=lambda sim: sim[1], reverse=True)
- ret_extra.extend(self.get_artists_from_player(similar))
- if current.artist in ret_extra:
- ret_extra.remove(current.artist)
- return ret_extra
-
- def get_local_similar_artists(self):
- """Check against local player for similar artists fetched from last.fm
- """
- current = self.player.current
- self.log.info('Looking for artist similar to "{0.artist}"'.format(current))
- similar = self.lfm_similar_artists()
- if not similar:
- self.log.info('Got nothing from last.fm!')
- return []
- similar = sorted(similar, key=lambda sim: sim[1], reverse=True)
- self.log.info('First five similar artist(s): {}...'.format(
- ' / '.join([a for a, m in similar[0:5]])))
- self.log.info('Looking availability in music library')
- ret = self.get_artists_from_player(similar)
- ret_extra = None
- if len(self.history) >= 2:
- if self.plugin_conf.getint('depth') > 1:
- ret_extra = self.get_recursive_similar_artist()
- if ret_extra:
- ret = list(set(ret) | set(ret_extra))
- if not ret:
- self.log.warning('Got nothing from music library.')
- self.log.warning('Try running in debug mode to guess why...')
- return []
- self.log.info('Got {} artists in library'.format(len(ret)))
- self.log.info(' / '.join(ret))
- # Move around similars items to get in unplayed|not recently played
- # artist first.
- return self._get_artists_list_reorg(ret)
-
- def _get_album_history(self, artist=None):
- """Retrieve album history"""
- duration = self.daemon_conf.getint('sima', 'history_duration')
- albums_list = set()
- for trk in self.sdb.get_history(artist=artist, duration=duration):
- albums_list.add(trk[1])
- return albums_list
-
- def find_album(self, artists):
- """Find albums to queue.
- """
- self.to_add = list()
- nb_album_add = 0
- target_album_to_add = self.plugin_conf.getint('album_to_add')
- for artist in artists:
- self.log.info('Looking for an album to add for "%s"...' % artist)
- albums = self.player.find_albums(artist)
- # str conversion while Album type is not propagated
- albums = [ str(album) for album in albums]
- if albums:
- self.log.debug('Albums candidate: {0:s}'.format(' / '.join(albums)))
- else: continue
- # albums yet in history for this artist
- albums = set(albums)
- albums_yet_in_hist = albums & self._get_album_history(artist=artist)
- albums_not_in_hist = list(albums - albums_yet_in_hist)
- # Get to next artist if there are no unplayed albums
- if not albums_not_in_hist:
- self.log.info('No album found for "%s"' % artist)
- continue
- album_to_queue = str()
- random.shuffle(albums_not_in_hist)
- for album in albums_not_in_hist:
- tracks = self.player.find_album(artist, album)
- # Look if one track of the album is already queued
- # Good heuristic, at least enough to guess if the whole album is
- # already queued.
- if tracks[0] in self.player.queue:
- self.log.debug('"%s" already queued, skipping!' %
- tracks[0].album)
- continue
- album_to_queue = album
- if not album_to_queue:
- self.log.info('No album found for "%s"' % artist)
- continue
- self.log.info('last.fm album candidate: {0} - {1}'.format(
- artist, album_to_queue))
- nb_album_add += 1
- self.to_add.extend(self.player.find_album(artist, album_to_queue))
- if nb_album_add == target_album_to_add:
- return True
-
- def _track(self):
- """Get some tracks for track queue mode
- """
- artists = self.get_local_similar_artists()
- nbtracks_target = self.plugin_conf.getint('track_to_add')
- for artist in artists:
- self.log.debug('Trying to find titles to add for "{}"'.format(
- artist))
- found = self.player.find_track(artist)
- # find tracks not in history for artist
- self.filter_track(found)
- if len(self.to_add) == nbtracks_target:
- break
- if not self.to_add:
- self.log.debug('Found no tracks to queue, is your ' +
- 'history getting too large?')
- return None
- for track in self.to_add:
- self.log.info('last.fm candidate: {0!s}'.format(track))
-
- def _album(self):
- """Get albums for album queue mode
- """
- artists = self.get_local_similar_artists()
- self.find_album(artists)
-
- def _top(self):
- """Get some tracks for top track queue mode
- """
- #artists = self.get_local_similar_artists()
- pass
-
- def callback_need_track(self):
- self._cleanup_cache()
- if not self.player.current:
- self.log.info('Not currently playing track, cannot queue')
- return None
- self.queue_mode()
- candidates = self.to_add
- self.to_add = list()
- if self.plugin_conf.get('queue_mode') != 'album':
- random.shuffle(candidates)
- return candidates