1
0
mirror of https://github.com/SuperBFG7/ympd synced 2024-12-24 18:10:26 +00:00

Feat: add ability to define and execute system commands, eg. reboot and shutdown

This commit is contained in:
jcorporation 2018-10-15 23:34:25 +01:00
parent 91f5d4131d
commit e371453b7b
8 changed files with 100 additions and 8 deletions

View File

@ -58,4 +58,5 @@ install(DIRECTORY htdocs/assets DESTINATION share/${PROJECT_NAME}/htdocs)
install(DIRECTORY DESTINATION ../var/lib/${PROJECT_NAME}/pics)
install(DIRECTORY DESTINATION ../var/lib/${PROJECT_NAME}/tmp)
install(DIRECTORY DESTINATION ../var/lib/${PROJECT_NAME}/state)
install(DIRECTORY DESTINATION ../etc/${PROJECT_NAME}/syscmds)
install(DIRECTORY dist/smartpls DESTINATION ../var/lib/${PROJECT_NAME})

1
dist/syscmds/Reboot vendored Normal file
View File

@ -0,0 +1 @@
sudo /sbin/reboot

1
dist/syscmds/Shutdown vendored Normal file
View File

@ -0,0 +1 @@
sudo /sbin/halt

View File

@ -34,6 +34,7 @@
<a class="dropdown-item text-light bg-dark" href="#" data-toggle="modal" data-target="#modalSettings">Settings</a>
<a class="dropdown-item text-light bg-dark" href="#" data-toggle="modal" data-target="#modalAbout">About</a>
<a id="nav-add2homescreen" class="dropdown-item text-light bg-dark hide" href="#">Add2HomeScreen</a>
<div id="syscmds"></div>
</div>
</div>
<div class="btn-toolbar col-auto pl-0 pr-0">

View File

@ -379,13 +379,21 @@ function appInit() {
addFilterLetter('BrowseDatabaseFilterLetters');
addFilterLetter('BrowsePlaylistsFilterLetters');
document.getElementById('syscmds').addEventListener('click', function(event) {
event.preventDefault();
if (event.target.nodeName == 'A') {
var cmd = JSON.parse(event.target.getAttribute('data-href'));
if (typeof window[cmd.cmd] === 'function')
window[cmd.cmd](... cmd.options);
}
}, false);
var hrefs = document.querySelectorAll('[data-href]');
var hrefsLen = hrefs.length;
for (var i = 0; i < hrefsLen; i++) {
hrefs[i].classList.add('clickable');
hrefs[i].addEventListener('click', function(event) {
event.preventDefault();
//event.stopPropagation();
var cmd = JSON.parse(this.getAttribute('data-href'));
if (typeof window[cmd.cmd] === 'function') {
switch(cmd.cmd) {
@ -934,9 +942,18 @@ function parseSettings(obj) {
addTagList('searchqueuetag', true);
addTagList('searchtags', true);
for (var i = 0; i < obj.data.tags.length; i++) {
for (var i = 0; i < obj.data.tags.length; i++)
app.apps.Browse.tabs.Database.views[obj.data.tags[i]] = { "state": "0/-/", "scrollPos": 0 };
var syscmdsList = '';
var syscmdsListLen = obj.data.syscmds.length;
if (syscmdsListLen > 0) {
syscmdsList = '<div class="dropdown-divider"></div>';
for (var i = 0; i < syscmdsListLen; i++)
syscmdsList += '<a class="dropdown-item text-light bg-dark" href="#" data-href=\'{"cmd": "execSyscmd", "options": ["' +
obj.data.syscmds[i] + '"]}\'>' + obj.data.syscmds[i] + '</a>';
}
document.getElementById('syscmds').innerHTML = syscmdsList;
}
function getSettings() {
@ -1605,6 +1622,10 @@ function parseSongDetails(obj) {
modal.getElementsByTagName('tbody')[0].innerHTML = songDetails;
}
function execSyscmd(cmd) {
sendAPI({"cmd": "MPD_API_SYSCMD", "data": {"cmd": cmd}});
}
function playlistDetails(uri) {
document.getElementById('BrowsePlaylistsAllList').classList.add('opacity05');
appGoto('Browse', 'Playlists', 'Detail', '0/-/' + uri);

View File

@ -109,6 +109,15 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) {
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"MPD stickers are disabled\"}");
}
break;
case MPD_API_SYSCMD:
je = json_scanf(msg.p, msg.len, "{data: {cmd: %Q}}", &p_charbuf1);
if (je == 1) {
int_buf1 = list_get_value(&syscmds, p_charbuf1);
if (int_buf1 == 1)
n = mympd_syscmd(mpd.buf, p_charbuf1);
free(p_charbuf1);
}
break;
case MPD_API_PLAYER_STATE:
n = mympd_put_state(mpd.buf, &mpd.song_id, &mpd.next_song_id, &mpd.last_song_id, &mpd.queue_version, &mpd.queue_length);
break;
@ -1214,6 +1223,28 @@ bool mympd_state_set(char *name, char *value) {
return true;
}
int mympd_syscmd(char *buffer, char *cmd) {
int len;
char filename[400];
char *line;
size_t n = 0;
ssize_t read;
snprintf(filename, 400, "%s/syscmds/%s", config.etcdir, cmd);
FILE *fp = fopen(filename, "r");
if (fp == NULL) {
len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't execute cmd %s\"}", cmd);
return len;
}
read = getline(&line, &n, fp);
fclose(fp);
strtok(line, "\n");
system(line);
len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Executed cmd %s\"}", line);
CHECK_RETURN_LEN();
return len;
}
int mympd_put_settings(char *buffer) {
struct mpd_status *status;
char *replaygain = strdup("");
@ -1276,7 +1307,18 @@ int mympd_put_settings(char *buffer) {
current = current->next;
}
len += json_printf(&out, "]}}");
len += json_printf(&out, "], syscmds: [");
nr = 0;
current = syscmds.list;
while (current != NULL) {
if (nr ++)
len += json_printf(&out, ",");
len += json_printf(&out, "%Q", current->data);
current = current->next;
}
len += json_printf(&out, "]}}");
CHECK_RETURN_LEN();
return len;
@ -2148,6 +2190,7 @@ int mympd_smartpls_update_all() {
printf("Can't parse file %s\n", filename);
}
free(smartpltype);
free(content);
}
closedir (dir);
} else {

View File

@ -109,6 +109,7 @@
X(MPD_API_MESSAGE_SEND) \
X(MPD_API_WELCOME) \
X(MPD_API_LIKE) \
X(MPD_API_SYSCMD) \
X(MPD_API_UNKNOWN)
enum mpd_cmd_ids {
@ -150,6 +151,8 @@ struct t_mpd {
struct list mpd_tags;
struct list mympd_tags;
struct list syscmds;
typedef struct {
long mpdport;
const char* mpdhost;
@ -167,6 +170,7 @@ typedef struct {
const char* taglist;
bool smartpls;
const char* varlibdir;
const char* etcdir;
long max_elements_per_page;
} t_config;
@ -207,6 +211,7 @@ void mympd_get_sticker(const char *uri, t_sticker *sticker);
void mympd_jukebox();
bool mympd_state_get(char *name, char *value);
bool mympd_state_set(char *name, char *value);
int mympd_syscmd(char *buffer, char *cmd);
int mympd_smartpls_save(char *smartpltype, char *playlist, char *tag, char *searchstr, int maxentries, int timerange);
int mympd_smartpls_put(char *buffer, char *playlist);
int mympd_smartpls_update_all();

View File

@ -29,6 +29,7 @@
#include <sys/time.h>
#include <pwd.h>
#include <grp.h>
#include <libgen.h>
#include "../dist/src/mongoose/mongoose.h"
#include "../dist/src/frozen/frozen.h"
@ -130,12 +131,8 @@ static int inihandler(void* user, const char* section, const char* name, const c
if (MATCH("mpdhost"))
p_config->mpdhost = strdup(value);
else if (MATCH("mpdhost"))
p_config->mpdhost = strdup(value);
else if (MATCH("mpdport"))
p_config->mpdport = strtol(value, &crap, 10);
else if (MATCH("mpdhost"))
p_config->mpdhost = strdup(value);
else if (MATCH("mpdpass"))
p_config->mpdpass = strdup(value);
else if (MATCH("webport"))
@ -187,6 +184,23 @@ static int inihandler(void* user, const char* section, const char* name, const c
return 1;
}
void read_syscmds() {
DIR *dir;
struct dirent *ent;
char dirname[400];
snprintf(dirname, 400, "%s/syscmds", config.etcdir);
printf("Reading syscmds: %s\n", dirname);
if ((dir = opendir (dirname)) != NULL) {
while ((ent = readdir(dir)) != NULL) {
if (strncmp(ent->d_name, ".", 1) == 0)
continue;
list_push(&syscmds, ent->d_name, 1);
}
closedir(dir);
}
}
void read_statefiles() {
char *crap;
char value[400];
@ -266,7 +280,7 @@ int main(int argc, char **argv) {
config.sslport = "443";
config.sslcert = "/etc/mympd/ssl/server.pem";
config.sslkey = "/etc/mympd/ssl/server.key";
config.user = "nobody";
config.user = "mympd";
config.streamport = 8000;
config.coverimage = "folder.jpg";
config.varlibdir = "/var/lib/mympd";
@ -275,6 +289,8 @@ int main(int argc, char **argv) {
config.taglist = "Artist,Album,AlbumArtist,Title,Track,Genre,Date,Composer,Performer";
config.smartpls = true;
config.max_elements_per_page = 100;
char *etcdir = strdup(argv[1]);
config.etcdir = dirname(etcdir);
mpd.timeout = 3000;
mpd.last_update_sticker_song_id = -1;
@ -380,6 +396,9 @@ int main(int argc, char **argv) {
read_statefiles();
list_init(&syscmds);
read_syscmds();
list_init(&mpd_tags);
list_init(&mympd_tags);