From 6d8df63a7e022532271c476b40da945d3cb50d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Thomas?= Date: Sat, 10 Dec 2016 18:22:59 +0100 Subject: [PATCH] Implement shuffle radio feature (#145) --- .../libresonic/player/ajax/PlayQueueInfo.java | 10 ++++++-- .../player/ajax/PlayQueueService.java | 24 ++++++++++++++++--- .../controller/RandomPlayQueueController.java | 2 +- .../libresonic/player/domain/PlayQueue.java | 11 ++++++++- .../player/i18n/ResourceBundle_en.properties | 4 +++- .../src/main/webapp/WEB-INF/jsp/more.jsp | 15 ++---------- .../src/main/webapp/WEB-INF/jsp/playQueue.jsp | 19 ++++++++++++--- 7 files changed, 61 insertions(+), 24 deletions(-) diff --git a/libresonic-main/src/main/java/org/libresonic/player/ajax/PlayQueueInfo.java b/libresonic-main/src/main/java/org/libresonic/player/ajax/PlayQueueInfo.java index 8d522cc4..0cb5f541 100644 --- a/libresonic-main/src/main/java/org/libresonic/player/ajax/PlayQueueInfo.java +++ b/libresonic-main/src/main/java/org/libresonic/player/ajax/PlayQueueInfo.java @@ -33,15 +33,17 @@ public class PlayQueueInfo { private final List entries; private final boolean stopEnabled; private final boolean repeatEnabled; + private final boolean radioEnabled; private final boolean sendM3U; private final float gain; private int startPlayerAt = -1; private long startPlayerAtPosition; // millis - public PlayQueueInfo(List entries, boolean stopEnabled, boolean repeatEnabled, boolean sendM3U, float gain) { + public PlayQueueInfo(List entries, boolean stopEnabled, boolean repeatEnabled, boolean radioEnabled, boolean sendM3U, float gain) { this.entries = entries; this.stopEnabled = stopEnabled; this.repeatEnabled = repeatEnabled; + this.radioEnabled = radioEnabled; this.sendM3U = sendM3U; this.gain = gain; } @@ -72,6 +74,10 @@ public class PlayQueueInfo { return repeatEnabled; } + public boolean isRadioEnabled() { + return radioEnabled; + } + public float getGain() { return gain; } @@ -215,4 +221,4 @@ public class PlayQueueInfo { return remoteCoverArtUrl; } } -} \ No newline at end of file +} diff --git a/libresonic-main/src/main/java/org/libresonic/player/ajax/PlayQueueService.java b/libresonic-main/src/main/java/org/libresonic/player/ajax/PlayQueueService.java index a2496290..bf8ff160 100644 --- a/libresonic-main/src/main/java/org/libresonic/player/ajax/PlayQueueService.java +++ b/libresonic-main/src/main/java/org/libresonic/player/ajax/PlayQueueService.java @@ -148,6 +148,18 @@ public class PlayQueueService { return convert(request, player, serverSidePlaylist, offset); } + public PlayQueueInfo reloadSearchCriteria() throws Exception { + HttpServletRequest request = WebContextFactory.get().getHttpServletRequest(); + HttpServletResponse response = WebContextFactory.get().getHttpServletResponse(); + String username = securityService.getCurrentUsername(request); + Player player = getCurrentPlayer(request, response); + PlayQueue playQueue = player.getPlayQueue(); + if (playQueue.getRandomSearchCriteria() != null) { + playQueue.addFiles(true, mediaFileService.getRandomSongs(playQueue.getRandomSearchCriteria(), username)); + } + return convert(request, player, false); + } + public void savePlayQueue(int currentSongIndex, long positionMillis) { HttpServletRequest request = WebContextFactory.get().getHttpServletRequest(); HttpServletResponse response = WebContextFactory.get().getHttpServletResponse(); @@ -581,7 +593,13 @@ public class PlayQueueService { HttpServletRequest request = WebContextFactory.get().getHttpServletRequest(); HttpServletResponse response = WebContextFactory.get().getHttpServletResponse(); Player player = getCurrentPlayer(request, response); - player.getPlayQueue().setRepeatEnabled(!player.getPlayQueue().isRepeatEnabled()); + PlayQueue playQueue = player.getPlayQueue(); + if (playQueue.isRadioEnabled()) { + playQueue.setRandomSearchCriteria(null); + playQueue.setRepeatEnabled(false); + } else { + playQueue.setRepeatEnabled(!player.getPlayQueue().isRepeatEnabled()); + } return convert(request, player, false); } @@ -668,7 +686,7 @@ public class PlayQueueService { } boolean isStopEnabled = playQueue.getStatus() == PlayQueue.Status.PLAYING && !player.isExternalWithPlaylist(); float gain = jukeboxService.getGain(); - return new PlayQueueInfo(entries, isStopEnabled, playQueue.isRepeatEnabled(), serverSidePlaylist, gain); + return new PlayQueueInfo(entries, isStopEnabled, playQueue.isRepeatEnabled(), playQueue.isRadioEnabled(), serverSidePlaylist, gain); } private String formatFileSize(Long fileSize, Locale locale) { @@ -751,4 +769,4 @@ public class PlayQueueService { public void setPlaylistService(PlaylistService playlistService) { this.playlistService = playlistService; } -} \ No newline at end of file +} diff --git a/libresonic-main/src/main/java/org/libresonic/player/controller/RandomPlayQueueController.java b/libresonic-main/src/main/java/org/libresonic/player/controller/RandomPlayQueueController.java index e741635d..886f278c 100644 --- a/libresonic-main/src/main/java/org/libresonic/player/controller/RandomPlayQueueController.java +++ b/libresonic-main/src/main/java/org/libresonic/player/controller/RandomPlayQueueController.java @@ -199,7 +199,7 @@ public class RandomPlayQueueController extends ParameterizableViewController { List musicFolders = getMusicFolders(request); // Do we add to the current playlist or do we replace it? - boolean shouldAddToPlayList = ServletRequestUtils.getBooleanParameter(request, "addToPlaylist", false); + boolean shouldAddToPlayList = request.getParameter("addToPlaylist") != null; // Search the database using these criteria RandomSearchCriteria criteria = new RandomSearchCriteria( diff --git a/libresonic-main/src/main/java/org/libresonic/player/domain/PlayQueue.java b/libresonic-main/src/main/java/org/libresonic/player/domain/PlayQueue.java index 2cc2ae42..ef665d19 100644 --- a/libresonic-main/src/main/java/org/libresonic/player/domain/PlayQueue.java +++ b/libresonic-main/src/main/java/org/libresonic/player/domain/PlayQueue.java @@ -368,6 +368,15 @@ public class PlayQueue { this.repeatEnabled = repeatEnabled; } + /** + * Returns whether the playlist is a shuffle radio + * + * @return Whether the playlist is a shuffle radio. + */ + public synchronized boolean isRadioEnabled() { + return this.randomSearchCriteria != null; + } + /** * Revert the last operation. */ @@ -455,4 +464,4 @@ public class PlayQueue { ARTIST, ALBUM } -} \ No newline at end of file +} diff --git a/libresonic-main/src/main/resources/org/libresonic/player/i18n/ResourceBundle_en.properties b/libresonic-main/src/main/resources/org/libresonic/player/i18n/ResourceBundle_en.properties index 771acad9..25cff3ab 100644 --- a/libresonic-main/src/main/resources/org/libresonic/player/i18n/ResourceBundle_en.properties +++ b/libresonic-main/src/main/resources/org/libresonic/player/i18n/ResourceBundle_en.properties @@ -100,6 +100,7 @@ playlist.clear = Clear playlist.shuffle = Shuffle playlist.repeat_on = Repeat is on playlist.repeat_off = Repeat is off +playlist.repeat_radio = Stop shuffle radio playlist.undo = Undo playlist.settings = Settings playlist.more = More actions... @@ -233,7 +234,8 @@ 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.addtoplaylist = Add to current playlist +more.random.add = Add to queue +more.random.radio = Shuffle radio more.random.any = Any more.random.format = Format more.random.genre = Genre diff --git a/libresonic-main/src/main/webapp/WEB-INF/jsp/more.jsp b/libresonic-main/src/main/webapp/WEB-INF/jsp/more.jsp index 3d708bf5..cc23dd5a 100644 --- a/libresonic-main/src/main/webapp/WEB-INF/jsp/more.jsp +++ b/libresonic-main/src/main/webapp/WEB-INF/jsp/more.jsp @@ -232,24 +232,13 @@ - - - - - "> + "> + "> - - - - - - - - diff --git a/libresonic-main/src/main/webapp/WEB-INF/jsp/playQueue.jsp b/libresonic-main/src/main/webapp/WEB-INF/jsp/playQueue.jsp index c8917a44..aa48c89d 100644 --- a/libresonic-main/src/main/webapp/WEB-INF/jsp/playQueue.jsp +++ b/libresonic-main/src/main/webapp/WEB-INF/jsp/playQueue.jsp @@ -37,6 +37,7 @@ var songs = null; var currentStreamUrl = null; var repeatEnabled = false; + var radioEnabled = false; var isVisible = ${model.autoHide ? 'false' : 'true'}; var CastPlayer = new CastPlayer(); var ignore = false; @@ -269,7 +270,13 @@ } function onNext(wrap) { var index = parseInt(getCurrentSongIndex()) + 1; - if (wrap) { + if (radioEnabled && index >= songs.length) { + playQueueService.reloadSearchCriteria(function(playQueue) { + playQueueCallback(playQueue); + onSkip(index); + }); + return; + } else if (wrap) { index = index % songs.length; } onSkip(index); @@ -402,14 +409,20 @@ function playQueueCallback(playQueue) { songs = playQueue.entries; repeatEnabled = playQueue.repeatEnabled; + radioEnabled = playQueue.radioEnabled; if ($("#start")) { $("#start").toggle(!playQueue.stopEnabled); $("#stop").toggle(playQueue.stopEnabled); } if ($("#toggleRepeat")) { - var text = repeatEnabled ? "" : ""; - $("#toggleRepeat").html(text); + if (radioEnabled) { + $("#toggleRepeat").html(""); + } else if (repeatEnabled) { + $("#toggleRepeat").html(""); + } else { + $("#toggleRepeat").html(""); + } } if (songs.length == 0) {