def _reset(self, full=False): """ clear recent play history + unset last played track """ self.acquire() self._history.clear() self._lastplayed_track = None self._playing_track = None for track in TrackFactory.active_tracks(): track.ranking = 0.5 track.relation = 0.5 track.relation_old = 0.5 track.relation_cnt = 0 if full: for track in TrackFactory.active_tracks(): track.lastplayed = 0 track.laststarted = 0 track.lastqueued = 0 for artist in ArtistFactory.active_artists(): artist.lastplayed = 0 artist.laststarted = 0 artist.lastqueued = 0 self.release()
def _update_ranking(self, locked=False): benchmark = Benchmark() if not locked: self.acquire() seed_track = None if self._lastplayed_track: seed_track = self._lastplayed_track elif self._playing_track: seed_track = self._playing_track if not self._relation_resetted: benchmark.start() self._relation_resetted = True for track in TrackFactory.active_tracks(): track.relation_old = track.relation track.relation_sum = 0.0 track.relation_cnt = 0 for artist in ArtistFactory.active_artists(): artist.relation_old = artist.relation artist.relation_sum = 0.0 artist.relation_cnt = 0 self._logger.info(u"update ranking: resetting took %s" % benchmark) has_active_tracks = False for track in TrackFactory.active_tracks(): has_active_tracks = True break benchmark.start() # new relation = old relation * decay # e.g. for decay = 0.5 (0.75) # decfacA = 0.5 * 0.5 = 0.25 (0.75 * 0.5 = 0.375) # decfacB = 1.0 - 0.5 = 0.5 (1.0 - 0.75 = 0.25) # relation_old=0.75 -> 0.25+0.5*0.75=0.625 (0.375+0.25*0.75=0.5625) decfacA = self._relation_decay * 0.5 decfacB = 1.0 - self._relation_decay for track in TrackFactory.active_tracks(): if (track.relation_old > 0.501) or (track.relation_old < 0.499): track.relation = (decfacA + decfacB * track.relation_old) else: track.relation = 0.5 for artist in ArtistFactory.active_artists(): if (artist.relation_old > 0.501) or (artist.relation_old < 0.499): artist.relation = (decfacA + decfacB * artist.relation_old) else: artist.relation = 0.5 self._logger.info(u"update ranking: set old relation + decay took %s" % benchmark) if has_active_tracks: self._ranking_updated = True self.seed(seed_track, True) benchmark.start() at = [] tt = [] for track in TrackFactory.active_tracks(): """ so we have: ranking [0-1.0] (old) rating [0-1.0] relation [0-1.0] random [0-1.0] and: factor min(track_lastplayed/started,artist_lastplayed/started) [0-1.0] ? moved to next_file() """ artist = track.artist r = random() # calculate new ranking if track.boost: self._logger.info(u"pre boost: %s" % track) track.relation = (track.relation + 99.0) / 100.0 self._logger.info(u"post boost: %s" % track) elif track.ban: track.relation = 0.0 # mix with artist relation if we don't have a track relation if track.relation_cnt == 0: if artist.relation_cnt > 0: track.relation = (0.75 * track.relation + 0.25 * artist.relation) top_ten(at, u'relation cnt = {} with {} now {} to {}'.format( artist.relation_cnt, scale_rating(artist.relation), scale_rating(track.relation), artist), track.relation) else: top_ten(tt, u'relation cnt = {} with {} to {}'.format( track.relation_cnt, scale_rating(track.relation), track), track.relation) track.ranking = ( self._factor_ranking['rating'] * track.get_rating() + self._factor_ranking['relation'] * track.relation + self._factor_ranking['random'] * r ) self._logger.info(u"update ranking: took %s" % benchmark) self._update_queued = False if not locked: self.release()
def reset_boost(self, locked=False): if not locked: self.acquire() for track in TrackFactory.active_tracks(): track.boost = False if not locked: self.release()
def next_file(self, locked=False): self._logger.info(u"next file: start") if not locked: self.acquire() if not self._ranking_updated: self.update_ranking() best_ranking = 0 best_tracks = [] tt = [] timestamp = now() # calculate last_*_timestamps (played / queued / started) track_lastplayed_timestamp = timestamp - self._thres_track_lastplayed track_laststarted_timestamp = timestamp - self._thres_track_laststarted track_lastqueued_timestamp = timestamp - self._thres_track_lastqueued artist_lastplayed_timestamp = timestamp - self._thres_artist_lastplayed artist_laststarted_timestamp = timestamp - self._thres_artist_laststarted artist_lastqueued_timestamp = timestamp - self._thres_artist_lastqueued has_active_tracks = False for track in TrackFactory.active_tracks(): has_active_tracks = True artist = track.artist factor = 1.0 if (track.lastplayed > track_lastplayed_timestamp): factor = min(factor, 1.0 - ((1.0 * track.lastplayed - track_lastplayed_timestamp) / self._thres_track_lastplayed)) if (artist.lastplayed > artist_lastplayed_timestamp): factor = min(factor, 1.0 - ((1.0 * artist.lastplayed - artist_lastplayed_timestamp) / self._thres_artist_lastplayed)) if (track.laststarted > track_laststarted_timestamp): factor = min(factor, 1.0 - ((1.0 * track.laststarted - track_laststarted_timestamp) / self._thres_track_laststarted)) if (artist.laststarted > artist_laststarted_timestamp): factor = min(factor, 1.0 - ((1.0 * artist.laststarted - artist_laststarted_timestamp) / self._thres_artist_laststarted)) if (track.lastqueued > track_lastqueued_timestamp): factor = min(factor, 1.0 - ((1.0 * track.lastqueued - track_lastqueued_timestamp) / self._thres_track_lastqueued)) if (artist.lastqueued > artist_lastqueued_timestamp): factor = min(factor, 1.0 - ((1.0 * artist.lastqueued - artist_lastqueued_timestamp) / self._thres_artist_lastqueued)) ranking = int(self._ranking_base * factor * track.ranking) if ranking > best_ranking: self._logger.debug("%2.2f (best=): %s" % (ranking, track)) best_ranking = ranking best_tracks = [track] elif ranking == best_ranking: self._logger.debug("%2.2f (best+): %s" % (ranking, track)) best_tracks.append(track) top_ten(tt, track, ranking) if not has_active_tracks: self._logger.error(u"No active tracks") if not locked: self.release() return None top_ten_dump(tt, self._logger.info, u"rank") self._logger.info("best tracks: %d" % (len(best_tracks))) best_track = choice(best_tracks) best_track.started() # pick the best file best_rating = 0.0 best_files = [] for file in best_track.files(): if not file.active: continue t = file.playcount / (1.0 + file.skipcount) if t > best_rating: best_rating = t best_files = [file] elif t == best_rating: best_files.append(file) if not locked: self.release() self._logger.info(u"next file: stop") return choice(best_files)