Implement shuffle radio feature (#145)
This commit is contained in:
@@ -33,15 +33,17 @@ public class PlayQueueInfo {
|
|||||||
private final List<Entry> entries;
|
private final List<Entry> entries;
|
||||||
private final boolean stopEnabled;
|
private final boolean stopEnabled;
|
||||||
private final boolean repeatEnabled;
|
private final boolean repeatEnabled;
|
||||||
|
private final boolean radioEnabled;
|
||||||
private final boolean sendM3U;
|
private final boolean sendM3U;
|
||||||
private final float gain;
|
private final float gain;
|
||||||
private int startPlayerAt = -1;
|
private int startPlayerAt = -1;
|
||||||
private long startPlayerAtPosition; // millis
|
private long startPlayerAtPosition; // millis
|
||||||
|
|
||||||
public PlayQueueInfo(List<Entry> entries, boolean stopEnabled, boolean repeatEnabled, boolean sendM3U, float gain) {
|
public PlayQueueInfo(List<Entry> entries, boolean stopEnabled, boolean repeatEnabled, boolean radioEnabled, boolean sendM3U, float gain) {
|
||||||
this.entries = entries;
|
this.entries = entries;
|
||||||
this.stopEnabled = stopEnabled;
|
this.stopEnabled = stopEnabled;
|
||||||
this.repeatEnabled = repeatEnabled;
|
this.repeatEnabled = repeatEnabled;
|
||||||
|
this.radioEnabled = radioEnabled;
|
||||||
this.sendM3U = sendM3U;
|
this.sendM3U = sendM3U;
|
||||||
this.gain = gain;
|
this.gain = gain;
|
||||||
}
|
}
|
||||||
@@ -72,6 +74,10 @@ public class PlayQueueInfo {
|
|||||||
return repeatEnabled;
|
return repeatEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isRadioEnabled() {
|
||||||
|
return radioEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
public float getGain() {
|
public float getGain() {
|
||||||
return gain;
|
return gain;
|
||||||
}
|
}
|
||||||
@@ -215,4 +221,4 @@ public class PlayQueueInfo {
|
|||||||
return remoteCoverArtUrl;
|
return remoteCoverArtUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,6 +148,18 @@ public class PlayQueueService {
|
|||||||
return convert(request, player, serverSidePlaylist, offset);
|
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) {
|
public void savePlayQueue(int currentSongIndex, long positionMillis) {
|
||||||
HttpServletRequest request = WebContextFactory.get().getHttpServletRequest();
|
HttpServletRequest request = WebContextFactory.get().getHttpServletRequest();
|
||||||
HttpServletResponse response = WebContextFactory.get().getHttpServletResponse();
|
HttpServletResponse response = WebContextFactory.get().getHttpServletResponse();
|
||||||
@@ -581,7 +593,13 @@ public class PlayQueueService {
|
|||||||
HttpServletRequest request = WebContextFactory.get().getHttpServletRequest();
|
HttpServletRequest request = WebContextFactory.get().getHttpServletRequest();
|
||||||
HttpServletResponse response = WebContextFactory.get().getHttpServletResponse();
|
HttpServletResponse response = WebContextFactory.get().getHttpServletResponse();
|
||||||
Player player = getCurrentPlayer(request, response);
|
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);
|
return convert(request, player, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -668,7 +686,7 @@ public class PlayQueueService {
|
|||||||
}
|
}
|
||||||
boolean isStopEnabled = playQueue.getStatus() == PlayQueue.Status.PLAYING && !player.isExternalWithPlaylist();
|
boolean isStopEnabled = playQueue.getStatus() == PlayQueue.Status.PLAYING && !player.isExternalWithPlaylist();
|
||||||
float gain = jukeboxService.getGain();
|
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) {
|
private String formatFileSize(Long fileSize, Locale locale) {
|
||||||
@@ -751,4 +769,4 @@ public class PlayQueueService {
|
|||||||
public void setPlaylistService(PlaylistService playlistService) {
|
public void setPlaylistService(PlaylistService playlistService) {
|
||||||
this.playlistService = playlistService;
|
this.playlistService = playlistService;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -199,7 +199,7 @@ public class RandomPlayQueueController extends ParameterizableViewController {
|
|||||||
List<MusicFolder> musicFolders = getMusicFolders(request);
|
List<MusicFolder> musicFolders = getMusicFolders(request);
|
||||||
|
|
||||||
// Do we add to the current playlist or do we replace it?
|
// 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
|
// Search the database using these criteria
|
||||||
RandomSearchCriteria criteria = new RandomSearchCriteria(
|
RandomSearchCriteria criteria = new RandomSearchCriteria(
|
||||||
|
|||||||
@@ -368,6 +368,15 @@ public class PlayQueue {
|
|||||||
this.repeatEnabled = repeatEnabled;
|
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.
|
* Revert the last operation.
|
||||||
*/
|
*/
|
||||||
@@ -455,4 +464,4 @@ public class PlayQueue {
|
|||||||
ARTIST,
|
ARTIST,
|
||||||
ALBUM
|
ALBUM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -100,6 +100,7 @@ playlist.clear = Clear
|
|||||||
playlist.shuffle = Shuffle
|
playlist.shuffle = Shuffle
|
||||||
playlist.repeat_on = Repeat is on
|
playlist.repeat_on = Repeat is on
|
||||||
playlist.repeat_off = Repeat is off
|
playlist.repeat_off = Repeat is off
|
||||||
|
playlist.repeat_radio = Stop shuffle radio
|
||||||
playlist.undo = Undo
|
playlist.undo = Undo
|
||||||
playlist.settings = Settings
|
playlist.settings = Settings
|
||||||
playlist.more = More actions...
|
playlist.more = More actions...
|
||||||
@@ -233,7 +234,8 @@ more.random.text = Shuffle play
|
|||||||
more.random.songs = {0} songs
|
more.random.songs = {0} songs
|
||||||
more.random.auto = Play more random songs when end of play queue is reached.
|
more.random.auto = Play more random songs when end of play queue is reached.
|
||||||
more.random.ok = OK
|
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.any = Any
|
||||||
more.random.format = Format
|
more.random.format = Format
|
||||||
more.random.genre = Genre
|
more.random.genre = Genre
|
||||||
|
|||||||
@@ -232,24 +232,13 @@
|
|||||||
<option value="mp3">MP3</option>
|
<option value="mp3">MP3</option>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td><fmt:message key="more.random.addtoplaylist"/></td>
|
|
||||||
<td>
|
|
||||||
<input name="addToPlaylist" value="true" type="checkbox"/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
<input type="submit" value="<fmt:message key="more.random.ok"/>">
|
<input type="submit" name="addToPlaylist" value="<fmt:message key="more.random.add"/>">
|
||||||
|
<input type="submit" name="autoRandom" value="<fmt:message key="more.random.radio"/>">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<c:if test="${not model.clientSidePlaylist}">
|
|
||||||
<tr>
|
|
||||||
<td colspan="9">
|
|
||||||
<input type="checkbox" name="autoRandom" id="autoRandom" class="checkbox"/>
|
|
||||||
<label for="autoRandom"><fmt:message key="more.random.auto"/></label>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</c:if>
|
|
||||||
</table>
|
</table>
|
||||||
</form>
|
</form>
|
||||||
</c:if>
|
</c:if>
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
var songs = null;
|
var songs = null;
|
||||||
var currentStreamUrl = null;
|
var currentStreamUrl = null;
|
||||||
var repeatEnabled = false;
|
var repeatEnabled = false;
|
||||||
|
var radioEnabled = false;
|
||||||
var isVisible = ${model.autoHide ? 'false' : 'true'};
|
var isVisible = ${model.autoHide ? 'false' : 'true'};
|
||||||
var CastPlayer = new CastPlayer();
|
var CastPlayer = new CastPlayer();
|
||||||
var ignore = false;
|
var ignore = false;
|
||||||
@@ -269,7 +270,13 @@
|
|||||||
}
|
}
|
||||||
function onNext(wrap) {
|
function onNext(wrap) {
|
||||||
var index = parseInt(getCurrentSongIndex()) + 1;
|
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;
|
index = index % songs.length;
|
||||||
}
|
}
|
||||||
onSkip(index);
|
onSkip(index);
|
||||||
@@ -402,14 +409,20 @@
|
|||||||
function playQueueCallback(playQueue) {
|
function playQueueCallback(playQueue) {
|
||||||
songs = playQueue.entries;
|
songs = playQueue.entries;
|
||||||
repeatEnabled = playQueue.repeatEnabled;
|
repeatEnabled = playQueue.repeatEnabled;
|
||||||
|
radioEnabled = playQueue.radioEnabled;
|
||||||
if ($("#start")) {
|
if ($("#start")) {
|
||||||
$("#start").toggle(!playQueue.stopEnabled);
|
$("#start").toggle(!playQueue.stopEnabled);
|
||||||
$("#stop").toggle(playQueue.stopEnabled);
|
$("#stop").toggle(playQueue.stopEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($("#toggleRepeat")) {
|
if ($("#toggleRepeat")) {
|
||||||
var text = repeatEnabled ? "<fmt:message key="playlist.repeat_on"/>" : "<fmt:message key="playlist.repeat_off"/>";
|
if (radioEnabled) {
|
||||||
$("#toggleRepeat").html(text);
|
$("#toggleRepeat").html("<fmt:message key="playlist.repeat_radio"/>");
|
||||||
|
} else if (repeatEnabled) {
|
||||||
|
$("#toggleRepeat").html("<fmt:message key="playlist.repeat_on"/>");
|
||||||
|
} else {
|
||||||
|
$("#toggleRepeat").html("<fmt:message key="playlist.repeat_off"/>");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (songs.length == 0) {
|
if (songs.length == 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user