2014-02-22 00:57:26 +00:00
|
|
|
/* ympd
|
|
|
|
(c) 2013-2014 Andrew Karpow <andy@ndyk.de>
|
2016-09-11 15:54:25 +00:00
|
|
|
This project's homepage is: https://www.ympd.org
|
2014-02-22 00:57:26 +00:00
|
|
|
|
|
|
|
This program 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; version 2 of the License.
|
|
|
|
|
|
|
|
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2014-01-17 18:41:41 +00:00
|
|
|
*/
|
|
|
|
|
2013-11-04 17:18:38 +00:00
|
|
|
var socket;
|
2013-11-05 13:59:12 +00:00
|
|
|
var last_state;
|
2015-04-28 09:08:21 +00:00
|
|
|
var last_outputs;
|
2013-11-07 12:47:31 +00:00
|
|
|
var current_app;
|
2014-02-22 01:11:45 +00:00
|
|
|
var pagination = 0;
|
|
|
|
var browsepath;
|
2014-01-17 17:34:22 +00:00
|
|
|
var lastSongTitle = "";
|
2014-01-16 17:32:20 +00:00
|
|
|
var current_song = new Object();
|
2014-02-22 01:11:45 +00:00
|
|
|
var MAX_ELEMENTS_PER_PAGE = 512;
|
2015-08-27 14:15:23 +00:00
|
|
|
var dirble_selected_cat = "";
|
|
|
|
var dirble_catid = "";
|
|
|
|
var dirble_page = 1;
|
2015-10-22 15:48:42 +00:00
|
|
|
var isTouch = Modernizr.touch ? 1 : 0;
|
2016-06-08 21:20:27 +00:00
|
|
|
var filter = undefined;
|
2016-09-11 15:54:25 +00:00
|
|
|
var dirble_api_token = "";
|
|
|
|
var dirble_stations = false;
|
2013-11-04 17:18:38 +00:00
|
|
|
|
2013-11-07 12:47:31 +00:00
|
|
|
var app = $.sammy(function() {
|
2014-01-16 17:32:20 +00:00
|
|
|
|
2014-02-22 01:11:45 +00:00
|
|
|
function runBrowse() {
|
2014-02-22 00:57:26 +00:00
|
|
|
current_app = 'queue';
|
2014-02-22 01:11:45 +00:00
|
|
|
|
2014-01-16 17:32:20 +00:00
|
|
|
$('#breadcrump').addClass('hide');
|
2016-06-08 21:20:27 +00:00
|
|
|
$('#filter').addClass('hide');
|
2015-08-27 14:15:23 +00:00
|
|
|
$('#salamisandwich').removeClass('hide').find("tr:gt(0)").remove();
|
|
|
|
$('#dirble_panel').addClass('hide');
|
2014-02-22 01:11:45 +00:00
|
|
|
socket.send('MPD_API_GET_QUEUE,'+pagination);
|
2014-01-16 17:32:20 +00:00
|
|
|
|
2014-02-22 00:57:26 +00:00
|
|
|
$('#panel-heading').text("Queue");
|
|
|
|
$('#queue').addClass('active');
|
2014-02-22 01:11:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function prepare() {
|
|
|
|
$('#nav_links > li').removeClass('active');
|
|
|
|
$('.page-btn').addClass('hide');
|
2015-08-17 21:01:47 +00:00
|
|
|
$('#add-all-songs').hide();
|
2014-02-22 01:11:45 +00:00
|
|
|
pagination = 0;
|
|
|
|
browsepath = '';
|
|
|
|
}
|
|
|
|
|
|
|
|
this.get(/\#\/(\d+)/, function() {
|
|
|
|
prepare();
|
|
|
|
pagination = parseInt(this.params['splat'][0]);
|
|
|
|
runBrowse();
|
2014-01-16 17:32:20 +00:00
|
|
|
});
|
|
|
|
|
2014-02-22 01:11:45 +00:00
|
|
|
this.get(/\#\/browse\/(\d+)\/(.*)/, function() {
|
|
|
|
prepare();
|
|
|
|
browsepath = this.params['splat'][1];
|
|
|
|
pagination = parseInt(this.params['splat'][0]);
|
2014-01-16 17:32:20 +00:00
|
|
|
current_app = 'browse';
|
2016-06-08 21:20:27 +00:00
|
|
|
$('#breadcrump').removeClass('hide').empty().append("<li><a href=\"#/browse/0/\" onclick=\"set_filter()\">root</a></li>");
|
|
|
|
$('#filter').removeClass('hide');
|
2015-08-27 14:15:23 +00:00
|
|
|
$('#salamisandwich').removeClass('hide').find("tr:gt(0)").remove();
|
|
|
|
$('#dirble_panel').addClass('hide');
|
2014-02-22 01:11:45 +00:00
|
|
|
socket.send('MPD_API_GET_BROWSE,'+pagination+','+(browsepath ? browsepath : "/"));
|
2015-08-17 21:01:47 +00:00
|
|
|
// Don't add all songs from root
|
|
|
|
if (browsepath) {
|
|
|
|
var add_all_songs = $('#add-all-songs');
|
|
|
|
add_all_songs.off(); // remove previous binds
|
|
|
|
add_all_songs.on('click', function() {
|
|
|
|
socket.send('MPD_API_ADD_TRACK,'+browsepath);
|
|
|
|
});
|
|
|
|
add_all_songs.show();
|
|
|
|
}
|
2014-01-16 17:32:20 +00:00
|
|
|
|
2014-02-22 01:11:45 +00:00
|
|
|
$('#panel-heading').text("Browse database: "+browsepath);
|
|
|
|
var path_array = browsepath.split('/');
|
2014-01-16 17:32:20 +00:00
|
|
|
var full_path = "";
|
|
|
|
$.each(path_array, function(index, chunk) {
|
|
|
|
if(path_array.length - 1 == index) {
|
|
|
|
$('#breadcrump').append("<li class=\"active\">"+ chunk + "</li>");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
full_path = full_path + chunk;
|
2014-02-22 01:11:45 +00:00
|
|
|
$('#breadcrump').append("<li><a href=\"#/browse/0/" + full_path + "\">"+chunk+"</a></li>");
|
2014-01-16 17:32:20 +00:00
|
|
|
full_path += "/";
|
|
|
|
});
|
|
|
|
$('#browse').addClass('active');
|
|
|
|
});
|
|
|
|
|
2014-02-22 00:57:26 +00:00
|
|
|
this.get(/\#\/search\/(.*)/, function() {
|
|
|
|
current_app = 'search';
|
|
|
|
$('#salamisandwich').find("tr:gt(0)").remove();
|
2015-08-27 14:15:23 +00:00
|
|
|
$('#dirble_panel').addClass('hide');
|
2014-02-22 00:57:26 +00:00
|
|
|
var searchstr = this.params['splat'][0];
|
|
|
|
|
|
|
|
$('#search > div > input').val(searchstr);
|
|
|
|
socket.send('MPD_API_SEARCH,' + searchstr);
|
|
|
|
|
|
|
|
$('#panel-heading').text("Search: "+searchstr);
|
|
|
|
});
|
|
|
|
|
2015-08-27 14:15:23 +00:00
|
|
|
|
|
|
|
this.get(/\#\/dirble\/(\d+)\/(\d+)/, function() {
|
|
|
|
prepare();
|
|
|
|
current_app = 'dirble';
|
|
|
|
$('#breadcrump').removeClass('hide').empty().append("<li><a href=\"#/dirble/\">Categories</a></li><li>"+dirble_selected_cat+"</li>");
|
|
|
|
$('#salamisandwich').addClass('hide');
|
|
|
|
$('#dirble_panel').removeClass('hide');
|
|
|
|
$('#dirble_loading').removeClass('hide');
|
|
|
|
$('#dirble_left').find("tr:gt(0)").remove();
|
|
|
|
$('#dirble_right').find("tr:gt(0)").remove();
|
|
|
|
|
|
|
|
$('#panel-heading').text("Dirble");
|
|
|
|
$('#dirble').addClass('active');
|
|
|
|
|
|
|
|
$('#next').addClass('hide');
|
|
|
|
|
|
|
|
if (this.params['splat'][1] > 1) $('#prev').removeClass('hide');
|
|
|
|
else $('#prev').addClass('hide');
|
|
|
|
|
|
|
|
dirble_catid = this.params['splat'][0];
|
|
|
|
dirble_page = this.params['splat'][1];
|
|
|
|
|
2016-09-11 15:54:25 +00:00
|
|
|
dirble_stations = true;
|
|
|
|
|
|
|
|
if(dirble_api_token) {
|
|
|
|
dirble_load_stations();
|
|
|
|
} else {
|
|
|
|
getDirbleApiToken();
|
|
|
|
}
|
2015-08-27 14:15:23 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
this.get(/\#\/dirble\//, function() {
|
|
|
|
prepare();
|
|
|
|
current_app = 'dirble';
|
|
|
|
$('#breadcrump').removeClass('hide').empty().append("<li>Categories</li>");
|
|
|
|
$('#salamisandwich').addClass('hide');
|
|
|
|
$('#dirble_panel').removeClass('hide');
|
|
|
|
$('#dirble_loading').removeClass('hide');
|
|
|
|
$('#dirble_left').find("tr:gt(0)").remove();
|
|
|
|
$('#dirble_right').find("tr:gt(0)").remove();
|
|
|
|
|
|
|
|
$('#panel-heading').text("Dirble");
|
|
|
|
$('#dirble').addClass('active');
|
|
|
|
|
2016-09-11 15:54:25 +00:00
|
|
|
dirble_stations = false;
|
|
|
|
|
|
|
|
if(dirble_api_token) {
|
|
|
|
dirble_load_categories();
|
|
|
|
} else {
|
|
|
|
getDirbleApiToken();
|
|
|
|
}
|
2015-08-27 14:15:23 +00:00
|
|
|
});
|
|
|
|
|
2014-01-16 17:32:20 +00:00
|
|
|
this.get("/", function(context) {
|
2014-02-22 01:11:45 +00:00
|
|
|
context.redirect("#/0");
|
2014-01-16 17:32:20 +00:00
|
|
|
});
|
2013-11-07 12:47:31 +00:00
|
|
|
});
|
|
|
|
|
2013-11-07 09:09:40 +00:00
|
|
|
$(document).ready(function(){
|
2014-01-16 17:32:20 +00:00
|
|
|
webSocketConnect();
|
|
|
|
$("#volumeslider").slider(0);
|
|
|
|
$("#volumeslider").on('slider.newValue', function(evt,data){
|
|
|
|
socket.send("MPD_API_SET_VOLUME,"+data.val);
|
|
|
|
});
|
|
|
|
$('#progressbar').slider(0);
|
|
|
|
$("#progressbar").on('slider.newValue', function(evt,data){
|
2014-01-17 15:41:54 +00:00
|
|
|
if(current_song && current_song.currentSongId >= 0) {
|
2014-01-16 17:32:20 +00:00
|
|
|
var seekVal = Math.ceil(current_song.totalTime*(data.val/100));
|
|
|
|
socket.send("MPD_API_SET_SEEK,"+current_song.currentSongId+","+seekVal);
|
|
|
|
}
|
|
|
|
});
|
2014-01-17 17:34:22 +00:00
|
|
|
|
2015-07-16 09:50:54 +00:00
|
|
|
$('#addstream').on('shown.bs.modal', function () {
|
|
|
|
$('#streamurl').focus();
|
|
|
|
})
|
|
|
|
$('#addstream form').on('submit', function (e) {
|
|
|
|
addStream();
|
|
|
|
});
|
|
|
|
|
2014-01-17 17:34:22 +00:00
|
|
|
if(!notificationsSupported())
|
|
|
|
$('#btnnotify').addClass("disabled");
|
|
|
|
else
|
|
|
|
if ($.cookie("notification") === "true")
|
|
|
|
$('#btnnotify').addClass("active")
|
2016-06-08 21:20:27 +00:00
|
|
|
|
|
|
|
add_filter();
|
2013-11-07 09:09:40 +00:00
|
|
|
});
|
|
|
|
|
2013-11-05 13:59:12 +00:00
|
|
|
|
|
|
|
function webSocketConnect() {
|
2014-01-16 17:32:20 +00:00
|
|
|
if (typeof MozWebSocket != "undefined") {
|
2014-02-16 18:46:53 +00:00
|
|
|
socket = new MozWebSocket(get_appropriate_ws_url());
|
2014-01-16 17:32:20 +00:00
|
|
|
} else {
|
2014-02-16 18:46:53 +00:00
|
|
|
socket = new WebSocket(get_appropriate_ws_url());
|
2014-01-16 17:32:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
socket.onopen = function() {
|
2014-02-16 18:46:53 +00:00
|
|
|
console.log("connected");
|
2014-01-16 17:32:20 +00:00
|
|
|
$('.top-right').notify({
|
2014-01-17 15:26:26 +00:00
|
|
|
message:{text:"Connected to ympd"},
|
|
|
|
fadeOut: { enabled: true, delay: 500 }
|
2014-01-16 17:32:20 +00:00
|
|
|
}).show();
|
|
|
|
|
|
|
|
app.run();
|
2015-04-28 09:08:21 +00:00
|
|
|
/* emit initial request for output names */
|
|
|
|
socket.send("MPD_API_GET_OUTPUTS");
|
2014-01-16 17:32:20 +00:00
|
|
|
}
|
|
|
|
|
2014-02-22 01:11:45 +00:00
|
|
|
socket.onmessage = function got_packet(msg) {
|
|
|
|
if(msg.data === last_state || msg.data.length == 0)
|
2014-02-22 00:57:26 +00:00
|
|
|
return;
|
2014-01-16 17:32:20 +00:00
|
|
|
|
2014-02-22 00:57:26 +00:00
|
|
|
var obj = JSON.parse(msg.data);
|
2014-01-16 17:32:20 +00:00
|
|
|
|
|
|
|
switch (obj.type) {
|
2014-02-22 00:57:26 +00:00
|
|
|
case "queue":
|
|
|
|
if(current_app !== 'queue')
|
2014-01-16 17:32:20 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
$('#salamisandwich > tbody').empty();
|
|
|
|
for (var song in obj.data) {
|
|
|
|
var minutes = Math.floor(obj.data[song].duration / 60);
|
|
|
|
var seconds = obj.data[song].duration - minutes * 60;
|
|
|
|
|
|
|
|
$('#salamisandwich > tbody').append(
|
2014-01-17 15:26:26 +00:00
|
|
|
"<tr trackid=\"" + obj.data[song].id + "\"><td>" + (obj.data[song].pos + 1) + "</td>" +
|
2014-01-16 17:32:20 +00:00
|
|
|
"<td>"+ obj.data[song].title +"</td>" +
|
|
|
|
"<td>"+ minutes + ":" + (seconds < 10 ? '0' : '') + seconds +
|
2014-01-17 15:26:26 +00:00
|
|
|
"</td><td></td></tr>");
|
2014-01-16 17:32:20 +00:00
|
|
|
}
|
|
|
|
|
2015-09-04 14:43:16 +00:00
|
|
|
if(obj.data.length && obj.data[obj.data.length-1].pos + 1 >= pagination + MAX_ELEMENTS_PER_PAGE)
|
2014-02-22 01:11:45 +00:00
|
|
|
$('#next').removeClass('hide');
|
|
|
|
if(pagination > 0)
|
|
|
|
$('#prev').removeClass('hide');
|
2015-10-22 15:48:42 +00:00
|
|
|
if ( isTouch ) {
|
|
|
|
$('#salamisandwich > tbody > tr > td:last-child').append(
|
|
|
|
"<a class=\"pull-right btn-group-hover\" href=\"#/\" " +
|
2017-04-08 09:25:40 +00:00
|
|
|
"onclick=\"trash($(this).parents('tr'));\">" +
|
2015-10-22 15:48:42 +00:00
|
|
|
"<span class=\"glyphicon glyphicon-trash\"></span></a>");
|
|
|
|
} else {
|
|
|
|
$('#salamisandwich > tbody > tr').on({
|
|
|
|
mouseover: function(){
|
2017-04-08 09:25:40 +00:00
|
|
|
var doomed = $(this);
|
|
|
|
if ( $('#btntrashmodeup').hasClass('active') )
|
|
|
|
doomed = $("#salamisandwich > tbody > tr:lt(" + ($(this).index() + 1) + ")");
|
|
|
|
if ( $('#btntrashmodedown').hasClass('active') )
|
|
|
|
doomed = $("#salamisandwich > tbody > tr:gt(" + ($(this).index() - 1) + ")");
|
|
|
|
$.each(doomed, function(){
|
2015-10-22 15:48:42 +00:00
|
|
|
if($(this).children().last().has("a").length == 0)
|
|
|
|
$(this).children().last().append(
|
|
|
|
"<a class=\"pull-right btn-group-hover\" href=\"#/\" " +
|
2017-04-08 09:25:40 +00:00
|
|
|
"onclick=\"trash($(this).parents('tr'));\">" +
|
2015-10-22 15:48:42 +00:00
|
|
|
"<span class=\"glyphicon glyphicon-trash\"></span></a>")
|
|
|
|
.find('a').fadeTo('fast',1);
|
2017-04-08 09:25:40 +00:00
|
|
|
});
|
2015-10-22 15:48:42 +00:00
|
|
|
},
|
|
|
|
mouseleave: function(){
|
2017-04-08 09:25:40 +00:00
|
|
|
var doomed = $(this);
|
|
|
|
if ( $('#btntrashmodeup').hasClass('active') )
|
|
|
|
doomed = $("#salamisandwich > tbody > tr:lt(" + ($(this).index() + 1) + ")");
|
|
|
|
if ( $('#btntrashmodedown').hasClass('active') )
|
|
|
|
doomed = $("#salamisandwich > tbody > tr:gt(" + ($(this).index() - 1) + ")");
|
|
|
|
$.each(doomed, function(){$(this).children().last().find("a").stop().remove();});
|
2015-10-22 15:48:42 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
2014-02-22 01:11:45 +00:00
|
|
|
|
2014-01-16 17:32:20 +00:00
|
|
|
$('#salamisandwich > tbody > tr').on({
|
|
|
|
click: function() {
|
|
|
|
$('#salamisandwich > tbody > tr').removeClass('active');
|
|
|
|
socket.send('MPD_API_PLAY_TRACK,'+$(this).attr('trackid'));
|
|
|
|
$(this).addClass('active');
|
|
|
|
},
|
|
|
|
});
|
2015-09-04 14:43:16 +00:00
|
|
|
//Helper function to keep table row from collapsing when being sorted
|
|
|
|
var fixHelperModified = function(e, tr) {
|
|
|
|
var $originals = tr.children();
|
|
|
|
var $helper = tr.clone();
|
|
|
|
$helper.children().each(function(index)
|
|
|
|
{
|
|
|
|
$(this).width($originals.eq(index).width())
|
|
|
|
});
|
|
|
|
return $helper;
|
|
|
|
};
|
|
|
|
|
|
|
|
//Make queue table sortable
|
|
|
|
$("#salamisandwich > tbody").sortable({
|
|
|
|
helper: fixHelperModified,
|
|
|
|
stop: function(event,ui) {renumber_table('#salamisandwich',ui.item)}
|
|
|
|
}).disableSelection();
|
2014-01-16 17:32:20 +00:00
|
|
|
break;
|
2014-02-22 00:57:26 +00:00
|
|
|
case "search":
|
2014-02-22 01:11:45 +00:00
|
|
|
$('#wait').modal('hide');
|
2014-01-16 17:32:20 +00:00
|
|
|
case "browse":
|
2014-02-22 00:57:26 +00:00
|
|
|
if(current_app !== 'browse' && current_app !== 'search')
|
2014-01-16 17:32:20 +00:00
|
|
|
break;
|
|
|
|
|
Fix browsing for non-ascii entity URI under Safari
Previously, browsing entities with non-ascii characters in their URI
under Safari wouldn't work. Directories would be empty, songs wouldn't
be added. I haven't tried it, but this behavior seems to be common to
Webkit-based browsers, so Chrome would be affected too.
This turned out to be because Safari normalizes all unicode strings to
NFC, breaking the link with MPD-spewed URIs, which are in NFD.
An obvious fix would have been to normalize all URIs to NFD, but
unfortunately, Safari doesn't have `str.normalize()`. Adding
normalization capabilities to our JS side would have involved
introductiing libraries such as `unorm`, which is rather big.
We could have done it on the C side, but it involves introducing `icu`,
which is far from trivial too.
After much fussing around, I stumbled on a simple solution: URI-encode
our URI when creating our browser table row. This magically prevents
Safari from trying to mess with our unicode form before we get the
chance to send it back to our server.
2015-06-21 02:39:42 +00:00
|
|
|
/* The use of encodeURI() below might seem useless, but it's not. It prevents
|
|
|
|
* some browsers, such as Safari, from changing the normalization form of the
|
|
|
|
* URI from NFD to NFC, breaking our link with MPD.
|
|
|
|
*/
|
2015-09-26 12:32:14 +00:00
|
|
|
if ($('#salamisandwich > tbody').is(':ui-sortable')) {
|
|
|
|
$('#salamisandwich > tbody').sortable('destroy');
|
|
|
|
}
|
2014-01-16 17:32:20 +00:00
|
|
|
for (var item in obj.data) {
|
|
|
|
switch(obj.data[item].type) {
|
|
|
|
case "directory":
|
2016-06-08 21:20:27 +00:00
|
|
|
var clazz = 'dir';
|
|
|
|
if (filter !== undefined) {
|
|
|
|
var first = obj.data[item].dir[0];
|
|
|
|
if (filter === "#" && isNaN(first)) {
|
|
|
|
clazz += ' hide';
|
|
|
|
} else if (filter >= "A" && filter <= "Z" && first.toUpperCase() !== filter) {
|
|
|
|
clazz += ' hide';
|
|
|
|
} else if (filter === "||") {
|
|
|
|
clazz += ' hide';
|
|
|
|
}
|
|
|
|
}
|
2014-01-16 17:32:20 +00:00
|
|
|
$('#salamisandwich > tbody').append(
|
2016-06-08 21:20:27 +00:00
|
|
|
"<tr uri=\"" + encodeURI(obj.data[item].dir) + "\" class=\"" + clazz + "\">" +
|
Fix browsing for non-ascii entity URI under Safari
Previously, browsing entities with non-ascii characters in their URI
under Safari wouldn't work. Directories would be empty, songs wouldn't
be added. I haven't tried it, but this behavior seems to be common to
Webkit-based browsers, so Chrome would be affected too.
This turned out to be because Safari normalizes all unicode strings to
NFC, breaking the link with MPD-spewed URIs, which are in NFD.
An obvious fix would have been to normalize all URIs to NFD, but
unfortunately, Safari doesn't have `str.normalize()`. Adding
normalization capabilities to our JS side would have involved
introductiing libraries such as `unorm`, which is rather big.
We could have done it on the C side, but it involves introducing `icu`,
which is far from trivial too.
After much fussing around, I stumbled on a simple solution: URI-encode
our URI when creating our browser table row. This magically prevents
Safari from trying to mess with our unicode form before we get the
chance to send it back to our server.
2015-06-21 02:39:42 +00:00
|
|
|
"<td><span class=\"glyphicon glyphicon-folder-open\"></span></td>" +
|
|
|
|
"<td><a>" + basename(obj.data[item].dir) + "</a></td>" +
|
2014-02-22 00:57:26 +00:00
|
|
|
"<td></td><td></td></tr>"
|
|
|
|
);
|
2014-01-16 17:32:20 +00:00
|
|
|
break;
|
|
|
|
case "playlist":
|
2016-06-08 21:20:27 +00:00
|
|
|
var clazz = 'plist';
|
|
|
|
if (filter !== "||") {
|
|
|
|
clazz += ' hide';
|
|
|
|
}
|
2014-02-22 00:57:26 +00:00
|
|
|
$('#salamisandwich > tbody').append(
|
2016-06-08 21:20:27 +00:00
|
|
|
"<tr uri=\"" + encodeURI(obj.data[item].plist) + "\" class=\"" + clazz + "\">" +
|
Fix browsing for non-ascii entity URI under Safari
Previously, browsing entities with non-ascii characters in their URI
under Safari wouldn't work. Directories would be empty, songs wouldn't
be added. I haven't tried it, but this behavior seems to be common to
Webkit-based browsers, so Chrome would be affected too.
This turned out to be because Safari normalizes all unicode strings to
NFC, breaking the link with MPD-spewed URIs, which are in NFD.
An obvious fix would have been to normalize all URIs to NFD, but
unfortunately, Safari doesn't have `str.normalize()`. Adding
normalization capabilities to our JS side would have involved
introductiing libraries such as `unorm`, which is rather big.
We could have done it on the C side, but it involves introducing `icu`,
which is far from trivial too.
After much fussing around, I stumbled on a simple solution: URI-encode
our URI when creating our browser table row. This magically prevents
Safari from trying to mess with our unicode form before we get the
chance to send it back to our server.
2015-06-21 02:39:42 +00:00
|
|
|
"<td><span class=\"glyphicon glyphicon-list\"></span></td>" +
|
|
|
|
"<td><a>" + basename(obj.data[item].plist) + "</a></td>" +
|
2014-02-22 00:57:26 +00:00
|
|
|
"<td></td><td></td></tr>"
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
case "song":
|
|
|
|
var minutes = Math.floor(obj.data[item].duration / 60);
|
|
|
|
var seconds = obj.data[item].duration - minutes * 60;
|
|
|
|
|
|
|
|
$('#salamisandwich > tbody').append(
|
Fix browsing for non-ascii entity URI under Safari
Previously, browsing entities with non-ascii characters in their URI
under Safari wouldn't work. Directories would be empty, songs wouldn't
be added. I haven't tried it, but this behavior seems to be common to
Webkit-based browsers, so Chrome would be affected too.
This turned out to be because Safari normalizes all unicode strings to
NFC, breaking the link with MPD-spewed URIs, which are in NFD.
An obvious fix would have been to normalize all URIs to NFD, but
unfortunately, Safari doesn't have `str.normalize()`. Adding
normalization capabilities to our JS side would have involved
introductiing libraries such as `unorm`, which is rather big.
We could have done it on the C side, but it involves introducing `icu`,
which is far from trivial too.
After much fussing around, I stumbled on a simple solution: URI-encode
our URI when creating our browser table row. This magically prevents
Safari from trying to mess with our unicode form before we get the
chance to send it back to our server.
2015-06-21 02:39:42 +00:00
|
|
|
"<tr uri=\"" + encodeURI(obj.data[item].uri) + "\" class=\"song\">" +
|
|
|
|
"<td><span class=\"glyphicon glyphicon-music\"></span></td>" +
|
|
|
|
"<td>" + obj.data[item].title +"</td>" +
|
2014-02-22 00:57:26 +00:00
|
|
|
"<td>"+ minutes + ":" + (seconds < 10 ? '0' : '') + seconds +
|
|
|
|
"</td><td></td></tr>"
|
|
|
|
);
|
2014-01-16 17:32:20 +00:00
|
|
|
break;
|
2014-02-22 01:11:45 +00:00
|
|
|
case "wrap":
|
|
|
|
if(current_app == 'browse') {
|
|
|
|
$('#next').removeClass('hide');
|
|
|
|
} else {
|
|
|
|
$('#salamisandwich > tbody').append(
|
|
|
|
"<tr><td><span class=\"glyphicon glyphicon-remove\"></span></td>" +
|
|
|
|
"<td>Too many results, please refine your search!</td>" +
|
|
|
|
"<td></td><td></td></tr>"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
break;
|
2014-01-16 17:32:20 +00:00
|
|
|
}
|
2014-02-22 01:11:45 +00:00
|
|
|
|
|
|
|
if(pagination > 0)
|
|
|
|
$('#prev').removeClass('hide');
|
|
|
|
|
2014-01-16 17:32:20 +00:00
|
|
|
}
|
|
|
|
|
2014-01-17 15:26:26 +00:00
|
|
|
function appendClickableIcon(appendTo, onClickAction, glyphicon) {
|
2015-10-22 15:48:42 +00:00
|
|
|
$(appendTo).append(
|
2014-01-17 15:26:26 +00:00
|
|
|
"<a role=\"button\" class=\"pull-right btn-group-hover\">" +
|
|
|
|
"<span class=\"glyphicon glyphicon-" + glyphicon + "\"></span></a>")
|
|
|
|
.find('a').click(function(e) {
|
|
|
|
e.stopPropagation();
|
2015-07-13 18:31:56 +00:00
|
|
|
socket.send(onClickAction + "," + decodeURI($(this).parents("tr").attr("uri")));
|
2014-01-17 15:26:26 +00:00
|
|
|
$('.top-right').notify({
|
|
|
|
message:{
|
|
|
|
text: $('td:nth-child(2)', $(this).parents("tr")).text() + " added"
|
|
|
|
} }).show();
|
|
|
|
}).fadeTo('fast',1);
|
|
|
|
}
|
|
|
|
|
2015-10-22 15:48:42 +00:00
|
|
|
if ( isTouch ) {
|
|
|
|
appendClickableIcon($("#salamisandwich > tbody > tr.dir > td:last-child"), 'MPD_API_ADD_TRACK', 'plus');
|
|
|
|
appendClickableIcon($("#salamisandwich > tbody > tr.song > td:last-child"), 'MPD_API_ADD_TRACK', 'play');
|
|
|
|
} else {
|
|
|
|
$('#salamisandwich > tbody > tr').on({
|
|
|
|
mouseenter: function() {
|
|
|
|
if($(this).is(".dir"))
|
|
|
|
appendClickableIcon($(this).children().last(), 'MPD_API_ADD_TRACK', 'plus');
|
|
|
|
else if($(this).is(".song"))
|
|
|
|
appendClickableIcon($(this).children().last(), 'MPD_API_ADD_PLAY_TRACK', 'play');
|
|
|
|
},
|
|
|
|
mouseleave: function(){
|
|
|
|
$(this).children().last().find("a").stop().remove();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
2014-01-16 17:32:20 +00:00
|
|
|
$('#salamisandwich > tbody > tr').on({
|
|
|
|
click: function() {
|
2014-02-22 01:11:45 +00:00
|
|
|
switch($(this).attr('class')) {
|
|
|
|
case 'dir':
|
2015-10-22 09:44:50 +00:00
|
|
|
pagination = 0;
|
|
|
|
browsepath = $(this).attr("uri");
|
|
|
|
$("#browse > a").attr("href", '#/browse/'+pagination+'/'+browsepath);
|
|
|
|
app.setLocation('#/browse/'+pagination+'/'+browsepath);
|
2014-02-22 01:11:45 +00:00
|
|
|
break;
|
|
|
|
case 'song':
|
2015-07-13 18:31:56 +00:00
|
|
|
socket.send("MPD_API_ADD_TRACK," + decodeURI($(this).attr("uri")));
|
2014-02-22 01:11:45 +00:00
|
|
|
$('.top-right').notify({
|
|
|
|
message:{
|
|
|
|
text: $('td:nth-child(2)', this).text() + " added"
|
|
|
|
}
|
|
|
|
}).show();
|
|
|
|
break;
|
|
|
|
case 'plist':
|
2015-07-13 18:31:56 +00:00
|
|
|
socket.send("MPD_API_ADD_PLAYLIST," + decodeURI($(this).attr("uri")));
|
2014-02-22 01:11:45 +00:00
|
|
|
$('.top-right').notify({
|
|
|
|
message:{
|
|
|
|
text: "Playlist " + $('td:nth-child(2)', this).text() + " added"
|
|
|
|
}
|
|
|
|
}).show();
|
|
|
|
break;
|
2014-02-22 00:57:26 +00:00
|
|
|
}
|
2014-01-16 17:32:20 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
break;
|
|
|
|
case "state":
|
|
|
|
updatePlayIcon(obj.data.state);
|
|
|
|
updateVolumeIcon(obj.data.volume);
|
|
|
|
|
|
|
|
if(JSON.stringify(obj) === JSON.stringify(last_state))
|
|
|
|
break;
|
|
|
|
|
|
|
|
current_song.totalTime = obj.data.totalTime;
|
|
|
|
current_song.currentSongId = obj.data.currentsongid;
|
|
|
|
var total_minutes = Math.floor(obj.data.totalTime / 60);
|
|
|
|
var total_seconds = obj.data.totalTime - total_minutes * 60;
|
|
|
|
|
|
|
|
var elapsed_minutes = Math.floor(obj.data.elapsedTime / 60);
|
|
|
|
var elapsed_seconds = obj.data.elapsedTime - elapsed_minutes * 60;
|
|
|
|
|
|
|
|
$('#volumeslider').slider(obj.data.volume);
|
|
|
|
var progress = Math.floor(100*obj.data.elapsedTime/obj.data.totalTime);
|
|
|
|
$('#progressbar').slider(progress);
|
|
|
|
|
|
|
|
$('#counter')
|
|
|
|
.text(elapsed_minutes + ":" +
|
|
|
|
(elapsed_seconds < 10 ? '0' : '') + elapsed_seconds + " / " +
|
|
|
|
total_minutes + ":" + (total_seconds < 10 ? '0' : '') + total_seconds);
|
|
|
|
|
|
|
|
$('#salamisandwich > tbody > tr').removeClass('active').css("font-weight", "");
|
|
|
|
$('#salamisandwich > tbody > tr[trackid='+obj.data.currentsongid+']').addClass('active').css("font-weight", "bold");
|
|
|
|
|
|
|
|
if(obj.data.random)
|
|
|
|
$('#btnrandom').addClass("active")
|
|
|
|
else
|
|
|
|
$('#btnrandom').removeClass("active");
|
|
|
|
|
|
|
|
if(obj.data.consume)
|
|
|
|
$('#btnconsume').addClass("active")
|
|
|
|
else
|
|
|
|
$('#btnconsume').removeClass("active");
|
|
|
|
|
|
|
|
if(obj.data.single)
|
|
|
|
$('#btnsingle').addClass("active")
|
|
|
|
else
|
|
|
|
$('#btnsingle').removeClass("active");
|
|
|
|
|
2015-02-17 14:45:26 +00:00
|
|
|
if(obj.data.crossfade)
|
|
|
|
$('#btncrossfade').addClass("active")
|
|
|
|
else
|
|
|
|
$('#btncrossfade').removeClass("active");
|
|
|
|
|
2014-01-16 17:32:20 +00:00
|
|
|
if(obj.data.repeat)
|
|
|
|
$('#btnrepeat').addClass("active")
|
|
|
|
else
|
|
|
|
$('#btnrepeat').removeClass("active");
|
|
|
|
|
|
|
|
last_state = obj;
|
|
|
|
break;
|
2015-04-28 09:08:21 +00:00
|
|
|
case "outputnames":
|
|
|
|
$('#btn-outputs-block button').remove();
|
|
|
|
$.each(obj.data, function(id, name){
|
|
|
|
var btn = $('<button id="btnoutput'+id+'" class="btn btn-default" onclick="toggleoutput(this, '+id+')"><span class="glyphicon glyphicon-volume-up"></span> '+name+'</button>');
|
|
|
|
btn.appendTo($('#btn-outputs-block'));
|
|
|
|
});
|
|
|
|
/* remove cache, since the buttons have been recreated */
|
|
|
|
last_outputs = '';
|
|
|
|
break;
|
|
|
|
case "outputs":
|
|
|
|
if(JSON.stringify(obj) === JSON.stringify(last_outputs))
|
|
|
|
break;
|
|
|
|
$.each(obj.data, function(id, enabled){
|
|
|
|
if (enabled)
|
|
|
|
$('#btnoutput'+id).addClass("active");
|
|
|
|
else
|
|
|
|
$('#btnoutput'+id).removeClass("active");
|
|
|
|
});
|
|
|
|
last_outputs = obj;
|
|
|
|
break;
|
2014-01-16 17:32:20 +00:00
|
|
|
case "disconnected":
|
|
|
|
if($('.top-right').has('div').length == 0)
|
|
|
|
$('.top-right').notify({
|
|
|
|
message:{text:"ympd lost connection to MPD "},
|
|
|
|
type: "danger",
|
|
|
|
fadeOut: { enabled: true, delay: 1000 },
|
|
|
|
}).show();
|
|
|
|
break;
|
2014-02-22 00:57:26 +00:00
|
|
|
case "update_queue":
|
|
|
|
if(current_app === 'queue')
|
2014-02-22 01:11:45 +00:00
|
|
|
socket.send('MPD_API_GET_QUEUE,'+pagination);
|
2014-01-16 17:32:20 +00:00
|
|
|
break;
|
2014-01-17 15:26:26 +00:00
|
|
|
case "song_change":
|
2015-08-27 14:15:23 +00:00
|
|
|
|
|
|
|
$('#album').text("");
|
|
|
|
$('#artist').text("");
|
|
|
|
|
2017-03-18 12:32:17 +00:00
|
|
|
$('#btnlove').removeClass("active");
|
|
|
|
|
2014-01-16 17:32:20 +00:00
|
|
|
$('#currenttrack').text(" " + obj.data.title);
|
2014-01-17 15:26:26 +00:00
|
|
|
var notification = "<strong><h4>" + obj.data.title + "</h4></strong>";
|
|
|
|
|
|
|
|
if(obj.data.album) {
|
2014-01-16 17:32:20 +00:00
|
|
|
$('#album').text(obj.data.album);
|
2014-01-17 15:26:26 +00:00
|
|
|
notification += obj.data.album + "<br />";
|
|
|
|
}
|
|
|
|
if(obj.data.artist) {
|
2014-01-16 17:32:20 +00:00
|
|
|
$('#artist').text(obj.data.artist);
|
2014-01-17 15:26:26 +00:00
|
|
|
notification += obj.data.artist + "<br />";
|
|
|
|
}
|
|
|
|
|
2014-01-17 17:34:22 +00:00
|
|
|
if ($.cookie("notification") === "true")
|
2014-03-08 11:23:21 +00:00
|
|
|
songNotify(obj.data.title, obj.data.artist, obj.data.album );
|
2014-01-17 17:34:22 +00:00
|
|
|
else
|
|
|
|
$('.top-right').notify({
|
|
|
|
message:{html: notification},
|
|
|
|
type: "info",
|
|
|
|
}).show();
|
|
|
|
|
2014-02-04 16:58:10 +00:00
|
|
|
break;
|
|
|
|
case "mpdhost":
|
|
|
|
$('#mpdhost').val(obj.data.host);
|
|
|
|
$('#mpdport').val(obj.data.port);
|
2014-02-22 01:11:45 +00:00
|
|
|
if(obj.data.passwort_set)
|
|
|
|
$('#mpd_password_set').removeClass('hide');
|
2013-11-07 09:09:40 +00:00
|
|
|
break;
|
2016-09-11 15:54:25 +00:00
|
|
|
case "dirbleapitoken":
|
|
|
|
dirble_api_token = obj.data;
|
|
|
|
|
|
|
|
if(dirble_stations) {
|
|
|
|
dirble_load_stations();
|
|
|
|
} else {
|
|
|
|
dirble_load_categories();
|
|
|
|
}
|
|
|
|
break;
|
2014-01-16 17:32:20 +00:00
|
|
|
case "error":
|
|
|
|
$('.top-right').notify({
|
|
|
|
message:{text: obj.data},
|
|
|
|
type: "danger",
|
|
|
|
}).show();
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-11-07 09:09:40 +00:00
|
|
|
|
2014-01-16 17:32:20 +00:00
|
|
|
}
|
|
|
|
socket.onclose = function(){
|
2014-02-16 18:46:53 +00:00
|
|
|
console.log("disconnected");
|
2014-01-16 17:32:20 +00:00
|
|
|
$('.top-right').notify({
|
|
|
|
message:{text:"Connection to ympd lost, retrying in 3 seconds "},
|
|
|
|
type: "danger",
|
|
|
|
onClose: function () {
|
|
|
|
webSocketConnect();
|
|
|
|
}
|
|
|
|
}).show();
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch(exception) {
|
|
|
|
alert('<p>Error' + exception);
|
|
|
|
}
|
2013-11-04 17:18:38 +00:00
|
|
|
|
2013-11-05 13:59:12 +00:00
|
|
|
}
|
2013-11-04 23:17:28 +00:00
|
|
|
|
2013-11-04 17:18:38 +00:00
|
|
|
function get_appropriate_ws_url()
|
|
|
|
{
|
2014-01-16 17:32:20 +00:00
|
|
|
var pcol;
|
|
|
|
var u = document.URL;
|
2016-07-07 13:22:15 +00:00
|
|
|
var separator;
|
2014-01-16 17:32:20 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
/* We open the websocket encrypted if this page came on an
|
|
|
|
/* https:// url itself, otherwise unencrypted
|
|
|
|
/*/
|
|
|
|
|
|
|
|
if (u.substring(0, 5) == "https") {
|
|
|
|
pcol = "wss://";
|
|
|
|
u = u.substr(8);
|
|
|
|
} else {
|
|
|
|
pcol = "ws://";
|
|
|
|
if (u.substring(0, 4) == "http")
|
|
|
|
u = u.substr(7);
|
|
|
|
}
|
|
|
|
|
2014-11-02 13:29:43 +00:00
|
|
|
u = u.split('#');
|
2014-01-16 17:32:20 +00:00
|
|
|
|
2016-07-07 13:22:15 +00:00
|
|
|
if (/\/$/.test(u[0])) {
|
|
|
|
separator = "";
|
|
|
|
} else {
|
|
|
|
separator = "/";
|
|
|
|
}
|
|
|
|
|
|
|
|
return pcol + u[0] + separator + "ws";
|
2013-11-04 17:18:38 +00:00
|
|
|
}
|
|
|
|
|
2013-11-04 23:17:28 +00:00
|
|
|
var updateVolumeIcon = function(volume)
|
2013-11-04 17:18:38 +00:00
|
|
|
{
|
2014-01-16 17:32:20 +00:00
|
|
|
$("#volume-icon").removeClass("glyphicon-volume-off");
|
|
|
|
$("#volume-icon").removeClass("glyphicon-volume-up");
|
|
|
|
$("#volume-icon").removeClass("glyphicon-volume-down");
|
|
|
|
|
|
|
|
if(volume == 0) {
|
|
|
|
$("#volume-icon").addClass("glyphicon-volume-off");
|
|
|
|
} else if (volume < 50) {
|
|
|
|
$("#volume-icon").addClass("glyphicon-volume-down");
|
|
|
|
} else {
|
|
|
|
$("#volume-icon").addClass("glyphicon-volume-up");
|
|
|
|
}
|
2013-11-04 17:18:38 +00:00
|
|
|
}
|
|
|
|
|
2013-11-04 23:17:28 +00:00
|
|
|
var updatePlayIcon = function(state)
|
|
|
|
{
|
2014-01-16 17:32:20 +00:00
|
|
|
$("#play-icon").removeClass("glyphicon-play")
|
|
|
|
.removeClass("glyphicon-pause");
|
|
|
|
$('#track-icon').removeClass("glyphicon-play")
|
|
|
|
.removeClass("glyphicon-pause")
|
|
|
|
.removeClass("glyphicon-stop");
|
|
|
|
|
|
|
|
if(state == 1) { // stop
|
|
|
|
$("#play-icon").addClass("glyphicon-play");
|
|
|
|
$('#track-icon').addClass("glyphicon-stop");
|
|
|
|
} else if(state == 2) { // pause
|
|
|
|
$("#play-icon").addClass("glyphicon-pause");
|
|
|
|
$('#track-icon').addClass("glyphicon-play");
|
|
|
|
} else { // play
|
|
|
|
$("#play-icon").addClass("glyphicon-play");
|
|
|
|
$('#track-icon').addClass("glyphicon-pause");
|
|
|
|
}
|
2013-11-04 23:17:28 +00:00
|
|
|
}
|
|
|
|
|
2014-01-17 15:26:26 +00:00
|
|
|
function updateDB() {
|
2014-01-16 17:32:20 +00:00
|
|
|
socket.send('MPD_API_UPDATE_DB');
|
|
|
|
$('.top-right').notify({
|
|
|
|
message:{text:"Updating MPD Database... "}
|
|
|
|
}).show();
|
2013-11-04 17:18:38 +00:00
|
|
|
}
|
|
|
|
|
2014-01-17 15:26:26 +00:00
|
|
|
function clickPlay() {
|
|
|
|
if($('#track-icon').hasClass('glyphicon-stop'))
|
|
|
|
socket.send('MPD_API_SET_PLAY');
|
|
|
|
else
|
|
|
|
socket.send('MPD_API_SET_PAUSE');
|
|
|
|
}
|
|
|
|
|
2017-04-08 09:25:40 +00:00
|
|
|
function trash(tr) {
|
|
|
|
if ( $('#btntrashmodeup').hasClass('active') ) {
|
|
|
|
socket.send('MPD_API_RM_RANGE,0,' + (tr.index() + 1));
|
|
|
|
tr.remove();
|
|
|
|
} else if ( $('#btntrashmodesingle').hasClass('active') ) {
|
|
|
|
socket.send('MPD_API_RM_TRACK,' + tr.attr('trackid'));
|
|
|
|
tr.remove();
|
|
|
|
} else if ( $('#btntrashmodedown').hasClass('active') ) {
|
|
|
|
socket.send('MPD_API_RM_RANGE,' + tr.index() + ',-1');
|
|
|
|
tr.remove();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2015-09-04 14:43:16 +00:00
|
|
|
function renumber_table(tableID,item) {
|
|
|
|
was = item.children("td").first().text();//Check if first item exists!
|
|
|
|
is = item.index() + 1;//maybe add pagination
|
|
|
|
|
|
|
|
if (was != is) {
|
|
|
|
socket.send("MPD_API_MOVE_TRACK," + was + "," + is);
|
|
|
|
socket.send('MPD_API_GET_QUEUE,'+pagination);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-13 14:30:54 +00:00
|
|
|
function basename(path) {
|
2014-01-16 17:32:20 +00:00
|
|
|
return path.split('/').reverse()[0];
|
2013-11-13 14:30:54 +00:00
|
|
|
}
|
2013-11-07 09:09:40 +00:00
|
|
|
|
2017-03-18 12:32:17 +00:00
|
|
|
function clickLove() {
|
|
|
|
socket.send("MPD_API_SEND_MESSAGE,mpdas," + ($('#btnlove').hasClass('active') ? "unlove" : "love"));
|
|
|
|
if ( $('#btnlove').hasClass('active') )
|
|
|
|
$('#btnlove').removeClass("active");
|
|
|
|
else
|
|
|
|
$('#btnlove').addClass("active");
|
|
|
|
}
|
|
|
|
|
2013-11-07 09:09:40 +00:00
|
|
|
$('#btnrandom').on('click', function (e) {
|
2014-01-16 17:32:20 +00:00
|
|
|
socket.send("MPD_API_TOGGLE_RANDOM," + ($(this).hasClass('active') ? 0 : 1));
|
2013-11-07 09:09:40 +00:00
|
|
|
|
|
|
|
});
|
|
|
|
$('#btnconsume').on('click', function (e) {
|
2014-01-16 17:32:20 +00:00
|
|
|
socket.send("MPD_API_TOGGLE_CONSUME," + ($(this).hasClass('active') ? 0 : 1));
|
2013-11-07 09:09:40 +00:00
|
|
|
|
|
|
|
});
|
|
|
|
$('#btnsingle').on('click', function (e) {
|
2014-01-16 17:32:20 +00:00
|
|
|
socket.send("MPD_API_TOGGLE_SINGLE," + ($(this).hasClass('active') ? 0 : 1));
|
2013-11-07 09:09:40 +00:00
|
|
|
});
|
2015-02-17 14:45:26 +00:00
|
|
|
$('#btncrossfade').on('click', function(e) {
|
|
|
|
socket.send("MPD_API_TOGGLE_CROSSFADE," + ($(this).hasClass('active') ? 0 : 1));
|
|
|
|
});
|
2013-11-07 09:09:40 +00:00
|
|
|
$('#btnrepeat').on('click', function (e) {
|
2014-01-16 17:32:20 +00:00
|
|
|
socket.send("MPD_API_TOGGLE_REPEAT," + ($(this).hasClass('active') ? 0 : 1));
|
2013-11-07 09:09:40 +00:00
|
|
|
});
|
2014-01-16 17:32:20 +00:00
|
|
|
|
2015-04-28 09:08:21 +00:00
|
|
|
function toggleoutput(button, id) {
|
|
|
|
socket.send("MPD_API_TOGGLE_OUTPUT,"+id+"," + ($(button).hasClass('active') ? 0 : 1));
|
|
|
|
}
|
|
|
|
|
2017-04-08 09:25:40 +00:00
|
|
|
$('#trashmode').children("button").on('click', function(e) {
|
|
|
|
$('#trashmode').children("button").removeClass("active");
|
|
|
|
$(this).addClass("active");
|
|
|
|
});
|
|
|
|
|
2014-01-17 17:34:22 +00:00
|
|
|
$('#btnnotify').on('click', function (e) {
|
2014-05-24 00:57:30 +00:00
|
|
|
if($.cookie("notification") === "true") {
|
2014-01-17 17:34:22 +00:00
|
|
|
$.cookie("notification", false);
|
2014-05-24 00:57:30 +00:00
|
|
|
} else {
|
|
|
|
Notification.requestPermission(function (permission) {
|
|
|
|
if(!('permission' in Notification)) {
|
|
|
|
Notification.permission = permission;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (permission === "granted") {
|
2014-05-24 01:12:51 +00:00
|
|
|
$.cookie("notification", true, { expires: 424242 });
|
2014-05-24 00:57:30 +00:00
|
|
|
$('btnnotify').addClass("active");
|
|
|
|
}
|
|
|
|
});
|
2014-01-17 17:34:22 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2014-02-04 16:58:10 +00:00
|
|
|
function getHost() {
|
|
|
|
socket.send('MPD_API_GET_MPDHOST');
|
|
|
|
|
|
|
|
function onEnter(event) {
|
2014-02-04 17:58:05 +00:00
|
|
|
if ( event.which == 13 ) {
|
2014-02-16 18:46:53 +00:00
|
|
|
confirmSettings();
|
2014-02-04 17:58:05 +00:00
|
|
|
}
|
2014-02-04 16:58:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
$('#mpdhost').keypress(onEnter);
|
|
|
|
$('#mpdport').keypress(onEnter);
|
2014-02-16 18:46:53 +00:00
|
|
|
$('#mpd_pw').keypress(onEnter);
|
|
|
|
$('#mpd_pw_con').keypress(onEnter);
|
2014-02-04 16:58:10 +00:00
|
|
|
}
|
|
|
|
|
2016-09-11 15:54:25 +00:00
|
|
|
function getDirbleApiToken() {
|
|
|
|
socket.send('MPD_API_GET_DIRBLEAPITOKEN');
|
|
|
|
}
|
|
|
|
|
2014-02-22 00:57:26 +00:00
|
|
|
$('#search').submit(function () {
|
|
|
|
app.setLocation("#/search/"+$('#search > div > input').val());
|
2014-02-22 01:11:45 +00:00
|
|
|
$('#wait').modal('show');
|
|
|
|
setTimeout(function() {
|
|
|
|
$('#wait').modal('hide');
|
|
|
|
}, 10000);
|
2014-02-22 00:57:26 +00:00
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
2014-02-22 01:11:45 +00:00
|
|
|
$('.page-btn').on('click', function (e) {
|
|
|
|
|
|
|
|
switch ($(this).text()) {
|
|
|
|
case "Next":
|
2015-08-27 14:15:23 +00:00
|
|
|
if (current_app == "dirble") dirble_page++;
|
|
|
|
else pagination += MAX_ELEMENTS_PER_PAGE;
|
2014-02-22 01:11:45 +00:00
|
|
|
break;
|
|
|
|
case "Previous":
|
2015-08-27 14:15:23 +00:00
|
|
|
if (current_app == "dirble") dirble_page--
|
|
|
|
else {
|
|
|
|
pagination -= MAX_ELEMENTS_PER_PAGE;
|
|
|
|
if(pagination <= 0)
|
|
|
|
pagination = 0;
|
|
|
|
}
|
2014-02-22 01:11:45 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(current_app) {
|
|
|
|
case "queue":
|
|
|
|
app.setLocation('#/'+pagination);
|
|
|
|
break;
|
|
|
|
case "browse":
|
|
|
|
app.setLocation('#/browse/'+pagination+'/'+browsepath);
|
|
|
|
break;
|
2015-08-27 14:15:23 +00:00
|
|
|
case "dirble":
|
|
|
|
app.setLocation("#/dirble/"+dirble_catid+"/"+dirble_page);
|
|
|
|
break;
|
2014-02-22 01:11:45 +00:00
|
|
|
}
|
|
|
|
e.preventDefault();
|
|
|
|
});
|
|
|
|
|
2015-03-06 11:40:14 +00:00
|
|
|
function addStream() {
|
|
|
|
if($('#streamurl').val().length > 0) {
|
2017-04-08 09:25:40 +00:00
|
|
|
socket.send('MPD_API_ADD_TRACK,'+$('#streamurl').val());
|
2015-03-06 11:40:14 +00:00
|
|
|
}
|
2015-07-16 09:50:54 +00:00
|
|
|
$('#streamurl').val("");
|
2015-03-06 11:40:14 +00:00
|
|
|
$('#addstream').modal('hide');
|
|
|
|
}
|
|
|
|
|
2015-09-02 17:24:52 +00:00
|
|
|
function saveQueue() {
|
|
|
|
if($('#playlistname').val().length > 0) {
|
2017-04-08 09:25:40 +00:00
|
|
|
socket.send('MPD_API_SAVE_QUEUE,'+$('#playlistname').val());
|
2015-09-02 17:24:52 +00:00
|
|
|
}
|
|
|
|
$('#savequeue').modal('hide');
|
|
|
|
}
|
|
|
|
|
2014-02-16 18:46:53 +00:00
|
|
|
function confirmSettings() {
|
|
|
|
if($('#mpd_pw').val().length + $('#mpd_pw_con').val().length > 0) {
|
|
|
|
if ($('#mpd_pw').val() !== $('#mpd_pw_con').val())
|
|
|
|
{
|
|
|
|
$('#mpd_pw_con').popover('show');
|
|
|
|
setTimeout(function() {
|
|
|
|
$('#mpd_pw_con').popover('hide');
|
|
|
|
}, 2000);
|
|
|
|
return;
|
|
|
|
} else
|
|
|
|
socket.send('MPD_API_SET_MPDPASS,'+$('#mpd_pw').val());
|
|
|
|
}
|
2014-02-04 16:58:10 +00:00
|
|
|
socket.send('MPD_API_SET_MPDHOST,'+$('#mpdport').val()+','+$('#mpdhost').val());
|
2014-02-16 18:46:53 +00:00
|
|
|
$('#settings').modal('hide');
|
2014-02-04 16:58:10 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 19:33:22 +00:00
|
|
|
$('#mpd_password_set > button').on('click', function (e) {
|
|
|
|
socket.send('MPD_API_SET_MPDPASS,');
|
|
|
|
$('#mpd_pw').val("");
|
|
|
|
$('#mpd_pw_con').val("");
|
|
|
|
$('#mpd_password_set').addClass('hide');
|
|
|
|
})
|
|
|
|
|
2014-01-17 17:34:22 +00:00
|
|
|
function notificationsSupported() {
|
2014-05-24 00:57:30 +00:00
|
|
|
return "Notification" in window;
|
2014-01-17 17:34:22 +00:00
|
|
|
}
|
|
|
|
|
2014-03-08 11:23:21 +00:00
|
|
|
function songNotify(title, artist, album) {
|
|
|
|
/*var opt = {
|
|
|
|
type: "list",
|
|
|
|
title: title,
|
|
|
|
message: title,
|
|
|
|
items: []
|
|
|
|
}
|
|
|
|
if(artist.length > 0)
|
|
|
|
opt.items.push({title: "Artist", message: artist});
|
|
|
|
if(album.length > 0)
|
|
|
|
opt.items.push({title: "Album", message: album});
|
|
|
|
*/
|
|
|
|
//chrome.notifications.create(id, options, creationCallback);
|
|
|
|
|
|
|
|
var textNotification = "";
|
2014-05-24 00:57:30 +00:00
|
|
|
if(typeof artist != 'undefined' && artist.length > 0)
|
2014-03-08 11:23:21 +00:00
|
|
|
textNotification += " " + artist;
|
2014-05-24 00:57:30 +00:00
|
|
|
if(typeof album != 'undefined' && album.length > 0)
|
2014-03-08 11:23:21 +00:00
|
|
|
textNotification += "\n " + album;
|
|
|
|
|
2017-04-08 09:25:40 +00:00
|
|
|
var notification = new Notification(title, {icon: 'assets/favicon.ico', body: textNotification});
|
2014-05-24 00:57:30 +00:00
|
|
|
setTimeout(function(notification) {
|
|
|
|
notification.close();
|
|
|
|
}, 3000, notification);
|
2014-01-17 17:34:22 +00:00
|
|
|
}
|
2015-09-13 08:38:18 +00:00
|
|
|
|
|
|
|
$(document).keydown(function(e){
|
|
|
|
if (e.target.tagName == 'INPUT') {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch (e.which) {
|
|
|
|
case 37: //left
|
|
|
|
socket.send('MPD_API_SET_PREV');
|
|
|
|
break;
|
|
|
|
case 39: //right
|
|
|
|
socket.send('MPD_API_SET_NEXT');
|
|
|
|
break;
|
|
|
|
case 32: //space
|
|
|
|
clickPlay();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
e.preventDefault();
|
|
|
|
});
|
2015-09-02 17:38:42 +00:00
|
|
|
|
|
|
|
function dirble_load_categories() {
|
|
|
|
|
|
|
|
dirble_page = 1;
|
|
|
|
|
2016-09-11 15:54:25 +00:00
|
|
|
$.getJSON( "https://api.dirble.com/v2/categories?token=" + dirble_api_token, function( data ) {
|
2015-09-02 17:38:42 +00:00
|
|
|
|
|
|
|
$('#dirble_loading').addClass('hide');
|
|
|
|
|
|
|
|
data = data.sort(function(a, b) {
|
|
|
|
return (a.title > b.title) ? 1 : 0;
|
|
|
|
});
|
|
|
|
|
|
|
|
var max = data.length - data.length%2;
|
|
|
|
|
|
|
|
for(i = 0; i < max; i+=2) {
|
|
|
|
|
|
|
|
$('#dirble_left > tbody').append(
|
|
|
|
"<tr><td catid=\""+data[i].id+"\">"+data[i].title+"</td></tr>"
|
|
|
|
);
|
|
|
|
|
|
|
|
$('#dirble_right > tbody').append(
|
|
|
|
"<tr><td catid=\""+data[i+1].id+"\">"+data[i+1].title+"</td></tr>"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (max != data.length) {
|
|
|
|
$('#dirble_left > tbody').append(
|
|
|
|
"<tr><td catid=\""+data[max].id+"\">"+data[max].title+"</td></tr>"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$('#dirble_left > tbody > tr > td').on({
|
|
|
|
click: function() {
|
|
|
|
dirble_selected_cat = $(this).text();
|
|
|
|
dirble_catid = $(this).attr("catid");
|
|
|
|
app.setLocation("#/dirble/"+dirble_catid+"/"+dirble_page);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
$('#dirble_right > tbody > tr > td').on({
|
|
|
|
click: function() {
|
|
|
|
dirble_selected_cat = $(this).text();
|
|
|
|
dirble_catid = $(this).attr("catid");
|
|
|
|
app.setLocation("#/dirble/"+dirble_catid+"/"+dirble_page);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function dirble_load_stations() {
|
|
|
|
|
2016-09-11 15:54:25 +00:00
|
|
|
$.getJSON( "https://api.dirble.com/v2/category/"+dirble_catid+"/stations?page="+dirble_page+"&per_page=20&token=" + dirble_api_token, function( data ) {
|
2015-09-02 17:38:42 +00:00
|
|
|
|
|
|
|
$('#dirble_loading').addClass('hide');
|
|
|
|
if (data.length == 20) $('#next').removeClass('hide');
|
|
|
|
|
|
|
|
var max = data.length - data.length%2;
|
|
|
|
|
|
|
|
for(i = 0; i < max; i+=2) {
|
|
|
|
|
|
|
|
$('#dirble_left > tbody').append(
|
|
|
|
"<tr><td radioid=\""+data[i].id+"\">"+data[i].name+"</td></tr>"
|
|
|
|
);
|
|
|
|
$('#dirble_right > tbody').append(
|
|
|
|
"<tr><td radioid=\""+data[i+1].id+"\">"+data[i+1].name+"</td></tr>"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (max != data.length) {
|
|
|
|
$('#dirble_left > tbody').append(
|
|
|
|
"<tr><td radioid=\""+data[max].id+"\">"+data[max].name+"</td></tr>"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$('#dirble_left > tbody > tr > td').on({
|
|
|
|
click: function() {
|
|
|
|
var _this = $(this);
|
|
|
|
|
2016-09-11 15:54:25 +00:00
|
|
|
$.getJSON( "https://api.dirble.com/v2/station/"+$(this).attr("radioid")+"?token=" + dirble_api_token, function( data ) {
|
2015-09-02 17:38:42 +00:00
|
|
|
|
|
|
|
socket.send("MPD_API_ADD_TRACK," + data.streams[0].stream);
|
|
|
|
$('.top-right').notify({
|
|
|
|
message:{
|
|
|
|
text: _this.text() + " added"
|
|
|
|
}
|
|
|
|
}).show();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
mouseenter: function() {
|
|
|
|
var _this = $(this);
|
|
|
|
|
|
|
|
$(this).last().append(
|
|
|
|
"<a role=\"button\" class=\"pull-right btn-group-hover\">" +
|
|
|
|
"<span class=\"glyphicon glyphicon-play\"></span></a>").find('a').click(function(e) {
|
|
|
|
e.stopPropagation();
|
|
|
|
|
2016-09-11 15:54:25 +00:00
|
|
|
$.getJSON( "https://api.dirble.com/v2/station/"+_this.attr("radioid")+"?token=" + dirble_api_token, function( data ) {
|
2015-09-02 17:38:42 +00:00
|
|
|
|
|
|
|
socket.send("MPD_API_ADD_PLAY_TRACK," + data.streams[0].stream);
|
|
|
|
$('.top-right').notify({
|
|
|
|
message:{
|
|
|
|
text: _this.text() + " added"
|
|
|
|
}
|
|
|
|
}).show();
|
|
|
|
});
|
|
|
|
}).fadeTo('fast',1);
|
|
|
|
},
|
|
|
|
|
|
|
|
mouseleave: function(){
|
|
|
|
$(this).last().find("a").stop().remove();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
$('#dirble_right> tbody > tr > td').on({
|
|
|
|
click: function() {
|
|
|
|
var _this = $(this);
|
|
|
|
|
2016-09-11 15:54:25 +00:00
|
|
|
$.getJSON( "https://api.dirble.com/v2/station/"+$(this).attr("radioid")+"?token=" + dirble_api_token, function( data ) {
|
2015-09-02 17:38:42 +00:00
|
|
|
|
|
|
|
socket.send("MPD_API_ADD_TRACK," + data.streams[0].stream);
|
|
|
|
$('.top-right').notify({
|
|
|
|
message:{
|
|
|
|
text: _this.text() + " added"
|
|
|
|
}
|
|
|
|
}).show();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
mouseenter: function() {
|
|
|
|
var _this = $(this);
|
|
|
|
|
|
|
|
$(this).last().append(
|
|
|
|
"<a role=\"button\" class=\"pull-right btn-group-hover\">" +
|
|
|
|
"<span class=\"glyphicon glyphicon-play\"></span></a>").find('a').click(function(e) {
|
|
|
|
e.stopPropagation();
|
|
|
|
|
2016-09-11 15:54:25 +00:00
|
|
|
$.getJSON( "https://api.dirble.com/v2/station/"+_this.attr("radioid")+"?token=" + dirble_api_token, function( data ) {
|
2015-09-02 17:38:42 +00:00
|
|
|
|
|
|
|
socket.send("MPD_API_ADD_PLAY_TRACK," + data.streams[0].stream);
|
|
|
|
$('.top-right').notify({
|
|
|
|
message:{
|
|
|
|
text: _this.text() + " added"
|
|
|
|
}
|
|
|
|
}).show();
|
|
|
|
});
|
|
|
|
}).fadeTo('fast',1);
|
|
|
|
},
|
|
|
|
|
|
|
|
mouseleave: function(){
|
|
|
|
$(this).last().find("a").stop().remove();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2015-09-20 14:00:45 +00:00
|
|
|
}
|
2016-06-08 21:20:27 +00:00
|
|
|
|
|
|
|
function set_filter (c) {
|
|
|
|
filter = c;
|
|
|
|
|
|
|
|
$.each($('#salamisandwich > tbody > tr.dir'), function(i, line) {
|
|
|
|
var first = $(line).attr('uri')[0];
|
|
|
|
|
|
|
|
if (filter === undefined) {
|
|
|
|
$(line).removeClass('hide');
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (filter === "#") {
|
|
|
|
if (!isNaN(first)) {
|
|
|
|
$(line).removeClass('hide');
|
|
|
|
} else {
|
|
|
|
$(line).addClass('hide');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (filter >= "A" && filter <= "Z") {
|
|
|
|
if (first.toUpperCase() === filter) {
|
|
|
|
$(line).removeClass('hide');
|
|
|
|
} else {
|
|
|
|
$(line).addClass('hide');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (filter === "||") {
|
|
|
|
$(line).addClass('hide');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
$.each($('#salamisandwich > tbody > tr.plist'), function(i, line) {
|
|
|
|
if (filter === undefined) {
|
|
|
|
$(line).removeClass('hide');
|
|
|
|
} else if (filter === "||") {
|
|
|
|
$(line).removeClass('hide');
|
|
|
|
} else {
|
|
|
|
$(line).addClass('hide');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function add_filter () {
|
|
|
|
$('#filter').append(' <a onclick="set_filter(\'#\')" href="#/browse/0/">#</a>');
|
|
|
|
|
|
|
|
for (i = 65; i <= 90; i++) {
|
|
|
|
var c = String.fromCharCode(i);
|
|
|
|
$('#filter').append(' <a onclick="set_filter(\'' + c + '\')" href="#/browse/0/">' + c + '</a>');
|
|
|
|
}
|
|
|
|
|
|
|
|
$('#filter').append(' <a onclick="set_filter(\'||\')" href="#/browse/0/" class="glyphicon glyphicon-list"></a>');
|
|
|
|
}
|