/* * 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.model.providers; import java.util.Calendar; import java.util.Date; import java.util.List; import ch.ethz.dcg.jukefox.commons.DataUnavailableException; import ch.ethz.dcg.jukefox.commons.utils.Pair; import ch.ethz.dcg.jukefox.commons.utils.Utils; import ch.ethz.dcg.jukefox.data.db.IDbDataPortal; import ch.ethz.dcg.jukefox.data.db.IDbStatisticsHelper; import ch.ethz.dcg.jukefox.data.db.IDbStatisticsHelper.Direction; import ch.ethz.dcg.jukefox.data.db.IDbStatisticsHelper.TimeFilter; 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.StatisticsAlbum; import ch.ethz.dcg.jukefox.model.collection.statistics.StatisticsArtist; import ch.ethz.dcg.jukefox.model.collection.statistics.StatisticsGenre; import ch.ethz.dcg.jukefox.model.collection.statistics.StatisticsSong; import ch.ethz.dcg.jukefox.model.rating.RatingEntry.RatingSource; /** * Provides statistics data */ public class StatisticsProvider { private final IDbDataPortal dbDataPortal; private final int profileId; private final static float MAX_LISTENED_PERCENTAGE = 0.3f; // 30%; private final static int AVERAGE_SONG_DURATION = 253353; // 4m 13s 353ms private final static int AVERAGE_ALBUM_DURATION = 1533544; // 25m 33s 544ms private final static int AVERAGE_ARTIST_DURATION = 1869546; // 31m 09s 546ms private final static int AVERAGE_GENRE_DURATION = 8532800; // 2h 22m 12s 800ms /** * Creates a new instance of {@link StatisticsProvider} * * @param profileId * The profile on which we should work * @param dbDataPortal * The database data portal which will be used */ public StatisticsProvider(int profileId, IDbDataPortal dbDataPortal) { this.dbDataPortal = dbDataPortal; this.profileId = profileId; } /** * Returns the timerange from the beginning of time until now. * * @return The all-the-time timerange */ public Pair<Date, Date> allTheTime() { return new Pair<Date, Date>(new Date(0), new Date()); } /** * @see IDbStatisticsHelper#getSongRatings(int, List, Pair, TimeFilter, RatingSource[], boolean) */ public <T extends BaseSong<BaseArtist, BaseAlbum>> List<StatisticsSong<BaseArtist, BaseAlbum>> getSongRatings( List<T> songs, Pair<Date, Date> timeRange, TimeFilter timeFilter, RatingSource[] ratingSources, boolean smoothed) { return dbDataPortal.getStatisticsHelper().getSongRatings(profileId, songs, timeRange, timeFilter, ratingSources, smoothed); } /** * @see IDbStatisticsHelper#getArtistRatings(int, List, Pair, TimeFilter, RatingSource[], boolean) */ public <T extends BaseArtist> List<StatisticsArtist> getArtistRatings(List<T> artists, Pair<Date, Date> timeRange, TimeFilter timeFilter, RatingSource[] ratingSources, boolean smoothed) { return dbDataPortal.getStatisticsHelper().getArtistRatings(profileId, artists, timeRange, timeFilter, ratingSources, smoothed); } /** * @see IDbStatisticsHelper#getLastPlayedTime(BaseSong) */ public Date getLastPlayedTime(BaseSong<BaseArtist, BaseAlbum> song) throws DataUnavailableException { return dbDataPortal.getStatisticsHelper().getLastPlayedTime(song); } /** * @see IDbStatisticsHelper#getLastPlayedTime(BaseArtist) */ public Date getLastPlayedTime(BaseArtist artist) throws DataUnavailableException { return dbDataPortal.getStatisticsHelper().getLastPlayedTime(artist); } /** * @see IDbStatisticsHelper#getTopSongs(int, int, Pair, TimeFilter, Direction, boolean) */ public List<StatisticsSong<BaseArtist, BaseAlbum>> getTopSongs(int maxNum, Pair<Date, Date> timeRange, TimeFilter timeFilter, Direction direction, boolean smoothed) { return dbDataPortal.getStatisticsHelper().getTopSongs(profileId, maxNum, timeRange, timeFilter, direction, smoothed); } /** * @see IDbStatisticsHelper#getTopAlbums(int, int, Pair, TimeFilter, Direction, boolean) */ public List<StatisticsAlbum> getTopAlbums(int maxNum, Pair<Date, Date> timeRange, TimeFilter timeFilter, Direction direction, boolean smoothed) { return dbDataPortal.getStatisticsHelper().getTopAlbums(profileId, maxNum, timeRange, timeFilter, direction, smoothed); } /** * @see IDbStatisticsHelper#getTopArtists(int, int, Pair, TimeFilter, Direction, boolean) */ public List<StatisticsArtist> getTopArtists(int maxNum, Pair<Date, Date> timeRange, TimeFilter timeFilter, Direction direction, boolean smoothed) { return dbDataPortal.getStatisticsHelper().getTopArtists(profileId, maxNum, timeRange, timeFilter, direction, smoothed); } /** * @see IDbStatisticsHelper#getTopGenres(int, int, Pair, TimeFilter, Direction, boolean) */ public List<StatisticsGenre> getTopGenres(int maxNum, Pair<Date, Date> timeRange, TimeFilter timeFilter, Direction direction, boolean smoothed) { return dbDataPortal.getStatisticsHelper().getTopGenres(profileId, maxNum, timeRange, timeFilter, direction, smoothed); } /** * Returns the utc timestamp from now minus one month. * * @return The timestamp in ms */ private Date getTimestampOfBeforeOneMonth() { Calendar now = Calendar.getInstance(); now.add(Calendar.MONTH, -1); return now.getTime(); } public static final Date DEFAULT_CUT_BETWEEN_ONCE_AND_LATELY = null; public static final long DEFAULT_MAX_LATELY_LISTENING_TIME = Long.MAX_VALUE; public static final long NO_MAX_LATELY_LISTENING_TIME_FILTER = Long.MIN_VALUE; /** * @see IDbStatisticsHelper#getSuggestedSongRatings(int, List, Date, long, Pair, TimeFilter, boolean) */ public List<StatisticsSong<BaseArtist, BaseAlbum>> getSuggestedSongRatings( List<BaseSong<BaseArtist, BaseAlbum>> songs, Pair<Date, Date> timeRange, TimeFilter timeFilter, boolean smoothed) { return getSuggestedSongRatings(songs, DEFAULT_CUT_BETWEEN_ONCE_AND_LATELY, DEFAULT_MAX_LATELY_LISTENING_TIME, timeRange, timeFilter, smoothed); } /** * @see IDbStatisticsHelper#getSuggestedSongRatings(int, List, Date, long, Pair, TimeFilter, boolean) */ public List<StatisticsSong<BaseArtist, BaseAlbum>> getSuggestedSongRatings( List<BaseSong<BaseArtist, BaseAlbum>> songs, Date cutBetweenOnceAndLately, long maxLatelyListeningTime, Pair<Date, Date> timeRange, TimeFilter timeFilter, boolean smoothed) { if ((maxLatelyListeningTime == DEFAULT_MAX_LATELY_LISTENING_TIME) || (maxLatelyListeningTime == NO_MAX_LATELY_LISTENING_TIME_FILTER)) { maxLatelyListeningTime = (long) (MAX_LISTENED_PERCENTAGE * AVERAGE_SONG_DURATION) * ((maxLatelyListeningTime < 0) ? -1 : 1); // see the documentation, for why we do this } if (Utils.nullEquals(cutBetweenOnceAndLately, DEFAULT_CUT_BETWEEN_ONCE_AND_LATELY)) { cutBetweenOnceAndLately = getTimestampOfBeforeOneMonth(); } return dbDataPortal.getStatisticsHelper().getSuggestedSongRatings(profileId, songs, cutBetweenOnceAndLately, maxLatelyListeningTime, timeRange, timeFilter, smoothed); } /** * @see IDbStatisticsHelper#getSuggestedSongs(int, Date, long, Pair, TimeFilter, int, boolean) */ public List<StatisticsSong<BaseArtist, BaseAlbum>> getSuggestedSongs(Pair<Date, Date> timeRange, TimeFilter timeFilter, int maxNum, boolean smoothed) { return getSuggestedSongs(DEFAULT_CUT_BETWEEN_ONCE_AND_LATELY, DEFAULT_MAX_LATELY_LISTENING_TIME, timeRange, timeFilter, maxNum, smoothed); } /** * @see IDbStatisticsHelper#getSuggestedSongs(int, Date, long, Pair, TimeFilter, int, boolean) */ public List<StatisticsSong<BaseArtist, BaseAlbum>> getSuggestedSongs(Date cutBetweenOnceAndLately, long maxLatelyListeningTime, Pair<Date, Date> timeRange, TimeFilter timeFilter, int maxNum, boolean smoothed) { if ((maxLatelyListeningTime == DEFAULT_MAX_LATELY_LISTENING_TIME) || (maxLatelyListeningTime == NO_MAX_LATELY_LISTENING_TIME_FILTER)) { maxLatelyListeningTime = (long) (MAX_LISTENED_PERCENTAGE * AVERAGE_SONG_DURATION) * ((maxLatelyListeningTime < 0) ? -1 : 1); // see the documentation, for why we do this } if (Utils.nullEquals(cutBetweenOnceAndLately, DEFAULT_CUT_BETWEEN_ONCE_AND_LATELY)) { cutBetweenOnceAndLately = getTimestampOfBeforeOneMonth(); } return dbDataPortal.getStatisticsHelper().getSuggestedSongs(profileId, cutBetweenOnceAndLately, maxLatelyListeningTime, timeRange, timeFilter, maxNum, smoothed); } /** * @see IDbStatisticsHelper#getSuggestedAlbums(int, Date, long, Pair, TimeFilter, int, boolean) */ public List<StatisticsAlbum> getSuggestedAlbums(Pair<Date, Date> timeRange, TimeFilter timeFilter, int maxNum, boolean smoothed) { Date cutBetweenOnceAndLately = getTimestampOfBeforeOneMonth(); long maxLatelyListeningTime = (long) (MAX_LISTENED_PERCENTAGE * AVERAGE_ALBUM_DURATION); return dbDataPortal.getStatisticsHelper().getSuggestedAlbums(profileId, cutBetweenOnceAndLately, maxLatelyListeningTime, timeRange, timeFilter, maxNum, smoothed); } /** * @see IDbStatisticsHelper#getSuggestedArtists(int, Date, long, Pair, TimeFilter, int, boolean) */ public List<StatisticsArtist> getSuggestedArtists(Pair<Date, Date> timeRange, TimeFilter timeFilter, int maxNum, boolean smoothed) { Date cutBetweenOnceAndLately = getTimestampOfBeforeOneMonth(); long maxLatelyListeningTime = (long) (MAX_LISTENED_PERCENTAGE * AVERAGE_ARTIST_DURATION); return dbDataPortal.getStatisticsHelper().getSuggestedArtists(profileId, cutBetweenOnceAndLately, maxLatelyListeningTime, timeRange, timeFilter, maxNum, smoothed); } /** * @see IDbStatisticsHelper#getSuggestedGenres(int, Date, long, Pair, TimeFilter, int, boolean) */ public List<StatisticsGenre> getSuggestedGenres(Pair<Date, Date> timeRange, TimeFilter timeFilter, int maxNum, boolean smoothed) { Date cutBetweenOnceAndLately = getTimestampOfBeforeOneMonth(); long maxLatelyListeningTime = (long) (MAX_LISTENED_PERCENTAGE * AVERAGE_GENRE_DURATION); return dbDataPortal.getStatisticsHelper().getSuggestedGenres(profileId, cutBetweenOnceAndLately, maxLatelyListeningTime, timeRange, timeFilter, maxNum, smoothed); } /** * Returns the utc timestamp from now minus two weeks. * * @return The timestamp in ms */ private Date getTimestampOfBeforeTwoWeeks() { Calendar now = Calendar.getInstance(); now.add(Calendar.WEEK_OF_YEAR, -2); return now.getTime(); } /** * @see IDbStatisticsHelper#getImportedSongs(Pair, int) */ public List<StatisticsSong<BaseArtist, BaseAlbum>> getRecentlyImportedSongs(int maxNum) { Pair<Date, Date> importRange = new Pair<Date, Date>(getTimestampOfBeforeTwoWeeks(), new Date()); return dbDataPortal.getStatisticsHelper().getImportedSongs(importRange, maxNum); } /** * @see IDbStatisticsHelper#getImportedAlbums(Pair, int) */ public List<StatisticsAlbum> getRecentlyImportedAlbums(int maxNum) { Pair<Date, Date> importRange = new Pair<Date, Date>(getTimestampOfBeforeTwoWeeks(), new Date()); return dbDataPortal.getStatisticsHelper().getImportedAlbums(importRange, maxNum); } /** * @see IDbStatisticsHelper#getImportedArtists(Pair, int) */ public List<StatisticsArtist> getRecentlyImportedArtists(int maxNum) { Pair<Date, Date> importRange = new Pair<Date, Date>(getTimestampOfBeforeTwoWeeks(), new Date()); return dbDataPortal.getStatisticsHelper().getImportedArtists(importRange, maxNum); } /** * @see IDbStatisticsHelper#getImportedGenres(Pair, int) */ public List<StatisticsGenre> getRecentlyImportedGenres(int maxNum) { Pair<Date, Date> importRange = new Pair<Date, Date>(getTimestampOfBeforeTwoWeeks(), new Date()); return dbDataPortal.getStatisticsHelper().getImportedGenres(importRange, maxNum); } /** * @see IDbStatisticsHelper#getLongNotRatedSongs(int, int) */ public List<BaseSong<BaseArtist, BaseAlbum>> getLongNotRatedSongs(int num, int longNotRatedThreshold) throws DataUnavailableException { return dbDataPortal.getStatisticsHelper().getLongNotRatedSongs(num, longNotRatedThreshold); } }