fixup table layout, notifications
This commit is contained in:
parent
5f613a878e
commit
fc1d7c1242
9 changed files with 93 additions and 184 deletions
|
@ -43,8 +43,6 @@ body {
|
|||
border-color: #adadad;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#salamisandwich td:nth-child(3), th:nth-child(3) {
|
||||
text-align: right;
|
||||
}
|
||||
|
@ -53,6 +51,10 @@ tbody {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
td:last-child, td:first-child {
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.notifications {
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
|
|
|
@ -1,138 +0,0 @@
|
|||
/*!
|
||||
* Slider for Bootstrap
|
||||
*
|
||||
* Copyright 2012 Stefan Petre
|
||||
* Licensed under the Apache License v2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*/
|
||||
.slider {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
}
|
||||
.slider.slider-horizontal {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
}
|
||||
.slider.slider-horizontal .slider-track {
|
||||
height: 10px;
|
||||
width: 100%;
|
||||
margin-top: -5px;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
}
|
||||
.slider.slider-horizontal .slider-selection {
|
||||
height: 100%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
.slider.slider-horizontal .slider-handle {
|
||||
margin-left: -10px;
|
||||
margin-top: -5px;
|
||||
}
|
||||
.slider.slider-horizontal .slider-handle.triangle {
|
||||
border-width: 0 10px 10px 10px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-bottom-color: #0480be;
|
||||
margin-top: 0;
|
||||
}
|
||||
.slider.slider-vertical {
|
||||
height: 210px;
|
||||
width: 20px;
|
||||
}
|
||||
.slider.slider-vertical .slider-track {
|
||||
width: 10px;
|
||||
height: 100%;
|
||||
margin-left: -5px;
|
||||
left: 50%;
|
||||
top: 0;
|
||||
}
|
||||
.slider.slider-vertical .slider-selection {
|
||||
width: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
.slider.slider-vertical .slider-handle {
|
||||
margin-left: -5px;
|
||||
margin-top: -10px;
|
||||
}
|
||||
.slider.slider-vertical .slider-handle.triangle {
|
||||
border-width: 10px 0 10px 10px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
border-left-color: #0480be;
|
||||
margin-left: 0;
|
||||
}
|
||||
.slider input {
|
||||
display: none;
|
||||
}
|
||||
.slider .tooltip-inner {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.slider-track {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
background-color: #f7f7f7;
|
||||
background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));
|
||||
background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9);
|
||||
background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9);
|
||||
background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);
|
||||
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
-moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.slider-selection {
|
||||
position: absolute;
|
||||
background-color: #f7f7f7;
|
||||
background-image: -moz-linear-gradient(top, #f9f9f9, #f5f5f5);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f9f9f9), to(#f5f5f5));
|
||||
background-image: -webkit-linear-gradient(top, #f9f9f9, #f5f5f5);
|
||||
background-image: -o-linear-gradient(top, #f9f9f9, #f5f5f5);
|
||||
background-image: linear-gradient(to bottom, #f9f9f9, #f5f5f5);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9', endColorstr='#fff5f5f5', GradientType=0);
|
||||
-webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
|
||||
-moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
|
||||
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.slider-handle {
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-color: #0e90d2;
|
||||
background-image: -moz-linear-gradient(top, #149bdf, #0480be);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));
|
||||
background-image: -webkit-linear-gradient(top, #149bdf, #0480be);
|
||||
background-image: -o-linear-gradient(top, #149bdf, #0480be);
|
||||
background-image: linear-gradient(to bottom, #149bdf, #0480be);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
|
||||
-moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
|
||||
box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
|
||||
opacity: 0.8;
|
||||
border: 0px solid transparent;
|
||||
}
|
||||
.slider-handle.round {
|
||||
-webkit-border-radius: 20px;
|
||||
-moz-border-radius: 20px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
.slider-handle.triangle {
|
||||
background: transparent none;
|
||||
}
|
|
@ -50,7 +50,7 @@
|
|||
<button type="button" class="btn btn-default" onclick="socket.send('MPD_API_SET_STOP');">
|
||||
<span id="stop-icon" class="glyphicon glyphicon-stop"></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default" onclick="socket.send('MPD_API_SET_PAUSE');">
|
||||
<button type="button" class="btn btn-default" onclick="clickPlay();">
|
||||
<span id="play-icon" class="glyphicon glyphicon-pause"></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default" onclick="socket.send('MPD_API_SET_PREV');">
|
||||
|
@ -103,6 +103,7 @@
|
|||
<th>#</th>
|
||||
<th>Title</th>
|
||||
<th>Duration</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
2
htdocs/js/bootstrap-notify.js
vendored
2
htdocs/js/bootstrap-notify.js
vendored
|
@ -46,7 +46,7 @@
|
|||
this.$note.html(this.options.message);
|
||||
|
||||
if(this.options.closable)
|
||||
var link = $('<a class="close pull-right" href="#">×</a>');
|
||||
var link = $('<a class="close pull-right" href="#"> ×</a>');
|
||||
$(link).on('click', $.proxy(onClose, this));
|
||||
this.$note.prepend(link);
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ var current_song = new Object();
|
|||
|
||||
var app = $.sammy(function() {
|
||||
this.before('/', function(e, data) {
|
||||
socket.send("MPD_API_GET_TRACK_INFO");
|
||||
$('#nav_links > li').removeClass('active');
|
||||
});
|
||||
|
||||
|
@ -74,8 +73,8 @@ function webSocketConnect() {
|
|||
try {
|
||||
socket.onopen = function() {
|
||||
$('.top-right').notify({
|
||||
message:{text:"Connected"},
|
||||
fadeOut: { enabled: true, delay: 1000 }
|
||||
message:{text:"Connected to ympd"},
|
||||
fadeOut: { enabled: true, delay: 500 }
|
||||
}).show();
|
||||
|
||||
app.run();
|
||||
|
@ -102,10 +101,10 @@ function webSocketConnect() {
|
|||
var seconds = obj.data[song].duration - minutes * 60;
|
||||
|
||||
$('#salamisandwich > tbody').append(
|
||||
"<tr trackid=\"" + obj.data[song].id + "\"><td>" + obj.data[song].pos + "</td>" +
|
||||
"<tr trackid=\"" + obj.data[song].id + "\"><td>" + (obj.data[song].pos + 1) + "</td>" +
|
||||
"<td>"+ obj.data[song].title +"</td>" +
|
||||
"<td>"+ minutes + ":" + (seconds < 10 ? '0' : '') + seconds +
|
||||
"</td></tr>");
|
||||
"</td><td></td></tr>");
|
||||
}
|
||||
|
||||
$('#salamisandwich > tbody > tr').on({
|
||||
|
@ -139,7 +138,7 @@ function webSocketConnect() {
|
|||
"<tr uri=\"" + obj.data[item].dir + "\" class=\"dir\">" +
|
||||
"<td><span class=\"glyphicon glyphicon-folder-open\"></span></td>" +
|
||||
"<td><a>" + basename(obj.data[item].dir) + "</a></td>" +
|
||||
"<td></td></tr>");
|
||||
"<td></td><td></td></tr>");
|
||||
break;
|
||||
case "song":
|
||||
var minutes = Math.floor(obj.data[item].duration / 60);
|
||||
|
@ -149,7 +148,7 @@ function webSocketConnect() {
|
|||
"<tr uri=\"" + obj.data[item].uri + "\" class=\"song\">" +
|
||||
"<td><span class=\"glyphicon glyphicon-music\"></span></td>" +
|
||||
"<td>" + obj.data[item].title +"</td>" +
|
||||
"<td>"+ minutes + ":" + (seconds < 10 ? '0' : '') + seconds +"</td></tr>");
|
||||
"<td>"+ minutes + ":" + (seconds < 10 ? '0' : '') + seconds +"</td><td></td></tr>");
|
||||
break;
|
||||
|
||||
case "playlist":
|
||||
|
@ -157,29 +156,33 @@ function webSocketConnect() {
|
|||
}
|
||||
}
|
||||
|
||||
function appendClickableIcon(appendTo, onClickAction, glyphicon) {
|
||||
$(appendTo).children().last().append(
|
||||
"<a role=\"button\" class=\"pull-right btn-group-hover\">" +
|
||||
"<span class=\"glyphicon glyphicon-" + glyphicon + "\"></span></a>")
|
||||
.find('a').click(function(e) {
|
||||
e.stopPropagation();
|
||||
socket.send(onClickAction + "," + $(this).parents("tr").attr("uri"));
|
||||
$('.top-right').notify({
|
||||
message:{
|
||||
text: $('td:nth-child(2)', $(this).parents("tr")).text() + " added"
|
||||
} }).show();
|
||||
}).fadeTo('fast',1);
|
||||
}
|
||||
|
||||
$('#salamisandwich > tbody > tr').on({
|
||||
mouseenter: function(){
|
||||
if($(this).is(".dir")) {
|
||||
$(this).children().last().append(
|
||||
"<a role=\"button\" class=\"pull-right btn-group-hover\">" +
|
||||
"Add Directory <span class=\"glyphicon glyphicon-plus\"></span></a>")
|
||||
.find('a').click(function(e) {
|
||||
e.stopPropagation();
|
||||
socket.send("MPD_API_ADD_TRACK," + $(this).parents("tr").attr("uri"));
|
||||
$('.top-right').notify({
|
||||
message:{
|
||||
text:"Added " + $('td:nth-child(2)', $(this).parents("tr")).text() + " to playlist "
|
||||
}
|
||||
}).show();
|
||||
}).fadeTo('fast',1);
|
||||
}
|
||||
mouseenter: function() {
|
||||
if($(this).is(".dir"))
|
||||
appendClickableIcon($(this), 'MPD_API_ADD_TRACK', 'plus');
|
||||
else if($(this).is(".song"))
|
||||
appendClickableIcon($(this), 'MPD_API_ADD_PLAY_TRACK', 'play');
|
||||
},
|
||||
click: function() {
|
||||
if($(this).is(".song")) {
|
||||
socket.send("MPD_API_ADD_TRACK," + $(this).attr("uri"));
|
||||
$('.top-right').notify({
|
||||
message:{
|
||||
text:"Added " + $('td:nth-child(2)', this).text() + " to playlist "
|
||||
text: $('td:nth-child(2)', this).text() + " added"
|
||||
}
|
||||
}).show();
|
||||
|
||||
|
@ -239,9 +242,6 @@ function webSocketConnect() {
|
|||
else
|
||||
$('#btnrepeat').removeClass("active");
|
||||
|
||||
if(obj.data.elapsedTime <= 1)
|
||||
socket.send("MPD_API_GET_TRACK_INFO");
|
||||
|
||||
last_state = obj;
|
||||
break;
|
||||
case "disconnected":
|
||||
|
@ -256,12 +256,23 @@ function webSocketConnect() {
|
|||
if(current_app === 'playlist')
|
||||
$.get( "/api/get_playlist", socket.onmessage);
|
||||
break;
|
||||
case "current_song":
|
||||
case "song_change":
|
||||
$('#currenttrack').text(" " + obj.data.title);
|
||||
if(obj.data.album)
|
||||
var notification = "<strong><h4>" + obj.data.title + "</h4></strong>";
|
||||
|
||||
if(obj.data.album) {
|
||||
$('#album').text(obj.data.album);
|
||||
if(obj.data.artist)
|
||||
notification += obj.data.album + "<br />";
|
||||
}
|
||||
if(obj.data.artist) {
|
||||
$('#artist').text(obj.data.artist);
|
||||
notification += obj.data.artist + "<br />";
|
||||
}
|
||||
|
||||
$('.top-right').notify({
|
||||
message:{html: notification},
|
||||
type: "info",
|
||||
}).show();
|
||||
break;
|
||||
case "error":
|
||||
$('.top-right').notify({
|
||||
|
@ -350,14 +361,20 @@ var updatePlayIcon = function(state)
|
|||
}
|
||||
}
|
||||
|
||||
function updateDB()
|
||||
{
|
||||
function updateDB() {
|
||||
socket.send('MPD_API_UPDATE_DB');
|
||||
$('.top-right').notify({
|
||||
message:{text:"Updating MPD Database... "}
|
||||
}).show();
|
||||
}
|
||||
|
||||
function clickPlay() {
|
||||
if($('#track-icon').hasClass('glyphicon-stop'))
|
||||
socket.send('MPD_API_SET_PLAY');
|
||||
else
|
||||
socket.send('MPD_API_SET_PAUSE');
|
||||
}
|
||||
|
||||
function basename(path) {
|
||||
return path.split('/').reverse()[0];
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ struct serveable {
|
|||
|
||||
static const struct serveable whitelist[] = {
|
||||
{ "/css/bootstrap.css", "text/css" },
|
||||
{ "/css/slider.css", "text/css" },
|
||||
{ "/css/mpd.css", "text/css" },
|
||||
|
||||
{ "/js/bootstrap.min.js", "text/javascript" },
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
struct mpd_connection *conn = NULL;
|
||||
enum mpd_conn_states mpd_conn_state = MPD_DISCONNECTED;
|
||||
enum mpd_state mpd_play_state = MPD_STATE_UNKNOWN;
|
||||
unsigned queue_version;
|
||||
|
||||
int callback_ympd(struct libwebsocket_context *context,
|
||||
struct libwebsocket *wsi,
|
||||
|
@ -53,10 +52,9 @@ int callback_ympd(struct libwebsocket_context *context,
|
|||
else if(mpd_conn_state != MPD_CONNECTED) {
|
||||
n = snprintf(p, MAX_SIZE, "{\"type\":\"disconnected\"}");
|
||||
}
|
||||
else if((pss->queue_version != queue_version) || (pss->do_send & DO_SEND_PLAYLIST)) {
|
||||
else if(pss->do_send & DO_SEND_PLAYLIST) {
|
||||
/*n = mpd_put_playlist(p);*/
|
||||
n = snprintf(p, MAX_SIZE, "{\"type\":\"update_playlist\"}");
|
||||
pss->queue_version = queue_version;
|
||||
pss->do_send &= ~DO_SEND_PLAYLIST;
|
||||
}
|
||||
else if(pss->do_send & DO_SEND_TRACK_INFO) {
|
||||
|
@ -68,8 +66,24 @@ int callback_ympd(struct libwebsocket_context *context,
|
|||
pss->do_send &= ~DO_SEND_BROWSE;
|
||||
free(pss->browse_path);
|
||||
}
|
||||
else
|
||||
n = mpd_put_state(p);
|
||||
else {
|
||||
/* Default Action */
|
||||
int current_song_id;
|
||||
unsigned queue_version;
|
||||
|
||||
n = mpd_put_state(p, ¤t_song_id, &queue_version);
|
||||
if(current_song_id != pss->current_song_id)
|
||||
{
|
||||
pss->current_song_id = current_song_id;
|
||||
pss->do_send |= DO_SEND_TRACK_INFO;
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
}
|
||||
else if(pss->queue_version != queue_version) {
|
||||
pss->queue_version = queue_version;
|
||||
pss->do_send |= DO_SEND_PLAYLIST;
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
}
|
||||
}
|
||||
|
||||
if(n > 0)
|
||||
m = libwebsocket_write(wsi, (unsigned char *)p, n, LWS_WRITE_TEXT);
|
||||
|
@ -105,6 +119,8 @@ int callback_ympd(struct libwebsocket_context *context,
|
|||
unsigned id;
|
||||
if(sscanf(in, "MPD_API_RM_TRACK,%u", &id))
|
||||
mpd_run_delete_id(conn, id);
|
||||
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
}
|
||||
else if(!strncmp((const char *)in, MPD_API_PLAY_TRACK, sizeof(MPD_API_PLAY_TRACK)-1)) {
|
||||
unsigned id;
|
||||
|
@ -156,6 +172,16 @@ int callback_ympd(struct libwebsocket_context *context,
|
|||
free(uri);
|
||||
}
|
||||
}
|
||||
else if(!strncmp((const char *)in, MPD_API_ADD_PLAY_TRACK, sizeof(MPD_API_ADD_PLAY_TRACK)-1)) {
|
||||
char *uri;
|
||||
if(sscanf(in, "MPD_API_ADD_PLAY_TRACK,%m[^\t\n]", &uri) && uri != NULL) {
|
||||
int added_song = mpd_run_add_id(conn, uri);
|
||||
if(added_song != -1)
|
||||
mpd_run_play_id(conn, added_song);
|
||||
free(uri);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS)
|
||||
pss->do_send |= DO_SEND_ERROR;
|
||||
|
@ -226,7 +252,7 @@ char* mpd_get_title(struct mpd_song const *song)
|
|||
return basename(str);
|
||||
}
|
||||
|
||||
int mpd_put_state(char *buffer)
|
||||
int mpd_put_state(char *buffer, int *current_song_id, unsigned *queue_version)
|
||||
{
|
||||
struct mpd_status *status;
|
||||
int len;
|
||||
|
@ -256,7 +282,8 @@ int mpd_put_state(char *buffer)
|
|||
mpd_status_get_total_time(status),
|
||||
mpd_status_get_song_id(status));
|
||||
|
||||
queue_version = mpd_status_get_queue_version(status);
|
||||
*current_song_id = mpd_status_get_song_id(status);
|
||||
*queue_version = mpd_status_get_queue_version(status);
|
||||
mpd_status_free(status);
|
||||
return len;
|
||||
}
|
||||
|
@ -271,7 +298,7 @@ int mpd_put_current_song(char *buffer)
|
|||
if(song == NULL)
|
||||
return 0;
|
||||
|
||||
cur += snprintf(cur, end - cur, "{\"type\": \"current_song\", \"data\":"
|
||||
cur += snprintf(cur, end - cur, "{\"type\": \"song_change\", \"data\":"
|
||||
"{\"pos\":%d, \"title\":\"%s\"",
|
||||
mpd_song_get_pos(song),
|
||||
mpd_get_title(song));
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#define MPD_API_GET_TRACK_INFO "MPD_API_GET_TRACK_INFO"
|
||||
#define MPD_API_GET_BROWSE "MPD_API_GET_BROWSE"
|
||||
#define MPD_API_ADD_TRACK "MPD_API_ADD_TRACK"
|
||||
#define MPD_API_ADD_PLAY_TRACK "MPD_API_ADD_PLAY_TRACK"
|
||||
#define MPD_API_PLAY_TRACK "MPD_API_PLAY_TRACK"
|
||||
#define MPD_API_RM_TRACK "MPD_API_RM_TRACK"
|
||||
#define MPD_API_RM_ALL "MPD_API_RM_ALL"
|
||||
|
@ -36,6 +37,7 @@
|
|||
struct per_session_data__ympd {
|
||||
int do_send;
|
||||
unsigned queue_version;
|
||||
int current_song_id;
|
||||
char *browse_path;
|
||||
};
|
||||
|
||||
|
@ -51,7 +53,7 @@ int callback_ympd(struct libwebsocket_context *context,
|
|||
enum libwebsocket_callback_reasons reason,
|
||||
void *user, void *in, size_t len);
|
||||
void mpd_loop();
|
||||
int mpd_put_state(char *buffer);
|
||||
int mpd_put_state(char *buffer, int *current_song_id, unsigned *queue_version);
|
||||
int mpd_put_current_song(char *buffer);
|
||||
int mpd_put_playlist(char *buffer);
|
||||
int mpd_put_browse(char *buffer, char *path);
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
ympd_process.c
|
Loading…
Reference in a new issue