Example #1
0
File: library.py Project: pscn/ads
  def seed(self, track, locked=False):
    """Calculate relations based on track as seed.
    """
    if not locked: self.acquire()
    benchmark = Benchmark()
    timestamp = now()
    seed_track = set()
    seed_artist = set()
    if track:
      seed_track.add(track)
      seed_artist.add(track.artist)
      self.lookup(track, True)

    # check artist relations
    cnt = 0
    benchmark.start()
    tt = []
    for seed_a in seed_artist.union(self._seed_artists):
      self._logger.info(u'check artist relations for {}'.format(seed_a))
      for artist_relation in ArtistRelationFactory.by_artist(seed_a):
        cnt += 1
        other_artist = artist_relation.artistA
        if artist_relation.artistA.name == seed_a.name:
          other_artist = artist_relation.artistB

        other_artist.relation_sum += artist_relation.rating
        other_artist.relation_cnt += 1
        other_artist.relation = (other_artist.relation_sum /
            other_artist.relation_cnt)
        top_ten(tt, u'artist related with {}({}/{}={}) to {}'.format(
              scale_rating(artist_relation.rating),
              scale_rating(other_artist.relation_sum),
              scale_rating(other_artist.relation_cnt),
              scale_rating(other_artist.relation),
              other_artist), artist_relation.rating)

        artist_relation.lastused = timestamp
    top_ten_dump(tt, self._logger.info)

    self._logger.info(u"update ranking: check artist took %s" % benchmark)
    self._logger.info(u"updated %d artist(s)" % cnt)

    cnt = 0
    benchmark.start()
    tt = []
    for seed_t in seed_track.union(self._seed_tracks):
      self._logger.info(u'check track relations for {}'.format(seed_t))
      for track_relation in TrackRelationFactory.by_track(seed_t):
        other_track = track_relation.trackA
        if track_relation.trackA.title == seed_t.title and \
            track_relation.trackA.artist.name == seed_t.artist.name:
          other_track = track_relation.trackB
        cnt += 1
        if not track.ban:
          other_track.relation_sum += track_relation.rating
          other_track.relation_cnt += 1
          other_track.relation = (other_track.relation_sum /
              other_track.relation_cnt)
          top_ten(tt, u'track related with {} to {}'.format(
              scale_rating(track_relation.rating), other_track),
              track_relation.rating)

        track_relation.lastused = timestamp
    top_ten_dump(tt, self._logger.info)
    self._logger.info(u"update ranking: check track took %s" % benchmark)
    self._logger.info(u"updated %d track(s)" % cnt)
    if not locked: self.release()
Example #2
0
File: library.py Project: pscn/ads
  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()
Example #3
0
File: library.py Project: pscn/ads
  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)