diff --git a/contrib/mympd.conf.dist b/contrib/mympd.conf.dist
index 9df4d1c..a7a0c46 100644
--- a/contrib/mympd.conf.dist
+++ b/contrib/mympd.conf.dist
@@ -17,9 +17,15 @@ sslkey = /etc/mympd/ssl/server.key
#myMPD user
user = mympd
+#Enable local player, needs streamport or streamurl setting
+localplayer = true
+
#Port for mpd http stream
streamport = 8000
+#Manual streamurl, overwrites streamport
+#streamurl = http://jukebox:8000
+
#Name for coverimages
coverimage = folder.jpg
@@ -34,9 +40,14 @@ stickers = true
#List of tags in myMPD gui
taglist = Artist,Album,AlbumArtist,Title,Track,Genre,Date,Composer,Performer
+searchtaglist = Artist,Album,AlbumArtist,Title,Genre,Composer,Performer
+browsetaglist = Artist,Album,AlbumArtist,Genre,Composer,Performer
#Enable smart playlists
smartpls = true
+#Enable system commands in /etc/mympd/syscmds/
+syscmds = false
+
#Elements per page for pagination, max: 400
max_elements_per_page = 100
diff --git a/htdocs/index.html b/htdocs/index.html
index 950b3e8..d3a6fbe 100644
--- a/htdocs/index.html
+++ b/htdocs/index.html
@@ -30,7 +30,7 @@
Rescan Database
Update Smart Playlists
- Local Player
+ Local Player
Settings
About
Add2HomeScreen
@@ -139,9 +139,9 @@
-
diff --git a/htdocs/js/mympd.js b/htdocs/js/mympd.js
index 3db0dfb..2886b9e 100644
--- a/htdocs/js/mympd.js
+++ b/htdocs/js/mympd.js
@@ -193,7 +193,7 @@ function appRoute() {
sendAPI({"cmd": "MPD_API_PLAYER_CURRENT_SONG"}, songChange);
}
else if (app.current.app == 'Queue' ) {
- selectTag('searchqueuetag', 'searchqueuetagdesc', app.current.filter);
+ selectTag('searchqueuetags', 'searchqueuetagsdesc', app.current.filter);
getQueue();
}
else if (app.current.app == 'Browse' && app.current.tab == 'Playlists' && app.current.view == 'All') {
@@ -528,7 +528,7 @@ function appInit() {
appGoto(app.current.app, app.current.tab, app.current.view, '0/' + app.current.filter + '/' + this.value);
}, false);
- document.getElementById('searchqueuetag').addEventListener('click', function(event) {
+ document.getElementById('searchqueuetags').addEventListener('click', function(event) {
if (event.target.nodeName == 'BUTTON')
appGoto(app.current.app, app.current.tab, app.current.view, app.current.page + '/' + event.target.getAttribute('data-tag') + '/' + app.current.search);
}, false);
@@ -962,36 +962,38 @@ function filterCols(x) {
}
function parseSettings(obj) {
- toggleBtn('btnRandom', obj.data.random);
- toggleBtn('btnConsume', obj.data.consume);
- toggleBtn('btnSingle', obj.data.single);
- toggleBtn('btnRepeat', obj.data.repeat);
+ settings = obj.data;
+
+ toggleBtn('btnRandom', settings.random);
+ toggleBtn('btnConsume', settings.consume);
+ toggleBtn('btnSingle', settings.single);
+ toggleBtn('btnRepeat', settings.repeat);
- if (obj.data.crossfade != undefined) {
+ if (settings.crossfade != undefined) {
document.getElementById('inputCrossfade').removeAttribute('disabled');
- document.getElementById('inputCrossfade').value = obj.data.crossfade;
+ document.getElementById('inputCrossfade').value = settings.crossfade;
} else {
document.getElementById('inputCrossfade').setAttribute('disabled', 'disabled');
}
- if (obj.data.mixrampdb != undefined) {
+ if (settings.mixrampdb != undefined) {
document.getElementById('inputMixrampdb').removeAttribute('disabled');
- document.getElementById('inputMixrampdb').value = obj.data.mixrampdb;
+ document.getElementById('inputMixrampdb').value = settings.mixrampdb;
} else {
document.getElementById('inputMixrampdb').setAttribute('disabled', 'disabled');
}
- if (obj.data.mixrampdelay != undefined) {
+ if (settings.mixrampdelay != undefined) {
document.getElementById('inputMixrampdelay').removeAttribute('disabled');
- document.getElementById('inputMixrampdelay').value = obj.data.mixrampdelay;
+ document.getElementById('inputMixrampdelay').value = settings.mixrampdelay;
} else {
document.getElementById('inputMixrampdelay').setAttribute('disabled', 'disabled');
}
- document.getElementById('selectReplaygain').value = obj.data.replaygain;
+ document.getElementById('selectReplaygain').value = settings.replaygain;
var btnnotifyWeb = document.getElementById('btnnotifyWeb');
if (notificationsSupported()) {
- if (obj.data.notificationWeb) {
- toggleBtn('btnnotifyWeb', obj.data.notificationWeb);
+ if (settings.notificationWeb) {
+ toggleBtn('btnnotifyWeb', settings.notificationWeb);
Notification.requestPermission(function (permission) {
if (!('permission' in Notification))
Notification.permission = permission;
@@ -999,7 +1001,7 @@ function parseSettings(obj) {
toggleBtn('btnnotifyWeb', 1);
} else {
toggleBtn('btnnotifyWeb', 0);
- obj.data.notificationWeb = true;
+ settings.notificationWeb = true;
}
});
}
@@ -1011,49 +1013,49 @@ function parseSettings(obj) {
toggleBtn('btnnotifyWeb', 0);
}
- toggleBtn('btnnotifyPage', obj.data.notificationPage);
+ toggleBtn('btnnotifyPage', settings.notificationPage);
var features = ["featStickers", "featSmartpls", "featPlaylists", "featTags"];
for (var j = 0; j < features.length; j++) {
var Els = document.getElementsByClassName(features[j]);
var ElsLen = Els.length;
- var displayEl = obj.data[features[j]] == true ? '' : 'none';
+ var displayEl = settings[features[j]] == true ? '' : 'none';
for (var i = 0; i < ElsLen; i++)
Els[i].style.display = displayEl;
}
- if (obj.data.featTags == false) {
+ if (settings.featTags == false) {
app.apps.Browse.active = 'Filesystem';
app.apps.Search.state = '0/filename/';
}
- if (obj.data.mixramp == true)
+ if (settings.mixramp == true)
document.getElementsByClassName('mixramp')[0].style.display = '';
else
document.getElementsByClassName('mixramp')[0].style.display = 'none';
- if (!obj.data.tags.includes('AlbumArtist') && obj.data.featTags) {
- if (obj.data.tags.includes('Artist'))
+ if (!settings.tags.includes('AlbumArtist') && settings.featTags) {
+ if (settings.tags.includes('Artist'))
app.apps.Browse.tabs.Database.active = 'Artist';
else
app.apps.Browse.tabs.Database.active = settings.tags[0];
}
- document.getElementById('selectJukeboxMode').value = obj.data.jukeboxMode;
- document.getElementById('inputJukeboxQueueLength').value = obj.data.jukeboxQueueLength;
- if (obj.data.jukeboxMode == 0 || obj.data.jukeboxMode == 2) {
+ document.getElementById('selectJukeboxMode').value = settings.jukeboxMode;
+ document.getElementById('inputJukeboxQueueLength').value = settings.jukeboxQueueLength;
+ if (settings.jukeboxMode == 0 || settings.jukeboxMode == 2) {
document.getElementById('inputJukeboxQueueLength').setAttribute('disabled', 'disabled');
document.getElementById('selectJukeboxPlaylist').setAttribute('disabled', 'disabled');
}
- else if (obj.data.jukeboxMode == 1) {
+ else if (settings.jukeboxMode == 1) {
document.getElementById('inputJukeboxQueueLength').removeAttribute('disabled');
document.getElementById('selectJukeboxPlaylist').removeAttribute('disabled');
}
- settings = obj.data;
- if (obj.data.featPlaylists) {
+
+ if (settings.featPlaylists) {
playlistEl = 'selectJukeboxPlaylist';
sendAPI({"cmd": "MPD_API_PLAYLIST_LIST", "data": {"offset": 0, "filter": "-"}}, getAllPlaylists);
} else {
@@ -1066,29 +1068,42 @@ function parseSettings(obj) {
filterCols('colsBrowsePlaylistsDetail');
filterCols('colsBrowseFilesystem');
- settings.mpdstream = 'http://';
- if (settings.mpdhost == '127.0.0.1' || settings.mpdhost == 'localhost')
- settings.mpdstream += window.location.hostname;
- else
- settings.mpdstream += settings.mpdhost;
- settings.mpdstream += ':' + settings.streamport + '/';
-
- addTagList('BrowseDatabaseByTagDropdown', false);
- addTagList('searchqueuetag', true);
- addTagList('searchtags', true);
-
- 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 = '';
- for (var i = 0; i < syscmdsListLen; i++)
- syscmdsList += '' + obj.data.syscmds[i] + '';
+ if (settings.localplayer) {
+ if (settings.streamurl == '') {
+ settings.mpdstream = 'http://';
+ if (settings.mpdhost == '127.0.0.1' || settings.mpdhost == 'localhost')
+ settings.mpdstream += window.location.hostname;
+ else
+ settings.mpdstream += settings.mpdhost;
+ settings.mpdstream += ':' + settings.streamport + '/';
+ }
+ else
+ settings.mpdstream = settings.streamurl;
+ document.getElementsByClassName('featLocalplayer')[0].classList.remove('hide');
}
- document.getElementById('syscmds').innerHTML = syscmdsList;
+ else
+ document.getElementsByClassName('featLocalplayer')[0].classList.add('hide');
+
+ addTagList('BrowseDatabaseByTagDropdown', 'browsetags');
+ addTagList('searchqueuetags', 'searchtags');
+ addTagList('searchtags', 'searchtags');
+
+ for (var i = 0; i < settings.tags.length; i++)
+ app.apps.Browse.tabs.Database.views[settings.tags[i]] = { "state": "0/-/", "scrollPos": 0 };
+
+ if (settings.featSyscmds) {
+ var syscmdsList = '';
+ var syscmdsListLen = settings.syscmds.length;
+ if (syscmdsListLen > 0) {
+ syscmdsList = '';
+ for (var i = 0; i < syscmdsListLen; i++)
+ syscmdsList += '' + settings.syscmds[i] + '';
+ }
+ document.getElementById('syscmds').innerHTML = syscmdsList;
+ }
+ else
+ document.getElementById('syscmds').innerHTML = '';
setCols('Queue');
setCols('Search');
@@ -1980,17 +1995,14 @@ function parseSmartPlaylist(obj) {
var nameEl = document.getElementById('saveSmartPlaylistName');
nameEl.value = obj.data.playlist;
nameEl.classList.remove('is-invalid');
- document.getElementById('saveSmartPlaylistType').value = obj.data.Type;
+ document.getElementById('saveSmartPlaylistType').value = obj.data.type;
document.getElementById('saveSmartPlaylistFrm').classList.remove('was-validated');
document.getElementById('saveSmartPlaylistSearch').classList.add('hide');
document.getElementById('saveSmartPlaylistSticker').classList.add('hide');
document.getElementById('saveSmartPlaylistNewest').classList.add('hide');
var tagList = '';
- for (var i = 0; i < settings.tags.length; i++) {
- if (settings.tags[i] != 'Track') {
- tagList += '';
- }
- }
+ for (var i = 0; i < settings.searchtags.length; i++)
+ tagList += '';
document.getElementById('selectSaveSmartPlaylistTag').innerHTML = tagList;
if (obj.data.type == 'search') {
document.getElementById('saveSmartPlaylistSearch').classList.remove('hide');
@@ -2715,7 +2727,7 @@ function selectTag(btnsEl, desc, setTo) {
document.getElementById(desc).innerText = aBtn.innerText;
}
}
-
+/*
function addTagList(x, any) {
var tagList = '';
var tagBlacklist = ["Title", "MUSICBRAINZ_TRACKID", "Count", "Disc", "Comment", "Name"];
@@ -2735,6 +2747,19 @@ function addTagList(x, any) {
var tagListEl = document.getElementById(x);
tagListEl.innerHTML = tagList;
}
+*/
+function addTagList(el, list) {
+ var tagList = '';
+ if (list == 'searchtags') {
+ if (settings.featTags == true)
+ tagList += '';
+ else
+ tagList += '';
+ }
+ for (var i = 0; i < settings[list].length; i++)
+ tagList += '';
+ document.getElementById(el).innerHTML = tagList;
+}
function gotoTagList() {
appGoto(app.current.app, app.current.tab, app.current.view, '0/-/');
diff --git a/src/mpd_client.c b/src/mpd_client.c
index 9a86674..de165a1 100644
--- a/src/mpd_client.c
+++ b/src/mpd_client.c
@@ -144,13 +144,17 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) {
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}");
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, int_buf1);
- free(p_charbuf1);
- }
+ if (config.syscmds == true) {
+ 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, int_buf1);
+ free(p_charbuf1);
+ }
+ }
+ else
+ n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"System commands are disabled.\"}");
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);
@@ -719,7 +723,9 @@ void mympd_parse_idle(struct mg_mgr *s, int idle_bitmask) {
void mympd_mpd_features() {
struct mpd_pair *pair;
char s[2] = ",";
- char *str = strdup(config.taglist);
+ char *taglist = strdup(config.taglist);
+ char *searchtaglist = strdup(config.searchtaglist);
+ char *browsetaglist = strdup(config.browsetaglist);
char *token;
mpd.protocol = mpd_connection_get_server_version(mpd.conn);
@@ -769,7 +775,7 @@ void mympd_mpd_features() {
else {
mpd.feat_tags = true;
printf("\nmyMPD enabled tags: ");
- token = strtok(str, s);
+ token = strtok(taglist, s);
while (token != NULL) {
if (list_get_value(&mpd_tags, token) == 1) {
list_push(&mympd_tags, token, 1);
@@ -777,9 +783,29 @@ void mympd_mpd_features() {
}
token = strtok(NULL, s);
}
- printf("\n");
+ printf("\nmyMPD enabled searchtags: ");
+ token = strtok(searchtaglist, s);
+ while (token != NULL) {
+ if (list_get_value(&mpd_tags, token) == 1) {
+ list_push(&mympd_searchtags, token, 1);
+ printf("%s ", token);
+ }
+ token = strtok(NULL, s);
+ }
+ printf("\nmyMPD enabled browsetags: ");
+ token = strtok(browsetaglist, s);
+ while (token != NULL) {
+ if (list_get_value(&mpd_tags, token) == 1) {
+ list_push(&mympd_browsetags, token, 1);
+ printf("%s ", token);
+ }
+ token = strtok(NULL, s);
+ }
+ printf("\n");
}
- free(str);
+ free(taglist);
+ free(searchtaglist);
+ free(browsetaglist);
}
void mympd_idle(struct mg_mgr *s, int timeout) {
@@ -1324,8 +1350,8 @@ int mympd_put_settings(char *buffer) {
len = json_printf(&out, "{type: settings, data: {"
"repeat: %d, single: %d, crossfade: %d, consume: %d, random: %d, "
- "mixrampdb: %f, mixrampdelay: %f, mpdhost: %Q, mpdport: %d, passwort_set: %B, featPlaylists: %B, featTags: %B, "
- "streamport: %d, coverimage: %Q, featStickers: %B, mixramp: %B, featSmartpls: %B, maxElementsPerPage: %d, "
+ "mixrampdb: %f, mixrampdelay: %f, mpdhost: %Q, mpdport: %d, passwort_set: %B, featSyscmds: %B, featPlaylists: %B, featTags: %B, "
+ "localplayer: %B, streamport: %d, streamurl: %Q, coverimage: %Q, featStickers: %B, mixramp: %B, featSmartpls: %B, maxElementsPerPage: %d, "
"replaygain: %Q, notificationWeb: %B, notificationPage: %B, jukeboxMode: %d, jukeboxPlaylist: %Q, jukeboxQueueLength: %d, "
"tags: [",
mpd_status_get_repeat(status),
@@ -1338,9 +1364,12 @@ int mympd_put_settings(char *buffer) {
config.mpdhost,
config.mpdport,
config.mpdpass ? "true" : "false",
+ config.syscmds,
mpd.feat_playlists,
mpd.feat_tags,
- config.streamport,
+ config.localplayer,
+ config.streamport,
+ config.streamurl,
config.coverimage,
config.stickers,
config.mixramp,
@@ -1356,6 +1385,7 @@ int mympd_put_settings(char *buffer) {
mpd_status_free(status);
free(replaygain);
+ nr = 0;
struct node *current = mympd_tags.list;
while (current != NULL) {
if (nr++)
@@ -1363,9 +1393,18 @@ int mympd_put_settings(char *buffer) {
len += json_printf(&out, "%Q", current->data);
current = current->next;
}
- len += json_printf(&out, "], syscmds: [");
+ len += json_printf(&out, "], searchtags: [");
nr = 0;
- current = syscmds.list;
+ current = mympd_searchtags.list;
+ while (current != NULL) {
+ if (nr++)
+ len += json_printf(&out, ",");
+ len += json_printf(&out, "%Q", current->data);
+ current = current->next;
+ }
+ len += json_printf(&out, "], browsetags: [");
+ nr = 0;
+ current = mympd_browsetags.list;
while (current != NULL) {
if (nr++)
len += json_printf(&out, ",");
@@ -1373,6 +1412,19 @@ int mympd_put_settings(char *buffer) {
current = current->next;
}
len += json_printf(&out, "]");
+
+ if (config.syscmds == true) {
+ 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, "]");
+ }
len += json_printf(&out, ", colsQueue: %s", mympd_state.colsQueue);
len += json_printf(&out, ", colsSearch: %s", mympd_state.colsSearch);
len += json_printf(&out, ", colsBrowseDatabase: %s", mympd_state.colsBrowseFilesystem);
diff --git a/src/mpd_client.h b/src/mpd_client.h
index a88c2d6..83e5493 100644
--- a/src/mpd_client.h
+++ b/src/mpd_client.h
@@ -168,6 +168,8 @@ struct t_mpd {
struct list mpd_tags;
struct list mympd_tags;
+struct list mympd_searchtags;
+struct list mympd_browsetags;
struct list syscmds;
@@ -181,15 +183,20 @@ typedef struct {
const char* sslcert;
const char* sslkey;
const char* user;
- long streamport;
const char* coverimage;
bool stickers;
bool mixramp;
const char* taglist;
+ const char* searchtaglist;
+ const char* browsetaglist;
bool smartpls;
const char* varlibdir;
const char* etcdir;
unsigned long max_elements_per_page;
+ bool syscmds;
+ bool localplayer;
+ long streamport;
+ const char* streamurl;
} t_config;
t_config config;
diff --git a/src/mympd.c b/src/mympd.c
index 1cd2185..7928b94 100644
--- a/src/mympd.c
+++ b/src/mympd.c
@@ -171,6 +171,10 @@ static int inihandler(void* user, const char* section, const char* name, const c
p_config->mixramp = false;
else if (MATCH("taglist"))
p_config->taglist = strdup(value);
+ else if (MATCH("searchtaglist"))
+ p_config->searchtaglist = strdup(value);
+ else if (MATCH("browsetaglist"))
+ p_config->browsetaglist = strdup(value);
else if (MATCH("max_elements_per_page")) {
p_config->max_elements_per_page = strtol(value, &crap, 10);
if (p_config->max_elements_per_page > MAX_ELEMENTS_PER_PAGE) {
@@ -178,6 +182,18 @@ static int inihandler(void* user, const char* section, const char* name, const c
p_config->max_elements_per_page = MAX_ELEMENTS_PER_PAGE;
}
}
+ else if (MATCH("syscmds"))
+ if (strcmp(value, "true") == 0)
+ p_config->syscmds = true;
+ else
+ p_config->syscmds = false;
+ else if (MATCH("localplayer"))
+ if (strcmp(value, "true") == 0)
+ p_config->localplayer = true;
+ else
+ p_config->localplayer = false;
+ else if (MATCH("streamurl"))
+ p_config->streamurl = strdup(value);
else
return 0; /* unknown section/name, error */
@@ -190,19 +206,22 @@ void read_syscmds() {
char dirname[400];
char *cmd;
long order;
-
- 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;
- order = strtol(ent->d_name, &cmd, 10);
- if (strcmp(cmd, "") != 0)
- list_push(&syscmds, strdup(cmd), order);
+ if (config.syscmds == true) {
+ 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;
+ order = strtol(ent->d_name, &cmd, 10);
+ if (strcmp(cmd, "") != 0)
+ list_push(&syscmds, strdup(cmd), order);
+ }
+ closedir(dir);
}
- closedir(dir);
}
+ else
+ printf("Syscmds are disabled\n");
}
void read_statefiles() {
@@ -321,15 +340,20 @@ int main(int argc, char **argv) {
config.sslkey = "/etc/mympd/ssl/server.key";
config.user = "mympd";
config.streamport = 8000;
+ config.streamurl = "";
config.coverimage = "folder.jpg";
config.varlibdir = "/var/lib/mympd";
config.stickers = true;
config.mixramp = true;
config.taglist = "Artist,Album,AlbumArtist,Title,Track,Genre,Date,Composer,Performer";
+ config.searchtaglist = "Artist,Album,AlbumArtist,Title,Genre,Composer,Performer";
+ config.browsetaglist = "Artist,Album,AlbumArtist,Genre,Composer,Performer";
config.smartpls = true;
config.max_elements_per_page = 100;
char *etcdir = strdup(argv[1]);
config.etcdir = dirname(etcdir);
+ config.syscmds = false;
+ config.localplayer = true;
mpd.timeout = 3000;
mpd.last_update_sticker_song_id = -1;