diff --git a/dist/htdocs/js/mpd.min.js b/dist/htdocs/js/mpd.min.js index 17f6e49..a5ee7d8 100644 --- a/dist/htdocs/js/mpd.min.js +++ b/dist/htdocs/js/mpd.min.js @@ -25,28 +25,28 @@ var c=app.current.search.split("/"),e=c.length,d="";for(a=0;asearchSearching...'),2<=app.current.search.length?sendAPI({cmd:"MPD_API_SEARCH",data:{mpdtag:app.current.filter,offset:app.current.page,searchstr:app.current.search}},parseSearch):(document.getElementById("SearchList").getElementsByTagName("tbody")[0].innerHTML= "",document.getElementById("searchAddAllSongs").setAttribute("disabled","disabled"),document.getElementById("searchAddAllSongsBtn").setAttribute("disabled","disabled"),document.getElementById("panel-heading-search").innerText="",document.getElementById("SearchList").classList.remove("opacity05"),setPagination(0)),b=document.getElementById("searchtags").getElementsByTagName("button"),c=b.length,a=0;a";domCache.outputs.innerHTML=b} +function parseOutputs(a){for(var b="",c=a.data.outputs.length,e=0;e";domCache.outputs.innerHTML=b} function parseState(a){if(JSON.stringify(a)!==JSON.stringify(last_state)){1==a.data.state?(domCache.btnPlay.innerText="play_arrow",playstate="stop"):2==a.data.state?(domCache.btnPlay.innerText="pause",playstate="play"):(domCache.btnPlay.innerText="play_arrow",playstate="pause");-1==a.data.nextsongpos?domCache.btnNext.setAttribute("disabled","disabled"):domCache.btnNext.removeAttribute("disabled");0>=a.data.songpos?domCache.btnPrev.setAttribute("disabled","disabled"):domCache.btnPrev.removeAttribute("disabled"); 0==a.data.queue_length?domCache.btnPlay.setAttribute("disabled","disabled"):domCache.btnPlay.removeAttribute("disabled");-1==a.data.volume?(domCache.volumePrct.innerText="Volumecontrol disabled",domCache.volumeControl.classList.add("hide")):(domCache.volumeControl.classList.remove("hide"),domCache.volumePrct.innerText=a.data.volume+" %",domCache.volumeIcon.innerText=0==a.data.volume?"volume_off":50>a.data.volume?"volume_down":"volume_up");domCache.volumeBar.value=a.data.volume;current_song.totalTime= a.data.totalTime;current_song.currentSongId=a.data.currentsongid;var b=Math.floor(a.data.totalTime/60),c=a.data.totalTime-60*b,e=Math.floor(a.data.elapsedTime/60),d=a.data.elapsedTime-60*e;domCache.progressBar.value=Math.floor(100*a.data.elapsedTime/a.data.totalTime);b=e+":"+(10>d?"0":"")+d+" / "+b+":"+(10>c?"0":"")+c;domCache.counter.innerText=b;last_state&&(c=document.getElementById("queueTrackId"+last_state.data.currentsongid))&&(e=c.getElementsByTagName("td"),e[4].innerText=c.getAttribute("data-duration"), diff --git a/htdocs/js/mpd.js b/htdocs/js/mpd.js index 3680ea5..3d5d6b0 100644 --- a/htdocs/js/mpd.js +++ b/htdocs/js/mpd.js @@ -288,7 +288,7 @@ function appRoute() { function appInit() { getSettings(); -// sendAPI({"cmd":"MPD_API_GET_OUTPUTS"}, parseOutputnames); + sendAPI({"cmd":"MPD_API_GET_STATE"}, parseState); webSocketConnect(); @@ -306,7 +306,7 @@ function appInit() { }, false); document.getElementById('volumeIcon').parentNode.addEventListener('show.bs.dropdown', function () { - sendAPI({"cmd":"MPD_API_GET_OUTPUTS"}, parseOutputnames); + sendAPI({"cmd":"MPD_API_GET_OUTPUTS"}, parseOutputs); }); document.getElementById('modalAbout').addEventListener('shown.bs.modal', function () { @@ -668,6 +668,12 @@ function webSocketConnect() { if (app.current.app === 'Queue') getQueue(); break; + case 'update_options': + getSettings(); + break; + case 'update_outputs': + sendAPI({"cmd":"MPD_API_GET_OUTPUTS"}, parseOutputs); + break; case 'song_change': songChange(obj); break; @@ -807,7 +813,7 @@ function getSettings() { sendAPI({"cmd": "MPD_API_GET_SETTINGS"}, parseSettings); } -function parseOutputnames(obj) { +function parseOutputs(obj) { var btns = ''; var outputsLen = obj.data.outputs.length; for (var i = 0; i < outputsLen; i++) { diff --git a/src/mpd_client.c b/src/mpd_client.c index 06a61b9..51fb840 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -38,7 +38,7 @@ #include "../dist/src/frozen/frozen.h" /* forward declaration */ -static int mympd_notify_callback(struct mg_connection *c, const char *param); +void mympd_notify(struct mg_mgr *s); const char * mpd_cmd_strs[] = { MPD_CMDS(GEN_STR) @@ -88,6 +88,9 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) { case MPD_API_UNKNOWN: n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Unknown request\"}"); break; + case MPD_API_GET_STATE: + n = mympd_put_state(mpd.buf, &mpd.song_id, &mpd.next_song_id, &mpd.queue_version); + break; case MPD_API_SET_SETTINGS: json_scanf(msg.p, msg.len, "{data: { notificationWeb: %d, notificationPage: %d}}", &state.a, &state.b); char tmpfile[200]; @@ -505,60 +508,6 @@ int mympd_close_handler(struct mg_connection *c) { return 0; } -static int mympd_notify_callback(struct mg_connection *c, const char *param) { - size_t n; - if (!is_websocket(c)) - return 0; - - if (param) { - /* error message? */ - n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"%s\"}",param); - #ifdef DEBUG - fprintf(stderr, "Error in mpd_notify_callback: %s\n",param); - #endif - mg_send_websocket_frame(c, WEBSOCKET_OP_TEXT, mpd.buf, n); - return 0; - } - - if (!c->user_data) - c->user_data = calloc(1, sizeof(struct t_mpd_client_session)); - - struct t_mpd_client_session *s = (struct t_mpd_client_session *)c->user_data; - - if (mpd.conn_state != MPD_CONNECTED) { - n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"disconnected\"}"); - #ifdef DEBUG - fprintf(stdout, "Notify: disconnected\n"); - #endif - mg_send_websocket_frame(c, WEBSOCKET_OP_TEXT, mpd.buf, n); - } - else { - #ifdef DEBUG - fprintf(stdout, "Notify: %s\n",mpd.buf); - #endif - mg_send_websocket_frame(c, WEBSOCKET_OP_TEXT, mpd.buf, strlen(mpd.buf)); - - if (s->song_id != mpd.song_id) { - n = mympd_put_current_song(mpd.buf); - #ifdef DEBUG - fprintf(stdout, "Notify: %s\n",mpd.buf); - #endif - mg_send_websocket_frame(c, WEBSOCKET_OP_TEXT, mpd.buf, n); - s->song_id = mpd.song_id; - } - - if (s->queue_version != mpd.queue_version) { - n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_queue\"}"); - #ifdef DEBUG - fprintf(stdout, "Notify: update_queue\n"); - #endif - mg_send_websocket_frame(c, WEBSOCKET_OP_TEXT, mpd.buf, n); - s->queue_version = mpd.queue_version; - } - } - return 0; -} - void mympd_poll(struct mg_mgr *s, int timeout) { struct pollfd fds[1]; int pollrc; @@ -570,24 +519,24 @@ void mympd_poll(struct mg_mgr *s, int timeout) { mpd.conn = mpd_connection_new(config.mpdhost, config.mpdport, mpd.timeout); if (mpd.conn == NULL) { fprintf(stderr, "Out of memory."); + snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"disconnected\"}"); + mympd_notify(s); mpd.conn_state = MPD_FAILURE; return; } if (mpd_connection_get_error(mpd.conn) != MPD_ERROR_SUCCESS) { fprintf(stderr, "MPD connection: %s\n", mpd_connection_get_error_message(mpd.conn)); - for (struct mg_connection *c = mg_next(s, NULL); c != NULL; c = mg_next(s, c)) { - mympd_notify_callback(c, mpd_connection_get_error_message(mpd.conn)); - } + snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"%s\"}", mpd_connection_get_error_message(mpd.conn)); + mympd_notify(s); mpd.conn_state = MPD_FAILURE; return; } if (config.mpdpass && !mpd_run_password(mpd.conn, config.mpdpass)) { fprintf(stderr, "MPD connection: %s\n", mpd_connection_get_error_message(mpd.conn)); - for (struct mg_connection *c = mg_next(s, NULL); c != NULL; c = mg_next(s, c)) { - mympd_notify_callback(c, mpd_connection_get_error_message(mpd.conn)); - } + snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"%s\"}", mpd_connection_get_error_message(mpd.conn)); + mympd_notify(s); mpd.conn_state = MPD_FAILURE; return; } @@ -600,6 +549,8 @@ void mympd_poll(struct mg_mgr *s, int timeout) { case MPD_FAILURE: fprintf(stderr, "MPD connection failed.\n"); + snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"disconnected\"}"); + mympd_notify(s); case MPD_DISCONNECT: case MPD_RECONNECT: @@ -622,9 +573,22 @@ void mympd_poll(struct mg_mgr *s, int timeout) { } } +void mympd_notify(struct mg_mgr *s) { + for (struct mg_connection *c = mg_next(s, NULL); c != NULL; c = mg_next(s, c)) { + if (!is_websocket(c)) + continue; + mg_send_websocket_frame(c, WEBSOCKET_OP_TEXT, mpd.buf, strlen(mpd.buf)); + } + #ifdef DEBUG + fprintf(stderr,"NOTIFY: %s\n", mpd.buf); + #endif +} + void mympd_parse_idle(struct mg_mgr *s) { - mpd_connection_set_timeout(mpd.conn, 100); + mpd_connection_set_timeout(mpd.conn, 60); enum mpd_idle idle_bitmask = mpd_recv_idle(mpd.conn, false); + mpd_connection_set_timeout(mpd.conn, mpd.timeout); + int len; for (unsigned j = 0;; ++j) { enum mpd_idle idle_event = 1 << j; @@ -637,39 +601,42 @@ void mympd_parse_idle(struct mg_mgr *s) { #endif switch(idle_event) { case MPD_IDLE_DATABASE: + len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_database\"}"); break; case MPD_IDLE_STORED_PLAYLIST: + len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_stored_playlist\"}"); break; case MPD_IDLE_QUEUE: + len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_queue\"}"); break; case MPD_IDLE_PLAYER: - break; case MPD_IDLE_MIXER: + len = mympd_put_state(mpd.buf, &mpd.song_id, &mpd.next_song_id, &mpd.queue_version); break; case MPD_IDLE_OUTPUT: + len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_outputs\"}"); break; case MPD_IDLE_OPTIONS: + len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_options\"}"); break; case MPD_IDLE_UPDATE: + len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_update\"}"); break; case MPD_IDLE_STICKER: + len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_sticker\"}"); break; case MPD_IDLE_SUBSCRIPTION: + len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_subscription\"}"); break; case MPD_IDLE_MESSAGE: + len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_message\"}"); break; } + if (len > 0) + mympd_notify(s); } } - -//old behaviour - if (idle_bitmask > 0) { - mpd_connection_set_timeout(mpd.conn, mpd.timeout); - mpd.buf_size = mympd_put_state(mpd.buf, &mpd.song_id, &mpd.next_song_id, &mpd.queue_version); - for (struct mg_connection *c = mg_next(s, NULL); c != NULL; c = mg_next(s, c)) - mympd_notify_callback(c, NULL); - } } char* mympd_get_tag(struct mpd_song const *song, enum mpd_tag_type tag) { @@ -684,7 +651,7 @@ char* mympd_get_tag(struct mpd_song const *song, enum mpd_tag_type tag) { return str; } -int mympd_put_state(char *buffer, int *current_song_id, int *next_song_id, unsigned *queue_version) { +int mympd_put_state(char *buffer, int *current_song_id, int *next_song_id, unsigned *queue_version) { struct mpd_status *status; const struct mpd_audio_format *audioformat; int len; @@ -697,7 +664,7 @@ int mympd_put_state(char *buffer, int *current_song_id, int *next_song_id, unsi return 0; } if (status) { - audioformat = mpd_status_get_audio_format(status); + audioformat = mpd_status_get_audio_format(status); } len = json_printf(&out,"{type:state, data:{" diff --git a/src/mpd_client.h b/src/mpd_client.h index c00343d..1d0f381 100644 --- a/src/mpd_client.h +++ b/src/mpd_client.h @@ -92,6 +92,7 @@ X(MPD_API_WELCOME) \ X(MPD_API_GET_SETTINGS) \ X(MPD_API_SET_SETTINGS) \ + X(MPD_API_GET_STATE) \ X(MPD_API_UNKNOWN) enum mpd_cmd_ids { @@ -141,12 +142,6 @@ static int is_websocket(const struct mg_connection *nc) { return nc->flags & MG_F_IS_WEBSOCKET; } -struct t_mpd_client_session { - int song_id; - int next_song_id; - unsigned queue_version; -}; - void mympd_poll(struct mg_mgr *sm, int timeout); void mympd_parse_idle(struct mg_mgr *s); void callback_mympd(struct mg_connection *nc, const struct mg_str msg); diff --git a/src/mympd.c b/src/mympd.c index 0f3a6e5..0febbec 100644 --- a/src/mympd.c +++ b/src/mympd.c @@ -256,8 +256,8 @@ int main(int argc, char **argv) { printf("myMPD started on ssl port %s\n", config.sslport); while (s_signal_received == 0) { - mympd_poll(&mgr, 100); - mg_mgr_poll(&mgr, 100); + mympd_poll(&mgr, 60); + mg_mgr_poll(&mgr, 60); } mg_mgr_free(&mgr); mympd_disconnect();