/* * Copyright 2008-2013, ETH Zürich, Samuel Welten, Michael Kuhn, Tobias Langner, * Sandro Affentranger, Lukas Bossard, Michael Grob, Rahul Jain, * Dominic Langenegger, Sonia Mayor Alonso, Roger Odermatt, Tobias Schlueter, * Yannick Stucki, Sebastian Wendland, Samuel Zehnder, Samuel Zihlmann, * Samuel Zweifel * * This file is part of Jukefox. * * Jukefox is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or any later version. Jukefox is * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * Jukefox. If not, see <http://www.gnu.org/licenses/>. */ package ch.ethz.dcg.jukefox.playmode.smartshuffle.agents; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.LinkedList; import java.util.List; import ch.ethz.dcg.jukefox.commons.utils.Pair; import ch.ethz.dcg.jukefox.commons.utils.RandomProvider; import ch.ethz.dcg.jukefox.model.collection.BaseAlbum; import ch.ethz.dcg.jukefox.model.collection.BaseArtist; import ch.ethz.dcg.jukefox.model.collection.BaseSong; import ch.ethz.dcg.jukefox.model.collection.statistics.StatisticsSong; import ch.ethz.dcg.jukefox.model.providers.StatisticsProvider; import ch.ethz.dcg.jukefox.playmode.smartshuffle.SongVote; import ch.ethz.dcg.jukefox.playmode.smartshuffle.agents.AgentManager.AgentType; /** * This agent votes for songs which are in the suggested list. * * @see StatisticsProvider#getSuggestedSongs(java.util.Date, int) * @see StatisticsProvider#getLongNotRatedSongs(int, int) */ public class SuggestedAgent extends AbstractRecentAgent { /** * The range of how much the cutBetweenOnceAndLately is allowed to be past when choosing one at random. [h] */ private static final Pair<Integer, Integer> CUT_BETWEEN_ONCE_AND_LATELY_RANDOM_RANGE = new Pair<Integer, Integer>( 1 * 30 * 24, 6 * 30 * 24); // 1month, 6months private final StatisticsProvider statisticsProvider; private List<StatisticsSong<BaseArtist, BaseAlbum>> suggestedSongs; private Date currentCutBetweenOnceAndLately; public SuggestedAgent(final StatisticsProvider statisticsProvider, TimeFilter timeFilter) { super(timeFilter); this.statisticsProvider = statisticsProvider; } /** * Suggests "suggested"-songs. * * @see StatisticsProvider#getSuggestedSongs(Date, Pair, ch.ethz.dcg.jukefox.data.db.IDbStatisticsHelper.TimeFilter, * int, boolean) */ @Override public List<BaseSong<BaseArtist, BaseAlbum>> suggestSongs(int num) { if (getTimeFilter() == TimeFilter.RECENTLY) { Pair<Date, Date> timeRange = getTimeRange(); currentCutBetweenOnceAndLately = timeRange.first; /*Nothing before recently*/ suggestedSongs = statisticsProvider.getSuggestedSongs( currentCutBetweenOnceAndLately, StatisticsProvider.DEFAULT_MAX_LATELY_LISTENING_TIME, timeRange, getTimeFilter().toDbTimeFilter(), num, false); } else { // We choose the cutBetweenOnceAndLately at random to get different ancient top data in each round int hoursBack = RandomProvider.getRandom().nextInt( CUT_BETWEEN_ONCE_AND_LATELY_RANDOM_RANGE.second - CUT_BETWEEN_ONCE_AND_LATELY_RANDOM_RANGE.first) + CUT_BETWEEN_ONCE_AND_LATELY_RANDOM_RANGE.first; Calendar cal = Calendar.getInstance(); cal.add(Calendar.HOUR, -hoursBack); currentCutBetweenOnceAndLately = cal.getTime(); suggestedSongs = statisticsProvider.getSuggestedSongs(currentCutBetweenOnceAndLately, StatisticsProvider.DEFAULT_MAX_LATELY_LISTENING_TIME, getTimeRange(), getTimeFilter().toDbTimeFilter(), num, false); } return new ArrayList<BaseSong<BaseArtist, BaseAlbum>>(suggestedSongs); } /** * Votes according to the neighborhood rating. No playlog ratings are taken - only inherited ones. */ @Override public List<SongVote> vote(List<BaseSong<BaseArtist, BaseAlbum>> songs) { List<BaseSong<BaseArtist, BaseAlbum>> toBeVoted = new LinkedList<BaseSong<BaseArtist, BaseAlbum>>(songs); // We already have the rating of our songs List<StatisticsSong<BaseArtist, BaseAlbum>> songRatings = new ArrayList<StatisticsSong<BaseArtist, BaseAlbum>>( suggestedSongs); toBeVoted.removeAll(suggestedSongs); // Find the rating of the other songs List<StatisticsSong<BaseArtist, BaseAlbum>> songRatingsTmp; if (getTimeFilter() == TimeFilter.RECENTLY) { Pair<Date, Date> timeRange = getTimeRange(); songRatingsTmp = statisticsProvider.getSuggestedSongRatings(toBeVoted, currentCutBetweenOnceAndLately, StatisticsProvider.DEFAULT_MAX_LATELY_LISTENING_TIME, // Exclude them as well, do not vote for recently listened songs! timeRange, getTimeFilter().toDbTimeFilter(), false); } else { songRatingsTmp = statisticsProvider.getSuggestedSongRatings(toBeVoted, currentCutBetweenOnceAndLately, StatisticsProvider.DEFAULT_MAX_LATELY_LISTENING_TIME, // Exclude them as well, do not vote for recently listened songs! getTimeRange(), getTimeFilter().toDbTimeFilter(), false); } songRatings.addAll(songRatingsTmp); // Transform the StatisticsSongs into SongVotes List<SongVote> votes = new ArrayList<SongVote>(songRatings.size()); for (StatisticsSong<BaseArtist, BaseAlbum> song : songRatings) { votes.add(new SongVote(song, (Float) song.getValue())); } return votes; } @Override public AgentType getAgentType() { return AgentType.Suggested; } }