Merge Pull Request #137 into develop
Conflicts: libresonic-main/src/main/webapp/WEB-INF/jsp/more.jsp
This commit is contained in:
+168
-26
@@ -19,30 +19,21 @@
|
||||
*/
|
||||
package org.libresonic.player.controller;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.taglibs.standard.lang.jstl.IntegerDivideOperator;
|
||||
import org.libresonic.player.domain.*;
|
||||
import org.libresonic.player.service.*;
|
||||
import org.springframework.web.bind.ServletRequestBindingException;
|
||||
import org.springframework.web.bind.ServletRequestUtils;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.mvc.ParameterizableViewController;
|
||||
|
||||
import org.libresonic.player.domain.MusicFolder;
|
||||
import org.libresonic.player.domain.PlayQueue;
|
||||
import org.libresonic.player.domain.Player;
|
||||
import org.libresonic.player.domain.RandomSearchCriteria;
|
||||
import org.libresonic.player.service.PlayerService;
|
||||
import org.libresonic.player.service.SearchService;
|
||||
import org.libresonic.player.service.SecurityService;
|
||||
import org.libresonic.player.service.SettingsService;
|
||||
|
||||
/**
|
||||
* Controller for the creating a random play queue.
|
||||
*
|
||||
@@ -52,21 +43,33 @@ public class RandomPlayQueueController extends ParameterizableViewController {
|
||||
|
||||
private PlayerService playerService;
|
||||
private List<ReloadFrame> reloadFrames;
|
||||
private SearchService searchService;
|
||||
private MediaFileService mediaFileService;
|
||||
private SecurityService securityService;
|
||||
private SettingsService settingsService;
|
||||
|
||||
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
|
||||
int size = ServletRequestUtils.getRequiredIntParameter(request, "size");
|
||||
String genre = request.getParameter("genre");
|
||||
|
||||
String genre;
|
||||
Integer fromYear = null;
|
||||
Integer toYear = null;
|
||||
Integer minAlbumRating = null;
|
||||
Integer maxAlbumRating = null;
|
||||
Integer minPlayCount = null;
|
||||
Integer maxPlayCount = null;
|
||||
Date minLastPlayedDate = null;
|
||||
Date maxLastPlayedDate = null;
|
||||
boolean doesShowStarredSongs = false;
|
||||
boolean doesShowUnstarredSongs = false;
|
||||
|
||||
// Handle the genre filter
|
||||
genre = request.getParameter("genre");
|
||||
if (StringUtils.equalsIgnoreCase("any", genre)) {
|
||||
genre = null;
|
||||
}
|
||||
|
||||
Integer fromYear = null;
|
||||
Integer toYear = null;
|
||||
|
||||
// Handle the release year filter
|
||||
String year = request.getParameter("year");
|
||||
if (!StringUtils.equalsIgnoreCase("any", year)) {
|
||||
String[] tmp = StringUtils.split(year);
|
||||
@@ -74,12 +77,151 @@ public class RandomPlayQueueController extends ParameterizableViewController {
|
||||
toYear = Integer.parseInt(tmp[1]);
|
||||
}
|
||||
|
||||
// Handle the song rating filter
|
||||
String songRating = request.getParameter("songRating");
|
||||
if (StringUtils.equalsIgnoreCase("any", songRating)) {
|
||||
doesShowStarredSongs = true;
|
||||
doesShowUnstarredSongs = true;
|
||||
} else if (StringUtils.equalsIgnoreCase("starred", songRating)) {
|
||||
doesShowStarredSongs = true;
|
||||
doesShowUnstarredSongs = false;
|
||||
} else if (StringUtils.equalsIgnoreCase("unstarred", songRating)) {
|
||||
doesShowStarredSongs = false;
|
||||
doesShowUnstarredSongs = true;
|
||||
}
|
||||
|
||||
// Handle the last played date filter
|
||||
String lastPlayedValue = request.getParameter("lastPlayedValue");
|
||||
String lastPlayedComp = request.getParameter("lastPlayedComp");
|
||||
Calendar lastPlayed = Calendar.getInstance();
|
||||
lastPlayed.setTime(new Date());
|
||||
switch (lastPlayedValue) {
|
||||
case "any":
|
||||
lastPlayed = null;
|
||||
break;
|
||||
case "1day":
|
||||
lastPlayed.add(Calendar.DAY_OF_YEAR, -1);
|
||||
break;
|
||||
case "1week":
|
||||
lastPlayed.add(Calendar.WEEK_OF_YEAR, -1);
|
||||
break;
|
||||
case "1month":
|
||||
lastPlayed.add(Calendar.MONTH, -1);
|
||||
break;
|
||||
case "3months":
|
||||
lastPlayed.add(Calendar.MONTH, -3);
|
||||
break;
|
||||
case "6months":
|
||||
lastPlayed.add(Calendar.MONTH, -6);
|
||||
break;
|
||||
case "1year":
|
||||
lastPlayed.add(Calendar.YEAR, -1);
|
||||
break;
|
||||
}
|
||||
if (lastPlayed != null) {
|
||||
switch (lastPlayedComp) {
|
||||
case "lt":
|
||||
minLastPlayedDate = null;
|
||||
maxLastPlayedDate = lastPlayed.getTime();
|
||||
break;
|
||||
case "gt":
|
||||
minLastPlayedDate = lastPlayed.getTime();
|
||||
maxLastPlayedDate = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the album rating filter
|
||||
Integer albumRatingValue = null;
|
||||
try { albumRatingValue = Integer.parseInt(request.getParameter("albumRatingValue")); }
|
||||
catch (NumberFormatException e) { }
|
||||
String albumRatingComp = request.getParameter("albumRatingComp");
|
||||
if (albumRatingValue != null) {
|
||||
switch (albumRatingComp) {
|
||||
case "lt":
|
||||
minAlbumRating = null;
|
||||
maxAlbumRating = albumRatingValue - 1;
|
||||
break;
|
||||
case "gt":
|
||||
minAlbumRating = albumRatingValue + 1;
|
||||
maxAlbumRating = null;
|
||||
break;
|
||||
case "le":
|
||||
minAlbumRating = null;
|
||||
maxAlbumRating = albumRatingValue;
|
||||
break;
|
||||
case "ge":
|
||||
minAlbumRating = albumRatingValue;
|
||||
maxAlbumRating = null;
|
||||
break;
|
||||
case "eq":
|
||||
minAlbumRating = albumRatingValue;
|
||||
maxAlbumRating = albumRatingValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the play count filter
|
||||
Integer playCountValue = null;
|
||||
try { playCountValue = Integer.parseInt(request.getParameter("playCountValue")); }
|
||||
catch (NumberFormatException e) { }
|
||||
String playCountComp = request.getParameter("playCountComp");
|
||||
if (playCountValue != null) {
|
||||
switch (playCountComp) {
|
||||
case "lt":
|
||||
minPlayCount = null;
|
||||
maxPlayCount = playCountValue - 1;
|
||||
break;
|
||||
case "gt":
|
||||
minPlayCount = playCountValue + 1;
|
||||
maxPlayCount = null;
|
||||
break;
|
||||
case "le":
|
||||
minPlayCount = null;
|
||||
maxPlayCount = playCountValue;
|
||||
break;
|
||||
case "ge":
|
||||
minPlayCount = playCountValue;
|
||||
maxPlayCount = null;
|
||||
break;
|
||||
case "eq":
|
||||
minPlayCount = playCountValue;
|
||||
maxPlayCount = playCountValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the format filter
|
||||
String format = request.getParameter("format");
|
||||
if (StringUtils.equalsIgnoreCase(format, "any")) format = null;
|
||||
|
||||
// Handle the music folder filter
|
||||
List<MusicFolder> musicFolders = getMusicFolders(request);
|
||||
|
||||
// Do we add to the current playlist or do we replace it?
|
||||
boolean shouldAddToPlayList = ServletRequestUtils.getBooleanParameter(request, "addToPlaylist", false);
|
||||
|
||||
// Search the database using these criteria
|
||||
RandomSearchCriteria criteria = new RandomSearchCriteria(
|
||||
size,
|
||||
genre,
|
||||
fromYear,
|
||||
toYear,
|
||||
musicFolders,
|
||||
minLastPlayedDate,
|
||||
maxLastPlayedDate,
|
||||
minAlbumRating,
|
||||
maxAlbumRating,
|
||||
minPlayCount,
|
||||
maxPlayCount,
|
||||
doesShowStarredSongs,
|
||||
doesShowUnstarredSongs,
|
||||
format
|
||||
);
|
||||
User user = securityService.getCurrentUser(request);
|
||||
Player player = playerService.getPlayer(request, response);
|
||||
PlayQueue playQueue = player.getPlayQueue();
|
||||
|
||||
RandomSearchCriteria criteria = new RandomSearchCriteria(size, genre, fromYear, toYear, musicFolders);
|
||||
playQueue.addFiles(false, searchService.getRandomSongs(criteria));
|
||||
playQueue.addFiles(shouldAddToPlayList, mediaFileService.getRandomSongs(criteria, user.getUsername()));
|
||||
|
||||
if (request.getParameter("autoRandom") != null) {
|
||||
playQueue.setRandomSearchCriteria(criteria);
|
||||
@@ -110,10 +252,6 @@ public class RandomPlayQueueController extends ParameterizableViewController {
|
||||
this.reloadFrames = reloadFrames;
|
||||
}
|
||||
|
||||
public void setSearchService(SearchService searchService) {
|
||||
this.searchService = searchService;
|
||||
}
|
||||
|
||||
public void setSecurityService(SecurityService securityService) {
|
||||
this.securityService = securityService;
|
||||
}
|
||||
@@ -121,4 +259,8 @@ public class RandomPlayQueueController extends ParameterizableViewController {
|
||||
public void setSettingsService(SettingsService settingsService) {
|
||||
this.settingsService = settingsService;
|
||||
}
|
||||
|
||||
public void setMediaFileService(MediaFileService mediaFileService) {
|
||||
this.mediaFileService = mediaFileService;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,10 +20,12 @@
|
||||
package org.libresonic.player.dao;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.libresonic.player.domain.RandomSearchCriteria;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
import org.libresonic.player.domain.Genre;
|
||||
import org.libresonic.player.domain.MediaFile;
|
||||
import org.libresonic.player.domain.MusicFolder;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
@@ -480,6 +482,114 @@ public class MediaFileDao extends AbstractDao {
|
||||
rowMapper, args);
|
||||
}
|
||||
|
||||
public List<MediaFile> getRandomSongs(RandomSearchCriteria criteria, final String username) {
|
||||
if (criteria.getMusicFolders().isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Map<String, Object> args = new HashMap<String, Object>() {{
|
||||
put("folders", MusicFolder.toPathList(criteria.getMusicFolders()));
|
||||
put("username", username);
|
||||
put("count", criteria.getCount());
|
||||
put("fromYear", criteria.getFromYear());
|
||||
put("toYear", criteria.getToYear());
|
||||
put("genre", criteria.getGenre());
|
||||
put("minLastPlayed", criteria.getMinLastPlayedDate());
|
||||
put("maxLastPlayed", criteria.getMaxLastPlayedDate());
|
||||
put("minAlbumRating", criteria.getMinAlbumRating());
|
||||
put("maxAlbumRating", criteria.getMaxAlbumRating());
|
||||
put("minPlayCount", criteria.getMinPlayCount());
|
||||
put("maxPlayCount", criteria.getMaxPlayCount());
|
||||
put("starred", criteria.isShowStarredSongs());
|
||||
put("unstarred", criteria.isShowUnstarredSongs());
|
||||
put("format", criteria.getFormat());
|
||||
}};
|
||||
|
||||
boolean joinAlbumRating = (criteria.getMinAlbumRating() != null || criteria.getMaxAlbumRating() != null);
|
||||
boolean joinStarred = (criteria.isShowStarredSongs() ^ criteria.isShowUnstarredSongs());
|
||||
|
||||
String query = "select top :count " + prefix(COLUMNS, "media_file") + " from media_file ";
|
||||
|
||||
if (joinStarred) {
|
||||
query += "left outer join starred_media_file on media_file.id = starred_media_file.media_file_id and starred_media_file.username = :username ";
|
||||
}
|
||||
|
||||
if (joinAlbumRating) {
|
||||
query += "left outer join media_file media_album on media_album.type = 'ALBUM' and media_album.album = media_file.album and media_album.artist = media_file.artist ";
|
||||
query += "left outer join user_rating on user_rating.path = media_album.path and user_rating.username = :username ";
|
||||
}
|
||||
|
||||
query += " where media_file.present and media_file.type = 'MUSIC'";
|
||||
|
||||
if (!criteria.getMusicFolders().isEmpty()) {
|
||||
query += " and media_file.folder in (:folders)";
|
||||
}
|
||||
|
||||
if (criteria.getGenre() != null) {
|
||||
query += " and media_file.genre = :genre";
|
||||
}
|
||||
|
||||
if (criteria.getFormat() != null) {
|
||||
query += " and media_file.format = :format";
|
||||
}
|
||||
|
||||
if (criteria.getFromYear() != null) {
|
||||
query += " and media_file.year >= :fromYear";
|
||||
}
|
||||
|
||||
if (criteria.getToYear() != null) {
|
||||
query += " and media_file.year <= :toYear";
|
||||
}
|
||||
|
||||
if (criteria.getMinLastPlayedDate() != null) {
|
||||
query += " and media_file.last_played >= :minLastPlayed";
|
||||
}
|
||||
|
||||
if (criteria.getMaxLastPlayedDate() != null) {
|
||||
if (criteria.getMinLastPlayedDate() == null) {
|
||||
query += " and (media_file.last_played is null or media_file.last_played <= :maxLastPlayed)";
|
||||
} else {
|
||||
query += " and media_file.last_played <= :maxLastPlayed";
|
||||
}
|
||||
}
|
||||
|
||||
if (criteria.getMinAlbumRating() != null) {
|
||||
query += " and user_rating.rating >= :minAlbumRating";
|
||||
}
|
||||
|
||||
if (criteria.getMaxAlbumRating() != null) {
|
||||
if (criteria.getMinAlbumRating() == null) {
|
||||
query += " and (user_rating.rating is null or user_rating.rating <= :maxAlbumRating)";
|
||||
} else {
|
||||
query += " and user_rating.rating <= :maxAlbumRating";
|
||||
}
|
||||
}
|
||||
|
||||
if (criteria.getMinPlayCount() != null) {
|
||||
query += " and media_file.play_count >= :minPlayCount";
|
||||
}
|
||||
|
||||
if (criteria.getMaxPlayCount() != null) {
|
||||
if (criteria.getMinPlayCount() == null) {
|
||||
query += " and (media_file.play_count is null or media_file.play_count <= :maxPlayCount)";
|
||||
} else {
|
||||
query += " and media_file.play_count <= :maxPlayCount";
|
||||
}
|
||||
}
|
||||
|
||||
if (criteria.isShowStarredSongs() && !criteria.isShowUnstarredSongs()) {
|
||||
query += " and starred_media_file.id is not null";
|
||||
}
|
||||
|
||||
if (criteria.isShowUnstarredSongs() && !criteria.isShowStarredSongs()) {
|
||||
query += " and starred_media_file.id is null";
|
||||
}
|
||||
|
||||
query += " order by rand()";
|
||||
|
||||
return namedQuery(query, rowMapper, args);
|
||||
}
|
||||
|
||||
public int getAlbumCount(final List<MusicFolder> musicFolders) {
|
||||
if (musicFolders.isEmpty()) {
|
||||
return 0;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
package org.libresonic.player.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -34,6 +35,15 @@ public class RandomSearchCriteria {
|
||||
private final Integer fromYear;
|
||||
private final Integer toYear;
|
||||
private final List<MusicFolder> musicFolders;
|
||||
private final Date minLastPlayedDate;
|
||||
private final Date maxLastPlayedDate;
|
||||
private final Integer minAlbumRating;
|
||||
private final Integer maxAlbumRating;
|
||||
private final Integer minPlayCount;
|
||||
private final Integer maxPlayCount;
|
||||
private final boolean showStarredSongs;
|
||||
private final boolean showUnstarredSongs;
|
||||
private final String format;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
@@ -45,11 +55,61 @@ public class RandomSearchCriteria {
|
||||
* @param musicFolders Only return songs from these music folder. May NOT be <code>null</code>.
|
||||
*/
|
||||
public RandomSearchCriteria(int count, String genre, Integer fromYear, Integer toYear, List<MusicFolder> musicFolders) {
|
||||
this(
|
||||
count, genre, fromYear, toYear, musicFolders,
|
||||
null, null, null, null, null, null, true, true, null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param count Maximum number of songs to return.
|
||||
* @param genre Only return songs of the given genre. May be <code>null</code>.
|
||||
* @param fromYear Only return songs released after (or in) this year. May be <code>null</code>.
|
||||
* @param toYear Only return songs released before (or in) this year. May be <code>null</code>.
|
||||
* @param musicFolders Only return songs from these music folder. May NOT be <code>null</code>.
|
||||
* @param minLastPlayedDate Only return songs last played after this date. May be <code>null</code>.
|
||||
* @param maxLastPlayedDate Only return songs last played before this date. May be <code>null</code>.
|
||||
* @param minAlbumRating Only return songs rated more or equalt to this value. May be <code>null</code>.
|
||||
* @param maxAlbumRating Only return songs rated less or equal to this value. May be <code>null</code>.
|
||||
* @param minPlayCount Only return songs whose play count is more or equal to this value. May be <code>null</code>.
|
||||
* @param maxPlayCount Only return songs whose play count is less or equal to this value. May be <code>null</code>.
|
||||
* @param showStarredSongs Show starred songs. May NOT be <code>null</code>.
|
||||
* @param showUnstarredSongs Show unstarred songs. May NOT be <code>null</code>.
|
||||
* @param format Only return songs whose file format is equal to this value. May be <code>null</code>.
|
||||
*/
|
||||
public RandomSearchCriteria(
|
||||
int count,
|
||||
String genre,
|
||||
Integer fromYear,
|
||||
Integer toYear,
|
||||
List<MusicFolder> musicFolders,
|
||||
Date minLastPlayedDate,
|
||||
Date maxLastPlayedDate,
|
||||
Integer minAlbumRating,
|
||||
Integer maxAlbumRating,
|
||||
Integer minPlayCount,
|
||||
Integer maxPlayCount,
|
||||
boolean showStarredSongs,
|
||||
boolean showUnstarredSongs,
|
||||
String format
|
||||
) {
|
||||
|
||||
this.count = count;
|
||||
this.genre = genre;
|
||||
this.fromYear = fromYear;
|
||||
this.toYear = toYear;
|
||||
this.musicFolders = musicFolders;
|
||||
this.minLastPlayedDate = minLastPlayedDate;
|
||||
this.maxLastPlayedDate = maxLastPlayedDate;
|
||||
this.minAlbumRating = minAlbumRating;
|
||||
this.maxAlbumRating = maxAlbumRating;
|
||||
this.minPlayCount = minPlayCount;
|
||||
this.maxPlayCount = maxPlayCount;
|
||||
this.showStarredSongs = showStarredSongs;
|
||||
this.showUnstarredSongs = showUnstarredSongs;
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
@@ -71,4 +131,40 @@ public class RandomSearchCriteria {
|
||||
public List<MusicFolder> getMusicFolders() {
|
||||
return musicFolders;
|
||||
}
|
||||
|
||||
public Date getMinLastPlayedDate() {
|
||||
return minLastPlayedDate;
|
||||
}
|
||||
|
||||
public Date getMaxLastPlayedDate() {
|
||||
return maxLastPlayedDate;
|
||||
}
|
||||
|
||||
public Integer getMinAlbumRating() {
|
||||
return minAlbumRating;
|
||||
}
|
||||
|
||||
public Integer getMaxAlbumRating() {
|
||||
return maxAlbumRating;
|
||||
}
|
||||
|
||||
public boolean isShowStarredSongs() {
|
||||
return showStarredSongs;
|
||||
}
|
||||
|
||||
public boolean isShowUnstarredSongs() {
|
||||
return showUnstarredSongs;
|
||||
}
|
||||
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public Integer getMinPlayCount() {
|
||||
return minPlayCount;
|
||||
}
|
||||
|
||||
public Integer getMaxPlayCount() {
|
||||
return maxPlayCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,11 +41,7 @@ import net.sf.ehcache.Element;
|
||||
import org.libresonic.player.Logger;
|
||||
import org.libresonic.player.dao.AlbumDao;
|
||||
import org.libresonic.player.dao.MediaFileDao;
|
||||
import org.libresonic.player.domain.Album;
|
||||
import org.libresonic.player.domain.Genre;
|
||||
import org.libresonic.player.domain.MediaFile;
|
||||
import org.libresonic.player.domain.MediaFileComparator;
|
||||
import org.libresonic.player.domain.MusicFolder;
|
||||
import org.libresonic.player.domain.*;
|
||||
import org.libresonic.player.service.metadata.JaudiotaggerParser;
|
||||
import org.libresonic.player.service.metadata.MetaData;
|
||||
import org.libresonic.player.service.metadata.MetaDataParser;
|
||||
@@ -331,7 +327,7 @@ public class MediaFileService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns random songs for the give parent.
|
||||
* Returns random songs for the given parent.
|
||||
*
|
||||
* @param parent The parent.
|
||||
* @param count Max number of songs to return.
|
||||
@@ -348,6 +344,18 @@ public class MediaFileService {
|
||||
return children.subList(0, Math.min(count, children.size()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns random songs matching search criteria.
|
||||
*
|
||||
* @param criteria Random search criteria.
|
||||
* @param count Max number of songs to return.
|
||||
* @return Random songs
|
||||
* @see SearchService.getRandomSongs
|
||||
*/
|
||||
public List<MediaFile> getRandomSongs(RandomSearchCriteria criteria, String username) {
|
||||
return mediaFileDao.getRandomSongs(criteria, username);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes video files from the given list.
|
||||
*/
|
||||
|
||||
+20
-3
@@ -233,12 +233,29 @@ more.random.text = Shuffle play
|
||||
more.random.songs = {0} songs
|
||||
more.random.auto = Play more random songs when end of play queue is reached.
|
||||
more.random.ok = OK
|
||||
more.random.genre = from genre
|
||||
more.random.addtoplaylist = Add to current playlist
|
||||
more.random.any = Any
|
||||
more.random.format = Format
|
||||
more.random.genre = Genre
|
||||
more.random.anygenre = Any
|
||||
more.random.year = and year
|
||||
more.random.year = Year
|
||||
more.random.anyyear = Any
|
||||
more.random.folder = in folder
|
||||
more.random.folder = Folder
|
||||
more.random.anyfolder = Any
|
||||
more.random.star = star
|
||||
more.random.stars = stars
|
||||
more.random.starred = Starred
|
||||
more.random.unstarred = Unstarred
|
||||
more.random.songrating = Song rating
|
||||
more.random.albumrating = Album rating
|
||||
more.random.lastplayed = Last played
|
||||
more.random.playcount = Play count
|
||||
more.random.1day = 1 day ago
|
||||
more.random.1week = 1 week ago
|
||||
more.random.1month = 1 month ago
|
||||
more.random.3months = 3 months ago
|
||||
more.random.6months = 6 months ago
|
||||
more.random.1year = 1 year ago
|
||||
more.apps.title = Libresonic Apps
|
||||
more.apps.text = <p>Check out the steadily growing list of <a href="http://libresonic.org/pages/apps.jsp" target="_blank">Libresonic apps</a>. \
|
||||
These provide fun and alternative ways to enjoy your media collection - no matter where you are. \
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<style type="text/css">
|
||||
#progressBar {width: 350px; height: 10px; border: 1px solid black; display:none;}
|
||||
#progressBarContent {width: 0; height: 10px; background: url("<c:url value="/icons/default_light/progress.png"/>") repeat;}
|
||||
#randomPlayQueue td { padding: 0 5px; }
|
||||
</style>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/transferService.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/engine.js"/>"></script>
|
||||
@@ -36,6 +38,58 @@
|
||||
window.setTimeout("refreshProgress()", 5000);
|
||||
}
|
||||
}
|
||||
|
||||
// From Modernizr
|
||||
// See: https://modernizr.com/
|
||||
function isLocalStorageEnabled() {
|
||||
var mod = 'modernizr';
|
||||
try {
|
||||
localStorage.setItem(mod, mod);
|
||||
localStorage.removeItem(mod);
|
||||
return true;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Load previously used shuffle parameters
|
||||
function loadShuffleForm() {
|
||||
if (!isLocalStorageEnabled()) return;
|
||||
var form = document.getElementById("randomPlayQueue");
|
||||
try {
|
||||
var data = JSON.parse(localStorage.getItem("randomPlayQueue"));
|
||||
} catch(e) { return; }
|
||||
elements = form.getElementsByTagName("input");
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
if (elements[i].type == "submit") continue;
|
||||
if (data[elements[i].name]) elements[i].value = data[elements[i].name];
|
||||
}
|
||||
elements = form.getElementsByTagName("select");
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
if (data[elements[i].name]) elements[i].value = data[elements[i].name];
|
||||
}
|
||||
}
|
||||
|
||||
// Save shuffle parameters
|
||||
function saveShuffleForm() {
|
||||
if (!isLocalStorageEnabled()) return;
|
||||
var form = document.getElementById("randomPlayQueue");
|
||||
var data = {}
|
||||
var elements = [];
|
||||
elements = form.getElementsByTagName("input");
|
||||
for (var i = 0; i < elements.length; i++) data[elements[i].name] = elements[i].value;
|
||||
elements = form.getElementsByTagName("select");
|
||||
for (var i = 0; i < elements.length; i++) data[elements[i].name] = elements[i].value;
|
||||
localStorage.setItem("randomPlayQueue", JSON.stringify(data));
|
||||
}
|
||||
|
||||
$(function() {
|
||||
${model.user.uploadRole ? "refreshProgress();" : ""}
|
||||
$("#randomPlayQueue").on("submit", saveShuffleForm);
|
||||
loadShuffleForm();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style type="text/css">
|
||||
@@ -45,7 +99,7 @@
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body class="mainframe bgcolor1" onload="${model.user.uploadRole ? "refreshProgress()" : ""}">
|
||||
<body class="mainframe bgcolor1">
|
||||
|
||||
<h1>
|
||||
<img src="<spring:theme code="moreImage"/>" alt=""/>
|
||||
@@ -58,31 +112,23 @@
|
||||
<span style="vertical-align: middle"><fmt:message key="more.random.title"/></span>
|
||||
</h2>
|
||||
|
||||
<form method="post" action="randomPlayQueue.view?">
|
||||
<form id="randomPlayQueue" method="post" action="randomPlayQueue.view?">
|
||||
<table>
|
||||
<tr>
|
||||
<td><fmt:message key="more.random.text"/></td>
|
||||
<td>
|
||||
<select name="size">
|
||||
<select style="width: 100%;" name="size">
|
||||
<option value="10"><fmt:message key="more.random.songs"><fmt:param value="10"/></fmt:message></option>
|
||||
<option value="20" selected><fmt:message key="more.random.songs"><fmt:param value="20"/></fmt:message></option>
|
||||
<option value="30"><fmt:message key="more.random.songs"><fmt:param value="30"/></fmt:message></option>
|
||||
<option value="40"><fmt:message key="more.random.songs"><fmt:param value="40"/></fmt:message></option>
|
||||
<option value="50"><fmt:message key="more.random.songs"><fmt:param value="50"/></fmt:message></option>
|
||||
</select>
|
||||
</td>
|
||||
<td><fmt:message key="more.random.genre"/></td>
|
||||
<td>
|
||||
<select name="genre">
|
||||
<option value="any"><fmt:message key="more.random.anygenre"/></option>
|
||||
<c:forEach items="${model.genres}" var="genre">
|
||||
<option value="${genre.name}"><str:truncateNicely upper="20">${genre.name} (${genre.songCount})</str:truncateNicely></option>
|
||||
</c:forEach>
|
||||
<option value="100"><fmt:message key="more.random.songs"><fmt:param value="100"/></fmt:message></option>
|
||||
</select>
|
||||
</td>
|
||||
<td><fmt:message key="more.random.year"/></td>
|
||||
<td>
|
||||
<select name="year">
|
||||
<select style="width: 100%;" name="year">
|
||||
<option value="any"><fmt:message key="more.random.anyyear"/></option>
|
||||
|
||||
<c:forEach begin="0" end="${model.currentYear - 2010}" var="yearOffset">
|
||||
@@ -101,17 +147,99 @@
|
||||
<option value="0 1949">< 1950</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="more.random.genre"/></td>
|
||||
<td>
|
||||
<select style="width: 100%;" name="genre">
|
||||
<option value="any"><fmt:message key="more.random.anygenre"/></option>
|
||||
<c:forEach items="${model.genres}" var="genre">
|
||||
<option value="${genre.name}"><str:truncateNicely upper="20">${genre.name} (${genre.songCount})</str:truncateNicely></option>
|
||||
</c:forEach>
|
||||
</select>
|
||||
</td>
|
||||
<td><fmt:message key="more.random.albumrating"/></td>
|
||||
<td>
|
||||
<select name="albumRatingComp">
|
||||
<option value="lt"><</option>
|
||||
<option value="le">≤</option>
|
||||
<option value="eq">=</option>
|
||||
<option value="ge" selected="selected">≥</option>
|
||||
<option value="gt">></option>
|
||||
</select>
|
||||
<select name="albumRatingValue">
|
||||
<option value="any" selected="selected"><fmt:message key="more.random.any"/></option>
|
||||
<option value="0">0 <fmt:message key="more.random.stars"/></option>
|
||||
<option value="1">1 <fmt:message key="more.random.star"/></option>
|
||||
<option value="2">2 <fmt:message key="more.random.stars"/></option>
|
||||
<option value="3">3 <fmt:message key="more.random.stars"/></option>
|
||||
<option value="4">4 <fmt:message key="more.random.stars"/></option>
|
||||
<option value="5">5 <fmt:message key="more.random.stars"/></option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="more.random.songrating"/></td>
|
||||
<td>
|
||||
<select style="width: 100%;" name="songRating">
|
||||
<option value="any" selected="selected"><fmt:message key="more.random.any"/></option>
|
||||
<option value="starred"><fmt:message key="more.random.starred"/></option>
|
||||
<option value="unstarred"><fmt:message key="more.random.unstarred"/></option>
|
||||
</select>
|
||||
</td>
|
||||
<td><fmt:message key="more.random.lastplayed"/></td>
|
||||
<td>
|
||||
<select name="lastPlayedComp">
|
||||
<option value="lt" selected="selected"><</option>
|
||||
<option value="gt">></option>
|
||||
</select>
|
||||
<select name="lastPlayedValue">
|
||||
<option value="any" selected="selected"><fmt:message key="more.random.any"/></option>
|
||||
<option value="1day"><fmt:message key="more.random.1day"/></option>
|
||||
<option value="1week"><fmt:message key="more.random.1week"/></option>
|
||||
<option value="1month"><fmt:message key="more.random.1month"/></option>
|
||||
<option value="3months"><fmt:message key="more.random.3months"/></option>
|
||||
<option value="6months"><fmt:message key="more.random.6months"/></option>
|
||||
<option value="1year"><fmt:message key="more.random.1year"/></option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="more.random.folder"/></td>
|
||||
<td>
|
||||
<select name="musicFolderId">
|
||||
<select style="width: 100%;" name="musicFolderId">
|
||||
<option value="-1"><fmt:message key="more.random.anyfolder"/></option>
|
||||
<c:forEach items="${model.musicFolders}" var="musicFolder">
|
||||
<option value="${musicFolder.id}">${musicFolder.name}</option>
|
||||
</c:forEach>
|
||||
</select>
|
||||
</td>
|
||||
<td><fmt:message key="more.random.playcount"/></td>
|
||||
<td>
|
||||
<input type="submit" value="<fmt:message key="more.random.ok"/>">
|
||||
<select name="playCountComp">
|
||||
<option value="lt" selected="selected"><</option>
|
||||
<option value="gt">></option>
|
||||
</select>
|
||||
<input type="number" name="playCountValue"/> times
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="more.random.format"/></td>
|
||||
<td>
|
||||
<select style="width: 100%;" name="format">
|
||||
<option value="any" selected="selected"><fmt:message key="more.random.any"/></option>
|
||||
<option value="flac">FLAC</option>
|
||||
<option value="mp3">MP3</option>
|
||||
</select>
|
||||
</td>
|
||||
<td><fmt:message key="more.random.addtoplaylist"/></td>
|
||||
<td>
|
||||
<input name="addToPlaylist" value="true" type="checkbox"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<input type="submit" value="<fmt:message key="more.random.ok"/>">
|
||||
</td>
|
||||
</tr>
|
||||
<c:if test="${not model.clientSidePlaylist}">
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
<bean id="randomPlayQueueController" class="org.libresonic.player.controller.RandomPlayQueueController">
|
||||
<property name="viewName" value="reload"/>
|
||||
<property name="playerService" ref="playerService"/>
|
||||
<property name="searchService" ref="searchService"/>
|
||||
<property name="mediaFileService" ref="mediaFileService"/>
|
||||
<property name="securityService" ref="securityService"/>
|
||||
<property name="settingsService" ref="settingsService"/>
|
||||
<property name="reloadFrames">
|
||||
|
||||
Reference in New Issue
Block a user