fix download plugin
also use config.js for config vars instead of leveldb
This commit is contained in:
parent
d6a685507a
commit
83ec17de20
12 changed files with 136 additions and 227 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,5 +1,6 @@
|
||||||
/node_modules
|
/node_modules
|
||||||
/groovebasin.db
|
/groovebasin.db
|
||||||
|
/config.js
|
||||||
|
|
||||||
# not shared with .npmignore
|
# not shared with .npmignore
|
||||||
/public/app.js
|
/public/app.js
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
/node_modules
|
/node_modules
|
||||||
/groovebasin.db
|
/groovebasin.db
|
||||||
|
/config.js
|
||||||
|
|
||||||
# not shared with .gitignore
|
# not shared with .gitignore
|
||||||
|
|
|
||||||
5
TODO
5
TODO
|
|
@ -1,10 +1,9 @@
|
||||||
High priority:
|
High priority:
|
||||||
* (andy) fix broken plugin - delete
|
* (andy) fix broken plugin - download
|
||||||
|
|
||||||
Before merging into master:
|
Before merging into master:
|
||||||
* fix broken plugin - upload
|
* fix broken plugin - upload
|
||||||
- while you're at it consider ditching qq fileuploader
|
- while you're at it consider ditching qq fileuploader
|
||||||
* fix broken plugin - download
|
|
||||||
* fix broken plugin - lastfm
|
* fix broken plugin - lastfm
|
||||||
* fix broken plugin - dynamicmode
|
* fix broken plugin - dynamicmode
|
||||||
* persist current playlist
|
* persist current playlist
|
||||||
|
|
@ -22,3 +21,5 @@ Eventually:
|
||||||
* ditch qq fileuploader
|
* ditch qq fileuploader
|
||||||
* extract the skewed random song selection into a separate, tested module
|
* extract the skewed random song selection into a separate, tested module
|
||||||
* player: finer-grained updates. 'playlistUpdate' shouldn't be the only kind of update
|
* player: finer-grained updates. 'playlistUpdate' shouldn't be the only kind of update
|
||||||
|
- also should utilize the player's 'delete' and 'update' events for library changes
|
||||||
|
* player should notice when you delete a file while it is not running.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
var levelup = require('level');
|
|
||||||
|
|
||||||
module.exports = function (dbPath) {
|
|
||||||
dbPath = dbPath || "./groovebasin.db";
|
|
||||||
return levelup(dbPath);
|
|
||||||
};
|
|
||||||
|
|
@ -13,20 +13,16 @@ var requireIndex = require('requireindex');
|
||||||
var plugins = requireIndex(path.join(__dirname, 'plugins'));
|
var plugins = requireIndex(path.join(__dirname, 'plugins'));
|
||||||
var Player = require('./player');
|
var Player = require('./player');
|
||||||
var PlayerServer = require('./player_server');
|
var PlayerServer = require('./player_server');
|
||||||
var getDb = require('./db');
|
var levelup = require('level');
|
||||||
|
|
||||||
module.exports = GrooveBasin;
|
module.exports = GrooveBasin;
|
||||||
|
|
||||||
var CONFIG_KEY_PREFIX = "Config.";
|
var CONFIG_KEY_PREFIX = "Config.";
|
||||||
|
|
||||||
util.inherits(GrooveBasin, EventEmitter);
|
var defaultConfig = {
|
||||||
function GrooveBasin() {
|
host: '0.0.0.0',
|
||||||
EventEmitter.call(this);
|
port: 16242,
|
||||||
|
dbPath: "groovebasin.db",
|
||||||
this.app = express();
|
|
||||||
|
|
||||||
// defaults until we load the real values from the db
|
|
||||||
this.config = {
|
|
||||||
musicDirectory: path.join(osenv.home(), "music"),
|
musicDirectory: path.join(osenv.home(), "music"),
|
||||||
permissions: {},
|
permissions: {},
|
||||||
defaultPermissions: {
|
defaultPermissions: {
|
||||||
|
|
@ -34,7 +30,21 @@ function GrooveBasin() {
|
||||||
add: true,
|
add: true,
|
||||||
control: true,
|
control: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
defaultConfig.permissions[genPassword()] = {
|
||||||
|
admin: true,
|
||||||
|
read: true,
|
||||||
|
add: true,
|
||||||
|
control: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
util.inherits(GrooveBasin, EventEmitter);
|
||||||
|
function GrooveBasin() {
|
||||||
|
EventEmitter.call(this);
|
||||||
|
|
||||||
|
this.app = express();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GrooveBasin.prototype.initConfigVar = function(name, defaultValue) {
|
GrooveBasin.prototype.initConfigVar = function(name, defaultValue) {
|
||||||
|
|
@ -42,20 +52,58 @@ GrooveBasin.prototype.initConfigVar = function(name, defaultValue) {
|
||||||
this[name] = defaultValue;
|
this[name] = defaultValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
GrooveBasin.prototype.start = function(options) {
|
GrooveBasin.prototype.loadConfig = function(cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
self.httpHost = options.host || "0.0.0.0";
|
var pathToConfig = "config.js";
|
||||||
self.httpPort = options.port || 16242;
|
fs.readFile(pathToConfig, {encoding: 'utf8'}, function(err, contents) {
|
||||||
self.db = getDb(options.dbPath);
|
var anythingAdded = false;
|
||||||
|
var config;
|
||||||
|
if (err) {
|
||||||
|
if (err.code === 'ENOENT') {
|
||||||
|
anythingAdded = true;
|
||||||
|
self.config = defaultConfig;
|
||||||
|
console.warn("No config.js found; writing default.");
|
||||||
|
} else {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
self.config = JSON.parse(contents);
|
||||||
|
} catch (err) {
|
||||||
|
cb(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// this ensures that even old files get new config values when we add them
|
||||||
|
for (var key in defaultConfig) {
|
||||||
|
if (self.config[key] === undefined) {
|
||||||
|
anythingAdded = true;
|
||||||
|
self.config[key] = defaultConfig[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (anythingAdded) {
|
||||||
|
fs.writeFile(pathToConfig, JSON.stringify(self.config, null, 4), cb);
|
||||||
|
} else {
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
GrooveBasin.prototype.start = function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.loadConfig(function(err) {
|
||||||
|
if (err) {
|
||||||
|
console.error("Error reading config:", err.stack);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.httpHost = self.config.host;
|
||||||
|
self.httpPort = self.config.port;
|
||||||
|
self.db = levelup(self.config.dbPath);
|
||||||
|
|
||||||
self.app.use(express.static(path.join(__dirname, '../public')));
|
self.app.use(express.static(path.join(__dirname, '../public')));
|
||||||
self.app.use(express.static(path.join(__dirname, '../src/public')));
|
self.app.use(express.static(path.join(__dirname, '../src/public')));
|
||||||
|
|
||||||
self.restoreState(function(err) {
|
|
||||||
if (err) {
|
|
||||||
console.error("unable to restore state:", err.stack);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.player = new Player(self.db, self.config.musicDirectory);
|
self.player = new Player(self.db, self.config.musicDirectory);
|
||||||
self.player.initialize(function(err) {
|
self.player.initialize(function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
@ -86,6 +134,7 @@ GrooveBasin.prototype.start = function(options) {
|
||||||
function authenticate(password) {
|
function authenticate(password) {
|
||||||
return self.config.permissions[password];
|
return self.config.permissions[password];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GrooveBasin.prototype.restoreState = function(cb) {
|
GrooveBasin.prototype.restoreState = function(cb) {
|
||||||
|
|
@ -138,3 +187,6 @@ GrooveBasin.prototype.startServer = function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function genPassword() {
|
||||||
|
return Math.random().toString();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
var groove = require('groove');
|
var groove = require('groove');
|
||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
|
var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var Pend = require('pend');
|
var Pend = require('pend');
|
||||||
var chokidar = require('chokidar');
|
var chokidar = require('chokidar');
|
||||||
|
|
@ -109,21 +110,16 @@ Player.prototype.initialize = function(cb) {
|
||||||
|
|
||||||
self.watcher.on('add', onAddOrChange);
|
self.watcher.on('add', onAddOrChange);
|
||||||
self.watcher.on('change', onAddOrChange);
|
self.watcher.on('change', onAddOrChange);
|
||||||
self.watcher.on('unlink', removeFile);
|
self.watcher.on('unlink', onFileMissing);
|
||||||
|
|
||||||
self.watcher.on('error', function(err) {
|
self.watcher.on('error', function(err) {
|
||||||
console.error("library watching error:", err.stack);
|
console.error("library watching error:", err.stack);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeFile(file) {
|
function onFileMissing(fullPath) {
|
||||||
self.db.del(file, function(err) {
|
var relPath = path.relative(self.musicDirectory, fullPath);
|
||||||
if (err) {
|
self.delDbEntry(relPath);
|
||||||
console.error("Error deleting", file, err.stack);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.emit('delete', file);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onAddOrChange(fullPath, stat) {
|
function onAddOrChange(fullPath, stat) {
|
||||||
|
|
@ -168,6 +164,28 @@ Player.prototype.initialize = function(cb) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Player.prototype.deleteFile = function(relPath) {
|
||||||
|
var self = this;
|
||||||
|
var fullPath = path.join(self.musicDirectory, relPath);
|
||||||
|
fs.unlink(fullPath, function(err) {
|
||||||
|
if (err) {
|
||||||
|
console.error("Error deleting", relPath, err.stack);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.delDbEntry(relPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.prototype.delDbEntry = function(relPath) {
|
||||||
|
var self = this;
|
||||||
|
delete self.allDbFiles[relPath];
|
||||||
|
self.emit('delete', relPath);
|
||||||
|
self.db.del(relPath, function(err) {
|
||||||
|
if (err) {
|
||||||
|
console.error("Error deleting db entry", relPath, err.stack);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
Player.prototype.setVolume = function(value) {
|
Player.prototype.setVolume = function(value) {
|
||||||
value = Math.min(1.0, value);
|
value = Math.min(1.0, value);
|
||||||
value = Math.max(0.0, value);
|
value = Math.max(0.0, value);
|
||||||
|
|
|
||||||
|
|
@ -5,23 +5,7 @@ module.exports = Delete;
|
||||||
|
|
||||||
function Delete(gb) {
|
function Delete(gb) {
|
||||||
this.gb = gb;
|
this.gb = gb;
|
||||||
this.is_enabled = true;
|
this.gb.on('socketConnect', onSocketConnection.bind(this));
|
||||||
setup(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setup(self) {
|
|
||||||
self.gb.on('aboutToSaveState', function(state) {
|
|
||||||
state.status.delete_enabled = self.is_enabled;
|
|
||||||
});
|
|
||||||
self.gb.on('socketConnect', onSocketConnection.bind(self));
|
|
||||||
self.gb.on('stateRestored', function(state) {
|
|
||||||
self.music_directory = state.musicDirectory;
|
|
||||||
if (self.music_directory == null) {
|
|
||||||
self.is_enabled = false;
|
|
||||||
console.warn("No music directory set. Delete disabled.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSocketConnection(client) {
|
function onSocketConnection(client) {
|
||||||
|
|
@ -32,21 +16,8 @@ function onSocketConnection(client) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var files = JSON.parse(data);
|
var files = JSON.parse(data);
|
||||||
var file = null;
|
files.forEach(function(file) {
|
||||||
function next(err){
|
self.gb.player.deleteFile(file);
|
||||||
var file;
|
});
|
||||||
if (err) {
|
|
||||||
console.error("deleting " + file + ": " + err.stack);
|
|
||||||
} else if (file != null) {
|
|
||||||
console.info("deleted " + file);
|
|
||||||
}
|
|
||||||
if ((file = files.shift()) == null) {
|
|
||||||
self.gb.rescanLibrary();
|
|
||||||
} else {
|
|
||||||
fs.unlink(path.join(self.music_directory, file), next);
|
|
||||||
// TODO remove from library?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,4 @@ gb.on('listening', function() {
|
||||||
process.on('message', function(message){
|
process.on('message', function(message){
|
||||||
if (message === 'shutdown') process.exit(0);
|
if (message === 'shutdown') process.exit(0);
|
||||||
});
|
});
|
||||||
gb.start({
|
gb.start();
|
||||||
dbPath: process.env.DB_PATH,
|
|
||||||
host: process.env.HOST,
|
|
||||||
port: process.env.PORT,
|
|
||||||
});
|
|
||||||
|
|
|
||||||
104
lib/state.js
104
lib/state.js
|
|
@ -1,104 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
/* this command line utility displays or updates information from the db */
|
|
||||||
|
|
||||||
var getDb = require('./db');
|
|
||||||
var db = getDb(process.env.DB_PATH);
|
|
||||||
|
|
||||||
var args = process.argv.slice(2);
|
|
||||||
|
|
||||||
if (args.length === 0) {
|
|
||||||
dump();
|
|
||||||
} else {
|
|
||||||
processArgs();
|
|
||||||
}
|
|
||||||
|
|
||||||
function processArgs() {
|
|
||||||
var openThings = 0;
|
|
||||||
var putFlag = false;
|
|
||||||
var putKey = null;
|
|
||||||
var delFlag = false;
|
|
||||||
var getFlag = false;
|
|
||||||
process.argv.slice(2).forEach(function(arg) {
|
|
||||||
if (getFlag) {
|
|
||||||
get(arg);
|
|
||||||
getFlag = false;
|
|
||||||
} else if (delFlag) {
|
|
||||||
del(arg);
|
|
||||||
delFlag = false;
|
|
||||||
} else if (putKey != null) {
|
|
||||||
put(putKey, arg);
|
|
||||||
putFlag = false;
|
|
||||||
} else if (putFlag) {
|
|
||||||
putKey = arg;
|
|
||||||
} else if (arg === '--get') {
|
|
||||||
getFlag = true;
|
|
||||||
} else if (arg === '--put') {
|
|
||||||
putFlag = true;
|
|
||||||
} else if (arg === '--del') {
|
|
||||||
delFlag = true;
|
|
||||||
} else {
|
|
||||||
console.error("Unexpected argument:", arg);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function get(key) {
|
|
||||||
openAThing();
|
|
||||||
db.get(key, function(err, val) {
|
|
||||||
closeAThing();
|
|
||||||
if (err) {
|
|
||||||
console.error("Error getting", key, err.stack);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log(key, "=", val);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function put(key, val) {
|
|
||||||
openAThing();
|
|
||||||
db.put(key, val, function(err) {
|
|
||||||
closeAThing();
|
|
||||||
if (err) {
|
|
||||||
console.error("Error putting", key, err.stack);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log("put", key, "=", val);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function del(key) {
|
|
||||||
openAThing();
|
|
||||||
db.del(key, function(err, val) {
|
|
||||||
closeAThing();
|
|
||||||
if (err) {
|
|
||||||
console.error("Error deleting", key, err.stack);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log("del", key);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function openAThing() {
|
|
||||||
openThings += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeAThing() {
|
|
||||||
openThings -= 1;
|
|
||||||
if (openThings === 0) {
|
|
||||||
db.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function dump() {
|
|
||||||
var stream = db.createReadStream();
|
|
||||||
stream.on('data', function(data) {
|
|
||||||
console.log(data.key, "=", data.value);
|
|
||||||
});
|
|
||||||
stream.on('error', function(err) {
|
|
||||||
console.error(err.stack);
|
|
||||||
});
|
|
||||||
stream.on('close', function() {
|
|
||||||
db.close();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -546,15 +546,13 @@ function getDragPosition(x, y){
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
function renderSettings(){
|
|
||||||
var api_key, context;
|
function renderSettings() {
|
||||||
if ((api_key = server_status != null ? server_status.lastfm_api_key : void 8) == null) {
|
var apiKey = ""; // TODO fix this when lastfm plugin is fixed
|
||||||
return;
|
var context = {
|
||||||
}
|
|
||||||
context = {
|
|
||||||
lastfm: {
|
lastfm: {
|
||||||
auth_url: "http://www.last.fm/api/auth/?api_key=" +
|
auth_url: "http://www.last.fm/api/auth/?api_key=" +
|
||||||
encodeURIComponent(api_key) + "&cb=" +
|
encodeURIComponent(apiKey) + "&cb=" +
|
||||||
encodeURIComponent(location.protocol + "//" + location.host + "/"),
|
encodeURIComponent(location.protocol + "//" + location.host + "/"),
|
||||||
username: localState.lastfm.username,
|
username: localState.lastfm.username,
|
||||||
session_key: localState.lastfm.session_key,
|
session_key: localState.lastfm.session_key,
|
||||||
|
|
@ -578,6 +576,7 @@ function renderSettings(){
|
||||||
$settings.find('.auth-clear').button();
|
$settings.find('.auth-clear').button();
|
||||||
$settings.find('#auth-password').val(settings_ui.auth.password);
|
$settings.find('#auth-password').val(settings_ui.auth.password);
|
||||||
}
|
}
|
||||||
|
|
||||||
function scrollChatWindowToBottom(){
|
function scrollChatWindowToBottom(){
|
||||||
$chatList.scrollTop(1000000);
|
$chatList.scrollTop(1000000);
|
||||||
}
|
}
|
||||||
|
|
@ -636,12 +635,10 @@ function renderPlaylistButtons(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function renderPlaylist(){
|
function renderPlaylist(){
|
||||||
var context, scroll_top;
|
var context = {
|
||||||
context = {
|
|
||||||
playlist: mpd.playlist.item_list,
|
playlist: mpd.playlist.item_list,
|
||||||
server_status: server_status
|
|
||||||
};
|
};
|
||||||
scroll_top = $playlist_items.scrollTop();
|
var scroll_top = $playlist_items.scrollTop();
|
||||||
$playlist_items.html(Handlebars.templates.playlist(context));
|
$playlist_items.html(Handlebars.templates.playlist(context));
|
||||||
refreshSelection();
|
refreshSelection();
|
||||||
labelPlaylistItems();
|
labelPlaylistItems();
|
||||||
|
|
@ -1313,12 +1310,10 @@ function queueSelection(event){
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
function sendAuth(){
|
|
||||||
var pass;
|
function sendAuth() {
|
||||||
pass = localState.authPassword;
|
var pass = localState.authPassword;
|
||||||
if (pass == null) {
|
if (!pass) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
mpd.authenticate(pass, function(err){
|
mpd.authenticate(pass, function(err){
|
||||||
if (err) {
|
if (err) {
|
||||||
localState.authPassword = null;
|
localState.authPassword = null;
|
||||||
|
|
@ -1327,10 +1322,10 @@ function sendAuth(){
|
||||||
renderSettings();
|
renderSettings();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function settingsAuthSave(){
|
function settingsAuthSave(){
|
||||||
var $text_box;
|
|
||||||
settings_ui.auth.show_edit = false;
|
settings_ui.auth.show_edit = false;
|
||||||
$text_box = $('#auth-password');
|
var $text_box = $('#auth-password');
|
||||||
localState.authPassword = $text_box.val();
|
localState.authPassword = $text_box.val();
|
||||||
saveLocalState();
|
saveLocalState();
|
||||||
renderSettings();
|
renderSettings();
|
||||||
|
|
@ -1341,10 +1336,9 @@ function settingsAuthCancel(){
|
||||||
renderSettings();
|
renderSettings();
|
||||||
}
|
}
|
||||||
function performDrag(event, callbacks){
|
function performDrag(event, callbacks){
|
||||||
var start_drag_x, start_drag_y;
|
|
||||||
abortDrag();
|
abortDrag();
|
||||||
start_drag_x = event.pageX;
|
var start_drag_x = event.pageX;
|
||||||
start_drag_y = event.pageY;
|
var start_drag_y = event.pageY;
|
||||||
abortDrag = function(){
|
abortDrag = function(){
|
||||||
$document.off('mousemove', onDragMove).off('mouseup', onDragEnd);
|
$document.off('mousemove', onDragMove).off('mouseup', onDragEnd);
|
||||||
if (started_drag) {
|
if (started_drag) {
|
||||||
|
|
@ -1502,7 +1496,7 @@ function setUpPlaylistUi(){
|
||||||
refreshSelection();
|
refreshSelection();
|
||||||
}
|
}
|
||||||
context = {
|
context = {
|
||||||
status: server_status,
|
downloadEnabled: false, // TODO this will change when download plugin is fixed
|
||||||
permissions: permissions
|
permissions: permissions
|
||||||
};
|
};
|
||||||
if (selection.isMulti()) {
|
if (selection.isMulti()) {
|
||||||
|
|
@ -1957,7 +1951,7 @@ function genericTreeUi($elem, options){
|
||||||
refreshSelection();
|
refreshSelection();
|
||||||
}
|
}
|
||||||
context = {
|
context = {
|
||||||
status: server_status,
|
downloadEnabled: false, // TODO change this when download plugin is fixed
|
||||||
permissions: permissions
|
permissions: permissions
|
||||||
};
|
};
|
||||||
if (selection.isMulti()) {
|
if (selection.isMulti()) {
|
||||||
|
|
@ -2123,13 +2117,6 @@ $document.ready(function(){
|
||||||
chatState = data;
|
chatState = data;
|
||||||
renderChat();
|
renderChat();
|
||||||
});
|
});
|
||||||
socket.on('Status', function(data){
|
|
||||||
server_status = JSON.parse(data.toString());
|
|
||||||
renderPlaylistButtons();
|
|
||||||
labelPlaylistItems();
|
|
||||||
renderSettings();
|
|
||||||
window._debug_server_status = server_status;
|
|
||||||
});
|
|
||||||
mpd = new PlayerClient(socket);
|
mpd = new PlayerClient(socket);
|
||||||
mpd.on('libraryupdate', renderLibrary);
|
mpd.on('libraryupdate', renderLibrary);
|
||||||
mpd.on('playlistupdate', renderPlaylist);
|
mpd.on('playlistupdate', renderPlaylist);
|
||||||
|
|
|
||||||
|
|
@ -4,18 +4,14 @@
|
||||||
<li><a href="#" class="queue-random hoverable">Queue in Random Order</a></li>
|
<li><a href="#" class="queue-random hoverable">Queue in Random Order</a></li>
|
||||||
<li><a href="#" class="queue-next-random hoverable">Queue Next in Random Order</a></li>
|
<li><a href="#" class="queue-next-random hoverable">Queue Next in Random Order</a></li>
|
||||||
<li>
|
<li>
|
||||||
{{#if status.delete_enabled}}
|
|
||||||
{{#if permissions.admin}}
|
{{#if permissions.admin}}
|
||||||
<a href="#" class="delete hoverable">Delete</a>
|
<a href="#" class="delete hoverable">Delete</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<span title="Delete is disabled: insufficient privileges. See Settings.">Delete</span>
|
<span title="Delete is disabled: insufficient privileges. See Settings.">Delete</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{else}}
|
|
||||||
<span title="Delete is disabled due to invalid server configuration.">Delete</span>
|
|
||||||
{{/if}}
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
{{#if status.download_enabled}}
|
{{#if downloadEnabled}}
|
||||||
{{#if track}}
|
{{#if track}}
|
||||||
<a href="library/{{track.file}}" class="download hoverable" target="_blank">Download</a>
|
<a href="library/{{track.file}}" class="download hoverable" target="_blank">Download</a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,14 @@
|
||||||
<ul id="menu" class="ui-widget-content ui-corner-all">
|
<ul id="menu" class="ui-widget-content ui-corner-all">
|
||||||
<li><a href="#" class="remove hoverable">Remove</a></li>
|
<li><a href="#" class="remove hoverable">Remove</a></li>
|
||||||
<li>
|
<li>
|
||||||
{{#if status.delete_enabled}}
|
|
||||||
{{#if permissions.admin}}
|
{{#if permissions.admin}}
|
||||||
<a href="#" class="delete hoverable">Delete From Library</a>
|
<a href="#" class="delete hoverable">Delete From Library</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<span title="Delete is disabled: insufficient privileges. See Settings.">Delete From Library</span>
|
<span title="Delete is disabled: insufficient privileges. See Settings.">Delete From Library</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{else}}
|
|
||||||
<span title="Delete is disabled due to invalid server configuration.">Delete From Library</span>
|
|
||||||
{{/if}}
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
{{#if status.download_enabled}}
|
{{#if downloadEnabled}}
|
||||||
{{#if item}}
|
{{#if item}}
|
||||||
<a href="library/{{item.track.file}}" class="download hoverable" target="_blank">Download</a>
|
<a href="library/{{item.track.file}}" class="download hoverable" target="_blank">Download</a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue