Play internet radios in MediaElement (fix #408)
This allows the user to control playback for the internet radios, which were previously started outside of the main player without any possibility for direct control.
This commit is contained in:
@@ -33,17 +33,19 @@ public class PlayQueueInfo {
|
||||
private final List<Entry> entries;
|
||||
private final boolean stopEnabled;
|
||||
private final boolean repeatEnabled;
|
||||
private final boolean radioEnabled;
|
||||
private final boolean shuffleRadioEnabled;
|
||||
private final boolean internetRadioEnabled;
|
||||
private final boolean sendM3U;
|
||||
private final float gain;
|
||||
private int startPlayerAt = -1;
|
||||
private long startPlayerAtPosition; // millis
|
||||
|
||||
public PlayQueueInfo(List<Entry> entries, boolean stopEnabled, boolean repeatEnabled, boolean radioEnabled, boolean sendM3U, float gain) {
|
||||
public PlayQueueInfo(List<Entry> entries, boolean stopEnabled, boolean repeatEnabled, boolean shuffleRadioEnabled, boolean internetRadioEnabled, boolean sendM3U, float gain) {
|
||||
this.entries = entries;
|
||||
this.stopEnabled = stopEnabled;
|
||||
this.repeatEnabled = repeatEnabled;
|
||||
this.radioEnabled = radioEnabled;
|
||||
this.shuffleRadioEnabled = shuffleRadioEnabled;
|
||||
this.internetRadioEnabled = internetRadioEnabled;
|
||||
this.sendM3U = sendM3U;
|
||||
this.gain = gain;
|
||||
}
|
||||
@@ -74,8 +76,12 @@ public class PlayQueueInfo {
|
||||
return repeatEnabled;
|
||||
}
|
||||
|
||||
public boolean isRadioEnabled() {
|
||||
return radioEnabled;
|
||||
public boolean isShuffleRadioEnabled() {
|
||||
return shuffleRadioEnabled;
|
||||
}
|
||||
|
||||
public boolean isInternetRadioEnabled() {
|
||||
return internetRadioEnabled;
|
||||
}
|
||||
|
||||
public float getGain() {
|
||||
@@ -121,9 +127,27 @@ public class PlayQueueInfo {
|
||||
private final String coverArtUrl;
|
||||
private final String remoteCoverArtUrl;
|
||||
|
||||
public Entry(int id, Integer trackNumber, String title, String artist, String album, String genre, Integer year,
|
||||
String bitRate, Integer duration, String durationAsString, String format, String contentType, String fileSize,
|
||||
boolean starred, String albumUrl, String streamUrl, String remoteStreamUrl, String coverArtUrl, String remoteCoverArtUrl) {
|
||||
public Entry(
|
||||
int id,
|
||||
Integer trackNumber,
|
||||
String title,
|
||||
String artist,
|
||||
String album,
|
||||
String genre,
|
||||
Integer year,
|
||||
String bitRate,
|
||||
Integer duration,
|
||||
String durationAsString,
|
||||
String format,
|
||||
String contentType,
|
||||
String fileSize,
|
||||
boolean starred,
|
||||
String albumUrl,
|
||||
String streamUrl,
|
||||
String remoteStreamUrl,
|
||||
String coverArtUrl,
|
||||
String remoteCoverArtUrl) {
|
||||
|
||||
this.id = id;
|
||||
this.trackNumber = trackNumber;
|
||||
this.title = title;
|
||||
@@ -220,5 +244,6 @@ public class PlayQueueInfo {
|
||||
public String getRemoteCoverArtUrl() {
|
||||
return remoteCoverArtUrl;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,11 @@
|
||||
*/
|
||||
package org.airsonic.player.ajax;
|
||||
|
||||
import chameleon.playlist.*;
|
||||
import chameleon.playlist.Playlist;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.airsonic.player.dao.InternetRadioDao;
|
||||
import org.airsonic.player.dao.MediaFileDao;
|
||||
import org.airsonic.player.dao.PlayQueueDao;
|
||||
import org.airsonic.player.domain.*;
|
||||
@@ -28,6 +31,8 @@ import org.airsonic.player.service.*;
|
||||
import org.airsonic.player.service.PlaylistService;
|
||||
import org.airsonic.player.util.StringUtil;
|
||||
import org.directwebremoting.WebContextFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.servlet.support.RequestContextUtils;
|
||||
@@ -35,6 +40,7 @@ import org.springframework.web.servlet.support.RequestContextUtils;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@@ -74,8 +80,12 @@ public class PlayQueueService {
|
||||
@Autowired
|
||||
private PlayQueueDao playQueueDao;
|
||||
@Autowired
|
||||
private InternetRadioDao internetRadioDao;
|
||||
@Autowired
|
||||
private JWTSecurityService jwtSecurityService;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(PlayQueueService.class);
|
||||
|
||||
/**
|
||||
* Returns the play queue for the player of the current user.
|
||||
*
|
||||
@@ -143,6 +153,7 @@ public class PlayQueueService {
|
||||
String username = securityService.getCurrentUsername(request);
|
||||
Player player = getCurrentPlayer(request, response);
|
||||
PlayQueue playQueue = player.getPlayQueue();
|
||||
playQueue.setInternetRadio(null);
|
||||
if (playQueue.getRandomSearchCriteria() != null) {
|
||||
playQueue.addFiles(true, mediaFileService.getRandomSongs(playQueue.getRandomSearchCriteria(), username));
|
||||
}
|
||||
@@ -232,6 +243,19 @@ public class PlayQueueService {
|
||||
return doPlay(request, player, songs).setStartPlayerAt(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index Start playing at this index, or play whole radio playlist if {@code null}.
|
||||
*/
|
||||
public PlayQueueInfo playInternetRadio(int id, Integer index) throws Exception {
|
||||
HttpServletRequest request = WebContextFactory.get().getHttpServletRequest();
|
||||
|
||||
InternetRadio radio = internetRadioDao.getInternetRadioById(id);
|
||||
if (!radio.isEnabled()) { throw new Exception("Radio is not enabled"); }
|
||||
|
||||
Player player = resolvePlayer();
|
||||
return doPlayInternetRadio(request, player, radio).setStartPlayerAt(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index Start playing at this index, or play whole playlist if {@code null}.
|
||||
*/
|
||||
@@ -418,6 +442,17 @@ public class PlayQueueService {
|
||||
}
|
||||
player.getPlayQueue().addFiles(false, files);
|
||||
player.getPlayQueue().setRandomSearchCriteria(null);
|
||||
player.getPlayQueue().setInternetRadio(null);
|
||||
if (player.isJukebox()) {
|
||||
jukeboxService.play(player);
|
||||
}
|
||||
return convert(request, player, true);
|
||||
}
|
||||
|
||||
private PlayQueueInfo doPlayInternetRadio(HttpServletRequest request, Player player, InternetRadio radio) throws Exception {
|
||||
player.getPlayQueue().clear();
|
||||
player.getPlayQueue().setRandomSearchCriteria(null);
|
||||
player.getPlayQueue().setInternetRadio(radio);
|
||||
if (player.isJukebox()) {
|
||||
jukeboxService.play(player);
|
||||
}
|
||||
@@ -433,6 +468,7 @@ public class PlayQueueService {
|
||||
Player player = getCurrentPlayer(request, response);
|
||||
player.getPlayQueue().addFiles(false, randomFiles);
|
||||
player.getPlayQueue().setRandomSearchCriteria(null);
|
||||
player.getPlayQueue().setInternetRadio(null);
|
||||
return convert(request, player, true).setStartPlayerAt(0);
|
||||
}
|
||||
|
||||
@@ -445,6 +481,8 @@ public class PlayQueueService {
|
||||
List<MediaFile> similarSongs = lastFmService.getSimilarSongs(artist, count, musicFolders);
|
||||
Player player = getCurrentPlayer(request, response);
|
||||
player.getPlayQueue().addFiles(false, similarSongs);
|
||||
player.getPlayQueue().setRandomSearchCriteria(null);
|
||||
player.getPlayQueue().setInternetRadio(null);
|
||||
return convert(request, player, true).setStartPlayerAt(0);
|
||||
}
|
||||
|
||||
@@ -478,6 +516,7 @@ public class PlayQueueService {
|
||||
playQueue.addFiles(true, files);
|
||||
}
|
||||
playQueue.setRandomSearchCriteria(null);
|
||||
playQueue.setInternetRadio(null);
|
||||
return playQueue;
|
||||
}
|
||||
|
||||
@@ -589,7 +628,7 @@ public class PlayQueueService {
|
||||
HttpServletResponse response = WebContextFactory.get().getHttpServletResponse();
|
||||
Player player = getCurrentPlayer(request, response);
|
||||
PlayQueue playQueue = player.getPlayQueue();
|
||||
if (playQueue.isRadioEnabled()) {
|
||||
if (playQueue.isShuffleRadioEnabled()) {
|
||||
playQueue.setRandomSearchCriteria(null);
|
||||
playQueue.setRepeatEnabled(false);
|
||||
} else {
|
||||
@@ -636,20 +675,43 @@ public class PlayQueueService {
|
||||
}
|
||||
|
||||
private PlayQueueInfo convert(HttpServletRequest request, Player player, boolean serverSidePlaylist, int offset) throws Exception {
|
||||
|
||||
String url = NetworkService.getBaseUrl(request);
|
||||
|
||||
/* if (serverSidePlaylist && player.isJukebox()) {
|
||||
updateJukebox(player, offset);
|
||||
} */
|
||||
boolean isCurrentPlayer = player.getIpAddress() != null && player.getIpAddress().equals(request.getRemoteAddr());
|
||||
|
||||
boolean m3uSupported = player.isExternal() || player.isExternalWithPlaylist();
|
||||
serverSidePlaylist = player.isAutoControlEnabled() && m3uSupported && isCurrentPlayer && serverSidePlaylist;
|
||||
Locale locale = RequestContextUtils.getLocale(request);
|
||||
|
||||
List<PlayQueueInfo.Entry> entries = new ArrayList<PlayQueueInfo.Entry>();
|
||||
PlayQueue playQueue = player.getPlayQueue();
|
||||
|
||||
List<PlayQueueInfo.Entry> entries;
|
||||
if (playQueue.isInternetRadioEnabled()) {
|
||||
entries = convertInternetRadio(request, player);
|
||||
} else {
|
||||
entries = convertMediaFileList(request, player);
|
||||
}
|
||||
|
||||
boolean isCurrentPlayer = player.getIpAddress() != null && player.getIpAddress().equals(request.getRemoteAddr());
|
||||
boolean isStopEnabled = playQueue.getStatus() == PlayQueue.Status.PLAYING && !player.isExternalWithPlaylist();
|
||||
boolean m3uSupported = player.isExternal() || player.isExternalWithPlaylist();
|
||||
serverSidePlaylist = player.isAutoControlEnabled() && m3uSupported && isCurrentPlayer && serverSidePlaylist;
|
||||
|
||||
float gain = jukeboxService.getGain(player);
|
||||
|
||||
return new PlayQueueInfo(
|
||||
entries,
|
||||
isStopEnabled,
|
||||
playQueue.isRepeatEnabled(),
|
||||
playQueue.isShuffleRadioEnabled(),
|
||||
playQueue.isInternetRadioEnabled(),
|
||||
serverSidePlaylist,
|
||||
gain
|
||||
);
|
||||
}
|
||||
|
||||
private List<PlayQueueInfo.Entry> convertMediaFileList(HttpServletRequest request, Player player) {
|
||||
|
||||
String url = NetworkService.getBaseUrl(request);
|
||||
Locale locale = RequestContextUtils.getLocale(request);
|
||||
PlayQueue playQueue = player.getPlayQueue();
|
||||
|
||||
List<PlayQueueInfo.Entry> entries = new ArrayList<PlayQueueInfo.Entry>();
|
||||
for (MediaFile file : playQueue.getFiles()) {
|
||||
|
||||
String albumUrl = url + "main.view?id=" + file.getId();
|
||||
@@ -668,12 +730,114 @@ public class PlayQueueService {
|
||||
formatFileSize(file.getFileSize(), locale), starred, albumUrl, streamUrl, remoteStreamUrl,
|
||||
coverArtUrl, remoteCoverArtUrl));
|
||||
}
|
||||
boolean isStopEnabled = playQueue.getStatus() == PlayQueue.Status.PLAYING && !player.isExternalWithPlaylist();
|
||||
|
||||
float gain = 0.0f;
|
||||
gain = jukeboxService.getGain(player);
|
||||
return entries;
|
||||
}
|
||||
|
||||
return new PlayQueueInfo(entries, isStopEnabled, playQueue.isRepeatEnabled(), playQueue.isRadioEnabled(), serverSidePlaylist, gain);
|
||||
private List<PlayQueueInfo.Entry> convertInternetRadio(HttpServletRequest request, Player player) throws Exception {
|
||||
|
||||
// Retrieve radio playlist and parse it
|
||||
PlayQueue playQueue = player.getPlayQueue();
|
||||
InternetRadio radio = playQueue.getInternetRadio();
|
||||
URL playlistUrl = new URL(radio.getStreamUrl());
|
||||
SpecificPlaylist inputPlaylist = null;
|
||||
try {
|
||||
LOG.info("Parsing playlist at {}...", playlistUrl.toString());
|
||||
inputPlaylist = SpecificPlaylistFactory.getInstance().readFrom(playlistUrl);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Unable to parse playlist: {}", playlistUrl.toString(), e);
|
||||
throw e;
|
||||
}
|
||||
if (inputPlaylist == null) {
|
||||
LOG.error("Unsupported playlist format: {}", playlistUrl.toString());
|
||||
throw new Exception("Unsupported playlist format " + playlistUrl.toString());
|
||||
}
|
||||
|
||||
// Retrieve stream URLs
|
||||
List<PlayQueueInfo.Entry> entries = new ArrayList<>();
|
||||
final String radioHomepageUrl = radio.getHomepageUrl();
|
||||
final String radioName = radio.getName();
|
||||
inputPlaylist.toPlaylist().acceptDown(new PlaylistVisitor() {
|
||||
@Override
|
||||
public void beginVisitPlaylist(Playlist playlist) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisitPlaylist(Playlist playlist) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginVisitParallel(Parallel parallel) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisitParallel(Parallel parallel) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginVisitSequence(Sequence sequence) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisitSequence(Sequence sequence) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginVisitMedia(Media media) throws Exception {
|
||||
|
||||
// Retrieve stream URL
|
||||
String streamUrl = media.getSource().getURI().toString();
|
||||
// Fake stream title using the URL
|
||||
String streamTitle = streamUrl;
|
||||
String streamAlbum = radioName;
|
||||
String streamGenre = "Internet Radio";
|
||||
// Fake entry id so that the source can be selected
|
||||
Integer streamId = -(1+entries.size());
|
||||
Integer streamTrackNumber = entries.size();
|
||||
Integer streamYear = 0;
|
||||
|
||||
LOG.info("Got source media at {}...", streamUrl);
|
||||
|
||||
entries.add(new PlayQueueInfo.Entry(
|
||||
streamId, // Entry id
|
||||
streamTrackNumber, // Track number
|
||||
streamTitle, // Use URL as stream title
|
||||
"",
|
||||
streamAlbum, // Album name
|
||||
streamGenre,
|
||||
streamYear,
|
||||
"",
|
||||
0,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
false,
|
||||
radioHomepageUrl, // Album URL
|
||||
streamUrl, // Stream URL
|
||||
streamUrl, // Remote stream URL
|
||||
null,
|
||||
null
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVisitMedia(Media media) throws Exception {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
if (entries.isEmpty()) {
|
||||
LOG.error("Cannot fetch stream URLs from radio source {}", playlistUrl.toString());
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private String formatFileSize(Long fileSize, Locale locale) {
|
||||
@@ -797,4 +961,8 @@ public class PlayQueueService {
|
||||
public void setJwtSecurityService(JWTSecurityService jwtSecurityService) {
|
||||
this.jwtSecurityService = jwtSecurityService;
|
||||
}
|
||||
|
||||
public void setInternetRadioDao(InternetRadioDao internetRadioDao) {
|
||||
this.internetRadioDao = internetRadioDao;
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -239,6 +239,7 @@ public class RandomPlayQueueController {
|
||||
|
||||
if (autoRandom != null) {
|
||||
playQueue.setRandomSearchCriteria(criteria);
|
||||
playQueue.setInternetRadio(null);
|
||||
}
|
||||
|
||||
// Render the 'reload' view to reload the play queue and the main page
|
||||
|
||||
@@ -42,6 +42,17 @@ public class InternetRadioDao extends AbstractDao {
|
||||
private static final String QUERY_COLUMNS = "id, " + INSERT_COLUMNS;
|
||||
private final InternetRadioRowMapper rowMapper = new InternetRadioRowMapper();
|
||||
|
||||
/**
|
||||
* Returns the internet radio station with the given ID.
|
||||
*
|
||||
* @param id The unique internet radio station ID.
|
||||
* @return The internet radio station with the given ID, or <code>null</code> if no such internet radio exists.
|
||||
*/
|
||||
public InternetRadio getInternetRadioById(int id) {
|
||||
String sql = "select " + QUERY_COLUMNS + " from internet_radio where id=?";
|
||||
return queryOne(sql, rowMapper, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all internet radio stations.
|
||||
*
|
||||
|
||||
@@ -35,7 +35,9 @@ public class PlayQueue {
|
||||
private boolean repeatEnabled;
|
||||
private String name = "(unnamed)";
|
||||
private Status status = Status.PLAYING;
|
||||
|
||||
private RandomSearchCriteria randomSearchCriteria;
|
||||
private InternetRadio internetRadio;
|
||||
|
||||
/**
|
||||
* The index of the current song, or -1 is the end of the playlist is reached.
|
||||
@@ -363,13 +365,18 @@ public class PlayQueue {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the playlist is a shuffle radio
|
||||
* Returns whether the play queue is in shuffle radio mode.
|
||||
*
|
||||
* @return Whether the playlist is a shuffle radio.
|
||||
* @return Whether the play queue is a shuffle radio mode.
|
||||
*/
|
||||
public synchronized boolean isRadioEnabled() {
|
||||
return this.randomSearchCriteria != null;
|
||||
}
|
||||
public synchronized boolean isShuffleRadioEnabled() { return this.randomSearchCriteria != null; }
|
||||
|
||||
/**
|
||||
* Returns whether the play queue is a internet radio mode.
|
||||
*
|
||||
* @return Whether the play queue is a internet radio mode.
|
||||
*/
|
||||
public synchronized boolean isInternetRadioEnabled() { return this.internetRadio != null; }
|
||||
|
||||
/**
|
||||
* Revert the last operation.
|
||||
@@ -407,22 +414,32 @@ public class PlayQueue {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the criteria used to generate this random playlist.
|
||||
* Sets the current internet radio
|
||||
*
|
||||
* @param internetRadio An internet radio, or <code>null</code> if this is not an internet radio playlist
|
||||
*/
|
||||
public void setInternetRadio(InternetRadio internetRadio) { this.internetRadio = internetRadio; }
|
||||
|
||||
/**
|
||||
* Gets the current internet radio
|
||||
*
|
||||
* @return The current internet radio, or <code>null</code> if this is not an internet radio playlist
|
||||
*/
|
||||
public InternetRadio getInternetRadio() { return internetRadio; }
|
||||
|
||||
/**
|
||||
* Returns the criteria used to generate this random playlist
|
||||
*
|
||||
* @return The search criteria, or <code>null</code> if this is not a random playlist.
|
||||
*/
|
||||
public synchronized RandomSearchCriteria getRandomSearchCriteria() {
|
||||
return randomSearchCriteria;
|
||||
}
|
||||
public synchronized RandomSearchCriteria getRandomSearchCriteria() { return randomSearchCriteria; }
|
||||
|
||||
/**
|
||||
* Sets the criteria used to generate this random playlist.
|
||||
* Sets the criteria used to generate this random playlist
|
||||
*
|
||||
* @param randomSearchCriteria The search criteria, or <code>null</code> if this is not a random playlist.
|
||||
*/
|
||||
public synchronized void setRandomSearchCriteria(RandomSearchCriteria randomSearchCriteria) {
|
||||
this.randomSearchCriteria = randomSearchCriteria;
|
||||
}
|
||||
public synchronized void setRandomSearchCriteria(RandomSearchCriteria randomSearchCriteria) { this.randomSearchCriteria = randomSearchCriteria; }
|
||||
|
||||
/**
|
||||
* Returns the total length in bytes.
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
top.main.location.href = mainLocation;
|
||||
}
|
||||
}
|
||||
|
||||
$('.radio-play').on('click', function() {
|
||||
top.playQueue.onPlayInternetRadio($(this).data("id"), 0);
|
||||
});
|
||||
}
|
||||
|
||||
function updatePlaylists() {
|
||||
@@ -118,9 +122,10 @@
|
||||
|
||||
<c:if test="${not empty model.radios}">
|
||||
<h2 class="bgcolor1" style="padding-left: 2px"><fmt:message key="left.radio"/></h2>
|
||||
<iframe id="radio-playlist-data" style="display:none;"></iframe>
|
||||
<c:forEach items="${model.radios}" var="radio">
|
||||
<p class="dense" style="padding-left: 2px">
|
||||
<a target="hidden" href="${radio.streamUrl}">
|
||||
<a target="hidden" href="${radio.streamUrl}" class="radio-play" data-id="${radio.id}">
|
||||
<img src="<spring:theme code="playImage"/>" alt="<fmt:message key="common.play"/>" title="<fmt:message key="common.play"/>"></a>
|
||||
<span style="vertical-align: middle">
|
||||
<c:choose>
|
||||
@@ -128,7 +133,7 @@
|
||||
${fn:escapeXml(radio.name)}
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<a target="main" href="${radio.homepageUrl}">${fn:escapeXml(radio.name)}</a>
|
||||
<a target="_blank" rel="noopener" href="${radio.homepageUrl}">${fn:escapeXml(radio.name)}</a>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</span>
|
||||
|
||||
@@ -31,13 +31,30 @@
|
||||
<span id="dummy-animation-target" style="max-width: ${model.autoHide ? 50 : 150}px; display: none"></span>
|
||||
|
||||
<script type="text/javascript" language="javascript">
|
||||
|
||||
// These variables store the media player state, received from DWR in the
|
||||
// playQueueCallback function below.
|
||||
|
||||
// List of songs (of type PlayQueueInfo.Entry)
|
||||
var songs = null;
|
||||
|
||||
// Stream URL of the media being played
|
||||
var currentStreamUrl = null;
|
||||
|
||||
// Is autorepeat enabled?
|
||||
var repeatEnabled = false;
|
||||
var radioEnabled = false;
|
||||
|
||||
// Is the "shuffle radio" playing? (More > Shuffle Radio)
|
||||
var shuffleRadioEnabled = false;
|
||||
|
||||
// Is the "internet radio" playing?
|
||||
var internetRadioEnabled = false;
|
||||
|
||||
// Is the play queue visible? (Initially hidden if set to "auto-hide" in the settings)
|
||||
var isVisible = ${model.autoHide ? 'false' : 'true'};
|
||||
|
||||
// Initialize the Cast player (ChromeCast support)
|
||||
var CastPlayer = new CastPlayer();
|
||||
var ignore = false;
|
||||
|
||||
function init() {
|
||||
<c:if test="${model.autoHide}">initAutoHide();</c:if>
|
||||
@@ -267,7 +284,7 @@
|
||||
}
|
||||
function onNext(wrap) {
|
||||
var index = parseInt(getCurrentSongIndex()) + 1;
|
||||
if (radioEnabled && index >= songs.length) {
|
||||
if (shuffleRadioEnabled && index >= songs.length) {
|
||||
playQueueService.reloadSearchCriteria(function(playQueue) {
|
||||
playQueueCallback(playQueue);
|
||||
onSkip(index);
|
||||
@@ -290,6 +307,9 @@
|
||||
function onPlayPlaylist(id, index) {
|
||||
playQueueService.playPlaylist(id, index, playQueueCallback);
|
||||
}
|
||||
function onPlayInternetRadio(id, index) {
|
||||
playQueueService.playInternetRadio(id, index, playQueueCallback);
|
||||
}
|
||||
function onPlayTopSong(id, index) {
|
||||
playQueueService.playTopSong(id, index, playQueueCallback);
|
||||
}
|
||||
@@ -410,14 +430,16 @@
|
||||
function playQueueCallback(playQueue) {
|
||||
songs = playQueue.entries;
|
||||
repeatEnabled = playQueue.repeatEnabled;
|
||||
radioEnabled = playQueue.radioEnabled;
|
||||
shuffleRadioEnabled = playQueue.shuffleRadioEnabled;
|
||||
internetRadioEnabled = playQueue.internetRadioEnabled;
|
||||
|
||||
if ($("#start")) {
|
||||
$("#start").toggle(!playQueue.stopEnabled);
|
||||
$("#stop").toggle(playQueue.stopEnabled);
|
||||
}
|
||||
|
||||
if ($("#toggleRepeat")) {
|
||||
if (radioEnabled) {
|
||||
if (shuffleRadioEnabled) {
|
||||
$("#toggleRepeat").html("<fmt:message key="playlist.repeat_radio"/>");
|
||||
} else if (repeatEnabled) {
|
||||
$("#toggleRepeat").attr('src', '<spring:theme code="repeatOn"/>');
|
||||
@@ -449,11 +471,24 @@
|
||||
if ($("#trackNumber" + id)) {
|
||||
$("#trackNumber" + id).text(song.trackNumber);
|
||||
}
|
||||
|
||||
if (!internetRadioEnabled) {
|
||||
// Show star/remove buttons in all cases...
|
||||
$("#starSong" + id).show();
|
||||
$("#removeSong" + id).show();
|
||||
|
||||
// Show star rating
|
||||
if (song.starred) {
|
||||
$("#starSong" + id).attr("src", "<spring:theme code='ratingOnImage'/>");
|
||||
} else {
|
||||
$("#starSong" + id).attr("src", "<spring:theme code='ratingOffImage'/>");
|
||||
}
|
||||
} else {
|
||||
// ...except from when internet radio is playing.
|
||||
$("#starSong" + id).hide();
|
||||
$("#removeSong" + id).hide();
|
||||
}
|
||||
|
||||
if ($("#currentImage" + id) && song.streamUrl == currentStreamUrl) {
|
||||
$("#currentImage" + id).show();
|
||||
if (isJavaJukeboxPresent()) {
|
||||
@@ -473,6 +508,13 @@
|
||||
$("#album" + id).text(song.album);
|
||||
$("#album" + id).attr("title", song.album);
|
||||
$("#albumUrl" + id).attr("href", song.albumUrl);
|
||||
// Open external internet radio links in new windows
|
||||
if (internetRadioEnabled) {
|
||||
$("#albumUrl" + id).attr({
|
||||
target: "_blank",
|
||||
rel: "noopener noreferrer",
|
||||
});
|
||||
}
|
||||
}
|
||||
if ($("#artist" + id)) {
|
||||
$("#artist" + id).text(song.artist);
|
||||
@@ -482,7 +524,13 @@
|
||||
$("#genre" + id).text(song.genre);
|
||||
}
|
||||
if ($("#year" + id)) {
|
||||
// If song.year is not an int, this will return NaN, which
|
||||
// conveniently returns false in all boolean operations.
|
||||
if (parseInt(song.year) > 0) {
|
||||
$("#year" + id).text(song.year);
|
||||
} else {
|
||||
$("#year" + id).text("");
|
||||
}
|
||||
}
|
||||
if ($("#bitRate" + id)) {
|
||||
$("#bitRate" + id).text(song.bitRate);
|
||||
|
||||
Reference in New Issue
Block a user