groovebasin/src/client/app.js
Andrew Kelley 83ec17de20 fix download plugin
also use config.js for config vars instead of leveldb
2013-09-26 04:21:31 -04:00

2174 lines
62 KiB
JavaScript

var $ = window.$;
var Handlebars = window.Handlebars;
var qq = window.qq;
var io = window.io;
var shuffle = require('mess');
var querystring = require('querystring');
var zfill = require('zfill');
var PlayerClient = require('./playerclient');
var streaming = require('./streaming');
var chatState;
var selection = {
ids: {
playlist: {},
artist: {},
album: {},
track: {},
stored_playlist: {},
stored_playlist_item: {}
},
cursor: null,
type: null,
isLibrary: function(){
return this.type === 'artist' || this.type === 'album' || this.type === 'track';
},
isPlaylist: function(){
return this.type === 'playlist';
},
isStoredPlaylist: function(){
return this.type === 'stored_playlist' || this.type === 'stored_playlist_item';
},
clear: function(){
this.ids.artist = {};
this.ids.album = {};
this.ids.track = {};
this.ids.playlist = {};
this.ids.stored_playlist = {};
this.ids.stored_playlist_item = {};
},
fullClear: function(){
this.clear();
this.type = null;
this.cursor = null;
},
selectOnly: function(sel_name, key){
this.clear();
this.type = sel_name;
this.ids[sel_name][key] = true;
this.cursor = key;
},
isMulti: function(){
var result, k;
if (this.isLibrary()) {
result = 2;
for (k in this.ids.artist) {
if (!--result) return true;
}
for (k in this.ids.album) {
if (!--result) return true;
}
for (k in this.ids.track) {
if (!--result) return true;
}
return false;
} else if (this.isPlaylist()) {
result = 2;
for (k in this.ids.playlist) {
if (!--result) return true;
}
return false;
} else if (this.isStoredPlaylist()) {
result = 2;
for (k in this.ids.stored_playlist) {
if (!--result) return true;
}
for (k in this.ids.stored_playlist_item) {
if (!--result) return true;
}
return false;
} else {
return false;
}
},
getPos: function(type, key){
var val;
if (type == null) type = this.type;
if (key == null) key = this.cursor;
if (this.isLibrary()) {
val = {
type: 'library',
artist: null,
album: null,
track: null
};
if (key != null) {
switch (type) {
case 'track':
val.track = mpd.search_results.track_table[key];
val.album = val.track.album;
val.artist = val.album.artist;
break;
case 'album':
val.album = mpd.search_results.album_table[key];
val.artist = val.album.artist;
break;
case 'artist':
val.artist = mpd.search_results.artist_table[key];
break;
}
} else {
val.artist = mpd.search_results.artists[0];
}
return val;
} else if (this.isStoredPlaylist()) {
val = {
type: 'stored_playlist',
stored_playlist: null,
stored_playlist_item: null
};
if (key != null) {
switch (type) {
case 'stored_playlist_item':
val.stored_playlist_item = mpd.stored_playlist_item_table[key];
val.stored_playlist = val.stored_playlist_item.playlist;
break;
case 'stored_playlist':
val.stored_playlist = mpd.stored_playlist_table[key];
break;
}
} else {
val.stored_playlist = mpd.stored_playlists[0];
}
return val;
} else {
throw new Error("NothingSelected");
}
},
posToArr: function(pos){
var ref$;
if (pos.type === 'library') {
return [(ref$ = pos.artist) != null ? ref$.pos : void 8, (ref$ = pos.album) != null ? ref$.pos : void 8, (ref$ = pos.track) != null ? ref$.pos : void 8];
} else if (pos.type === 'stored_playlist') {
return [(ref$ = pos.stored_playlist) != null ? ref$.pos : void 8, (ref$ = pos.stored_playlist_item) != null ? ref$.pos : void 8];
} else {
throw new Error("NothingSelected");
}
},
posEqual: function(pos1, pos2){
var arr1 = this.posToArr(pos1);
var arr2 = this.posToArr(pos2);
return compareArrays(arr1, arr2) === 0;
},
posInBounds: function(pos){
if (pos.type === 'library') {
return pos.artist != null;
} else if (pos.type === 'stored_playlist') {
return pos.stored_playlist != null;
} else {
throw new Error("NothingSelected");
}
},
selectPos: function(pos){
if (pos.type === 'library') {
if (pos.track != null) {
selection.ids.track[pos.track.file] = true;
} else if (pos.album != null) {
selection.ids.album[pos.album.key] = true;
} else if (pos.artist != null) {
selection.ids.artist[pos.artist.key] = true;
}
} else if (pos.type === 'stored_playlist') {
if (pos.stored_playlist_item != null) {
selection.ids.stored_playlist_item[pos.stored_playlist_item] = true;
} else if (pos.stored_playlist != null) {
selection.ids.stored_playlist[pos.stored_playlist] = true;
}
} else {
throw new Error("NothingSelected");
}
},
incrementPos: function(pos){
if (pos.type === 'library') {
if (pos.track != null) {
pos.track = pos.track.album.tracks[pos.track.pos + 1];
if (pos.track == null) {
pos.album = pos.artist.albums[pos.album.pos + 1];
if (pos.album == null) {
pos.artist = mpd.search_results.artists[pos.artist.pos + 1];
}
}
} else if (pos.album != null) {
if (isAlbumExpanded(pos.album)) {
pos.track = pos.album.tracks[0];
} else {
pos.artist = mpd.search_results.artists[pos.artist.pos + 1];
pos.album = null;
}
} else if (pos.artist != null) {
if (isArtistExpanded(pos.artist)) {
pos.album = pos.artist.albums[0];
} else {
pos.artist = mpd.search_results.artists[pos.artist.pos + 1];
}
}
} else if (pos.type === 'stored_playlist') {
if (pos.stored_playlist_item != null) {
pos.stored_playlist_item = pos.stored_playlist_item.playlist.item_list[pos.stored_playlist_item.pos + 1];
if (pos.stored_playlist_item == null) {
pos.stored_playlist = mpd.stored_playlists[pos.stored_playlist.pos + 1];
}
} else if (pos.stored_playlist != null) {
if (isStoredPlaylistExpanded(pos.stored_playlist)) {
pos.stored_playlist_item = pos.stored_playlist.item_list[0];
if (pos.stored_playlist_item == null) {
pos.stored_playlist = mpd.stored_playlists[pos.stored_playlist.pos + 1];
}
} else {
pos.stored_playlist = mpd.stored_playlists[pos.stored_playlist.pos + 1];
}
}
} else {
throw new Error("NothingSelected");
}
},
decrementPos: function(pos){},
toFiles: function(random){
var this$ = this;
if (random == null) random = false;
if (this.isLibrary()) {
return libraryToFiles();
} else if (this.isPlaylist()) {
return playlistToFiles();
} else if (this.isStoredPlaylist()) {
return storedPlaylistToFiles();
} else {
throw new Error("NothingSelected");
}
function libraryToFiles(){
var track_set, key, file;
track_set = {};
function selRenderArtist(artist){
var i$, ref$, len$, album;
for (i$ = 0, len$ = (ref$ = artist.albums).length; i$ < len$; ++i$) {
album = ref$[i$];
selRenderAlbum(album);
}
}
function selRenderAlbum(album){
var i$, ref$, len$, track;
for (i$ = 0, len$ = (ref$ = album.tracks).length; i$ < len$; ++i$) {
track = ref$[i$];
selRenderTrack(track);
}
}
function selRenderTrack(track){
track_set[track.file] = this$.posToArr(getTrackSelPos(track));
}
function getTrackSelPos(track){
return {
type: 'library',
artist: track.album.artist,
album: track.album,
track: track
};
}
for (key in selection.ids.artist) {
selRenderArtist(mpd.search_results.artist_table[key]);
}
for (key in selection.ids.album) {
selRenderAlbum(mpd.search_results.album_table[key]);
}
for (file in selection.ids.track) {
selRenderTrack(mpd.search_results.track_table[file]);
}
return trackSetToFiles(track_set);
}
function playlistToFiles(){
var res$, key, files;
res$ = [];
for (key in selection.ids.playlist) {
res$.push(mpd.playlist.item_table[key].track.file);
}
files = res$;
if (random) shuffle(files);
return files;
}
function storedPlaylistToFiles(){
var track_set, key;
track_set = {};
function renderPlaylist(playlist){
var i$, ref$, len$, item;
for (i$ = 0, len$ = (ref$ = playlist.item_list).length; i$ < len$; ++i$) {
item = ref$[i$];
renderPlaylistItem(item);
}
}
function renderPlaylistItem(item){
track_set[item.track.file] = this$.posToArr(getItemSelPos(item));
}
function getItemSelPos(item){
return {
type: 'stored_playlist',
stored_playlist: item.playlist,
stored_playlist_item: item
};
}
for (key in selection.ids.stored_playlist) {
renderPlaylist(mpd.stored_playlist_table[key]);
}
for (key in selection.ids.stored_playlist_item) {
renderPlaylistItem(mpd.stored_playlist_item_table[key]);
}
return trackSetToFiles(track_set);
}
function trackSetToFiles(track_set){
var res$, file, files, pos, track_arr, i$, len$, track, results$ = [];
if (random) {
res$ = [];
for (file in track_set) {
res$.push(file);
}
files = res$;
shuffle(files);
return files;
} else {
res$ = [];
for (file in track_set) {
pos = track_set[file];
res$.push({
file: file,
pos: pos
});
}
track_arr = res$;
track_arr.sort(function(a, b){
return compareArrays(a.pos, b.pos);
});
for (i$ = 0, len$ = track_arr.length; i$ < len$; ++i$) {
track = track_arr[i$];
results$.push(track.file);
}
return results$;
}
}
return trackSetToFiles;
}
};
var BASE_TITLE = document.title;
var MARGIN = 10;
var AUTO_EXPAND_LIMIT = 20;
var ICON_COLLAPSED = 'ui-icon-triangle-1-e';
var ICON_EXPANDED = 'ui-icon-triangle-1-se';
var server_status = null;
var permissions = {};
var socket = null;
var mpd = null;
var user_is_seeking = false;
var user_is_volume_sliding = false;
var started_drag = false;
var abortDrag = function(){};
var clickTab = null;
var myUserId = null;
var chat_name_input_visible = false;
var LoadStatus = {
Init: 'Loading...',
NoServer: 'Server is down.',
GoodToGo: '[good to go]'
};
var repeatModeNames = ["Off", "All", "One"];
var load_status = LoadStatus.Init;
var settings_ui = {
auth: {
show_edit: false,
password: ""
}
};
var localState = {
myUserIds: {},
userName: null,
lastfm: {
username: null,
session_key: null,
scrobbling_on: false
},
authPassword: null
};
var $document = $(document);
var $window = $(window);
var $pl_window = $('#playlist-window');
var $left_window = $('#left-window');
var $playlist_items = $('#playlist-items');
var $dynamic_mode = $('#dynamic-mode');
var $pl_btn_repeat = $('#pl-btn-repeat');
var $tabs = $('#tabs');
var $upload_tab = $tabs.find('.upload-tab');
var $chat_tab = $tabs.find('.chat-tab');
var $library = $('#library');
var $lib_filter = $('#lib-filter');
var $track_slider = $('#track-slider');
var $nowplaying = $('#nowplaying');
var $nowplaying_elapsed = $nowplaying.find('.elapsed');
var $nowplaying_left = $nowplaying.find('.left');
var $vol_slider = $('#vol-slider');
var $chatUserList = $('#chat-user-list');
var $chatList = $('#chat-list');
var $chat_user_id_span = $('#user-id');
var $settings = $('#settings');
var $upload_by_url = $('#upload-by-url');
var $main_err_msg = $('#main-err-msg');
var $main_err_msg_text = $('#main-err-msg-text');
var $stored_playlists = $('#stored-playlists');
var $upload = $('#upload');
var $track_display = $('#track-display');
var $chat_input = $('#chat-input');
var $chat_name_input = $('#chat-name-input');
var $chat_input_pane = $('#chat-input-pane');
var $lib_header = $('#library-pane .window-header');
var $pl_header = $pl_window.find('#playlist .header');
function saveLocalState(){
localStorage.setItem('state', JSON.stringify(localState));
}
function loadLocalState() {
var stateString = localStorage.getItem('state');
if (!stateString) return;
var obj;
try {
obj = JSON.parse(stateString);
} catch (err) {
return;
}
// this makes sure it still works when we change the format of localState
for (var key in localState) {
if (obj[key] !== undefined) {
localState[key] = obj[key];
}
}
}
function haveUserName(){
return !!(chatState && chatState.userNames[myUserId]);
}
function getUserName(){
return userIdToUserName(myUserId);
}
function userIdToUserName(userId) {
if (!chatState) return userId;
var userName = chatState.userNames[userId];
return userName || userId;
}
function setUserName(newName) {
newName = newName.trim();
localState.userName = newName;
saveLocalState();
socket.emit('SetUserName', newName);
}
function scrollLibraryToSelection(){
var helpers;
if ((helpers = getSelHelpers()) == null) {
return;
}
delete helpers.playlist;
scrollThingToSelection($library, helpers);
}
function scrollPlaylistToSelection(){
var helpers;
if ((helpers = getSelHelpers()) == null) {
return;
}
delete helpers.track;
delete helpers.artist;
delete helpers.album;
scrollThingToSelection($playlist_items, helpers);
}
function scrollThingToSelection($scroll_area, helpers){
var top_pos, bottom_pos, sel_name, ref$, ids, table, $getDiv, id, $div, item_top, item_bottom, scroll_area_top, selection_top, selection_bottom, scroll_amt;
top_pos = null;
bottom_pos = null;
for (sel_name in helpers) {
ref$ = helpers[sel_name], ids = ref$[0], table = ref$[1], $getDiv = ref$[2];
for (id in ids) {
item_top = ($div = $getDiv(id)).offset().top;
item_bottom = item_top + $div.height();
if (top_pos == null || item_top < top_pos) {
top_pos = item_top;
}
if (bottom_pos == null || item_bottom > bottom_pos) {
bottom_pos = item_bottom;
}
}
}
if (top_pos != null) {
scroll_area_top = $scroll_area.offset().top;
selection_top = top_pos - scroll_area_top;
selection_bottom = bottom_pos - scroll_area_top - $scroll_area.height();
scroll_amt = $scroll_area.scrollTop();
if (selection_top < 0) {
return $scroll_area.scrollTop(scroll_amt + selection_top);
} else if (selection_bottom > 0) {
return $scroll_area.scrollTop(scroll_amt + selection_bottom);
}
}
}
function downloadFiles(files){
var $form = $(document.createElement('form'));
$form.attr('action', "/download/custom");
$form.attr('method', "post");
$form.attr('target', "_blank");
for (var i = 0; i < files.length; i += 1) {
var file = files[i];
var $input = $(document.createElement('input'));
$input.attr('type', 'hidden');
$input.attr('name', 'file');
$input.attr('value', file);
$form.append($input);
}
$form.submit();
}
function getDragPosition(x, y){
var result, i$, ref$, len$, item, $item, middle, track;
result = {};
for (i$ = 0, len$ = (ref$ = $playlist_items.find(".pl-item").get()).length; i$ < len$; ++i$) {
item = ref$[i$];
$item = $(item);
middle = $item.offset().top + $item.height() / 2;
track = mpd.playlist.item_table[$item.attr('data-id')];
if (middle < y) {
if (result.previous_key == null || track.sort_key > result.previous_key) {
result.$previous = $item;
result.previous_key = track.sort_key;
}
} else {
if (result.next_key == null || track.sort_key < result.next_key) {
result.$next = $item;
result.next_key = track.sort_key;
}
}
}
return result;
}
function renderSettings() {
var apiKey = ""; // TODO fix this when lastfm plugin is fixed
var context = {
lastfm: {
auth_url: "http://www.last.fm/api/auth/?api_key=" +
encodeURIComponent(apiKey) + "&cb=" +
encodeURIComponent(location.protocol + "//" + location.host + "/"),
username: localState.lastfm.username,
session_key: localState.lastfm.session_key,
scrobbling_on: localState.lastfm.scrobbling_on
},
auth: {
password: localState.authPassword,
show_edit: localState.authPassword == null || settings_ui.auth.show_edit,
permissions: permissions
},
misc: {
stream_url: streaming.getUrl()
}
};
$settings.html(Handlebars.templates.settings(context));
$settings.find('.signout').button();
$settings.find('#toggle-scrobble').button();
$settings.find('.auth-cancel').button();
$settings.find('.auth-save').button();
$settings.find('.auth-edit').button();
$settings.find('.auth-clear').button();
$settings.find('#auth-password').val(settings_ui.auth.password);
}
function scrollChatWindowToBottom(){
$chatList.scrollTop(1000000);
}
function renderChat() {
var i;
var chatStatusText = "";
var users = chatState && chatState.users;
if (users) {
var userObjects = [];
for (i = 0; i < users.length; ++i) {
var userId = users[i];
var userName = userIdToUserName(userId);
if (userName === '[server]') {
continue;
}
var class_ = userId === myUserId ? "chat-user-self" : "chat-user";
userObjects.push({
userName: userName,
"class": class_
});
}
if (userObjects.length > 1) {
chatStatusText = " (" + userObjects.length + ")";
}
$chatUserList.html(Handlebars.templates.chat_user_list({
users: userObjects
}));
for (i = 0; i < chatState.chats.length; ++i) {
var chatObject = chatState.chats[i];
chatObject["class"] = localState.myUserIds[chatObject.userId] != null ? "chat-user-self" : "chat-user";
chatObject.userName = userIdToUserName(chatObject.userId);
}
$chatList.html(Handlebars.templates.chat_list({
chats: chatState.chats
}));
scrollChatWindowToBottom();
$chat_user_id_span.text(chat_name_input_visible ? "" : getUserName() + ": ");
}
$chat_tab.find("span").text("Chat" + chatStatusText);
}
function renderPlaylistButtons(){
$dynamic_mode
.prop("checked", server_status != null && server_status.dynamic_mode ? true : false)
.button("option", "disabled", !(server_status != null && server_status.dynamic_mode_enabled))
.button("refresh");
var repeatModeName = repeatModeNames[mpd.status.repeat];
$pl_btn_repeat
.button("option", "label", "Repeat: " + repeatModeName)
.prop("checked", mpd.status.repeat !== PlayerClient.REPEAT_OFF)
.button("refresh");
$upload_tab.removeClass("ui-state-disabled");
if (!(server_status != null && server_status.upload_enabled)) {
$upload_tab.addClass("ui-state-disabled");
}
}
function renderPlaylist(){
var context = {
playlist: mpd.playlist.item_list,
};
var scroll_top = $playlist_items.scrollTop();
$playlist_items.html(Handlebars.templates.playlist(context));
refreshSelection();
labelPlaylistItems();
$playlist_items.scrollTop(scroll_top);
}
function renderStoredPlaylists(){
var context, scroll_top;
context = {
stored_playlists: mpd.stored_playlists
};
scroll_top = $stored_playlists.scrollTop();
$stored_playlists.html(Handlebars.templates.stored_playlists(context));
$stored_playlists.scrollTop(scroll_top);
refreshSelection();
}
function labelPlaylistItems(){
var cur_item, pos, to$, ref$, id, i$, len$, item;
cur_item = mpd.status.current_item;
$playlist_items.find(".pl-item").removeClass('current').removeClass('old');
if (cur_item != null && (server_status != null && server_status.dynamic_mode)) {
for (pos = 0, to$ = cur_item.pos; pos < to$; ++pos) {
if ((id = (ref$ = mpd.playlist.item_list[pos]) != null ? ref$.id : void 8) != null) {
$("#playlist-track-" + id).addClass('old');
}
}
}
for (i$ = 0, len$ = (ref$ = mpd.playlist.item_list).length; i$ < len$; ++i$) {
item = ref$[i$];
if (item.is_random) {
$("#playlist-track-" + item.id).addClass('random');
}
}
if (cur_item != null) {
$("#playlist-track-" + cur_item.id).addClass('current');
}
}
function getSelHelpers(){
var ref$;
if ((mpd != null ? (ref$ = mpd.playlist) != null ? ref$.item_table : void 8 : void 8) == null) {
return null;
}
if ((mpd != null ? (ref$ = mpd.search_results) != null ? ref$.artist_table : void 8 : void 8) == null) {
return null;
}
return {
playlist: [
selection.ids.playlist, mpd.playlist.item_table, function(id){
return $("#playlist-track-" + id);
}
],
artist: [
selection.ids.artist, mpd.search_results.artist_table, function(id){
return $("#lib-artist-" + toHtmlId(id));
}
],
album: [
selection.ids.album, mpd.search_results.album_table, function(id){
return $("#lib-album-" + toHtmlId(id));
}
],
track: [
selection.ids.track, mpd.search_results.track_table, function(id){
return $("#lib-track-" + toHtmlId(id));
}
],
stored_playlist: [
selection.ids.stored_playlist, mpd.stored_playlist_table, function(id){
return $("#stored-pl-pl-" + toHtmlId(id));
}
],
stored_playlist_item: [
selection.ids.stored_playlist_item, mpd.stored_playlist_item_table, function(id){
return $("#stored-pl-item-" + toHtmlId(id));
}
]
};
}
function refreshSelection(){
var helpers, sel_name, ref$, ids, table, $getDiv, i$, id, len$;
if ((helpers = getSelHelpers()) == null) {
return;
}
$playlist_items.find(".pl-item").removeClass('selected').removeClass('cursor');
$library.find(".clickable").removeClass('selected').removeClass('cursor');
$stored_playlists.find(".clickable").removeClass('selected').removeClass('cursor');
if (selection.type == null) {
return;
}
for (sel_name in helpers) {
ref$ = helpers[sel_name], ids = ref$[0], table = ref$[1], $getDiv = ref$[2];
for (i$ = 0, len$ = (ref$ = (fn$())).length; i$ < len$; ++i$) {
id = ref$[i$];
delete ids[id];
}
for (id in ids) {
$getDiv(id).addClass('selected');
}
if (selection.cursor != null && sel_name === selection.type) {
$getDiv(selection.cursor).addClass('cursor');
}
}
function fn$(){
var results$ = [];
for (var id in ids) {
if (table[id] == null) {
results$.push(id);
}
}
return results$;
}
}
function renderLibrary(){
var context = {
artists: mpd.search_results.artists,
empty_library_message: mpd.have_file_list_cache ? "No Results" : "loading..."
};
var scroll_top = $library.scrollTop();
$library.html(Handlebars.templates.library(context));
var $artists = $library.children("ul").children("li");
var node_count = $artists.length;
function expandStuff($li_set){
var i$, len$, li, $li, $ul, $sub_li_set, proposed_node_count;
for (i$ = 0, len$ = $li_set.length; i$ < len$; ++i$) {
li = $li_set[i$];
$li = $(li);
if (node_count >= AUTO_EXPAND_LIMIT) {
return;
}
$ul = $li.children("ul");
$sub_li_set = $ul.children("li");
proposed_node_count = node_count + $sub_li_set.length;
if (proposed_node_count <= AUTO_EXPAND_LIMIT) {
toggleLibraryExpansion($li);
$ul = $li.children("ul");
$sub_li_set = $ul.children("li");
node_count = proposed_node_count;
expandStuff($sub_li_set);
}
}
}
expandStuff($artists);
$library.scrollTop(scroll_top);
refreshSelection();
}
function getCurrentTrackPosition(){
if (mpd.status.track_start_date != null && mpd.status.state === "play") {
return (new Date() - mpd.status.track_start_date) / 1000;
} else {
return mpd.status.paused_time;
}
}
function updateSliderPos(){
var ref$, disabled, elapsed, time, slider_pos;
if (user_is_seeking) return;
if (mpd.status.current_item != null && ((ref$ = mpd.status.state) != null ? ref$ : "stop") !== "stop") {
disabled = false;
elapsed = getCurrentTrackPosition();
time = mpd.status.current_item.track.time;
slider_pos = elapsed / time;
} else {
disabled = true;
elapsed = time = slider_pos = 0;
}
$track_slider.slider("option", "disabled", disabled).slider("option", "value", slider_pos);
$nowplaying_elapsed.html(formatTime(elapsed));
$nowplaying_left.html(formatTime(time));
}
function renderNowPlaying(){
var ref$, track, track_display, state, toggle_icon, old_class, new_class, vol, enabled;
if ((track = (ref$ = mpd.status.current_item) != null ? ref$.track : void 8) != null) {
track_display = track.name + " - " + track.artist_name;
if (track.album_name.length) {
track_display += " - " + track.album_name;
}
document.title = track_display + " - " + BASE_TITLE;
if (track.name.indexOf("Groove Basin") === 0) {
$("html").addClass('groovebasin');
} else {
$("html").removeClass('groovebasin');
}
if (track.name.indexOf("Never Gonna Give You Up") === 0 && track.artist_name.indexOf("Rick Astley") === 0) {
$("html").addClass('nggyu');
} else {
$("html").removeClass('nggyu');
}
} else {
track_display = "&nbsp;";
document.title = BASE_TITLE;
}
$track_display.html(track_display);
state = (ref$ = mpd.status.state) != null ? ref$ : "stop";
toggle_icon = {
play: ['ui-icon-play', 'ui-icon-pause'],
stop: ['ui-icon-pause', 'ui-icon-play'],
pause: ['ui-icon-pause', 'ui-icon-play']
};
ref$ = toggle_icon[state], old_class = ref$[0], new_class = ref$[1];
$nowplaying.find(".toggle span").removeClass(old_class).addClass(new_class);
$track_slider.slider("option", "disabled", state === "stop");
updateSliderPos();
if (!user_is_volume_sliding) {
enabled = (vol = mpd.status.volume) != null;
if (enabled) {
$vol_slider.slider('option', 'value', vol);
}
$vol_slider.slider('option', 'disabled', !enabled);
}
}
function render(){
var hide_main_err = load_status === LoadStatus.GoodToGo;
$pl_window.toggle(hide_main_err);
$left_window.toggle(hide_main_err);
$nowplaying.toggle(hide_main_err);
$main_err_msg.toggle(!hide_main_err);
if (!hide_main_err) {
document.title = BASE_TITLE;
$main_err_msg_text.text(load_status);
return;
}
renderPlaylist();
renderPlaylistButtons();
renderLibrary();
renderNowPlaying();
renderChat();
renderSettings();
handleResize();
}
function genericToggleExpansion($li, options){
var $div = $li.find("> div");
var $ul = $li.find("> ul");
if ($div.attr('data-type') === options.top_level_type) {
if (!$li.data('cached')) {
$li.data('cached', true);
$ul.html(options.template(options.context($div.attr('data-key'))));
$ul.toggle();
refreshSelection();
}
}
$ul.toggle();
var old_class = ICON_EXPANDED;
var new_class = ICON_COLLAPSED;
if ($ul.is(":visible")) {
var tmp = old_class;
old_class = new_class;
new_class = tmp;
}
$div.find("div").removeClass(old_class).addClass(new_class);
}
function togglePlaylistExpansion($li){
genericToggleExpansion($li, {
top_level_type: 'stored_playlist',
template: Handlebars.templates.playlist_items,
context: function(key){
return {
item_list: mpd.stored_playlist_table[key].item_list
};
}
});
}
function toggleLibraryExpansion($li){
return genericToggleExpansion($li, {
top_level_type: 'artist',
template: Handlebars.templates.albums,
context: function(key){
return {
albums: mpd.search_results.artist_table[key].albums
};
}
});
}
function confirmDelete(files_list){
var list_text = files_list.slice(0, 7).join("\n ");
if (files_list.length > 7) {
list_text += "\n ...";
}
var song_text = files_list.length === 1 ? "song" : "songs";
return confirm("You are about to delete " + files_list.length + " " + song_text + " permanently:\n\n " + list_text);
}
function handleDeletePressed(shift){
var files_list;
if (selection.isLibrary()) {
files_list = selection.toFiles();
if (!confirmDelete(files_list)) {
return;
}
socket.emit('DeleteFromLibrary', JSON.stringify(files_list));
} else if (selection.isPlaylist()) {
if (shift) {
files_list = [];
for (var id in selection.ids.playlist) {
files_list.push(mpd.playlist.item_table[id].track.file);
}
if (!confirmDelete(files_list)) return;
socket.emit('DeleteFromLibrary', JSON.stringify(files_list));
}
var pos = mpd.playlist.item_table[selection.cursor].pos;
mpd.removeIds((function(){
var results$ = [];
for (var id in selection.ids.playlist) {
results$.push(id);
}
return results$;
}()));
if (pos >= mpd.playlist.item_list.length) {
pos = mpd.playlist.item_list.length - 1;
}
if (pos > -1) {
selection.selectOnly('playlist', mpd.playlist.item_list[pos].id);
}
refreshSelection();
}
}
function togglePlayback(){
if (mpd.status.state === 'play') {
mpd.pause();
} else {
mpd.play();
}
}
function setDynamicMode(value){
var args = {
dynamic_mode: value
};
socket.emit('DynamicMode', JSON.stringify(args));
}
function toggleDynamicMode(){
setDynamicMode(!server_status.dynamic_mode);
}
function nextRepeatState(){
mpd.setRepeatMode((mpd.status.repeat + 1) % repeatModeNames.length);
}
var keyboard_handlers = (function(){
var handlers;
function upDownHandler(event){
var default_index, dir, next_pos;
if (event.which === 38) {
default_index = mpd.playlist.item_list.length - 1;
dir = -1;
} else {
default_index = 0;
dir = 1;
}
if (event.ctrlKey) {
if (selection.isPlaylist()) {
mpd.shiftIds(selection.ids.playlist, dir);
}
} else {
if (selection.isPlaylist()) {
next_pos = mpd.playlist.item_table[selection.cursor].pos + dir;
if (next_pos < 0 || next_pos >= mpd.playlist.item_list.length) {
return;
}
selection.cursor = mpd.playlist.item_list[next_pos].id;
if (!event.shiftKey) {
selection.clear();
}
selection.ids.playlist[selection.cursor] = true;
} else if (selection.isLibrary()) {
next_pos = selection.getPos();
if (dir > 0) {
selection.incrementPos(next_pos);
} else {
prevLibPos(next_pos);
}
if (next_pos.artist == null) {
return;
}
if (!event.shiftKey) {
selection.clear();
}
if (next_pos.track != null) {
selection.type = 'track';
selection.cursor = next_pos.track.file;
} else if (next_pos.album != null) {
selection.type = 'album';
selection.cursor = next_pos.album.key;
} else {
selection.type = 'artist';
selection.cursor = next_pos.artist.key;
}
selection.ids[selection.type][selection.cursor] = true;
} else {
selection.selectOnly('playlist', mpd.playlist.item_list[default_index].id);
}
refreshSelection();
}
if (selection.isPlaylist()) {
scrollPlaylistToSelection();
}
if (selection.isLibrary()) {
scrollLibraryToSelection();
}
}
function leftRightHandler(event){
var dir, helpers, ref$, ids, table, $getDiv, selected_item, is_expanded_funcs, is_expanded, $li, cursor_pos;
dir = event.which === 37 ? -1 : 1;
if (selection.isLibrary()) {
if (!(helpers = getSelHelpers())) {
return;
}
ref$ = helpers[selection.type], ids = ref$[0], table = ref$[1], $getDiv = ref$[2];
selected_item = table[selection.cursor];
is_expanded_funcs = {
artist: isArtistExpanded,
album: isAlbumExpanded,
track: function(){
return true;
}
};
is_expanded = is_expanded_funcs[selection.type](selected_item);
$li = $getDiv(selection.cursor).closest("li");
cursor_pos = selection.getPos();
if (dir > 0) {
if (!is_expanded) {
toggleLibraryExpansion($li);
}
} else {
if (is_expanded) {
toggleLibraryExpansion($li);
}
}
} else {
if (event.ctrlKey) {
if (dir > 0) {
mpd.next();
} else {
mpd.prev();
}
} else if (event.shiftKey) {
mpd.seek(getCurrentTrackPosition() + dir * mpd.status.time * 0.10);
} else {
mpd.seek(getCurrentTrackPosition() + dir * 10);
}
}
}
return handlers = {
13: {
ctrl: false,
alt: null,
shift: null,
handler: function(event){
if (selection.isPlaylist()) {
mpd.playId(selection.cursor);
} else if (selection.isLibrary()) {
queueSelection(event);
}
return false;
}
},
27: {
ctrl: false,
alt: false,
shift: false,
handler: function(){
if (started_drag) {
abortDrag();
return;
}
if ($('#menu').get().length > 0) {
removeContextMenu();
return;
}
selection.fullClear();
refreshSelection();
}
},
32: {
ctrl: false,
alt: false,
shift: false,
handler: togglePlayback
},
37: {
ctrl: null,
alt: false,
shift: null,
handler: leftRightHandler
},
38: {
ctrl: null,
alt: false,
shift: null,
handler: upDownHandler
},
39: {
ctrl: null,
alt: false,
shift: null,
handler: leftRightHandler
},
40: {
ctrl: null,
alt: false,
shift: null,
handler: upDownHandler
},
46: {
ctrl: false,
alt: false,
shift: null,
handler: function(event){
handleDeletePressed(event.shiftKey);
}
},
67: {
ctrl: false,
alt: false,
shift: true,
handler: function(){
mpd.clear();
}
},
68: {
ctrl: false,
alt: false,
shift: false,
handler: toggleDynamicMode
},
72: {
ctrl: false,
alt: false,
shift: true,
handler: function(){
mpd.shuffle();
}
},
76: {
ctrl: false,
alt: false,
shift: false,
handler: function(){
clickTab('library');
}
},
82: {
ctrl: false,
alt: false,
shift: false,
handler: nextRepeatState
},
83: {
ctrl: false,
alt: false,
shift: false,
handler: streaming.toggleStatus
},
84: {
ctrl: false,
alt: false,
shift: false,
handler: function(){
clickTab('chat');
$chat_input.focus().select();
}
},
85: {
ctrl: false,
alt: false,
shift: false,
handler: function(){
clickTab('upload');
$upload_by_url.focus().select();
}
},
187: {
ctrl: false,
alt: false,
shift: null,
handler: function(){
mpd.setVolume(mpd.status.volume + 0.10);
}
},
188: {
ctrl: false,
alt: false,
shift: null,
handler: function(){
mpd.prev();
}
},
189: {
ctrl: false,
alt: false,
shift: null,
handler: function(){
mpd.setVolume(mpd.status.volume - 0.10);
}
},
190: {
ctrl: false,
alt: false,
shift: null,
handler: function(){
mpd.next();
}
},
191: {
ctrl: false,
alt: false,
shift: null,
handler: function(event){
if (event.shiftKey) {
$(Handlebars.templates.shortcuts()).appendTo(document.body);
$('#shortcuts').dialog({
modal: true,
title: "Keyboard Shortcuts",
minWidth: 600,
height: $document.height() - 40,
close: function(){
$('#shortcuts').remove();
}
});
} else {
clickTab('library');
$lib_filter.focus().select();
}
}
}
};
})();
function removeContextMenu(){
$('#menu').remove();
}
function isArtistExpanded(artist){
var $li;
$li = $("#lib-artist-" + toHtmlId(artist.key)).closest("li");
if (!$li.data('cached')) {
return false;
}
return $li.find("> ul").is(":visible");
}
function isAlbumExpanded(album){
var $li;
$li = $("#lib-album-" + toHtmlId(album.key)).closest("li");
return $li.find("> ul").is(":visible");
}
function isStoredPlaylistExpanded(stored_playlist){
var $li;
$li = $("#stored-pl-pl-" + toHtmlId(stored_playlist.name)).closest("li");
return $li.find("> ul").is(":visible");
}
function prevLibPos(lib_pos){
if (lib_pos.track != null) {
lib_pos.track = lib_pos.track.album.tracks[lib_pos.track.pos - 1];
} else if (lib_pos.album != null) {
lib_pos.album = lib_pos.artist.albums[lib_pos.album.pos - 1];
if (lib_pos.album != null && isAlbumExpanded(lib_pos.album)) {
lib_pos.track = lib_pos.album.tracks[lib_pos.album.tracks.length - 1];
}
} else if (lib_pos.artist != null) {
lib_pos.artist = mpd.search_results.artists[lib_pos.artist.pos - 1];
if (lib_pos.artist != null && isArtistExpanded(lib_pos.artist)) {
lib_pos.album = lib_pos.artist.albums[lib_pos.artist.albums.length - 1];
if (lib_pos.album != null && isAlbumExpanded(lib_pos.album)) {
lib_pos.track = lib_pos.album.tracks[lib_pos.album.tracks.length - 1];
}
}
}
}
function queueSelection(event){
var files;
files = selection.toFiles(event.altKey);
if (event.shiftKey) {
mpd.queueFilesNext(files);
} else {
mpd.queueFiles(files);
}
return false;
}
function sendAuth() {
var pass = localState.authPassword;
if (!pass) return;
mpd.authenticate(pass, function(err){
if (err) {
localState.authPassword = null;
saveLocalState();
}
renderSettings();
});
}
function settingsAuthSave(){
settings_ui.auth.show_edit = false;
var $text_box = $('#auth-password');
localState.authPassword = $text_box.val();
saveLocalState();
renderSettings();
sendAuth();
}
function settingsAuthCancel(){
settings_ui.auth.show_edit = false;
renderSettings();
}
function performDrag(event, callbacks){
abortDrag();
var start_drag_x = event.pageX;
var start_drag_y = event.pageY;
abortDrag = function(){
$document.off('mousemove', onDragMove).off('mouseup', onDragEnd);
if (started_drag) {
$playlist_items.find(".pl-item").removeClass('border-top').removeClass('border-bottom');
started_drag = false;
}
abortDrag = function(){};
};
function onDragMove(event){
var dist, result;
if (!started_drag) {
dist = Math.pow(event.pageX - start_drag_x, 2) + Math.pow(event.pageY - start_drag_y, 2);
if (dist > 64) {
started_drag = true;
}
if (!started_drag) {
return;
}
}
result = getDragPosition(event.pageX, event.pageY);
$playlist_items.find(".pl-item").removeClass('border-top').removeClass('border-bottom');
if (result.$next != null) {
result.$next.addClass("border-top");
} else if (result.$previous != null) {
result.$previous.addClass("border-bottom");
}
}
function onDragEnd(event){
if (event.which !== 1) {
return false;
}
if (started_drag) {
callbacks.complete(getDragPosition(event.pageX, event.pageY), event);
} else {
callbacks.cancel();
}
abortDrag();
}
$document.on('mousemove', onDragMove).on('mouseup', onDragEnd);
onDragMove(event);
}
function setUpGenericUi(){
$document.on('mouseover', '.hoverable', function(event){
$(this).addClass("ui-state-hover");
});
$document.on('mouseout', '.hoverable', function(event){
$(this).removeClass("ui-state-hover");
});
$(".jquery-button").button();
$document.on('mousedown', function(){
removeContextMenu();
selection.type = null;
refreshSelection();
});
$document.on('keydown', function(event){
var handler;
if ((handler = keyboard_handlers[event.which]) != null && (handler.ctrl == null || handler.ctrl === event.ctrlKey) && (handler.alt == null || handler.alt === event.altKey) && (handler.shift == null || handler.shift === event.shiftKey)) {
handler.handler(event);
return false;
}
return true;
});
}
function setUpPlaylistUi(){
$pl_window.on('click', 'button.clear', function(){
mpd.clear();
});
$pl_window.on('click', 'button.shuffle', function(){
mpd.shuffle();
});
$pl_btn_repeat.on('click', function(){
nextRepeatState();
});
$dynamic_mode.on('click', function(){
var value;
value = $(this).prop("checked");
setDynamicMode(value);
return false;
});
$playlist_items.on('dblclick', '.pl-item', function(event){
var track_id;
track_id = $(this).attr('data-id');
mpd.playId(track_id);
});
$playlist_items.on('contextmenu', function(event){
return event.altKey;
});
$playlist_items.on('mousedown', '.pl-item', function(event){
var track_id, skip_drag, old_pos, new_pos, i, context, $menu;
if (started_drag) {
return true;
}
$(document.activeElement).blur();
if (event.which === 1) {
event.preventDefault();
removeContextMenu();
track_id = $(this).attr('data-id');
skip_drag = false;
if (!selection.isPlaylist()) {
selection.selectOnly('playlist', track_id);
} else if (event.ctrlKey || event.shiftKey) {
skip_drag = true;
if (event.shiftKey && !event.ctrlKey) {
selection.clear();
}
if (event.shiftKey) {
old_pos = selection.cursor != null ? mpd.playlist.item_table[selection.cursor].pos : 0;
new_pos = mpd.playlist.item_table[track_id].pos;
for (i = old_pos; i <= new_pos; ++i) {
selection.ids.playlist[mpd.playlist.item_list[i].id] = true;
}
} else if (event.ctrlKey) {
if (selection.ids.playlist[track_id] != null) {
delete selection.ids.playlist[track_id];
} else {
selection.ids.playlist[track_id] = true;
}
selection.cursor = track_id;
}
} else if (selection.ids.playlist[track_id] == null) {
selection.selectOnly('playlist', track_id);
}
refreshSelection();
if (!skip_drag) {
return performDrag(event, {
complete: function(result, event){
var delta, id;
delta = {
top: 0,
bottom: 1
};
mpd.moveIds((function(){
var results$ = [];
for (var id in selection.ids.playlist) {
results$.push(id);
}
return results$;
}()), result.previous_key, result.next_key);
},
cancel: function(){
selection.selectOnly('playlist', track_id);
refreshSelection();
}
});
}
} else if (event.which === 3) {
if (event.altKey) {
return;
}
event.preventDefault();
removeContextMenu();
track_id = $(this).attr('data-id');
if (!selection.isPlaylist() || selection.ids.playlist[track_id] == null) {
selection.selectOnly('playlist', track_id);
refreshSelection();
}
context = {
downloadEnabled: false, // TODO this will change when download plugin is fixed
permissions: permissions
};
if (selection.isMulti()) {
context.download_multi = true;
} else {
context.item = mpd.playlist.item_table[track_id];
}
$(Handlebars.templates.playlist_menu(context)).appendTo(document.body);
$menu = $('#menu');
$menu.offset({
left: event.pageX + 1,
top: event.pageY + 1
});
$menu.on('mousedown', function(){
return false;
});
$menu.on('click', '.remove', function(){
handleDeletePressed(false);
removeContextMenu();
return false;
});
$menu.on('click', '.download', function(){
removeContextMenu();
return true;
});
$menu.on('click', '.download-multi', function(){
removeContextMenu();
downloadFiles(selection.toFiles());
return false;
});
return $menu.on('click', '.delete', function(){
handleDeletePressed(true);
removeContextMenu();
return false;
});
}
});
$playlist_items.on('mousedown', function(){
return false;
});
}
function setUpChatUi(){
$chat_user_id_span.on('click', function(event){
$chat_input.attr("disabled", "disabled");
chat_name_input_visible = true;
$chat_name_input.show().val("").focus().select();
renderChat();
});
$chat_name_input.on('keydown', function(event){
var done;
event.stopPropagation();
if (event.which === 27) {
done = true;
} else if (event.which === 13) {
done = true;
setUserName($(event.target).val());
}
if (done) {
chat_name_input_visible = false;
$chat_name_input.hide();
$chat_input.removeAttr("disabled").focus().select();
renderChat();
return false;
}
});
$chat_input.on('keydown', function(event){
var message, newUserName, NICK;
event.stopPropagation();
if (event.which === 27) {
$(event.target).blur();
return false;
} else if (event.which === 13) {
message = $(event.target).val().trim();
setTimeout(function(){
$(event.target).val("");
}, 0);
if (message === "") {
return false;
}
if (!haveUserName()) {
newUserName = message;
}
NICK = "/nick ";
if (message.substr(0, NICK.length) === NICK) {
newUserName = message.substring(0, NICK.length);
}
if (newUserName != null) {
setUserName(newUserName);
return false;
}
socket.emit('Chat', message);
return false;
}
});
}
function updateSliderUi(value){
var percent;
percent = value * 100;
$track_slider.css('background-size', percent + "% 100%");
}
function setUpNowPlayingUi(){
var actions, cls, action;
actions = {
toggle: togglePlayback,
prev: function(){
mpd.prev();
},
next: function(){
mpd.next();
},
stop: function(){
mpd.stop();
}
};
for (cls in actions) {
action = actions[cls];
(fn$.call(this, cls, action));
}
$track_slider.slider({
step: 0.0001,
min: 0,
max: 1,
change: function(event, ui){
updateSliderUi(ui.value);
if (event.originalEvent == null) {
return;
}
mpd.seek(ui.value * mpd.status.time);
},
slide: function(event, ui){
updateSliderUi(ui.value);
$nowplaying_elapsed.html(formatTime(ui.value * mpd.status.time));
},
start: function(event, ui){
user_is_seeking = true;
},
stop: function(event, ui){
user_is_seeking = false;
}
});
function setVol(event, ui){
if (event.originalEvent == null) {
return;
}
mpd.setVolume(ui.value);
}
$vol_slider.slider({
step: 0.01,
min: 0,
max: 1,
change: setVol,
start: function(event, ui){
user_is_volume_sliding = true;
},
stop: function(event, ui){
user_is_volume_sliding = false;
}
});
setInterval(updateSliderPos, 100);
function fn$(cls, action){
$nowplaying.on('mousedown', "li." + cls, function(event){
action();
return false;
});
}
}
function setUpTabsUi(){
var tabs, i$, len$, tab;
$tabs.on('mouseover', 'li', function(event){
$(this).addClass('ui-state-hover');
});
$tabs.on('mouseout', 'li', function(event){
$(this).removeClass('ui-state-hover');
});
tabs = ['library', 'stored-playlists', 'upload', 'chat', 'settings'];
function tabSelector(tab_name){
return "li." + tab_name + "-tab";
}
function $pane(tab_name){
return $("#" + tab_name + "-pane");
}
function $tab(tab_name){
return $tabs.find(tabSelector(tab_name));
}
function unselectTabs(){
var i$, ref$, len$, tab;
$tabs.find('li').removeClass('ui-state-active');
for (i$ = 0, len$ = (ref$ = tabs).length; i$ < len$; ++i$) {
tab = ref$[i$];
$pane(tab).hide();
}
}
clickTab = function(name){
if (name === 'upload' && !(server_status != null && server_status.upload_enabled)) {
return;
}
unselectTabs();
$tab(name).addClass('ui-state-active');
$pane(name).show();
handleResize();
};
for (i$ = 0, len$ = tabs.length; i$ < len$; ++i$) {
tab = tabs[i$];
(fn$.call(this, tab));
}
function fn$(tab){
$tabs.on('click', tabSelector(tab), function(event){
clickTab(tab);
});
}
}
function setUpUploadUi(){
var uploader;
uploader = new qq.FileUploader({
element: document.getElementById("upload-widget"),
action: '/upload',
encoding: 'multipart'
});
$upload_by_url.on('keydown', function(event){
var url;
event.stopPropagation();
if (event.which === 27) {
$upload_by_url.val("").blur();
} else if (event.which === 13) {
url = $upload_by_url.val();
$upload_by_url.val("").blur();
socket.emit('ImportTrackUrl', url);
}
});
}
function setUpSettingsUi(){
$settings.on('click', '.signout', function(event){
localState.lastfm.username = null;
localState.lastfm.session_key = null;
localState.lastfm.scrobbling_on = false;
saveLocalState();
renderSettings();
return false;
});
$settings.on('click', '#toggle-scrobble', function(event){
var value, msg, params;
value = $(this).prop("checked");
if (value) {
msg = 'LastfmScrobblersAdd';
localState.lastfm.scrobbling_on = true;
} else {
msg = 'LastfmScrobblersRemove';
localState.lastfm.scrobbling_on = false;
}
saveLocalState();
params = {
username: localState.lastfm.username,
session_key: localState.lastfm.session_key
};
socket.emit(msg, JSON.stringify(params));
renderSettings();
return false;
});
$settings.on('click', '.auth-edit', function(event){
var $text_box, ref$;
settings_ui.auth.show_edit = true;
renderSettings();
$text_box = $('#auth-password');
$text_box.focus().val((ref$ = localState.authPassword) != null ? ref$ : "").select();
});
$settings.on('click', '.auth-clear', function(event){
localState.authPassword = null;
saveLocalState();
settings_ui.auth.password = "";
renderSettings();
});
$settings.on('click', '.auth-save', function(event){
settingsAuthSave();
});
$settings.on('click', '.auth-cancel', function(event){
settingsAuthCancel();
});
$settings.on('keydown', '#auth-password', function(event){
var $text_box;
$text_box = $(this);
event.stopPropagation();
settings_ui.auth.password = $text_box.val();
if (event.which === 27) {
settingsAuthCancel();
} else if (event.which === 13) {
settingsAuthSave();
}
});
$settings.on('keyup', '#auth-password', function(event){
settings_ui.auth.password = $(this).val();
});
}
function setUpLibraryUi(){
$lib_filter.on('keydown', function(event){
var files, i$, ref$, len$, artist, j$, ref1$, len1$, album, k$, ref2$, len2$, track;
event.stopPropagation();
switch (event.which) {
case 27:
if ($(event.target).val().length === 0) {
$(event.target).blur();
} else {
setTimeout(function(){
$(event.target).val("");
mpd.search("");
}, 0);
}
return false;
case 13:
files = [];
for (i$ = 0, len$ = (ref$ = mpd.search_results.artists).length; i$ < len$; ++i$) {
artist = ref$[i$];
for (j$ = 0, len1$ = (ref1$ = artist.albums).length; j$ < len1$; ++j$) {
album = ref1$[j$];
for (k$ = 0, len2$ = (ref2$ = album.tracks).length; k$ < len2$; ++k$) {
track = ref2$[k$];
files.push(track.file);
}
}
}
if (event.altKey) shuffle(files);
if (files.length > 2000) {
if (!confirm("You are about to queue " + files.length + " songs.")) {
return false;
}
}
if (event.shiftKey) {
mpd.queueFilesNext(files);
} else {
mpd.queueFiles(files);
}
return false;
case 40:
selection.selectOnly('artist', mpd.search_results.artists[0].key);
refreshSelection();
$lib_filter.blur();
return false;
case 38:
selection.selectOnly('artist', mpd.search_results.artists[mpd.search_results.artists.length - 1].key);
refreshSelection();
$lib_filter.blur();
return false;
}
});
$lib_filter.on('keyup', function(event){
mpd.search($(event.target).val());
});
genericTreeUi($library, {
toggleExpansion: toggleLibraryExpansion,
isSelectionOwner: function(){
return selection.isLibrary();
}
});
}
function setUpStoredPlaylistsUi(){
genericTreeUi($stored_playlists, {
toggleExpansion: togglePlaylistExpansion,
isSelectionOwner: function(){
return selection.isStoredPlaylist();
}
});
}
function genericTreeUi($elem, options){
$elem.on('mousedown', 'div.expandable > div.ui-icon', function(event){
options.toggleExpansion($(this).closest('li'));
return false;
});
$elem.on('dblclick', 'div.expandable > div.ui-icon', function(){
return false;
});
$elem.on('dblclick', 'div.clickable', queueSelection);
$elem.on('contextmenu', function(event){
return event.altKey;
});
$elem.on('mousedown', '.clickable', function(event){
var $this, type, key;
$(document.activeElement).blur();
$this = $(this);
type = $this.attr('data-type');
key = $this.attr('data-key');
if (event.which === 1) {
leftMouseDown(event);
} else if (event.which === 3) {
if (event.altKey) {
return;
}
rightMouseDown(event);
}
function leftMouseDown(event){
var skip_drag, old_pos, new_pos, new_arr, old_arr, ref$;
event.preventDefault();
removeContextMenu();
skip_drag = false;
if (!options.isSelectionOwner()) {
selection.selectOnly(type, key);
} else if (event.ctrlKey || event.shiftKey) {
skip_drag = true;
if (event.shiftKey && !event.ctrlKey) {
selection.clear();
}
if (event.shiftKey) {
old_pos = selection.getPos(selection.type, selection.cursor);
new_pos = selection.getPos(type, key);
new_arr = selection.posToArr(new_pos);
old_arr = selection.posToArr(old_pos);
if (compareArrays(old_arr, new_arr) > 0) {
ref$ = [new_pos, old_pos], old_pos = ref$[0], new_pos = ref$[1];
}
while (selection.posInBounds(old_pos)) {
selection.selectPos(old_pos);
if (selection.posEqual(old_pos, new_pos)) {
break;
}
selection.incrementPos(old_pos);
}
} else if (event.ctrlKey) {
if (selection.ids[type][key] != null) {
delete selection.ids[type][key];
} else {
selection.ids[type][key] = true;
}
selection.cursor = key;
selection.type = type;
}
} else if (selection.ids[type][key] == null) {
selection.selectOnly(type, key);
}
refreshSelection();
if (!skip_drag) {
performDrag(event, {
complete: function(result, event){
var delta, files;
delta = {
top: 0,
bottom: 1
};
files = selection.toFiles(event.altKey);
mpd.queueFiles(files, result.previous_key, result.next_key);
},
cancel: function(){
selection.selectOnly(type, key);
refreshSelection();
}
});
}
}
function rightMouseDown(event){
var context, $menu;
event.preventDefault();
removeContextMenu();
if (!options.isSelectionOwner() || selection.ids[type][key] == null) {
selection.selectOnly(type, key);
refreshSelection();
}
context = {
downloadEnabled: false, // TODO change this when download plugin is fixed
permissions: permissions
};
if (selection.isMulti()) {
context.download_multi = true;
} else {
if (type === 'track') {
context.track = mpd.search_results.track_table[key];
} else if (type === 'stored_playlist_item') {
context.track = mpd.stored_playlist_item_table[key].track;
} else {
context.download_type = type;
context.escaped_key = encodeURIComponent(key);
}
}
$(Handlebars.templates.library_menu(context)).appendTo(document.body);
$menu = $('#menu');
$menu.offset({
left: event.pageX + 1,
top: event.pageY + 1
});
$menu.on('mousedown', function(){
return false;
});
$menu.on('click', '.queue', function(){
mpd.queueFiles(selection.toFiles());
removeContextMenu();
return false;
});
$menu.on('click', '.queue-next', function(){
mpd.queueFilesNext(selection.toFiles());
removeContextMenu();
return false;
});
$menu.on('click', '.queue-random', function(){
mpd.queueFiles(selection.toFiles(true));
removeContextMenu();
return false;
});
$menu.on('click', '.queue-next-random', function(){
mpd.queueFilesNext(selection.toFiles(true));
removeContextMenu();
return false;
});
$menu.on('click', '.download', function(){
removeContextMenu();
return true;
});
$menu.on('click', '.download-multi', function(){
removeContextMenu();
downloadFiles(selection.toFiles());
return false;
});
$menu.on('click', '.delete', function(){
handleDeletePressed(true);
removeContextMenu();
return false;
});
}
});
$elem.on('mousedown', function(){
return false;
});
}
function setUpUi(){
setUpGenericUi();
setUpPlaylistUi();
setUpLibraryUi();
setUpStoredPlaylistsUi();
setUpChatUi();
setUpNowPlayingUi();
setUpTabsUi();
setUpUploadUi();
setUpSettingsUi();
}
function initHandlebars(){
Handlebars.registerHelper('time', formatTime);
Handlebars.registerHelper('artistid', function(s){
return "lib-artist-" + toHtmlId(s);
});
Handlebars.registerHelper('albumid', function(s){
return "lib-album-" + toHtmlId(s);
});
Handlebars.registerHelper('trackid', function(s){
return "lib-track-" + toHtmlId(s);
});
Handlebars.registerHelper('storedplaylistid', function(s){
return "stored-pl-pl-" + toHtmlId(s);
});
Handlebars.registerHelper('storedplaylistitemid', function(s){
return "stored-pl-item-" + toHtmlId(s);
});
}
function handleResize(){
var second_layer_top, tab_contents_height;
$nowplaying.width(MARGIN);
$pl_window.height(MARGIN);
$left_window.height(MARGIN);
$library.height(MARGIN);
$upload.height(MARGIN);
$stored_playlists.height(MARGIN);
$chatList.height(MARGIN);
$playlist_items.height(MARGIN);
$nowplaying.width($document.width() - MARGIN * 2);
second_layer_top = $nowplaying.offset().top + $nowplaying.height() + MARGIN;
$left_window.offset({
left: MARGIN,
top: second_layer_top
});
$pl_window.offset({
left: $left_window.offset().left + $left_window.width() + MARGIN,
top: second_layer_top
});
$pl_window.width($window.width() - $pl_window.offset().left - MARGIN);
$left_window.height($window.height() - $left_window.offset().top);
$pl_window.height($left_window.height() - MARGIN);
tab_contents_height = $left_window.height() - $tabs.height() - MARGIN;
$library.height(tab_contents_height - $lib_header.height());
$upload.height(tab_contents_height);
$stored_playlists.height(tab_contents_height);
$chatList.height(tab_contents_height - $chatUserList.height() - $chat_input_pane.height());
$playlist_items.height($pl_window.height() - $pl_header.position().top - $pl_header.height());
}
function refreshPage(){
location.href = location.protocol + "//" + location.host + "/";
}
window.WEB_SOCKET_SWF_LOCATION = "/vendor/socket.io/WebSocketMain.swf";
$document.ready(function(){
var ref$, token;
loadLocalState();
socket = io.connect();
var queryObj = querystring.parse(location.search.substring(1));
if (queryObj.token) {
socket.emit('LastfmGetSession', queryObj.token);
socket.on('LastfmGetSessionSuccess', function(data){
var params;
params = JSON.parse(data);
localState.lastfm.username = params.session.name;
localState.lastfm.session_key = params.session.key;
localState.lastfm.scrobbling_on = false;
saveLocalState();
refreshPage();
});
socket.on('LastfmGetSessionError', function(data){
var params;
params = JSON.parse(data);
alert("Error authenticating: " + params.message);
refreshPage();
});
return;
}
socket.on('Identify', function(data){
myUserId = data.toString();
localState.myUserIds[myUserId] = 1;
saveLocalState();
var userName = localState.userName;
if (userName) setUserName(userName);
});
socket.on('Permissions', function(data){
permissions = JSON.parse(data.toString());
renderSettings();
});
socket.on('Chat', function(data) {
chatState = data;
renderChat();
});
mpd = new PlayerClient(socket);
mpd.on('libraryupdate', renderLibrary);
mpd.on('playlistupdate', renderPlaylist);
mpd.on('storedplaylistupdate', renderStoredPlaylists);
mpd.on('statusupdate', function(){
renderNowPlaying();
renderPlaylistButtons();
labelPlaylistItems();
});
socket.on('connect', function(){
sendAuth();
load_status = LoadStatus.GoodToGo;
render();
});
socket.on('disconnect', function(){
load_status = LoadStatus.NoServer;
render();
});
setUpUi();
initHandlebars();
streaming.init(mpd, socket);
render();
$window.resize(handleResize);
window._debug_mpd = mpd;
});
function compareArrays(arr1, arr2) {
for (var i1 = 0; i1 < arr1.length; i1 += 1) {
var val1 = arr1[i1];
var val2 = arr2[i1];
var diff = (val1 != null ? val1 : -1) - (val2 != null ? val2 : -1);
if (diff !== 0) return diff;
}
return 0;
}
function formatTime(seconds) {
seconds = Math.floor(seconds);
var minutes = Math.floor(seconds / 60);
seconds -= minutes * 60;
var hours = Math.floor(minutes / 60);
minutes -= hours * 60;
if (hours !== 0) {
return hours + ":" + zfill(minutes, 2) + ":" + zfill(seconds, 2);
} else {
return minutes + ":" + zfill(seconds, 2);
}
}
var badCharRe = new RegExp('[^a-zA-Z0-9-]', 'gm');
function toHtmlId(string) {
return string.replace(badCharRe, function(c) {
return "_" + c.charCodeAt(0) + "_";
});
}