File System Renames (No content changes)
Signed-off-by: Andrew DeMaria <lostonamountain@gmail.com>
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN" "http://getahead.org/dwr/dwr30.dtd">
|
||||
|
||||
<dwr>
|
||||
<allow>
|
||||
|
||||
<create creator="spring" javascript="multiService">
|
||||
<param name="beanName" value="ajaxMultiService"/>
|
||||
</create>
|
||||
|
||||
<create creator="spring" javascript="nowPlayingService">
|
||||
<param name="beanName" value="ajaxNowPlayingService"/>
|
||||
</create>
|
||||
|
||||
<create creator="spring" javascript="playQueueService">
|
||||
<param name="beanName" value="ajaxPlayQueueService"/>
|
||||
</create>
|
||||
|
||||
<create creator="spring" javascript="playlistService">
|
||||
<param name="beanName" value="ajaxPlaylistService"/>
|
||||
</create>
|
||||
|
||||
<create creator="spring" javascript="lyricsService">
|
||||
<param name="beanName" value="ajaxLyricsService"/>
|
||||
</create>
|
||||
|
||||
<create creator="spring" javascript="coverArtService">
|
||||
<param name="beanName" value="ajaxCoverArtService"/>
|
||||
</create>
|
||||
|
||||
<create creator="spring" javascript="starService">
|
||||
<param name="beanName" value="ajaxStarService"/>
|
||||
</create>
|
||||
|
||||
<create creator="spring" javascript="tagService">
|
||||
<param name="beanName" value="ajaxTagService"/>
|
||||
</create>
|
||||
|
||||
<create creator="spring" javascript="transferService">
|
||||
<param name="beanName" value="ajaxTransferService"/>
|
||||
</create>
|
||||
|
||||
<convert converter="bean" match="org.libresonic.player.ajax.NowPlayingInfo"/>
|
||||
<convert converter="bean" match="org.libresonic.player.ajax.ScanInfo"/>
|
||||
<convert converter="bean" match="org.libresonic.player.ajax.PlayQueueInfo"/>
|
||||
<convert converter="bean" match="org.libresonic.player.ajax.PlayQueueInfo$Entry"/>
|
||||
<convert converter="bean" match="org.libresonic.player.ajax.PlaylistInfo"/>
|
||||
<convert converter="bean" match="org.libresonic.player.ajax.PlaylistInfo$Entry"/>
|
||||
<convert converter="bean" match="org.libresonic.player.domain.Playlist"/>
|
||||
<convert converter="bean" match="org.libresonic.player.domain.ArtistBio"/>
|
||||
<convert converter="bean" match="org.libresonic.player.domain.LastFmCoverArt"/>
|
||||
|
||||
<convert converter="bean" match="org.libresonic.player.ajax.UploadInfo"/>
|
||||
<convert converter="bean" match="org.libresonic.player.ajax.LyricsInfo"/>
|
||||
<convert converter="bean" match="org.libresonic.player.ajax.CoverArtInfo"/>
|
||||
<convert converter="bean" match="org.libresonic.player.ajax.SimilarArtist"/>
|
||||
<convert converter="bean" match="org.libresonic.player.ajax.ArtistInfo"/>
|
||||
<convert converter="bean" match="org.libresonic.player.ajax.TopSong"/>
|
||||
|
||||
</allow>
|
||||
</dwr>
|
||||
@@ -0,0 +1,22 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<%@ include file="head.jsp" %>
|
||||
</head>
|
||||
|
||||
<body class="mainframe bgcolor1">
|
||||
|
||||
<h1>
|
||||
<img src="<spring:theme code="errorImage"/>" alt=""/>
|
||||
<span style="vertical-align: middle"><fmt:message key="accessDenied.title"/></span>
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
<fmt:message key="accessDenied.text"/>
|
||||
</p>
|
||||
|
||||
<div class="back"><a href="javascript:history.go(-1)"><fmt:message key="common.back"/></a></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,155 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
<%--@elvariable id="command" type="org.libresonic.player.command.AdvancedSettingsCommand"--%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value="/script/scripts-2.0.js"/>"></script>
|
||||
<script type="text/javascript" language="javascript">
|
||||
function enableLdapFields() {
|
||||
$("#ldap").is(":checked") ? $("#ldapTable").show() : $("#ldapTable").hide();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body class="mainframe bgcolor1" onload="enableLdapFields()">
|
||||
<script type="text/javascript" src="<c:url value="/script/wz_tooltip.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/tip_balloon.js"/>"></script>
|
||||
|
||||
<c:import url="settingsHeader.jsp">
|
||||
<c:param name="cat" value="advanced"/>
|
||||
<c:param name="toast" value="${settings_toast}"/>
|
||||
</c:import>
|
||||
|
||||
<form:form method="post" action="advancedSettings.view" commandName="command">
|
||||
|
||||
<table style="white-space:nowrap" class="indent">
|
||||
<tr>
|
||||
<td><fmt:message key="advancedsettings.downloadlimit"/></td>
|
||||
<td>
|
||||
<form:input path="downloadLimit" size="8"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="downloadlimit"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="advancedsettings.uploadlimit"/></td>
|
||||
<td>
|
||||
<form:input path="uploadLimit" size="8"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="uploadlimit"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table class="indent">
|
||||
<tr>
|
||||
<td><fmt:message key="advancedsettings.smtpFrom"/></td>
|
||||
<td>
|
||||
<form:input path="smtpFrom" size="50"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="smtpFrom"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="advancedsettings.smtpServer"/></td>
|
||||
<td>
|
||||
<form:input path="smtpServer" size="50"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="smtpServer"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="advancedsettings.smtpPort"/></td>
|
||||
<td>
|
||||
<form:input path="smtpPort" size="5"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="smtpPort"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="advancedsettings.smtpEncryption"/></td>
|
||||
<td>
|
||||
<form:select path="smtpEncryption" cssStyle="width:8em">
|
||||
<fmt:message key="advancedsettings.smtpEncryption.none" var="none"/>
|
||||
<fmt:message key="advancedsettings.smtpEncryption.starttls" var="starttls"/>
|
||||
<fmt:message key="advancedsettings.smtpEncryption.ssl" var="ssl"/>
|
||||
|
||||
<form:option value="None" label="None"/>
|
||||
<form:option value="STARTTLS" label="STARTTLS"/>
|
||||
<form:option value="SSL/TLS" label="SSL/TLS"/>
|
||||
</form:select>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="smtpEncryption"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="advancedsettings.smtpUser"/></td>
|
||||
<td>
|
||||
<form:input path="smtpUser" size="20"/>
|
||||
<fmt:message key="advancedsettings.smtpPassword"/>
|
||||
<form:password path="smtpPassword" size="20"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="smtpCredentials"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<table class="indent"><tr><td>
|
||||
<form:checkbox path="ldapEnabled" id="ldap" cssClass="checkbox" onclick="enableLdapFields()"/>
|
||||
<label for="ldap"><fmt:message key="advancedsettings.ldapenabled"/></label>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="ldap"/></c:import>
|
||||
</td></tr></table>
|
||||
|
||||
<table class="indent" id="ldapTable" style="padding-left:2em;padding-bottom: 1em">
|
||||
<tr>
|
||||
<td><fmt:message key="advancedsettings.ldapurl"/></td>
|
||||
<td colspan="3">
|
||||
<form:input path="ldapUrl" size="70"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="ldapurl"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="advancedsettings.ldapsearchfilter"/></td>
|
||||
<td colspan="3">
|
||||
<form:input path="ldapSearchFilter" size="70"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="ldapsearchfilter"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="advancedsettings.ldapmanagerdn"/></td>
|
||||
<td>
|
||||
<form:input path="ldapManagerDn" size="20"/>
|
||||
</td>
|
||||
<td><fmt:message key="advancedsettings.ldapmanagerpassword"/></td>
|
||||
<td>
|
||||
<form:password path="ldapManagerPassword" size="20"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="ldapmanagerdn"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<form:checkbox path="ldapAutoShadowing" id="ldapAutoShadowing" cssClass="checkbox"/>
|
||||
<label for="ldapAutoShadowing"><fmt:message key="advancedsettings.ldapautoshadowing"><fmt:param value="${command.brand}"/></fmt:message></label>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="ldapautoshadowing"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p class="warning"><fmt:message key="advancedsettings.ldapRequiresRestart"/></p>
|
||||
|
||||
<input type="submit" value="<fmt:message key="common.save"/>" style="margin-right:0.3em">
|
||||
<input type="button" value="<fmt:message key="common.cancel"/>" onclick="location.href='nowPlaying.view'">
|
||||
|
||||
</form:form>
|
||||
|
||||
<c:if test="${settings_reload}">
|
||||
<script language="javascript" type="text/javascript">
|
||||
parent.frames.left.location.href="left.view?";
|
||||
parent.frames.playQueue.location.href="playQueue.view?";
|
||||
</script>
|
||||
</c:if>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,516 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<%--@elvariable id="model" type="java.util.Map"--%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value="/script/scripts-2.0.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/engine.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/starService.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/playlistService.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/multiService.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/fancyzoom/FancyZoom.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/fancyzoom/FancyZoomHTML.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/util.js"/>"></script>
|
||||
|
||||
</head><body class="mainframe bgcolor1" onload="init();">
|
||||
|
||||
<sub:url value="createShare.view" var="shareUrl">
|
||||
<sub:param name="id" value="${model.dir.id}"/>
|
||||
</sub:url>
|
||||
<sub:url value="download.view" var="downloadUrl">
|
||||
<sub:param name="id" value="${model.dir.id}"/>
|
||||
</sub:url>
|
||||
|
||||
<script type="text/javascript" language="javascript">
|
||||
function init() {
|
||||
setupZoom('<c:url value="/"/>');
|
||||
|
||||
$("#dialog-select-playlist").dialog({resizable: true, height: 350, autoOpen: false,
|
||||
buttons: {
|
||||
"<fmt:message key="common.cancel"/>": function() {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}});
|
||||
|
||||
<c:if test="${model.showArtistInfo}">
|
||||
loadArtistInfo();
|
||||
</c:if>
|
||||
}
|
||||
|
||||
function loadArtistInfo() {
|
||||
multiService.getArtistInfo(${model.dir.id}, 8, 0, function (artistInfo) {
|
||||
if (artistInfo.similarArtists.length > 0) {
|
||||
var html = "";
|
||||
for (var i = 0; i < artistInfo.similarArtists.length; i++) {
|
||||
html += "<a href='main.view?id=" + artistInfo.similarArtists[i].mediaFileId + "' target='main'>" +
|
||||
escapeHtml(artistInfo.similarArtists[i].artistName) + "</a>";
|
||||
if (i < artistInfo.similarArtists.length - 1) {
|
||||
html += " <span class='similar-artist-divider'>|</span> ";
|
||||
}
|
||||
}
|
||||
$("#similarArtists").append(html);
|
||||
$("#similarArtists").show();
|
||||
$("#similarArtistsTitle").show();
|
||||
$("#similarArtistsRadio").show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
<!-- actionSelected() is invoked when the users selects from the "More actions..." combo box. -->
|
||||
function actionSelected(id) {
|
||||
var selectedIndexes = getSelectedIndexes();
|
||||
|
||||
if (id == "top") {
|
||||
return;
|
||||
} else if (id == "selectAll") {
|
||||
selectAll(true);
|
||||
} else if (id == "selectNone") {
|
||||
selectAll(false);
|
||||
} else if (id == "share" && selectedIndexes != "") {
|
||||
location.href = "${shareUrl}&" + selectedIndexes;
|
||||
} else if (id == "download" && selectedIndexes != "") {
|
||||
location.href = "${downloadUrl}&" + selectedIndexes;
|
||||
} else if (id == "appendPlaylist" && selectedIndexes != "") {
|
||||
onAppendPlaylist();
|
||||
}
|
||||
$("#moreActions").prop("selectedIndex", 0);
|
||||
}
|
||||
|
||||
function getSelectedIndexes() {
|
||||
var result = "";
|
||||
for (var i = 0; i < ${fn:length(model.files)}; i++) {
|
||||
var checkbox = $("#songIndex" + i);
|
||||
if (checkbox != null && checkbox.is(":checked")) {
|
||||
result += "i=" + i + "&";
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function selectAll(b) {
|
||||
for (var i = 0; i < ${fn:length(model.files)}; i++) {
|
||||
var checkbox = $("#songIndex" + i);
|
||||
if (checkbox != null) {
|
||||
if (b) {
|
||||
checkbox.attr("checked", "checked");
|
||||
} else {
|
||||
checkbox.removeAttr("checked");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function toggleStar(mediaFileId, imageId) {
|
||||
if ($(imageId).attr("src").indexOf("<spring:theme code="ratingOnImage"/>") != -1) {
|
||||
$(imageId).attr("src", "<spring:theme code="ratingOffImage"/>");
|
||||
starService.unstar(mediaFileId);
|
||||
}
|
||||
else if ($(imageId).attr("src").indexOf("<spring:theme code="ratingOffImage"/>") != -1) {
|
||||
$(imageId).attr("src", "<spring:theme code="ratingOnImage"/>");
|
||||
starService.star(mediaFileId);
|
||||
}
|
||||
}
|
||||
|
||||
function playAll() {
|
||||
top.playQueue.onPlay(${model.dir.id});
|
||||
}
|
||||
|
||||
function playRandom() {
|
||||
top.playQueue.onPlayRandom(${model.dir.id}, 40);
|
||||
}
|
||||
|
||||
function addAll() {
|
||||
top.playQueue.onAdd(${model.dir.id});
|
||||
}
|
||||
|
||||
function playSimilar() {
|
||||
top.playQueue.onPlaySimilar(${model.dir.id}, 50);
|
||||
}
|
||||
|
||||
function onAppendPlaylist() {
|
||||
playlistService.getWritablePlaylists(playlistCallback);
|
||||
}
|
||||
function playlistCallback(playlists) {
|
||||
$("#dialog-select-playlist-list").empty();
|
||||
for (var i = 0; i < playlists.length; i++) {
|
||||
var playlist = playlists[i];
|
||||
$("<p class='dense'><b><a href='#' onclick='appendPlaylist(" + playlist.id + ")'>" + escapeHtml(playlist.name)
|
||||
+ "</a></b></p>").appendTo("#dialog-select-playlist-list");
|
||||
}
|
||||
$("#dialog-select-playlist").dialog("open");
|
||||
}
|
||||
function appendPlaylist(playlistId) {
|
||||
$("#dialog-select-playlist").dialog("close");
|
||||
|
||||
var mediaFileIds = new Array();
|
||||
for (var i = 0; i < ${fn:length(model.files)}; i++) {
|
||||
var checkbox = $("#songIndex" + i);
|
||||
if (checkbox && checkbox.is(":checked")) {
|
||||
mediaFileIds.push($("#songId" + i).html());
|
||||
}
|
||||
}
|
||||
playlistService.appendToPlaylist(playlistId, mediaFileIds, function (){
|
||||
top.left.updatePlaylists();
|
||||
$().toastmessage("showSuccessToast", "<fmt:message key="playlist.toast.appendtoplaylist"/>");
|
||||
});
|
||||
}
|
||||
function showAllAlbums() {
|
||||
window.location.href = updateQueryStringParameter(window.location.href, "showAll", "1");
|
||||
}
|
||||
</script>
|
||||
|
||||
<div style="float:left">
|
||||
<h1>
|
||||
<img id="starImage" src="<spring:theme code="${not empty model.dir.starredDate ? 'ratingOnImage' : 'ratingOffImage'}"/>"
|
||||
onclick="toggleStar(${model.dir.id}, '#starImage'); return false;" style="cursor:pointer" alt="">
|
||||
|
||||
<span style="vertical-align: middle">
|
||||
<c:forEach items="${model.ancestors}" var="ancestor">
|
||||
<sub:url value="main.view" var="ancestorUrl">
|
||||
<sub:param name="id" value="${ancestor.id}"/>
|
||||
</sub:url>
|
||||
<a href="${ancestorUrl}">${fn:escapeXml(ancestor.name)}</a> »
|
||||
</c:forEach>
|
||||
${fn:escapeXml(model.dir.name)}
|
||||
</span>
|
||||
|
||||
<c:if test="${model.averageRating gt 0}">
|
||||
|
||||
<c:import url="rating.jsp">
|
||||
<c:param name="readonly" value="true"/>
|
||||
<c:param name="rating" value="${model.averageRating}"/>
|
||||
</c:import>
|
||||
</c:if>
|
||||
</h1>
|
||||
|
||||
<c:if test="${not model.partyMode}">
|
||||
<h2>
|
||||
<c:if test="${model.navigateUpAllowed}">
|
||||
<sub:url value="main.view" var="upUrl">
|
||||
<sub:param name="id" value="${model.parent.id}"/>
|
||||
</sub:url>
|
||||
<span class="header"><a href="${upUrl}"><fmt:message key="main.up"/></a></span>
|
||||
<c:set var="needSep" value="true"/>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.user.streamRole}">
|
||||
<c:if test="${needSep}">|</c:if>
|
||||
<span class="header"><a href="javascript:playAll()"><fmt:message key="main.playall"/></a></span> |
|
||||
<span class="header"><a href="javascript:playRandom()"><fmt:message key="main.playrandom"/></a></span> |
|
||||
<span class="header"><a href="javascript:addAll()"><fmt:message key="main.addall"/></a></span>
|
||||
<c:set var="needSep" value="true"/>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.user.downloadRole}">
|
||||
<c:if test="${needSep}">|</c:if>
|
||||
<span class="header"><a href="${downloadUrl}"><fmt:message key="main.downloadall"/></a></span>
|
||||
<c:set var="needSep" value="true"/>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.user.coverArtRole}">
|
||||
<sub:url value="editTags.view" var="editTagsUrl">
|
||||
<sub:param name="id" value="${model.dir.id}"/>
|
||||
</sub:url>
|
||||
<c:if test="${needSep}">|</c:if>
|
||||
<span class="header"><a href="${editTagsUrl}"><fmt:message key="main.tags"/></a></span>
|
||||
<c:set var="needSep" value="true"/>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.user.commentRole}">
|
||||
<c:if test="${needSep}">|</c:if>
|
||||
<span class="header"><a href="javascript:toggleComment()"><fmt:message key="main.comment"/></a></span>
|
||||
</c:if>
|
||||
</h2>
|
||||
</c:if>
|
||||
</div>
|
||||
|
||||
<%@ include file="viewSelector.jsp" %>
|
||||
<div style="clear:both"></div>
|
||||
|
||||
<div class="detail">
|
||||
<c:if test="${model.user.commentRole}">
|
||||
<c:import url="rating.jsp">
|
||||
<c:param name="id" value="${model.dir.id}"/>
|
||||
<c:param name="readonly" value="false"/>
|
||||
<c:param name="rating" value="${model.userRating}"/>
|
||||
</c:import>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.user.shareRole}">
|
||||
<span class="header"><a href="${shareUrl}"><img src="<spring:theme code="shareSmallImage"/>" alt=""></a>
|
||||
<a href="${shareUrl}"><fmt:message key="main.sharealbum"/></a> </span> |
|
||||
</c:if>
|
||||
|
||||
<c:if test="${not empty model.artist and not empty model.album}">
|
||||
<sub:url value="http://www.google.com/search" var="googleUrl" encoding="UTF-8">
|
||||
<sub:param name="q" value="\"${model.artist}\" \"${model.album}\""/>
|
||||
</sub:url>
|
||||
<sub:url value="http://en.wikipedia.org/wiki/Special:Search" var="wikipediaUrl" encoding="UTF-8">
|
||||
<sub:param name="search" value="\"${model.album}\""/>
|
||||
<sub:param name="go" value="Go"/>
|
||||
</sub:url>
|
||||
<sub:url value="allmusic.view" var="allmusicUrl">
|
||||
<sub:param name="album" value="${model.album}"/>
|
||||
</sub:url>
|
||||
<sub:url value="http://www.last.fm/search" var="lastFmUrl" encoding="UTF-8">
|
||||
<sub:param name="q" value="\"${model.artist}\" \"${model.album}\""/>
|
||||
<sub:param name="type" value="album"/>
|
||||
</sub:url>
|
||||
<span class="header"><fmt:message key="top.search"/> <a target="_blank" href="${googleUrl}">Google</a></span> |
|
||||
<span class="header"><a target="_blank" href="${wikipediaUrl}">Wikipedia</a></span> |
|
||||
<span class="header"><a target="_blank" href="${allmusicUrl}">allmusic</a></span> |
|
||||
<span class="header"><a target="_blank" href="${lastFmUrl}">Last.fm</a></span> |
|
||||
<span class="header">
|
||||
<fmt:message key="main.playcount"><fmt:param value="${model.dir.playCount}"/></fmt:message>
|
||||
<c:if test="${not empty model.dir.lastPlayed}">
|
||||
<fmt:message key="main.lastplayed">
|
||||
<fmt:param><fmt:formatDate type="date" dateStyle="long" value="${model.dir.lastPlayed}"/></fmt:param>
|
||||
</fmt:message>
|
||||
</c:if>
|
||||
</span>
|
||||
|
||||
</c:if>
|
||||
</div>
|
||||
|
||||
<div id="comment" class="albumComment"><sub:wiki text="${model.dir.comment}"/></div>
|
||||
|
||||
<div id="commentForm" style="display:none">
|
||||
<form method="post" action="setMusicFileInfo.view">
|
||||
<sec:csrfInput />
|
||||
<input type="hidden" name="action" value="comment">
|
||||
<input type="hidden" name="id" value="${model.dir.id}">
|
||||
<textarea name="comment" rows="6" cols="70">${model.dir.comment}</textarea>
|
||||
<input type="submit" value="<fmt:message key="common.save"/>">
|
||||
</form>
|
||||
<fmt:message key="main.wiki"/>
|
||||
</div>
|
||||
|
||||
<script type='text/javascript'>
|
||||
function toggleComment() {
|
||||
$("#commentForm").toggle();
|
||||
$("#comment").toggle();
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<table cellpadding="0" style="width:100%;padding-top: 0.3em;padding-bottom: 1em">
|
||||
<tr style="vertical-align:top;">
|
||||
<td style="vertical-align:top;padding-bottom: 1em">
|
||||
<table class="music" style="width: 100%">
|
||||
<c:forEach items="${model.files}" var="song" varStatus="loopStatus">
|
||||
<%--@elvariable id="song" type="org.libresonic.player.domain.MediaFile"--%>
|
||||
<tr style="margin:0;padding:0;border:0">
|
||||
<c:import url="playButtons.jsp">
|
||||
<c:param name="id" value="${song.id}"/>
|
||||
<c:param name="video" value="${song.video and model.player.web}"/>
|
||||
<c:param name="playEnabled" value="${model.user.streamRole and not model.partyMode}"/>
|
||||
<c:param name="addEnabled" value="${model.user.streamRole and (not model.partyMode or not song.directory)}"/>
|
||||
<c:param name="starEnabled" value="true"/>
|
||||
<c:param name="starred" value="${not empty song.starredDate}"/>
|
||||
<c:param name="asTable" value="true"/>
|
||||
</c:import>
|
||||
|
||||
<td class="fit"><input type="checkbox" class="checkbox" id="songIndex${loopStatus.count - 1}">
|
||||
<span id="songId${loopStatus.count - 1}" style="display: none">${song.id}</span></td>
|
||||
|
||||
<c:if test="${model.visibility.trackNumberVisible}">
|
||||
<td class="fit rightalign">
|
||||
<span class="detail">${song.trackNumber}</span>
|
||||
</td>
|
||||
</c:if>
|
||||
|
||||
<td class="truncate">
|
||||
<span class="songTitle" title="${fn:escapeXml(song.title)}">${fn:escapeXml(song.title)}</span>
|
||||
</td>
|
||||
|
||||
<c:if test="${model.visibility.albumVisible}">
|
||||
<td class="truncate">
|
||||
<span class="detail" title="${fn:escapeXml(song.albumName)}">${fn:escapeXml(song.albumName)}</span>
|
||||
</td>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.visibility.artistVisible}">
|
||||
<td class="truncate">
|
||||
<span class="detail" title="${fn:escapeXml(song.artist)}">${fn:escapeXml(song.artist)}</span>
|
||||
</td>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.visibility.genreVisible}">
|
||||
<td class="fit rightalign">
|
||||
<span class="detail">${fn:escapeXml(song.genre)}</span>
|
||||
</td>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.visibility.yearVisible}">
|
||||
<td class="fit rightalign">
|
||||
<span class="detail">${song.year}</span>
|
||||
</td>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.visibility.formatVisible}">
|
||||
<td class="fit rightalign">
|
||||
<span class="detail">${fn:toLowerCase(song.format)}</span>
|
||||
</td>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.visibility.fileSizeVisible}">
|
||||
<td class="fit rightalign">
|
||||
<span class="detail"><sub:formatBytes bytes="${song.fileSize}"/></span>
|
||||
</td>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.visibility.durationVisible}">
|
||||
<td class="fit rightalign">
|
||||
<span class="detail">${song.durationString}</span>
|
||||
</td>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.visibility.bitRateVisible}">
|
||||
<td class="fit rightalign">
|
||||
<span class="detail">
|
||||
<c:if test="${not empty song.bitRate}">
|
||||
${song.bitRate} Kbps ${song.variableBitRate ? "vbr" : ""}
|
||||
</c:if>
|
||||
<c:if test="${song.video and not empty song.width and not empty song.height}">
|
||||
(${song.width}x${song.height})
|
||||
</c:if>
|
||||
</span>
|
||||
</td>
|
||||
</c:if>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</table>
|
||||
</td>
|
||||
|
||||
<td class="fit" style="vertical-align:top;" rowspan="3">
|
||||
<div class="albumThumb">
|
||||
<c:import url="coverArt.jsp">
|
||||
<c:param name="albumId" value="${model.dir.id}"/>
|
||||
<c:param name="coverArtSize" value="${model.coverArtSizeLarge}"/>
|
||||
<c:param name="showZoom" value="true"/>
|
||||
<c:param name="showChange" value="${model.user.coverArtRole}"/>
|
||||
</c:import>
|
||||
</div>
|
||||
</td>
|
||||
<c:if test="${model.showAd}">
|
||||
<td style="vertical-align:top;width:160px" rowspan="3">
|
||||
<h2 style="padding-bottom: 1em">Subsonic Premium</h2>
|
||||
<p style="font-size: 90%">
|
||||
Upgrade to Subsonic Premium and get:
|
||||
</p>
|
||||
<div style="font-size: 90%;padding-bottom: 1em">
|
||||
<p><a href="http://libresonic.org/pages/apps.jsp" target="_blank">Apps</a> for Android, iPhone, Windows Phone ++.</p>
|
||||
<p>Video streaming.</p>
|
||||
<p>Chromecast and Sonos support.</p>
|
||||
<p>DLNA/UPnP support</p>
|
||||
<p>Share on Facebook, Twitter, Google+</p>
|
||||
<p>No ads.</p>
|
||||
<p>Your personal server address: <em>you</em>.libresonic.org</p>
|
||||
<p>Podcast receiver.</p>
|
||||
</div>
|
||||
</td>
|
||||
</c:if>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<select id="moreActions" onchange="actionSelected(this.options[selectedIndex].id);" style="margin-bottom:1.0em">
|
||||
<option id="top" selected="selected"><fmt:message key="main.more.selection"/></option>
|
||||
<option id="selectAll"> <fmt:message key="playlist.more.selectall"/></option>
|
||||
<option id="selectNone"> <fmt:message key="playlist.more.selectnone"/></option>
|
||||
<c:if test="${model.user.downloadRole}">
|
||||
<option id="download"> <fmt:message key="common.download"/></option>
|
||||
</c:if>
|
||||
<c:if test="${model.user.shareRole}">
|
||||
<option id="share"> <fmt:message key="main.more.share"/></option>
|
||||
</c:if>
|
||||
<option id="appendPlaylist"> <fmt:message key="playlist.append"/></option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td style="vertical-align:top;height: 100%">
|
||||
<table class="music indent">
|
||||
<c:forEach items="${model.subDirs}" var="child" varStatus="loopStatus">
|
||||
<sub:url value="main.view" var="albumUrl">
|
||||
<sub:param name="id" value="${child.id}"/>
|
||||
</sub:url>
|
||||
<tr>
|
||||
<c:import url="playButtons.jsp">
|
||||
<c:param name="id" value="${child.id}"/>
|
||||
<c:param name="playEnabled" value="${model.user.streamRole and not model.partyModeEnabled}"/>
|
||||
<c:param name="addEnabled" value="${model.user.streamRole and not model.partyModeEnabled}"/>
|
||||
<c:param name="asTable" value="true"/>
|
||||
</c:import>
|
||||
<td class="truncate"><a href="${albumUrl}" title="${fn:escapeXml(child.name)}">${fn:escapeXml(child.name)}</a></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
<c:if test="${model.viewAsList}">
|
||||
<c:forEach items="${model.sieblingAlbums}" var="album" varStatus="loopStatus">
|
||||
<tr>
|
||||
<c:import url="playButtons.jsp">
|
||||
<c:param name="id" value="${album.id}"/>
|
||||
<c:param name="playEnabled" value="${model.user.streamRole and not model.partyModeEnabled}"/>
|
||||
<c:param name="addEnabled" value="${model.user.streamRole and not model.partyModeEnabled}"/>
|
||||
<c:param name="asTable" value="true"/>
|
||||
</c:import>
|
||||
<td class="truncate"><a href="main.view?id=${album.id}" title="${fn:escapeXml(album.name)}">${fn:escapeXml(album.name)}</a></td>
|
||||
<td class="fit rightalign detail">${album.year}</td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</c:if>
|
||||
</table>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
<c:if test="${model.thereIsMore}">
|
||||
<input id="showAllButton" class="albumOverflowButton" type="button" value="<fmt:message key="main.showall"/>" onclick="showAllAlbums()">
|
||||
</c:if>
|
||||
|
||||
<c:if test="${not model.viewAsList}">
|
||||
<div style="float: left">
|
||||
<c:forEach items="${model.sieblingAlbums}" var="album" varStatus="loopStatus">
|
||||
<div class="albumThumb">
|
||||
<c:import url="coverArt.jsp">
|
||||
<c:param name="albumId" value="${album.id}"/>
|
||||
<c:param name="caption1" value="${fn:escapeXml(album.name)}"/>
|
||||
<c:param name="caption2" value="${album.year}"/>
|
||||
<c:param name="captionCount" value="2"/>
|
||||
<c:param name="coverArtSize" value="${model.coverArtSizeMedium}"/>
|
||||
<c:param name="showLink" value="true"/>
|
||||
<c:param name="appearAfter" value="${loopStatus.count * 30}"/>
|
||||
<c:param name="hideOverflow" value="true"/>
|
||||
</c:import>
|
||||
</div>
|
||||
</c:forEach>
|
||||
<c:if test="${model.thereIsMore}">
|
||||
<input id="showAllButton" class="albumOverflowButton" type="button" value="<fmt:message key="main.showall"/>" onclick="showAllAlbums()">
|
||||
</c:if>
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<table style="width: 90%">
|
||||
<tr><td>
|
||||
<span id="similarArtistsTitle" style="padding-right: 0.5em; display: none"><fmt:message key="main.similarartists"/>:</span>
|
||||
<span id="similarArtists"></span>
|
||||
</td></tr>
|
||||
<tr><td style="padding-bottom: 0.5em">
|
||||
<div id="similarArtistsRadio" class="forward" style="display: none">
|
||||
<a href="javascript:playSimilar()"><fmt:message key="main.startradio"/></a>
|
||||
</div>
|
||||
</td></tr>
|
||||
<tr><td style="height: 100%"></td></tr>
|
||||
</table>
|
||||
|
||||
<div id="dialog-select-playlist" title="<fmt:message key="main.addtoplaylist.title"/>" style="display: none;">
|
||||
<p><fmt:message key="main.addtoplaylist.text"/></p>
|
||||
<div id="dialog-select-playlist-list"></div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,16 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
</head>
|
||||
|
||||
<body onload="document.allmusic.submit();" class="mainframe bgcolor1">
|
||||
<h2><fmt:message key="allmusic.text"><fmt:param value="${album}"/></fmt:message></h2>
|
||||
|
||||
<form name="allmusic" action="http://www.allmusic.com/search" method="POST" accept-charset="iso-8859-1">
|
||||
<input type="hidden" name="search_term" value="${album}"/>
|
||||
<input type="hidden" name="search_type" value="album"/>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,339 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<%--
|
||||
~ This file is part of Libresonic.
|
||||
~
|
||||
~ Libresonic 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
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ Libresonic 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 Libresonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
~
|
||||
~ Copyright 2014 (C) Sindre Mehus
|
||||
--%>
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<%--@elvariable id="model" type="java.util.Map"--%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value="/script/scripts-2.0.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value='/dwr/util.js'/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/engine.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/starService.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/multiService.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/fancyzoom/FancyZoom.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/fancyzoom/FancyZoomHTML.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/util.js"/>"></script>
|
||||
|
||||
</head><body class="mainframe bgcolor1" onload="init();">
|
||||
|
||||
<script type="text/javascript" language="javascript">
|
||||
|
||||
var topSongs;
|
||||
|
||||
function init() {
|
||||
setupZoom('<c:url value="/"/>');
|
||||
|
||||
<c:if test="${model.showArtistInfo}">
|
||||
loadArtistInfo();
|
||||
</c:if>
|
||||
}
|
||||
|
||||
function loadArtistInfo() {
|
||||
multiService.getArtistInfo(${model.dir.id}, 8, 50, function (artistInfo) {
|
||||
if (artistInfo.similarArtists.length > 0) {
|
||||
|
||||
var html = "";
|
||||
for (var i = 0; i < artistInfo.similarArtists.length; i++) {
|
||||
html += "<a href='main.view?id=" + artistInfo.similarArtists[i].mediaFileId + "' target='main'>" +
|
||||
escapeHtml(artistInfo.similarArtists[i].artistName) + "</a>";
|
||||
if (i < artistInfo.similarArtists.length - 1) {
|
||||
html += " <span class='similar-artist-divider'>|</span> ";
|
||||
}
|
||||
}
|
||||
$("#similarArtists").append(html);
|
||||
$("#similarArtists").show();
|
||||
$("#similarArtistsTitle").show();
|
||||
$("#similarArtistsRadio").show();
|
||||
$("#artistInfoTable").show();
|
||||
}
|
||||
|
||||
if (artistInfo.artistBio && artistInfo.artistBio.biography) {
|
||||
$("#artistBio").append(artistInfo.artistBio.biography);
|
||||
if (artistInfo.artistBio.largeImageUrl) {
|
||||
$("#artistImage").attr("src", artistInfo.artistBio.largeImageUrl);
|
||||
$("#artistImageZoom").attr("href", artistInfo.artistBio.largeImageUrl);
|
||||
$("#artistImage").show();
|
||||
$("#artistInfoTable").show();
|
||||
}
|
||||
}
|
||||
|
||||
this.topSongs = artistInfo.topSongs;
|
||||
|
||||
if (topSongs.length > 0) {
|
||||
$("#topSongsHeader").show();
|
||||
$("#playTopSongs").show();
|
||||
|
||||
// Delete all the rows except for the "pattern" row
|
||||
dwr.util.removeAllRows("topSongsBody", { filter:function(tr) {
|
||||
return (tr.id != "pattern");
|
||||
}});
|
||||
|
||||
// Create a new set cloned from the pattern row
|
||||
for (var i = 0; i < topSongs.length; i++) {
|
||||
var song = topSongs[i];
|
||||
var id = i + 1;
|
||||
dwr.util.cloneNode("pattern", { idSuffix:id });
|
||||
if (song.starred) {
|
||||
$("#starSong" + id).attr("src", "<spring:theme code='ratingOnImage'/>");
|
||||
} else {
|
||||
$("#starSong" + id).attr("src", "<spring:theme code='ratingOffImage'/>");
|
||||
}
|
||||
$("#rank" + id).html(i + 1);
|
||||
$("#title" + id).html(song.title);
|
||||
$("#title" + id).attr("title", song.title);
|
||||
$("#album" + id).html(song.album);
|
||||
$("#album" + id).attr("title", song.album);
|
||||
$("#albumUrl" + id).attr("href", "main.view?id=" + song.id);
|
||||
$("#artist" + id).html(song.artist);
|
||||
$("#artist" + id).attr("title", song.artist);
|
||||
$("#songDuration" + id).html(song.durationAsString);
|
||||
|
||||
// Note: show() method causes page to scroll to top.
|
||||
$("#pattern" + id).css("display", "table-row");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function toggleStarTopSong(index, imageId) {
|
||||
toggleStar(topSongs[index].id, imageId);
|
||||
}
|
||||
|
||||
function toggleStar(mediaFileId, imageId) {
|
||||
if ($(imageId).attr("src").indexOf("<spring:theme code="ratingOnImage"/>") != -1) {
|
||||
$(imageId).attr("src", "<spring:theme code="ratingOffImage"/>");
|
||||
starService.unstar(mediaFileId);
|
||||
}
|
||||
else if ($(imageId).attr("src").indexOf("<spring:theme code="ratingOffImage"/>") != -1) {
|
||||
$(imageId).attr("src", "<spring:theme code="ratingOnImage"/>");
|
||||
starService.star(mediaFileId);
|
||||
}
|
||||
}
|
||||
function playAll() {
|
||||
top.playQueue.onPlay(${model.dir.id});
|
||||
}
|
||||
function playRandom() {
|
||||
top.playQueue.onPlayRandom(${model.dir.id}, 40);
|
||||
}
|
||||
function addAll() {
|
||||
top.playQueue.onAdd(${model.dir.id});
|
||||
}
|
||||
function playSimilar() {
|
||||
top.playQueue.onPlaySimilar(${model.dir.id}, 50);
|
||||
}
|
||||
function playAllTopSongs() {
|
||||
top.playQueue.onPlayTopSong(${model.dir.id});
|
||||
}
|
||||
function playTopSong(index) {
|
||||
top.playQueue.onPlayTopSong(${model.dir.id}, index);
|
||||
}
|
||||
function addTopSong(index) {
|
||||
top.playQueue.onAdd(topSongs[index].id);
|
||||
$().toastmessage('showSuccessToast', '<fmt:message key="main.addlast.toast"/>')
|
||||
}
|
||||
function addNextTopSong(index) {
|
||||
top.playQueue.onAddNext(topSongs[index].id);
|
||||
$().toastmessage('showSuccessToast', '<fmt:message key="main.addnext.toast"/>')
|
||||
}
|
||||
function showAllAlbums() {
|
||||
window.location.href = updateQueryStringParameter(window.location.href, "showAll", "1");
|
||||
}
|
||||
</script>
|
||||
|
||||
<div style="float:left">
|
||||
<h1>
|
||||
<img id="starImage" src="<spring:theme code="${not empty model.dir.starredDate ? 'ratingOnImage' : 'ratingOffImage'}"/>"
|
||||
onclick="toggleStar(${model.dir.id}, '#starImage'); return false;" style="cursor:pointer" alt="">
|
||||
|
||||
<span style="vertical-align: middle">
|
||||
<c:forEach items="${model.ancestors}" var="ancestor">
|
||||
<sub:url value="main.view" var="ancestorUrl">
|
||||
<sub:param name="id" value="${ancestor.id}"/>
|
||||
</sub:url>
|
||||
<a href="${ancestorUrl}">${fn:escapeXml(ancestor.name)}</a> »
|
||||
</c:forEach>
|
||||
${fn:escapeXml(model.dir.name)}
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<c:if test="${not model.partyMode}">
|
||||
<h2>
|
||||
<c:if test="${model.navigateUpAllowed}">
|
||||
<sub:url value="main.view" var="upUrl">
|
||||
<sub:param name="id" value="${model.parent.id}"/>
|
||||
</sub:url>
|
||||
<span class="header"><a href="${upUrl}"><fmt:message key="main.up"/></a></span>
|
||||
<c:set var="needSep" value="true"/>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.user.streamRole}">
|
||||
<c:if test="${needSep}">|</c:if>
|
||||
<span class="header"><a href="javascript:playAll()"><fmt:message key="main.playall"/></a></span> |
|
||||
<span class="header"><a href="javascript:playRandom(0)"><fmt:message key="main.playrandom"/></a></span> |
|
||||
<span class="header"><a href="javascript:addAll(0)"><fmt:message key="main.addall"/></a></span>
|
||||
<c:set var="needSep" value="true"/>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.user.commentRole}">
|
||||
<c:if test="${needSep}">|</c:if>
|
||||
<span class="header"><a href="javascript:toggleComment()"><fmt:message key="main.comment"/></a></span>
|
||||
</c:if>
|
||||
</h2>
|
||||
</c:if>
|
||||
</div>
|
||||
|
||||
<%@ include file="viewSelector.jsp" %>
|
||||
<div style="clear:both"></div>
|
||||
|
||||
<div id="comment" class="albumComment"><sub:wiki text="${model.dir.comment}"/></div>
|
||||
|
||||
<div id="commentForm" style="display:none">
|
||||
<form method="post" action="setMusicFileInfo.view">
|
||||
<sec:csrfInput />
|
||||
<input type="hidden" name="action" value="comment">
|
||||
<input type="hidden" name="id" value="${model.dir.id}">
|
||||
<textarea name="comment" rows="6" cols="70">${model.dir.comment}</textarea>
|
||||
<input type="submit" value="<fmt:message key="common.save"/>">
|
||||
</form>
|
||||
<fmt:message key="main.wiki"/>
|
||||
</div>
|
||||
|
||||
<script type='text/javascript'>
|
||||
function toggleComment() {
|
||||
$("#commentForm").toggle();
|
||||
$("#comment").toggle();
|
||||
}
|
||||
</script>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${model.viewAsList}">
|
||||
<table class="music indent">
|
||||
<c:forEach items="${model.subDirs}" var="subDir">
|
||||
<tr>
|
||||
<c:import url="playButtons.jsp">
|
||||
<c:param name="id" value="${subDir.id}"/>
|
||||
<c:param name="playEnabled" value="${model.user.streamRole and not model.partyModeEnabled}"/>
|
||||
<c:param name="addEnabled" value="${model.user.streamRole and not model.partyModeEnabled}"/>
|
||||
<c:param name="asTable" value="true"/>
|
||||
</c:import>
|
||||
<td class="truncate"><a href="main.view?id=${subDir.id}" title="${fn:escapeXml(subDir.name)}">${fn:escapeXml(subDir.name)}</a></td>
|
||||
<td class="fit rightalign detail">${subDir.year}</td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</table>
|
||||
</c:when>
|
||||
|
||||
<c:otherwise>
|
||||
<table class="music indent">
|
||||
<c:forEach items="${model.subDirs}" var="subDir">
|
||||
<c:if test="${not subDir.album}">
|
||||
<tr>
|
||||
<c:import url="playButtons.jsp">
|
||||
<c:param name="id" value="${subDir.id}"/>
|
||||
<c:param name="playEnabled" value="${model.user.streamRole and not model.partyModeEnabled}"/>
|
||||
<c:param name="addEnabled" value="${model.user.streamRole and not model.partyModeEnabled}"/>
|
||||
<c:param name="asTable" value="true"/>
|
||||
</c:import>
|
||||
<td class="truncate"><a href="main.view?id=${subDir.id}" title="${fn:escapeXml(subDir.name)}">${fn:escapeXml(subDir.name)}</a></td>
|
||||
<td class="fit rightalign detail">${subDir.year}</td>
|
||||
</tr>
|
||||
</c:if>
|
||||
</c:forEach>
|
||||
</table>
|
||||
|
||||
<div style="float: left;padding-top: 1.5em">
|
||||
<c:set var="albumCount" value="0"/>
|
||||
<c:forEach items="${model.subDirs}" var="subDir" varStatus="loopStatus">
|
||||
<c:if test="${subDir.album}">
|
||||
<c:set var="albumCount" value="${albumCount + 1}"/>
|
||||
<div class="albumThumb">
|
||||
<c:import url="coverArt.jsp">
|
||||
<c:param name="albumId" value="${subDir.id}"/>
|
||||
<c:param name="caption1" value="${fn:escapeXml(subDir.name)}"/>
|
||||
<c:param name="caption2" value="${subDir.year}"/>
|
||||
<c:param name="captionCount" value="2"/>
|
||||
<c:param name="coverArtSize" value="${model.coverArtSizeMedium}"/>
|
||||
<c:param name="showLink" value="true"/>
|
||||
<c:param name="appearAfter" value="${loopStatus.count * 30}"/>
|
||||
<c:param name="hideOverflow" value="true"/>
|
||||
</c:import>
|
||||
</div>
|
||||
</c:if>
|
||||
</c:forEach>
|
||||
<c:if test="${model.thereIsMore}">
|
||||
<input id="showAllButton" class="albumOverflowButton" type="button" value="<fmt:message key="main.showall"/>" onclick="showAllAlbums()">
|
||||
</c:if>
|
||||
</div>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<table id="artistInfoTable" style="padding:2em;clear:both;display:none" class="bgcolor2 dropshadow">
|
||||
<tr>
|
||||
<td rowspan="5" style="vertical-align: top">
|
||||
<a id="artistImageZoom" rel="zoom" href="void">
|
||||
<img id="artistImage" class="dropshadow" alt="" style="margin-right:2em; display:none; max-width:300px; max-height:300px">
|
||||
</a>
|
||||
</td>
|
||||
<td style="text-align:center"><h2>${fn:escapeXml(model.dir.name)}</h2></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="artistBio" style="padding-bottom: 0.5em"></td>
|
||||
</tr>
|
||||
<tr><td style="padding-bottom: 0.5em">
|
||||
<span id="similarArtistsTitle" style="padding-right: 0.5em; display: none"><fmt:message key="main.similarartists"/>:</span>
|
||||
<span id="similarArtists"></span>
|
||||
</td></tr>
|
||||
<tr><td style="text-align:center">
|
||||
<input id="similarArtistsRadio" style="display:none;margin-top:1em;margin-right:0.3em;cursor:pointer" type="button" value="<fmt:message key="main.startradio"/>" onclick="playSimilar()">
|
||||
<input id="playTopSongs" style="display:none;margin-top:1em;margin-left:0.3em;cursor:pointer" type="button" value="<fmt:message key="main.playtopsongs"/>" onclick="playAllTopSongs()">
|
||||
</td></tr>
|
||||
<tr><td style="height: 100%"></td></tr>
|
||||
</table>
|
||||
|
||||
<h2 id="topSongsHeader" style="display:none; padding-top:1em"><fmt:message key="main.topsongs"/></h2>
|
||||
|
||||
<table class="music indent">
|
||||
<tbody id="topSongsBody">
|
||||
<tr id="pattern" style="display:none;margin:0;padding:0;border:0">
|
||||
<td class="fit">
|
||||
<img id="starSong" onclick="toggleStarTopSong(this.id.substring(8) - 1, '#starSong' + this.id.substring(8))" src="<spring:theme code="ratingOffImage"/>"
|
||||
style="cursor:pointer" alt="" title=""></td>
|
||||
<td class="fit">
|
||||
<img id="play" src="<spring:theme code="playImage"/>" alt="<fmt:message key="common.play"/>" title="<fmt:message key="common.play"/>"
|
||||
style="padding-right:0.1em;cursor:pointer" onclick="playTopSong(this.id.substring(4) - 1)"></td>
|
||||
<td class="fit">
|
||||
<img id="add" src="<spring:theme code="addImage"/>" alt="<fmt:message key="common.add"/>" title="<fmt:message key="common.add"/>"
|
||||
style="padding-right:0.1em;cursor:pointer" onclick="addTopSong(this.id.substring(3) - 1)"></td>
|
||||
<td class="fit" style="padding-right:30px">
|
||||
<img id="addNext" src="<spring:theme code="addNextImage"/>" alt="<fmt:message key="main.addnext"/>" title="<fmt:message key="main.addnext"/>"
|
||||
style="padding-right:0.1em;cursor:pointer" onclick="addNextTopSong(this.id.substring(7) - 1)"></td>
|
||||
<td class="fit rightalign"><span id="rank" class="detail">Rank</span></td>
|
||||
<td class="truncate"><span id="title" class="songTitle">Title</span></td>
|
||||
<td class="truncate"><a id="albumUrl" target="main"><span id="album" class="detail">Album</span></a></td>
|
||||
<td class="truncate"><span id="artist" class="detail">Artist</span></td>
|
||||
<td class="fit rightalign"><span id="songDuration" class="detail">Duration</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,36 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<%@ include file="head.jsp" %>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1">
|
||||
|
||||
<h1>
|
||||
<img src="<spring:theme code="settingsImage"/>" alt=""/>
|
||||
<span style="vertical-align: middle"><fmt:message key="avataruploadresult.title"/></span>
|
||||
</h1>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${empty model.error}">
|
||||
<p>
|
||||
<fmt:message key="avataruploadresult.success"><fmt:param value="${model.avatar.name}"/></fmt:message>
|
||||
<sub:url value="avatar.view" var="avatarUrl">
|
||||
<sub:param name="username" value="${model.username}"/>
|
||||
<sub:param name="forceCustom" value="true"/>
|
||||
</sub:url>
|
||||
<img src="${avatarUrl}" alt="${model.avatar.name}" width="${model.avatar.width}"
|
||||
height="${model.avatar.height}" style="padding-left:2em"/>
|
||||
</p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<p class="warning">
|
||||
<fmt:message key="avataruploadresult.failure"/>
|
||||
</p>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<div class="back"><a href="personalSettings.view?"><fmt:message key="common.back"/></a></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,139 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/coverArtService.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/engine.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/util.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/prototype.js"/>"></script>
|
||||
|
||||
<script type="text/javascript" language="javascript">
|
||||
|
||||
dwr.engine.setErrorHandler(function() {
|
||||
$("wait").hide();
|
||||
dwr.util.setValue("errorDetails", "Sorry, an error occurred while searching for cover art.");
|
||||
$("errorDetails").show();
|
||||
});
|
||||
|
||||
function setImage(imageUrl) {
|
||||
$("wait").show();
|
||||
$("result").hide();
|
||||
$("success").hide();
|
||||
$("error").hide();
|
||||
$("errorDetails").hide();
|
||||
$("noImagesFound").hide();
|
||||
coverArtService.setCoverArtImage(${model.id}, imageUrl, setImageComplete);
|
||||
}
|
||||
|
||||
function setImageComplete(errorDetails) {
|
||||
$("wait").hide();
|
||||
if (errorDetails != null) {
|
||||
dwr.util.setValue("errorDetails", errorDetails, { escapeHtml:false });
|
||||
$("error").show();
|
||||
$("errorDetails").show();
|
||||
} else {
|
||||
$("success").show();
|
||||
}
|
||||
}
|
||||
|
||||
function searchComplete(searchResults) {
|
||||
$("wait").hide();
|
||||
|
||||
if (searchResults.length > 0) {
|
||||
|
||||
var images = $("images");
|
||||
images.innerHTML = "";
|
||||
|
||||
for (var i = 0; i < searchResults.length; i++) {
|
||||
var result = searchResults[i];
|
||||
var node = $("template").cloneNode(true);
|
||||
|
||||
var link = node.getElementsByClassName("search-result-link")[0];
|
||||
link.href = "javascript:setImage('" + result.imageUrl + "');";
|
||||
|
||||
var thumbnail = node.getElementsByClassName("search-result-image")[0];
|
||||
thumbnail.src = result.imageUrl;
|
||||
|
||||
var title = node.getElementsByClassName("search-result-artist")[0];
|
||||
title.innerHTML = result.artist;
|
||||
|
||||
var dimension = node.getElementsByClassName("search-result-album")[0];
|
||||
dimension.innerHTML = result.album;
|
||||
|
||||
node.show();
|
||||
images.appendChild(node);
|
||||
}
|
||||
|
||||
$("result").show();
|
||||
|
||||
|
||||
} else {
|
||||
$("noImagesFound").show();
|
||||
}
|
||||
}
|
||||
|
||||
function search() {
|
||||
|
||||
$("wait").show();
|
||||
$("result").hide();
|
||||
$("success").hide();
|
||||
$("error").hide();
|
||||
$("errorDetails").hide();
|
||||
$("noImagesFound").hide();
|
||||
|
||||
var artist = dwr.util.getValue("artist");
|
||||
var album = dwr.util.getValue("album");
|
||||
coverArtService.searchCoverArt(artist, album, searchComplete);
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1" onload="search()">
|
||||
<h1><fmt:message key="changecoverart.title"/></h1>
|
||||
<form action="javascript:search()">
|
||||
<sec:csrfInput />
|
||||
<table class="indent"><tr>
|
||||
<td><input id="artist" name="artist" placeholder="<fmt:message key="changecoverart.artist"/>" size="35" type="text" value="${model.artist}" onclick="select()"/></td>
|
||||
<td><input id="album" name="album" placeholder="<fmt:message key="changecoverart.album"/>" size="35" type="text" value="${model.album}" onclick="select()"/></td>
|
||||
<td style="padding-left:0.5em"><input type="submit" value="<fmt:message key="changecoverart.search"/>"/></td>
|
||||
</tr></table>
|
||||
</form>
|
||||
|
||||
<form action="javascript:setImage(dwr.util.getValue('url'))">
|
||||
<sec:csrfInput />
|
||||
<table><tr>
|
||||
<td><label for="url"><fmt:message key="changecoverart.address"/></label></td>
|
||||
<td style="padding-left:0.5em"><input type="text" name="url" size="50" id="url" value="http://" onclick="select()"/></td>
|
||||
<td style="padding-left:0.5em"><input type="submit" value="<fmt:message key="common.ok"/>"></td>
|
||||
</tr></table>
|
||||
</form>
|
||||
<sub:url value="main.view" var="backUrl"><sub:param name="id" value="${model.id}"/></sub:url>
|
||||
<div style="padding-top:0.5em;padding-bottom:0.5em">
|
||||
<div class="back"><a href="${backUrl}"><fmt:message key="common.back"/></a></div>
|
||||
</div>
|
||||
|
||||
<h2 id="wait" style="display:none"><fmt:message key="changecoverart.wait"/></h2>
|
||||
<h2 id="noImagesFound" style="display:none"><fmt:message key="changecoverart.noimagesfound"/></h2>
|
||||
<h2 id="success" style="display:none"><fmt:message key="changecoverart.success"/></h2>
|
||||
<h2 id="error" style="display:none"><fmt:message key="changecoverart.error"/></h2>
|
||||
<div id="errorDetails" class="warning" style="display:none">
|
||||
</div>
|
||||
|
||||
<div id="result" style="padding-top:2em">
|
||||
<div style="clear:both;"></div>
|
||||
<div id="images"></div>
|
||||
<div style="clear:both;"></div>
|
||||
<a href="http://last.fm/" target="_blank"><img src="<c:url value="/icons/lastfm.gif"/>"></a>
|
||||
<span class="detail" style="padding-left:1em"><fmt:message key="changecoverart.courtesy"/></span>
|
||||
</div>
|
||||
|
||||
<div id="template" class="coverart dropshadow" style="float:left;margin-right:2.0em;margin-bottom:2.0em;width:250px;display:none">
|
||||
<div>
|
||||
<a class="search-result-link"><img class="search-result-image" style="width:250px;height:250px"></a>
|
||||
<div class="search-result-artist caption1"></div>
|
||||
<div class="search-result-album caption2"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body></html>
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
<%@ include file="include.jsp" %>
|
||||
|
||||
<%--
|
||||
PARAMETERS
|
||||
albumId: ID of album.
|
||||
playlistId: ID of playlist.
|
||||
podcastChannelId: ID of podcast channel
|
||||
coverArtSize: Height and width of cover art.
|
||||
caption1: Caption line 1
|
||||
caption2: Caption line 2
|
||||
caption3: Caption line 3
|
||||
captionCount: Number of caption lines to display (default 0)
|
||||
showLink: Whether to make the cover art image link to the album page.
|
||||
showZoom: Whether to display a link for zooming the cover art.
|
||||
showChange: Whether to display a link for changing the cover art.
|
||||
appearAfter: Fade in after this many milliseconds, or nil if no fading in should happen.
|
||||
hideOverflow: Hide cover art overflow when height is greater than width
|
||||
--%>
|
||||
<c:choose>
|
||||
<c:when test="${empty param.coverArtSize}">
|
||||
<c:set var="size" value="auto"/>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<c:set var="size" value="${param.coverArtSize}px"/>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<c:set var="captionCount" value="${empty param.captionCount ? 0 : param.captionCount}"/>
|
||||
|
||||
<str:randomString count="5" type="alphabet" var="divId"/>
|
||||
<str:randomString count="5" type="alphabet" var="imgId"/>
|
||||
<str:randomString count="5" type="alphabet" var="playId"/>
|
||||
|
||||
<div class="coverart dropshadow">
|
||||
<div style="width:${size};max-width:${size};height:${size};max-height:${size};cursor:pointer;<c:if test="${param.hideOverflow}">overflow:hidden</c:if>;" title="${param.caption1}" id="${divId}">
|
||||
|
||||
<c:if test="${not empty param.albumId}">
|
||||
<c:url value="main.view" var="targetUrl">
|
||||
<c:param name="id" value="${param.albumId}"/>
|
||||
</c:url>
|
||||
</c:if>
|
||||
<c:if test="${not empty param.playlistId}">
|
||||
<c:url value="playlist.view" var="targetUrl">
|
||||
<c:param name="id" value="${param.playlistId}"/>
|
||||
</c:url>
|
||||
</c:if>
|
||||
<c:if test="${not empty param.podcastChannelId}">
|
||||
<c:url value="podcastChannel.view" var="targetUrl">
|
||||
<c:param name="id" value="${param.podcastChannelId}"/>
|
||||
</c:url>
|
||||
</c:if>
|
||||
|
||||
<c:url value="/coverArt.view" var="coverArtUrl">
|
||||
<c:if test="${not empty param.coverArtSize}">
|
||||
<c:param name="size" value="${param.coverArtSize}"/>
|
||||
</c:if>
|
||||
<c:if test="${not empty param.albumId}">
|
||||
<c:param name="id" value="${param.albumId}"/>
|
||||
</c:if>
|
||||
<c:if test="${not empty param.podcastChannelId}">
|
||||
<c:param name="id" value="pod-${param.podcastChannelId}"/>
|
||||
</c:if>
|
||||
<c:if test="${not empty param.playlistId}">
|
||||
<c:param name="id" value="pl-${param.playlistId}"/>
|
||||
</c:if>
|
||||
</c:url>
|
||||
|
||||
<c:url value="/coverArt.view" var="zoomCoverArtUrl">
|
||||
<c:param name="id" value="${param.albumId}"/>
|
||||
</c:url>
|
||||
|
||||
<div style="position: relative; width: 0; height: 0">
|
||||
<img src="<spring:theme code="playOverlayImage"/>" id="${playId}"
|
||||
style="position: relative; top: 8px; left: 8px; z-index: 2; display:none" >
|
||||
</div>
|
||||
<c:choose>
|
||||
<c:when test="${param.showLink}"><a href="${targetUrl}" title="${param.caption1}"></c:when>
|
||||
<c:when test="${param.showZoom}"><a href="${zoomCoverArtUrl}" rel="zoom" title="${param.caption1}"></c:when>
|
||||
</c:choose>
|
||||
<img src="${coverArtUrl}" id="${imgId}" alt="${param.caption1}"
|
||||
style="display:none">
|
||||
<c:if test="${param.showLink or param.showZoom}"></a></c:if>
|
||||
</div>
|
||||
|
||||
<c:if test="${captionCount gt 0}">
|
||||
<div class="caption1" style="width:${param.coverArtSize - 16}px"><a href="${targetUrl}" title="${param.caption1}">${param.caption1}</a></div>
|
||||
</c:if>
|
||||
<c:if test="${captionCount gt 1}">
|
||||
<div class="caption2" style="width:${param.coverArtSize - 16}px">${param.caption2} </div>
|
||||
</c:if>
|
||||
<c:if test="${captionCount gt 2}">
|
||||
<div class="caption3" style="width:${param.coverArtSize - 16}px">${param.caption3} </div>
|
||||
</c:if>
|
||||
</div>
|
||||
|
||||
<c:if test="${param.showChange or param.showZoom}">
|
||||
<div style="padding-top:6px;text-align:right">
|
||||
<c:if test="${param.showChange}">
|
||||
<c:url value="/changeCoverArt.view" var="changeCoverArtUrl">
|
||||
<c:param name="id" value="${param.albumId}"/>
|
||||
</c:url>
|
||||
<a class="detail" href="${changeCoverArtUrl}"><fmt:message key="coverart.change"/></a>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${param.showZoom and param.showChange}">
|
||||
|
|
||||
</c:if>
|
||||
|
||||
<c:if test="${param.showZoom}">
|
||||
<a class="detail" rel="zoom" title="${param.caption1}" href="${zoomCoverArtUrl}"><fmt:message key="coverart.zoom"/></a>
|
||||
</c:if>
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
setTimeout("$('#${imgId}').fadeIn(500)", ${empty param.appearAfter ? 0 : param.appearAfter});
|
||||
});
|
||||
|
||||
$("#${divId}").mouseenter(function () {
|
||||
$("#${playId}").show();
|
||||
$("#${imgId}").stop();
|
||||
$("#${imgId}").animate({opacity: 0.7}, 150);
|
||||
});
|
||||
$("#${divId}").mouseleave(function () {
|
||||
$("#${playId}").hide();
|
||||
$("#${imgId}").stop();
|
||||
$("#${imgId}").animate({opacity: 1.0}, 150);
|
||||
});
|
||||
$("#${playId}").click(function () {
|
||||
<c:if test="${not empty param.albumId}">
|
||||
top.playQueue.onPlay(${param.albumId});
|
||||
</c:if>
|
||||
<c:if test="${not empty param.playlistId}">
|
||||
top.playQueue.onPlayPlaylist(${param.playlistId});
|
||||
</c:if>
|
||||
<c:if test="${not empty param.podcastChannelId}">
|
||||
top.playQueue.onPlayPodcastChannel(${param.podcastChannelId});
|
||||
</c:if>
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1">
|
||||
|
||||
<h1>
|
||||
<img src="<spring:theme code="shareImage"/>" alt="">
|
||||
<span style="vertical-align: middle"><fmt:message key="share.title"/></span>
|
||||
</h1>
|
||||
|
||||
<fmt:message key="share.warning"/>
|
||||
<p>
|
||||
<a href="http://www.facebook.com/sharer.php?u=${model.playUrl}" target="_blank"><img src="<spring:theme code="shareFacebookImage"/>" alt=""></a>
|
||||
<a href="http://www.facebook.com/sharer.php?u=${model.playUrl}" target="_blank"><fmt:message key="share.facebook"/></a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="http://twitter.com/?status=Listening to ${model.playUrl}" target="_blank"><img src="<spring:theme code="shareTwitterImage"/>" alt=""></a>
|
||||
<a href="http://twitter.com/?status=Listening to ${model.playUrl}" target="_blank"><fmt:message key="share.twitter"/></a>
|
||||
</p>
|
||||
<p>
|
||||
<g:plusone size="small" annotation="none" href="${model.playUrl}"></g:plusone> <fmt:message key="share.googleplus"/>
|
||||
</p>
|
||||
<p>
|
||||
<fmt:message key="share.link">
|
||||
<fmt:param>${model.playUrl}</fmt:param>
|
||||
</fmt:message>
|
||||
</p>
|
||||
|
||||
<div style="padding-top:1em">
|
||||
<c:if test="${not empty model.dir}">
|
||||
<sub:url value="main.view" var="backUrl"><sub:param name="path" value="${model.dir.path}"/></sub:url>
|
||||
<div class="back" style="float:left;padding-right:10pt"><a href="${backUrl}"><fmt:message key="common.back"/></a></div>
|
||||
</c:if>
|
||||
<c:if test="${model.user.settingsRole}">
|
||||
<div class="forward" style="float:left"><a href="shareSettings.view"><fmt:message key="share.manage"/></a></div>
|
||||
</c:if>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,128 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
<%--@elvariable id="command" type="org.libresonic.player.command.DatabaseSettingsCommand"--%>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<script>
|
||||
function updateShownOptions() {
|
||||
$(".hideawayDatabaseOptions").hide();
|
||||
var value = $('select#configType').val();
|
||||
var objToShow = $("#" + value + "DatabaseOptions");
|
||||
if (objToShow.length) {
|
||||
objToShow.show();
|
||||
}
|
||||
if(value != 'LEGACY') {
|
||||
$("#nonLEGACYDatabaseOptions").show();
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
updateShownOptions();
|
||||
$('select#configType').on('change', function () {
|
||||
updateShownOptions();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1">
|
||||
<script type="text/javascript" src="<c:url value="/script/wz_tooltip.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/tip_balloon.js"/>"></script>
|
||||
|
||||
<c:import url="settingsHeader.jsp">
|
||||
<c:param name="cat" value="database"/>
|
||||
<c:param name="toast" value="${settings_toast}"/>
|
||||
</c:import>
|
||||
|
||||
<form:form commandName="command" action="databaseSettings.view" method="post">
|
||||
<p><fmt:message key="databasesettings.moreinfo"/></p>
|
||||
|
||||
<table style="white-space:nowrap" class="indent">
|
||||
<tr>
|
||||
<td><fmt:message key="databasesettings.configtype"/></td>
|
||||
<td>
|
||||
<form:select path="configType" cssStyle="width:12em" id="configType">
|
||||
<form:option value="LEGACY" label="Legacy"/>
|
||||
<form:option value="EMBED" label="Embedded JDBC"/>
|
||||
<form:option value="JNDI" label="JNDI"/>
|
||||
</form:select>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="databaseConfigType"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div id="EMBEDDatabaseOptions" class="hideawayDatabaseOptions">
|
||||
<table style="white-space:nowrap;" class="indent">
|
||||
<table style="white-space:nowrap;" class="indent">
|
||||
<tr>
|
||||
<td><fmt:message key="databasesettings.embeddriver"/></td>
|
||||
<td>
|
||||
<form:input path="embedDriver" size="30"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="embeddriver"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="databasesettings.embedurl"/></td>
|
||||
<td>
|
||||
<form:input path="embedUrl" size="58"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="databasesettings.embedusername"/></td>
|
||||
<td>
|
||||
<form:input path="embedUsername" size="36"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="databasesettings.embedpassword"/></td>
|
||||
<td>
|
||||
<form:input path="embedPassword" size="36"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="JNDIDatabaseOptions" class="hideawayDatabaseOptions">
|
||||
<table style="white-space:nowrap;" class="indent">
|
||||
<tr>
|
||||
<td><fmt:message key="databasesettings.jndiname"/></td>
|
||||
<td>
|
||||
<form:input path="JNDIName" size="36"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="jndiname"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="nonLEGACYDatabaseOptions" class="hideawayDatabaseOptions">
|
||||
<table style="white-space:nowrap" class="indent">
|
||||
<tr>
|
||||
<td><fmt:message key="databasesettings.mysqlvarcharmaxlength"/></td>
|
||||
<td>
|
||||
<form:input path="mysqlVarcharMaxlength" size="8"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="mysqlvarcharmaxlength"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="databasesettings.usertablequote"/></td>
|
||||
<td>
|
||||
<form:input path="usertableQuote" size="1" htmlEscape="true"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="usertablequote"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p class="warning"><fmt:message key="databasesettings.jdbclibrary"/></p>
|
||||
</div>
|
||||
|
||||
<p class="warning"><fmt:message key="databasettings.restartRequired"/></p>
|
||||
|
||||
<p>
|
||||
<input type="submit" value="<fmt:message key="common.save"/>" style="margin-right:0.3em">
|
||||
<input type="button" value="<fmt:message key="common.cancel"/>" onclick="location.href='nowPlaying.view'">
|
||||
</p>
|
||||
|
||||
</form:form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,46 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
</head><body class="mainframe bgcolor1" onload="document.getElementById('query').focus()">
|
||||
|
||||
<h1>Database query</h1>
|
||||
|
||||
<form method="post" action="db.view">
|
||||
<sec:csrfInput />
|
||||
<textarea rows="10" cols="80" id="query" name="query" style="margin-top:1em">${model.query}</textarea>
|
||||
<input type="submit" value="<fmt:message key="common.ok"/>">
|
||||
</form>
|
||||
|
||||
<c:if test="${not empty model.result}">
|
||||
<h1 style="margin-top:2em">Result</h1>
|
||||
|
||||
<table class="indent ruleTable">
|
||||
<c:forEach items="${model.result}" var="row" varStatus="loopStatus">
|
||||
|
||||
<c:if test="${loopStatus.count == 1}">
|
||||
<tr>
|
||||
<c:forEach items="${row}" var="entry">
|
||||
<td class="ruleTableHeader">${entry.key}</td>
|
||||
</c:forEach>
|
||||
</tr>
|
||||
</c:if>
|
||||
<tr>
|
||||
<c:forEach items="${row}" var="entry">
|
||||
<td class="ruleTableCell">${entry.value}</td>
|
||||
</c:forEach>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
|
||||
</table>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${not empty model.error}">
|
||||
<h1 style="margin-top:2em">Error</h1>
|
||||
|
||||
<p class="warning">
|
||||
${model.error}
|
||||
</p>
|
||||
</c:if>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,73 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
<%--
|
||||
~ This file is part of Libresonic.
|
||||
~
|
||||
~ Libresonic 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
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ Libresonic 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 Libresonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
~
|
||||
~ Copyright 2013 (C) Sindre Mehus
|
||||
--%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value="/script/scripts-2.0.js"/>"></script>
|
||||
</head>
|
||||
|
||||
<body class="mainframe bgcolor1">
|
||||
<script type="text/javascript" src="<c:url value="/script/wz_tooltip.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/tip_balloon.js"/>"></script>
|
||||
|
||||
<c:import url="settingsHeader.jsp">
|
||||
<c:param name="cat" value="dlna"/>
|
||||
<c:param name="toast" value="${settings_toast}"/>
|
||||
</c:import>
|
||||
|
||||
<form method="post" action="dlnaSettings.view">
|
||||
<sec:csrfInput />
|
||||
|
||||
<div>
|
||||
<input type="checkbox" name="dlnaEnabled" id="dlnaEnabled" class="checkbox"
|
||||
<c:if test="${model.dlnaEnabled}">checked="checked"</c:if>/>
|
||||
<label for="dlnaEnabled"><fmt:message key="dlnasettings.enabled"/></label>
|
||||
</div>
|
||||
<p class="detail" style="width:60%;white-space:normal">
|
||||
<fmt:message key="dlnasettings.description"/>
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<fmt:message key="dlnasettings.servername"/>
|
||||
<input name="dlnaServerName" id="dlnaServerName" size="40"
|
||||
value="<c:out value="${model.dlnaServerName}" escapeXml="true"/>"/>
|
||||
</div>
|
||||
<p class="detail" style="width:60%;white-space:normal;padding-top:0">
|
||||
<fmt:message key="dlnasettings.servername.description"/>
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<label for="dlnaBaseLANURL" ><fmt:message key="dlnasettings.baselanurl"/></label>
|
||||
<input type="text" size="50" name="dlnaBaseLANURL" id="dlnaBaseLANURL"
|
||||
value="<c:out value="${model.dlnaBaseLANURL}" />" />
|
||||
</div>
|
||||
<p class="detail" style="width:60%;white-space:normal">
|
||||
<fmt:message key="dlnasettings.lanurl.description"/>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<input type="submit" value="<fmt:message key="common.save"/>" style="margin-right:0.3em">
|
||||
<input type="button" value="<fmt:message key="common.cancel"/>" onclick="location.href='nowPlaying.view'">
|
||||
</p>
|
||||
|
||||
</form>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,164 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/tagService.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/engine.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/util.js"/>"></script>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1">
|
||||
|
||||
<script type="text/javascript" language="javascript">
|
||||
var index = 0;
|
||||
var fileCount = ${fn:length(model.songs)};
|
||||
function setArtist() {
|
||||
var artist = dwr.util.getValue("artistAll");
|
||||
for (i = 0; i < fileCount; i++) {
|
||||
dwr.util.setValue("artist" + i, artist);
|
||||
}
|
||||
}
|
||||
function setAlbum() {
|
||||
var album = dwr.util.getValue("albumAll");
|
||||
for (i = 0; i < fileCount; i++) {
|
||||
dwr.util.setValue("album" + i, album);
|
||||
}
|
||||
}
|
||||
function setYear() {
|
||||
var year = dwr.util.getValue("yearAll");
|
||||
for (i = 0; i < fileCount; i++) {
|
||||
dwr.util.setValue("year" + i, year);
|
||||
}
|
||||
}
|
||||
function setGenre() {
|
||||
var genre = dwr.util.getValue("genreAll");
|
||||
for (i = 0; i < fileCount; i++) {
|
||||
dwr.util.setValue("genre" + i, genre);
|
||||
}
|
||||
}
|
||||
function suggestTitle() {
|
||||
for (i = 0; i < fileCount; i++) {
|
||||
var title = dwr.util.getValue("suggestedTitle" + i);
|
||||
dwr.util.setValue("title" + i, title);
|
||||
}
|
||||
}
|
||||
function resetTitle() {
|
||||
for (i = 0; i < fileCount; i++) {
|
||||
var title = dwr.util.getValue("originalTitle" + i);
|
||||
dwr.util.setValue("title" + i, title);
|
||||
}
|
||||
}
|
||||
function suggestTrack() {
|
||||
for (i = 0; i < fileCount; i++) {
|
||||
var track = dwr.util.getValue("suggestedTrack" + i);
|
||||
dwr.util.setValue("track" + i, track);
|
||||
}
|
||||
}
|
||||
function resetTrack() {
|
||||
for (i = 0; i < fileCount; i++) {
|
||||
var track = dwr.util.getValue("originalTrack" + i);
|
||||
dwr.util.setValue("track" + i, track);
|
||||
}
|
||||
}
|
||||
function updateTags() {
|
||||
document.getElementById("save").disabled = true;
|
||||
index = 0;
|
||||
dwr.util.setValue("errors", "");
|
||||
for (i = 0; i < fileCount; i++) {
|
||||
dwr.util.setValue("status" + i, "");
|
||||
}
|
||||
updateNextTag();
|
||||
}
|
||||
function updateNextTag() {
|
||||
var id = dwr.util.getValue("id" + index);
|
||||
var artist = dwr.util.getValue("artist" + index);
|
||||
var track = dwr.util.getValue("track" + index);
|
||||
var album = dwr.util.getValue("album" + index);
|
||||
var title = dwr.util.getValue("title" + index);
|
||||
var year = dwr.util.getValue("year" + index);
|
||||
var genre = dwr.util.getValue("genre" + index);
|
||||
dwr.util.setValue("status" + index, "<fmt:message key="edittags.working"/>");
|
||||
tagService.setTags(id, track, artist, album, title, year, genre, setTagsCallback);
|
||||
}
|
||||
function setTagsCallback(result) {
|
||||
var message;
|
||||
if (result == "SKIPPED") {
|
||||
message = "<fmt:message key="edittags.skipped"/>";
|
||||
} else if (result == "UPDATED") {
|
||||
message = "<b><fmt:message key="edittags.updated"/></b>";
|
||||
} else {
|
||||
message = "<div class='warning'><fmt:message key="edittags.error"/></div>"
|
||||
var errors = dwr.util.getValue("errors");
|
||||
errors += "<br>" + result + "<br>";
|
||||
dwr.util.setValue("errors", errors, { escapeHtml:false });
|
||||
}
|
||||
dwr.util.setValue("status" + index, message, { escapeHtml:false });
|
||||
index++;
|
||||
if (index < fileCount) {
|
||||
updateNextTag();
|
||||
} else {
|
||||
document.getElementById("save").disabled = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<h1><fmt:message key="edittags.title"/></h1>
|
||||
<sub:url value="main.view" var="backUrl"><sub:param name="id" value="${model.id}"/></sub:url>
|
||||
<div class="back"><a href="${backUrl}"><fmt:message key="common.back"/></a></div>
|
||||
|
||||
<table class="ruleTable indent">
|
||||
<tr>
|
||||
<th class="ruleTableHeader"><fmt:message key="edittags.file"/></th>
|
||||
<th class="ruleTableHeader"><fmt:message key="edittags.track"/></th>
|
||||
<th class="ruleTableHeader"><fmt:message key="edittags.songtitle"/></th>
|
||||
<th class="ruleTableHeader"><fmt:message key="edittags.artist"/></th>
|
||||
<th class="ruleTableHeader"><fmt:message key="edittags.album"/></th>
|
||||
<th class="ruleTableHeader"><fmt:message key="edittags.year"/></th>
|
||||
<th class="ruleTableHeader"><fmt:message key="edittags.genre"/></th>
|
||||
<th class="ruleTableHeader" width="60pt"><fmt:message key="edittags.status"/></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="ruleTableHeader"/>
|
||||
<th class="ruleTableHeader"><a href="javascript:suggestTrack()"><fmt:message key="edittags.suggest.short"/></a> |
|
||||
<a href="javascript:resetTrack()"><fmt:message key="edittags.reset.short"/></a></th>
|
||||
<th class="ruleTableHeader"><a href="javascript:suggestTitle()"><fmt:message key="edittags.suggest"/></a> |
|
||||
<a href="javascript:resetTitle()"><fmt:message key="edittags.reset"/></a></th>
|
||||
<th class="ruleTableHeader" style="white-space: nowrap"><input type="text" name="artistAll" size="15" onkeypress="dwr.util.onReturn(event, setArtist)" value="${model.defaultArtist}"/> <a href="javascript:setArtist()"><fmt:message key="edittags.set"/></a></th>
|
||||
<th class="ruleTableHeader" style="white-space: nowrap"><input type="text" name="albumAll" size="15" onkeypress="dwr.util.onReturn(event, setAlbum)" value="${model.defaultAlbum}"/> <a href="javascript:setAlbum()"><fmt:message key="edittags.set"/></a></th>
|
||||
<th class="ruleTableHeader" style="white-space: nowrap"><input type="text" name="yearAll" size="5" onkeypress="dwr.util.onReturn(event, setYear)" value="${model.defaultYear}"/> <a href="javascript:setYear()"><fmt:message key="edittags.set"/></a></th>
|
||||
<th class="ruleTableHeader" style="white-space: nowrap">
|
||||
<select name="genreAll" style="width:7em">
|
||||
<option value=""/>
|
||||
<c:forEach items="${model.allGenres}" var="genre">
|
||||
<option ${genre eq model.defaultGenre ? "selected" : ""} value="${genre}">${genre}</option>
|
||||
</c:forEach>
|
||||
</select>
|
||||
|
||||
<a href="javascript:setGenre()"><fmt:message key="edittags.set"/></a>
|
||||
</th>
|
||||
<th class="ruleTableHeader"/>
|
||||
</tr>
|
||||
|
||||
<c:forEach items="${model.songs}" var="song" varStatus="loopStatus">
|
||||
<tr>
|
||||
<str:truncateNicely lower="25" upper="25" var="fileName">${song.fileName}</str:truncateNicely>
|
||||
<input type="hidden" name="id${loopStatus.count - 1}" value="${song.id}"/>
|
||||
<input type="hidden" name="suggestedTitle${loopStatus.count - 1}" value="${song.suggestedTitle}"/>
|
||||
<input type="hidden" name="originalTitle${loopStatus.count - 1}" value="${song.title}"/>
|
||||
<input type="hidden" name="suggestedTrack${loopStatus.count - 1}" value="${song.suggestedTrack}"/>
|
||||
<input type="hidden" name="originalTrack${loopStatus.count - 1}" value="${song.track}"/>
|
||||
<td class="ruleTableCell" title="${song.fileName}">${fileName}</td>
|
||||
<td class="ruleTableCell"><input type="text" size="5" name="track${loopStatus.count - 1}" value="${song.track}"/></td>
|
||||
<td class="ruleTableCell"><input type="text" size="30" name="title${loopStatus.count - 1}" value="${song.title}"/></td>
|
||||
<td class="ruleTableCell"><input type="text" size="15" name="artist${loopStatus.count - 1}" value="${song.artist}"/></td>
|
||||
<td class="ruleTableCell"><input type="text" size="15" name="album${loopStatus.count - 1}" value="${song.album}"/></td>
|
||||
<td class="ruleTableCell"><input type="text" size="5" name="year${loopStatus.count - 1}" value="${song.year}"/></td>
|
||||
<td class="ruleTableCell"><input type="text" name="genre${loopStatus.count - 1}" value="${song.genre}" style="width:7em"/></td>
|
||||
<td class="ruleTableCell"><div id="status${loopStatus.count - 1}"/></td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
|
||||
</table>
|
||||
|
||||
<p><input type="submit" id="save" value="<fmt:message key="common.save"/>" onclick="javascript:updateTags()"/></p>
|
||||
<div class="warning" id="errors"/>
|
||||
</body></html>
|
||||
@@ -0,0 +1,67 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="UTF-8" isErrorPage="true" %>
|
||||
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
|
||||
|
||||
<html><head>
|
||||
<!--[if lt IE 7.]>
|
||||
<script defer type="text/javascript" src="script/pngfix.js"></script>
|
||||
<![endif]-->
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<link rel="stylesheet" href="style/default.css" type="text/css"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>
|
||||
<img src="icons/default_light/error.png" alt=""/>
|
||||
<span style="vertical-align: middle">Error</span>
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
Libresonic encountered an internal error. You can report this error in the
|
||||
<a href="https://www.reddit.com/r/libresonic" target="_blank">Libresonic Forum</a>.
|
||||
Please include the information below.
|
||||
</p>
|
||||
|
||||
<%
|
||||
|
||||
long totalMemory = Runtime.getRuntime().totalMemory();
|
||||
long freeMemory = Runtime.getRuntime().freeMemory();
|
||||
long usedMemory = totalMemory - freeMemory;
|
||||
%>
|
||||
|
||||
<table class="ruleTable indent">
|
||||
<tr><td class="ruleTableHeader">Status</td>
|
||||
<td class="ruleTableCell"><c:out value="${status}" /></td></tr>
|
||||
<tr><td class="ruleTableHeader">Error</td>
|
||||
<td class="ruleTableCell"><c:out value="${error}" /></td></tr>
|
||||
<tr><td class="ruleTableHeader">Message</td>
|
||||
<td class="ruleTableCell"><c:out value="${message}" /></td></tr>
|
||||
<tr><td class="ruleTableHeader">Path</td>
|
||||
<td class="ruleTableCell"><c:out value="${path}" /></td></tr>
|
||||
<tr><td class="ruleTableHeader">Time</td>
|
||||
<td class="ruleTableCell"><c:out value="${timestamp}" /></td></tr>
|
||||
<tr><td class="ruleTableHeader">Exception</td>
|
||||
<td class="ruleTableCell"><c:out value="${exception}" /></td></tr>
|
||||
<tr><td class="ruleTableHeader">Java version</td>
|
||||
<td class="ruleTableCell"><%=System.getProperty("java.vendor") + ' ' + System.getProperty("java.version")%></td></tr>
|
||||
<tr><td class="ruleTableHeader">Operating system</td>
|
||||
<td class="ruleTableCell"><%=System.getProperty("os.name") + ' ' + System.getProperty("os.version")%></td></tr>
|
||||
<tr><td class="ruleTableHeader">Server</td>
|
||||
<td class="ruleTableCell"><%=application.getServerInfo()%></td></tr>
|
||||
<tr><td class="ruleTableHeader">Memory</td>
|
||||
<td class="ruleTableCell">Used <%=usedMemory/1024L/1024L%> of <%=totalMemory/1024L/1024L%> MB</td></tr>
|
||||
<c:if test="${not empty trace}">
|
||||
<tr>
|
||||
<td class="ruleTableHeader" style="vertical-align:top;">Stack trace</td>
|
||||
<td class="ruleTableCell" style="white-space:pre">
|
||||
<pre>
|
||||
${fn:escapeXml(trace)}
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
</c:if>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,93 @@
|
||||
<%--@elvariable id="model" type="java.util.Map"--%>
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value="/script/swfobject.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/prototype.js"/>"></script>
|
||||
|
||||
<meta name="og:type" content="album"/>
|
||||
|
||||
<c:if test="${not empty model.songs}">
|
||||
<meta name="og:title" content="${fn:escapeXml(model.songs[0].artist)} — ${fn:escapeXml(model.songs[0].albumName)}"/>
|
||||
<meta name="og:image" content="${model.songs[0].coverArtUrl}"/>
|
||||
</c:if>
|
||||
|
||||
<script type="text/javascript">
|
||||
function init() {
|
||||
var flashvars = {
|
||||
id:"player1",
|
||||
screencolor:"000000",
|
||||
frontcolor:"<spring:theme code="textColor"/>",
|
||||
backcolor:"<spring:theme code="backgroundColor"/>",
|
||||
"playlist.position": "bottom",
|
||||
"playlist.size": 300,
|
||||
repeat: "list"
|
||||
};
|
||||
var params = {
|
||||
allowfullscreen:"true",
|
||||
allowscriptaccess:"always"
|
||||
};
|
||||
var attributes = {
|
||||
id:"player1",
|
||||
name:"player1"
|
||||
};
|
||||
swfobject.embedSWF("<c:url value="/flash/jw-player-5.10.swf"/>", "placeholder", "500", "600", "9.0.0", false, flashvars, params, attributes);
|
||||
}
|
||||
|
||||
function playerReady(thePlayer) {
|
||||
var player = $("player1");
|
||||
var list = new Array();
|
||||
|
||||
<c:forEach items="${model.songs}" var="song" varStatus="loopStatus">
|
||||
<%--@elvariable id="song" type="org.libresonic.player.domain.MediaFileWithUrlInfo"--%>
|
||||
|
||||
// TODO: Use video provider for aac, m4a
|
||||
list[${loopStatus.count - 1}] = {
|
||||
file: "${song.streamUrl}",
|
||||
image: "${song.coverArtUrl}",
|
||||
title: "${fn:escapeXml(song.title)}",
|
||||
provider: "${song.video ? "video" : "sound"}",
|
||||
description: "${fn:escapeXml(song.artist)}"
|
||||
};
|
||||
|
||||
<c:if test="${not empty song.durationSeconds}">
|
||||
list[${loopStatus.count-1}].duration = ${song.durationSeconds};
|
||||
</c:if>
|
||||
|
||||
</c:forEach>
|
||||
|
||||
player.sendEvent("LOAD", list);
|
||||
player.sendEvent("PLAY");
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body class="mainframe bgcolor1" style="padding-top:2em" onload="init();">
|
||||
|
||||
<div style="margin:auto;width:500px">
|
||||
<h1>
|
||||
<c:choose>
|
||||
<c:when test="${empty model.share or empty model.songs}">
|
||||
Sorry, the content is not available.
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
${empty model.share.description ? model.songs[0].artist : fn:escapeXml(model.share.description)}
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</h1>
|
||||
<div style="float:left;padding-right:1.5em">
|
||||
<h2 style="margin:0;">${empty model.share.description ? model.songs[0].albumName : fn:escapeXml(model.share.username)}</h2>
|
||||
</div>
|
||||
<div class="detail" style="float:right">Streaming by <a href="http://libresonic.org/" target="_blank"><b>Libresonic</b></a></div>
|
||||
|
||||
<div style="clear:both;padding-top:1em">
|
||||
<div id="placeholder">
|
||||
<a href="http://www.adobe.com/go/getflashplayer" target="_blank"><fmt:message key="playlist.getflash"/></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,175 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
<%--@elvariable id="command" type="org.libresonic.player.command.GeneralSettingsCommand"--%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value="/script/scripts-2.0.js"/>"></script>
|
||||
</head>
|
||||
|
||||
<body class="mainframe bgcolor1">
|
||||
<script type="text/javascript" src="<c:url value="/script/wz_tooltip.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/tip_balloon.js"/>"></script>
|
||||
|
||||
<c:import url="settingsHeader.jsp">
|
||||
<c:param name="cat" value="general"/>
|
||||
<c:param name="toast" value="${settings_toast}"/>
|
||||
</c:import>
|
||||
|
||||
<form:form method="post" action="generalSettings.view" commandName="command">
|
||||
|
||||
<table style="white-space:nowrap" class="indent">
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="generalsettings.musicmask"/></td>
|
||||
<td>
|
||||
<form:input path="musicFileTypes" size="70"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="musicmask"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="generalsettings.videomask"/></td>
|
||||
<td>
|
||||
<form:input path="videoFileTypes" size="70"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="videomask"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="generalsettings.coverartmask"/></td>
|
||||
<td>
|
||||
<form:input path="coverArtFileTypes" size="70"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="coverartmask"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="generalsettings.playlistfolder"/></td>
|
||||
<td>
|
||||
<form:input path="playlistFolder" size="70"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="playlistfolder"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr><td colspan="2"> </td></tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="generalsettings.index"/></td>
|
||||
<td>
|
||||
<form:input path="index" size="70"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="index"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="generalsettings.ignoredarticles"/></td>
|
||||
<td>
|
||||
<form:input path="ignoredArticles" size="70"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="ignoredarticles"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="generalsettings.shortcuts"/></td>
|
||||
<td>
|
||||
<form:input path="shortcuts" size="70"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="shortcuts"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr><td colspan="2"> </td></tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="generalsettings.language"/></td>
|
||||
<td>
|
||||
<form:select path="localeIndex" cssStyle="width:15em">
|
||||
<c:forEach items="${command.locales}" var="locale" varStatus="loopStatus">
|
||||
<form:option value="${loopStatus.count - 1}" label="${locale}"/>
|
||||
</c:forEach>
|
||||
</form:select>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="language"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="generalsettings.theme"/></td>
|
||||
<td>
|
||||
<form:select path="themeIndex" cssStyle="width:15em">
|
||||
<c:forEach items="${command.themes}" var="theme" varStatus="loopStatus">
|
||||
<form:option value="${loopStatus.count - 1}" label="${theme.name}"/>
|
||||
</c:forEach>
|
||||
</form:select>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="theme"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr><td colspan="2"> </td></tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<form:checkbox path="sortAlbumsByYear" id="sortAlbumsByYear"/>
|
||||
<label for="sortAlbumsByYear"><fmt:message key="generalsettings.sortalbumsbyyear"/></label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
<form:checkbox path="gettingStartedEnabled" id="gettingStartedEnabled"/>
|
||||
<label for="gettingStartedEnabled"><fmt:message key="generalsettings.showgettingstarted"/></label>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr><td colspan="2"> </td></tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="generalsettings.welcometitle"/></td>
|
||||
<td>
|
||||
<form:input path="welcomeTitle" size="70"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="welcomemessage"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="generalsettings.welcomesubtitle"/></td>
|
||||
<td>
|
||||
<form:input path="welcomeSubtitle" size="70"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="welcomemessage"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align:top;"><fmt:message key="generalsettings.welcomemessage"/></td>
|
||||
<td>
|
||||
<form:textarea path="welcomeMessage" rows="5" cols="70"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="welcomemessage"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align:top;"><fmt:message key="generalsettings.loginmessage"/></td>
|
||||
<td>
|
||||
<form:textarea path="loginMessage" rows="5" cols="70"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="loginmessage"/></c:import>
|
||||
<fmt:message key="main.wiki"/>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2" style="padding-top:1.5em">
|
||||
<input type="submit" value="<fmt:message key="common.save"/>" style="margin-right:0.3em">
|
||||
<input type="button" value="<fmt:message key="common.cancel"/>" onclick="location.href='nowPlaying.view'">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</form:form>
|
||||
|
||||
<c:if test="${settings_reload}">
|
||||
<script language="javascript" type="text/javascript">
|
||||
parent.frames.left.location.href="left.view?";
|
||||
parent.frames.playQueue.location.href="playQueue.view?";
|
||||
</script>
|
||||
</c:if>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,53 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<script type="text/javascript" language="javascript">
|
||||
function hideGettingStarted() {
|
||||
alert("<fmt:message key="gettingStarted.hidealert"/>");
|
||||
location.href = "gettingStarted.view?hide";
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1">
|
||||
|
||||
<h1 style="padding-bottom:0.5em">
|
||||
<img src="<spring:theme code="homeImage"/>" alt="">
|
||||
<fmt:message key="gettingStarted.title"/>
|
||||
</h1>
|
||||
|
||||
<fmt:message key="gettingStarted.text"/>
|
||||
|
||||
<c:if test="${model.runningAsRoot}">
|
||||
<h2 class="warning"><fmt:message key="gettingStarted.root"/></h2>
|
||||
</c:if>
|
||||
|
||||
<table style="padding-top:1em;padding-bottom:2em;width:60%">
|
||||
<tr>
|
||||
<td style="font-size:26pt;padding:20pt">1</td>
|
||||
<td>
|
||||
<div style="font-size:14pt"><a href="userSettings.view?userIndex=0"><fmt:message key="gettingStarted.step1.title"/></a></div>
|
||||
<div style="padding-top:5pt"><fmt:message key="gettingStarted.step1.text"/></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-size:26pt;padding:20pt">2</td>
|
||||
<td>
|
||||
<div style="font-size:14pt"><a href="musicFolderSettings.view"><fmt:message key="gettingStarted.step2.title"/></a></div>
|
||||
<div style="padding-top:5pt"><fmt:message key="gettingStarted.step2.text"/></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-size:26pt;padding:20pt">3</td>
|
||||
<td>
|
||||
<div style="font-size:14pt"><fmt:message key="gettingStarted.step3.title"/></div>
|
||||
<div style="padding-top:5pt"><fmt:message key="gettingStarted.step3.text"/></div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<div class="forward"><a href="javascript:hideGettingStarted()"><fmt:message key="gettingStarted.hide"/></a></div>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,49 @@
|
||||
<%@ include file="include.jsp" %>
|
||||
|
||||
<!--[if lt IE 7.]>
|
||||
<script defer type="text/javascript" src="<c:url value="/script/pngfix.js"/>"></script>
|
||||
<![endif]-->
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<c:set var="styleSheet"><spring:theme code="styleSheet"/></c:set>
|
||||
<link rel="icon" type="image/png" href="<c:url value="/icons/favicon.png"/>"/>
|
||||
<link rel="stylesheet" href="<c:url value="/${styleSheet}"/>" type="text/css">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu&subset=latin,cyrillic-ext,greek-ext,greek,latin-ext,cyrillic" type="text/css"/>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:400,300,400italic,500,300italic,500italic,700,700italic,100,100italic" type="text/css"/>
|
||||
<title>Libresonic</title>
|
||||
|
||||
<!-- Import Mousetrap and enable shortcuts if necessary -->
|
||||
<script>
|
||||
function isKeyboardShortcutsEnabled() {
|
||||
if (window === parent.frames.top) {
|
||||
return ${model.keyboardShortcutsEnabled ? 'true' : 'false'};
|
||||
} else {
|
||||
return parent.frames.top.isKeyboardShortcutsEnabled();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Bind shortcuts if enabled -->
|
||||
<script type="text/javascript" src="<c:url value="/script/mousetrap-1.6.0.js"/>"></script>
|
||||
<script type="text/javascript">
|
||||
if (isKeyboardShortcutsEnabled()) {
|
||||
Mousetrap.bind('space', function() { parent.frames.playQueue.onToggleStartStop(); return false; });
|
||||
Mousetrap.bind('left', function() { parent.frames.playQueue.onPrevious(); });
|
||||
Mousetrap.bind('right', function() { parent.frames.playQueue.onNext(); });
|
||||
Mousetrap.bind('*', function() { parent.frames.playQueue.onStarCurrent(); });
|
||||
Mousetrap.bind('plus', function() { parent.frames.playQueue.onGainAdd(+5); });
|
||||
Mousetrap.bind('-', function() { parent.frames.playQueue.onGainAdd(-5); });
|
||||
Mousetrap.bind('q', function() { parent.frames.playQueue.onTogglePlayQueue(); });
|
||||
|
||||
Mousetrap.bind('/', function() { parent.frames.upper.$("#query").focus(); });
|
||||
Mousetrap.bind('m', function() { parent.frames.upper.toggleLeftFrameVisible(); });
|
||||
|
||||
Mousetrap.bind('g h', function() { parent.frames.main.location.href = "home.view?"; });
|
||||
Mousetrap.bind('g p', function() { parent.frames.main.location.href = "playlists.view?"; });
|
||||
Mousetrap.bind('g o', function() { parent.frames.main.location.href = "podcastChannels.view?"; });
|
||||
Mousetrap.bind('g s', function() { parent.frames.main.location.href = "settings.view?"; });
|
||||
Mousetrap.bind('g t', function() { parent.frames.main.location.href = "starred.view?"; });
|
||||
Mousetrap.bind('g r', function() { parent.frames.main.location.href = "more.view?"; });
|
||||
Mousetrap.bind('g a', function() { parent.frames.main.location.href = "help.view?"; });
|
||||
Mousetrap.bind('?', function() { parent.frames.main.location.href = "more.view#shortcuts"; });
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,68 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value="/script/scripts-2.0.js"/>"></script>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1">
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${empty model.buildDate}">
|
||||
<fmt:message key="common.unknown" var="buildDateString"/>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<fmt:formatDate value="${model.buildDate}" dateStyle="long" var="buildDateString"/>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${empty model.localVersion}">
|
||||
<fmt:message key="common.unknown" var="versionString"/>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<c:set var="versionString" value="${model.localVersion}"/>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<h1>
|
||||
<img src="<spring:theme code="helpImage"/>" alt="">
|
||||
<span style="vertical-align: middle"><fmt:message key="help.title"><fmt:param value="${model.brand}"/></fmt:message></span>
|
||||
</h1>
|
||||
|
||||
<c:if test="${model.newVersionAvailable}">
|
||||
<p class="warning"><fmt:message key="help.upgrade"><fmt:param value="${model.brand}"/><fmt:param value="${model.latestVersion}"/></fmt:message></p>
|
||||
</c:if>
|
||||
|
||||
<table width="75%" class="ruleTable indent">
|
||||
|
||||
<tr><td class="ruleTableHeader"><fmt:message key="help.version.title"/></td><td class="ruleTableCell">${versionString} – ${buildDateString}</td></tr>
|
||||
<tr><td class="ruleTableHeader"><fmt:message key="help.server.title"/></td><td class="ruleTableCell">${model.serverInfo} (<sub:formatBytes bytes="${model.usedMemory}"/> / <sub:formatBytes bytes="${model.totalMemory}"/>)</td></tr>
|
||||
<tr><td class="ruleTableHeader"><fmt:message key="help.license.title"/></td><td class="ruleTableCell">
|
||||
<a href="http://www.gnu.org/copyleft/gpl.html" target="_blank"><img style="float:right;margin-left: 10px" alt="GPL 3.0" src="<c:url value="/icons/default_light/gpl.png"/>"></a>
|
||||
<fmt:message key="help.license.text"><fmt:param value="${model.brand}"/></fmt:message></td></tr>
|
||||
<tr><td class="ruleTableHeader"><fmt:message key="help.homepage.title"/></td><td class="ruleTableCell"><a target="_blank" href="https://www.libresonic.org/">Libresonic website</a></td></tr>
|
||||
<tr><td class="ruleTableHeader"><fmt:message key="help.forum.title"/></td><td class="ruleTableCell"><a target="_blank" href="https://www.reddit.com/r/libresonic">Libresonic on Reddit</a></td></tr>
|
||||
<tr><td class="ruleTableHeader"><fmt:message key="help.contact.title"/></td><td class="ruleTableCell"><fmt:message key="help.contact.text"><fmt:param value="${model.brand}"/></fmt:message></td></tr>
|
||||
</table>
|
||||
|
||||
<p></p>
|
||||
|
||||
<h2>
|
||||
<img src="<spring:theme code="logImage"/>" alt="">
|
||||
<span style="vertical-align: middle"><fmt:message key="help.log"/></span>
|
||||
</h2>
|
||||
|
||||
<table cellpadding="2" class="log indent">
|
||||
<c:forEach items="${model.logEntries}" var="entry">
|
||||
<tr>
|
||||
<td>${fn:escapeXml(entry)}</td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</table>
|
||||
|
||||
<p><fmt:message key="help.logfile"><fmt:param value="${model.logFile}"/></fmt:message> </p>
|
||||
|
||||
<div class="forward"><a href="help.view?"><fmt:message key="common.refresh"/></a></div>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,18 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<%@ include file="include.jsp" %>
|
||||
|
||||
<%--
|
||||
Shows online help as a balloon tool tip.
|
||||
|
||||
PARAMETERS
|
||||
topic: Refers to a key in the resource bundle containing the text to display in the tool tip.
|
||||
--%>
|
||||
|
||||
<spring:theme code="helpPopupImage" var="imageUrl"/>
|
||||
<fmt:message key="common.help" var="help"/>
|
||||
|
||||
<div id="placeholder-${param.topic}" style="display:none">
|
||||
<div style="font-weight:bold;"><fmt:message key="helppopup.${param.topic}.title"><fmt:param value="Libresonic"/></fmt:message></div>
|
||||
<div><fmt:message key="helppopup.${param.topic}.text"><fmt:param value="Libresonic"/></fmt:message></div>
|
||||
</div>
|
||||
<img src="${imageUrl}" alt="${help}" title="${help}" onmouseover="TagToTip('placeholder-${param.topic}', BALLOON, true, ABOVE, true, OFFSETX, -17, PADDING, 8, WIDTH, -240, CLICKSTICKY, true, CLICKCLOSE, true)" onmouseout="UnTip()"/>
|
||||
@@ -0,0 +1,131 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
|
||||
<script type="text/javascript" language="javascript">
|
||||
function init() {
|
||||
<c:if test="${model.listReloadDelay gt 0}">
|
||||
setTimeout("refresh()", ${model.listReloadDelay * 1000});
|
||||
</c:if>
|
||||
|
||||
<c:if test="${not model.musicFoldersExist}">
|
||||
$().toastmessage("showNoticeToast", "<fmt:message key="top.missing"/>");
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.isIndexBeingCreated}">
|
||||
$().toastmessage("showNoticeToast", "<fmt:message key="home.scan"/>");
|
||||
</c:if>
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
top.main.location.href = top.main.location.href;
|
||||
}
|
||||
|
||||
function playShuffle() {
|
||||
top.playQueue.onPlayShuffle('${model.listType}', ${model.listOffset}, ${model.listSize}, '${model.genre}', '${model.decade}')
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1" onload="init();">
|
||||
<h1>
|
||||
<img src="<spring:theme code="homeImage"/>" alt="">
|
||||
<span style="vertical-align: middle">${model.welcomeTitle}</span>
|
||||
</h1>
|
||||
|
||||
<c:if test="${not empty model.welcomeSubtitle}">
|
||||
<h2>${model.welcomeSubtitle}</h2>
|
||||
</c:if>
|
||||
|
||||
<h2>
|
||||
<c:forTokens items="random newest starred highest frequent recent decade genre alphabetical" delims=" " var="cat" varStatus="loopStatus">
|
||||
<c:if test="${loopStatus.count > 1}"> | </c:if>
|
||||
<sub:url var="url" value="home.view">
|
||||
<sub:param name="listType" value="${cat}"/>
|
||||
</sub:url>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${model.listType eq cat}">
|
||||
<span class="headerSelected"><fmt:message key="home.${cat}.title"/></span>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<span class="header"><a href="${url}"><fmt:message key="home.${cat}.title"/></a></span>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
</c:forTokens>
|
||||
</h2>
|
||||
|
||||
<%@ include file="homePager.jsp" %>
|
||||
|
||||
<c:if test="${not empty model.welcomeMessage}">
|
||||
<div style="width:15em;float:right;padding:0 1em 0 1em;border-left:1px solid #<spring:theme code="detailColor"/>">
|
||||
<sub:wiki text="${model.welcomeMessage}"/>
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<c:forEach items="${model.albums}" var="album" varStatus="loopStatus">
|
||||
|
||||
<c:set var="albumTitle">
|
||||
<c:choose>
|
||||
<c:when test="${empty album.albumTitle}">
|
||||
<fmt:message key="common.unknown"/>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
${album.albumTitle}
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</c:set>
|
||||
|
||||
<c:set var="captionCount" value="2"/>
|
||||
|
||||
<c:if test="${not empty album.playCount}">
|
||||
<c:set var="caption3"><fmt:message key="home.playcount"><fmt:param value="${album.playCount}"/></fmt:message></c:set>
|
||||
<c:set var="captionCount" value="3"/>
|
||||
</c:if>
|
||||
<c:if test="${not empty album.lastPlayed}">
|
||||
<fmt:formatDate value="${album.lastPlayed}" dateStyle="short" var="lastPlayedDate"/>
|
||||
<c:set var="caption3"><fmt:message key="home.lastplayed"><fmt:param value="${lastPlayedDate}"/></fmt:message></c:set>
|
||||
<c:set var="captionCount" value="3"/>
|
||||
</c:if>
|
||||
<c:if test="${not empty album.created}">
|
||||
<fmt:formatDate value="${album.created}" dateStyle="short" var="creationDate"/>
|
||||
<c:set var="caption3"><fmt:message key="home.created"><fmt:param value="${creationDate}"/></fmt:message></c:set>
|
||||
<c:set var="captionCount" value="3"/>
|
||||
</c:if>
|
||||
<c:if test="${not empty album.year}">
|
||||
<c:set var="caption3" value="${album.year}"/>
|
||||
<c:set var="captionCount" value="3"/>
|
||||
</c:if>
|
||||
|
||||
<div class="albumThumb">
|
||||
<c:import url="coverArt.jsp">
|
||||
<c:param name="albumId" value="${album.id}"/>
|
||||
<c:param name="caption1" value="${fn:escapeXml(album.albumTitle)}"/>
|
||||
<c:param name="caption2" value="${fn:escapeXml(album.artist)}"/>
|
||||
<c:param name="caption3" value="${caption3}"/>
|
||||
<c:param name="captionCount" value="${captionCount}"/>
|
||||
<c:param name="coverArtSize" value="${model.coverArtSize}"/>
|
||||
<c:param name="showLink" value="true"/>
|
||||
<c:param name="appearAfter" value="${loopStatus.count * 30}"/>
|
||||
<c:param name="hideOverflow" value="true"/>
|
||||
</c:import>
|
||||
|
||||
<c:if test="${not empty album.rating}">
|
||||
<c:import url="rating.jsp">
|
||||
<c:param name="readonly" value="true"/>
|
||||
<c:param name="rating" value="${album.rating}"/>
|
||||
</c:import>
|
||||
</c:if>
|
||||
|
||||
</div>
|
||||
</c:forEach>
|
||||
|
||||
<c:if test="${model.listSize eq fn:length(model.albums)}">
|
||||
<%@ include file="homePager.jsp" %>
|
||||
</c:if>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,79 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<table>
|
||||
<tr>
|
||||
<c:if test="${not empty model.musicFolder}">
|
||||
<td style="padding-right: 2em">
|
||||
<div style="border:1px solid #<spring:theme code="detailColor"/>; padding-left: 0.5em;padding-right: 0.5em">
|
||||
${fn:escapeXml(model.musicFolder.name)}
|
||||
</div>
|
||||
</td>
|
||||
</c:if>
|
||||
<c:choose>
|
||||
<c:when test="${model.listType eq 'random'}">
|
||||
<td><div class="forward"><a href="home.view?listType=random"><fmt:message key="common.more"/></a></div></td>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<sub:url value="home.view" var="previousUrl">
|
||||
<sub:param name="listType" value="${model.listType}"/>
|
||||
<sub:param name="listOffset" value="${model.listOffset - model.listSize}"/>
|
||||
<sub:param name="genre" value="${model.genre}"/>
|
||||
<sub:param name="decade" value="${model.decade}"/>
|
||||
</sub:url>
|
||||
<sub:url value="home.view" var="nextUrl">
|
||||
<sub:param name="listType" value="${model.listType}"/>
|
||||
<sub:param name="listOffset" value="${model.listOffset + model.listSize}"/>
|
||||
<sub:param name="genre" value="${model.genre}"/>
|
||||
<sub:param name="decade" value="${model.decade}"/>
|
||||
</sub:url>
|
||||
|
||||
<c:if test="${fn:length(model.albums) gt 0}">
|
||||
<td style="padding-right:0.5em">
|
||||
<fmt:message key="home.albums">
|
||||
<fmt:param value="${model.listOffset + 1}"/>
|
||||
<fmt:param value="${model.listOffset + fn:length(model.albums)}"/>
|
||||
</fmt:message>
|
||||
</td>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.listOffset gt 0}">
|
||||
<td><a href="${previousUrl}"><img src="<spring:theme code="backImage"/>" alt=""></a></td>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${fn:length(model.albums) eq model.listSize}">
|
||||
<td><a href="${nextUrl}"><img src="<spring:theme code="forwardImage"/>" alt=""></a></td>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.listType eq 'decade'}">
|
||||
<td style="padding-left: 2em">
|
||||
<fmt:message key="home.decade.text"/>
|
||||
</td>
|
||||
<td>
|
||||
<select name="decade" onchange="location='home.view?listType=${model.listType}&decade=' + options[selectedIndex].value">
|
||||
<c:forEach items="${model.decades}" var="decade">
|
||||
<option
|
||||
${decade eq model.decade ? "selected" : ""} value="${decade}">${decade}</option>
|
||||
</c:forEach>
|
||||
</select>
|
||||
</td>
|
||||
</c:if>
|
||||
<c:if test="${model.listType eq 'genre'}">
|
||||
<td style="padding-left: 2em">
|
||||
<fmt:message key="home.genre.text"/>
|
||||
</td>
|
||||
<td>
|
||||
<select name="genre" onchange="location='home.view?listType=${model.listType}&genre=' + encodeURIComponent(options[selectedIndex].value)">
|
||||
<c:forEach items="${model.genres}" var="genre">
|
||||
<option ${genre.name eq model.genre ? "selected" : ""} value="${genre.name}">${genre.name} (${genre.albumCount})</option>
|
||||
</c:forEach>
|
||||
</select>
|
||||
</td>
|
||||
</c:if>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<c:if test="${not empty model.albums}">
|
||||
<td style="padding-left: 2em">
|
||||
<a href="javascript:playShuffle()"><img src="<spring:theme code="shuffleImage"/>" alt=""> <fmt:message key="home.shuffle"/></a></td>
|
||||
</c:if>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -0,0 +1,38 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1">
|
||||
|
||||
<h1 style="padding-bottom:0.5em">
|
||||
<fmt:message key="importPlaylist.title"/>
|
||||
</h1>
|
||||
|
||||
<c:if test="${not empty model.playlist}">
|
||||
<p>
|
||||
<fmt:message key="importPlaylist.success"><fmt:param value="${model.playlist.name}"/></fmt:message>
|
||||
<script type="text/javascript" language="javascript">
|
||||
top.left.updatePlaylists();
|
||||
top.main.location.href = "playlist.view?id=${model.playlist.id}";
|
||||
</script>
|
||||
</p>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${not empty model.error}">
|
||||
<p class="warning">
|
||||
<fmt:message key="importPlaylist.error"><fmt:param value="${model.error}"/></fmt:message>
|
||||
</p>
|
||||
</c:if>
|
||||
|
||||
<div style="padding-bottom: 0.25em">
|
||||
<fmt:message key="importPlaylist.text"/>
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data" action="importPlaylist.view?${_csrf.parameterName}=${_csrf.token}">
|
||||
<input type="file" id="file" name="file" size="40"/>
|
||||
<input type="submit" value="<fmt:message key="common.ok"/>"/>
|
||||
</form>
|
||||
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<%@ page session="false"%>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
|
||||
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
|
||||
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
|
||||
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
|
||||
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
|
||||
<%@ taglib prefix="sub" uri="http://libresonic.org/taglib/sub" %>
|
||||
<%@ taglib prefix="str" uri="http://jakarta.apache.org/taglibs/string-1.1" %>
|
||||
@@ -0,0 +1,26 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<link rel="alternate" type="application/rss+xml" title="Libresonic Podcast" href="podcast.view?suffix=.rss">
|
||||
</head>
|
||||
|
||||
<frameset rows="80,*,0" border="0" framespacing="0" frameborder="0">
|
||||
<frame name="upper" src="top.view?" class="bgcolor2">
|
||||
<frameset id="mainFrameset" cols=${model.showSideBar ? "230,*" : "0,*"} border="0" framespacing="0" frameborder="0">
|
||||
<frame name="left" src="left.view?" marginwidth="0" marginheight="0" class="bgcolor2">
|
||||
|
||||
<frameset id="playQueueFrameset" rows=${model.autoHidePlayQueue ? "*,50" : "*,150"} border="0" framespacing="0" frameborder="0">
|
||||
<frameset cols="*,${model.showRight ? 235 : 0}" border="0" framespacing="0" frameborder="0">
|
||||
<frame name="main" src="nowPlaying.view?" marginwidth="0" marginheight="0" class="bgcolor1">
|
||||
<frame name="right" src="right.view?" class="bgcolor1">
|
||||
</frameset>
|
||||
<frame name="playQueue" src="playQueue.view?" class="bgcolor2">
|
||||
</frameset>
|
||||
</frameset>
|
||||
<frame name="hidden" frameborder="0" noresize="noresize">
|
||||
|
||||
</frameset>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,67 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1">
|
||||
|
||||
<c:import url="settingsHeader.jsp">
|
||||
<c:param name="cat" value="internetRadio"/>
|
||||
<c:param name="toast" value="${settings_toast}"/>
|
||||
</c:import>
|
||||
|
||||
<form method="post" action="internetRadioSettings.view">
|
||||
<sec:csrfInput />
|
||||
<table class="indent">
|
||||
<tr>
|
||||
<th><fmt:message key="internetradiosettings.name"/></th>
|
||||
<th><fmt:message key="internetradiosettings.streamurl"/></th>
|
||||
<th><fmt:message key="internetradiosettings.homepageurl"/></th>
|
||||
<th style="padding-left:1em"><fmt:message key="internetradiosettings.enabled"/></th>
|
||||
<th style="padding-left:1em"><fmt:message key="common.delete"/></th>
|
||||
</tr>
|
||||
|
||||
<c:forEach items="${model.internetRadios}" var="radio">
|
||||
<tr>
|
||||
<td><input type="text" name="name[${radio.id}]" size="20" value="${radio.name}"/></td>
|
||||
<td><input type="text" name="streamUrl[${radio.id}]" size="40" value="${radio.streamUrl}"/></td>
|
||||
<td><input type="text" name="homepageUrl[${radio.id}]" size="40" value="${radio.homepageUrl}"/></td>
|
||||
<td align="center" style="padding-left:1em"><input type="checkbox" ${radio.enabled ? "checked" : ""} name="enabled[${radio.id}]" class="checkbox"/></td>
|
||||
<td align="center" style="padding-left:1em"><input type="checkbox" name="delete[${radio.id}]" class="checkbox"/></td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
|
||||
<c:if test="${not empty model.internetRadios}">
|
||||
<tr>
|
||||
<th colspan="5" align="left" style="padding-top:1em"><fmt:message key="internetradiosettings.add"/></th>
|
||||
</tr>
|
||||
</c:if>
|
||||
|
||||
<tr>
|
||||
<td><input type="text" name="name" size="20" placeholder="<fmt:message key="internetradiosettings.name"/>"/></td>
|
||||
<td><input type="text" name="streamUrl" size="40" placeholder="<fmt:message key="internetradiosettings.streamurl"/>"/></td>
|
||||
<td><input type="text" name="homepageUrl" size="40" placeholder="<fmt:message key="internetradiosettings.homepageurl"/>"/></td>
|
||||
<td align="center" style="padding-left:1em"><input name="enabled" checked type="checkbox" class="checkbox"/></td>
|
||||
<td/>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td style="padding-top:1.5em" colspan="5">
|
||||
<input type="submit" value="<fmt:message key="common.save"/>" style="margin-right:0.3em">
|
||||
<input type="button" value="<fmt:message key="common.cancel"/>" onclick="location.href='nowPlaying.view'">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
|
||||
<c:if test="${not empty error}">
|
||||
<p class="warning"><fmt:message key="${error}"/></p>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${settings_reload}">
|
||||
<script language="javascript" type="text/javascript">parent.frames.left.location.href="left.view?"</script>
|
||||
</c:if>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,7 @@
|
||||
<link rel="stylesheet" href="<c:url value="/style/smoothness/jquery-ui-1.8.18.custom.css"/>" type="text/css">
|
||||
<link rel="stylesheet" href="<c:url value="/script/jquery.toastmessage/css/jquery.toastmessage.css" />" type="text/css" >
|
||||
<link rel="stylesheet" href="<c:url value="/style/jquery.contextMenu.css"/>" type="text/css" >
|
||||
<script type="text/javascript" src="<c:url value='/script/jquery-1.7.1.min.js'/>"></script>
|
||||
<script type="text/javascript" src="<c:url value='/script/jquery-ui-1.11.1.min.js'/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/jquery.toastmessage/jquery.toastmessage.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/jquery.contextMenu.js"/>"></script>
|
||||
@@ -0,0 +1,202 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value="/script/scripts-2.0.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/engine.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/playlistService.js"/>"></script>
|
||||
<script type="text/javascript" language="javascript">
|
||||
|
||||
var playlists;
|
||||
|
||||
function init() {
|
||||
dwr.engine.setErrorHandler(null);
|
||||
updatePlaylists();
|
||||
|
||||
var mainLocation = top.main.location.href;
|
||||
if (${model.musicFolderChanged}) {
|
||||
if (mainLocation.indexOf("/home.view") != -1) {
|
||||
top.main.location.href = mainLocation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updatePlaylists() {
|
||||
playlistService.getReadablePlaylists(playlistCallback);
|
||||
}
|
||||
|
||||
function createEmptyPlaylist() {
|
||||
showAllPlaylists();
|
||||
playlistService.createEmptyPlaylist(playlistCallback);
|
||||
}
|
||||
|
||||
function showAllPlaylists() {
|
||||
$('#playlistOverflow').show('blind');
|
||||
$('#showAllPlaylists').hide('blind');
|
||||
}
|
||||
|
||||
function playlistCallback(playlists) {
|
||||
this.playlists = playlists;
|
||||
|
||||
$("#playlists").empty();
|
||||
$("#playlistOverflow").empty();
|
||||
for (var i = 0; i < playlists.length; i++) {
|
||||
var playlist = playlists[i];
|
||||
var overflow = i > 9;
|
||||
$("<p class='dense'><a target='main' href='playlist.view?id=" +
|
||||
playlist.id + "'>" + escapeHtml(playlist.name) + " (" + playlist.fileCount + ")</a></p>").appendTo(overflow ? "#playlistOverflow" : "#playlists");
|
||||
}
|
||||
|
||||
if (playlists.length > 10 && !$('#playlistOverflow').is(":visible")) {
|
||||
$('#showAllPlaylists').show();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body class="bgcolor2 leftframe" onload="init()">
|
||||
<a name="top"></a>
|
||||
|
||||
<div style="padding-bottom:1.5em">
|
||||
<a href="help.view?" target="main"><img src="<spring:theme code="logoImage"/>" title="<fmt:message key="top.help"/>" alt=""></a>
|
||||
</div>
|
||||
|
||||
<c:if test="${fn:length(model.musicFolders) > 1}">
|
||||
<div style="padding-bottom:1.0em">
|
||||
<select name="musicFolderId" style="width:100%" onchange="location='left.view?musicFolderId=' + options[selectedIndex].value;">
|
||||
<option value="-1"><fmt:message key="left.allfolders"/></option>
|
||||
<c:forEach items="${model.musicFolders}" var="musicFolder">
|
||||
<option ${model.selectedMusicFolder.id == musicFolder.id ? "selected" : ""} value="${musicFolder.id}">${fn:escapeXml(musicFolder.name)}</option>
|
||||
</c:forEach>
|
||||
</select>
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<div style="margin-bottom:0.5em;padding-left: 2px" class="bgcolor1">
|
||||
<c:forEach items="${model.indexes}" var="index">
|
||||
<a href="#${index.index}" accesskey="${index.index}">${index.index}</a>
|
||||
</c:forEach>
|
||||
</div>
|
||||
|
||||
<div style="padding-bottom:0.5em">
|
||||
<div class="forward">
|
||||
<c:choose>
|
||||
<c:when test="${model.scanning}">
|
||||
<a href="left.view"><fmt:message key="common.refresh"/></a>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<a href="left.view?refresh=true"><fmt:message key="common.refresh"/></a>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<c:if test="${not empty model.shortcuts}">
|
||||
<h2 class="bgcolor1" style="padding-left: 2px"><fmt:message key="left.shortcut"/></h2>
|
||||
<c:forEach items="${model.shortcuts}" var="shortcut">
|
||||
<p class="dense" style="padding-left:2px">
|
||||
<sub:url value="main.view" var="mainUrl">
|
||||
<sub:param name="id" value="${shortcut.id}"/>
|
||||
</sub:url>
|
||||
<a target="main" href="${mainUrl}">${fn:escapeXml(shortcut.name)}</a>
|
||||
</p>
|
||||
</c:forEach>
|
||||
</c:if>
|
||||
|
||||
<h2 class="bgcolor1" style="padding-left: 2px"><fmt:message key="left.playlists"/></h2>
|
||||
<div id="playlistWrapper" style='padding-left:2px'>
|
||||
<div id="playlists"></div>
|
||||
<div id="playlistOverflow" style="display:none"></div>
|
||||
<div style="padding-top: 0.3em"></div>
|
||||
<div class="forward" id="showAllPlaylists" style="display: none"><a href="javascript:noop()" onclick="showAllPlaylists()"><fmt:message key="left.showallplaylists"/></a></div>
|
||||
<div class="forward"><a href="javascript:noop()" onclick="createEmptyPlaylist()"><fmt:message key="left.createplaylist"/></a></div>
|
||||
<div class="forward"><a href="importPlaylist.view" target="main"><fmt:message key="left.importplaylist"/></a></div>
|
||||
</div>
|
||||
|
||||
<c:if test="${not empty model.radios}">
|
||||
<h2 class="bgcolor1" style="padding-left: 2px"><fmt:message key="left.radio"/></h2>
|
||||
<c:forEach items="${model.radios}" var="radio">
|
||||
<p class="dense" style="padding-left: 2px">
|
||||
<a target="hidden" href="${radio.streamUrl}">
|
||||
<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>
|
||||
<c:when test="${empty radio.homepageUrl}">
|
||||
${fn:escapeXml(radio.name)}
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<a target="main" href="${radio.homepageUrl}">${fn:escapeXml(radio.name)}</a>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</span>
|
||||
</p>
|
||||
</c:forEach>
|
||||
</c:if>
|
||||
|
||||
<c:forEach items="${model.indexedArtists}" var="entry">
|
||||
<table class="bgcolor1" style="width:100%;padding:0;margin:1em 0 0 0;border:0">
|
||||
<tr style="padding:0;margin:0;border:0">
|
||||
<th style="text-align:left;padding:0;margin:0;border:0"><a name="${fn:escapeXml(entry.key.index)}"></a>
|
||||
<h2 style="padding:0;margin:0;border:0">${fn:escapeXml(entry.key.index)}</h2>
|
||||
</th>
|
||||
<th style="text-align:right;">
|
||||
<a href="#top"><img src="<spring:theme code="upImage"/>" alt=""></a>
|
||||
</th>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<c:forEach items="${entry.value}" var="artist">
|
||||
<p class="dense" style="padding-left:2px">
|
||||
<span title="${artist.name}">
|
||||
<sub:url value="main.view" var="mainUrl">
|
||||
<c:forEach items="${artist.mediaFiles}" var="mediaFile">
|
||||
<sub:param name="id" value="${mediaFile.id}"/>
|
||||
</c:forEach>
|
||||
</sub:url>
|
||||
<a target="main" href="${mainUrl}"><str:truncateNicely upper="${35}">${fn:escapeXml(artist.name)}</str:truncateNicely></a>
|
||||
</span>
|
||||
</p>
|
||||
</c:forEach>
|
||||
</c:forEach>
|
||||
|
||||
<div style="padding-top:1em"></div>
|
||||
|
||||
<c:forEach items="${model.singleSongs}" var="song">
|
||||
<p class="dense" style="padding-left:2px">
|
||||
<span class="songTitle" title="${fn:escapeXml(song.title)}">
|
||||
<c:import url="playButtons.jsp">
|
||||
<c:param name="id" value="${song.id}"/>
|
||||
<c:param name="playEnabled" value="${model.user.streamRole and not model.partyMode}"/>
|
||||
<c:param name="addEnabled" value="${model.user.streamRole}"/>
|
||||
<c:param name="downloadEnabled" value="${model.user.downloadRole and not model.partyMode}"/>
|
||||
<c:param name="video" value="${song.video and model.player.web}"/>
|
||||
</c:import>
|
||||
<str:truncateNicely upper="${35}">${fn:escapeXml(song.title)}</str:truncateNicely>
|
||||
</span>
|
||||
</p>
|
||||
</c:forEach>
|
||||
|
||||
<c:if test="${model.statistics.songCount gt 0}">
|
||||
<div class="detail" style="padding-top: 0.6em; padding-left: 2px">
|
||||
<fmt:message key="left.statistics">
|
||||
<fmt:param value="${model.statistics.artistCount}"/>
|
||||
<fmt:param value="${model.statistics.albumCount}"/>
|
||||
<fmt:param value="${model.statistics.songCount}"/>
|
||||
<fmt:param value="${model.bytes}"/>
|
||||
<fmt:param value="${model.hours}"/>
|
||||
</fmt:message>
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<div style="height:5em"></div>
|
||||
|
||||
|
||||
<div class="bgcolor2" style="opacity: 1.0; clear: both; position: fixed; bottom: 0; right: 0; left: 0;
|
||||
padding: 0.25em 0.75em 0.25em 0.75em; border-top:1px solid black; max-width: 850px;">
|
||||
<c:forEach items="${model.indexes}" var="index">
|
||||
<a href="#${index.index}">${index.index}</a>
|
||||
</c:forEach>
|
||||
</div>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,61 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<script type="text/javascript">
|
||||
if (window != window.top) {
|
||||
top.location.href = location.href;
|
||||
}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body style="min-width:550px" class="mainframe bgcolor1" onload="document.getElementById('j_username').focus()">
|
||||
|
||||
<form action="<c:url value="/login"/>" method="POST">
|
||||
<sec:csrfInput />
|
||||
|
||||
<div id="loginframe" class="bgcolor2 shadow">
|
||||
|
||||
<img src="<spring:theme code="logoImage"/>" alt="">
|
||||
|
||||
<div class="loginmessagetop"><sub:wiki text="${model.loginMessage}"/></div>
|
||||
|
||||
<input type="text" id="j_username" name="j_username" tabindex="1" placeholder="<fmt:message key="login.username"/>">
|
||||
|
||||
<input type="password" name="j_password" tabindex="2" placeholder="<fmt:message key="login.password"/>">
|
||||
|
||||
<input name="submit" type="submit" value="<fmt:message key="login.login"/>" tabindex="4"></td>
|
||||
|
||||
<div class="details">
|
||||
<div id="loginremember">
|
||||
<label for="remember"><fmt:message key="login.remember"/></label>
|
||||
<input type="checkbox" name="remember-me" id="remember" class="checkbox" tabindex="3">
|
||||
</div>
|
||||
|
||||
<a href="recover.view"><fmt:message key="login.recover"/></a>
|
||||
</div>
|
||||
|
||||
<c:if test="${model.logout}">
|
||||
<div class="loginmessagebottom">
|
||||
<b><fmt:message key="login.logout"/></b>
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.error}">
|
||||
<div class="loginmessagebottom">
|
||||
<span class="warning"><fmt:message key="login.error"/></span>
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.insecure}">
|
||||
<div class="loginmessagebottom">
|
||||
<p class="warning"><fmt:message key="login.insecure"><fmt:param value="${model.brand}"/></fmt:message></p>
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,88 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<title><fmt:message key="lyrics.title"/></title>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/lyricsService.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/engine.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/util.js"/>"></script>
|
||||
|
||||
<script type="text/javascript" language="javascript">
|
||||
|
||||
dwr.engine.setErrorHandler(null);
|
||||
|
||||
function init() {
|
||||
getLyrics('${model.artist}', '${model.song}');
|
||||
}
|
||||
|
||||
function getLyrics(artist, song) {
|
||||
$("wait").style.display = "inline";
|
||||
$("lyrics").style.display = "none";
|
||||
$("noLyricsFound").style.display = "none";
|
||||
$("tryLater").style.display = "none";
|
||||
lyricsService.getLyrics(artist, song, getLyricsCallback);
|
||||
}
|
||||
|
||||
function getLyricsCallback(lyricsInfo) {
|
||||
dwr.util.setValue("lyricsHeader", lyricsInfo.artist + " - " + lyricsInfo.title);
|
||||
var lyrics;
|
||||
if (lyricsInfo.lyrics != null) {
|
||||
lyrics = lyricsInfo.lyrics.replace(/\n/g, "<br>");
|
||||
}
|
||||
dwr.util.setValue("lyricsText", lyrics, { escapeHtml:false });
|
||||
$("wait").style.display = "none";
|
||||
if (lyricsInfo.tryLater) {
|
||||
$("tryLater").style.display = "inline";
|
||||
} else if (lyrics != null) {
|
||||
$("lyrics").style.display = "inline";
|
||||
} else {
|
||||
$("noLyricsFound").style.display = "inline";
|
||||
}
|
||||
}
|
||||
|
||||
function search() {
|
||||
getLyrics(dwr.util.getValue('artist'), dwr.util.getValue('song'));
|
||||
}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body class="mainframe bgcolor1" onload="init();">
|
||||
|
||||
<form action="#" onsubmit="search();return false;">
|
||||
<table>
|
||||
<tr>
|
||||
<td><fmt:message key="lyrics.artist"/></td>
|
||||
<td style="padding-left:0.50em"><input id="artist" type="text" size="40" value="${model.artist}" tabindex="1"/></td>
|
||||
<td style="padding-left:0.75em"><input type="submit" value="<fmt:message key="lyrics.search"/>" style="width:6em"
|
||||
tabindex="3"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="lyrics.song"/></td>
|
||||
<td style="padding-left:0.50em"><input id="song" type="text" size="40" value="${model.song}" tabindex="2"/></td>
|
||||
<td style="padding-left:0.75em"><input type="button" value="<fmt:message key="common.close"/>" style="width:6em"
|
||||
onclick="self.close()" tabindex="4"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<hr/>
|
||||
<h2 id="wait"><fmt:message key="lyrics.wait"/></h2>
|
||||
<h2 id="noLyricsFound" style="display:none"><fmt:message key="lyrics.nolyricsfound"/></h2>
|
||||
<p id="tryLater" style="display:none"><b><fmt:message key="lyrics.trylater"/></b></p>
|
||||
|
||||
<div id="lyrics" style="display:none;">
|
||||
<h2 id="lyricsHeader" style="text-align:center;margin-bottom:1em"></h2>
|
||||
|
||||
<div id="lyricsText"></div>
|
||||
|
||||
<p class="detail" style="text-align:right">
|
||||
<fmt:message key="lyrics.courtesy"/>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
<p style="text-align:center">
|
||||
<a href="javascript:self.close()">[<fmt:message key="common.close"/>]</a>
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,371 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
|
||||
<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>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/util.js"/>"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
function refreshProgress() {
|
||||
transferService.getUploadInfo(updateProgress);
|
||||
}
|
||||
|
||||
function updateProgress(uploadInfo) {
|
||||
|
||||
var progressBar = document.getElementById("progressBar");
|
||||
var progressBarContent = document.getElementById("progressBarContent");
|
||||
var progressText = document.getElementById("progressText");
|
||||
|
||||
|
||||
if (uploadInfo.bytesTotal > 0) {
|
||||
var percent = Math.ceil((uploadInfo.bytesUploaded / uploadInfo.bytesTotal) * 100);
|
||||
var width = parseInt(percent * 3.5) + 'px';
|
||||
progressBarContent.style.width = width;
|
||||
progressText.innerHTML = percent + "<fmt:message key="more.upload.progress"/>";
|
||||
progressBar.style.display = "block";
|
||||
progressText.style.display = "block";
|
||||
window.setTimeout("refreshProgress()", 1000);
|
||||
} else {
|
||||
progressBar.style.display = "none";
|
||||
progressText.style.display = "none";
|
||||
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 == "hidden") continue;
|
||||
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++) {
|
||||
var element = elements[i];
|
||||
var value = data[element.name];
|
||||
if (value) {
|
||||
for (var j = 0; j < element.options.length; j++) {
|
||||
if (element.options[j].value == value) {
|
||||
element.value = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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++) {
|
||||
if (elements[i].type == "hidden") continue;
|
||||
if (elements[i].type == "submit") continue;
|
||||
data[elements[i].name] = elements[i].value;
|
||||
}
|
||||
elements = form.getElementsByTagName("select");
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
if (elements[i].type == "hidden") continue;
|
||||
if (elements[i].type == "submit") continue;
|
||||
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">
|
||||
.more-shortcut {
|
||||
padding: 0 15px;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body class="mainframe bgcolor1">
|
||||
|
||||
<h1>
|
||||
<img src="<spring:theme code="moreImage"/>" alt=""/>
|
||||
<span style="vertical-align: middle"><fmt:message key="more.title"/></span>
|
||||
</h1>
|
||||
|
||||
<c:if test="${model.user.streamRole}">
|
||||
<h2>
|
||||
<img src="<spring:theme code="shuffleImage"/>" alt=""/>
|
||||
<span style="vertical-align: middle"><fmt:message key="more.random.title"/></span>
|
||||
</h2>
|
||||
|
||||
<form id="randomPlayQueue" method="post" action="randomPlayQueue.view?">
|
||||
<sec:csrfInput />
|
||||
<table>
|
||||
<tr>
|
||||
<td><fmt:message key="more.random.text"/></td>
|
||||
<td>
|
||||
<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>
|
||||
<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 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">
|
||||
<c:set var="year" value="${model.currentYear - yearOffset}"/>
|
||||
<option value="${year} ${year}">${year}</option>
|
||||
</c:forEach>
|
||||
|
||||
<option value="2010 2015">2010 – 2015</option>
|
||||
<option value="2005 2010">2005 – 2010</option>
|
||||
<option value="2000 2005">2000 – 2005</option>
|
||||
<option value="1990 2000">1990 – 2000</option>
|
||||
<option value="1980 1990">1980 – 1990</option>
|
||||
<option value="1970 1980">1970 – 1980</option>
|
||||
<option value="1960 1970">1960 – 1970</option>
|
||||
<option value="1950 1960">1950 – 1960</option>
|
||||
<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="" 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 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>
|
||||
<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>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<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>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</c:if>
|
||||
|
||||
<a href="http://libresonic.org/pages/apps.jsp" target="_blank"><img alt="Apps" src="<c:url value="/icons/default_light/apps.png"/>" style="float: right;margin-left: 3em; margin-right: 3em"/></a>
|
||||
|
||||
<h2>
|
||||
<img src="<spring:theme code="androidImage"/>" alt=""/>
|
||||
<span style="vertical-align: middle"><fmt:message key="more.apps.title"/></span>
|
||||
</h2>
|
||||
<fmt:message key="more.apps.text"/>
|
||||
|
||||
|
||||
<h2>
|
||||
<img src="<spring:theme code="statusSmallImage"/>" alt=""/>
|
||||
<span style="vertical-align: middle"><fmt:message key="more.status.title"/></span>
|
||||
</h2>
|
||||
<fmt:message key="more.status.text"/>
|
||||
|
||||
<h2>
|
||||
<img src="<spring:theme code="podcastImage"/>" alt=""/>
|
||||
<span style="vertical-align: middle"><fmt:message key="more.podcast.title"/></span>
|
||||
</h2>
|
||||
<fmt:message key="more.podcast.text"/>
|
||||
|
||||
<c:if test="${model.user.uploadRole}">
|
||||
|
||||
<h2>
|
||||
<img src="<spring:theme code="uploadImage"/>" alt=""/>
|
||||
<span style="vertical-align: middle"><fmt:message key="more.upload.title"/></span>
|
||||
</h2>
|
||||
|
||||
<form method="post" enctype="multipart/form-data" action="upload.view?${_csrf.parameterName}=${_csrf.token}">
|
||||
<table>
|
||||
<tr>
|
||||
<td><fmt:message key="more.upload.source"/></td>
|
||||
<td colspan="2"><input type="file" id="file" name="file" size="40"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="more.upload.target"/></td>
|
||||
<td><input type="text" id="dir" name="dir" size="37" value="${model.uploadDirectory}"/></td>
|
||||
<td><input type="submit" value="<fmt:message key="more.upload.ok"/>"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<input type="checkbox" checked name="unzip" id="unzip" class="checkbox"/>
|
||||
<label for="unzip"><fmt:message key="more.upload.unzip"/></label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
|
||||
<p class="detail" id="progressText"/>
|
||||
|
||||
<div id="progressBar">
|
||||
<div id="progressBarContent"></div>
|
||||
</div>
|
||||
|
||||
</c:if>
|
||||
|
||||
<a name="shortcuts"></a>
|
||||
<h2>
|
||||
<img src="<spring:theme code="keyboardImage"/>" alt=""/>
|
||||
<span style="vertical-align: middle"><fmt:message key="more.keyboard.title"/></span>
|
||||
</h2>
|
||||
<fmt:message key="more.keyboard.text"/>
|
||||
<table class="indent music" style="width:inherit">
|
||||
<tr>
|
||||
<th colspan="2"><fmt:message key="more.keyboard.playback"/></th>
|
||||
<th colspan="2"><fmt:message key="more.keyboard.navigation"/></th>
|
||||
<th colspan="2"><fmt:message key="more.keyboard.general"/></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="more-shortcut">Space</td><td class="more-shortcut-descr"><fmt:message key="more.keyboard.playpause"/></td>
|
||||
<td class="more-shortcut">g <fmt:message key="more.keyboard.then"/> h</td><td class="more-shortcut-descr"><fmt:message key="more.keyboard.home"/></td>
|
||||
<td class="more-shortcut">/</td><td class="more-shortcut-descr"><fmt:message key="more.keyboard.search"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="more-shortcut">←</td><td class="more-shortcut-descr"><fmt:message key="more.keyboard.previous"/></td>
|
||||
<td class="more-shortcut">g <fmt:message key="more.keyboard.then"/> p</td><td class="more-shortcut-descr"><fmt:message key="more.keyboard.playlists"/></td>
|
||||
<td class="more-shortcut">m</td><td class="more-shortcut-descr"><fmt:message key="more.keyboard.sidebar"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="more-shortcut">→</td><td class="more-shortcut-descr"><fmt:message key="more.keyboard.next"/></td>
|
||||
<td class="more-shortcut">g <fmt:message key="more.keyboard.then"/> o</td><td class="more-shortcut-descr"><fmt:message key="more.keyboard.podcasts"/></td>
|
||||
<td class="more-shortcut">q</td><td class="more-shortcut-descr"><fmt:message key="more.keyboard.playqueue"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="more-shortcut">–</td><td class="more-shortcut-descr"><fmt:message key="more.keyboard.volumedown"/></td>
|
||||
<td class="more-shortcut">g <fmt:message key="more.keyboard.then"/> s</td><td class="more-shortcut-descr"><fmt:message key="more.keyboard.settings"/></td>
|
||||
<td class="more-shortcut">?</td><td class="more-shortcut-descr"><fmt:message key="more.keyboard.shortcuts"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="more-shortcut">+</td><td class="more-shortcut-descr"><fmt:message key="more.keyboard.volumeup"/></td>
|
||||
<td class="more-shortcut">g <fmt:message key="more.keyboard.then"/> t</td><td class="more-shortcut-descr"><fmt:message key="more.keyboard.starred"/></td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td><td></td>
|
||||
<td class="more-shortcut">g <fmt:message key="more.keyboard.then"/> r</td><td class="more-shortcut-descr"><fmt:message key="more.keyboard.more"/></td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td><td></td>
|
||||
<td class="more-shortcut">g <fmt:message key="more.keyboard.then"/> a</td><td class="more-shortcut-descr"><fmt:message key="more.keyboard.about"/></td>
|
||||
<td></td><td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,136 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
<%--@elvariable id="command" type="org.libresonic.player.command.MusicFolderSettingsCommand"--%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
|
||||
<script type="text/javascript">
|
||||
function init() {
|
||||
$("#newMusicFolderName").attr("placeholder", "<fmt:message key="musicfoldersettings.name"/>");
|
||||
$("#newMusicFolderPath").attr("placeholder", "<fmt:message key="musicfoldersettings.path"/>");
|
||||
|
||||
<c:if test="${settings_reload}">
|
||||
parent.frames.upper.location.href="top.view?";
|
||||
parent.frames.left.location.href="left.view?";
|
||||
parent.frames.right.location.href="right.view?";
|
||||
</c:if>
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1" onload="init()">
|
||||
<script type="text/javascript" src="<c:url value="/script/wz_tooltip.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/tip_balloon.js"/>"></script>
|
||||
|
||||
|
||||
<c:import url="settingsHeader.jsp">
|
||||
<c:param name="cat" value="musicFolder"/>
|
||||
<c:param name="toast" value="${settings_toast}"/>
|
||||
</c:import>
|
||||
|
||||
<form:form commandName="command" action="musicFolderSettings.view" method="post">
|
||||
|
||||
<table class="indent">
|
||||
<tr>
|
||||
<th><fmt:message key="musicfoldersettings.name"/></th>
|
||||
<th><fmt:message key="musicfoldersettings.path"/></th>
|
||||
<th style="padding-left:1em"><fmt:message key="musicfoldersettings.enabled"/></th>
|
||||
<th style="padding-left:1em"><fmt:message key="common.delete"/></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
|
||||
<c:forEach items="${command.musicFolders}" var="folder" varStatus="loopStatus">
|
||||
<tr>
|
||||
<td><form:input path="musicFolders[${loopStatus.count-1}].name" size="20"/></td>
|
||||
<td><form:input path="musicFolders[${loopStatus.count-1}].path" size="40"/></td>
|
||||
<td align="center" style="padding-left:1em"><form:checkbox path="musicFolders[${loopStatus.count-1}].enabled" cssClass="checkbox"/></td>
|
||||
<td align="center" style="padding-left:1em"><form:checkbox path="musicFolders[${loopStatus.count-1}].delete" cssClass="checkbox"/></td>
|
||||
<td><c:if test="${not folder.existing}"><span class="warning"><fmt:message key="musicfoldersettings.notfound"/></span></c:if></td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
|
||||
<c:if test="${not empty command.musicFolders}">
|
||||
<tr>
|
||||
<th colspan="4" align="left" style="padding-top:1em"><fmt:message key="musicfoldersettings.add"/></th>
|
||||
</tr>
|
||||
</c:if>
|
||||
|
||||
<tr>
|
||||
<td><form:input id="newMusicFolderName" path="newMusicFolder.name" size="20"/></td>
|
||||
<td><form:input id="newMusicFolderPath" path="newMusicFolder.path" size="40"/></td>
|
||||
<td align="center" style="padding-left:1em"><form:checkbox path="newMusicFolder.enabled" cssClass="checkbox"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<p class="forward"><a href="userSettings.view"><fmt:message key="musicfoldersettings.access"/></a></p>
|
||||
<p class="detail" style="width:60%;white-space:normal;margin-top:-10px;">
|
||||
<fmt:message key="musicfoldersettings.access.description"/>
|
||||
</p>
|
||||
|
||||
<div style="padding-top: 0.5em;padding-bottom: 0.3em">
|
||||
<span style="white-space: nowrap">
|
||||
<fmt:message key="musicfoldersettings.scan"/>
|
||||
<form:select path="interval">
|
||||
<fmt:message key="musicfoldersettings.interval.never" var="never"/>
|
||||
<fmt:message key="musicfoldersettings.interval.one" var="one"/>
|
||||
<form:option value="-1" label="${never}"/>
|
||||
<form:option value="1" label="${one}"/>
|
||||
|
||||
<c:forTokens items="2 3 7 14 30 60" delims=" " var="interval">
|
||||
<fmt:message key="musicfoldersettings.interval.many" var="many"><fmt:param value="${interval}"/></fmt:message>
|
||||
<form:option value="${interval}" label="${many}"/>
|
||||
</c:forTokens>
|
||||
</form:select>
|
||||
<form:select path="hour">
|
||||
<c:forEach begin="0" end="23" var="hour">
|
||||
<fmt:message key="musicfoldersettings.hour" var="hourLabel"><fmt:param value="${hour}"/></fmt:message>
|
||||
<form:option value="${hour}" label="${hourLabel}"/>
|
||||
</c:forEach>
|
||||
</form:select>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><div class="forward"><a href="musicFolderSettings.view?scanNow"><fmt:message key="musicfoldersettings.scannow"/></a></div></td>
|
||||
<td><c:import url="helpToolTip.jsp"><c:param name="topic" value="scanMediaFolders"/></c:import></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<c:if test="${command.scanning}">
|
||||
<p style="width:60%"><b><fmt:message key="musicfoldersettings.nowscanning"/></b></p>
|
||||
</c:if>
|
||||
|
||||
<div>
|
||||
<form:checkbox path="fastCache" cssClass="checkbox" id="fastCache"/>
|
||||
<form:label path="fastCache"><fmt:message key="musicfoldersettings.fastcache"/></form:label>
|
||||
</div>
|
||||
|
||||
<p class="detail" style="width:60%;white-space:normal;">
|
||||
<fmt:message key="musicfoldersettings.fastcache.description"/>
|
||||
</p>
|
||||
|
||||
<p class="forward"><a href="musicFolderSettings.view?expunge"><fmt:message key="musicfoldersettings.expunge"/></a></p>
|
||||
<p class="detail" style="width:60%;white-space:normal;margin-top:-10px;">
|
||||
<fmt:message key="musicfoldersettings.expunge.description"/>
|
||||
</p>
|
||||
|
||||
<%--<div>--%>
|
||||
<%--<form:checkbox path="organizeByFolderStructure" cssClass="checkbox" id="organizeByFolderStructure"/>--%>
|
||||
<%--<form:label path="organizeByFolderStructure"><fmt:message key="musicfoldersettings.organizebyfolderstructure"/></form:label>--%>
|
||||
<%--</div>--%>
|
||||
|
||||
<%--<p class="detail" style="width:60%;white-space:normal;">--%>
|
||||
<%--<fmt:message key="musicfoldersettings.organizebyfolderstructure.description"/>--%>
|
||||
<%--</p>--%>
|
||||
|
||||
<p >
|
||||
<input type="submit" value="<fmt:message key="common.save"/>" style="margin-right:0.3em">
|
||||
<input type="button" value="<fmt:message key="common.cancel"/>" onclick="location.href='nowPlaying.view'">
|
||||
</p>
|
||||
|
||||
</form:form>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,21 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<%@ include file="head.jsp" %>
|
||||
</head>
|
||||
|
||||
<body class="mainframe bgcolor1">
|
||||
|
||||
<h1>
|
||||
<img src="<spring:theme code="errorImage"/>" alt=""/>
|
||||
<span style="vertical-align: middle"><fmt:message key="notFound.title"/></span>
|
||||
</h1>
|
||||
|
||||
<fmt:message key="notFound.text"/>
|
||||
|
||||
<div class="forward" style="float:left;padding-right:10pt"><a href="javascript:top.location.reload(true)"><fmt:message key="notFound.reload"/></a></div>
|
||||
<div class="forward" style="float:left"><a href="musicFolderSettings.view"><fmt:message key="notFound.scan"/></a></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,50 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<%--@elvariable id="command" type="org.libresonic.player.command.passwordsettingscommand"--%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1">
|
||||
|
||||
<c:import url="settingsHeader.jsp">
|
||||
<c:param name="cat" value="password"/>
|
||||
<c:param name="toast" value="${settings_toast}"/>
|
||||
<c:param name="restricted" value="true"/>
|
||||
</c:import>
|
||||
|
||||
<c:choose>
|
||||
|
||||
<c:when test="${command.ldapAuthenticated}">
|
||||
<p><fmt:message key="usersettings.passwordnotsupportedforldap"/></p>
|
||||
</c:when>
|
||||
|
||||
<c:otherwise>
|
||||
<fmt:message key="passwordsettings.title" var="title"><fmt:param>${command.username}</fmt:param></fmt:message>
|
||||
<h2>${fn:escapeXml(title)}</h2>
|
||||
<form:form method="post" action="passwordSettings.view" commandName="command">
|
||||
<form:hidden path="username"/>
|
||||
<table class="indent">
|
||||
<tr>
|
||||
<td><fmt:message key="usersettings.newpassword"/></td>
|
||||
<td><form:password path="password"/></td>
|
||||
<td class="warning"><form:errors path="password"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="usersettings.confirmpassword"/></td>
|
||||
<td><form:password path="confirmPassword"/></td>
|
||||
<td/>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3" style="padding-top:1.5em">
|
||||
<input type="submit" value="<fmt:message key="common.save"/>" style="margin-right:0.3em">
|
||||
<input type="button" value="<fmt:message key="common.cancel"/>" onclick="location.href='nowPlaying.view'">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</form:form>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,265 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
<%--@elvariable id="command" type="org.libresonic.player.command.PersonalSettingsCommand"--%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value="/script/scripts-2.0.js"/>"></script>
|
||||
|
||||
<script type="text/javascript" language="javascript">
|
||||
function enableLastFmFields() {
|
||||
$("#lastFm").is(":checked") ? $("#lastFmTable").show() : $("#lastFmTable").hide();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body class="mainframe bgcolor1" onload="enableLastFmFields()">
|
||||
<script type="text/javascript" src="<c:url value="/script/wz_tooltip.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/tip_balloon.js"/>"></script>
|
||||
|
||||
<c:import url="settingsHeader.jsp">
|
||||
<c:param name="cat" value="personal"/>
|
||||
<c:param name="restricted" value="${not command.user.adminRole}"/>
|
||||
<c:param name="toast" value="${settings_toast}"/>
|
||||
</c:import>
|
||||
|
||||
<fmt:message key="personalsettings.title" var="title"><fmt:param>${command.user.username}</fmt:param></fmt:message>
|
||||
<h2>${fn:escapeXml(title)}</h2>
|
||||
|
||||
<fmt:message key="common.default" var="defaultTitle"/>
|
||||
<form:form method="post" action="personalSettings.view" commandName="command">
|
||||
|
||||
<table style="white-space:nowrap" class="indent">
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="personalsettings.language"/></td>
|
||||
<td>
|
||||
<form:select path="localeIndex" cssStyle="width:15em">
|
||||
<form:option value="-1" label="${defaultTitle}"/>
|
||||
<c:forEach items="${command.locales}" var="locale" varStatus="loopStatus">
|
||||
<form:option value="${loopStatus.count - 1}" label="${locale}"/>
|
||||
</c:forEach>
|
||||
</form:select>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="language"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="personalsettings.theme"/></td>
|
||||
<td>
|
||||
<form:select path="themeIndex" cssStyle="width:15em">
|
||||
<form:option value="-1" label="${defaultTitle}"/>
|
||||
<c:forEach items="${command.themes}" var="theme" varStatus="loopStatus">
|
||||
<form:option value="${loopStatus.count - 1}" label="${theme.name}"/>
|
||||
</c:forEach>
|
||||
</form:select>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="theme"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="personalsettings.albumlist"/></td>
|
||||
<td>
|
||||
<form:select path="albumListId" cssStyle="width:15em">
|
||||
<c:forEach items="${command.albumLists}" var="albumList" varStatus="loopStatus">
|
||||
<c:set var="label">
|
||||
<fmt:message key="home.${albumList.id}.title"/>
|
||||
</c:set>
|
||||
<form:option value="${albumList.id}" label="${label}"/>
|
||||
</c:forEach>
|
||||
</form:select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table class="indent">
|
||||
<tr>
|
||||
<th style="padding:0 0.5em 0.5em 0;text-align:left;"><fmt:message key="personalsettings.display"/></th>
|
||||
<th style="padding:0 0.5em 0.5em 0.5em;text-align:center;"><fmt:message key="personalsettings.browse"/></th>
|
||||
<th style="padding:0 0 0.5em 0.5em;text-align:center;"><fmt:message key="personalsettings.playlist"/></th>
|
||||
<th style="padding:0 0 0.5em 0.5em">
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="visibility"/></c:import>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="personalsettings.tracknumber"/></td>
|
||||
<td style="text-align:center"><form:checkbox path="mainVisibility.trackNumberVisible" cssClass="checkbox"/></td>
|
||||
<td style="text-align:center"><form:checkbox path="playlistVisibility.trackNumberVisible" cssClass="checkbox"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="personalsettings.artist"/></td>
|
||||
<td style="text-align:center"><form:checkbox path="mainVisibility.artistVisible" cssClass="checkbox"/></td>
|
||||
<td style="text-align:center"><form:checkbox path="playlistVisibility.artistVisible" cssClass="checkbox"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="personalsettings.album"/></td>
|
||||
<td style="text-align:center"><form:checkbox path="mainVisibility.albumVisible" cssClass="checkbox"/></td>
|
||||
<td style="text-align:center"><form:checkbox path="playlistVisibility.albumVisible" cssClass="checkbox"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="personalsettings.genre"/></td>
|
||||
<td style="text-align:center"><form:checkbox path="mainVisibility.genreVisible" cssClass="checkbox"/></td>
|
||||
<td style="text-align:center"><form:checkbox path="playlistVisibility.genreVisible" cssClass="checkbox"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="personalsettings.year"/></td>
|
||||
<td style="text-align:center"><form:checkbox path="mainVisibility.yearVisible" cssClass="checkbox"/></td>
|
||||
<td style="text-align:center"><form:checkbox path="playlistVisibility.yearVisible" cssClass="checkbox"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="personalsettings.bitrate"/></td>
|
||||
<td style="text-align:center"><form:checkbox path="mainVisibility.bitRateVisible" cssClass="checkbox"/></td>
|
||||
<td style="text-align:center"><form:checkbox path="playlistVisibility.bitRateVisible" cssClass="checkbox"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="personalsettings.duration"/></td>
|
||||
<td style="text-align:center"><form:checkbox path="mainVisibility.durationVisible" cssClass="checkbox"/></td>
|
||||
<td style="text-align:center"><form:checkbox path="playlistVisibility.durationVisible" cssClass="checkbox"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="personalsettings.format"/></td>
|
||||
<td style="text-align:center"><form:checkbox path="mainVisibility.formatVisible" cssClass="checkbox"/></td>
|
||||
<td style="text-align:center"><form:checkbox path="playlistVisibility.formatVisible" cssClass="checkbox"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="personalsettings.filesize"/></td>
|
||||
<td style="text-align:center"><form:checkbox path="mainVisibility.fileSizeVisible" cssClass="checkbox"/></td>
|
||||
<td style="text-align:center"><form:checkbox path="playlistVisibility.fileSizeVisible" cssClass="checkbox"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table class="indent">
|
||||
<tr>
|
||||
<td><form:checkbox path="showNowPlayingEnabled" id="nowPlaying" cssClass="checkbox"/></td>
|
||||
<td><label for="nowPlaying"><fmt:message key="personalsettings.shownowplaying"/></label></td>
|
||||
<td style="padding-left:2em"><form:checkbox path="showArtistInfoEnabled" id="artistInfo" cssClass="checkbox"/></td>
|
||||
<td><label for="artistInfo"><fmt:message key="personalsettings.showartistinfo"/></label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><form:checkbox path="nowPlayingAllowed" id="nowPlayingAllowed" cssClass="checkbox"/></td>
|
||||
<td><label for="nowPlayingAllowed"><fmt:message key="personalsettings.nowplayingallowed"/></label></td>
|
||||
<td style="padding-left:2em"><form:checkbox path="autoHidePlayQueue" id="autoHidePlayQueue" cssClass="checkbox"/></td>
|
||||
<td><label for="autoHidePlayQueue"><fmt:message key="personalsettings.autohideplayqueue"/></label></td>
|
||||
<td style="padding-left:2em"><form:checkbox path="partyModeEnabled" id="partyModeEnabled" cssClass="checkbox"/></td>
|
||||
<td><label for="partyModeEnabled"><fmt:message key="personalsettings.partymode"/></label>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="partymode"/></c:import>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><form:checkbox path="queueFollowingSongs" id="queueFollowingSongs" cssClass="checkbox"/></td>
|
||||
<td><label for="queueFollowingSongs"><fmt:message key="personalsettings.queuefollowingsongs"/></label></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table class="indent">
|
||||
<tr>
|
||||
<td><form:checkbox path="finalVersionNotificationEnabled" id="final" cssClass="checkbox"/></td>
|
||||
<td><label for="final"><fmt:message key="personalsettings.finalversionnotification"/></label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><form:checkbox path="betaVersionNotificationEnabled" id="beta" cssClass="checkbox"/></td>
|
||||
<td><label for="beta"><fmt:message key="personalsettings.betaversionnotification"/></label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><form:checkbox path="songNotificationEnabled" id="song" cssClass="checkbox"/></td>
|
||||
<td><label for="song"><fmt:message key="personalsettings.songnotification"/></label></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table class="indent">
|
||||
<tr>
|
||||
<td><form:checkbox path="lastFmEnabled" id="lastFm" cssClass="checkbox" onclick="enableLastFmFields()"/></td>
|
||||
<td><label for="lastFm"><fmt:message key="personalsettings.lastfmenabled"/></label></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table class="indent">
|
||||
<tr>
|
||||
<td><form:checkbox path="keyboardShortcutsEnabled" id="keyboardShortcutsEnabled" cssClass="checkbox"/></td>
|
||||
<td><label for="keyboardShortcutsEnabled"><fmt:message key="personalsettings.keyboardshortcutsenabled"/></label></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table class="indent">
|
||||
<tr>
|
||||
<td><fmt:message key="personalsettings.listreloaddelay"/></td>
|
||||
<td><form:input path="listReloadDelay" size="24"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="personalsettings.paginationsize"/></td>
|
||||
<td><form:input path="paginationSize" size="24"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table id="lastFmTable" style="padding-left:2em">
|
||||
<tr>
|
||||
<td><fmt:message key="personalsettings.lastfmusername"/></td>
|
||||
<td><form:input path="lastFmUsername" size="24"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="personalsettings.lastfmpassword"/></td>
|
||||
<td><form:password path="lastFmPassword" size="24"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p style="padding-top:1em;padding-bottom:1em">
|
||||
<input type="submit" value="<fmt:message key="common.save"/>" style="margin-right:0.3em"/>
|
||||
<input type="button" value="<fmt:message key="common.cancel"/>" onclick="location.href='nowPlaying.view'">
|
||||
</p>
|
||||
|
||||
<h2><fmt:message key="personalsettings.avatar.title"/></h2>
|
||||
|
||||
<p style="padding-top:1em">
|
||||
<c:forEach items="${command.avatars}" var="avatar">
|
||||
<c:url value="avatar.view" var="avatarUrl">
|
||||
<c:param name="id" value="${avatar.id}"/>
|
||||
</c:url>
|
||||
<span style="white-space:nowrap;">
|
||||
<form:radiobutton id="avatar-${avatar.id}" path="avatarId" value="${avatar.id}"/>
|
||||
<label for="avatar-${avatar.id}"><img src="${avatarUrl}" alt="${avatar.name}" width="${avatar.width}" height="${avatar.height}" style="padding-right:2em;padding-bottom:1em"/></label>
|
||||
</span>
|
||||
</c:forEach>
|
||||
</p>
|
||||
<p>
|
||||
<form:radiobutton id="noAvatar" path="avatarId" value="-1"/>
|
||||
<label for="noAvatar"><fmt:message key="personalsettings.avatar.none"/></label>
|
||||
</p>
|
||||
<p>
|
||||
<form:radiobutton id="customAvatar" path="avatarId" value="-2"/>
|
||||
<label for="customAvatar"><fmt:message key="personalsettings.avatar.custom"/>
|
||||
<c:if test="${not empty command.customAvatar}">
|
||||
<sub:url value="avatar.view" var="avatarUrl">
|
||||
<sub:param name="username" value="${command.user.username}"/>
|
||||
<sub:param name="forceCustom" value="true"/>
|
||||
</sub:url>
|
||||
<img src="${avatarUrl}" alt="${command.customAvatar.name}" width="${command.customAvatar.width}" height="${command.customAvatar.height}" style="padding-right:2em"/>
|
||||
</c:if>
|
||||
</label>
|
||||
</p>
|
||||
</form:form>
|
||||
|
||||
<form method="post" enctype="multipart/form-data" action="avatarUpload.view?${_csrf.parameterName}=${_csrf.token}">
|
||||
<table>
|
||||
<tr>
|
||||
<td style="padding-right:1em"><fmt:message key="personalsettings.avatar.changecustom"/></td>
|
||||
<td style="padding-right:1em"><input type="file" id="file" name="file" size="40"/></td>
|
||||
<td style="padding-right:1em"><input type="submit" value="<fmt:message key="personalsettings.avatar.upload"/>"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
<p class="detail" style="text-align:right">
|
||||
<fmt:message key="personalsettings.avatar.courtesy"/>
|
||||
</p>
|
||||
|
||||
<c:if test="${settings_reload}">
|
||||
<script language="javascript" type="text/javascript">
|
||||
parent.location.href="index.view?";
|
||||
</script>
|
||||
</c:if>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,80 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
<%@ include file="include.jsp" %>
|
||||
|
||||
<%--
|
||||
PARAMETERS
|
||||
id: ID of file.
|
||||
video: Whether the file is a video (default false).
|
||||
playEnabled: Whether to show play button (default true).
|
||||
addEnabled: Whether to show add next/last buttons (default true).
|
||||
downloadEnabled: Whether to show download button (default false).
|
||||
starEnabled: Whether to show star/unstar controls (default false).
|
||||
starred: Whether the file is currently starred.
|
||||
asTable: Whether to put the images in td tags.
|
||||
onPlay: Overrides the javascript used for the play action.
|
||||
--%>
|
||||
|
||||
<c:if test="${param.starEnabled}">
|
||||
<c:if test="${param.asTable}"><td class="fit"></c:if>
|
||||
<c:choose>
|
||||
<c:when test="${param.starred}">
|
||||
<img id="starImage${param.id}" src="<spring:theme code="ratingOnImage"/>" alt="" style="cursor:pointer"
|
||||
onclick="toggleStar(${param.id}, '#starImage${param.id}'); return false;">
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<img id="starImage${param.id}" src="<spring:theme code="ratingOffImage"/>" alt="" style="cursor:pointer"
|
||||
onclick="toggleStar(${param.id}, '#starImage${param.id}'); return false;">
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
<c:if test="${param.asTable}"></td></c:if>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${param.asTable}"><td class="fit"></c:if>
|
||||
<c:if test="${empty param.playEnabled or param.playEnabled}">
|
||||
<c:choose>
|
||||
<c:when test="${param.video}">
|
||||
<sub:url value="/videoPlayer.view" var="videoUrl">
|
||||
<sub:param name="id" value="${param.id}"/>
|
||||
</sub:url>
|
||||
<a href="${videoUrl}" target="main">
|
||||
<img src="<spring:theme code="playImage"/>" alt="<fmt:message key="common.play"/>"
|
||||
title="<fmt:message key="common.play"/>"></a>
|
||||
</c:when>
|
||||
<c:when test="${not empty param.onPlay}">
|
||||
<img src="<spring:theme code="playImage"/>" alt="<fmt:message key="common.play"/>" style="cursor:pointer"
|
||||
onclick="${param.onPlay}; return false;" title="<fmt:message key="common.play"/>">
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<img src="<spring:theme code="playImage"/>" alt="<fmt:message key="common.play"/>" style="cursor:pointer"
|
||||
onclick="top.playQueue.onPlay(${param.id}); return false;" title="<fmt:message key="common.play"/>">
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</c:if>
|
||||
<c:if test="${param.asTable}"></td></c:if>
|
||||
|
||||
<c:if test="${param.asTable}"><td class="fit"></c:if>
|
||||
<c:if test="${(empty param.addEnabled or param.addEnabled) and not param.video}">
|
||||
<img id="add${param.id}" src="<spring:theme code="addImage"/>" alt="<fmt:message key="main.addlast"/>"
|
||||
onclick="top.playQueue.onAdd(${param.id}); $().toastmessage('showSuccessToast', '<fmt:message key="main.addlast.toast"/>'); return false;"
|
||||
style="cursor:pointer" title="<fmt:message key="main.addlast"/>">
|
||||
</c:if>
|
||||
<c:if test="${param.asTable}"></td></c:if>
|
||||
|
||||
<c:if test="${param.asTable}"><td class="fit"></c:if>
|
||||
<c:if test="${(empty param.addEnabled or param.addEnabled) and not param.video}">
|
||||
<img id="add${param.id}" src="<spring:theme code="addNextImage"/>" alt="<fmt:message key="main.addnext"/>"
|
||||
onclick="top.playQueue.onAddNext(${param.id}); $().toastmessage('showSuccessToast', '<fmt:message key="main.addnext.toast"/>'); return false;"
|
||||
style="cursor:pointer" title="<fmt:message key="main.addnext"/>">
|
||||
</c:if>
|
||||
<c:if test="${param.asTable}"></td></c:if>
|
||||
|
||||
<c:if test="${param.asTable}"><td class="fit"></c:if>
|
||||
<c:if test="${param.downloadEnabled}">
|
||||
<sub:url value="/download.view" var="downloadUrl">
|
||||
<sub:param name="id" value="${param.id}"/>
|
||||
</sub:url>
|
||||
<a href="${downloadUrl}">
|
||||
<img src="<spring:theme code="downloadImage"/>" alt="<fmt:message key="common.download"/>"
|
||||
title="<fmt:message key="common.download"/>" ></a>
|
||||
</c:if>
|
||||
<c:if test="${param.asTable}"></td></c:if>
|
||||
@@ -0,0 +1,848 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<link type="text/css" rel="stylesheet" href="<c:url value="/script/webfx/luna.css"/>">
|
||||
<script type="text/javascript" src="<c:url value="/script/scripts-2.0.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/nowPlayingService.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/playQueueService.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/playlistService.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/engine.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/util.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/mediaelement/mediaelement-and-player.min.js"/>"></script>
|
||||
<%@ include file="playQueueCast.jsp" %>
|
||||
<link type="text/css" rel="stylesheet" href="<c:url value="/script/webfx/luna.css"/>">
|
||||
<link type="text/css" rel="stylesheet" href="<c:url value="/script/mediaelement/mediaelementplayer.min.css"/>">
|
||||
<style type="text/css">
|
||||
.ui-slider .ui-slider-handle {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.ui-slider a {
|
||||
outline:none;
|
||||
}
|
||||
.ui-slider {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="bgcolor2 playlistframe" onload="init()">
|
||||
|
||||
<span id="dummy-animation-target" style="max-width: ${model.autoHide ? 50 : 150}px; display: none"></span>
|
||||
|
||||
<script type="text/javascript" language="javascript">
|
||||
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;
|
||||
|
||||
function init() {
|
||||
<c:if test="${model.autoHide}">initAutoHide();</c:if>
|
||||
|
||||
dwr.engine.setErrorHandler(null);
|
||||
startTimer();
|
||||
|
||||
$("#dialog-select-playlist").dialog({resizable: true, height: 220, autoOpen: false,
|
||||
buttons: {
|
||||
"<fmt:message key="common.cancel"/>": function() {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}});
|
||||
|
||||
<c:if test="${model.player.web}">createPlayer();</c:if>
|
||||
|
||||
$("#playlistBody").sortable({
|
||||
stop: function(event, ui) {
|
||||
var indexes = [];
|
||||
$("#playlistBody").children().each(function() {
|
||||
var id = $(this).attr("id").replace("pattern", "");
|
||||
if (id.length > 0) {
|
||||
indexes.push(parseInt(id) - 1);
|
||||
}
|
||||
});
|
||||
onRearrange(indexes);
|
||||
},
|
||||
cursor: "move",
|
||||
axis: "y",
|
||||
containment: "parent",
|
||||
helper: function(e, tr) {
|
||||
var originals = tr.children();
|
||||
var trclone = tr.clone();
|
||||
trclone.children().each(function(index) {
|
||||
// Set cloned cell sizes to match the original sizes
|
||||
$(this).width(originals.eq(index).width());
|
||||
$(this).css("maxWidth", originals.eq(index).width());
|
||||
$(this).css("border-top", "1px solid black");
|
||||
$(this).css("border-bottom", "1px solid black");
|
||||
});
|
||||
return trclone;
|
||||
}
|
||||
});
|
||||
|
||||
getPlayQueue();
|
||||
}
|
||||
|
||||
function onHidePlayQueue() {
|
||||
setFrameHeight(50);
|
||||
isVisible = false;
|
||||
}
|
||||
|
||||
function onShowPlayQueue() {
|
||||
var height = $("body").height() + 25;
|
||||
height = Math.min(height, window.top.innerHeight * 0.8);
|
||||
setFrameHeight(height);
|
||||
isVisible = true;
|
||||
}
|
||||
|
||||
function onTogglePlayQueue() {
|
||||
if (isVisible) onHidePlayQueue();
|
||||
else onShowPlayQueue();
|
||||
}
|
||||
|
||||
function initAutoHide() {
|
||||
$(window).mouseleave(function (event) {
|
||||
if (event.clientY < 30) onHidePlayQueue();
|
||||
});
|
||||
|
||||
$(window).mouseenter(function () {
|
||||
onShowPlayQueue();
|
||||
});
|
||||
}
|
||||
|
||||
function setFrameHeight(height) {
|
||||
<%-- Disable animation in Chrome. It stopped working in Chrome 44. --%>
|
||||
var duration = navigator.userAgent.indexOf("Chrome") != -1 ? 0 : 400;
|
||||
|
||||
$("#dummy-animation-target").stop();
|
||||
$("#dummy-animation-target").animate({"max-width": height}, {
|
||||
step: function (now, fx) {
|
||||
top.document.getElementById("playQueueFrameset").rows = "*," + now;
|
||||
},
|
||||
duration: duration
|
||||
});
|
||||
}
|
||||
|
||||
function startTimer() {
|
||||
<!-- Periodically check if the current song has changed. -->
|
||||
nowPlayingService.getNowPlayingForCurrentPlayer(nowPlayingCallback);
|
||||
setTimeout("startTimer()", 10000);
|
||||
}
|
||||
|
||||
function nowPlayingCallback(nowPlayingInfo) {
|
||||
if (nowPlayingInfo != null && nowPlayingInfo.streamUrl != currentStreamUrl) {
|
||||
getPlayQueue();
|
||||
<c:if test="${not model.player.web}">
|
||||
currentStreamUrl = nowPlayingInfo.streamUrl;
|
||||
updateCurrentImage();
|
||||
</c:if>
|
||||
}
|
||||
}
|
||||
|
||||
function onEnded() {
|
||||
onNext(repeatEnabled);
|
||||
}
|
||||
|
||||
function createPlayer() {
|
||||
$('#audioPlayer').get(0).addEventListener("ended", onEnded);
|
||||
}
|
||||
|
||||
function getPlayQueue() {
|
||||
playQueueService.getPlayQueue(playQueueCallback);
|
||||
}
|
||||
|
||||
function onClear() {
|
||||
var ok = true;
|
||||
<c:if test="${model.partyMode}">
|
||||
ok = confirm("<fmt:message key="playlist.confirmclear"/>");
|
||||
</c:if>
|
||||
if (ok) {
|
||||
playQueueService.clear(playQueueCallback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start playing from the current playlist
|
||||
*/
|
||||
function onStart() {
|
||||
if (CastPlayer.castSession) {
|
||||
CastPlayer.playCast();
|
||||
} else if ($('#audioPlayer')) {
|
||||
var audioPlayer = $('#audioPlayer');
|
||||
if(audioPlayer.paused) {
|
||||
skip(0, audioPlayer.currentTime);
|
||||
}
|
||||
} else {
|
||||
playQueueService.start(playQueueCallback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause playing
|
||||
*/
|
||||
function onStop() {
|
||||
if (CastPlayer.castSession) {
|
||||
CastPlayer.pauseCast();
|
||||
} else if ($('#audioPlayer')) {
|
||||
$('#audioPlayer').get(0).pause();
|
||||
} else {
|
||||
playQueueService.stop(playQueueCallback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle play/pause
|
||||
*
|
||||
* FIXME: Only works for the Web player for now
|
||||
*/
|
||||
function onToggleStartStop() {
|
||||
if (CastPlayer.castSession) {
|
||||
var playing = CastPlayer.mediaSession && CastPlayer.mediaSession.playerState == chrome.cast.media.PlayerState.PLAYING;
|
||||
if (playing) onStop();
|
||||
else onStart();
|
||||
} else if ($('#audioPlayer')) {
|
||||
if (!$('#audioPlayer').get(0).paused) onStop();
|
||||
else onStart();
|
||||
} else {
|
||||
playQueueService.toggleStartStop(playQueueCallback);
|
||||
}
|
||||
}
|
||||
|
||||
function onGain(gain) {
|
||||
playQueueService.setGain(gain);
|
||||
}
|
||||
function onJukeboxVolumeChanged() {
|
||||
var value = parseInt($("#jukeboxVolume").slider("option", "value"));
|
||||
onGain(value / 100);
|
||||
}
|
||||
function onCastVolumeChanged() {
|
||||
var value = parseInt($("#castVolume").slider("option", "value"));
|
||||
CastPlayer.setCastVolume(value / 100, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase or decrease volume by a certain amount
|
||||
*
|
||||
* @param amount to add or remove from the current volume
|
||||
*/
|
||||
function onGainAdd(gain) {
|
||||
if (CastPlayer.castSession) {
|
||||
var volume = parseInt($("#castVolume").slider("option", "value")) + gain;
|
||||
if (volume > 100) volume = 100;
|
||||
if (volume < 0) volume = 0;
|
||||
CastPlayer.setCastVolume(volume / 100, false);
|
||||
$("#castVolume").slider("option", "value", volume); // Need to update UI
|
||||
} else if ($('#audioPlayer')) {
|
||||
var volume = parseInt($('#audioPlayer').get(0).volume) + gain;
|
||||
if (volume > 100) volume = 100;
|
||||
if (volume < 0) volume = 0;
|
||||
$('#audioPlayer').get(0).volume = volume;
|
||||
} else {
|
||||
var volume = parseInt($("#jukeboxVolume").slider("option", "value")) + gain;
|
||||
if (volume > 100) volume = 100;
|
||||
if (volume < 0) volume = 0;
|
||||
onGain(volume / 100);
|
||||
$("#jukeboxVolume").slider("option", "value", volume); // Need to update UI
|
||||
}
|
||||
}
|
||||
|
||||
function onSkip(index) {
|
||||
<c:choose>
|
||||
<c:when test="${model.player.web}">
|
||||
skip(index);
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
currentStreamUrl = songs[index].streamUrl;
|
||||
playQueueService.skip(index, playQueueCallback);
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
}
|
||||
function onNext(wrap) {
|
||||
var index = parseInt(getCurrentSongIndex()) + 1;
|
||||
if (radioEnabled && index >= songs.length) {
|
||||
playQueueService.reloadSearchCriteria(function(playQueue) {
|
||||
playQueueCallback(playQueue);
|
||||
onSkip(index);
|
||||
});
|
||||
return;
|
||||
} else if (wrap) {
|
||||
index = index % songs.length;
|
||||
}
|
||||
onSkip(index);
|
||||
}
|
||||
function onPrevious() {
|
||||
onSkip(parseInt(getCurrentSongIndex()) - 1);
|
||||
}
|
||||
function onPlay(id) {
|
||||
playQueueService.play(id, playQueueCallback);
|
||||
}
|
||||
function onPlayShuffle(albumListType, offset, size, genre, decade) {
|
||||
playQueueService.playShuffle(albumListType, offset, size, genre, decade, playQueueCallback);
|
||||
}
|
||||
function onPlayPlaylist(id, index) {
|
||||
playQueueService.playPlaylist(id, index, playQueueCallback);
|
||||
}
|
||||
function onPlayTopSong(id, index) {
|
||||
playQueueService.playTopSong(id, index, playQueueCallback);
|
||||
}
|
||||
function onPlayPodcastChannel(id) {
|
||||
playQueueService.playPodcastChannel(id, playQueueCallback);
|
||||
}
|
||||
function onPlayPodcastEpisode(id) {
|
||||
playQueueService.playPodcastEpisode(id, playQueueCallback);
|
||||
}
|
||||
function onPlayNewestPodcastEpisode(index) {
|
||||
playQueueService.playNewestPodcastEpisode(index, playQueueCallback);
|
||||
}
|
||||
function onPlayStarred() {
|
||||
playQueueService.playStarred(playQueueCallback);
|
||||
}
|
||||
function onPlayRandom(id, count) {
|
||||
playQueueService.playRandom(id, count, playQueueCallback);
|
||||
}
|
||||
function onPlaySimilar(id, count) {
|
||||
playQueueService.playSimilar(id, count, playQueueCallback);
|
||||
}
|
||||
function onAdd(id) {
|
||||
playQueueService.add(id, playQueueCallback);
|
||||
}
|
||||
function onAddNext(id) {
|
||||
playQueueService.addAt(id, getCurrentSongIndex() + 1, playQueueCallback);
|
||||
}
|
||||
function onShuffle() {
|
||||
playQueueService.shuffle(playQueueCallback);
|
||||
}
|
||||
function onStar(index) {
|
||||
playQueueService.toggleStar(index, playQueueCallback);
|
||||
}
|
||||
function onStarCurrent() {
|
||||
onStar(getCurrentSongIndex());
|
||||
}
|
||||
function onRemove(index) {
|
||||
playQueueService.remove(index, playQueueCallback);
|
||||
}
|
||||
function onRemoveSelected() {
|
||||
var indexes = new Array();
|
||||
var counter = 0;
|
||||
for (var i = 0; i < songs.length; i++) {
|
||||
var index = i + 1;
|
||||
if ($("#songIndex" + index).is(":checked")) {
|
||||
indexes[counter++] = i;
|
||||
}
|
||||
}
|
||||
playQueueService.removeMany(indexes, playQueueCallback);
|
||||
}
|
||||
|
||||
function onRearrange(indexes) {
|
||||
playQueueService.rearrange(indexes, playQueueCallback);
|
||||
}
|
||||
function onToggleRepeat() {
|
||||
playQueueService.toggleRepeat(playQueueCallback);
|
||||
}
|
||||
function onUndo() {
|
||||
playQueueService.undo(playQueueCallback);
|
||||
}
|
||||
function onSortByTrack() {
|
||||
playQueueService.sortByTrack(playQueueCallback);
|
||||
}
|
||||
function onSortByArtist() {
|
||||
playQueueService.sortByArtist(playQueueCallback);
|
||||
}
|
||||
function onSortByAlbum() {
|
||||
playQueueService.sortByAlbum(playQueueCallback);
|
||||
}
|
||||
function onSavePlayQueue() {
|
||||
var positionMillis = $('#audioPlayer') ? Math.round(1000.0 * $('#audioPlayer').get(0).currentTime) : 0;
|
||||
playQueueService.savePlayQueue(getCurrentSongIndex(), positionMillis);
|
||||
$().toastmessage("showSuccessToast", "<fmt:message key="playlist.toast.saveplayqueue"/>");
|
||||
}
|
||||
function onLoadPlayQueue() {
|
||||
playQueueService.loadPlayQueue(playQueueCallback);
|
||||
}
|
||||
function onSavePlaylist() {
|
||||
playlistService.createPlaylistForPlayQueue(function (playlistId) {
|
||||
top.left.updatePlaylists();
|
||||
top.left.showAllPlaylists();
|
||||
top.main.location.href = "playlist.view?id=" + playlistId;
|
||||
$().toastmessage("showSuccessToast", "<fmt:message key="playlist.toast.saveasplaylist"/>");
|
||||
});
|
||||
}
|
||||
function onAppendPlaylist() {
|
||||
playlistService.getWritablePlaylists(playlistCallback);
|
||||
}
|
||||
function playlistCallback(playlists) {
|
||||
$("#dialog-select-playlist-list").empty();
|
||||
for (var i = 0; i < playlists.length; i++) {
|
||||
var playlist = playlists[i];
|
||||
$("<p class='dense'><b><a href='#' onclick='appendPlaylist(" + playlist.id + ")'>" + escapeHtml(playlist.name)
|
||||
+ "</a></b></p>").appendTo("#dialog-select-playlist-list");
|
||||
}
|
||||
$("#dialog-select-playlist").dialog("open");
|
||||
}
|
||||
function appendPlaylist(playlistId) {
|
||||
$("#dialog-select-playlist").dialog("close");
|
||||
|
||||
var mediaFileIds = new Array();
|
||||
for (var i = 0; i < songs.length; i++) {
|
||||
if ($("#songIndex" + (i + 1)).is(":checked")) {
|
||||
mediaFileIds.push(songs[i].id);
|
||||
}
|
||||
}
|
||||
playlistService.appendToPlaylist(playlistId, mediaFileIds, function (){
|
||||
top.left.updatePlaylists();
|
||||
top.main.location.href = "playlist.view?id=" + playlistId;
|
||||
$().toastmessage("showSuccessToast", "<fmt:message key="playlist.toast.appendtoplaylist"/>");
|
||||
});
|
||||
}
|
||||
|
||||
function playQueueCallback(playQueue) {
|
||||
songs = playQueue.entries;
|
||||
repeatEnabled = playQueue.repeatEnabled;
|
||||
radioEnabled = playQueue.radioEnabled;
|
||||
if ($("#start")) {
|
||||
$("#start").toggle(!playQueue.stopEnabled);
|
||||
$("#stop").toggle(playQueue.stopEnabled);
|
||||
}
|
||||
|
||||
if ($("#toggleRepeat")) {
|
||||
if (radioEnabled) {
|
||||
$("#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) {
|
||||
$("#songCountAndDuration").html("");
|
||||
$("#empty").show();
|
||||
} else {
|
||||
$("#songCountAndDuration").html(songs.length + " <fmt:message key="playlist2.songs"/> – " + playQueue.durationAsString);
|
||||
$("#empty").hide();
|
||||
}
|
||||
|
||||
// Delete all the rows except for the "pattern" row
|
||||
dwr.util.removeAllRows("playlistBody", { filter:function(tr) {
|
||||
return (tr.id != "pattern");
|
||||
}});
|
||||
|
||||
// Create a new set cloned from the pattern row
|
||||
for (var i = 0; i < songs.length; i++) {
|
||||
var song = songs[i];
|
||||
var id = i + 1;
|
||||
dwr.util.cloneNode("pattern", { idSuffix:id });
|
||||
if ($("#trackNumber" + id)) {
|
||||
$("#trackNumber" + id).html(song.trackNumber);
|
||||
}
|
||||
if (song.starred) {
|
||||
$("#starSong" + id).attr("src", "<spring:theme code='ratingOnImage'/>");
|
||||
} else {
|
||||
$("#starSong" + id).attr("src", "<spring:theme code='ratingOffImage'/>");
|
||||
}
|
||||
if ($("#currentImage" + id) && song.streamUrl == currentStreamUrl) {
|
||||
$("#currentImage" + id).show();
|
||||
}
|
||||
if ($("#title" + id)) {
|
||||
$("#title" + id).html(song.title);
|
||||
$("#title" + id).attr("title", song.title);
|
||||
}
|
||||
if ($("#titleUrl" + id)) {
|
||||
$("#titleUrl" + id).html(song.title);
|
||||
$("#titleUrl" + id).attr("title", song.title);
|
||||
$("#titleUrl" + id).click(function () {onSkip(this.id.substring(8) - 1)});
|
||||
}
|
||||
if ($("#album" + id)) {
|
||||
$("#album" + id).html(song.album);
|
||||
$("#album" + id).attr("title", song.album);
|
||||
$("#albumUrl" + id).attr("href", song.albumUrl);
|
||||
}
|
||||
if ($("#artist" + id)) {
|
||||
$("#artist" + id).html(song.artist);
|
||||
$("#artist" + id).attr("title", song.artist);
|
||||
}
|
||||
if ($("#genre" + id)) {
|
||||
$("#genre" + id).html(song.genre);
|
||||
}
|
||||
if ($("#year" + id)) {
|
||||
$("#year" + id).html(song.year);
|
||||
}
|
||||
if ($("#bitRate" + id)) {
|
||||
$("#bitRate" + id).html(song.bitRate);
|
||||
}
|
||||
if ($("#duration" + id)) {
|
||||
$("#duration" + id).html(song.durationAsString);
|
||||
}
|
||||
if ($("#format" + id)) {
|
||||
$("#format" + id).html(song.format);
|
||||
}
|
||||
if ($("#fileSize" + id)) {
|
||||
$("#fileSize" + id).html(song.fileSize);
|
||||
}
|
||||
|
||||
$("#pattern" + id).addClass((i % 2 == 0) ? "bgcolor1" : "bgcolor2");
|
||||
|
||||
// Note: show() method causes page to scroll to top.
|
||||
$("#pattern" + id).css("display", "table-row");
|
||||
}
|
||||
|
||||
if (playQueue.sendM3U) {
|
||||
parent.frames.main.location.href="play.m3u?";
|
||||
}
|
||||
|
||||
var jukeboxVolume = $("#jukeboxVolume");
|
||||
if (jukeboxVolume) {
|
||||
jukeboxVolume.slider("option", "value", Math.floor(playQueue.gain * 100));
|
||||
}
|
||||
|
||||
<c:if test="${model.player.web}">
|
||||
triggerPlayer(playQueue.startPlayerAt, playQueue.startPlayerAtPosition);
|
||||
</c:if>
|
||||
}
|
||||
|
||||
function triggerPlayer(index, positionMillis) {
|
||||
if (index != -1) {
|
||||
if (songs.length > index) {
|
||||
skip(index);
|
||||
if (positionMillis != 0) {
|
||||
$('#audioPlayer').get(0).currentTime = positionMillis / 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
updateCurrentImage();
|
||||
if (songs.length == 0) {
|
||||
$('#audioPlayer').get(0).stop();
|
||||
}
|
||||
}
|
||||
|
||||
function skip(index, position) {
|
||||
if (index < 0 || index >= songs.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var song = songs[index];
|
||||
currentStreamUrl = song.streamUrl;
|
||||
updateCurrentImage();
|
||||
|
||||
if (CastPlayer.castSession) {
|
||||
CastPlayer.loadCastMedia(song, position);
|
||||
} else {
|
||||
$('#audioPlayer').get(0).src = song.streamUrl;
|
||||
$('#audioPlayer').get(0).load();
|
||||
$('#audioPlayer').get(0).play();
|
||||
console.log(song.streamUrl);
|
||||
}
|
||||
|
||||
updateWindowTitle(song);
|
||||
|
||||
<c:if test="${model.notify}">
|
||||
showNotification(song);
|
||||
</c:if>
|
||||
}
|
||||
|
||||
function updateWindowTitle(song) {
|
||||
top.document.title = song.title + " - " + song.artist + " - Libresonic";
|
||||
}
|
||||
|
||||
function showNotification(song) {
|
||||
if (!("Notification" in window)) {
|
||||
return;
|
||||
}
|
||||
if (Notification.permission === "granted") {
|
||||
createNotification(song);
|
||||
}
|
||||
else if (Notification.permission !== 'denied') {
|
||||
Notification.requestPermission(function (permission) {
|
||||
Notification.permission = permission;
|
||||
if (permission === "granted") {
|
||||
createNotification(song);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function createNotification(song) {
|
||||
var n = new Notification(song.title, {
|
||||
tag: "libresonic",
|
||||
body: song.artist + " - " + song.album,
|
||||
icon: "coverArt.view?id=" + song.id + "&size=110"
|
||||
});
|
||||
n.onshow = function() {
|
||||
setTimeout(function() {n.close()}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
function updateCurrentImage() {
|
||||
for (var i = 0; i < songs.length; i++) {
|
||||
var song = songs[i];
|
||||
var id = i + 1;
|
||||
var image = $("#currentImage" + id);
|
||||
|
||||
if (image) {
|
||||
if (song.streamUrl == currentStreamUrl) {
|
||||
image.show();
|
||||
} else {
|
||||
image.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getCurrentSongIndex() {
|
||||
for (var i = 0; i < songs.length; i++) {
|
||||
if (songs[i].streamUrl == currentStreamUrl) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
<!-- actionSelected() is invoked when the users selects from the "More actions..." combo box. -->
|
||||
function actionSelected(id) {
|
||||
var selectedIndexes = getSelectedIndexes();
|
||||
if (id == "top") {
|
||||
return;
|
||||
} else if (id == "savePlayQueue") {
|
||||
onSavePlayQueue();
|
||||
} else if (id == "loadPlayQueue") {
|
||||
onLoadPlayQueue();
|
||||
} else if (id == "savePlaylist") {
|
||||
onSavePlaylist();
|
||||
} else if (id == "downloadPlaylist") {
|
||||
location.href = "download.view?player=${model.player.id}";
|
||||
} else if (id == "sharePlaylist") {
|
||||
parent.frames.main.location.href = "createShare.view?player=${model.player.id}&" + getSelectedIndexes();
|
||||
} else if (id == "sortByTrack") {
|
||||
onSortByTrack();
|
||||
} else if (id == "sortByArtist") {
|
||||
onSortByArtist();
|
||||
} else if (id == "sortByAlbum") {
|
||||
onSortByAlbum();
|
||||
} else if (id == "selectAll") {
|
||||
selectAll(true);
|
||||
} else if (id == "selectNone") {
|
||||
selectAll(false);
|
||||
} else if (id == "removeSelected") {
|
||||
onRemoveSelected();
|
||||
} else if (id == "download" && selectedIndexes != "") {
|
||||
location.href = "download.view?player=${model.player.id}&" + selectedIndexes;
|
||||
} else if (id == "appendPlaylist" && selectedIndexes != "") {
|
||||
onAppendPlaylist();
|
||||
}
|
||||
$("#moreActions").prop("selectedIndex", 0);
|
||||
}
|
||||
|
||||
function getSelectedIndexes() {
|
||||
var result = "";
|
||||
for (var i = 0; i < songs.length; i++) {
|
||||
if ($("#songIndex" + (i + 1)).is(":checked")) {
|
||||
result += "i=" + i + "&";
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function selectAll(b) {
|
||||
for (var i = 0; i < songs.length; i++) {
|
||||
if (b) {
|
||||
$("#songIndex" + (i + 1)).attr("checked", "checked");
|
||||
} else {
|
||||
$("#songIndex" + (i + 1)).removeAttr("checked");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="bgcolor2" style="position:fixed; bottom:0; width:100%;padding-top:10px;">
|
||||
<table style="white-space:nowrap;">
|
||||
<tr style="white-space:nowrap;">
|
||||
<c:if test="${model.user.settingsRole and fn:length(model.players) gt 1}">
|
||||
<td style="padding-right: 5px"><select name="player" onchange="location='playQueue.view?player=' + options[selectedIndex].value;">
|
||||
<c:forEach items="${model.players}" var="player">
|
||||
<option ${player.id eq model.player.id ? "selected" : ""} value="${player.id}">${player.shortDescription}</option>
|
||||
</c:forEach>
|
||||
</select></td>
|
||||
</c:if>
|
||||
<c:if test="${model.player.web}">
|
||||
<td>
|
||||
<div id="player" style="width:340px; height:40px;padding-right:10px">
|
||||
<audio id="audioPlayer" class="mejs__player" data-mejsoptions='{"alwaysShowControls": "true"}' width="340px" height"40px"/>
|
||||
</div>
|
||||
<div id="castPlayer" style="display: none">
|
||||
<div style="float:left">
|
||||
<img id="castPlay" src="<spring:theme code="castPlayImage"/>" onclick="CastPlayer.playCast()" style="cursor:pointer">
|
||||
<img id="castPause" src="<spring:theme code="castPauseImage"/>" onclick="CastPlayer.pauseCast()" style="cursor:pointer; display:none">
|
||||
<img id="castMuteOn" src="<spring:theme code="volumeImage"/>" onclick="CastPlayer.castMuteOn()" style="cursor:pointer">
|
||||
<img id="castMuteOff" src="<spring:theme code="muteImage"/>" onclick="CastPlayer.castMuteOff()" style="cursor:pointer; display:none">
|
||||
</div>
|
||||
<div style="float:left">
|
||||
<div id="castVolume" style="width:80px;height:4px;margin-left:10px;margin-right:10px;margin-top:8px"></div>
|
||||
<script type="text/javascript">
|
||||
$("#castVolume").slider({max: 100, value: 50, animate: "fast", range: "min"});
|
||||
$("#castVolume").on("slidestop", onCastVolumeChanged);
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<img id="castOn" src="<spring:theme code="castIdleImage"/>" onclick="CastPlayer.launchCastApp()" style="cursor:pointer; display:none">
|
||||
<img id="castOff" src="<spring:theme code="castActiveImage"/>" onclick="CastPlayer.stopCastApp()" style="cursor:pointer; display:none">
|
||||
</td>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.user.streamRole and not model.player.web}">
|
||||
<td>
|
||||
<img id="start" src="<spring:theme code="castPlayImage"/>" onclick="onStart()" style="cursor:pointer">
|
||||
<img id="stop" src="<spring:theme code="castPauseImage"/>" onclick="onStop()" style="cursor:pointer; display:none">
|
||||
</td>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.player.jukebox}">
|
||||
<td style="white-space:nowrap;">
|
||||
<img src="<spring:theme code="volumeImage"/>" alt="">
|
||||
</td>
|
||||
<td style="white-space:nowrap;">
|
||||
<div id="jukeboxVolume" style="width:80px;height:4px"></div>
|
||||
<script type="text/javascript">
|
||||
$("#jukeboxVolume").slider({max: 100, value: 50, animate: "fast", range: "min"});
|
||||
$("#jukeboxVolume").on("slidestop", onJukeboxVolumeChanged);
|
||||
</script>
|
||||
</td>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${model.player.web}">
|
||||
<td><span class="header">
|
||||
<img src="<spring:theme code="backImage"/>" alt="" onclick="onPrevious()" style="cursor:pointer"></span>
|
||||
</td>
|
||||
<td><span class="header">
|
||||
<img src="<spring:theme code="forwardImage"/>" alt="" onclick="onNext(false)" style="cursor:pointer"></span>
|
||||
</td>
|
||||
</c:if>
|
||||
|
||||
<td style="white-space:nowrap;"><span class="header"><a href="javascript:onClear()"><fmt:message key="playlist.clear"/></a></span> |</td>
|
||||
<td style="white-space:nowrap;"><span class="header"><a href="javascript:onShuffle()"><fmt:message key="playlist.shuffle"/></a></span> |</td>
|
||||
|
||||
<c:if test="${model.player.web or model.player.jukebox or model.player.external}">
|
||||
<td style="white-space:nowrap;"><span class="header"><a href="javascript:onToggleRepeat()"><span id="toggleRepeat"><fmt:message key="playlist.repeat_on"/></span></a></span> |</td>
|
||||
</c:if>
|
||||
|
||||
<td style="white-space:nowrap;"><span class="header"><a href="javascript:onUndo()"><fmt:message key="playlist.undo"/></a></span> |</td>
|
||||
|
||||
<c:if test="${model.user.settingsRole}">
|
||||
<td style="white-space:nowrap;"><span class="header"><a href="playerSettings.view?id=${model.player.id}" target="main"><fmt:message key="playlist.settings"/></a></span> |</td>
|
||||
</c:if>
|
||||
|
||||
<td style="white-space:nowrap;"><select id="moreActions" onchange="actionSelected(this.options[selectedIndex].id)">
|
||||
<option id="top" selected="selected"><fmt:message key="playlist.more"/></option>
|
||||
<optgroup label="<fmt:message key="playlist.more.playlist"/>">
|
||||
<option id="savePlayQueue"><fmt:message key="playlist.saveplayqueue"/></option>
|
||||
<option id="loadPlayQueue"><fmt:message key="playlist.loadplayqueue"/></option>
|
||||
<option id="savePlaylist"><fmt:message key="playlist.save"/></option>
|
||||
<c:if test="${model.user.downloadRole}">
|
||||
<option id="downloadPlaylist"><fmt:message key="common.download"/></option>
|
||||
</c:if>
|
||||
<c:if test="${model.user.shareRole}">
|
||||
<option id="sharePlaylist"><fmt:message key="main.more.share"/></option>
|
||||
</c:if>
|
||||
<option id="sortByTrack"><fmt:message key="playlist.more.sortbytrack"/></option>
|
||||
<option id="sortByAlbum"><fmt:message key="playlist.more.sortbyalbum"/></option>
|
||||
<option id="sortByArtist"><fmt:message key="playlist.more.sortbyartist"/></option>
|
||||
</optgroup>
|
||||
<optgroup label="<fmt:message key="playlist.more.selection"/>">
|
||||
<option id="selectAll"><fmt:message key="playlist.more.selectall"/></option>
|
||||
<option id="selectNone"><fmt:message key="playlist.more.selectnone"/></option>
|
||||
<option id="removeSelected"><fmt:message key="playlist.remove"/></option>
|
||||
<c:if test="${model.user.downloadRole}">
|
||||
<option id="download"><fmt:message key="common.download"/></option>
|
||||
</c:if>
|
||||
<option id="appendPlaylist"><fmt:message key="playlist.append"/></option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
</tr></table>
|
||||
</div>
|
||||
|
||||
<h2 style="float:left"><fmt:message key="playlist.more.playlist"/></h2>
|
||||
<h2 id="songCountAndDuration" style="float:right;padding-right:1em"></h2>
|
||||
<div style="clear:both"></div>
|
||||
<p id="empty"><em><fmt:message key="playlist.empty"/></em></p>
|
||||
|
||||
<table class="music indent" style="cursor:pointer">
|
||||
<tbody id="playlistBody">
|
||||
<tr id="pattern" style="display:none;margin:0;padding:0;border:0">
|
||||
<td class="fit">
|
||||
<img id="starSong" onclick="onStar(this.id.substring(8) - 1)" src="<spring:theme code="ratingOffImage"/>"
|
||||
style="cursor:pointer" alt="" title=""></td>
|
||||
<td class="fit">
|
||||
<img id="removeSong" onclick="onRemove(this.id.substring(10) - 1)" src="<spring:theme code="removeImage"/>"
|
||||
style="cursor:pointer" alt="<fmt:message key="playlist.remove"/>" title="<fmt:message key="playlist.remove"/>"></td>
|
||||
<td class="fit"><input type="checkbox" class="checkbox" id="songIndex"></td>
|
||||
|
||||
<c:if test="${model.visibility.trackNumberVisible}">
|
||||
<td class="fit rightalign"><span class="detail" id="trackNumber">1</span></td>
|
||||
</c:if>
|
||||
|
||||
<td class="truncate">
|
||||
<img id="currentImage" src="<spring:theme code="currentImage"/>" alt="" style="display:none;padding-right: 0.5em">
|
||||
<c:choose>
|
||||
<c:when test="${model.player.externalWithPlaylist}">
|
||||
<span id="title" class="songTitle">Title</span>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<span class="songTitle"><a id="titleUrl" href="javascript:void(0)">Title</a></span>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</td>
|
||||
|
||||
<c:if test="${model.visibility.albumVisible}">
|
||||
<td class="truncate"><a id="albumUrl" target="main"><span id="album" class="detail">Album</span></a></td>
|
||||
</c:if>
|
||||
<c:if test="${model.visibility.artistVisible}">
|
||||
<td class="truncate"><span id="artist" class="detail">Artist</span></td>
|
||||
</c:if>
|
||||
<c:if test="${model.visibility.genreVisible}">
|
||||
<td class="truncate"><span id="genre" class="detail">Genre</span></td>
|
||||
</c:if>
|
||||
<c:if test="${model.visibility.yearVisible}">
|
||||
<td class="fit rightalign"><span id="year" class="detail">Year</span></td>
|
||||
</c:if>
|
||||
<c:if test="${model.visibility.formatVisible}">
|
||||
<td class="fit rightalign"><span id="format" class="detail">Format</span></td>
|
||||
</c:if>
|
||||
<c:if test="${model.visibility.fileSizeVisible}">
|
||||
<td class="fit rightalign"><span id="fileSize" class="detail">Format</span></td>
|
||||
</c:if>
|
||||
<c:if test="${model.visibility.durationVisible}">
|
||||
<td class="fit rightalign"><span id="duration" class="detail">Duration</span></td>
|
||||
</c:if>
|
||||
<c:if test="${model.visibility.bitRateVisible}">
|
||||
<td class="fit rightalign"><span id="bitRate" class="detail">Bit Rate</span></td>
|
||||
</c:if>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div style="height:3.2em"></div>
|
||||
|
||||
<div id="dialog-select-playlist" title="<fmt:message key="main.addtoplaylist.title"/>" style="display: none;">
|
||||
<p><fmt:message key="main.addtoplaylist.text"/></p>
|
||||
<div id="dialog-select-playlist-list"></div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
window['__onGCastApiAvailable'] = function(isAvailable) {
|
||||
if (isAvailable) {
|
||||
CastPlayer.initializeCastPlayer();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,278 @@
|
||||
<script type="text/javascript">
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var CastPlayer = function () {
|
||||
|
||||
this.castSession = null;
|
||||
this.mediaSession = null;
|
||||
this.volume = 1.0;
|
||||
};
|
||||
|
||||
CastPlayer.prototype.initializeCastPlayer = function () {
|
||||
if (!window.chrome) {
|
||||
return;
|
||||
}
|
||||
if (!chrome.cast || !chrome.cast.isAvailable) {
|
||||
setTimeout(this.initializeCastPlayer.bind(this), 1000);
|
||||
return;
|
||||
}
|
||||
var applicationID = "4FBFE470";
|
||||
var sessionRequest = new chrome.cast.SessionRequest(applicationID);
|
||||
var apiConfig = new chrome.cast.ApiConfig(sessionRequest,
|
||||
this.sessionListener.bind(this),
|
||||
this.receiverListener.bind(this));
|
||||
chrome.cast.initialize(apiConfig, this.onInitSuccess.bind(this), this.onError.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* session listener during initialization
|
||||
*/
|
||||
CastPlayer.prototype.sessionListener = function (s) {
|
||||
this.log('New session ID:' + s.sessionId);
|
||||
this.castSession = s;
|
||||
this.setCastControlsVisible(true);
|
||||
if (this.castSession.media.length > 0) {
|
||||
this.log('Found ' + this.castSession.media.length + ' existing media sessions.');
|
||||
this.onMediaDiscovered('onRequestSessionSuccess_', this.castSession.media[0]);
|
||||
}
|
||||
this.castSession.addMediaListener(this.onMediaDiscovered.bind(this, 'addMediaListener'));
|
||||
this.castSession.addUpdateListener(this.sessionUpdateListener.bind(this));
|
||||
this.syncControls();
|
||||
};
|
||||
|
||||
/**
|
||||
* receiver listener during initialization
|
||||
*/
|
||||
CastPlayer.prototype.receiverListener = function (e) {
|
||||
if (e === 'available') {
|
||||
this.log("receiver found");
|
||||
$("#castOn").show();
|
||||
$("#castOff").hide();
|
||||
}
|
||||
else {
|
||||
this.log("receiver list empty");
|
||||
$("#castOn").hide();
|
||||
$("#castOff").hide();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* session update listener
|
||||
*/
|
||||
CastPlayer.prototype.sessionUpdateListener = function (isAlive) {
|
||||
var message = isAlive ? 'Session Updated' : 'Session Removed';
|
||||
message += ': ' + this.castSession.sessionId;
|
||||
this.log(message);
|
||||
if (!isAlive) {
|
||||
this.castSession = null;
|
||||
this.setCastControlsVisible(false);
|
||||
}
|
||||
};
|
||||
|
||||
CastPlayer.prototype.onInitSuccess = function () {
|
||||
this.log("init success");
|
||||
};
|
||||
|
||||
CastPlayer.prototype.onError = function () {
|
||||
this.log("error");
|
||||
};
|
||||
|
||||
CastPlayer.prototype.setCastControlsVisible = function (visible) {
|
||||
$("#player").toggle(!visible);
|
||||
$("#castPlayer").toggle(visible);
|
||||
$("#castOff").toggle(visible);
|
||||
$("#castOn").toggle(!visible);
|
||||
};
|
||||
|
||||
/**
|
||||
* launch app and request session
|
||||
*/
|
||||
CastPlayer.prototype.launchCastApp = function () {
|
||||
this.log("launching app...");
|
||||
chrome.cast.requestSession(this.onRequestSessionSuccess.bind(this), this.onLaunchError.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Stops the running receiver application associated with the session.
|
||||
*/
|
||||
CastPlayer.prototype.stopCastApp = function () {
|
||||
this.castSession.stop(this.onStopAppSuccess.bind(this, 'Session stopped'),
|
||||
this.onError.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback function for stop app success
|
||||
*/
|
||||
CastPlayer.prototype.onStopAppSuccess = function (message) {
|
||||
console.log(message);
|
||||
this.currentMediaSession = null;
|
||||
this.syncControls();
|
||||
};
|
||||
|
||||
/**
|
||||
* callback on success for requestSession call
|
||||
* @param {Object} s A non-null new session.
|
||||
*/
|
||||
CastPlayer.prototype.onRequestSessionSuccess = function (s) {
|
||||
this.log("session success: " + s.sessionId);
|
||||
this.castSession = s;
|
||||
|
||||
var position = -1;
|
||||
if (!$('#audioPlayer').get(0).paused) {
|
||||
position = $('#audioPlayer').get(0).currentTime;
|
||||
$('#audioPlayer').get(0).pause();
|
||||
}
|
||||
|
||||
this.setCastControlsVisible(true);
|
||||
this.castSession.addUpdateListener(this.sessionUpdateListener.bind(this));
|
||||
this.syncControls();
|
||||
|
||||
// Continue song at same position?
|
||||
if (position != -1) {
|
||||
skip(getCurrentSongIndex(), position);
|
||||
}
|
||||
};
|
||||
|
||||
CastPlayer.prototype.onLaunchError = function () {
|
||||
this.log("launch error");
|
||||
};
|
||||
|
||||
CastPlayer.prototype.loadCastMedia = function (song, position) {
|
||||
if (!this.castSession) {
|
||||
this.log("no session");
|
||||
return;
|
||||
}
|
||||
this.log("loading..." + song.remoteStreamUrl);
|
||||
var mediaInfo = new chrome.cast.media.MediaInfo(song.remoteStreamUrl);
|
||||
mediaInfo.contentType = song.contentType;
|
||||
mediaInfo.streamType = chrome.cast.media.StreamType.BUFFERED;
|
||||
mediaInfo.duration = song.duration;
|
||||
mediaInfo.metadata = new chrome.cast.media.MusicTrackMediaMetadata();
|
||||
mediaInfo.metadata.metadataType = chrome.cast.media.MetadataType.MUSIC_TRACK;
|
||||
mediaInfo.metadata.songName = song.title;
|
||||
mediaInfo.metadata.title = song.title;
|
||||
mediaInfo.metadata.albumName = song.album;
|
||||
mediaInfo.metadata.artist = song.artist;
|
||||
mediaInfo.metadata.trackNumber = song.trackNumber;
|
||||
mediaInfo.metadata.images = [new chrome.cast.Image(song.remoteCoverArtUrl + "&size=384")];
|
||||
mediaInfo.metadata.releaseYear = song.year;
|
||||
|
||||
var request = new chrome.cast.media.LoadRequest(mediaInfo);
|
||||
request.autoplay = true;
|
||||
request.currentTime = position;
|
||||
|
||||
this.castSession.loadMedia(request,
|
||||
this.onMediaDiscovered.bind(this, 'loadMedia'),
|
||||
this.onMediaError.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* callback on success for loading media
|
||||
*/
|
||||
CastPlayer.prototype.onMediaDiscovered = function (how, ms) {
|
||||
this.mediaSession = ms;
|
||||
this.log("new media session ID:" + this.mediaSession.mediaSessionId + ' (' + how + ')');
|
||||
this.log(ms);
|
||||
this.mediaSession.addUpdateListener(this.onMediaStatusUpdate.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* callback on media loading error
|
||||
* @param {Object} e A non-null media object
|
||||
*/
|
||||
CastPlayer.prototype.onMediaError = function (e) {
|
||||
this.log("media error");
|
||||
};
|
||||
|
||||
/**
|
||||
* callback for media status event
|
||||
*/
|
||||
CastPlayer.prototype.onMediaStatusUpdate = function () {
|
||||
this.log(this.mediaSession.playerState);
|
||||
if (this.mediaSession.playerState === chrome.cast.media.PlayerState.IDLE && this.mediaSession.idleReason === "FINISHED") {
|
||||
onNext(repeatEnabled);
|
||||
}
|
||||
this.syncControls();
|
||||
};
|
||||
|
||||
CastPlayer.prototype.playCast = function () {
|
||||
if (!this.mediaSession) {
|
||||
return;
|
||||
}
|
||||
this.mediaSession.play(null, this.mediaCommandSuccessCallback.bind(this, "playing started for " + this.mediaSession.sessionId),
|
||||
this.onError.bind(this));
|
||||
$("#castPlay").hide();
|
||||
$("#castPause").show();
|
||||
};
|
||||
|
||||
CastPlayer.prototype.pauseCast = function () {
|
||||
if (!this.mediaSession) {
|
||||
return;
|
||||
}
|
||||
this.mediaSession.pause(null, this.mediaCommandSuccessCallback.bind(this, "paused " + this.mediaSession.sessionId),
|
||||
this.onError.bind(this));
|
||||
$("#castPlay").show();
|
||||
$("#castPause").hide();
|
||||
};
|
||||
|
||||
/**
|
||||
* set receiver volume
|
||||
* @param {Number} level A number for volume level
|
||||
* @param {Boolean} mute A true/false for mute/unmute
|
||||
*/
|
||||
CastPlayer.prototype.setCastVolume = function (level, mute) {
|
||||
if (!this.castSession)
|
||||
return;
|
||||
|
||||
if (!mute) {
|
||||
this.castSession.setReceiverVolumeLevel(level, this.mediaCommandSuccessCallback.bind(this, 'media set-volume done'),
|
||||
this.onError.bind(this));
|
||||
this.volume = level;
|
||||
}
|
||||
else {
|
||||
this.castSession.setReceiverMuted(true, this.mediaCommandSuccessCallback.bind(this, 'media set-volume done'),
|
||||
this.onError.bind(this));
|
||||
}
|
||||
$("#castMuteOn").toggle(!mute);
|
||||
$("#castMuteOff").toggle(mute);
|
||||
};
|
||||
|
||||
CastPlayer.prototype.castMuteOn = function () {
|
||||
this.setCastVolume(this.volume, true);
|
||||
};
|
||||
|
||||
CastPlayer.prototype.castMuteOff = function () {
|
||||
this.setCastVolume(this.volume, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* callback on success for media commands
|
||||
* @param {string} info A message string
|
||||
*/
|
||||
CastPlayer.prototype.mediaCommandSuccessCallback = function (info) {
|
||||
this.log(info);
|
||||
};
|
||||
|
||||
CastPlayer.prototype.syncControls = function () {
|
||||
if (this.castSession && this.castSession.receiver.volume) {
|
||||
this.volume = this.castSession.receiver.volume.level;
|
||||
var muted = this.castSession.receiver.volume.muted;
|
||||
$("#castMuteOn").toggle(!muted);
|
||||
$("#castMuteOff").toggle(muted);
|
||||
document.getElementById("castVolume").value = this.volume * 100;
|
||||
}
|
||||
|
||||
var playing = this.mediaSession && this.mediaSession.playerState === chrome.cast.media.PlayerState.PLAYING;
|
||||
$("#castPause").toggle(playing);
|
||||
$("#castPlay").toggle(!playing);
|
||||
};
|
||||
|
||||
CastPlayer.prototype.log = function (message) {
|
||||
console.log(message);
|
||||
};
|
||||
|
||||
window.CastPlayer = CastPlayer;
|
||||
})();
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,170 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
<%--@elvariable id="command" type="org.libresonic.player.command.PlayerSettingsCommand"--%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value="/script/scripts-2.0.js"/>"></script>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1">
|
||||
<script type="text/javascript" src="<c:url value="/script/wz_tooltip.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/tip_balloon.js"/>"></script>
|
||||
|
||||
<c:import url="settingsHeader.jsp">
|
||||
<c:param name="cat" value="player"/>
|
||||
<c:param name="toast" value="${settings_toast}"/>
|
||||
<c:param name="restricted" value="${not command.admin}"/>
|
||||
</c:import>
|
||||
|
||||
<fmt:message key="common.unknown" var="unknown"/>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${empty command.players}">
|
||||
<p><fmt:message key="playersettings.noplayers"/></p>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
|
||||
<c:url value="playerSettings.view" var="deleteUrl">
|
||||
<c:param name="delete" value="${command.playerId}"/>
|
||||
</c:url>
|
||||
<c:url value="playerSettings.view" var="cloneUrl">
|
||||
<c:param name="clone" value="${command.playerId}"/>
|
||||
</c:url>
|
||||
|
||||
<table class="indent">
|
||||
<tr>
|
||||
<td><b><fmt:message key="playersettings.title"/></b></td>
|
||||
<td>
|
||||
<select name="player" onchange="location='playerSettings.view?id=' + options[selectedIndex].value;">
|
||||
<c:forEach items="${command.players}" var="player">
|
||||
<option ${player.id eq command.playerId ? "selected" : ""}
|
||||
value="${player.id}">${fn:escapeXml(player.description)}</option>
|
||||
</c:forEach>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-right:1em"><div class="forward"><a href="${deleteUrl}"><fmt:message key="playersettings.forget"/></a></div></td>
|
||||
<td><div class="forward"><a href="${cloneUrl}"><fmt:message key="playersettings.clone"/></a></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<form:form commandName="command" method="post" action="playerSettings.view">
|
||||
<form:hidden path="playerId"/>
|
||||
|
||||
<table class="ruleTable indent">
|
||||
<c:forEach items="${command.technologyHolders}" var="technologyHolder">
|
||||
<c:set var="technologyName">
|
||||
<fmt:message key="playersettings.technology.${fn:toLowerCase(technologyHolder.name)}.title"/>
|
||||
</c:set>
|
||||
|
||||
<tr>
|
||||
<td class="ruleTableHeader">
|
||||
<form:radiobutton id="radio-${technologyName}" path="technologyName" value="${technologyHolder.name}"/>
|
||||
<b><label for="radio-${technologyName}">${technologyName}</label></b>
|
||||
</td>
|
||||
<td class="ruleTableCell" style="width:40em">
|
||||
<fmt:message key="playersettings.technology.${fn:toLowerCase(technologyHolder.name)}.text"/>
|
||||
</td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</table>
|
||||
|
||||
<table class="indent" style="border-spacing:3pt;">
|
||||
<tr>
|
||||
<td style="padding-right: 1.5em"><fmt:message key="playersettings.type"/></td>
|
||||
<td>
|
||||
<c:choose>
|
||||
<c:when test="${empty command.type}">${unknown}</c:when>
|
||||
<c:otherwise>${command.type}</c:otherwise>
|
||||
</c:choose>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-right: 1.5em"><fmt:message key="playersettings.lastseen"/></td>
|
||||
<td><fmt:formatDate value="${command.lastSeen}" type="both" dateStyle="long" timeStyle="medium"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table class="indent" style="border-spacing:3pt;">
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="playersettings.name"/></td>
|
||||
<td><form:input path="name" size="16"/></td>
|
||||
<td colspan="2"><c:import url="helpToolTip.jsp"><c:param name="topic" value="playername"/></c:import></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="playersettings.maxbitrate"/></td>
|
||||
<td>
|
||||
<form:select path="transcodeSchemeName" cssStyle="width:8em">
|
||||
<c:forEach items="${command.transcodeSchemeHolders}" var="transcodeSchemeHolder">
|
||||
<form:option value="${transcodeSchemeHolder.name}" label="${transcodeSchemeHolder.description}"/>
|
||||
</c:forEach>
|
||||
</form:select>
|
||||
</td>
|
||||
<td>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="transcode"/></c:import>
|
||||
</td>
|
||||
<td class="warning">
|
||||
<c:if test="${not command.transcodingSupported}">
|
||||
<fmt:message key="playersettings.notranscoder"/>
|
||||
</c:if>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<table class="indent" style="border-spacing:3pt">
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<form:checkbox path="dynamicIp" id="dynamicIp" cssClass="checkbox"/>
|
||||
<label for="dynamicIp"><fmt:message key="playersettings.dynamicip"/></label>
|
||||
</td>
|
||||
<td><c:import url="helpToolTip.jsp"><c:param name="topic" value="dynamicip"/></c:import></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<form:checkbox path="autoControlEnabled" id="autoControlEnabled" cssClass="checkbox"/>
|
||||
<label for="autoControlEnabled"><fmt:message key="playersettings.autocontrol"/></label>
|
||||
</td>
|
||||
<td><c:import url="helpToolTip.jsp"><c:param name="topic" value="autocontrol"/></c:import></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<form:checkbox path="m3uBomEnabled" id="m3uBomEnabled" cssClass="checkbox"/>
|
||||
<label for="m3uBomEnabled"><fmt:message key="playersettings.m3ubom"/></label>
|
||||
</td>
|
||||
<td><c:import url="helpToolTip.jsp"><c:param name="topic" value="m3ubom"/></c:import></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<c:if test="${not empty command.allTranscodings}">
|
||||
<table class="indent">
|
||||
<tr><td><b><fmt:message key="playersettings.transcodings"/></b></td></tr>
|
||||
<c:forEach items="${command.allTranscodings}" var="transcoding" varStatus="loopStatus">
|
||||
<c:if test="${loopStatus.count % 3 == 1}"><tr></c:if>
|
||||
<td style="padding-right:2em">
|
||||
<form:checkbox path="activeTranscodingIds" id="transcoding${transcoding.id}" value="${transcoding.id}" cssClass="checkbox"/>
|
||||
<label for="transcoding${transcoding.id}">${transcoding.name}</label>
|
||||
</td>
|
||||
<c:if test="${loopStatus.count % 3 == 0 or loopStatus.count eq fn:length(command.allTranscodings)}"></tr></c:if>
|
||||
</c:forEach>
|
||||
</table>
|
||||
</c:if>
|
||||
|
||||
<input type="submit" value="<fmt:message key="common.save"/>" style="margin-top:1em;margin-right:0.3em">
|
||||
<input type="button" value="<fmt:message key="common.cancel"/>" style="margin-top:1em" onclick="location.href='nowPlaying.view'">
|
||||
</form:form>
|
||||
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<c:if test="${settings_reload}">
|
||||
<script language="javascript" type="text/javascript">parent.frames.playQueue.location.href="playQueue.view?"</script>
|
||||
</c:if>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,276 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value='/dwr/util.js'/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/engine.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/playlistService.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/starService.js"/>"></script>
|
||||
<script type="text/javascript" language="javascript">
|
||||
|
||||
var playlist;
|
||||
var songs;
|
||||
|
||||
function init() {
|
||||
dwr.engine.setErrorHandler(null);
|
||||
$("#dialog-edit").dialog({resizable: true, width:400, autoOpen: false,
|
||||
buttons: {
|
||||
"<fmt:message key="common.save"/>": function() {
|
||||
$(this).dialog("close");
|
||||
var name = $("#newName").val();
|
||||
var comment = $("#newComment").val();
|
||||
var shared = $("#newShared").is(":checked");
|
||||
$("#name").text(name);
|
||||
$("#comment").text(comment);
|
||||
playlistService.updatePlaylist(playlist.id, name, comment, shared, function (playlistInfo){playlistCallback(playlistInfo); top.left.updatePlaylists()});
|
||||
},
|
||||
"<fmt:message key="common.cancel"/>": function() {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}});
|
||||
|
||||
$("#dialog-delete").dialog({resizable: false, height: 170, autoOpen: false,
|
||||
buttons: {
|
||||
"<fmt:message key="common.delete"/>": function() {
|
||||
$(this).dialog("close");
|
||||
playlistService.deletePlaylist(playlist.id, function (){top.left.updatePlaylists(); location = "playlists.view";});
|
||||
},
|
||||
"<fmt:message key="common.cancel"/>": function() {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}});
|
||||
|
||||
$("#playlistBody").sortable({
|
||||
stop: function(event, ui) {
|
||||
var indexes = [];
|
||||
$("#playlistBody").children().each(function() {
|
||||
var id = $(this).attr("id").replace("pattern", "");
|
||||
if (id.length > 0) {
|
||||
indexes.push(parseInt(id) - 1);
|
||||
}
|
||||
});
|
||||
onRearrange(indexes);
|
||||
},
|
||||
cursor: "move",
|
||||
axis: "y",
|
||||
containment: "parent",
|
||||
helper: function(e, tr) {
|
||||
var originals = tr.children();
|
||||
var trclone = tr.clone();
|
||||
trclone.children().each(function(index) {
|
||||
// Set cloned cell sizes to match the original sizes
|
||||
$(this).width(originals.eq(index).width());
|
||||
$(this).css("maxWidth", originals.eq(index).width());
|
||||
$(this).css("border-top", "1px solid black");
|
||||
$(this).css("border-bottom", "1px solid black");
|
||||
});
|
||||
return trclone;
|
||||
}
|
||||
});
|
||||
|
||||
getPlaylist();
|
||||
}
|
||||
|
||||
function getPlaylist() {
|
||||
playlistService.getPlaylist(${model.playlist.id}, playlistCallback);
|
||||
}
|
||||
|
||||
function playlistCallback(playlistInfo) {
|
||||
this.playlist = playlistInfo.playlist;
|
||||
this.songs = playlistInfo.entries;
|
||||
|
||||
if (songs.length == 0) {
|
||||
$("#empty").show();
|
||||
} else {
|
||||
$("#empty").hide();
|
||||
}
|
||||
|
||||
$("#songCount").html(playlist.fileCount);
|
||||
$("#duration").html(playlist.durationAsString);
|
||||
|
||||
if (playlist.shared) {
|
||||
$("#shared").html("<fmt:message key="playlist2.shared"/>");
|
||||
} else {
|
||||
$("#shared").html("<fmt:message key="playlist2.notshared"/>");
|
||||
}
|
||||
|
||||
// Delete all the rows except for the "pattern" row
|
||||
dwr.util.removeAllRows("playlistBody", { filter:function(tr) {
|
||||
return (tr.id != "pattern");
|
||||
}});
|
||||
|
||||
// Create a new set cloned from the pattern row
|
||||
for (var i = 0; i < songs.length; i++) {
|
||||
var song = songs[i];
|
||||
var id = i + 1;
|
||||
dwr.util.cloneNode("pattern", { idSuffix:id });
|
||||
if (song.starred) {
|
||||
$("#starSong" + id).attr("src", "<spring:theme code='ratingOnImage'/>");
|
||||
} else {
|
||||
$("#starSong" + id).attr("src", "<spring:theme code='ratingOffImage'/>");
|
||||
}
|
||||
if (!song.present) {
|
||||
$("#missing" + id).show();
|
||||
}
|
||||
$("#index" + id).html(id);
|
||||
$("#title" + id).html(song.title);
|
||||
$("#title" + id).attr("title", song.title);
|
||||
$("#album" + id).html(song.album);
|
||||
$("#album" + id).attr("title", song.album);
|
||||
$("#albumUrl" + id).attr("href", "main.view?id=" + song.id);
|
||||
$("#artist" + id).html(song.artist);
|
||||
$("#artist" + id).attr("title", song.artist);
|
||||
$("#songDuration" + id).html(song.durationAsString);
|
||||
|
||||
// Note: show() method causes page to scroll to top.
|
||||
$("#pattern" + id).css("display", "table-row");
|
||||
}
|
||||
}
|
||||
|
||||
function onPlay(index) {
|
||||
top.playQueue.onPlayPlaylist(playlist.id, index);
|
||||
}
|
||||
function onPlayAll() {
|
||||
top.playQueue.onPlayPlaylist(playlist.id);
|
||||
}
|
||||
function onAdd(index) {
|
||||
top.playQueue.onAdd(songs[index].id);
|
||||
$().toastmessage('showSuccessToast', '<fmt:message key="main.addlast.toast"/>')
|
||||
}
|
||||
function onAddNext(index) {
|
||||
top.playQueue.onAddNext(songs[index].id);
|
||||
$().toastmessage('showSuccessToast', '<fmt:message key="main.addnext.toast"/>')
|
||||
}
|
||||
function onStar(index) {
|
||||
playlistService.toggleStar(playlist.id, index, playlistCallback);
|
||||
}
|
||||
function onRemove(index) {
|
||||
playlistService.remove(playlist.id, index, function (playlistInfo){playlistCallback(playlistInfo); top.left.updatePlaylists()});
|
||||
}
|
||||
function onRearrange(indexes) {
|
||||
playlistService.rearrange(playlist.id, indexes, playlistCallback);
|
||||
}
|
||||
function onEditPlaylist() {
|
||||
$("#dialog-edit").dialog("open");
|
||||
}
|
||||
function onDeletePlaylist() {
|
||||
$("#dialog-delete").dialog("open");
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style type="text/css">
|
||||
.playlist-missing {
|
||||
color: red;
|
||||
border: 1px solid red;
|
||||
display: none;
|
||||
font-size: 90%;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body class="mainframe bgcolor1" onload="init()">
|
||||
|
||||
<div style="float:left;margin-right:1.5em;margin-bottom:1.5em">
|
||||
<c:import url="coverArt.jsp">
|
||||
<c:param name="playlistId" value="${model.playlist.id}"/>
|
||||
<c:param name="coverArtSize" value="200"/>
|
||||
</c:import>
|
||||
</div>
|
||||
|
||||
<h1><a href="playlists.view"><fmt:message key="left.playlists"/></a> » <span id="name">${fn:escapeXml(model.playlist.name)}</span></h1>
|
||||
<h2>
|
||||
<span class="header"><a href="javascript:void(0)" onclick="onPlayAll();"><fmt:message key="common.play"/></a></span>
|
||||
|
||||
<c:if test="${model.user.downloadRole}">
|
||||
<c:url value="download.view" var="downloadUrl"><c:param name="playlist" value="${model.playlist.id}"/></c:url>
|
||||
| <span class="header"><a href="${downloadUrl}"><fmt:message key="common.download"/></a></span>
|
||||
</c:if>
|
||||
<c:if test="${model.user.shareRole}">
|
||||
<c:url value="createShare.view" var="shareUrl"><c:param name="playlist" value="${model.playlist.id}"/></c:url>
|
||||
| <span class="header"><a href="${shareUrl}"><fmt:message key="share.title"/></a></span>
|
||||
</c:if>
|
||||
<c:if test="${model.editAllowed}">
|
||||
| <span class="header"><a href="javascript:void(0)" onclick="onEditPlaylist();"><fmt:message key="common.edit"/></a></span>
|
||||
| <span class="header"><a href="javascript:void(0)" onclick="onDeletePlaylist();"><fmt:message key="common.delete"/></a></span>
|
||||
</c:if>
|
||||
<c:url value="exportPlaylist.view" var="exportUrl"><c:param name="id" value="${model.playlist.id}"/></c:url>
|
||||
| <span class="header"><a href="${exportUrl}"><fmt:message key="playlist2.export"/></a></span>
|
||||
|
||||
</h2>
|
||||
|
||||
<div id="comment" class="detail" style="padding-top:0.2em">${fn:escapeXml(model.playlist.comment)}</div>
|
||||
|
||||
<div class="detail" style="padding-top:0.2em">
|
||||
<span id="songCount"></span> <fmt:message key="playlist2.songs"/> – <span id="duration"></span>
|
||||
</div>
|
||||
<div class="detail" style="padding-top:0.2em">
|
||||
<fmt:message key="playlist2.created" var="created">
|
||||
<fmt:param>${model.playlist.username}</fmt:param>
|
||||
<fmt:param><fmt:formatDate type="date" dateStyle="long" value="${model.playlist.created}"/></fmt:param>
|
||||
</fmt:message>
|
||||
${fn:escapeXml(created)}.
|
||||
</div>
|
||||
<div class="detail" style="padding-top:0.2em">
|
||||
<span id="shared"></span>.
|
||||
</div>
|
||||
|
||||
<div style="height:0.7em;clear:both"></div>
|
||||
|
||||
<p id="empty" style="display: none;"><em><fmt:message key="playlist2.empty"/></em></p>
|
||||
|
||||
<table class="music" style="cursor:pointer">
|
||||
<tbody id="playlistBody">
|
||||
<tr id="pattern" style="display:none;margin:0;padding:0;border:0">
|
||||
<td class="fit">
|
||||
<img id="starSong" onclick="onStar(this.id.substring(8) - 1)" src="<spring:theme code="ratingOffImage"/>"
|
||||
style="cursor:pointer" alt="" title=""></td>
|
||||
<td class="fit">
|
||||
<img id="play" src="<spring:theme code="playImage"/>" alt="<fmt:message key="common.play"/>" title="<fmt:message key="common.play"/>"
|
||||
style="padding-right:0.1em;cursor:pointer" onclick="onPlay(this.id.substring(4) - 1)"></td>
|
||||
<td class="fit">
|
||||
<img id="add" src="<spring:theme code="addImage"/>" alt="<fmt:message key="common.add"/>" title="<fmt:message key="common.add"/>"
|
||||
style="padding-right:0.1em;cursor:pointer" onclick="onAdd(this.id.substring(3) - 1)"></td>
|
||||
<td class="fit" style="padding-right:30px">
|
||||
<img id="addNext" src="<spring:theme code="addNextImage"/>" alt="<fmt:message key="main.addnext"/>" title="<fmt:message key="main.addnext"/>"
|
||||
style="padding-right:0.1em;cursor:pointer" onclick="onAddNext(this.id.substring(7) - 1)"></td>
|
||||
|
||||
<td class="fit rightalign"><span id="index">1</span></td>
|
||||
<td class="fit"><span id="missing" class="playlist-missing"><fmt:message key="playlist.missing"/></span></td>
|
||||
<td class="truncate"><span id="title" class="songTitle">Title</span></td>
|
||||
<td class="truncate"><a id="albumUrl" target="main"><span id="album" class="detail">Album</span></a></td>
|
||||
<td class="truncate"><span id="artist" class="detail">Artist</span></td>
|
||||
<td class="fit rightalign"><span id="songDuration" class="detail">Duration</span></td>
|
||||
|
||||
<c:if test="${model.editAllowed}">
|
||||
<td class="fit">
|
||||
<img id="removeSong" onclick="onRemove(this.id.substring(10) - 1)" src="<spring:theme code="removeImage"/>"
|
||||
style="cursor:pointer" alt="<fmt:message key="playlist.remove"/>" title="<fmt:message key="playlist.remove"/>"></td>
|
||||
</c:if>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div id="dialog-delete" title="<fmt:message key="common.confirm"/>" style="display: none;">
|
||||
<p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>
|
||||
<fmt:message key="playlist2.confirmdelete"/></p>
|
||||
</div>
|
||||
|
||||
<div id="dialog-edit" title="<fmt:message key="common.edit"/>" style="display: none;">
|
||||
<form>
|
||||
<label for="newName" style="display:block;"><fmt:message key="playlist2.name"/></label>
|
||||
<input type="text" name="newName" id="newName" value="${fn:escapeXml(model.playlist.name)}" class="ui-widget-content"
|
||||
style="display:block;width:95%;"/>
|
||||
<label for="newComment" style="display:block;margin-top:1em"><fmt:message key="playlist2.comment"/></label>
|
||||
<input type="text" name="newComment" id="newComment" value="${fn:escapeXml(model.playlist.comment)}" class="ui-widget-content"
|
||||
style="display:block;width:95%;"/>
|
||||
<input type="checkbox" name="newShared" id="newShared" ${model.playlist.shared ? "checked='checked'" : ""} style="margin-top:1.5em" class="ui-widget-content"/>
|
||||
<label for="newShared"><fmt:message key="playlist2.public"/></label>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,38 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<%--@elvariable id="model" type="java.util.Map"--%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
</head><body class="mainframe bgcolor1">
|
||||
|
||||
<h1 style="padding-bottom: 1em">
|
||||
<img src="<spring:theme code="playlistImage"/>" alt="">
|
||||
<span style="vertical-align: middle"><fmt:message key="left.playlists"/></span>
|
||||
</h1>
|
||||
|
||||
<c:if test="${empty model.playlists}">
|
||||
<p><em><fmt:message key="playlist2.noplaylists"/></em></p>
|
||||
</c:if>
|
||||
|
||||
<c:forEach items="${model.playlists}" var="playlist" varStatus="loopStatus">
|
||||
|
||||
<c:set var="caption2">
|
||||
${playlist.fileCount} <fmt:message key="playlist2.songs"/> – ${playlist.durationAsString}
|
||||
</c:set>
|
||||
<div class="albumThumb">
|
||||
<c:import url="coverArt.jsp">
|
||||
<c:param name="playlistId" value="${playlist.id}"/>
|
||||
<c:param name="coverArtSize" value="200"/>
|
||||
<c:param name="caption1" value="${fn:escapeXml(playlist.name)}"/>
|
||||
<c:param name="caption2" value="${caption2}"/>
|
||||
<c:param name="captionCount" value="2"/>
|
||||
<c:param name="showLink" value="true"/>
|
||||
<c:param name="appearAfter" value="${loopStatus.count * 30}"/>
|
||||
</c:import>
|
||||
</div>
|
||||
|
||||
</c:forEach>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,26 @@
|
||||
<%@ include file="include.jsp" %>
|
||||
<%@ page language="java" contentType="text/xml; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
|
||||
<rss version="2.0">
|
||||
<channel>
|
||||
<title>Libresonic Podcast</title>
|
||||
<link>${model.url}</link>
|
||||
<description>Libresonic Podcast</description>
|
||||
<language>en-us</language>
|
||||
<image>
|
||||
<url>http://www.libresonic.org/pages/inc/img/libresonic_logo.png</url>
|
||||
<title>Libresonic Podcast</title>
|
||||
</image>
|
||||
|
||||
<c:forEach var="podcast" items="${model.podcasts}">
|
||||
<item>
|
||||
<title>${fn:escapeXml(podcast.name)}</title>
|
||||
<link>${model.url}</link>
|
||||
<description>Libresonic playlist "${fn:escapeXml(podcast.name)}"</description>
|
||||
<pubDate>${podcast.publishDate}</pubDate>
|
||||
<enclosure url="${podcast.enclosureUrl}" length="${podcast.length}" type="${podcast.type}"/>
|
||||
</item>
|
||||
</c:forEach>
|
||||
|
||||
</channel>
|
||||
</rss>
|
||||
@@ -0,0 +1,186 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
|
||||
<%--
|
||||
~ This file is part of Libresonic.
|
||||
~
|
||||
~ Libresonic 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
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ Libresonic 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 Libresonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
~
|
||||
~ Copyright 2015 (C) Sindre Mehus
|
||||
--%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
|
||||
<script type="text/javascript" language="javascript">
|
||||
function init() {
|
||||
$("#dialog-delete").dialog({resizable: false, height: 170, autoOpen: false,
|
||||
buttons: {
|
||||
"<fmt:message key="common.delete"/>": function() {
|
||||
location.href = "podcastReceiverAdmin.view?channelId=${model.channel.id}" +
|
||||
"&deleteChannel=${model.channel.id}";
|
||||
},
|
||||
"<fmt:message key="common.cancel"/>": function() {
|
||||
$(this).dialog("close");
|
||||
}
|
||||
}});
|
||||
}
|
||||
|
||||
function downloadSelected() {
|
||||
location.href = "podcastReceiverAdmin.view?channelId=${model.channel.id}" +
|
||||
"&downloadEpisode=" + getSelectedEpisodes();
|
||||
}
|
||||
|
||||
function deleteChannel() {
|
||||
$("#dialog-delete").dialog("open");
|
||||
}
|
||||
|
||||
function deleteSelected() {
|
||||
location.href = "podcastReceiverAdmin.view?channelId=${model.channel.id}" +
|
||||
"&deleteEpisode=" + getSelectedEpisodes();
|
||||
}
|
||||
|
||||
function refreshChannels() {
|
||||
location.href = "podcastReceiverAdmin.view?refresh&channelId=${model.channel.id}";
|
||||
}
|
||||
|
||||
function refreshPage() {
|
||||
location.href = "podcastChannel.view?id=${model.channel.id}";
|
||||
}
|
||||
|
||||
function getSelectedEpisodes() {
|
||||
var result = "";
|
||||
for (var i = 0; i < ${fn:length(model.episodes)}; i++) {
|
||||
var checkbox = $("#episode" + i);
|
||||
if (checkbox.is(":checked")) {
|
||||
result += (checkbox.val() + " ");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1" onload="init()">
|
||||
|
||||
<div style="float:left;margin-right:1.5em;margin-bottom:1.5em">
|
||||
<c:import url="coverArt.jsp">
|
||||
<c:param name="podcastChannelId" value="${model.channel.id}"/>
|
||||
<c:param name="coverArtSize" value="200"/>
|
||||
</c:import>
|
||||
</div>
|
||||
|
||||
<h1 id="name"><a href="podcastChannels.view"><fmt:message key="podcastreceiver.title"/></a> » ${fn:escapeXml(model.channel.title)}</h1>
|
||||
<h2>
|
||||
<span class="header"><a href="javascript:top.playQueue.onPlayPodcastChannel(${model.channel.id})"><fmt:message key="common.play"/></a></span>
|
||||
|
||||
<c:if test="${model.user.podcastRole}">
|
||||
| <span class="header"><a href="javascript:deleteChannel()"><fmt:message key="common.delete"/></a></span>
|
||||
| <span class="header"><a href="javascript:refreshChannels()"><fmt:message key="podcastreceiver.check"/></a></span>
|
||||
</c:if>
|
||||
</h2>
|
||||
|
||||
<div class="detail" style="padding-top:0.2em;white-space:normal;width:80%">${fn:escapeXml(model.channel.description)}</div>
|
||||
|
||||
<div class="detail" style="padding-top:1.0em">
|
||||
<fmt:message key="podcastreceiver.episodes"><fmt:param value="${fn:length(model.episodes)}"/></fmt:message> –
|
||||
<fmt:message key="podcastreceiver.status.${fn:toLowerCase(model.channel.status)}"/>
|
||||
<c:if test="${model.channel.status eq 'ERROR'}">
|
||||
<span class="warning">${model.channel.errorMessage}</span>
|
||||
</c:if>
|
||||
</div>
|
||||
|
||||
<div style="height:0.7em;clear:both"></div>
|
||||
|
||||
<table class="music">
|
||||
<c:forEach items="${model.episodes}" var="episode" varStatus="i">
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="fit"><input type="checkbox" class="checkbox" id="episode${i.index}" value="${episode.id}"/></td>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${empty episode.mediaFileId or episode.status ne 'COMPLETED'}">
|
||||
<td colspan="4"></td>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<c:import url="playButtons.jsp">
|
||||
<c:param name="id" value="${episode.mediaFileId}"/>
|
||||
<c:param name="playEnabled" value="${model.user.streamRole and not model.partyMode}"/>
|
||||
<c:param name="addEnabled" value="${model.user.streamRole and not model.partyMode}"/>
|
||||
<c:param name="asTable" value="true"/>
|
||||
<c:param name="onPlay" value="top.playQueue.onPlayPodcastEpisode(${episode.id})"/>
|
||||
</c:import>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<td class="truncate">
|
||||
<span title="${episode.title}" class="songTitle">${episode.title}</span>
|
||||
</td>
|
||||
|
||||
<td class="fit">
|
||||
<span class="detail">${episode.duration}</span>
|
||||
</td>
|
||||
|
||||
<td class="fit">
|
||||
<span class="detail"><fmt:formatDate value="${episode.publishDate}" dateStyle="medium"/></span>
|
||||
</td>
|
||||
|
||||
<td class="fit" style="text-align:center">
|
||||
<span class="detail">
|
||||
<c:choose>
|
||||
<c:when test="${episode.status eq 'DOWNLOADING'}">
|
||||
<fmt:formatNumber type="percent" value="${episode.completionRate}"/>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<fmt:message key="podcastreceiver.status.${fn:toLowerCase(episode.status)}"/>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="truncate">
|
||||
<c:choose>
|
||||
<c:when test="${episode.status eq 'ERROR'}">
|
||||
<span class="detail warning" title="${episode.errorMessage}">${episode.errorMessage}</span>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<span class="detail" title="${episode.description}">${episode.description}</span>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</c:forEach>
|
||||
|
||||
</table>
|
||||
|
||||
<table style="padding-top:1em"><tr>
|
||||
<c:if test="${model.user.podcastRole}">
|
||||
<td style="padding-right:2em"><div class="forward"><a href="javascript:downloadSelected()"><fmt:message key="podcastreceiver.downloadselected"/></a></div></td>
|
||||
<td style="padding-right:2em"><div class="forward"><a href="javascript:deleteSelected()"><fmt:message key="podcastreceiver.deleteselected"/></a></div></td>
|
||||
</c:if>
|
||||
<td style="padding-right:2em"><div class="forward"><a href="javascript:refreshPage()"><fmt:message key="podcastreceiver.refresh"/></a></div></td>
|
||||
<c:if test="${model.user.adminRole}">
|
||||
<td style="padding-right:2em"><div class="forward"><a href="podcastSettings.view?"><fmt:message key="podcastreceiver.settings"/></a></div></td>
|
||||
</c:if>
|
||||
</tr></table>
|
||||
|
||||
|
||||
<div id="dialog-delete" title="<fmt:message key="common.confirm"/>" style="display: none;">
|
||||
<p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>
|
||||
<fmt:message key="podcastreceiver.confirmdelete"/></p>
|
||||
</div>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,114 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<%--
|
||||
~ This file is part of Libresonic.
|
||||
~
|
||||
~ Libresonic 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
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ Libresonic 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 Libresonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
~
|
||||
~ Copyright 2015 (C) Sindre Mehus
|
||||
--%>
|
||||
|
||||
<%--@elvariable id="model" type="java.util.Map"--%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
</head><body class="mainframe bgcolor1">
|
||||
|
||||
<h1 style="padding-bottom: 1em">
|
||||
<img src="<spring:theme code="podcastLargeImage"/>" alt="">
|
||||
<span style="vertical-align: middle"><fmt:message key="podcastreceiver.title"/></span>
|
||||
</h1>
|
||||
|
||||
<c:if test="${empty model.channels}">
|
||||
<p><em><fmt:message key="podcastreceiver.empty"/></em></p>
|
||||
</c:if>
|
||||
|
||||
<c:forEach items="${model.channels}" var="channel" varStatus="loopStatus">
|
||||
|
||||
<c:set var="caption2">
|
||||
<fmt:message key="podcastreceiver.episodes"><fmt:param value="${fn:length(channel.value)}"/></fmt:message>
|
||||
</c:set>
|
||||
<div class="albumThumb">
|
||||
<c:import url="coverArt.jsp">
|
||||
<c:param name="podcastChannelId" value="${channel.key.id}"/>
|
||||
<c:param name="coverArtSize" value="200"/>
|
||||
<c:param name="caption1" value="${fn:escapeXml(channel.key.title)}"/>
|
||||
<c:param name="caption2" value="${caption2}"/>
|
||||
<c:param name="captionCount" value="2"/>
|
||||
<c:param name="showLink" value="true"/>
|
||||
<c:param name="appearAfter" value="${loopStatus.count * 30}"/>
|
||||
</c:import>
|
||||
</div>
|
||||
|
||||
</c:forEach>
|
||||
|
||||
<c:if test="${not empty model.newestEpisodes}">
|
||||
<h2 style="margin-top:1em"><fmt:message key="podcastreceiver.newestepisodes"/></h2>
|
||||
<table class="music indent">
|
||||
<c:forEach items="${model.newestEpisodes}" var="episode" varStatus="i">
|
||||
<tr>
|
||||
<c:import url="playButtons.jsp">
|
||||
<c:param name="id" value="${episode.mediaFileId}"/>
|
||||
<c:param name="podcastEpisodeId" value="${episode.id}"/>
|
||||
<c:param name="playEnabled" value="${model.user.streamRole and not model.partyMode}"/>
|
||||
<c:param name="addEnabled" value="${model.user.streamRole and not model.partyMode}"/>
|
||||
<c:param name="asTable" value="true"/>
|
||||
<c:param name="onPlay" value="top.playQueue.onPlayNewestPodcastEpisode(${i.index})"/>
|
||||
</c:import>
|
||||
<c:set var="channelTitle" value="${model.channelMap[episode.channelId].title}"/>
|
||||
|
||||
<td class="truncate">
|
||||
<span title="${episode.title}" class="songTitle">${episode.title}</span>
|
||||
</td>
|
||||
|
||||
<td class="truncate">
|
||||
<a href="podcastChannel.view?id=${episode.channelId}"><span class="detail" title="${channelTitle}">${channelTitle}</span></a>
|
||||
</td>
|
||||
|
||||
<td class="fit">
|
||||
<span class="detail">${episode.duration}</span>
|
||||
</td>
|
||||
|
||||
<td class="fit">
|
||||
<span class="detail"><fmt:formatDate value="${episode.publishDate}" dateStyle="medium"/></span>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</table>
|
||||
</c:if>
|
||||
|
||||
<table style="padding-top:1em"><tr>
|
||||
<c:if test="${model.user.podcastRole}">
|
||||
<td style="padding-right:2em"><div class="forward"><a href="podcastReceiverAdmin.view?refresh"><fmt:message key="podcastreceiver.check"/></a></div></td>
|
||||
</c:if>
|
||||
<c:if test="${model.user.adminRole}">
|
||||
<td style="padding-right:2em"><div class="forward"><a href="podcastSettings.view?"><fmt:message key="podcastreceiver.settings"/></a></div></td>
|
||||
</c:if>
|
||||
</tr></table>
|
||||
|
||||
<c:if test="${model.user.podcastRole}">
|
||||
<form:form method="post" action="podcastReceiverAdmin.view?">
|
||||
<table>
|
||||
<tr>
|
||||
<td><fmt:message key="podcastreceiver.subscribe"/></td>
|
||||
<td><input type="text" name="add" value="http://" style="width:30em" onclick="select()"/></td>
|
||||
<td><input type="submit" value="<fmt:message key="common.ok"/>"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form:form>
|
||||
</c:if>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,91 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
<%--@elvariable id="command" type="org.libresonic.player.command.PodcastSettingsCommand"--%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1">
|
||||
|
||||
<c:import url="settingsHeader.jsp">
|
||||
<c:param name="cat" value="podcast"/>
|
||||
<c:param name="toast" value="${settings_toast}"/>
|
||||
</c:import>
|
||||
|
||||
<form:form commandName="command" action="podcastSettings.view" method="post">
|
||||
|
||||
<table class="indent">
|
||||
<tr>
|
||||
<td><fmt:message key="podcastsettings.update"/></td>
|
||||
<td>
|
||||
<form:select path="interval" cssStyle="width:20em">
|
||||
<fmt:message key="podcastsettings.interval.manually" var="never"/>
|
||||
<fmt:message key="podcastsettings.interval.hourly" var="hourly"/>
|
||||
<fmt:message key="podcastsettings.interval.daily" var="daily"/>
|
||||
<fmt:message key="podcastsettings.interval.weekly" var="weekly"/>
|
||||
|
||||
<form:option value="-1" label="${never}"/>
|
||||
<form:option value="1" label="${hourly}"/>
|
||||
<form:option value="24" label="${daily}"/>
|
||||
<form:option value="168" label="${weekly}"/>
|
||||
</form:select>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="podcastsettings.keep"/></td>
|
||||
<td>
|
||||
<form:select path="episodeRetentionCount" cssStyle="width:20em">
|
||||
<fmt:message key="podcastsettings.keep.all" var="all"/>
|
||||
<fmt:message key="podcastsettings.keep.one" var="one"/>
|
||||
|
||||
<form:option value="-1" label="${all}"/>
|
||||
<form:option value="1" label="${one}"/>
|
||||
|
||||
<c:forTokens items="2 3 4 5 10 20 30 50" delims=" " var="count">
|
||||
<fmt:message key="podcastsettings.keep.many" var="many"><fmt:param value="${count}"/></fmt:message>
|
||||
<form:option value="${count}" label="${many}"/>
|
||||
</c:forTokens>
|
||||
|
||||
</form:select>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="podcastsettings.download"/></td>
|
||||
<td>
|
||||
<form:select path="episodeDownloadCount" cssStyle="width:20em">
|
||||
<fmt:message key="podcastsettings.download.all" var="all"/>
|
||||
<fmt:message key="podcastsettings.download.one" var="one"/>
|
||||
<fmt:message key="podcastsettings.download.none" var="none"/>
|
||||
|
||||
<form:option value="-1" label="${all}"/>
|
||||
<form:option value="1" label="${one}"/>
|
||||
|
||||
<c:forTokens items="2 3 4 5 10" delims=" " var="count">
|
||||
<fmt:message key="podcastsettings.download.many" var="many"><fmt:param value="${count}"/></fmt:message>
|
||||
<form:option value="${count}" label="${many}"/>
|
||||
</c:forTokens>
|
||||
<form:option value="0" label="${none}"/>
|
||||
|
||||
</form:select>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><fmt:message key="podcastsettings.folder"/></td>
|
||||
<td><form:input path="folder" cssStyle="width:20em"/></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td style="padding-top:1.5em" colspan="2">
|
||||
<input type="submit" value="<fmt:message key="common.save"/>" style="margin-right:0.3em">
|
||||
<input type="button" value="<fmt:message key="common.cancel"/>" onclick="location.href='nowPlaying.view'">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
</form:form>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,51 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<%@ include file="include.jsp" %>
|
||||
|
||||
<%--
|
||||
Creates HTML for displaying the rating stars.
|
||||
PARAMETERS
|
||||
id: Album ID. May be null if readonly.
|
||||
readonly: Whether rating can be changed.
|
||||
rating: The rating, an integer from 0 (no rating), through 10 (lowest rating), to 50 (highest rating).
|
||||
--%>
|
||||
|
||||
<c:forEach var="i" begin="1" end="5">
|
||||
|
||||
<sub:url value="setRating.view" var="ratingUrl">
|
||||
<sub:param name="id" value="${param.id}"/>
|
||||
<sub:param name="action" value="rating"/>
|
||||
<sub:param name="rating" value="${i}"/>
|
||||
</sub:url>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${param.rating ge i * 10}">
|
||||
<spring:theme code="ratingOnImage" var="imageUrl"/>
|
||||
</c:when>
|
||||
<c:when test="${param.rating ge i*10 - 7 and param.rating le i*10 - 3}">
|
||||
<spring:theme code="ratingHalfImage" var="imageUrl"/>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<spring:theme code="ratingOffImage" var="imageUrl"/>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${param.readonly}">
|
||||
<img src="${imageUrl}" style="margin-right:-3px" alt="" title="<fmt:message key="rating.rating"/> ${param.rating/10}">
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<a href="${ratingUrl}"><img src="${imageUrl}" style="margin-right:-3px" alt="" title="<fmt:message key="rating.rating"/> ${i}"></a>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
</c:forEach>
|
||||
|
||||
<sub:url value="setRating.view" var="clearRatingUrl">
|
||||
<sub:param name="id" value="${param.id}"/>
|
||||
<sub:param name="action" value="rating"/>
|
||||
<sub:param name="rating" value="0"/>
|
||||
</sub:url>
|
||||
|
||||
<c:if test="${not param.readonly}">
|
||||
| <a href="${clearRatingUrl}"><img src="<spring:theme code="clearRatingImage"/>" alt="" title="<fmt:message key="rating.clearrating"/>" style="margin-right:5px"></a>
|
||||
</c:if>
|
||||
@@ -0,0 +1,44 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<%@ include file="head.jsp" %>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1" onload="document.getElementById('usernameOrEmail').focus()">
|
||||
|
||||
<form action="recover.view" method="POST">
|
||||
<sec:csrfInput />
|
||||
<div class="bgcolor2 shadow" style="padding:20px 50px 20px 50px; margin-top:100px;margin-left:50px;margin-right:50px">
|
||||
|
||||
<div style="margin-left: auto; margin-right: auto; width: 45em">
|
||||
|
||||
<h1><fmt:message key="recover.title"/></h1>
|
||||
<p style="padding-top: 1em; padding-bottom: 0.5em"><fmt:message key="recover.text"/></p>
|
||||
|
||||
<c:if test="${empty model.sentTo}">
|
||||
<input type="text" id="usernameOrEmail" name="usernameOrEmail" style="width:18em;margin-right: 1em">
|
||||
<input name="submit" type="submit" value="<fmt:message key="recover.send"/>">
|
||||
</c:if>
|
||||
|
||||
<c:if test="${not empty model.captcha}">
|
||||
<p style="padding-top: 1em">
|
||||
<c:out value="${model.captcha}" escapeXml="false"/>
|
||||
</p>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${not empty model.sentTo}">
|
||||
<p style="padding-top: 1em"><fmt:message key="recover.success"><fmt:param value="${model.sentTo}"/></fmt:message></p>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${not empty model.error}">
|
||||
<p style="padding-top: 1em" class="warning"><fmt:message key="${model.error}"/></p>
|
||||
</c:if>
|
||||
|
||||
<div class="back" style="margin-top: 1.5em"><a href="login.view"><fmt:message key="common.back"/></a></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,11 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
</head><body>
|
||||
|
||||
<c:forEach items="${model.reloadFrames}" var="reloadFrame">
|
||||
<script language="javascript" type="text/javascript">parent.frames.${reloadFrame.frame}.location.href="${reloadFrame.view}"</script>
|
||||
</c:forEach>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,141 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<%@ include file="../include.jsp" %>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<link rel="stylesheet" href="../<spring:theme code="styleSheet"/>" type="text/css">
|
||||
|
||||
<c:url value="/rest/stream.view" var="streamUrl">
|
||||
<c:param name="c" value="${model.c}"/>
|
||||
<c:param name="v" value="${model.v}"/>
|
||||
<c:param name="id" value="${model.id}"/>
|
||||
</c:url>
|
||||
|
||||
<script type="text/javascript" src="<c:url value="/script/swfobject.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/prototype.js"/>"></script>
|
||||
<script type="text/javascript" language="javascript">
|
||||
|
||||
var player;
|
||||
var position;
|
||||
var maxBitRate = ${model.maxBitRate};
|
||||
var timeOffset = ${model.timeOffset};
|
||||
|
||||
function init() {
|
||||
var flashvars = {
|
||||
id:"player1",
|
||||
skin:"<c:url value="/flash/whotube.zip"/>",
|
||||
screencolor:"000000",
|
||||
autostart:false,
|
||||
bufferlength:4,
|
||||
backcolor:"<spring:theme code="backgroundColor"/>",
|
||||
frontcolor:"<spring:theme code="textColor"/>",
|
||||
provider:"video"
|
||||
};
|
||||
var params = {
|
||||
allowfullscreen:"true",
|
||||
allowscriptaccess:"always"
|
||||
};
|
||||
var attributes = {
|
||||
id:"player1",
|
||||
name:"player1"
|
||||
};
|
||||
|
||||
swfobject.embedSWF("<c:url value="/flash/jw-player-5.10.swf"/>", "placeholder1", "360", "240", "9.0.0", false, flashvars, params, attributes);
|
||||
}
|
||||
|
||||
function playerReady(thePlayer) {
|
||||
player = $("player1");
|
||||
player.addModelListener("TIME", "timeListener");
|
||||
|
||||
<c:if test="${model.autoplay}">
|
||||
play();
|
||||
</c:if>
|
||||
}
|
||||
|
||||
function play() {
|
||||
var list = new Array();
|
||||
list[0] = {
|
||||
file:"${streamUrl}&maxBitRate=" + maxBitRate + "&timeOffset=" + timeOffset + "&p=${model.p}" + "&u=${model.u}",
|
||||
duration:${model.duration} - timeOffset,
|
||||
provider:"video"
|
||||
};
|
||||
player.sendEvent("LOAD", list);
|
||||
player.sendEvent("PLAY");
|
||||
}
|
||||
|
||||
function timeListener(obj) {
|
||||
var newPosition = Math.round(obj.position);
|
||||
if (newPosition != position) {
|
||||
position = newPosition;
|
||||
updatePosition();
|
||||
}
|
||||
}
|
||||
|
||||
function updatePosition() {
|
||||
var pos = parseInt(timeOffset) + parseInt(position);
|
||||
|
||||
var minutes = Math.round(pos / 60);
|
||||
var seconds = pos % 60;
|
||||
|
||||
var result = minutes + ":";
|
||||
if (seconds < 10) {
|
||||
result += "0";
|
||||
}
|
||||
result += seconds;
|
||||
$("position").innerHTML = result;
|
||||
}
|
||||
|
||||
function changeTimeOffset() {
|
||||
timeOffset = $("timeOffset").getValue();
|
||||
play();
|
||||
}
|
||||
|
||||
function changeBitRate() {
|
||||
maxBitRate = $("maxBitRate").getValue();
|
||||
timeOffset = parseInt(timeOffset) + parseInt(position);
|
||||
play();
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body class="mainframe bgcolor1" onload="init();">
|
||||
<h1>${model.video.title}</h1>
|
||||
|
||||
<div id="wrapper" style="padding-top:1em">
|
||||
<div id="placeholder1"><span class="warning"><a href="http://www.adobe.com/go/getflashplayer"><fmt:message key="playlist.getflash"/></a></span></div>
|
||||
</div>
|
||||
|
||||
<div style="padding-top:1.3em;padding-bottom:0.7em;font-size:16px">
|
||||
|
||||
<span id="progress" style="padding-right:0.5em">0:00</span>
|
||||
<select id="timeOffset" onchange="changeTimeOffset();" style="padding-left:0.25em;padding-right:0.25em;margin-right:0.5em;font-size:16px">
|
||||
<c:forEach items="${model.skipOffsets}" var="skipOffset">
|
||||
<c:choose>
|
||||
<c:when test="${skipOffset.value eq model.timeOffset}">
|
||||
<option selected="selected" value="${skipOffset.value}">${skipOffset.key}</option>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<option value="${skipOffset.value}">${skipOffset.key}</option>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</c:forEach>
|
||||
</select>
|
||||
|
||||
<select id="maxBitRate" onchange="changeBitRate();" style="padding-left:0.25em;padding-right:0.25em;margin-right:0.5em;font-size:16px">
|
||||
<c:forEach items="${model.bitRates}" var="bitRate">
|
||||
<c:choose>
|
||||
<c:when test="${bitRate eq model.maxBitRate}">
|
||||
<option selected="selected" value="${bitRate}">${bitRate} Kbps</option>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<option value="${bitRate}">${bitRate} Kbps</option>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</c:forEach>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,98 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/engine.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/util.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/nowPlayingService.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/scripts-2.0.js"/>"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
function init() {
|
||||
dwr.engine.setErrorHandler(null);
|
||||
|
||||
startGetScanningStatusTimer();
|
||||
|
||||
<c:if test="${model.showNowPlaying}">
|
||||
startGetNowPlayingTimer();
|
||||
</c:if>
|
||||
|
||||
}
|
||||
|
||||
function startGetNowPlayingTimer() {
|
||||
nowPlayingService.getNowPlaying(getNowPlayingCallback);
|
||||
setTimeout("startGetNowPlayingTimer()", 10000);
|
||||
}
|
||||
|
||||
function getNowPlayingCallback(nowPlaying) {
|
||||
var html = nowPlaying.length == 0 ? "" : "<h2><fmt:message key="main.nowplaying"/></h2><table style='width:100%'>";
|
||||
for (var i = 0; i < nowPlaying.length; i++) {
|
||||
html += "<tr><td colspan='2' class='detail' style='padding-top:1em;white-space:nowrap'>";
|
||||
|
||||
if (nowPlaying[i].avatarUrl != null) {
|
||||
html += "<img src='" + nowPlaying[i].avatarUrl + "' style='padding-right:5pt;width:30px;height:30px'>";
|
||||
}
|
||||
html += "<b>" + nowPlaying[i].username + "</b></td></tr>";
|
||||
|
||||
html += "<tr><td class='detail' style='padding-right:1em'>" +
|
||||
"<a title='" + nowPlaying[i].tooltip + "' target='main' href='" + nowPlaying[i].albumUrl + "'>";
|
||||
|
||||
if (nowPlaying[i].artist != null) {
|
||||
html += nowPlaying[i].artist + "<br/>";
|
||||
}
|
||||
|
||||
html += "<span class='songTitle'>" + nowPlaying[i].title + "</span></a><br/>";
|
||||
if (nowPlaying[i].lyricsUrl != null) {
|
||||
html += "<span class='forward'><a href='" + nowPlaying[i].lyricsUrl + "' onclick=\"return popupSize(this, 'lyrics', 500, 550)\">" +
|
||||
"<fmt:message key="main.lyrics"/>" + "</a></span>";
|
||||
}
|
||||
html += "</td><td>" +
|
||||
"<a title='" + nowPlaying[i].tooltip + "' target='main' href='" + nowPlaying[i].albumUrl + "'>" +
|
||||
"<img src='" + nowPlaying[i].coverArtUrl + "' class='dropshadow' height='60' width='60'></a>" +
|
||||
"</td></tr>";
|
||||
|
||||
var minutesAgo = nowPlaying[i].minutesAgo;
|
||||
if (minutesAgo > 4) {
|
||||
html += "<tr><td class='detail' colspan='2'>" + minutesAgo + " <fmt:message key="main.minutesago"/></td></tr>";
|
||||
}
|
||||
}
|
||||
html += "</table>";
|
||||
$("#nowPlaying").html(html);
|
||||
}
|
||||
|
||||
function startGetScanningStatusTimer() {
|
||||
nowPlayingService.getScanningStatus(getScanningStatusCallback);
|
||||
}
|
||||
|
||||
function getScanningStatusCallback(scanInfo) {
|
||||
$("#scanCount").text(scanInfo.count);
|
||||
if (scanInfo.scanning) {
|
||||
$("#scanningStatus").show();
|
||||
setTimeout("startGetScanningStatusTimer()", 1000);
|
||||
} else {
|
||||
$("#scanningStatus").hide();
|
||||
setTimeout("startGetScanningStatusTimer()", 15000);
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body class="bgcolor1 rightframe" style="padding-top:2em" onload="init()">
|
||||
|
||||
<c:if test="${model.newVersionAvailable}">
|
||||
<div class="warning" style="padding-bottom: 1em">
|
||||
<fmt:message key="top.upgrade"><fmt:param value="${model.brand}"/><fmt:param value="${model.latestVersion}"/></fmt:message>
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<div id="scanningStatus" style="display: none;" class="warning">
|
||||
<img src="<spring:theme code="scanningImage"/>" title="" alt=""> <fmt:message key="main.scanning"/> <span id="scanCount"></span>
|
||||
</div>
|
||||
|
||||
<div id="nowPlaying"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,124 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<%--@elvariable id="command" type="org.libresonic.player.command.SearchCommand"--%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
|
||||
<script type="text/javascript" language="javascript">
|
||||
|
||||
function showMoreArtists() {
|
||||
$('.artistRow').show(); $('#moreArtists').hide();
|
||||
}
|
||||
|
||||
function showMoreAlbums() {
|
||||
$('.albumRow').show(); $('#moreAlbums').hide();
|
||||
}
|
||||
|
||||
function showMoreSongs() {
|
||||
$('.songRow').show();$('#moreSongs').hide();
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1">
|
||||
|
||||
<h1>
|
||||
<img src="<spring:theme code="searchImage"/>" alt=""/>
|
||||
<span style="vertical-align: middle"><fmt:message key="search.title"/></span>
|
||||
</h1>
|
||||
|
||||
<c:if test="${command.indexBeingCreated}">
|
||||
<p class="warning"><fmt:message key="search.index"/></p>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${not command.indexBeingCreated and empty command.artists and empty command.albums and empty command.songs}">
|
||||
<p class="warning"><fmt:message key="search.hits.none"/></p>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${not empty command.artists}">
|
||||
<h2><b><fmt:message key="search.hits.artists"/></b></h2>
|
||||
<table class="music indent">
|
||||
<c:forEach items="${command.artists}" var="match" varStatus="loopStatus">
|
||||
|
||||
<sub:url value="/main.view" var="mainUrl">
|
||||
<sub:param name="path" value="${match.path}"/>
|
||||
</sub:url>
|
||||
|
||||
<tr class="artistRow" ${loopStatus.count > 5 ? "style='display:none'" : ""}>
|
||||
<c:import url="playButtons.jsp">
|
||||
<c:param name="id" value="${match.id}"/>
|
||||
<c:param name="playEnabled" value="${command.user.streamRole and not command.partyModeEnabled}"/>
|
||||
<c:param name="addEnabled" value="${command.user.streamRole and (not command.partyModeEnabled or not match.directory)}"/>
|
||||
<c:param name="asTable" value="true"/>
|
||||
</c:import>
|
||||
<td class="truncate"><a href="${mainUrl}">${fn:escapeXml(match.name)}</a></td>
|
||||
</tr>
|
||||
|
||||
</c:forEach>
|
||||
</table>
|
||||
<c:if test="${fn:length(command.artists) gt 5}">
|
||||
<div id="moreArtists" class="forward"><a href="javascript:showMoreArtists()"><fmt:message key="search.hits.more"/></a></div>
|
||||
</c:if>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${not empty command.albums}">
|
||||
<h2><b><fmt:message key="search.hits.albums"/></b></h2>
|
||||
<table class="music indent">
|
||||
<c:forEach items="${command.albums}" var="match" varStatus="loopStatus">
|
||||
|
||||
<sub:url value="/main.view" var="mainUrl">
|
||||
<sub:param name="path" value="${match.path}"/>
|
||||
</sub:url>
|
||||
|
||||
<tr class="albumRow" ${loopStatus.count > 5 ? "style='display:none'" : ""}>
|
||||
<c:import url="playButtons.jsp">
|
||||
<c:param name="id" value="${match.id}"/>
|
||||
<c:param name="playEnabled" value="${command.user.streamRole and not command.partyModeEnabled}"/>
|
||||
<c:param name="addEnabled" value="${command.user.streamRole and (not command.partyModeEnabled or not match.directory)}"/>
|
||||
<c:param name="asTable" value="true"/>
|
||||
</c:import>
|
||||
|
||||
<td class="truncate"><a href="${mainUrl}">${fn:escapeXml(match.albumName)}</a></td>
|
||||
<td class="truncate"><span class="detail">${fn:escapeXml(match.artist)}</span></td>
|
||||
</tr>
|
||||
|
||||
</c:forEach>
|
||||
</table>
|
||||
<c:if test="${fn:length(command.albums) gt 5}">
|
||||
<div id="moreAlbums" class="forward"><a href="javascript:showMoreAlbums()"><fmt:message key="search.hits.more"/></a></div>
|
||||
</c:if>
|
||||
</c:if>
|
||||
|
||||
|
||||
<c:if test="${not empty command.songs}">
|
||||
<h2><b><fmt:message key="search.hits.songs"/></b></h2>
|
||||
<table class="music indent">
|
||||
<c:forEach items="${command.songs}" var="match" varStatus="loopStatus">
|
||||
|
||||
<sub:url value="/main.view" var="mainUrl">
|
||||
<sub:param name="path" value="${match.parentPath}"/>
|
||||
</sub:url>
|
||||
|
||||
<tr class="songRow" ${loopStatus.count > 15 ? "style='display:none'" : ""}>
|
||||
<c:import url="playButtons.jsp">
|
||||
<c:param name="id" value="${match.id}"/>
|
||||
<c:param name="playEnabled" value="${command.user.streamRole and not command.partyModeEnabled}"/>
|
||||
<c:param name="addEnabled" value="${command.user.streamRole and (not command.partyModeEnabled or not match.directory)}"/>
|
||||
<c:param name="video" value="${match.video and command.player.web}"/>
|
||||
<c:param name="asTable" value="true"/>
|
||||
</c:import>
|
||||
|
||||
<td class="truncate"><span class="songTitle">${fn:escapeXml(match.title)}</span></td>
|
||||
<td class="truncate"><a href="${mainUrl}"><span class="detail">${fn:escapeXml(match.albumName)}</span></a></td>
|
||||
<td class="truncate"><span class="detail">${fn:escapeXml(match.artist)}</span></td>
|
||||
</tr>
|
||||
|
||||
</c:forEach>
|
||||
</table>
|
||||
<c:if test="${fn:length(command.songs) gt 15}">
|
||||
<div id="moreSongs" class="forward"><a href="javascript:showMoreSongs()"><fmt:message key="search.hits.more"/></a></div>
|
||||
</c:if>
|
||||
</c:if>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,39 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
<%@ include file="include.jsp" %>
|
||||
|
||||
<c:if test="${param.toast}">
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
$().toastmessage("showSuccessToast", "<fmt:message key="common.settingssaved"/>");
|
||||
});
|
||||
</script>
|
||||
</c:if>
|
||||
|
||||
<c:set var="categories" value="${param.restricted ? 'personal password player share' : 'musicFolder general advanced personal user player share dlna sonos transcoding internetRadio podcast database'}"/>
|
||||
<h1>
|
||||
<img src="<spring:theme code="settingsImage"/>" alt=""/>
|
||||
<span style="vertical-align: middle"><fmt:message key="settingsheader.title"/></span>
|
||||
</h1>
|
||||
|
||||
<h2>
|
||||
<c:forTokens items="${categories}" delims=" " var="cat" varStatus="loopStatus">
|
||||
<c:choose>
|
||||
<c:when test="${loopStatus.count > 1 and (loopStatus.count - 1) % 7 != 0}"> | </c:when>
|
||||
<c:otherwise></h2><h2></c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<c:url var="url" value="${cat}Settings.view?"/>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${param.cat eq cat}">
|
||||
<span class="headerSelected"><fmt:message key="settingsheader.${cat}"/></span>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<span class="header"><a href="${url}"><fmt:message key="settingsheader.${cat}"/></a></span>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
</c:forTokens>
|
||||
</h2>
|
||||
|
||||
<p></p>
|
||||
@@ -0,0 +1,68 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
<%--@elvariable id="model" type="Map"--%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1">
|
||||
|
||||
<c:import url="settingsHeader.jsp">
|
||||
<c:param name="cat" value="share"/>
|
||||
<c:param name="toast" value="${settings_toast}"/>
|
||||
<c:param name="restricted" value="${not model.user.adminRole}"/>
|
||||
</c:import>
|
||||
|
||||
<form method="post" action="shareSettings.view">
|
||||
<sec:csrfInput />
|
||||
|
||||
<table class="music indent">
|
||||
<tr>
|
||||
<th style="padding-left:1em"><fmt:message key="sharesettings.name"/></th>
|
||||
<th style="padding-left:1em"><fmt:message key="sharesettings.owner"/></th>
|
||||
<th style="padding-left:1em"><fmt:message key="sharesettings.description"/></th>
|
||||
<th style="padding-left:1em"><fmt:message key="sharesettings.lastvisited"/></th>
|
||||
<th style="padding-left:1em"><fmt:message key="sharesettings.visits"/></th>
|
||||
<th style="padding-left:1em"><fmt:message key="sharesettings.files"/></th>
|
||||
<th style="padding-left:1em"><fmt:message key="sharesettings.expires"/></th>
|
||||
<th style="padding-left:1em"><fmt:message key="sharesettings.expirein"/></th>
|
||||
<th style="padding-left:1em"><fmt:message key="common.delete"/></th>
|
||||
</tr>
|
||||
|
||||
<c:forEach items="${model.shareInfos}" var="shareInfo" varStatus="loopStatus">
|
||||
<c:set var="share" value="${shareInfo.share}"/>
|
||||
|
||||
<c:url value="main.view" var="albumUrl">
|
||||
<c:param name="id" value="${shareInfo.dir.id}"/>
|
||||
</c:url>
|
||||
|
||||
<tr>
|
||||
<td style="padding-left:1em"><a href="${shareInfo.shareUrl}" target="_blank">${share.name}</a></td>
|
||||
<td style="padding-left:1em">${fn:escapeXml(share.username)}</td>
|
||||
<td style="padding-left:1em"><input type="text" name="description[${share.id}]" size="40" value="${share.description}"/></td>
|
||||
<td style="padding-left:1em"><fmt:formatDate value="${share.lastVisited}" type="date" dateStyle="medium"/></td>
|
||||
<td style="padding-left:1em; text-align:right">${share.visitCount}</td>
|
||||
<td style="padding-left:1em"><a href="${albumUrl}" title="${shareInfo.dir.name}"><str:truncateNicely upper="30">${fn:escapeXml(shareInfo.dir.name)}</str:truncateNicely></a></td>
|
||||
<td style="padding-left:1em"><fmt:formatDate value="${share.expires}" type="date" dateStyle="medium"/></td>
|
||||
<td style="padding-left:1em">
|
||||
<label><input type="radio" name="expireIn[${share.id}]" value="7"><fmt:message key="sharesettings.expirein.week"/></label>
|
||||
<label><input type="radio" name="expireIn[${share.id}]" value="30"><fmt:message key="sharesettings.expirein.month"/></label>
|
||||
<label><input type="radio" name="expireIn[${share.id}]" value="365"><fmt:message key="sharesettings.expirein.year"/></label>
|
||||
<label><input type="radio" name="expireIn[${share.id}]" value="0"><fmt:message key="sharesettings.expirein.never"/></label>
|
||||
</td>
|
||||
<td style="padding-left:1em" align="center" style="padding-left:1em"><input type="checkbox" name="delete[${share.id}]" class="checkbox"/></td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
|
||||
</table>
|
||||
|
||||
<p style="padding-top:1em">
|
||||
<input type="submit" value="<fmt:message key="common.save"/>" style="margin-right:0.3em">
|
||||
<input type="button" value="<fmt:message key="common.cancel"/>" onclick="location.href='nowPlaying.view'" style="margin-right:2.0em">
|
||||
<input type="checkbox" id="deleteExpired" name="deleteExpired" class="checkbox"/>
|
||||
<label for="deleteExpired"><fmt:message key="sharesettings.deleteexpired"/></label>
|
||||
</p>
|
||||
|
||||
</form>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,64 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
<%--
|
||||
~ This file is part of Libresonic.
|
||||
~
|
||||
~ Libresonic 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
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ Libresonic 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 Libresonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
~
|
||||
~ Copyright 2015 (C) Sindre Mehus
|
||||
--%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value="/script/scripts.js"/>"></script>
|
||||
</head>
|
||||
|
||||
<body class="mainframe bgcolor1">
|
||||
<script type="text/javascript" src="<c:url value="/script/wz_tooltip.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/tip_balloon.js"/>"></script>
|
||||
|
||||
<c:import url="settingsHeader.jsp">
|
||||
<c:param name="cat" value="sonos"/>
|
||||
<c:param name="toast" value="${settings_toast}"/>
|
||||
</c:import>
|
||||
|
||||
<form method="post" action="sonosSettings.view">
|
||||
<sec:csrfInput />
|
||||
|
||||
<div>
|
||||
<input type="checkbox" name="sonosEnabled" id="sonosEnabled" class="checkbox"
|
||||
<c:if test="${model.sonosEnabled}">checked="checked"</c:if>/>
|
||||
<label for="sonosEnabled"><fmt:message key="sonossettings.enabled"/></label>
|
||||
</div>
|
||||
|
||||
<p class="detail" style="width:60%;white-space:normal">
|
||||
<fmt:message key="sonossettings.description"/>
|
||||
</p>
|
||||
<div>
|
||||
<fmt:message key="sonossettings.servicename"/>
|
||||
<input name="sonosServiceName" id="sonosServiceName" size="40"
|
||||
value="<c:out value="${model.sonosServiceName}" escapeXml="true"/>"/>
|
||||
</div>
|
||||
<p class="detail" style="width:60%;white-space:normal;padding-top:0">
|
||||
<fmt:message key="sonossettings.servicename.description"/>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<input type="submit" value="<fmt:message key="common.save"/>" style="margin-right:0.3em">
|
||||
<input type="button" value="<fmt:message key="common.cancel"/>" onclick="location.href='nowPlaying.view'">
|
||||
</p>
|
||||
|
||||
</form>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,182 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value="/script/scripts-2.0.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value='/dwr/util.js'/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/engine.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/starService.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/playlistService.js"/>"></script>
|
||||
<script type="text/javascript" language="javascript">
|
||||
|
||||
function toggleStar(mediaFileId, imageId) {
|
||||
if ($(imageId).attr("src").indexOf("<spring:theme code="ratingOnImage"/>") != -1) {
|
||||
$(imageId).attr("src", "<spring:theme code="ratingOffImage"/>");
|
||||
starService.unstar(mediaFileId);
|
||||
}
|
||||
else if ($(imageId).attr("src").indexOf("<spring:theme code="ratingOffImage"/>") != -1) {
|
||||
$(imageId).attr("src", "<spring:theme code="ratingOnImage"/>");
|
||||
starService.star(mediaFileId);
|
||||
}
|
||||
}
|
||||
|
||||
function onSavePlaylist() {
|
||||
playlistService.createPlaylistForStarredSongs(function (playlistId) {
|
||||
top.left.updatePlaylists();
|
||||
top.left.showAllPlaylists();
|
||||
top.main.location.href = "playlist.view?id=" + playlistId;
|
||||
$().toastmessage("showSuccessToast", "<fmt:message key="playlist.toast.saveasplaylist"/>");
|
||||
});
|
||||
}
|
||||
|
||||
function onPlayAll() {
|
||||
top.playQueue.onPlayStarred();
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1">
|
||||
|
||||
<h1>
|
||||
<img src="<spring:theme code="starredImage"/>" alt="">
|
||||
<span style="vertical-align: middle"><fmt:message key="starred.title"/></span>
|
||||
</h1>
|
||||
|
||||
<c:if test="${empty model.artists and empty model.albums and empty model.songs}">
|
||||
<p style="padding-top: 1em"><em><fmt:message key="starred.empty"/></em></p>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${not empty model.albums}">
|
||||
<h2><fmt:message key="search.hits.albums"/></h2>
|
||||
|
||||
<div style="padding-top:0.5em">
|
||||
<c:forEach items="${model.albums}" var="album" varStatus="loopStatus">
|
||||
|
||||
<c:set var="albumTitle">
|
||||
<c:choose>
|
||||
<c:when test="${empty album.name}">
|
||||
<fmt:message key="common.unknown"/>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
${fn:escapeXml(album.name)}
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</c:set>
|
||||
|
||||
<div class="albumThumb">
|
||||
<c:import url="coverArt.jsp">
|
||||
<c:param name="albumId" value="${album.id}"/>
|
||||
<c:param name="caption1" value="${albumTitle}"/>
|
||||
<c:param name="caption2" value="${fn:escapeXml(album.artist)}"/>
|
||||
<c:param name="captionCount" value="2"/>
|
||||
<c:param name="coverArtSize" value="${model.coverArtSize}"/>
|
||||
<c:param name="showLink" value="true"/>
|
||||
<c:param name="appearAfter" value="${loopStatus.count * 30}"/>
|
||||
<c:param name="hideOverflow" value="true"/>
|
||||
</c:import>
|
||||
</div>
|
||||
</c:forEach>
|
||||
</c:if>
|
||||
</div>
|
||||
|
||||
<c:if test="${not empty model.artists}">
|
||||
<h2><fmt:message key="search.hits.artists"/></h2>
|
||||
<table class="music indent">
|
||||
<c:forEach items="${model.artists}" var="artist">
|
||||
|
||||
<c:url value="/main.view" var="mainUrl">
|
||||
<c:param name="id" value="${artist.id}"/>
|
||||
</c:url>
|
||||
|
||||
<tr>
|
||||
<c:import url="playButtons.jsp">
|
||||
<c:param name="id" value="${artist.id}"/>
|
||||
<c:param name="playEnabled" value="${model.user.streamRole and not model.partyModeEnabled}"/>
|
||||
<c:param name="addEnabled" value="${model.user.streamRole and (not model.partyModeEnabled or not artist.directory)}"/>
|
||||
<c:param name="starEnabled" value="true"/>
|
||||
<c:param name="starred" value="${not empty artist.starredDate}"/>
|
||||
<c:param name="asTable" value="true"/>
|
||||
</c:import>
|
||||
<td class="truncate">
|
||||
<a href="${mainUrl}">${fn:escapeXml(artist.name)}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</table>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${not empty model.songs}">
|
||||
<h2><fmt:message key="search.hits.songs"/></h2>
|
||||
<table class="music indent">
|
||||
<c:forEach items="${model.songs}" var="song">
|
||||
|
||||
<sub:url value="/main.view" var="mainUrl">
|
||||
<sub:param name="path" value="${song.parentPath}"/>
|
||||
</sub:url>
|
||||
|
||||
<tr>
|
||||
<c:import url="playButtons.jsp">
|
||||
<c:param name="id" value="${song.id}"/>
|
||||
<c:param name="playEnabled" value="${model.user.streamRole and not model.partyModeEnabled}"/>
|
||||
<c:param name="addEnabled" value="${model.user.streamRole and not model.partyModeEnabled}"/>
|
||||
<c:param name="starEnabled" value="true"/>
|
||||
<c:param name="starred" value="${not empty song.starredDate}"/>
|
||||
<c:param name="video" value="false"/>
|
||||
<c:param name="asTable" value="true"/>
|
||||
</c:import>
|
||||
|
||||
<td class="truncate">
|
||||
${fn:escapeXml(song.title)}
|
||||
</td>
|
||||
|
||||
<td class="truncate">
|
||||
<a href="${mainUrl}"><span class="detail">${fn:escapeXml(song.albumName)}</span></a>
|
||||
</td>
|
||||
|
||||
<td class="truncate">
|
||||
<span class="detail">${fn:escapeXml(song.artist)}</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</c:forEach>
|
||||
</table>
|
||||
|
||||
<div class="forward" style="float:left;padding-right:1.5em">
|
||||
<a href="javascript:noop()" onclick="onSavePlaylist()"><fmt:message key="playlist.save"/></a>
|
||||
</div>
|
||||
<div class="forward" style="float: left">
|
||||
<a href="javascript:noop()" onclick="onPlayAll()"><fmt:message key="main.playall"/></a>
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
|
||||
</c:if>
|
||||
|
||||
<c:if test="${not empty model.videos}">
|
||||
<h2><fmt:message key="search.hits.videos"/></h2>
|
||||
<table class="music indent">
|
||||
<c:forEach items="${model.videos}" var="video">
|
||||
|
||||
<c:url value="/videoPlayer.view" var="videoUrl">
|
||||
<c:param name="id" value="${video.id}"/>
|
||||
</c:url>
|
||||
|
||||
<tr>
|
||||
<c:import url="playButtons.jsp">
|
||||
<c:param name="id" value="${video.id}"/>
|
||||
<c:param name="playEnabled" value="${model.user.streamRole and not model.partyModeEnabled}"/>
|
||||
<c:param name="addEnabled" value="${model.user.streamRole and not model.partyModeEnabled}"/>
|
||||
<c:param name="starEnabled" value="true"/>
|
||||
<c:param name="starred" value="${not empty video.starredDate}"/>
|
||||
<c:param name="video" value="${model.player.web}"/>
|
||||
<c:param name="asTable" value="true"/>
|
||||
</c:import>
|
||||
<td class="truncate">
|
||||
<a href="${videoUrl}">${fn:escapeXml(video.name)}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</table>
|
||||
</c:if>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,112 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<meta http-equiv="CACHE-CONTROL" content="NO-CACHE">
|
||||
<meta http-equiv="REFRESH" content="20;URL=status.view">
|
||||
</head>
|
||||
<body class="mainframe bgcolor1">
|
||||
|
||||
<h1>
|
||||
<img src="<spring:theme code="statusImage"/>" alt="">
|
||||
<span style="vertical-align: middle"><fmt:message key="status.title"/></span>
|
||||
</h1>
|
||||
|
||||
<table width="100%" class="ruleTable indent">
|
||||
<tr>
|
||||
<th class="ruleTableHeader"><fmt:message key="status.type"/></th>
|
||||
<th class="ruleTableHeader"><fmt:message key="status.player"/></th>
|
||||
<th class="ruleTableHeader"><fmt:message key="status.user"/></th>
|
||||
<th class="ruleTableHeader"><fmt:message key="status.current"/></th>
|
||||
<th class="ruleTableHeader"><fmt:message key="status.transmitted"/></th>
|
||||
<th class="ruleTableHeader"><fmt:message key="status.bitrate"/></th>
|
||||
</tr>
|
||||
|
||||
<c:forEach items="${model.transferStatuses}" var="status">
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${empty status.playerType}">
|
||||
<fmt:message key="common.unknown" var="type"/>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<c:set var="type" value="(${status.playerType})"/>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${status.stream}">
|
||||
<fmt:message key="status.stream" var="transferType"/>
|
||||
</c:when>
|
||||
<c:when test="${status.download}">
|
||||
<fmt:message key="status.download" var="transferType"/>
|
||||
</c:when>
|
||||
<c:when test="${status.upload}">
|
||||
<fmt:message key="status.upload" var="transferType"/>
|
||||
</c:when>
|
||||
</c:choose>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${empty status.username}">
|
||||
<fmt:message key="common.unknown" var="user"/>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<c:set var="user" value="${status.username}"/>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${empty status.path}">
|
||||
<fmt:message key="common.unknown" var="current"/>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<c:set var="current" value="${status.path}"/>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<sub:url value="/statusChart.view" var="chartUrl">
|
||||
<c:if test="${status.stream}">
|
||||
<sub:param name="type" value="stream"/>
|
||||
</c:if>
|
||||
<c:if test="${status.download}">
|
||||
<sub:param name="type" value="download"/>
|
||||
</c:if>
|
||||
<c:if test="${status.upload}">
|
||||
<sub:param name="type" value="upload"/>
|
||||
</c:if>
|
||||
<sub:param name="index" value="${status.index}"/>
|
||||
</sub:url>
|
||||
|
||||
<tr>
|
||||
<td class="ruleTableCell">${transferType}</td>
|
||||
<td class="ruleTableCell">${status.player}<br>${type}</td>
|
||||
<td class="ruleTableCell">${user}</td>
|
||||
<td class="ruleTableCell">${current}</td>
|
||||
<td class="ruleTableCell">${status.bytes}</td>
|
||||
<td class="ruleTableCell" width="${model.chartWidth}"><img width="${model.chartWidth}" height="${model.chartHeight}" src="${chartUrl}" alt=""></td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</table>
|
||||
|
||||
<table style="width:100%;padding-top:3em">
|
||||
<tr>
|
||||
<th><fmt:message key="home.chart.total"/></th>
|
||||
<th><fmt:message key="home.chart.stream"/></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="<c:url value="/userChart.view"><c:param name="type" value="total"/></c:url>" alt=""></td>
|
||||
<td><img src="<c:url value="/userChart.view"><c:param name="type" value="stream"/></c:url>" alt=""></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><fmt:message key="home.chart.download"/></th>
|
||||
<th><fmt:message key="home.chart.upload"/></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="<c:url value="/userChart.view"><c:param name="type" value="download"/></c:url>" alt=""></td>
|
||||
<td><img src="<c:url value="/userChart.view"><c:param name="type" value="upload"/></c:url>" alt=""></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="forward"><a href="status.view?"><fmt:message key="common.refresh"/></a></div>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,26 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<%@ include file="head.jsp" %>
|
||||
</head>
|
||||
<body style="padding-top: 10em">
|
||||
|
||||
|
||||
<audio id="demo" autoplay preload="none" controls src="http://localhost:4040/stream?id=1009&maxBitRate=64&foo=3bar"></audio>
|
||||
<%--<audio id="demo" autoplay preload="none" controls src="http://localhost:4040/stream?id=98"></audio>--%>
|
||||
<div>
|
||||
<button onclick="document.getElementById('demo').play()">Play the Audio</button>
|
||||
<button onclick="document.getElementById('demo').pause()">Pause the Audio</button>
|
||||
<button onclick="document.getElementById('demo').volume+=0.1">Increase Volume</button>
|
||||
<button onclick="document.getElementById('demo').volume-=0.1">Decrease Volume</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var a = document.getElementById("demo");
|
||||
a.addEventListener("seeked", function() { console.log("seeked") }, true);
|
||||
// a.addEventListener("timeupdate", function() { console.log("timeupdate " + a.currentTime) }, true);
|
||||
a.addEventListener("progress", function() { console.log("progress " + a.buffered.end(0)) }, true);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,156 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/engine.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/multiService.js"/>"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var previousQuery = "";
|
||||
var instantSearchTimeout;
|
||||
var showSideBar = ${model.showSideBar ? 'true' : 'false'};
|
||||
|
||||
function triggerInstantSearch() {
|
||||
if (instantSearchTimeout) {
|
||||
window.clearTimeout(instantSearchTimeout);
|
||||
}
|
||||
instantSearchTimeout = window.setTimeout(executeInstantSearch, 300);
|
||||
}
|
||||
|
||||
function executeInstantSearch() {
|
||||
var query = $("#query").val().trim();
|
||||
if (query.length > 1 && query != previousQuery) {
|
||||
previousQuery = query;
|
||||
document.searchForm.submit();
|
||||
}
|
||||
}
|
||||
|
||||
function showLeftFrame() {
|
||||
$("#show-left-frame").hide();
|
||||
$("#hide-left-frame").show();
|
||||
toggleLeftFrame(230);
|
||||
multiService.setShowSideBar(true);
|
||||
showSideBar = true;
|
||||
}
|
||||
|
||||
function hideLeftFrame() {
|
||||
$("#hide-left-frame").hide();
|
||||
$("#show-left-frame").show();
|
||||
toggleLeftFrame(0);
|
||||
multiService.setShowSideBar(false);
|
||||
showSideBar = false;
|
||||
}
|
||||
|
||||
function toggleLeftFrameVisible() {
|
||||
if (showSideBar) hideLeftFrame();
|
||||
else showLeftFrame();
|
||||
}
|
||||
|
||||
function toggleLeftFrame(width) {
|
||||
<%-- Disable animation in Chrome. It stopped working in Chrome 44. --%>
|
||||
var duration = navigator.userAgent.indexOf("Chrome") != -1 ? 0 : 400;
|
||||
|
||||
$("#dummy-animation-target").stop();
|
||||
$("#dummy-animation-target").animate({"max-width": width}, {
|
||||
step: function (now, fx) {
|
||||
top.document.getElementById("mainFrameset").cols = now + ",*";
|
||||
},
|
||||
duration: duration
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body class="bgcolor2 topframe" style="margin:0.4em 1em 0 1em;">
|
||||
|
||||
<span id="dummy-animation-target" style="max-width:0;display: none"></span>
|
||||
|
||||
<fmt:message key="top.home" var="home"/>
|
||||
<fmt:message key="top.now_playing" var="nowPlaying"/>
|
||||
<fmt:message key="top.starred" var="starred"/>
|
||||
<fmt:message key="left.playlists" var="playlists"/>
|
||||
<fmt:message key="top.settings" var="settings"/>
|
||||
<fmt:message key="top.status" var="status" />
|
||||
<fmt:message key="top.podcast" var="podcast"/>
|
||||
<fmt:message key="top.more" var="more"/>
|
||||
<fmt:message key="top.help" var="help"/>
|
||||
<fmt:message key="top.search" var="search"/>
|
||||
|
||||
<table style="margin:0;padding-top:5px">
|
||||
<tr>
|
||||
<td style="padding-right:4.5em;">
|
||||
<img id="show-left-frame" src="<spring:theme code="viewAsListImage"/>" onclick="showLeftFrame()" alt="" style="display:${model.showSideBar ? 'none' : 'inline'};cursor:pointer">
|
||||
<img id="hide-left-frame" src="<spring:theme code="viewAsListImage"/>" onclick="hideLeftFrame()" alt="" style="display:${model.showSideBar ? 'inline' : 'none'};cursor:pointer">
|
||||
</td>
|
||||
<td style="min-width:3em;padding-right:1em;text-align: center">
|
||||
<a href="home.view?" target="main"><img src="<spring:theme code="homeImage"/>" title="${home}" alt="${home}"></a>
|
||||
<div class="topHeader"><a href="home.view?" target="main">${home}</a></div>
|
||||
</td>
|
||||
<td style="min-width:3em;padding-right:1em;text-align: center">
|
||||
<a href="nowPlaying.view?" target="main"><img src="<spring:theme code="nowPlayingImage"/>" title="${nowPlaying}" alt="${nowPlaying}"></a>
|
||||
<div class="topHeader"><a href="nowPlaying.view?" target="main">${nowPlaying}</a></div>
|
||||
</td>
|
||||
<td style="min-width:3em;padding-right:1em;text-align: center">
|
||||
<a href="starred.view?" target="main"><img src="<spring:theme code="starredImage"/>" title="${starred}" alt="${starred}"></a>
|
||||
<div class="topHeader"><a href="starred.view?" target="main">${starred}</a></div>
|
||||
</td>
|
||||
<td style="min-width:3em;padding-right:1em;text-align: center">
|
||||
<a href="playlists.view?" target="main"><img src="<spring:theme code="playlistImage"/>" title="${playlists}" alt="${playlists}"></a>
|
||||
<div class="topHeader"><a href="playlists.view?" target="main">${playlists}</a></div>
|
||||
</td>
|
||||
<td style="min-width:4em;padding-right:1em;text-align: center">
|
||||
<a href="podcastChannels.view?" target="main"><img src="<spring:theme code="podcastLargeImage"/>" title="${podcast}" alt="${podcast}"></a>
|
||||
<div class="topHeader"><a href="podcastChannels.view?" target="main">${podcast}</a></div>
|
||||
</td>
|
||||
<c:if test="${model.user.settingsRole}">
|
||||
<td style="min-width:3em;padding-right:1em;text-align: center">
|
||||
<a href="settings.view?" target="main"><img src="<spring:theme code="settingsImage"/>" title="${settings}" alt="${settings}"></a>
|
||||
<div class="topHeader"><a href="settings.view?" target="main">${settings}</a></div>
|
||||
</td>
|
||||
</c:if>
|
||||
<td style="min-width:3em;padding-right:1em;text-align: center">
|
||||
<a href="status.view?" target="main"><img src="<spring:theme code="statusImage"/>" title="${status}" alt="${status}"></a>
|
||||
<div class="topHeader"><a href="status.view?" target="main">${status}</a></div>
|
||||
</td>
|
||||
<td style="min-width:3em;padding-right:1em;text-align: center">
|
||||
<a href="more.view?" target="main"><img src="<spring:theme code="moreImage"/>" title="${more}" alt="${more}"></a>
|
||||
<div class="topHeader"><a href="more.view?" target="main">${more}</a></div>
|
||||
</td>
|
||||
<td style="min-width:3em;padding-right:1em;text-align: center">
|
||||
<a href="help.view?" target="main"><img src="<spring:theme code="helpImage"/>" title="${help}" alt="${help}"></a>
|
||||
<div class="topHeader"><a href="help.view?" target="main">${help}</a></div>
|
||||
</td>
|
||||
|
||||
<td style="padding-left:1em">
|
||||
<form method="post" action="search.view" target="main" name="searchForm">
|
||||
<sec:csrfInput />
|
||||
<td><input type="text" name="query" id="query" size="28" placeholder="${search}" onclick="select();"
|
||||
onkeyup="triggerInstantSearch();"></td>
|
||||
<td><a href="javascript:document.searchForm.submit()"><img src="<spring:theme code="searchImage"/>" alt="${search}" title="${search}"></a></td>
|
||||
</form>
|
||||
</td>
|
||||
|
||||
<td style="padding-left:15pt;padding-right:5pt;vertical-align: middle;width: 100%;text-align: center">
|
||||
|
||||
<c:if test="${model.showAvatar}">
|
||||
<sub:url value="avatar.view" var="avatarUrl">
|
||||
<sub:param name="username" value="${model.user.username}"/>
|
||||
</sub:url>
|
||||
<div style="padding-bottom: 4px">
|
||||
<c:if test="${model.user.settingsRole}"><a href="personalSettings.view" target="main"></c:if>
|
||||
<img src="${avatarUrl}" alt="" width="30" height="30">
|
||||
<c:if test="${model.user.settingsRole}"></a></c:if>
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<div class="detail">
|
||||
<fmt:message key="top.logout" var="logout"><fmt:param value="${model.user.username}"/></fmt:message>
|
||||
<a href="<c:url value="/logout"/>" target="_top">${fn:escapeXml(logout)}</a>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
</tr></table>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,98 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
</head>
|
||||
<body class="mainframe bgcolor1">
|
||||
<script type="text/javascript" src="<c:url value="/script/wz_tooltip.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/tip_balloon.js"/>"></script>
|
||||
|
||||
<c:import url="settingsHeader.jsp">
|
||||
<c:param name="cat" value="transcoding"/>
|
||||
<c:param name="toast" value="${settings_toast}"/>
|
||||
</c:import>
|
||||
|
||||
<form method="post" action="transcodingSettings.view">
|
||||
<sec:csrfInput />
|
||||
<table class="indent">
|
||||
<tr>
|
||||
<th><fmt:message key="transcodingsettings.name"/></th>
|
||||
<th><fmt:message key="transcodingsettings.sourceformat"/></th>
|
||||
<th><fmt:message key="transcodingsettings.targetformat"/></th>
|
||||
<th><fmt:message key="transcodingsettings.step1"/></th>
|
||||
<th><fmt:message key="transcodingsettings.step2"/></th>
|
||||
<th style="padding-left:1em"><fmt:message key="common.delete"/></th>
|
||||
</tr>
|
||||
|
||||
<c:forEach items="${model.transcodings}" var="transcoding">
|
||||
<tr>
|
||||
<td><input style="font-family:monospace" type="text" name="name[${transcoding.id}]" size="10" value="${transcoding.name}"/></td>
|
||||
<td><input style="font-family:monospace" type="text" name="sourceFormats[${transcoding.id}]" size="36" value="${transcoding.sourceFormats}"/></td>
|
||||
<td><input style="font-family:monospace" type="text" name="targetFormat[${transcoding.id}]" size="10" value="${transcoding.targetFormat}"/></td>
|
||||
<td><input style="font-family:monospace" type="text" name="step1[${transcoding.id}]" size="60" value="${transcoding.step1}"/></td>
|
||||
<td><input style="font-family:monospace" type="text" name="step2[${transcoding.id}]" size="22" value="${transcoding.step2}"/></td>
|
||||
<td align="center" style="padding-left:1em"><input type="checkbox" name="delete[${transcoding.id}]" class="checkbox"/></td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
|
||||
<tr>
|
||||
<th colspan="6" align="left" style="padding-top:1em"><fmt:message key="transcodingsettings.add"/></th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><input style="font-family:monospace" type="text" name="name" size="10" placeholder="<fmt:message key="transcodingsettings.name"/>" value="${newTranscoding.name}"/></td>
|
||||
<td><input style="font-family:monospace" type="text" name="sourceFormats" size="36" placeholder="<fmt:message key="transcodingsettings.sourceformat"/>" value="${newTranscoding.sourceFormats}"/></td>
|
||||
<td><input style="font-family:monospace" type="text" name="targetFormat" size="10" placeholder="<fmt:message key="transcodingsettings.targetformat"/>" value="${newTranscoding.targetFormat}"/></td>
|
||||
<td><input style="font-family:monospace" type="text" name="step1" size="60" placeholder="<fmt:message key="transcodingsettings.step1"/>" value="${newTranscoding.step1}"/></td>
|
||||
<td><input style="font-family:monospace" type="text" name="step2" size="22" placeholder="<fmt:message key="transcodingsettings.step2"/>" value="${newTranscoding.step2}"/></td>
|
||||
<td/>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="6" style="padding-top:0.1em">
|
||||
<input type="checkbox" id="defaultActive" name="defaultActive" class="checkbox" checked/>
|
||||
<label for="defaultActive"><fmt:message key="transcodingsettings.defaultactive"/></label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<table style="white-space:nowrap" class="indent">
|
||||
<tr>
|
||||
<td style="font-weight: bold;">
|
||||
<fmt:message key="advancedsettings.downsamplecommand"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="downsamplecommand"/></c:import>
|
||||
</td>
|
||||
<td>
|
||||
<input style="font-family:monospace" type="text" name="downsampleCommand" size="100" value="${model.downsampleCommand}"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="font-weight: bold;">
|
||||
<fmt:message key="advancedsettings.hlscommand"/>
|
||||
<c:import url="helpToolTip.jsp"><c:param name="topic" value="hlscommand"/></c:import>
|
||||
</td>
|
||||
<td>
|
||||
<input style="font-family:monospace" type="text" name="hlsCommand" size="100" value="${model.hlsCommand}"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<p style="padding-top:0.75em">
|
||||
<input type="submit" value="<fmt:message key="common.save"/>" style="margin-right:0.3em">
|
||||
<input type="button" value="<fmt:message key="common.cancel"/>" onclick="location.href='nowPlaying.view'" style="margin-right:1.3em">
|
||||
<a href="http://www.libresonic.org/pages/transcoding.jsp" target="_blank"><fmt:message key="transcodingsettings.recommended"/></a>
|
||||
</p>
|
||||
|
||||
</form>
|
||||
|
||||
<c:if test="${not empty error}">
|
||||
<p class="warning"><fmt:message key="${error}"/></p>
|
||||
</c:if>
|
||||
|
||||
<div style="width:60%">
|
||||
<fmt:message key="transcodingsettings.info"><fmt:param value="${model.transcodeDirectory}"/><fmt:param value="${model.brand}"/></fmt:message>
|
||||
</div>
|
||||
</body></html>
|
||||
@@ -0,0 +1,29 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
</head><body>
|
||||
|
||||
<h1><fmt:message key="upload.title"/></h1>
|
||||
|
||||
<c:forEach items="${model.uploadedFiles}" var="file">
|
||||
<p><fmt:message key="upload.success"><fmt:param value="${file.path}"/></fmt:message></p>
|
||||
</c:forEach>
|
||||
|
||||
<c:forEach items="${model.unzippedFiles}" var="file">
|
||||
<fmt:message key="upload.unzipped"><fmt:param value="${file.path}"/></fmt:message><br/>
|
||||
</c:forEach>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${not empty model.exception}">
|
||||
<p><fmt:message key="upload.failed"><fmt:param value="${model.exception.message}"/></fmt:message></p>
|
||||
</c:when>
|
||||
<c:when test="${empty model.uploadedFiles}">
|
||||
<p><fmt:message key="upload.empty"/></p>
|
||||
</c:when>
|
||||
</c:choose>
|
||||
|
||||
<div class="back"><a href="more.view?"><fmt:message key="common.back"/></a></div>
|
||||
</body></html>
|
||||
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<%--@elvariable id="command" type="org.libresonic.player.command.UserSettingsCommand"--%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value="/script/scripts-2.0.js"/>"></script>
|
||||
<script type="text/javascript">
|
||||
function init() {
|
||||
enablePasswordChangeFields();
|
||||
<c:if test="${settings_reload}">
|
||||
parent.frames.left.location.href="left.view?";
|
||||
</c:if>
|
||||
}
|
||||
function enablePasswordChangeFields() {
|
||||
var changePasswordCheckbox = $("#passwordChange");
|
||||
var ldapCheckbox = $("#ldapAuthenticated");
|
||||
var passwordChangeTable = $("#passwordChangeTable");
|
||||
var passwordChangeCheckboxTable = $("#passwordChangeCheckboxTable");
|
||||
|
||||
if (changePasswordCheckbox && changePasswordCheckbox.is(":checked") && (ldapCheckbox == null || !ldapCheckbox.is(":checked"))) {
|
||||
passwordChangeTable.show();
|
||||
} else {
|
||||
passwordChangeTable.hide();
|
||||
}
|
||||
|
||||
if (changePasswordCheckbox) {
|
||||
if (ldapCheckbox && ldapCheckbox.is(":checked")) {
|
||||
passwordChangeCheckboxTable.hide();
|
||||
} else {
|
||||
passwordChangeCheckboxTable.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body class="mainframe bgcolor1" onload="init()">
|
||||
<script type="text/javascript" src="<c:url value="/script/wz_tooltip.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/tip_balloon.js"/>"></script>
|
||||
|
||||
<c:import url="settingsHeader.jsp">
|
||||
<c:param name="cat" value="user"/>
|
||||
<c:param name="toast" value="${settings_toast}"/>
|
||||
</c:import>
|
||||
|
||||
<table class="indent">
|
||||
<tr>
|
||||
<td><b><fmt:message key="usersettings.title"/></b></td>
|
||||
<td>
|
||||
<select name="username" onchange="location='userSettings.view?userIndex=' + (selectedIndex - 1);">
|
||||
<option value="">-- <fmt:message key="usersettings.newuser"/> --</option>
|
||||
<c:forEach items="${command.users}" var="user">
|
||||
<option ${user.username eq command.username ? "selected" : ""}
|
||||
value="${fn:escapeXml(user.username)}">${fn:escapeXml(user.username)}</option>
|
||||
</c:forEach>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p/>
|
||||
|
||||
<form:form method="post" action="userSettings.view" modelAttribute="command">
|
||||
<table style="${command.admin ? 'display:none' : ''}">
|
||||
<tr>
|
||||
<td><form:checkbox path="adminRole" id="admin" cssClass="checkbox"/></td>
|
||||
<td><label for="admin"><fmt:message key="usersettings.admin"/></label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><form:checkbox path="settingsRole" id="settings" cssClass="checkbox"/></td>
|
||||
<td><label for="settings"><fmt:message key="usersettings.settings"/></label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-top:1em"><form:checkbox path="streamRole" id="stream" cssClass="checkbox"/></td>
|
||||
<td style="padding-top:1em"><label for="stream"><fmt:message key="usersettings.stream"/></label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><form:checkbox path="jukeboxRole" id="jukebox" cssClass="checkbox"/></td>
|
||||
<td><label for="jukebox"><fmt:message key="usersettings.jukebox"/></label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><form:checkbox path="downloadRole" id="download" cssClass="checkbox"/></td>
|
||||
<td><label for="download"><fmt:message key="usersettings.download"/></label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><form:checkbox path="uploadRole" id="upload" cssClass="checkbox"/></td>
|
||||
<td><label for="upload"><fmt:message key="usersettings.upload"/></label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><form:checkbox path="shareRole" id="share" cssClass="checkbox"/></td>
|
||||
<td><label for="share"><fmt:message key="usersettings.share"/></label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><form:checkbox path="coverArtRole" id="coverArt" cssClass="checkbox"/></td>
|
||||
<td><label for="coverArt"><fmt:message key="usersettings.coverart"/></label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><form:checkbox path="commentRole" id="comment" cssClass="checkbox"/></td>
|
||||
<td><label for="comment"><fmt:message key="usersettings.comment"/></label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><form:checkbox path="podcastRole" id="podcast" cssClass="checkbox"/></td>
|
||||
<td><label for="podcast"><fmt:message key="usersettings.podcast"/></label></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<c:if test="${not empty command.allMusicFolders}">
|
||||
<h2><fmt:message key="usersettings.folderaccess"/></h2>
|
||||
|
||||
<div style="width:75%">
|
||||
<c:forEach items="${command.allMusicFolders}" var="musicFolder">
|
||||
<span style="white-space:nowrap">
|
||||
<form:checkbox path="allowedMusicFolderIds" id="musicFolder${musicFolder.id}" value="${musicFolder.id}" cssClass="checkbox"/>
|
||||
<label for="musicFolder${musicFolder.id}" style="padding-right:1.5em">${musicFolder.name}</label>
|
||||
</span>
|
||||
</c:forEach>
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<table class="indent">
|
||||
<tr>
|
||||
<td><fmt:message key="playersettings.maxbitrate"/></td>
|
||||
<td>
|
||||
<form:select path="transcodeSchemeName" cssStyle="width:8em">
|
||||
<c:forEach items="${command.transcodeSchemeHolders}" var="transcodeSchemeHolder">
|
||||
<form:option value="${transcodeSchemeHolder.name}" label="${transcodeSchemeHolder.description}"/>
|
||||
</c:forEach>
|
||||
</form:select>
|
||||
</td>
|
||||
<td><c:import url="helpToolTip.jsp"><c:param name="topic" value="transcode"/></c:import></td>
|
||||
<c:if test="${not command.transcodingSupported}">
|
||||
<td class="warning"><fmt:message key="playersettings.notranscoder"/></td>
|
||||
</c:if>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<c:if test="${not command.newUser and not command.admin}">
|
||||
<table class="indent">
|
||||
<tr>
|
||||
<td><form:checkbox path="deleteUser" id="delete" cssClass="checkbox"/></td>
|
||||
<td><label for="delete"><fmt:message key="usersettings.delete"/></label></td>
|
||||
</tr>
|
||||
</table>
|
||||
</c:if>
|
||||
|
||||
<c:if test="${command.ldapEnabled and not command.admin}">
|
||||
<table>
|
||||
<tr>
|
||||
<td><form:checkbox path="ldapAuthenticated" id="ldapAuthenticated" cssClass="checkbox" onclick="enablePasswordChangeFields()"/></td>
|
||||
<td><label for="ldapAuthenticated"><fmt:message key="usersettings.ldap"/></label></td>
|
||||
<td><c:import url="helpToolTip.jsp"><c:param name="topic" value="ldap"/></c:import></td>
|
||||
</tr>
|
||||
</table>
|
||||
</c:if>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${command.newUser}">
|
||||
<div style="display:none"><form:input path="newUser" /></div>
|
||||
<table class="indent">
|
||||
<tr>
|
||||
<td><fmt:message key="usersettings.username"/></td>
|
||||
<td><form:input path="username" cssStyle="width:15em"/></td>
|
||||
<td class="warning"><form:errors path="username" cssStyle="width:15em"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="usersettings.email"/></td>
|
||||
<td><form:input path="email" cssStyle="width:15em"/></td>
|
||||
<td class="warning"><form:errors path="email"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="usersettings.password"/></td>
|
||||
<td><form:password path="password" cssStyle="width:15em"/></td>
|
||||
<td class="warning"><form:errors path="password"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="usersettings.confirmpassword"/></td>
|
||||
<td><form:password path="confirmPassword" cssStyle="width:15em"/></td>
|
||||
<td/>
|
||||
</tr>
|
||||
</table>
|
||||
</c:when>
|
||||
|
||||
<c:otherwise>
|
||||
<div style="display:none"><form:input path="username"/></div>
|
||||
<table id="passwordChangeCheckboxTable">
|
||||
<tr>
|
||||
<td><form:checkbox path="passwordChange" id="passwordChange" onclick="enablePasswordChangeFields();" cssClass="checkbox"/></td>
|
||||
<td><label for="passwordChange"><fmt:message key="usersettings.changepassword"/></label></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table id="passwordChangeTable" style="display:none">
|
||||
<tr>
|
||||
<td><fmt:message key="usersettings.newpassword"/></td>
|
||||
<td><form:password path="password" id="path"/></td>
|
||||
<td class="warning"><form:errors path="password"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><fmt:message key="usersettings.confirmpassword"/></td>
|
||||
<td><form:password path="confirmPassword" id="confirmPassword"/></td>
|
||||
<td/>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><fmt:message key="usersettings.email"/></td>
|
||||
<td><form:input path="email" cssStyle="width:20em"/></td>
|
||||
<td class="warning"><form:errors path="email"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<input type="submit" value="<fmt:message key="common.save"/>" style="margin-top:1.5em;margin-right:0.3em">
|
||||
<input type="button" value="<fmt:message key="common.cancel"/>" onclick="location.href='nowPlaying.view'" style="margin-top:1.5em">
|
||||
</form:form>
|
||||
|
||||
</body></html>
|
||||
@@ -0,0 +1,161 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
<%--
|
||||
~ This file is part of Libresonic.
|
||||
~
|
||||
~ Libresonic 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
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ Libresonic 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 Libresonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
~
|
||||
~ Copyright 2014 (C) Sindre Mehus
|
||||
--%>
|
||||
|
||||
<%--@elvariable id="model" type="java.util.Map"--%>
|
||||
|
||||
<html><head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<script type="text/javascript" src="<c:url value="/script/util.js"/>"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var image;
|
||||
var id;
|
||||
var duration;
|
||||
var timer;
|
||||
var offset;
|
||||
var step;
|
||||
var size = 120;
|
||||
|
||||
function startPreview(img, id, duration) {
|
||||
stopPreview();
|
||||
image = $(img);
|
||||
step = Math.max(5, Math.round(duration / 50));
|
||||
offset = step;
|
||||
this.id = id;
|
||||
this.duration = duration;
|
||||
updatePreview();
|
||||
timer = window.setInterval(updatePreview, 1000);
|
||||
}
|
||||
|
||||
function updatePreview() {
|
||||
image.attr("src", "coverArt.view?id=" + id + "&size=" + size + "&offset=" + offset);
|
||||
offset += step;
|
||||
if (offset > duration) {
|
||||
stopPreview();
|
||||
}
|
||||
}
|
||||
|
||||
function stopPreview() {
|
||||
if (timer != null) {
|
||||
window.clearInterval(timer);
|
||||
timer = null;
|
||||
}
|
||||
if (image != null) {
|
||||
image.attr("src", "coverArt.view?id=" + id + "&size=" + size);
|
||||
}
|
||||
}
|
||||
function showAllAlbums() {
|
||||
window.location.href = updateQueryStringParameter(window.location.href, "showAll", "1");
|
||||
}
|
||||
</script>
|
||||
|
||||
<style type="text/css">
|
||||
.duration {
|
||||
position: absolute;
|
||||
bottom: 3px;
|
||||
right: 3px;
|
||||
color: #d3d3d3;
|
||||
background-color: black;
|
||||
opacity: 0.8;
|
||||
padding-right:3px;
|
||||
padding-left:3px;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head><body class="mainframe bgcolor1">
|
||||
|
||||
<h1 style="float:left">
|
||||
<span style="vertical-align: middle;">
|
||||
<c:forEach items="${model.ancestors}" var="ancestor">
|
||||
<sub:url value="main.view" var="ancestorUrl">
|
||||
<sub:param name="id" value="${ancestor.id}"/>
|
||||
</sub:url>
|
||||
<a href="${ancestorUrl}">${fn:escapeXml(ancestor.name)}</a> »
|
||||
</c:forEach>
|
||||
${fn:escapeXml(model.dir.name)}
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<%@ include file="viewSelector.jsp" %>
|
||||
<div style="clear:both;padding-bottom:2em"></div>
|
||||
|
||||
<table class="music">
|
||||
<c:forEach items="${model.subDirs}" var="subDir" varStatus="loopStatus">
|
||||
<tr><td class="truncate" colspan="9"><a href="main.view?id=${subDir.id}" title="${fn:escapeXml(subDir.name)}">${fn:escapeXml(subDir.name)}</a></td></tr>
|
||||
</c:forEach>
|
||||
<c:if test="${model.viewAsList}">
|
||||
<c:forEach items="${model.files}" var="child">
|
||||
<c:url value="/videoPlayer.view" var="videoUrl">
|
||||
<c:param name="id" value="${child.id}"/>
|
||||
</c:url>
|
||||
<tr>
|
||||
<c:import url="playButtons.jsp">
|
||||
<c:param name="id" value="${child.id}"/>
|
||||
<c:param name="playEnabled" value="${model.user.streamRole and not model.partyMode}"/>
|
||||
<c:param name="downloadEnabled" value="${model.user.downloadRole and not model.partyMode}"/>
|
||||
<c:param name="video" value="${child.video and model.player.web}"/>
|
||||
<c:param name="asTable" value="true"/>
|
||||
</c:import>
|
||||
<td class="truncate">
|
||||
<a href="${videoUrl}"><span class="songTitle" title="${fn:escapeXml(child.name)}">${fn:escapeXml(child.name)}</span></a>
|
||||
</td>
|
||||
<td class="fit rightalign detail">${child.year}</td>
|
||||
<td class="fit rightalign detail">${fn:toLowerCase(child.format)}</td>
|
||||
<td class="fit rightalign detail"><sub:formatBytes bytes="${child.fileSize}"/></td>
|
||||
<td class="fit rightalign detail">${child.durationString}</td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</c:if>
|
||||
</table>
|
||||
<c:if test="${model.thereIsMore && fn:length(model.subDirs) gt 0}">
|
||||
<input id="showAllButton" class="albumOverflowButton" type="button" value="<fmt:message key="main.showall"/>" onclick="showAllAlbums()">
|
||||
</c:if>
|
||||
|
||||
<div style="clear:both;height:1.5em"></div>
|
||||
|
||||
<c:if test="${not model.viewAsList}">
|
||||
<c:forEach items="${model.files}" var="child">
|
||||
<c:url value="/videoPlayer.view" var="videoUrl">
|
||||
<c:param name="id" value="${child.id}"/>
|
||||
</c:url>
|
||||
<c:url value="/coverArt.view" var="coverArtUrl">
|
||||
<c:param name="id" value="${child.id}"/>
|
||||
<c:param name="size" value="120"/>
|
||||
</c:url>
|
||||
|
||||
<div class="albumThumb">
|
||||
<div class="coverart dropshadow" style="width:213px">
|
||||
<div style="position:relative">
|
||||
<div>
|
||||
<a href="${videoUrl}"><img src="${coverArtUrl}" height="120" width="213" alt=""
|
||||
onmouseover="startPreview(this, ${child.id}, ${child.durationSeconds})"
|
||||
onmouseout="stopPreview()"></a>
|
||||
</div>
|
||||
<div class="detail duration">${child.durationString}</div>
|
||||
</div>
|
||||
<div class="caption1" title="${fn:escapeXml(child.name)}"><a href="${videoUrl}" title="${fn:escapeXml(child.name)}">${fn:escapeXml(child.name)}</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</c:forEach>
|
||||
</c:if>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,80 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<%@ include file="head.jsp" %>
|
||||
<%@ include file="jquery.jsp" %>
|
||||
<link rel="stylesheet" type="text/css" href="<c:url value="/style/videoPlayer.css"/>">
|
||||
<script type="text/javascript" src="<c:url value="/dwr/engine.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/dwr/interface/starService.js"/>"></script>
|
||||
<script type="text/javascript" src="<c:url value="/script/cast_sender-v1.js"/>"></script>
|
||||
<%@ include file="videoPlayerCast.jsp" %>
|
||||
|
||||
<script type="text/javascript" language="javascript">
|
||||
function toggleStar(mediaFileId, imageId) {
|
||||
if ($(imageId).attr("src").indexOf("<spring:theme code="ratingOnImage"/>") != -1) {
|
||||
$(imageId).attr("src", "<spring:theme code="ratingOffImage"/>");
|
||||
starService.unstar(mediaFileId);
|
||||
}
|
||||
else if ($(imageId).attr("src").indexOf("<spring:theme code="ratingOffImage"/>") != -1) {
|
||||
$(imageId).attr("src", "<spring:theme code="ratingOnImage"/>");
|
||||
starService.star(mediaFileId);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body class="mainframe bgcolor1" style="padding-bottom:0.5em">
|
||||
|
||||
<div>
|
||||
<div id="overlay">
|
||||
<div id="overlay_text">Playing on Chromecast</div>
|
||||
</div>
|
||||
<video id="videoPlayer" width="640" height="360"></video>
|
||||
<div id="media_control">
|
||||
<div id="progress_slider"></div>
|
||||
<div id="play"></div>
|
||||
<div id="pause"></div>
|
||||
<div id="progress">0:00</div>
|
||||
<div id="duration">0:00</div>
|
||||
<div id="audio_on"></div>
|
||||
<div id="audio_off"></div>
|
||||
<div id="volume_slider"></div>
|
||||
<select name="bitrate_menu" id="bitrate_menu">
|
||||
<c:forEach items="${model.bitRates}" var="bitRate">
|
||||
<c:choose>
|
||||
<c:when test="${bitRate eq model.defaultBitRate}">
|
||||
<option selected="selected" value="${bitRate}">${bitRate} Kbps</option>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<option value="${bitRate}">${bitRate} Kbps</option>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</c:forEach>
|
||||
</select>
|
||||
<div id="share"></div>
|
||||
<div id="download"></div>
|
||||
<div id="casticonactive"></div>
|
||||
<div id="casticonidle"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="debug"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var CastPlayer = new CastPlayer();
|
||||
</script>
|
||||
|
||||
|
||||
<h1 style="padding-top:1em;padding-bottom:0.5em;">
|
||||
<img id="starImage" src="<spring:theme code="${not empty model.video.starredDate ? 'ratingOnImage' : 'ratingOffImage'}"/>"
|
||||
onclick="toggleStar(${model.video.id}, '#starImage'); return false;" style="cursor:pointer" alt="">
|
||||
<span style="vertical-align:middle">${fn:escapeXml(model.video.title)}</span>
|
||||
</h1>
|
||||
|
||||
<sub:url value="main.view" var="backUrl"><sub:param name="id" value="${model.video.id}"/></sub:url>
|
||||
|
||||
<div class="back" style="float:left;padding-right:2em"><a href="${backUrl}"><fmt:message key="common.back"/></a></div>
|
||||
<div style="clear: both"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,695 @@
|
||||
<script type="text/javascript">
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Constants of states for Chromecast device
|
||||
**/
|
||||
var DEVICE_STATE = {
|
||||
'NOT_PRESENT': 0,
|
||||
'IDLE': 1,
|
||||
'ACTIVE': 2,
|
||||
'WARNING': 3,
|
||||
'ERROR': 4
|
||||
};
|
||||
|
||||
var PLAYER_STATE = {
|
||||
'IDLE': 'IDLE',
|
||||
'LOADING': 'LOADING',
|
||||
'LOADED': 'LOADED',
|
||||
'PLAYING': 'PLAYING',
|
||||
'PAUSED': 'PAUSED',
|
||||
'SEEKING': 'SEEKING'
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast player object
|
||||
* main variables:
|
||||
* - deviceState for Cast mode:
|
||||
* IDLE: Default state indicating that Cast extension is installed, but showing no current activity
|
||||
* ACTIVE: Shown when Chrome has one or more local activities running on a receiver
|
||||
* WARNING: Shown when the device is actively being used, but when one or more issues have occurred
|
||||
* ERROR: Should not normally occur, but shown when there is a failure
|
||||
* - Cast player variables for controlling Cast mode media playback
|
||||
* - Local player variables for controlling local mode media playbacks
|
||||
* - Current media variables for transition between Cast and local modes
|
||||
*/
|
||||
var CastPlayer = function () {
|
||||
|
||||
/* device variables */
|
||||
|
||||
// @type {DEVICE_STATE} A state for device
|
||||
this.deviceState = DEVICE_STATE.NOT_PRESENT;
|
||||
|
||||
/* Cast player variables */
|
||||
|
||||
// @type {Object} a chrome.cast.media.Media object
|
||||
this.currentMediaSession = null;
|
||||
|
||||
// @type {Number} volume between 0 and 100
|
||||
this.currentVolume = 50;
|
||||
|
||||
// @type {Boolean} A flag for autoplay after load
|
||||
this.autoplay = true;
|
||||
|
||||
// @type {string} a chrome.cast.Session object
|
||||
this.session = null;
|
||||
|
||||
// @type {PLAYER_STATE} A state for Cast media player
|
||||
this.castPlayerState = PLAYER_STATE.IDLE;
|
||||
|
||||
/* Local player variables */
|
||||
|
||||
// @type {PLAYER_STATE} A state for local media player
|
||||
this.localPlayerState = PLAYER_STATE.IDLE;
|
||||
|
||||
// @type {video} local player
|
||||
this.localPlayer = null;
|
||||
|
||||
/* Current media variables */
|
||||
|
||||
// @type {Boolean} Muted audio
|
||||
this.muted = false;
|
||||
|
||||
// @type {Number} A number for current media offset
|
||||
this.currentMediaOffset = 0;
|
||||
|
||||
// @type {Number} A number for current media time, relative to offset
|
||||
this.currentMediaTime = 0;
|
||||
|
||||
// @type {Number} A number for current media duration
|
||||
this.currentMediaDuration = ${empty model.duration ? 0: model.duration};
|
||||
|
||||
// @type {Boolean} A boolean to stop timer update of progress when triggered by media status event
|
||||
this.seekInProgress = false;
|
||||
|
||||
this.updateDurationLabel();
|
||||
this.initializeUI();
|
||||
this.initializeLocalPlayer();
|
||||
this.initializeCastPlayer();
|
||||
this.playMediaLocally(0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize local media player
|
||||
*/
|
||||
CastPlayer.prototype.initializeLocalPlayer = function () {
|
||||
this.localPlayer = $('#videoPlayer').get(0);
|
||||
this.localPlayer.volume = this.currentVolume/100;
|
||||
this.localPlayer.addEventListener("timeupdate", this.updateLocalProgress.bind(this));
|
||||
this.localPlayer.addEventListener("play", this.updateLocalState.bind(this));
|
||||
this.localPlayer.addEventListener("pause", this.updateLocalState.bind(this));
|
||||
this.localPlayer.addEventListener("playing", this.updateLocalState.bind(this));
|
||||
this.localPlayer.addEventListener("paused", this.updateLocalState.bind(this));
|
||||
};
|
||||
|
||||
CastPlayer.prototype.updateLocalProgress = function () {
|
||||
var newTime = Math.round(this.localPlayer.currentTime);
|
||||
if (newTime != this.currentMediaTime && !this.seekInProgress) {
|
||||
this.currentMediaTime = newTime;
|
||||
this.updateProgressBar();
|
||||
}
|
||||
};
|
||||
|
||||
CastPlayer.prototype.updateLocalState = function () {
|
||||
if (this.localPlayer.paused) {
|
||||
this.localPlayerState = PLAYER_STATE.PAUSED;
|
||||
} else {
|
||||
this.localPlayerState = PLAYER_STATE.PLAYING;
|
||||
}
|
||||
this.updateMediaControlUI();
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize Cast media player
|
||||
* Initializes the API. Note that either successCallback and errorCallback will be
|
||||
* invoked once the API has finished initialization. The sessionListener and
|
||||
* receiverListener may be invoked at any time afterwards, and possibly more than once.
|
||||
*/
|
||||
CastPlayer.prototype.initializeCastPlayer = function () {
|
||||
|
||||
if (!window.chrome) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!chrome.cast || !chrome.cast.isAvailable) {
|
||||
setTimeout(this.initializeCastPlayer.bind(this), 1000);
|
||||
return;
|
||||
}
|
||||
// request session
|
||||
var applicationID = "9EAA0B71";
|
||||
var sessionRequest = new chrome.cast.SessionRequest(applicationID);
|
||||
var apiConfig = new chrome.cast.ApiConfig(sessionRequest,
|
||||
this.sessionListener.bind(this),
|
||||
this.receiverListener.bind(this));
|
||||
|
||||
chrome.cast.initialize(apiConfig, this.onInitSuccess.bind(this), this.onError.bind(this));
|
||||
this.timer = setInterval(this.incrementMediaTime.bind(this), 1000);
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback function for init success
|
||||
*/
|
||||
CastPlayer.prototype.onInitSuccess = function () {
|
||||
console.log("init success");
|
||||
this.updateMediaControlUI();
|
||||
};
|
||||
|
||||
/**
|
||||
* Generic error callback function
|
||||
*/
|
||||
CastPlayer.prototype.onError = function () {
|
||||
console.log("error");
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {!Object} e A new session
|
||||
* This handles auto-join when a page is reloaded
|
||||
* When active session is detected, playback will automatically
|
||||
* join existing session and occur in Cast mode and media
|
||||
* status gets synced up with current media of the session
|
||||
*/
|
||||
CastPlayer.prototype.sessionListener = function (e) {
|
||||
this.session = e;
|
||||
if (this.session) {
|
||||
this.deviceState = DEVICE_STATE.ACTIVE;
|
||||
if (this.session.media[0]) {
|
||||
this.onMediaDiscovered('activeSession', this.session.media[0]);
|
||||
}
|
||||
else {
|
||||
this.loadMedia();
|
||||
}
|
||||
this.session.addUpdateListener(this.sessionUpdateListener.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} e Receiver availability
|
||||
* This indicates availability of receivers but
|
||||
* does not provide a list of device IDs
|
||||
*/
|
||||
CastPlayer.prototype.receiverListener = function (e) {
|
||||
if (e === 'available') {
|
||||
console.log("receiver found");
|
||||
this.deviceState = DEVICE_STATE.IDLE;
|
||||
}
|
||||
else {
|
||||
console.log("receiver list empty");
|
||||
this.deviceState = DEVICE_STATE.NOT_PRESENT;
|
||||
}
|
||||
this.updateMediaControlUI();
|
||||
};
|
||||
|
||||
/**
|
||||
* session update listener
|
||||
*/
|
||||
CastPlayer.prototype.sessionUpdateListener = function (isAlive) {
|
||||
if (!isAlive) {
|
||||
this.session = null;
|
||||
this.deviceState = DEVICE_STATE.IDLE;
|
||||
this.castPlayerState = PLAYER_STATE.IDLE;
|
||||
console.log(this.castPlayerState + " (sessionUpdateListener)");
|
||||
this.currentMediaSession = null;
|
||||
|
||||
// continue to play media locally
|
||||
this.playMediaLocally(this.currentMediaOffset + this.currentMediaTime);
|
||||
this.updateMediaControlUI();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Requests that a receiver application session be created or joined. By default, the SessionRequest
|
||||
* passed to the API at initialization time is used; this may be overridden by passing a different
|
||||
* session request in opt_sessionRequest.
|
||||
*/
|
||||
CastPlayer.prototype.launchApp = function () {
|
||||
console.log("launching app...");
|
||||
chrome.cast.requestSession(this.onRequestSessionSuccess.bind(this), this.onLaunchError.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback function for request session success
|
||||
* @param {Object} e A chrome.cast.Session object
|
||||
*/
|
||||
CastPlayer.prototype.onRequestSessionSuccess = function (e) {
|
||||
console.log("session success: " + e.sessionId);
|
||||
this.session = e;
|
||||
this.deviceState = DEVICE_STATE.ACTIVE;
|
||||
this.stopMediaLocally();
|
||||
this.loadMedia();
|
||||
this.session.addUpdateListener(this.sessionUpdateListener.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback function for launch error
|
||||
*/
|
||||
CastPlayer.prototype.onLaunchError = function () {
|
||||
console.log("launch error");
|
||||
this.deviceState = DEVICE_STATE.ERROR;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stops the running receiver application associated with the session.
|
||||
*/
|
||||
CastPlayer.prototype.stopApp = function () {
|
||||
this.session.stop(this.onStopAppSuccess.bind(this, 'Session stopped'),
|
||||
this.onError.bind(this));
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback function for stop app success
|
||||
*/
|
||||
CastPlayer.prototype.onStopAppSuccess = function (message) {
|
||||
console.log(message);
|
||||
this.deviceState = DEVICE_STATE.IDLE;
|
||||
this.castPlayerState = PLAYER_STATE.IDLE;
|
||||
console.log(this.castPlayerState + " (onStopAppSuccess)");
|
||||
this.currentMediaSession = null;
|
||||
|
||||
// continue to play media locally
|
||||
this.playMediaLocally(this.currentMediaOffset + this.currentMediaTime);
|
||||
this.updateMediaControlUI();
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads media into a running receiver application
|
||||
*/
|
||||
CastPlayer.prototype.loadMedia = function () {
|
||||
if (!this.session) {
|
||||
console.log("no session");
|
||||
return;
|
||||
}
|
||||
var offset = this.currentMediaOffset + this.currentMediaTime;
|
||||
this.currentMediaOffset = offset;
|
||||
this.currentMediaTime = 0;
|
||||
|
||||
var url = "${model.remoteStreamUrl}" + "&maxBitRate=" + this.getBitRate() + "&format=mkv&timeOffset=" + offset;
|
||||
console.log("casting " + url);
|
||||
var mediaInfo = new chrome.cast.media.MediaInfo(url);
|
||||
mediaInfo.contentType = 'video/x-matroska';
|
||||
mediaInfo.streamType = chrome.cast.media.StreamType.BUFFERED;
|
||||
mediaInfo.duration = this.currentMediaDuration;
|
||||
mediaInfo.metadata = new chrome.cast.media.MovieMediaMetadata();
|
||||
mediaInfo.metadata.metadataType = chrome.cast.media.MetadataType.MOVIE;
|
||||
mediaInfo.metadata.title = "${model.video.title}";
|
||||
mediaInfo.metadata.images = [new chrome.cast.Image("${model.remoteCoverArtUrl}&size=384")];
|
||||
|
||||
var request = new chrome.cast.media.LoadRequest(mediaInfo);
|
||||
request.autoplay = this.autoplay;
|
||||
request.currentTime = 0;
|
||||
|
||||
this.castPlayerState = PLAYER_STATE.LOADING;
|
||||
console.log(this.castPlayerState + " (loadMedia)");
|
||||
|
||||
this.session.loadMedia(request,
|
||||
this.onMediaDiscovered.bind(this, 'loadMedia'),
|
||||
this.onLoadMediaError.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback function for loadMedia success
|
||||
* @param {Object} mediaSession A new media object.
|
||||
* @param {String} how How the session was discovered.
|
||||
*/
|
||||
CastPlayer.prototype.onMediaDiscovered = function (how, mediaSession) {
|
||||
console.log("new media session ID:" + mediaSession.mediaSessionId + ' (' + how + ')');
|
||||
this.currentMediaSession = mediaSession;
|
||||
if (how == 'loadMedia') {
|
||||
this.castPlayerState = this.castPlayerState = PLAYER_STATE.LOADED;
|
||||
console.log(this.castPlayerState + " (onMediaDiscovered-loadMedia)");
|
||||
}
|
||||
|
||||
if (how == 'activeSession') {
|
||||
// TODO: Use currentMediaSession?
|
||||
this.castPlayerState = this.session.media[0].playerState;
|
||||
console.log(this.castPlayerState + " (onMediaDiscovered-activeSession)");
|
||||
this.currentMediaTime = Math.round(this.session.media[0].currentTime);
|
||||
}
|
||||
|
||||
this.currentMediaSession.addUpdateListener(this.onMediaStatusUpdate.bind(this));
|
||||
|
||||
// update UI
|
||||
this.updateMediaControlUI();
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback function when media load returns error
|
||||
*/
|
||||
CastPlayer.prototype.onLoadMediaError = function (e) {
|
||||
console.log("media error");
|
||||
this.castPlayerState = PLAYER_STATE.IDLE;
|
||||
console.log(this.castPlayerState + " (onLoadMediaError)");
|
||||
this.updateMediaControlUI();
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback function for media status update from receiver
|
||||
* @param {!Boolean} alive whether the media object is still alive.
|
||||
*/
|
||||
CastPlayer.prototype.onMediaStatusUpdate = function (alive) {
|
||||
if (!alive) {
|
||||
this.castPlayerState = PLAYER_STATE.IDLE;
|
||||
console.log(this.castPlayerState + " (onMediaStatusUpdate-dead)");
|
||||
} else {
|
||||
this.castPlayerState = this.currentMediaSession.playerState;
|
||||
console.log(this.castPlayerState + " (onMediaStatusUpdate)");
|
||||
}
|
||||
|
||||
this.updateProgressBar();
|
||||
this.updateMediaControlUI();
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function
|
||||
* Increment media current position by 1 second
|
||||
*/
|
||||
CastPlayer.prototype.incrementMediaTime = function () {
|
||||
if (this.castPlayerState == PLAYER_STATE.PLAYING) {
|
||||
if (this.currentMediaOffset + this.currentMediaTime < this.currentMediaDuration) {
|
||||
this.currentMediaTime += 1;
|
||||
this.updateProgressBar();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the duration label.
|
||||
*/
|
||||
CastPlayer.prototype.updateDurationLabel = function () {
|
||||
$("#duration").html(this.formatDuration(this.currentMediaDuration));
|
||||
};
|
||||
|
||||
CastPlayer.prototype.formatDuration = function (duration) {
|
||||
var hours = Math.floor(duration / 3600);
|
||||
duration = duration % 3600;
|
||||
var minutes = Math.floor(duration / 60);
|
||||
var seconds = Math.floor(duration % 60);
|
||||
|
||||
var result = "";
|
||||
if (hours > 0) {
|
||||
result += hours + ":";
|
||||
if (minutes < 10) {
|
||||
result += "0";
|
||||
}
|
||||
}
|
||||
result += minutes + ":";
|
||||
if (seconds < 10) {
|
||||
result += "0";
|
||||
}
|
||||
result += seconds;
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Play media in Cast mode
|
||||
*/
|
||||
CastPlayer.prototype.playMedia = function () {
|
||||
if (!this.currentMediaSession) {
|
||||
this.playMediaLocally(0);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (this.castPlayerState) {
|
||||
case PLAYER_STATE.LOADED:
|
||||
case PLAYER_STATE.PAUSED:
|
||||
this.currentMediaSession.play(null,
|
||||
this.mediaCommandSuccessCallback.bind(this, "playing started for " + this.currentMediaSession.sessionId),
|
||||
this.onError.bind(this));
|
||||
this.currentMediaSession.addUpdateListener(this.onMediaStatusUpdate.bind(this));
|
||||
this.castPlayerState = PLAYER_STATE.PLAYING;
|
||||
console.log(this.castPlayerState + " (playMedia)");
|
||||
break;
|
||||
case PLAYER_STATE.IDLE:
|
||||
case PLAYER_STATE.LOADING:
|
||||
this.loadMedia();
|
||||
this.currentMediaSession.addUpdateListener(this.onMediaStatusUpdate.bind(this));
|
||||
this.castPlayerState = PLAYER_STATE.PLAYING;
|
||||
console.log(this.castPlayerState + " (playMedia)");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
this.updateMediaControlUI();
|
||||
};
|
||||
|
||||
/**
|
||||
* Play media in local player
|
||||
* @param {Number} offset A number for media current position
|
||||
*/
|
||||
CastPlayer.prototype.playMediaLocally = function (offset) {
|
||||
this.currentMediaDuration = this.localPlayer.duration;
|
||||
|
||||
if (this.localPlayerState == PLAYER_STATE.PLAYING || this.localPlayerState == PLAYER_STATE.PAUSED) {
|
||||
this.localPlayer.play();
|
||||
} else {
|
||||
this.currentMediaOffset = offset;
|
||||
this.currentMediaTime = 0;
|
||||
|
||||
var url = "${model.streamUrl}" + "&maxBitRate=" + this.getBitRate() + "&timeOffset=" + offset;
|
||||
console.log("playing local: " + url);
|
||||
|
||||
this.localPlayer.src = url;
|
||||
this.localPlayer.play();
|
||||
this.seekInProgress = false;
|
||||
}
|
||||
this.updateMediaControlUI();
|
||||
};
|
||||
|
||||
CastPlayer.prototype.getBitRate = function () {
|
||||
return $("#bitrate_menu").val();
|
||||
};
|
||||
|
||||
/**
|
||||
* Pause media playback in Cast mode
|
||||
*/
|
||||
CastPlayer.prototype.pauseMedia = function () {
|
||||
if (!this.currentMediaSession) {
|
||||
this.pauseMediaLocally();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.castPlayerState == PLAYER_STATE.PLAYING) {
|
||||
this.castPlayerState = PLAYER_STATE.PAUSED;
|
||||
console.log(this.castPlayerState + " (pauseMedia)");
|
||||
this.currentMediaSession.pause(null,
|
||||
this.mediaCommandSuccessCallback.bind(this, "paused " + this.currentMediaSession.sessionId),
|
||||
this.onError.bind(this));
|
||||
this.updateMediaControlUI();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Changes the bit rate.
|
||||
*/
|
||||
CastPlayer.prototype.changeBitRate = function () {
|
||||
// This effectively restarts streaming with the new bit rate.
|
||||
this.seekMedia();
|
||||
};
|
||||
|
||||
/**
|
||||
* Share the video.
|
||||
*/
|
||||
CastPlayer.prototype.share = function () {
|
||||
location.href = "createShare.view?id=${model.video.id}";
|
||||
};
|
||||
|
||||
/**
|
||||
* Download the video.
|
||||
*/
|
||||
CastPlayer.prototype.download = function () {
|
||||
location.href = "download.view?id=${model.video.id}";
|
||||
};
|
||||
|
||||
/**
|
||||
* Pause media playback in local player
|
||||
*/
|
||||
CastPlayer.prototype.pauseMediaLocally = function () {
|
||||
this.localPlayer.pause();
|
||||
this.updateMediaControlUI();
|
||||
};
|
||||
|
||||
/**
|
||||
* Stop media playback in local player
|
||||
*/
|
||||
CastPlayer.prototype.stopMediaLocally = function () {
|
||||
this.localPlayer.pause();
|
||||
this.localPlayer.currentTime = 0;
|
||||
this.updateMediaControlUI();
|
||||
};
|
||||
|
||||
/**
|
||||
* Set media volume in local or Cast mode
|
||||
* @param {Boolean} mute A boolean
|
||||
*/
|
||||
CastPlayer.prototype.setVolume = function (mute) {
|
||||
this.currentVolume = parseInt($("#volume_slider").slider("option", "value"));
|
||||
|
||||
if (!this.currentMediaSession) {
|
||||
this.localPlayer.muted = mute;
|
||||
if (!mute) {
|
||||
this.localPlayer.volume = this.currentVolume / 100;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (mute) {
|
||||
this.session.setReceiverMuted(true,
|
||||
this.mediaCommandSuccessCallback.bind(this),
|
||||
this.onError.bind(this));
|
||||
} else {
|
||||
this.session.setReceiverVolumeLevel(this.currentVolume / 100.0,
|
||||
this.mediaCommandSuccessCallback.bind(this),
|
||||
this.onError.bind(this));
|
||||
}
|
||||
this.updateMediaControlUI();
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggle mute in either Cast or local mode
|
||||
*/
|
||||
CastPlayer.prototype.muteMedia = function () {
|
||||
this.muted = !this.muted;
|
||||
this.setVolume(this.muted);
|
||||
$('#audio_on').toggle(!this.muted);
|
||||
$('#audio_off').toggle(this.muted);
|
||||
this.updateMediaControlUI();
|
||||
};
|
||||
|
||||
/**
|
||||
* media seek function in either Cast or local mode
|
||||
*/
|
||||
CastPlayer.prototype.seekMedia = function () {
|
||||
|
||||
var offset = parseInt($("#progress_slider").slider("option", "value"));
|
||||
this.seekInProgress = true;
|
||||
this.currentMediaOffset = offset;
|
||||
this.currentMediaTime = 0;
|
||||
|
||||
if (this.localPlayerState == PLAYER_STATE.PLAYING || this.localPlayerState == PLAYER_STATE.PAUSED) {
|
||||
this.localPlayerState = PLAYER_STATE.SEEKING;
|
||||
this.playMediaLocally(offset);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.castPlayerState != PLAYER_STATE.PLAYING && this.castPlayerState != PLAYER_STATE.PAUSED) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.castPlayerState = PLAYER_STATE.SEEKING;
|
||||
this.loadMedia();
|
||||
this.updateMediaControlUI();
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback function for media command success
|
||||
*/
|
||||
CastPlayer.prototype.mediaCommandSuccessCallback = function (info, e) {
|
||||
this.currentMediaTime = Math.round(this.session.media[0].currentTime);
|
||||
if (info) {
|
||||
console.log(info);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update progress bar with the current media time.
|
||||
*/
|
||||
CastPlayer.prototype.updateProgressBar = function () {
|
||||
$("#progress_slider").slider("option", "value", this.currentMediaOffset + this.currentMediaTime);
|
||||
$("#progress").html(this.formatDuration(this.currentMediaOffset + this.currentMediaTime));
|
||||
};
|
||||
|
||||
CastPlayer.prototype.updateDebug = function () {
|
||||
var debug = "<br>currentMediaOffset: " + this.currentMediaOffset + "<br>"
|
||||
+ "currentMediaTime: " + this.currentMediaTime + "<br>"
|
||||
+ "localPlayerState: " + this.localPlayerState + "<br>"
|
||||
+ "castPlayerState: " + this.castPlayerState;
|
||||
$("#debug").html(debug);
|
||||
};
|
||||
|
||||
/**
|
||||
* Update media control UI components based on localPlayerState or castPlayerState
|
||||
*/
|
||||
CastPlayer.prototype.updateMediaControlUI = function () {
|
||||
|
||||
var playerState = this.localPlayerState;
|
||||
|
||||
if (this.deviceState == DEVICE_STATE.NOT_PRESENT) {
|
||||
$("#casticonactive").hide();
|
||||
$("#casticonidle").hide();
|
||||
$("#overlay_text").hide();
|
||||
var loaded = false;
|
||||
if(this.localPlayer.src) {
|
||||
loaded = true;
|
||||
}
|
||||
$("#overlay").toggle(!loaded);
|
||||
} else if (this.deviceState == DEVICE_STATE.ACTIVE) {
|
||||
$("#casticonactive").show();
|
||||
$("#casticonidle").hide();
|
||||
$("#overlay_text").show();
|
||||
$("#overlay").show();
|
||||
playerState = this.castPlayerState;
|
||||
} else {
|
||||
$("#casticonactive").hide();
|
||||
$("#casticonidle").show();
|
||||
$("#overlay_text").hide();
|
||||
var loaded = false;
|
||||
if(this.localPlayer.src) {
|
||||
loaded = true;
|
||||
}
|
||||
$("#overlay").toggle(!loaded);
|
||||
}
|
||||
|
||||
switch (playerState) {
|
||||
case PLAYER_STATE.LOADED:
|
||||
case PLAYER_STATE.PLAYING:
|
||||
$("#play").hide();
|
||||
$("#pause").show();
|
||||
break;
|
||||
case PLAYER_STATE.PAUSED:
|
||||
case PLAYER_STATE.IDLE:
|
||||
case PLAYER_STATE.LOADING:
|
||||
$("#play").show();
|
||||
$("#pause").hide();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize UI components and add event listeners
|
||||
*/
|
||||
CastPlayer.prototype.initializeUI = function () {
|
||||
|
||||
$("#progress_slider").slider({max: this.currentMediaDuration, animate: "fast", range: "min"});
|
||||
$("#volume_slider").slider({max: 100, value: 50, animate: "fast", range: "min"});
|
||||
|
||||
// add event handlers to UI components
|
||||
$("#casticonidle").on('click', this.launchApp.bind(this));
|
||||
$("#casticonactive").on('click', this.stopApp.bind(this));
|
||||
$("#progress_slider").on('slidestop', this.seekMedia.bind(this));
|
||||
$("#volume_slider").on('slidestop', this.setVolume.bind(this, false));
|
||||
$("#audio_on").on('click', this.muteMedia.bind(this));
|
||||
$("#audio_off").on('click', this.muteMedia.bind(this));
|
||||
$("#play").on('click', this.playMedia.bind(this));
|
||||
$("#pause").on('click', this.pauseMedia.bind(this));
|
||||
$("#bitrate_menu").on('change', this.changeBitRate.bind(this));
|
||||
$("#share").on('click', this.share.bind(this));
|
||||
$("#download").on('click', this.download.bind(this));
|
||||
|
||||
<c:if test="${not model.user.shareRole}">
|
||||
$("#share").hide();
|
||||
</c:if>
|
||||
<c:if test="${not model.user.downloadRole}">
|
||||
$("#download").hide();
|
||||
</c:if>
|
||||
|
||||
// setInterval(this.updateDebug.bind(this), 100);
|
||||
};
|
||||
|
||||
window.CastPlayer = CastPlayer;
|
||||
})();
|
||||
</script>
|
||||
@@ -0,0 +1,38 @@
|
||||
<%--
|
||||
~ This file is part of Libresonic.
|
||||
~
|
||||
~ Libresonic 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
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ Libresonic 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 Libresonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
~
|
||||
~ Copyright 2015 (C) Sindre Mehus
|
||||
--%>
|
||||
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
|
||||
<div style="float:right;padding-right:1em">
|
||||
<c:url value="main.view" var="changeViewUrl">
|
||||
<c:param name="id" value="${model.dir.id}"/>
|
||||
<c:param name="viewAsList" value="${not model.viewAsList}"/>
|
||||
</c:url>
|
||||
<c:choose>
|
||||
<c:when test="${model.viewAsList}">
|
||||
<img src="<spring:theme code="viewAsListImage"/>" alt="" class="headerSelected" style="margin-right:8px"/>
|
||||
<a href="${changeViewUrl}"><img src="<spring:theme code="viewAsGridImage"/>" alt=""/></a>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<a href="${changeViewUrl}"><img src="<spring:theme code="viewAsListImage"/>" alt="" style="margin-right:8px"/></a>
|
||||
<img src="<spring:theme code="viewAsGridImage"/>" alt="" class="headerSelected"/>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
|
||||
|
||||
<%@ page language="java" contentType="text/vnd.wap.wml; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
|
||||
<wml>
|
||||
|
||||
<%@ include file="head.jsp" %>
|
||||
|
||||
<card id="main" title="Libresonic" newcontext="false">
|
||||
|
||||
<p><small><b>
|
||||
|
||||
<sub:url value="/wap/playlist.view" var="playUrl">
|
||||
<sub:param name="play" value="${model.parent.path}"/>
|
||||
</sub:url>
|
||||
<sub:url value="/wap/playlist.view" var="addUrl">
|
||||
<sub:param name="add" value="${model.parent.path}"/>
|
||||
</sub:url>
|
||||
<sub:url value="/wap/download.view" var="downloadUrl">
|
||||
<sub:param name="path" value="${model.parent.path}"/>
|
||||
</sub:url>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${fn:length(model.children) eq 1 and model.children[0].file}">
|
||||
<a href="${playUrl}">[<fmt:message key="wap.browse.playone"/>]</a><br/>
|
||||
<a href="${addUrl}">[<fmt:message key="wap.browse.addone"/>]</a><br/>
|
||||
<c:if test="${model.user.downloadRole}">
|
||||
<a href="${downloadUrl}">[<fmt:message key="wap.browse.downloadone"/>]</a><br/>
|
||||
</c:if>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<a href="${playUrl}">[<fmt:message key="wap.browse.playall"/>]</a><br/>
|
||||
<a href="${addUrl}">[<fmt:message key="wap.browse.addall"/>]</a><br/>
|
||||
<c:if test="${model.user.downloadRole}">
|
||||
<a href="${downloadUrl}">[<fmt:message key="wap.browse.downloadall"/>]</a><br/>
|
||||
</c:if>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<a href="<c:url value="/wap/index.view"/>">[<fmt:message key="common.home"/>]</a><br/>
|
||||
</b></small></p>
|
||||
|
||||
<p><small>
|
||||
|
||||
<c:forEach items="${model.children}" var="child">
|
||||
<sub:url value="/wap/browse.view" var="browseUrl">
|
||||
<sub:param name="path" value="${child.path}"/>
|
||||
</sub:url>
|
||||
<a href="${browseUrl}">${fn:escapeXml(child.title)}</a><br/>
|
||||
</c:forEach>
|
||||
|
||||
</small></p>
|
||||
</card>
|
||||
</wml>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<%@ include file="../include.jsp" %>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Cache-Control" content="max-age=0" forua="true"/>
|
||||
<meta http-equiv="Cache-Control" content="must-revalidate" forua="true"/>
|
||||
</head>
|
||||
|
||||
<template>
|
||||
<do type="prev" name="back" label="<fmt:message key="common.back"/>"><prev/></do>
|
||||
</template>
|
||||
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
|
||||
|
||||
<%@ page language="java" contentType="text/vnd.wap.wml; charset=utf-8" pageEncoding="iso-8859-1" %>
|
||||
|
||||
<wml>
|
||||
|
||||
<%@ include file="head.jsp" %>
|
||||
|
||||
<card id="main" title="Libresonic" newcontext="false">
|
||||
<p>
|
||||
<small>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${empty model.artists}">
|
||||
|
||||
<b>
|
||||
<a href="<c:url value="/wap/playlist.view"/>">[<fmt:message key="wap.index.playlist"/>]</a>
|
||||
</b>
|
||||
<br/>
|
||||
<b>
|
||||
<a href="<c:url value="/wap/search.view"/>">[<fmt:message key="wap.index.search"/>]</a>
|
||||
</b>
|
||||
<br/>
|
||||
<b>
|
||||
<a href="<c:url value="/wap/settings.view"/>">[<fmt:message key="wap.index.settings"/>]</a>
|
||||
</b>
|
||||
<br/>
|
||||
</small>
|
||||
</p>
|
||||
<p>
|
||||
<small>
|
||||
<c:forEach items="${model.indexes}" var="index">
|
||||
<sub:url var="url" value="/wap/index.view">
|
||||
<sub:param name="index" value="${index.index}"/>
|
||||
</sub:url>
|
||||
<a href="${url}">${index.index}</a>
|
||||
</c:forEach>
|
||||
</c:when>
|
||||
|
||||
<c:otherwise>
|
||||
<c:forEach items="${model.artists}" var="artist">
|
||||
<c:forEach items="${artist.musicFiles}" var="mediaFile">
|
||||
<sub:url var="url" value="/wap/browse.view">
|
||||
<sub:param name="path" value="${mediaFile.path}"/>
|
||||
</sub:url>
|
||||
<a href="${url}">${fn:escapeXml(mediaFile.title)}</a>
|
||||
<br/>
|
||||
</c:forEach>
|
||||
</c:forEach>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
<c:if test="${model.noMusic}">
|
||||
<fmt:message key="wap.index.missing"/>
|
||||
</c:if>
|
||||
|
||||
</small>
|
||||
</p>
|
||||
</card>
|
||||
</wml>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
|
||||
|
||||
<%@ page language="java" contentType="text/vnd.wap.wml; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
|
||||
<wml>
|
||||
|
||||
<%@ include file="head.jsp" %>
|
||||
|
||||
<card id="main" title="Libresonic" newcontext="false">
|
||||
<p><small>
|
||||
|
||||
<c:forEach items="${model.playlists}" var="playlist">
|
||||
<sub:url var="url" value="/wap/playlist.view">
|
||||
<sub:param name="load" value="${playlist.id}"/>
|
||||
</sub:url>
|
||||
<b><a href="${url}">${fn:escapeXml(playlist.name)}</a></b><br/>
|
||||
</c:forEach>
|
||||
</small></p>
|
||||
|
||||
</card>
|
||||
</wml>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
|
||||
|
||||
<%@ page language="java" contentType="text/vnd.wap.wml; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
|
||||
<wml>
|
||||
|
||||
<%@ include file="head.jsp" %>
|
||||
|
||||
<c:if test="${fn:length(model.players) eq 1}">
|
||||
<c:choose>
|
||||
<c:when test="${empty model.players[0].name}">
|
||||
<c:set var="playerName" value=" - Player ${model.players[0].id}"/>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<c:set var="playerName" value=" - ${model.players[0].name}"/>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</c:if>
|
||||
|
||||
|
||||
<card id="main" title="Libresonic" newcontext="false">
|
||||
<p><small><b><fmt:message key="wap.playlist.title"/>${playerName}</b></small></p>
|
||||
<p><small>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${empty model.players}">
|
||||
<fmt:message key="wap.playlist.noplayer"/>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<b><a href="<c:url value="/wap/index.view"/>">[<fmt:message key="common.home"/>]</a></b><br/>
|
||||
<b><a href="<c:url value="/wap/loadPlaylist.view"/>">[<fmt:message key="wap.playlist.load"/>]</a></b><br/>
|
||||
<b><a href="<c:url value="/wap/playlist.view?random"/>">[<fmt:message key="wap.playlist.random"/>]</a></b><br/>
|
||||
|
||||
<c:set var="playlist" value="${model.players[0].playlist}"/>
|
||||
|
||||
<c:if test="${not empty playlist.files}">
|
||||
<b><a href="<c:url value="/play.m3u"/>">[<fmt:message key="wap.playlist.play"/>]</a></b><br/>
|
||||
<b><a href="<c:url value="/wap/playlist.view?clear"/>">[<fmt:message key="wap.playlist.clear"/>]</a></b><br/>
|
||||
</small></p>
|
||||
<p><small>
|
||||
|
||||
<c:forEach items="${playlist.files}" var="file" varStatus="loopStatus">
|
||||
<c:set var="isCurrent" value="${(file eq playlist.currentFile) and (loopStatus.count - 1 eq playlist.index)}"/>
|
||||
${isCurrent ? "<b>" : ""}
|
||||
<a href="<c:url value="/wap/playlist.view?skip=${loopStatus.count - 1}"/>">${fn:escapeXml(file.title)}</a>
|
||||
${isCurrent ? "</b>" : ""}
|
||||
<br/>
|
||||
</c:forEach>
|
||||
</c:if>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</small></p>
|
||||
</card>
|
||||
</wml>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
|
||||
|
||||
<%@ page language="java" contentType="text/vnd.wap.wml; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
|
||||
<wml>
|
||||
<%@ include file="head.jsp" %>
|
||||
<card id="main" title="Libresonic" newcontext="false">
|
||||
<p>
|
||||
<input name="query" value="" size="10"/>
|
||||
<anchor><fmt:message key="wap.search.title"/>
|
||||
<go href="<c:url value="/wap/searchResult.view"/>" method="get">
|
||||
<postfield name="query" value="$query"/>
|
||||
</go>
|
||||
</anchor>
|
||||
</p>
|
||||
</card>
|
||||
</wml>
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
|
||||
|
||||
<%@ page language="java" contentType="text/vnd.wap.wml; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
|
||||
<wml>
|
||||
|
||||
<%@ include file="head.jsp" %>
|
||||
<card id="main" title="Libresonic" newcontext="false">
|
||||
<p><small>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${model.creatingIndex}">
|
||||
<fmt:message key="wap.searchresult.index"/>
|
||||
</c:when>
|
||||
|
||||
<c:otherwise>
|
||||
<c:forEach items="${model.hits}" var="hit">
|
||||
<sub:url var="url" value="/wap/browse.view">
|
||||
<sub:param name="path" value="${hit.path}"/>
|
||||
</sub:url>
|
||||
<a href="${url}">${fn:escapeXml(hit.title)}</a><br/>
|
||||
</c:forEach>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
</small></p>
|
||||
</card>
|
||||
|
||||
</wml>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
|
||||
|
||||
<%@ page language="java" contentType="text/vnd.wap.wml; charset=utf-8" pageEncoding="iso-8859-1"%>
|
||||
|
||||
<wml>
|
||||
|
||||
<%@ include file="head.jsp" %>
|
||||
<card id="main" title="Libresonic" newcontext="false">
|
||||
<p><small>
|
||||
<b><a href="<c:url value="/wap/index.view"/>">[<fmt:message key="common.home"/>]</a><br/></b>
|
||||
<b><a href="#player">[<fmt:message key="wap.settings.selectplayer"/>]</a></b>
|
||||
</small></p>
|
||||
</card>
|
||||
|
||||
<card id="player" title="Libresonic" newcontext="false">
|
||||
<p><small>
|
||||
|
||||
<b><a href="<c:url value="/wap/index.view"/>">[<fmt:message key="common.home"/>]</a><br/></b>
|
||||
</small></p><p><small>
|
||||
|
||||
<c:choose>
|
||||
<c:when test="${empty model.playerId}">
|
||||
<fmt:message key="wap.settings.allplayers"/>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<a href="<c:url value="/wap/selectPlayer.view"/>"><fmt:message key="wap.settings.allplayers"/></a>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
<br/>
|
||||
|
||||
<c:forEach items="${model.players}" var="player">
|
||||
<c:choose>
|
||||
<c:when test="${player.id eq model.playerId}">
|
||||
${player}
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<a href="<c:url value="/wap/selectPlayer.view?playerId=${player.id}"/>">${player}</a>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
<br/>
|
||||
</c:forEach>
|
||||
</small></p>
|
||||
</card>
|
||||
|
||||
</wml>
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
|
||||
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
|
||||
version="2.0">
|
||||
|
||||
<description>Libresonic tag library</description>
|
||||
<display-name>Libresonic tag library</display-name>
|
||||
<tlib-version>1.1</tlib-version>
|
||||
<short-name>sub</short-name>
|
||||
<uri>http://libresonic.org/taglib/sub</uri>
|
||||
|
||||
<tag>
|
||||
<description>
|
||||
Creates a URL with optional query parameters. Similar to 'c:url', but
|
||||
you may specify which character encoding to use for the URL query
|
||||
parameters. If no encoding is specified, the following steps are performed:
|
||||
a) Parameter values are encoded as the hexadecimal representation of the UTF-8 bytes of the original string.
|
||||
b) Parameter names are prepended with the suffix "Utf8Hex"
|
||||
</description>
|
||||
<name>url</name>
|
||||
<tag-class>org.libresonic.player.taglib.UrlTag</tag-class>
|
||||
<body-content>JSP</body-content>
|
||||
<attribute>
|
||||
<description>
|
||||
Name of the exported scoped variable for the
|
||||
processed url. The type of the scoped variable is
|
||||
String.
|
||||
</description>
|
||||
<name>var</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>false</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<description>URL to be processed.</description>
|
||||
<name>value</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<description>The encoding to use. Default is ISO-8859-1.</description>
|
||||
<name>encoding</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<description>Adds a parameter to a containing 'url' tag.</description>
|
||||
<name>param</name>
|
||||
<tag-class>org.libresonic.player.taglib.ParamTag</tag-class>
|
||||
<body-content>empty</body-content>
|
||||
<attribute>
|
||||
<description>Name of the query string parameter.</description>
|
||||
<name>name</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<description>Value of the parameter.</description>
|
||||
<name>value</name>
|
||||
<required>false</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<description>
|
||||
Converts a byte-count to a formatted string suitable for display to the user, with respect
|
||||
to the current locale.
|
||||
</description>
|
||||
<name>formatBytes</name>
|
||||
<tag-class>org.libresonic.player.taglib.FormatBytesTag</tag-class>
|
||||
<body-content>JSP</body-content>
|
||||
<attribute>
|
||||
<description>The byte count.</description>
|
||||
<name>bytes</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<description>
|
||||
Renders a Wiki text with markup to HTML, using the Radeox render engine.
|
||||
</description>
|
||||
<name>wiki</name>
|
||||
<tag-class>org.libresonic.player.taglib.WikiTag</tag-class>
|
||||
<body-content>JSP</body-content>
|
||||
<attribute>
|
||||
<description>The Wiki markup text.</description>
|
||||
<name>text</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
<tag>
|
||||
<description>
|
||||
Escapes the characters in a string using JavaScript rules.
|
||||
</description>
|
||||
<name>escapeJavaScript</name>
|
||||
<tag-class>org.libresonic.player.taglib.EscapeJavaScriptTag</tag-class>
|
||||
<body-content>JSP</body-content>
|
||||
<attribute>
|
||||
<description>The string to escape.</description>
|
||||
<name>string</name>
|
||||
<required>true</required>
|
||||
<rtexprvalue>true</rtexprvalue>
|
||||
</attribute>
|
||||
</tag>
|
||||
|
||||
</taglib>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
|
||||
|
||||
<cross-domain-policy>
|
||||
<allow-access-from domain="*" />
|
||||
</cross-domain-policy>
|
||||
|
After Width: | Height: | Size: 747 B |
|
After Width: | Height: | Size: 755 B |
|
After Width: | Height: | Size: 464 B |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 667 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 475 B |
|
After Width: | Height: | Size: 679 B |
|
After Width: | Height: | Size: 698 B |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 472 B |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 831 B |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 497 B |
|
After Width: | Height: | Size: 241 B |
|
After Width: | Height: | Size: 824 B |
|
After Width: | Height: | Size: 2.8 KiB |