From 87872f05548a5ce1b31c1cf03e09619e02af5709 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Mon, 1 Oct 2018 22:50:40 +0100 Subject: [PATCH 01/20] Feat: add more keyboard shortcuts #58 --- htdocs/js/mympd.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/htdocs/js/mympd.js b/htdocs/js/mympd.js index d0c4d1e..40a1a0d 100644 --- a/htdocs/js/mympd.js +++ b/htdocs/js/mympd.js @@ -567,7 +567,7 @@ function appInit() { }, false); document.addEventListener('keydown', function(event) { - if (event.target.tagName == 'INPUT') + if (event.target.tagName == 'INPUT' || event.target.tagName == 'SELECT') return; switch (event.which) { case 37: //left @@ -579,6 +579,21 @@ function appInit() { case 32: //space clickPlay(); break; + case 83: //s + clickStop(); + break; + case 173: //- + chVolume(-5); + break; + case 171: //+ + chVolume(5); + break; + case 67: //C c + if (event.shiftKey) + sendAPI({"cmd": "MPD_API_QUEUE_CROP"}); + else + sendAPI({"cmd": "MPD_API_QUEUE_CLEAR"}); + break; default: return; } From 7a6d000e583d1f76fc39402024509b2821de4278 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Mon, 1 Oct 2018 23:02:49 +0100 Subject: [PATCH 02/20] Fix: differentiate between lower and upper case keyboard shortcuts --- htdocs/js/mympd.js | 61 +++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/htdocs/js/mympd.js b/htdocs/js/mympd.js index 40a1a0d..15a8ae0 100644 --- a/htdocs/js/mympd.js +++ b/htdocs/js/mympd.js @@ -569,33 +569,44 @@ function appInit() { document.addEventListener('keydown', function(event) { if (event.target.tagName == 'INPUT' || event.target.tagName == 'SELECT') return; - switch (event.which) { - case 37: //left - clickPrev(); - break; - case 39: //right - clickNext(); - break; - case 32: //space - clickPlay(); - break; - case 83: //s - clickStop(); - break; - case 173: //- - chVolume(-5); - break; - case 171: //+ - chVolume(5); - break; - case 67: //C c - if (event.shiftKey) + if (event.shiftKey) { + switch (event.which) { + case 83: //S + sendAPI({"cmd": "MPD_API_QUEUE_SHUFFLE"}); + break; + case 67: //C sendAPI({"cmd": "MPD_API_QUEUE_CROP"}); - else + break; + default: + return; + } + } + else { + switch (event.which) { + case 37: //left + clickPrev(); + break; + case 39: //right + clickNext(); + break; + case 32: //space + clickPlay(); + break; + case 83: //s + clickStop(); + break; + case 173: //- + chVolume(-5); + break; + case 171: //+ + chVolume(5); + break; + case 67: //c sendAPI({"cmd": "MPD_API_QUEUE_CLEAR"}); - break; - default: - return; + break; + default: + return; + } } event.preventDefault(); }, false); From 12778fea53b4abae066852b4a255f500d9d62418 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Mon, 1 Oct 2018 23:14:15 +0100 Subject: [PATCH 03/20] Fix: bump version to 4.3.1 --- CMakeLists.txt | 2 +- PKGBUILD | 4 ++-- contrib/myMPD.spec | 4 ++-- debian/changelog | 4 ++-- htdocs/sw.js | 2 +- mkdebian.sh | 13 ++++++++++++- 6 files changed, 20 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e4cf57b..b52f79a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project (mympd C) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/") set(CPACK_PACKAGE_VERSION_MAJOR "4") set(CPACK_PACKAGE_VERSION_MINOR "3") -set(CPACK_PACKAGE_VERSION_PATCH "0") +set(CPACK_PACKAGE_VERSION_PATCH "1") if(CMAKE_BUILD_TYPE MATCHES RELEASE) set(ASSETS_PATH "/usr/share/${PROJECT_NAME}/htdocs") diff --git a/PKGBUILD b/PKGBUILD index 3f3dda8..c44ce9b 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -4,9 +4,9 @@ pkgname=mympd _pkgname=myMPD -pkgver=4.3.0 +pkgver=4.3.1 pkgrel=1 -pkgdesc="A standalone MPD Web GUI based on YMPD - Default port set to 80" +pkgdesc="myMPD is a standalone and mobile friendly web mpdclient." arch=('x86_64' 'armv7h' 'aarch64') url="http://github.org/jcorporation/myMPD" license=('GPL') diff --git a/contrib/myMPD.spec b/contrib/myMPD.spec index c584db3..2675239 100644 --- a/contrib/myMPD.spec +++ b/contrib/myMPD.spec @@ -4,13 +4,13 @@ # (c) 2018 Juergen Mang Name: myMPD -Version: 4.3.0 +Version: 4.3.1 Release: 0 License: GPL-2.0 Group: Productivity/Multimedia/Sound/Players Summary: Standalone webclient for mpd Url: https://github.com/jcorporation/myMPD -Source: https://github.com/jcorporation/myMPD/archive/v4.3.0.zip +Source: https://github.com/jcorporation/myMPD/archive/v%{version}.zip BuildRequires: gcc BuildRequires: cmake BuildRequires: unzip diff --git a/debian/changelog b/debian/changelog index a878d06..ff9f313 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,5 @@ -mympd (4.3.0-1) stable; urgency=medium +mympd (4.3.1-1) stable; urgency=medium * Release from master - -- Juergen Mang Tue, 25 Sep 2018 00:35:00 +0200 + -- Juergen Mang Mon, 02 Oct 2018 00:04:00 +0200 diff --git a/htdocs/sw.js b/htdocs/sw.js index a096159..471406c 100644 --- a/htdocs/sw.js +++ b/htdocs/sw.js @@ -1,4 +1,4 @@ -var CACHE = 'myMPD-cache-v4.3.0'; +var CACHE = 'myMPD-cache-v4.3.1'; var urlsToCache = [ '/', '/player.html', diff --git a/mkdebian.sh b/mkdebian.sh index 1d5cc33..993bd9a 100755 --- a/mkdebian.sh +++ b/mkdebian.sh @@ -1,4 +1,15 @@ #!/bin/bash + +VERSION=$(grep VERSION_ CMakeLists.txt | cut -d\" -f2 | tr '\n' '.') + +cat > debian/changelog << EOL +mympd (${VERSION}-1) stable; urgency=medium + + * Release from master + + -- Juergen Mang Mon, 02 Oct 2018 00:04:00 +0200 +EOL + ./mkclean.sh -tar -czvf ../mympd_4.3.0.orig.tar.gz * +tar -czvf ../mympd_${VERSION}.orig.tar.gz * dpkg-buildpackage -rfakeroot From f5490b49a47e3999d08c1a1300e06e83540c5cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Mang?= Date: Tue, 2 Oct 2018 16:49:45 +0200 Subject: [PATCH 04/20] Update mympd.1 --- contrib/mympd.1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contrib/mympd.1 b/contrib/mympd.1 index c304adb..1bc502d 100644 --- a/contrib/mympd.1 +++ b/contrib/mympd.1 @@ -1,18 +1,18 @@ .\" Manpage for myMPD. .\" Contact mail@jcgames.de to correct errors or typos. -.TH man 1 "22 Aug 2018" "4.0.0" "myMPD man page" +.TH man 1 "02 Oct 2018" "4.3.1" "myMPD man page" .SH NAME -myMPD \- Standalone MPD Web GUI written in C, utilizing Websockets and Bootstrap/JS +myMPD \- myMPD is a standalone and mobile friendly web mpdclient .SH SYNOPSIS mympd /path/to/mympd.conf .SH DESCRIPTION -myMPD is a lightweight MPD web client that runs without a dedicated webserver or interpreter. -It's tuned for minimal resource usage and requires only very litte dependencies. -myMPD is a fork of ympd. +myMPD is a lightweight MPD web client that runs without a dedicated webserver or interpreter. It's tuned for minimal resource usage and requires only very litte dependencies. +myMPD is a fork of ympd (https://github.com/notandy/ympd). +This fork provides a reworked ui based on Bootstrap 4, a modernized backend and many new features while having the same small footprint as ympd. .SH BUGS No known bugs. .SH AUTHOR Juergen Mang (mail@jcgames.de) -https://github.com/jcorporation/mympd \ No newline at end of file +https://github.com/jcorporation/mympd From cd334d2f411577a1e4f8dfd5f3853401f91cad93 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Wed, 3 Oct 2018 23:24:14 +0100 Subject: [PATCH 05/20] Fix: jukebox mode now using the classic one-pass algorithm described in Knuth --- src/mpd_client.c | 219 +++++++++++++++++++++++++++-------------------- src/mpd_client.h | 7 ++ 2 files changed, 135 insertions(+), 91 deletions(-) diff --git a/src/mpd_client.c b/src/mpd_client.c index 3c1c450..36afd96 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -1008,11 +1008,12 @@ char* mympd_get_tag(struct mpd_song const *song, enum mpd_tag_type tag) { void mympd_jukebox() { struct mpd_status *status; status = mpd_run_status(mpd.conn); - int queue_length, num_songs, rand_song, i, j, addSongs; + int queue_length, addSongs, i; struct mpd_entity *entity; const struct mpd_song *song; struct mpd_pair *pair; - char *album; + int lineno = 1; + int nkeep = 0; if (!status) { LOG_ERROR_AND_RECOVER("mpd_run_status"); @@ -1022,30 +1023,73 @@ void mympd_jukebox() { mpd_status_free(status); if (queue_length > mympd_state.jukeboxQueueLength) return; - - srand((unsigned int)time(NULL)); - num_songs = 0; - if (mympd_state.jukeboxMode == 1 && strcmp(mympd_state.jukeboxPlaylist, "Database") == 0) { - struct mpd_stats *stats = mpd_run_stats(mpd.conn); - if (stats == NULL) { - LOG_ERROR_AND_RECOVER("mpd_run_stats"); - return; - } - num_songs = mpd_stats_get_number_of_songs(stats); - mpd_stats_free(stats); + if (mympd_state.jukeboxMode == 1) + addSongs = mympd_state.jukeboxQueueLength - queue_length; + else + addSongs = 1; + + if (addSongs < 1) + return; + + srand((unsigned int)time(NULL)); + struct aline *keepentries; + keepentries = malloc(addSongs * sizeof(*keepentries)); + if (keepentries == NULL) { + printf("Can't allocate space for %d lines\n", addSongs); + exit(1); } - else if (mympd_state.jukeboxMode == 1) { - if (!mpd_send_list_playlist(mpd.conn, mympd_state.jukeboxPlaylist)) { - LOG_ERROR_AND_RECOVER("mpd_send_list_playlist"); - return; + for (i = 0; i < addSongs; i++) { + keepentries[i].nalloc = 0; + keepentries[i].ptr = NULL; + } + + if (mympd_state.jukeboxMode == 1) { + //add songs + if (strcmp(mympd_state.jukeboxPlaylist, "Database") == 0) { + if (!mpd_send_list_all(mpd.conn, "/")) { + LOG_ERROR_AND_RECOVER("mpd_send_list_playlist"); + return; + } + } + else { + if (!mpd_send_list_playlist(mpd.conn, mympd_state.jukeboxPlaylist)) { + LOG_ERROR_AND_RECOVER("mpd_send_list_playlist"); + return; + } } while ((entity = mpd_recv_entity(mpd.conn)) != NULL) { - num_songs++; + if (randrange(lineno) < addSongs) { + if (nkeep < addSongs) { + song = mpd_entity_get_song(entity); + save_entry(&keepentries[nkeep++], mpd_song_get_uri(song)); + } + else { + i = 0; + if (addSongs > 1) + i = randrange(addSongs); + if (addSongs == 1) { + song = mpd_entity_get_song(entity); + save_entry(&keepentries[i], mpd_song_get_uri(song)); + } + else { + int nm = addSongs - i - 1; + if (nm > 0) { + struct aline tmp = keepentries[i]; + memmove(&keepentries[i], &keepentries[i+1], nm * sizeof(*keepentries)); + keepentries[addSongs - 1] = tmp; + } + song = mpd_entity_get_song(entity); + save_entry(&keepentries[nkeep - 1], mpd_song_get_uri(song)); + } + } + } + lineno++; mpd_entity_free(entity); - } + } } else if (mympd_state.jukeboxMode == 2) { + //add album if (!mpd_search_db_tags(mpd.conn, MPD_TAG_ALBUM)) { LOG_ERROR_AND_RECOVER("mpd_send_list_playlist"); return; @@ -1054,84 +1098,77 @@ void mympd_jukebox() { LOG_ERROR_AND_RECOVER("mpd_send_list_playlist"); return; } - while ((pair = mpd_recv_pair_tag(mpd.conn, MPD_TAG_ALBUM)) != NULL) { - num_songs++; + while ((pair = mpd_recv_pair_tag(mpd.conn, MPD_TAG_ALBUM )) != NULL) { + if (randrange(lineno) < addSongs) { + if (nkeep < addSongs) { + save_entry(&keepentries[nkeep++], strdup(pair->value)); + } + else { + i = 0; + if (addSongs > 1) + i = randrange(addSongs); + if (addSongs == 1) { + save_entry(&keepentries[i], strdup(pair->value)); + } + else { + int nm = addSongs - i - 1; + if (nm > 0) { + struct aline tmp = keepentries[i]; + memmove(&keepentries[i], &keepentries[i+1], nm * sizeof(*keepentries)); + keepentries[addSongs - 1] = tmp; + } + save_entry(&keepentries[nkeep - 1], strdup(pair->value)); + } + } + } + lineno++; mpd_return_pair(mpd.conn, pair); } - mpd_response_finish(mpd.conn); } - num_songs--; - if (mympd_state.jukeboxMode == 1) - addSongs = mympd_state.jukeboxQueueLength - queue_length; - else - addSongs = 1; - if (num_songs > 0) { - for (j = 0; j < addSongs; j++) { - rand_song = rand() % num_songs; - if (mympd_state.jukeboxMode == 1) { - //add songs - if (strcmp(mympd_state.jukeboxPlaylist, "Database") == 0) { - if (!mpd_send_list_all(mpd.conn, "/")) { - LOG_ERROR_AND_RECOVER("mpd_send_list_playlist"); - return; - } - } - else { - if (!mpd_send_list_playlist(mpd.conn, mympd_state.jukeboxPlaylist)) { - LOG_ERROR_AND_RECOVER("mpd_send_list_playlist"); - return; - } - } - i = 0; - while ((entity = mpd_recv_entity(mpd.conn)) != NULL) { - if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) { - if (i == rand_song) - break; - i++; - } - mpd_entity_free(entity); - } - mpd_response_finish(mpd.conn); - song = mpd_entity_get_song(entity); - if (song != NULL) { - printf("Jukebox enabled, adding random song: %d/%d\n", rand_song, num_songs); - if (!mpd_run_add(mpd.conn, mpd_song_get_uri(song))) { - LOG_ERROR_AND_RECOVER("mpd_send_list_playlist"); - } - } - mpd_entity_free(entity); - } - else if (mympd_state.jukeboxMode == 2) { - //add album - if (!mpd_search_db_tags(mpd.conn, MPD_TAG_ALBUM)) { - LOG_ERROR_AND_RECOVER("mpd_send_list_playlist"); - return; - } - if (!mpd_search_commit(mpd.conn)) { - LOG_ERROR_AND_RECOVER("mpd_send_list_playlist"); - return; - } - i = 0; - while ((pair = mpd_recv_pair_tag(mpd.conn, MPD_TAG_ALBUM )) != NULL) { - if (i == rand_song) { - album = strdup(pair->value); - break; - } - i++; - mpd_return_pair(mpd.conn, pair); - } - mpd_return_pair(mpd.conn, pair); - mpd_response_finish(mpd.conn); - printf("Jukebox enabled, adding random album %s: %d/%d\n", album, rand_song, num_songs); - if (!mpd_send_command(mpd.conn, "searchadd", "Album", album, NULL)) { - LOG_ERROR_AND_RECOVER("mpd_send_list_playlist"); - return; - } - mpd_response_finish(mpd.conn); + if (nkeep < addSongs) { + fprintf(stderr, "Warning: input didn't contain %d lines\n", addSongs); + return; + } + for (i = 0; i < nkeep; i++) { + if (mympd_state.jukeboxMode == 1) { + printf("Jukebox adding song: %s\n", keepentries[i].ptr); + if (!mpd_run_add(mpd.conn, keepentries[i].ptr)) { + LOG_ERROR_AND_RECOVER("mpd_run_add"); } } - mpd_run_play(mpd.conn); + else { + printf("Jukebox adding album: %s\n", keepentries[i].ptr); + if (!mpd_send_command(mpd.conn, "searchadd", "Album", keepentries[i].ptr, NULL)) { + LOG_ERROR_AND_RECOVER("mpd_send_command"); + return; + } + mpd_response_finish(mpd.conn); + } + } + free(keepentries); + mpd_run_play(mpd.conn); +} + +int randrange(int n) { + return rand() / (RAND_MAX / (n + 1)); +} + +void save_entry(struct aline *alp, const char *entry) { + int need = strlen(entry) + 1; + if (need > alp->nalloc) { + alp->nalloc = need; + if (alp->nalloc < 80) /* arbitrary threshold */ + alp->nalloc = 80; + if (alp->ptr == NULL) + alp->ptr = malloc(alp->nalloc); + else + alp->ptr = realloc(alp->ptr, alp->nalloc); + if (alp->ptr == NULL) { + fprintf(stderr, "Can't (re)allocate space for saved entry\n"); + exit(1); + } } + strcpy(alp->ptr, entry); } int mympd_put_state(char *buffer, int *current_song_id, int *next_song_id, int *last_song_id, unsigned *queue_version, unsigned *queue_length) { diff --git a/src/mpd_client.h b/src/mpd_client.h index 5378098..c1ee153 100644 --- a/src/mpd_client.h +++ b/src/mpd_client.h @@ -186,10 +186,17 @@ typedef struct { t_mympd_state mympd_state; +struct aline { + char *ptr; + int nalloc; +}; + static int is_websocket(const struct mg_connection *nc) { return nc->flags & MG_F_IS_WEBSOCKET; } +int randrange(int n); +void save_entry(struct aline *alp, const char *entry); void mympd_idle(struct mg_mgr *sm, int timeout); void mympd_parse_idle(struct mg_mgr *s, int idle_bitmask); void callback_mympd(struct mg_connection *nc, const struct mg_str msg); From cac4e8bfd5a3cc1948cef4f112506339a9adf759 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Sun, 7 Oct 2018 22:21:00 +0100 Subject: [PATCH 06/20] Fix: move dynamic linked list management in separate src files Fix: write state files on startup --- CMakeLists.txt | 1 + src/list.c | 37 ++++++++++++++ src/list.h | 15 ++++++ src/mpd_client.c | 124 +++++++++++++++++++---------------------------- src/mpd_client.h | 6 --- src/mympd.c | 25 +++++++--- 6 files changed, 121 insertions(+), 87 deletions(-) create mode 100644 src/list.c create mode 100644 src/list.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b52f79a..4d422b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS NS_ENABLE_SSL) set(SOURCES src/mympd.c src/mpd_client.c + src/list.c dist/src/mongoose/mongoose.c dist/src/frozen/frozen.c dist/src/inih/ini.c diff --git a/src/list.c b/src/list.c new file mode 100644 index 0000000..c39a8d1 --- /dev/null +++ b/src/list.c @@ -0,0 +1,37 @@ +#include +#include +#include "list.h" + +int list_init(struct list *list) { + list->length = 0; + list->list = NULL; + return 0; +} + +int list_push(struct list *l, char *data, int value) { + struct node *n = malloc(sizeof(struct node)); + n->value = value; + n->data = malloc(strlen(data)); + n->data = strdup(data); + n->next = NULL; + + struct node **next = &l->list; + while (*next != NULL) { + next = &(*next)->next; + } + *next = n; + l->length++; + return 0; +} + +int list_free(struct list *l) { + struct node * current = l->list, *tmp = NULL; + while (current != NULL) { + free(current->data); + tmp = current; + current = current->next; + free(tmp); + } + list_init(l); + return 0; +} diff --git a/src/list.h b/src/list.h new file mode 100644 index 0000000..dc507b1 --- /dev/null +++ b/src/list.h @@ -0,0 +1,15 @@ +struct node { + char *data; + int value; + struct node *next; +}; + +struct list { + unsigned length; + struct node *list; +}; + + +int list_init(struct list *); +int list_push(struct list *l, char *data, int value); +int list_free(struct list *l); diff --git a/src/mpd_client.c b/src/mpd_client.c index 36afd96..e783a0f 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -33,6 +33,7 @@ #include #include "mpd_client.h" +#include "list.h" #include "config.h" #include "../dist/src/frozen/frozen.h" @@ -1033,58 +1034,51 @@ void mympd_jukebox() { return; srand((unsigned int)time(NULL)); - struct aline *keepentries; - keepentries = malloc(addSongs * sizeof(*keepentries)); - if (keepentries == NULL) { - printf("Can't allocate space for %d lines\n", addSongs); - exit(1); - } - for (i = 0; i < addSongs; i++) { - keepentries[i].nalloc = 0; - keepentries[i].ptr = NULL; - } + + struct list add_list; + list_init(&add_list); if (mympd_state.jukeboxMode == 1) { //add songs if (strcmp(mympd_state.jukeboxPlaylist, "Database") == 0) { if (!mpd_send_list_all(mpd.conn, "/")) { LOG_ERROR_AND_RECOVER("mpd_send_list_playlist"); + list_free(&add_list); return; } } else { if (!mpd_send_list_playlist(mpd.conn, mympd_state.jukeboxPlaylist)) { LOG_ERROR_AND_RECOVER("mpd_send_list_playlist"); + list_free(&add_list); return; } } while ((entity = mpd_recv_entity(mpd.conn)) != NULL) { - if (randrange(lineno) < addSongs) { - if (nkeep < addSongs) { - song = mpd_entity_get_song(entity); - save_entry(&keepentries[nkeep++], mpd_song_get_uri(song)); - } - else { - i = 0; - if (addSongs > 1) - i = randrange(addSongs); - if (addSongs == 1) { - song = mpd_entity_get_song(entity); - save_entry(&keepentries[i], mpd_song_get_uri(song)); + if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) { + if (randrange(lineno) < addSongs) { + if (nkeep < addSongs) { + song = mpd_entity_get_song(entity); + list_push(&add_list, mpd_song_get_uri(song), lineno); + nkeep++; } else { - int nm = addSongs - i - 1; - if (nm > 0) { - struct aline tmp = keepentries[i]; - memmove(&keepentries[i], &keepentries[i+1], nm * sizeof(*keepentries)); - keepentries[addSongs - 1] = tmp; - } - song = mpd_entity_get_song(entity); - save_entry(&keepentries[nkeep - 1], mpd_song_get_uri(song)); + i = 0; + if (addSongs > 1) + i = randrange(addSongs); + if (addSongs == 1) { + song = mpd_entity_get_song(entity); + list_free(&add_list); + list_push(&add_list, mpd_song_get_uri(song), lineno); + } + else { + song = mpd_entity_get_song(entity); + list_push(&add_list, mpd_song_get_uri(song), lineno); + } } } + lineno++; } - lineno++; mpd_entity_free(entity); } } @@ -1092,32 +1086,30 @@ void mympd_jukebox() { //add album if (!mpd_search_db_tags(mpd.conn, MPD_TAG_ALBUM)) { LOG_ERROR_AND_RECOVER("mpd_send_list_playlist"); + list_free(&add_list); return; } if (!mpd_search_commit(mpd.conn)) { LOG_ERROR_AND_RECOVER("mpd_send_list_playlist"); + list_free(&add_list); return; } while ((pair = mpd_recv_pair_tag(mpd.conn, MPD_TAG_ALBUM )) != NULL) { if (randrange(lineno) < addSongs) { if (nkeep < addSongs) { - save_entry(&keepentries[nkeep++], strdup(pair->value)); + list_push(&add_list, strdup(pair->value), lineno); + nkeep++; } else { i = 0; if (addSongs > 1) i = randrange(addSongs); if (addSongs == 1) { - save_entry(&keepentries[i], strdup(pair->value)); + list_free(&add_list); + list_push(&add_list, strdup(pair->value), lineno); } else { - int nm = addSongs - i - 1; - if (nm > 0) { - struct aline tmp = keepentries[i]; - memmove(&keepentries[i], &keepentries[i+1], nm * sizeof(*keepentries)); - keepentries[addSongs - 1] = tmp; - } - save_entry(&keepentries[nkeep - 1], strdup(pair->value)); + list_push(&add_list, strdup(pair->value), lineno); } } } @@ -1126,26 +1118,30 @@ void mympd_jukebox() { } } if (nkeep < addSongs) { - fprintf(stderr, "Warning: input didn't contain %d lines\n", addSongs); - return; + fprintf(stderr, "Warning: input didn't contain %d entries\n", addSongs); } - for (i = 0; i < nkeep; i++) { + + struct node *current = add_list.list; + while (1) { if (mympd_state.jukeboxMode == 1) { - printf("Jukebox adding song: %s\n", keepentries[i].ptr); - if (!mpd_run_add(mpd.conn, keepentries[i].ptr)) { + printf("Jukebox adding song: %s\n", current->data); + if (!mpd_run_add(mpd.conn, current->data)) { LOG_ERROR_AND_RECOVER("mpd_run_add"); } } else { - printf("Jukebox adding album: %s\n", keepentries[i].ptr); - if (!mpd_send_command(mpd.conn, "searchadd", "Album", keepentries[i].ptr, NULL)) { + printf("Jukebox adding album: %s\n", current->data); + if (!mpd_send_command(mpd.conn, "searchadd", "Album", current->data, NULL)) { LOG_ERROR_AND_RECOVER("mpd_send_command"); return; } mpd_response_finish(mpd.conn); } - } - free(keepentries); + if (current->next == NULL) + break; + current = current->next; + } + list_free(&add_list); mpd_run_play(mpd.conn); } @@ -1153,24 +1149,6 @@ int randrange(int n) { return rand() / (RAND_MAX / (n + 1)); } -void save_entry(struct aline *alp, const char *entry) { - int need = strlen(entry) + 1; - if (need > alp->nalloc) { - alp->nalloc = need; - if (alp->nalloc < 80) /* arbitrary threshold */ - alp->nalloc = 80; - if (alp->ptr == NULL) - alp->ptr = malloc(alp->nalloc); - else - alp->ptr = realloc(alp->ptr, alp->nalloc); - if (alp->ptr == NULL) { - fprintf(stderr, "Can't (re)allocate space for saved entry\n"); - exit(1); - } - } - strcpy(alp->ptr, entry); -} - int mympd_put_state(char *buffer, int *current_song_id, int *next_song_id, int *last_song_id, unsigned *queue_version, unsigned *queue_length) { struct mpd_status *status; const struct mpd_audio_format *audioformat; @@ -1244,7 +1222,7 @@ bool mympd_state_get(char *name, char *value) { snprintf(cfgfile, 400, "%s/state/%s", config.varlibdir, name); FILE *fp = fopen(cfgfile, "r"); if (fp == NULL) { - printf("Error opening %s", cfgfile); + printf("Error opening %s\n", cfgfile); return false; } read = getline(&line, &n, fp); @@ -1267,7 +1245,7 @@ bool mympd_state_set(char *name, char *value) { FILE *fp = fopen(tmpfile, "w"); if (fp == NULL) { - printf("Error opening %s", tmpfile); + printf("Error opening %s\n", tmpfile); return false; } fprintf(fp, value); @@ -2291,7 +2269,7 @@ int mympd_smartpls_update(char *playlist, char *sticker, int maxentries) { snprintf(tmpfile, 400, "%s/tmp/playlist.tmp", config.varlibdir); FILE *fp = fopen(tmpfile, "w"); if (fp == NULL) { - printf("Error opening %s", tmpfile); + printf("Error opening %s\n", tmpfile); return 1; } while ((pair = mpd_recv_pair(mpd.conn)) != NULL) { @@ -2318,7 +2296,7 @@ int mympd_smartpls_update(char *playlist, char *sticker, int maxentries) { value_max = value_max / 2; fp = fopen(tmpfile, "r"); if (fp == NULL) { - printf("Error opening %s", tmpfile); + printf("Error opening %s\n", tmpfile); return 1; } while ((read = getline(&uri, &len, fp)) != -1) { @@ -2365,7 +2343,7 @@ int mympd_smartpls_update_newest(char *playlist, int timerange, int maxentries) snprintf(tmpfile, 400, "%s/tmp/playlist.tmp", config.varlibdir); FILE *fp = fopen(tmpfile, "w"); if (fp == NULL) { - printf("Error opening %s", tmpfile); + printf("Error opening %s\n", tmpfile); return 1; } while ((song = mpd_recv_song(mpd.conn)) != NULL) { @@ -2384,7 +2362,7 @@ int mympd_smartpls_update_newest(char *playlist, int timerange, int maxentries) fp = fopen(tmpfile, "r"); if (fp == NULL) { - printf("Error opening %s", tmpfile); + printf("Error opening %s\n", tmpfile); return 1; } while ((read = getline(&uri, &len, fp)) != -1) { diff --git a/src/mpd_client.h b/src/mpd_client.h index c1ee153..6bba011 100644 --- a/src/mpd_client.h +++ b/src/mpd_client.h @@ -186,17 +186,11 @@ typedef struct { t_mympd_state mympd_state; -struct aline { - char *ptr; - int nalloc; -}; - static int is_websocket(const struct mg_connection *nc) { return nc->flags & MG_F_IS_WEBSOCKET; } int randrange(int n); -void save_entry(struct aline *alp, const char *entry); void mympd_idle(struct mg_mgr *sm, int timeout); void mympd_parse_idle(struct mg_mgr *s, int idle_bitmask); void callback_mympd(struct mg_connection *nc, const struct mg_str msg); diff --git a/src/mympd.c b/src/mympd.c index 6048d90..998cbae 100644 --- a/src/mympd.c +++ b/src/mympd.c @@ -189,8 +189,10 @@ void read_statefiles() { else mympd_state.notificationWeb = false; } - else + else { mympd_state.notificationWeb = false; + mympd_state_set("notificationWeb", "false"); + } if (mympd_state_get("notificationPage", value)) { if (strcmp(value, "true") == 0) @@ -198,24 +200,31 @@ void read_statefiles() { else mympd_state.notificationPage = false; } - else + else { mympd_state.notificationPage = true; - + mympd_state_set("notificationPage", "true"); + } if (mympd_state_get("jukeboxMode", value)) mympd_state.jukeboxMode = strtol(value, &crap, 10); - else + else { mympd_state.jukeboxMode = 0; + mympd_state_set("jukeboxMode", "0"); + } if (mympd_state_get("jukeboxPlaylist", value)) mympd_state.jukeboxPlaylist = strdup(value); - else + else { mympd_state.jukeboxPlaylist = "Database"; + mympd_state_set("jukeboxPlaylist", "Database"); + } if (mympd_state_get("jukeboxQueueLength", value)) mympd_state.jukeboxQueueLength = strtol(value, &crap, 10); - else + else { mympd_state.jukeboxQueueLength = 1; + mympd_state_set("jukeboxQueueLength", "1"); + } } int main(int argc, char **argv) { @@ -278,8 +287,6 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } - read_statefiles(); - signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); setvbuf(stdout, NULL, _IOLBF, 0); @@ -341,6 +348,8 @@ int main(int argc, char **argv) { mg_mgr_free(&mgr); return EXIT_FAILURE; } + + read_statefiles(); if (config.ssl == true) mg_set_protocol_http_websocket(nc_http); From 9d1236e92aada209e5afb089c77899d229f57cfa Mon Sep 17 00:00:00 2001 From: jcorporation Date: Sun, 7 Oct 2018 22:34:54 +0100 Subject: [PATCH 07/20] Fix: install state files #64 --- contrib/archlinux.install | 15 +++++++++++---- contrib/myMPD.spec | 13 ++++++++++--- debian/postinst | 14 +++++++++++--- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/contrib/archlinux.install b/contrib/archlinux.install index 23d360b..cc8ed86 100644 --- a/contrib/archlinux.install +++ b/contrib/archlinux.install @@ -10,10 +10,6 @@ post_upgrade() { getent passwd mympd > /dev/null [ "$?" = "2" ] && useradd --system -d /var/lib/mympd -s /usr/sbin/nologin -g mympd mympd - # fix ownership of /var/lib/mympd - echo "INFO: Fixing ownership of /var/lib/mympd" - chown -R mympd.mympd /var/lib/mympd - # link music directory to mympd if not already exising echo "INFO: Trying to link musicdir to library" if [ -f /etc/mpd.conf ] @@ -64,6 +60,17 @@ post_upgrade() { fi done + #default state files + [ -f /var/lib/mympd/state/jukeboxMode ] || echo -n "0" > /var/lib/mympd/state/jukeboxMode + [ -f /var/lib/mympd/state/jukeboxPlaylist ] || echo -n "Database" > /var/lib/mympd/state/jukeboxPlaylist + [ -f /var/lib/mympd/state/jukeboxQueueLength ] || echo -n "1" > /var/lib/mympd/state/jukeboxQueueLength + [ -f /var/lib/mympd/state/notificationPage ] || echo -n "true" > /var/lib/mympd/state/notificationPage + [ -f /var/lib/mympd/state/notificationWeb ] || echo -n "false" > /var/lib/mympd/state/notificationWeb + + # fix ownership of /var/lib/mympd + echo "INFO: Fixing ownership of /var/lib/mympd" + chown -R mympd.mympd /var/lib/mympd + # move config into place unless already existing if [ ! -f /etc/mympd/mympd.conf ] then diff --git a/contrib/myMPD.spec b/contrib/myMPD.spec index 2675239..3661ec3 100644 --- a/contrib/myMPD.spec +++ b/contrib/myMPD.spec @@ -44,9 +44,6 @@ getent group mympd > /dev/null getent passwd mympd > /dev/null [ "$?" = "2" ] && useradd -r mympd -g mympd -d /var/lib/mympd -s /usr/sbin/nologin -echo "Fixing ownership of /var/lib/mympd" -chown -R mympd.mympd /var/lib/mympd - if [ -d /etc/systemd ] then [ -d /usr/lib/systemd/system ] || mkdir -p /usr/lib/systemd/system @@ -78,6 +75,16 @@ do fi done +#default state files +[ -f /var/lib/mympd/state/jukeboxMode ] || echo -n "0" > /var/lib/mympd/state/jukeboxMode +[ -f /var/lib/mympd/state/jukeboxPlaylist ] || echo -n "Database" > /var/lib/mympd/state/jukeboxPlaylist +[ -f /var/lib/mympd/state/jukeboxQueueLength ] || echo -n "1" > /var/lib/mympd/state/jukeboxQueueLength +[ -f /var/lib/mympd/state/notificationPage ] || echo -n "true" > /var/lib/mympd/state/notificationPage +[ -f /var/lib/mympd/state/notificationWeb ] || echo -n "false" > /var/lib/mympd/state/notificationWeb + +echo "Fixing ownership of /var/lib/mympd" +chown -R mympd.mympd /var/lib/mympd + # move config into place unless already existing if [ ! -f /etc/mympd/mympd.conf ] then diff --git a/debian/postinst b/debian/postinst index ecff3a1..5b0322e 100755 --- a/debian/postinst +++ b/debian/postinst @@ -6,8 +6,7 @@ getent group mympd > /dev/null getent passwd mympd > /dev/null [ "$?" = "2" ] && useradd -r mympd -g mympd -d /var/lib/mympd -s /usr/sbin/nologin -echo "Fixing ownership of /var/lib/mympd" -chown -R mympd.mympd /var/lib/mympd + echo "Trying to link musicdir to library" if [ -f /etc/mpd.conf ] @@ -48,7 +47,6 @@ do fi done - # move config into place unless already existing if [ ! -f /etc/mympd/mympd.conf ] then @@ -57,6 +55,16 @@ else echo "mympd.conf installed as mympd.conf.dist" fi +#default state files +[ -f /var/lib/mympd/state/jukeboxMode ] || echo -n "0" > /var/lib/mympd/state/jukeboxMode +[ -f /var/lib/mympd/state/jukeboxPlaylist ] || echo -n "Database" > /var/lib/mympd/state/jukeboxPlaylist +[ -f /var/lib/mympd/state/jukeboxQueueLength ] || echo -n "1" > /var/lib/mympd/state/jukeboxQueueLength +[ -f /var/lib/mympd/state/notificationPage ] || echo -n "true" > /var/lib/mympd/state/notificationPage +[ -f /var/lib/mympd/state/notificationWeb ] || echo -n "false" > /var/lib/mympd/state/notificationWeb + +echo "Fixing ownership of /var/lib/mympd" +chown -R mympd.mympd /var/lib/mympd + if [ -d /etc/mympd/ssl ] then echo "Certificates already created" From 2a675bc4e817b6bac639ee76732b04ac6731b18d Mon Sep 17 00:00:00 2001 From: jcorporation Date: Sun, 7 Oct 2018 22:56:11 +0100 Subject: [PATCH 08/20] Fix: check existance of needed directories under /var/lib/mympd --- src/mympd.c | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/src/mympd.c b/src/mympd.c index 998cbae..1c67c1c 100644 --- a/src/mympd.c +++ b/src/mympd.c @@ -183,6 +183,8 @@ static int inihandler(void* user, const char* section, const char* name, const c void read_statefiles() { char *crap; char value[400]; + + printf("Reading states\n"); if (mympd_state_get("notificationWeb", value)) { if (strcmp(value, "true") == 0) mympd_state.notificationWeb = true; @@ -227,12 +229,26 @@ void read_statefiles() { } } +bool testdir(char *name, char *dirname) { + DIR* dir = opendir(dirname); + if (dir) { + closedir(dir); + printf("%s: \"%s\"\n", name, dirname); + return true; + } + else { + printf("%s: \"%s\" don't exists\n", name, dirname); + return false; + } +} + int main(int argc, char **argv) { struct mg_mgr mgr; struct mg_connection *nc; struct mg_connection *nc_http; struct mg_bind_opts bind_opts; const char *err; + char testdirname[400]; //defaults config.mpdhost = "127.0.0.1"; @@ -277,16 +293,6 @@ int main(int argc, char **argv) { printf("Starting myMPD %s\n", MYMPD_VERSION); - DIR* dir = opendir(SRC_PATH); - if (dir) { - printf("Document root: %s\n", SRC_PATH); - closedir(dir); - } - else { - printf("Document root \"%s\" don't exists\n", SRC_PATH); - return EXIT_FAILURE; - } - signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); setvbuf(stdout, NULL, _IOLBF, 0); @@ -349,6 +355,21 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } + if (!testdir("Document root", SRC_PATH)) + return EXIT_FAILURE; + + snprintf(testdirname, 400, "%s/tmp", config.varlibdir); + if (!testdir("Temp dir", testdirname)) + return EXIT_FAILURE; + + snprintf(testdirname, 400, "%s/smartpls", config.varlibdir); + if (!testdir("Smartpls dir", testdirname)) + return EXIT_FAILURE; + + snprintf(testdirname, 400, "%s/state", config.varlibdir); + if (!testdir("State dir", testdirname)) + return EXIT_FAILURE; + read_statefiles(); if (config.ssl == true) From dab83d0e5e63a3e7dcd96287e1967f2362f7d712 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Sun, 7 Oct 2018 23:21:44 +0100 Subject: [PATCH 09/20] Fix: test of entity type in mympd_smartpls_update_newest --- src/mpd_client.c | 68 +++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/src/mpd_client.c b/src/mpd_client.c index e783a0f..71b6699 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -2325,6 +2325,7 @@ int mympd_smartpls_update(char *playlist, char *sticker, int maxentries) { int mympd_smartpls_update_newest(char *playlist, int timerange, int maxentries) { struct mpd_song *song; + struct mpd_entity *entity; char *uri; char *p_value; char *name; @@ -2346,12 +2347,16 @@ int mympd_smartpls_update_newest(char *playlist, int timerange, int maxentries) printf("Error opening %s\n", tmpfile); return 1; } - while ((song = mpd_recv_song(mpd.conn)) != NULL) { - value = mpd_song_get_last_modified(song); - if (value > value_max) - value_max = value; - fprintf(fp, "%s::%ld\n", mpd_song_get_uri(song), value); - mpd_song_free(song); + while ((entity = mpd_recv_entity(mpd.conn)) != NULL) { + if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) { + song = mpd_entity_get_song(entity); + value = mpd_song_get_last_modified(song); + if (value >= value_max) { + value_max = value; + fprintf(fp, "%s::%ld\n", mpd_song_get_uri(song), value); + } + mpd_entity_free(entity); + } } mpd_response_finish(mpd.conn); fclose(fp); @@ -2360,31 +2365,36 @@ int mympd_smartpls_update_newest(char *playlist, int timerange, int maxentries) value_max -= timerange; - fp = fopen(tmpfile, "r"); - if (fp == NULL) { - printf("Error opening %s\n", tmpfile); - return 1; - } - while ((read = getline(&uri, &len, fp)) != -1) { - name = strtok(uri, "::"); - p_value = strtok(NULL, "::"); - value = strtol(p_value, &crap, 10); - if (value >= value_max) - continue; - if (!mpd_run_playlist_add(mpd.conn, playlist, name)) { - LOG_ERROR_AND_RECOVER("mpd_run_playlist_add"); - fclose(fp); - unlink(tmpfile); - free(uri); - return 1; + if (value_max > 0) { + fp = fopen(tmpfile, "r"); + if (fp == NULL) { + printf("Error opening %s\n", tmpfile); + return 1; } - i++; - if (i >= maxentries) - break; + while ((read = getline(&uri, &len, fp)) != -1) { + name = strtok(uri, "::"); + p_value = strtok(NULL, "::"); + value = strtol(p_value, &crap, 10); + if (value >= value_max) + continue; + if (!mpd_run_playlist_add(mpd.conn, playlist, name)) { + LOG_ERROR_AND_RECOVER("mpd_run_playlist_add"); + fclose(fp); + unlink(tmpfile); + free(uri); + return 1; + } + i++; + if (i >= maxentries) + break; + } + fclose(fp); + free(uri); + printf("Updated %s with %ld songs, minValue: %ld\n", playlist, i, value_max); + } + else { + printf("Error updating %s\n", playlist); } - fclose(fp); - free(uri); unlink(tmpfile); - printf("Updated %s with %ld songs, minValue: %ld\n", playlist, i, value_max); return 0; } From 25a8653510e32777f2ab567af5517089ca027cd1 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Mon, 8 Oct 2018 17:14:07 +0100 Subject: [PATCH 10/20] Fix: use modified-since find and last database update for creating myMPDsmart-newest #64 --- src/mpd_client.c | 78 ++++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/src/mpd_client.c b/src/mpd_client.c index 71b6699..c7abc90 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -1073,7 +1073,16 @@ void mympd_jukebox() { } else { song = mpd_entity_get_song(entity); - list_push(&add_list, mpd_song_get_uri(song), lineno); +/* + int nm = nr - i - 1; + if (nm > 0) { + struct aline tmp = keeplines[i]; + memmove(&keeplines[i], &keeplines[i+1], nm * sizeof(*keeplines)); + keeplines[nkeep-1] = tmp; + } + savestr(&keeplines[nkeep-1], line); +*/ +// list_push(&add_list, mpd_song_get_uri(song), lineno); } } } @@ -1121,8 +1130,10 @@ void mympd_jukebox() { fprintf(stderr, "Warning: input didn't contain %d entries\n", addSongs); } +// list_shuffle(&add_list); + struct node *current = add_list.list; - while (1) { + while (current != NULL) { if (mympd_state.jukeboxMode == 1) { printf("Jukebox adding song: %s\n", current->data); if (!mpd_run_add(mpd.conn, current->data)) { @@ -1137,8 +1148,6 @@ void mympd_jukebox() { } mpd_response_finish(mpd.conn); } - if (current->next == NULL) - break; current = current->next; } list_free(&add_list); @@ -1146,7 +1155,7 @@ void mympd_jukebox() { } int randrange(int n) { - return rand() / (RAND_MAX / (n + 1)); + return rand() / (RAND_MAX / (n + 1) + 1); } int mympd_put_state(char *buffer, int *current_song_id, int *next_song_id, int *last_song_id, unsigned *queue_version, unsigned *queue_length) { @@ -2325,47 +2334,48 @@ int mympd_smartpls_update(char *playlist, char *sticker, int maxentries) { int mympd_smartpls_update_newest(char *playlist, int timerange, int maxentries) { struct mpd_song *song; - struct mpd_entity *entity; char *uri; - char *p_value; char *name; - char *crap; char tmpfile[400]; - time_t value; - time_t value_max = 0; + unsigned long value; size_t len = 0; ssize_t read; long i = 0; + unsigned long value_max = 0; + char search[20]; - if (!mpd_send_list_all_meta(mpd.conn, "/")) { - LOG_ERROR_AND_RECOVER("mpd_send_list_all_meta"); - return 1; + struct mpd_stats *stats = mpd_run_stats(mpd.conn); + if (stats != NULL) { + value_max = mpd_stats_get_db_update_time(stats); + mpd_stats_free(stats); } - snprintf(tmpfile, 400, "%s/tmp/playlist.tmp", config.varlibdir); - FILE *fp = fopen(tmpfile, "w"); - if (fp == NULL) { - printf("Error opening %s\n", tmpfile); + else { + LOG_ERROR_AND_RECOVER("mpd_run_stats"); return 1; - } - while ((entity = mpd_recv_entity(mpd.conn)) != NULL) { - if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) { - song = mpd_entity_get_song(entity); - value = mpd_song_get_last_modified(song); - if (value >= value_max) { - value_max = value; - fprintf(fp, "%s::%ld\n", mpd_song_get_uri(song), value); - } - mpd_entity_free(entity); - } } - mpd_response_finish(mpd.conn); - fclose(fp); mympd_smartpls_clear(playlist); - value_max -= timerange; - + snprintf(search, 20, "%lu", value_max); + if (value_max > 0) { + if (mpd_send_command(mpd.conn, "find", "modified-since", search, NULL) == false) { + LOG_ERROR_AND_RECOVER("mpd_find"); + return 1; + } + snprintf(tmpfile, 400, "%s/tmp/playlist.tmp", config.varlibdir); + FILE *fp = fopen(tmpfile, "w"); + if (fp == NULL) { + printf("Error opening %s\n", tmpfile); + return 1; + } + while ((song = mpd_recv_song(mpd.conn)) != NULL) { + value = mpd_song_get_last_modified(song); + fprintf(fp, "%s::%lu\n", mpd_song_get_uri(song), value); + mpd_song_free(song); + } + fclose(fp); + fp = fopen(tmpfile, "r"); if (fp == NULL) { printf("Error opening %s\n", tmpfile); @@ -2373,10 +2383,6 @@ int mympd_smartpls_update_newest(char *playlist, int timerange, int maxentries) } while ((read = getline(&uri, &len, fp)) != -1) { name = strtok(uri, "::"); - p_value = strtok(NULL, "::"); - value = strtol(p_value, &crap, 10); - if (value >= value_max) - continue; if (!mpd_run_playlist_add(mpd.conn, playlist, name)) { LOG_ERROR_AND_RECOVER("mpd_run_playlist_add"); fclose(fp); From 4e62c336ba2a0689f1947692d35145115f5627f1 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Mon, 8 Oct 2018 21:44:22 +0100 Subject: [PATCH 11/20] Fix: use central list functions for smart playlists and jukebox mode --- src/list.c | 83 ++++++++++++++++++++++-- src/list.h | 8 ++- src/mpd_client.c | 164 +++++++++++++---------------------------------- src/mpd_client.h | 2 +- 4 files changed, 132 insertions(+), 125 deletions(-) diff --git a/src/list.c b/src/list.c index c39a8d1..b4ece0f 100644 --- a/src/list.c +++ b/src/list.c @@ -1,10 +1,85 @@ #include #include +#include +#include #include "list.h" -int list_init(struct list *list) { - list->length = 0; - list->list = NULL; +int list_init(struct list *l) { + l->length = 0; + l->list = NULL; + return 0; +} + + +struct node *list_node_at(const struct list * l, unsigned index) { + /* if there's no data in the list, fail */ + if (l->list == NULL) { return NULL; } + struct node * current = l->list; + for (; index > 0; index--) { + if (current->next == NULL) { return NULL; } + current = current->next; + } + return current; +} + + +int list_swap_item(struct node *n1, struct node *n2) { + if (n1 == n2) + return 1; + + if (n1 == NULL || n2 == NULL) + return 1; + + int value = n2->value; + char *data; + data = malloc(strlen(n2->data)); + data = strdup(n2->data); + + n2->value = n1->value; + n2->data = realloc(n2->data, strlen(n1->data)); + n2->data = strdup(n1->data); + + n1->value = value; + n1->data = realloc(n1->data, strlen(data)); + n1->data = strdup(data); + + free(data); + return 0; +} + +int list_shuffle(struct list *l) { + int pos; + int n = 0; + + if (l->length < 2) + return 1; + + srand((unsigned int)time(NULL)); + + struct node *current = l->list; + while (current != NULL) { + pos = rand() / (RAND_MAX / (l->length - n + 1) + 1); + list_swap_item(current, list_node_at(l, pos)); + n++; + current = current->next; + } + return 0; +} + + +int list_replace(struct list *l, int pos, char *data, int value) { + int i = 0; + struct node *current = l->list; + while (current->next != NULL) { + if (i == pos) + break; + current = current->next; + i++; + } + + current->value = value; + current->data = realloc(current->data, strlen(data)); + current->data = strdup(data); return 0; } @@ -25,7 +100,7 @@ int list_push(struct list *l, char *data, int value) { } int list_free(struct list *l) { - struct node * current = l->list, *tmp = NULL; + struct node *current = l->list, *tmp = NULL; while (current != NULL) { free(current->data); tmp = current; diff --git a/src/list.h b/src/list.h index dc507b1..07b09ce 100644 --- a/src/list.h +++ b/src/list.h @@ -4,12 +4,18 @@ struct node { struct node *next; }; + struct list { unsigned length; struct node *list; }; -int list_init(struct list *); +int list_init(struct list *l); int list_push(struct list *l, char *data, int value); +int list_replace(struct list *l, int pos, char *data, int value); int list_free(struct list *l); + +int list_shuffle(struct list *l); +int list_swap_item(struct node *n1, struct node *n2); +struct node *list_node_at(const struct list * l, unsigned index); diff --git a/src/mpd_client.c b/src/mpd_client.c index c7abc90..dbc5a42 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -211,8 +211,8 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) { free(p_charbuf3); } else if (strcmp(p_charbuf1, "newest") == 0) { - je = json_scanf(msg.p, msg.len, "{data: {playlist: %Q, timerange: %d, maxentries: %d}}", &p_charbuf2, &int_buf1, &int_buf2); - n = mympd_smartpls_save(p_charbuf1, p_charbuf2, NULL, NULL, int_buf2, int_buf1); + je = json_scanf(msg.p, msg.len, "{data: {playlist: %Q, timerange: %d}}", &p_charbuf2, &int_buf1); + n = mympd_smartpls_save(p_charbuf1, p_charbuf2, NULL, NULL, 0, int_buf1); free(p_charbuf2); } else if (strcmp(p_charbuf1, "search") == 0) { @@ -1068,21 +1068,11 @@ void mympd_jukebox() { i = randrange(addSongs); if (addSongs == 1) { song = mpd_entity_get_song(entity); - list_free(&add_list); - list_push(&add_list, mpd_song_get_uri(song), lineno); + list_replace(&add_list, 0, mpd_song_get_uri(song), lineno); } else { song = mpd_entity_get_song(entity); -/* - int nm = nr - i - 1; - if (nm > 0) { - struct aline tmp = keeplines[i]; - memmove(&keeplines[i], &keeplines[i+1], nm * sizeof(*keeplines)); - keeplines[nkeep-1] = tmp; - } - savestr(&keeplines[nkeep-1], line); -*/ -// list_push(&add_list, mpd_song_get_uri(song), lineno); + list_replace(&add_list, i, mpd_song_get_uri(song), lineno); } } } @@ -1114,11 +1104,10 @@ void mympd_jukebox() { if (addSongs > 1) i = randrange(addSongs); if (addSongs == 1) { - list_free(&add_list); - list_push(&add_list, strdup(pair->value), lineno); + list_replace(&add_list, 0, strdup(pair->value), lineno); } else { - list_push(&add_list, strdup(pair->value), lineno); + list_replace(&add_list, i, strdup(pair->value), lineno); } } } @@ -1126,11 +1115,12 @@ void mympd_jukebox() { mpd_return_pair(mpd.conn, pair); } } + if (nkeep < addSongs) { fprintf(stderr, "Warning: input didn't contain %d entries\n", addSongs); } -// list_shuffle(&add_list); + list_shuffle(&add_list); struct node *current = add_list.list; while (current != NULL) { @@ -2095,7 +2085,7 @@ int mympd_smartpls_put(char *buffer, char *playlist) { char pl_file[400]; char *smartpltype; char *p_charbuf1, *p_charbuf2; - int je, int_buf1, int_buf2; + int je, int_buf1; int len = 0; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); @@ -2115,13 +2105,12 @@ int mympd_smartpls_put(char *buffer, char *playlist) { } } else if (strcmp(smartpltype, "newest") == 0) { - je = json_scanf(content, strlen(content), "{timerange: %d, maxentries: %d}", &int_buf1, &int_buf2); - if (je == 2) { - len = json_printf(&out, "{type: smartpls, data: {playlist: %Q, type: %Q, timerange: %d, maxentries: %d}}", + je = json_scanf(content, strlen(content), "{timerange: %d}", &int_buf1); + if (je == 1) { + len = json_printf(&out, "{type: smartpls, data: {playlist: %Q, type: %Q, timerange: %d}}", playlist, smartpltype, - int_buf1, - int_buf2); + int_buf1); } } else if (strcmp(smartpltype, "search") == 0) { @@ -2152,9 +2141,9 @@ int mympd_smartpls_save(char *smartpltype, char *playlist, char *tag, char *sear mympd_smartpls_update(playlist, tag, maxentries); } else if (strcmp(smartpltype, "newest") == 0) { - json_fprintf(tmp_file, "{type: %Q, timerange: %d, maxentries: %d}", smartpltype, timerange, maxentries); + json_fprintf(tmp_file, "{type: %Q, timerange: %d}", smartpltype, timerange); rename(tmp_file, pl_file); - mympd_smartpls_update_newest(playlist, timerange, maxentries); + mympd_smartpls_update_newest(playlist, timerange); } else if (strcmp(smartpltype, "search") == 0) { json_fprintf(tmp_file, "{type: %Q, tag: %Q, searchstr: %Q}", smartpltype, tag, searchstr); @@ -2172,7 +2161,7 @@ int mympd_smartpls_update_all() { char dirname[400]; int je; char *p_charbuf1, *p_charbuf2; - int int_buf1, int_buf2; + int int_buf1; if (!config.smartpls) return 0; @@ -2197,9 +2186,9 @@ int mympd_smartpls_update_all() { printf("Can't parse file %s\n", filename); } else if (strcmp(smartpltype, "newest") == 0) { - je = json_scanf(content, strlen(content), "{timerange: %d, maxentries: %d}", &int_buf1, &int_buf2); - if (je == 2) { - mympd_smartpls_update_newest(ent->d_name, int_buf1, int_buf2); + je = json_scanf(content, strlen(content), "{timerange: %d}", &int_buf1); + if (je == 1) { + mympd_smartpls_update_newest(ent->d_name, int_buf1); } else printf("Can't parse file %s\n", filename); @@ -2264,23 +2253,18 @@ int mympd_smartpls_update(char *playlist, char *sticker, int maxentries) { char *name; char *p_value; char *crap; - char tmpfile[400]; long value; long value_max = 0; - size_t len = 0; - ssize_t read; long i = 0; if (!mpd_send_sticker_find(mpd.conn, "song", "", sticker)) { LOG_ERROR_AND_RECOVER("mpd_send_sticker_find"); return 1; } - snprintf(tmpfile, 400, "%s/tmp/playlist.tmp", config.varlibdir); - FILE *fp = fopen(tmpfile, "w"); - if (fp == NULL) { - printf("Error opening %s\n", tmpfile); - return 1; - } + + struct list add_list; + list_init(&add_list); + while ((pair = mpd_recv_pair(mpd.conn)) != NULL) { if (strcmp(pair->name, "file") == 0) { uri = strdup(pair->value); @@ -2289,60 +2273,43 @@ int mympd_smartpls_update(char *playlist, char *sticker, int maxentries) { name = strtok(strdup(pair->value), "="); p_value = strtok(NULL, "="); value = strtol(p_value, &crap, 10); - if (value > 1) - fprintf(fp, "%s::%ld\n", uri, value); + if (value > 1) + list_push(&add_list, uri, value); if (value > value_max) value_max = value; } mpd_return_pair(mpd.conn, pair); } mpd_response_finish(mpd.conn); - fclose(fp); + free(uri); mympd_smartpls_clear(playlist); if (value_max > 2) value_max = value_max / 2; - fp = fopen(tmpfile, "r"); - if (fp == NULL) { - printf("Error opening %s\n", tmpfile); - return 1; - } - while ((read = getline(&uri, &len, fp)) != -1) { - name = strtok(uri, "::"); - p_value = strtok(NULL, "::"); - value = strtol(p_value, &crap, 10); - if (value < value_max) - continue; - if (!mpd_run_playlist_add(mpd.conn, playlist, name)) { - LOG_ERROR_AND_RECOVER("mpd_run_playlist_add"); - fclose(fp); - free(uri); - unlink(tmpfile); - return 1; + + struct node *current = add_list.list; + while (current != NULL) { + if (current->value >= value_max) { + if (!mpd_run_playlist_add(mpd.conn, playlist, current->data)) { + LOG_ERROR_AND_RECOVER("mpd_run_playlist_add"); + list_free(&add_list); + return 1; + } + i++; + if (i >= maxentries) + break; } - i++; - if (i >= maxentries) - break; + current = current->next; } - fclose(fp); - free(uri); - unlink(tmpfile); + list_free(&add_list); printf("Updated %s with %ld songs, minValue: %ld\n", playlist, i, value_max); return 0; } -int mympd_smartpls_update_newest(char *playlist, int timerange, int maxentries) { - struct mpd_song *song; - char *uri; - char *name; - char tmpfile[400]; - unsigned long value; - size_t len = 0; - ssize_t read; - long i = 0; +int mympd_smartpls_update_newest(char *playlist, int timerange) { unsigned long value_max = 0; - char search[20]; + char searchstr[20]; struct mpd_stats *stats = mpd_run_stats(mpd.conn); if (stats != NULL) { @@ -2356,51 +2323,10 @@ int mympd_smartpls_update_newest(char *playlist, int timerange, int maxentries) mympd_smartpls_clear(playlist); value_max -= timerange; - snprintf(search, 20, "%lu", value_max); - if (value_max > 0) { - if (mpd_send_command(mpd.conn, "find", "modified-since", search, NULL) == false) { - LOG_ERROR_AND_RECOVER("mpd_find"); - return 1; - } - snprintf(tmpfile, 400, "%s/tmp/playlist.tmp", config.varlibdir); - FILE *fp = fopen(tmpfile, "w"); - if (fp == NULL) { - printf("Error opening %s\n", tmpfile); - return 1; - } - while ((song = mpd_recv_song(mpd.conn)) != NULL) { - value = mpd_song_get_last_modified(song); - fprintf(fp, "%s::%lu\n", mpd_song_get_uri(song), value); - mpd_song_free(song); - } - fclose(fp); - - fp = fopen(tmpfile, "r"); - if (fp == NULL) { - printf("Error opening %s\n", tmpfile); - return 1; - } - while ((read = getline(&uri, &len, fp)) != -1) { - name = strtok(uri, "::"); - if (!mpd_run_playlist_add(mpd.conn, playlist, name)) { - LOG_ERROR_AND_RECOVER("mpd_run_playlist_add"); - fclose(fp); - unlink(tmpfile); - free(uri); - return 1; - } - i++; - if (i >= maxentries) - break; - } - fclose(fp); - free(uri); - printf("Updated %s with %ld songs, minValue: %ld\n", playlist, i, value_max); + snprintf(searchstr, 20, "%lu", value_max); + mympd_search(mpd.buf, searchstr, "modified-since", playlist, 0); + printf("Updated %s\n", playlist); } - else { - printf("Error updating %s\n", playlist); - } - unlink(tmpfile); return 0; } diff --git a/src/mpd_client.h b/src/mpd_client.h index 6bba011..a34a2b5 100644 --- a/src/mpd_client.h +++ b/src/mpd_client.h @@ -209,7 +209,7 @@ int mympd_smartpls_put(char *buffer, char *playlist); int mympd_smartpls_update_all(); int mympd_smartpls_clear(char *playlist); int mympd_smartpls_update(char *sticker, char *playlist, int maxentries); -int mympd_smartpls_update_newest(char *playlist, int timerange, int maxentries); +int mympd_smartpls_update_newest(char *playlist, int timerange); int mympd_smartpls_update_search(char *playlist, char *tag, char *searchstr); int mympd_get_updatedb_state(char *buffer); int mympd_put_state(char *buffer, int *current_song_id, int *next_song_id, int *last_song_id, unsigned *queue_version, unsigned *queue_length); From ceb694b7b210925e626d8baee7c1a0610e73530b Mon Sep 17 00:00:00 2001 From: jcorporation Date: Mon, 8 Oct 2018 21:45:10 +0100 Subject: [PATCH 12/20] Fix: remove maxelements from myMPDsmart-newest --- dist/htdocs/index.html | 2 +- dist/htdocs/js/mympd.min.js | 13 +++++++------ dist/htdocs/sw.min.js | 2 +- dist/smartpls/myMPDsmart-newestSongs.dist | 2 +- htdocs/index.html | 5 ----- htdocs/js/mympd.js | 7 +------ 6 files changed, 11 insertions(+), 20 deletions(-) diff --git a/dist/htdocs/index.html b/dist/htdocs/index.html index c324fbd..3c92487 100644 --- a/dist/htdocs/index.html +++ b/dist/htdocs/index.html @@ -1 +1 @@ -myMPD
Playback

Artist

Album

Queue
#TitleArtistAlbumDuration
PlaylistLast modified
Playlist List
#TitleArtistAlbumDuration
Artist

TitleArtistAlbumDuration
Search
TitleArtistAlbumDuration
\ No newline at end of file +myMPD
Playback

Artist

Album

Queue
#TitleArtistAlbumDuration
PlaylistLast modified
Playlist List
#TitleArtistAlbumDuration
Artist

TitleArtistAlbumDuration
Search
TitleArtistAlbumDuration
\ No newline at end of file diff --git a/dist/htdocs/js/mympd.min.js b/dist/htdocs/js/mympd.min.js index f7ce7eb..32eda44 100644 --- a/dist/htdocs/js/mympd.min.js +++ b/dist/htdocs/js/mympd.min.js @@ -42,9 +42,10 @@ showAddToPlaylist(app.current.search))},!1);document.getElementById("searchAddAl ("Add all to queue"==a.target.innerText?addAllFromBrowseDatabasePlist("queue"):"Add all to playlist"==a.target.innerText&&showAddToPlaylist("DATABASE"))},!1);document.getElementById("searchtags").addEventListener("click",function(a){"BUTTON"==a.target.nodeName&&appGoto(app.current.app,app.current.tab,app.current.view,"0/"+a.target.getAttribute("data-tag")+"/"+app.current.search)},!1);document.getElementById("searchqueuestr").addEventListener("keyup",function(a){appGoto(app.current.app,app.current.tab, app.current.view,"0/"+app.current.filter+"/"+this.value)},!1);document.getElementById("searchqueuetag").addEventListener("click",function(a){"BUTTON"==a.target.nodeName&&appGoto(app.current.app,app.current.tab,app.current.view,app.current.page+"/"+a.target.getAttribute("data-tag")+"/"+app.current.search)},!1);document.getElementById("search").addEventListener("submit",function(){return!1},!1);document.getElementById("searchqueue").addEventListener("submit",function(){return!1},!1);document.getElementById("searchstr").addEventListener("keyup", function(a){appGoto("Search",void 0,void 0,"0/"+app.current.filter+"/"+this.value)},!1);document.getElementById("BrowseDatabaseByTagDropdown").addEventListener("click",function(a){"BUTTON"==a.target.nodeName&&appGoto(app.current.app,app.current.tab,a.target.getAttribute("data-tag"),"0/"+app.current.filter+"/"+app.current.search)},!1);document.getElementsByTagName("body")[0].addEventListener("click",function(a){hideMenu()},!1);dragAndDropTable("QueueList");dragAndDropTable("BrowsePlaylistsDetailList"); -window.addEventListener("hashchange",appRoute,!1);window.addEventListener("focus",function(){sendAPI({cmd:"MPD_API_PLAYER_STATE"},parseState)},!1);document.addEventListener("keydown",function(a){if("INPUT"!=a.target.tagName){switch(a.which){case 37:clickPrev();break;case 39:clickNext();break;case 32:clickPlay();break;default:return}a.preventDefault()}},!1);"serviceWorker"in navigator&&"https"==document.URL.substring(0,5)&&window.addEventListener("load",function(){navigator.serviceWorker.register("/sw.min.js", -{scope:"/"}).then(function(a){console.log("ServiceWorker registration successful with scope: ",a.scope);a.update()},function(a){console.log("ServiceWorker registration failed: ",a)})});window.addEventListener("beforeinstallprompt",function(a){a.preventDefault();deferredPrompt=a});window.addEventListener("beforeinstallprompt",function(a){a.preventDefault();deferredPrompt=a;domCache.btnAdd.classList.remove("hide")});domCache.btnAdd.addEventListener("click",function(a){domCache.btnAdd.classList.add("hide"); -deferredPrompt.prompt();deferredPrompt.userChoice.then(function(a){"accepted"===a.outcome?console.log("User accepted the A2HS prompt"):console.log("User dismissed the A2HS prompt");deferredPrompt=null})});window.addEventListener("appinstalled",function(a){console.log("myMPD installed as app")})} +window.addEventListener("hashchange",appRoute,!1);window.addEventListener("focus",function(){sendAPI({cmd:"MPD_API_PLAYER_STATE"},parseState)},!1);document.addEventListener("keydown",function(a){if("INPUT"!=a.target.tagName&&"SELECT"!=a.target.tagName){if(a.shiftKey)switch(a.which){case 83:sendAPI({cmd:"MPD_API_QUEUE_SHUFFLE"});break;case 67:sendAPI({cmd:"MPD_API_QUEUE_CROP"});break;default:return}else switch(a.which){case 37:clickPrev();break;case 39:clickNext();break;case 32:clickPlay();break;case 83:clickStop(); +break;case 173:chVolume(-5);break;case 171:chVolume(5);break;case 67:sendAPI({cmd:"MPD_API_QUEUE_CLEAR"});break;default:return}a.preventDefault()}},!1);"serviceWorker"in navigator&&"https"==document.URL.substring(0,5)&&window.addEventListener("load",function(){navigator.serviceWorker.register("/sw.min.js",{scope:"/"}).then(function(a){console.log("ServiceWorker registration successful with scope: ",a.scope);a.update()},function(a){console.log("ServiceWorker registration failed: ",a)})});window.addEventListener("beforeinstallprompt", +function(a){a.preventDefault();deferredPrompt=a});window.addEventListener("beforeinstallprompt",function(a){a.preventDefault();deferredPrompt=a;domCache.btnAdd.classList.remove("hide")});domCache.btnAdd.addEventListener("click",function(a){domCache.btnAdd.classList.add("hide");deferredPrompt.prompt();deferredPrompt.userChoice.then(function(a){"accepted"===a.outcome?console.log("User accepted the A2HS prompt"):console.log("User dismissed the A2HS prompt");deferredPrompt=null})});window.addEventListener("appinstalled", +function(a){console.log("myMPD installed as app")})} function dragAndDropTable(a){var b=document.getElementById(a).getElementsByTagName("tbody")[0];b.addEventListener("dragstart",function(a){"TR"==a.target.nodeName&&(a.target.classList.add("opacity05"),a.dataTransfer.setDragImage(a.target,0,0),a.dataTransfer.effectAllowed="move",a.dataTransfer.setData("Text",a.target.getAttribute("id")),dragEl=a.target.cloneNode(!0))},!1);b.addEventListener("dragleave",function(a){a.preventDefault();var b=a.target;"TD"==a.target.nodeName&&(b=a.target.parentNode);"TR"== b.nodeName&&b.classList.remove("dragover")},!1);b.addEventListener("dragover",function(a){a.preventDefault();for(var c=b.getElementsByClassName("dragover"),e=c.length,f=0;f'+d+"");document.getElementById("selectSaveSmartPlaylistTag").innerHTML=c;"search"==a.data.type?(document.getElementById("saveSmartPlaylistSearch").classList.remove("hide"),document.getElementById("selectSaveSmartPlaylistTag").value=a.data.tag,document.getElementById("inputSaveSmartPlaylistSearchstr").value=a.data.searchstr):"sticker"==a.data.type?(document.getElementById("saveSmartPlaylistSticker").classList.remove("hide"), -document.getElementById("selectSaveSmartPlaylistSticker").value=a.data.sticker,document.getElementById("inputSaveSmartPlaylistStickerMaxentries").value=a.data.maxentries):"newest"==a.data.type&&(document.getElementById("saveSmartPlaylistNewest").classList.remove("hide"),c=a.data.timerange/24/60/60,document.getElementById("inputSaveSmartPlaylistNewestTimerange").value=c,document.getElementById("inputSaveSmartPlaylistNewestMaxentries").value=a.data.maxentries);modalSaveSmartPlaylist.show();b.focus()} +document.getElementById("selectSaveSmartPlaylistSticker").value=a.data.sticker,document.getElementById("inputSaveSmartPlaylistStickerMaxentries").value=a.data.maxentries):"newest"==a.data.type&&(document.getElementById("saveSmartPlaylistNewest").classList.remove("hide"),a=a.data.timerange/24/60/60,document.getElementById("inputSaveSmartPlaylistNewestTimerange").value=a);modalSaveSmartPlaylist.show();b.focus()} function chkInt(a,b){if(""!=a.value.replace(/\d/g,""))return a.classList.add("is-invalid"),b.classList.add("was-validated"),!1;a.classList.remove("is-invalid");return!0} function saveSmartPlaylist(){var a=document.getElementById("saveSmartPlaylistName").value,b=document.getElementById("saveSmartPlaylistType").value,c=a.replace(/[\w\-]/g,""),d=document.getElementById("saveSmartPlaylistFrm");if(""!=a&&""==c){if("search"==b)d=document.getElementById("selectSaveSmartPlaylistTag"),d=d.options[d.selectedIndex].value,c=document.getElementById("inputSaveSmartPlaylistSearchstr").value,sendAPI({cmd:"MPD_API_SMARTPLS_SAVE",data:{type:b,playlist:a,tag:d,searchstr:c}});else if("sticker"== -b){c=document.getElementById("selectSaveSmartPlaylistSticker");c=c.options[c.selectedIndex].value;var e=document.getElementById("inputSaveSmartPlaylistStickerMaxentries");if(!chkInt(e,d))return;d=e.value;sendAPI({cmd:"MPD_API_SMARTPLS_SAVE",data:{type:b,playlist:a,sticker:c,maxentries:d}})}else if("newest"==b){c=document.getElementById("inputSaveSmartPlaylistNewestTimerange");if(!chkInt(c,d))return;c=86400*parseInt(c.value);e=document.getElementById("inputSaveSmartPlaylistNewestMaxentries");if(!chkInt(e, -d))return;d=e.value;sendAPI({cmd:"MPD_API_SMARTPLS_SAVE",data:{type:b,playlist:a,timerange:c,maxentries:d}})}else{document.getElementById("saveSmartPlaylistType").classList.add("is-invalid");return}modalSaveSmartPlaylist.hide();showNotification("Saved smart playlist "+a,"","","success")}else document.getElementById("saveSmartPlaylistName").classList.add("is-invalid"),d.classList.add("was-validated")} +b){c=document.getElementById("selectSaveSmartPlaylistSticker");c=c.options[c.selectedIndex].value;var e=document.getElementById("inputSaveSmartPlaylistStickerMaxentries");if(!chkInt(e,d))return;sendAPI({cmd:"MPD_API_SMARTPLS_SAVE",data:{type:b,playlist:a,sticker:c,maxentries:e.value}})}else if("newest"==b){c=document.getElementById("inputSaveSmartPlaylistNewestTimerange");if(!chkInt(c,d))return;d=86400*parseInt(c.value);sendAPI({cmd:"MPD_API_SMARTPLS_SAVE",data:{type:b,playlist:a,timerange:d}})}else{document.getElementById("saveSmartPlaylistType").classList.add("is-invalid"); +return}modalSaveSmartPlaylist.hide();showNotification("Saved smart playlist "+a,"","","success")}else document.getElementById("saveSmartPlaylistName").classList.add("is-invalid"),d.classList.add("was-validated")} function showAddToPlaylist(a){document.getElementById("addToPlaylistUri").value=a;document.getElementById("addToPlaylistPlaylist").innerHTML="";document.getElementById("addToPlaylistNewPlaylist").value="";document.getElementById("addToPlaylistNewPlaylistDiv").classList.add("hide");document.getElementById("addToPlaylistFrm").classList.remove("was-validated");document.getElementById("addToPlaylistNewPlaylist").classList.remove("is-invalid");toggleBtn("toggleAddToPlaylistBtn",0);var b=document.getElementById("streamUrl"); b.focus();b.value="";b.classList.remove("is-invalid");document.getElementById("addStreamFrm").classList.remove("was-validated");"stream"!=a?(document.getElementById("addStreamFooter").classList.add("hide"),document.getElementById("addStreamFrm").classList.add("hide"),document.getElementById("addToPlaylistFooter").classList.remove("hide"),document.getElementById("addToPlaylistFrm").classList.remove("hide"),document.getElementById("addToPlaylistLabel").innerText="Add to playlist"):(document.getElementById("addStreamFooter").classList.remove("hide"), document.getElementById("addStreamFrm").classList.remove("hide"),document.getElementById("addToPlaylistFooter").classList.add("hide"),document.getElementById("addToPlaylistFrm").classList.add("hide"),document.getElementById("addToPlaylistLabel").innerText="Add Stream");modalAddToPlaylist.show();playlistEl="addToPlaylistPlaylist";sendAPI({cmd:"MPD_API_PLAYLIST_LIST",data:{offset:0,filter:"-"}},getAllPlaylists)} diff --git a/dist/htdocs/sw.min.js b/dist/htdocs/sw.min.js index 1ee760e..02bcf84 100644 --- a/dist/htdocs/sw.min.js +++ b/dist/htdocs/sw.min.js @@ -10,5 +10,5 @@ function(){function a(a){return function(d){c||(c=!0,a.call(b,d))}}var b=this,c= void 0;try{d=a.then}catch(h){this.reject_(h);return}"function"==typeof d?this.settleSameAsThenable_(d,a):this.fulfill_(a)};c.prototype.reject_=function(a){this.settle_(2,a)};c.prototype.fulfill_=function(a){this.settle_(1,a)};c.prototype.settle_=function(a,b){if(0!=this.state_)throw Error("Cannot settle("+a+", "+b+"): Promise already settled in state"+this.state_);this.state_=a;this.result_=b;this.executeOnSettledCallbacks_()};c.prototype.executeOnSettledCallbacks_=function(){if(null!=this.onSettledCallbacks_){for(var a= 0;a
Must be a number.
-
- - -
Must be a number.
-
diff --git a/htdocs/js/mympd.js b/htdocs/js/mympd.js index 15a8ae0..30bccdf 100644 --- a/htdocs/js/mympd.js +++ b/htdocs/js/mympd.js @@ -1695,7 +1695,6 @@ function parseSmartPlaylist(obj) { document.getElementById('saveSmartPlaylistNewest').classList.remove('hide'); var timerange = obj.data.timerange / 24 / 60 / 60; document.getElementById('inputSaveSmartPlaylistNewestTimerange').value = timerange; - document.getElementById('inputSaveSmartPlaylistNewestMaxentries').value = obj.data.maxentries; } modalSaveSmartPlaylist.show(); nameEl.focus(); @@ -1737,11 +1736,7 @@ function saveSmartPlaylist() { if (!chkInt(timerangeEl, frm)) return; var timerange = parseInt(timerangeEl.value) * 60 * 60 * 24; - var maxentriesEl = document.getElementById('inputSaveSmartPlaylistNewestMaxentries'); - if (!chkInt(maxentriesEl, frm)) - return; - var maxentries = maxentriesEl.value; - sendAPI({"cmd": "MPD_API_SMARTPLS_SAVE", "data": {"type": type, "playlist": name, "timerange": timerange, "maxentries": maxentries}}); + sendAPI({"cmd": "MPD_API_SMARTPLS_SAVE", "data": {"type": type, "playlist": name, "timerange": timerange}}); } else { document.getElementById('saveSmartPlaylistType').classList.add('is-invalid'); From 61adcb1c59ffc19cf52c06b38452e9891f9f83a0 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Mon, 8 Oct 2018 21:58:25 +0100 Subject: [PATCH 13/20] Fix: get current song only on song change --- htdocs/js/mympd.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/js/mympd.js b/htdocs/js/mympd.js index 30bccdf..90a56de 100644 --- a/htdocs/js/mympd.js +++ b/htdocs/js/mympd.js @@ -1055,7 +1055,8 @@ function parseState(obj) { setCounter(obj.data.currentSongId, obj.data.totalTime, obj.data.elapsedTime); //Get current song - sendAPI({"cmd": "MPD_API_PLAYER_CURRENT_SONG"}, songChange); + if (lastState && lastState.data.currentSongId != obj.data.currentSongId) + sendAPI({"cmd": "MPD_API_PLAYER_CURRENT_SONG"}, songChange); //clear playback card if not playing if (obj.data.songPos == '-1') { domCache.currentTrack.innerText = 'Not playing'; From 0c89fbc7d34aed7a4dcc9e480e7d05c579bcafef Mon Sep 17 00:00:00 2001 From: jcorporation Date: Mon, 8 Oct 2018 23:46:08 +0100 Subject: [PATCH 14/20] Fix: malloc errors --- src/list.c | 20 ++++++++++---------- src/mpd_client.c | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/list.c b/src/list.c index b4ece0f..a9ecd44 100644 --- a/src/list.c +++ b/src/list.c @@ -31,17 +31,17 @@ int list_swap_item(struct node *n1, struct node *n2) { return 1; int value = n2->value; - char *data; - data = malloc(strlen(n2->data)); - data = strdup(n2->data); + char *data = strdup(n2->data); n2->value = n1->value; - n2->data = realloc(n2->data, strlen(n1->data)); - n2->data = strdup(n1->data); + n2->data = realloc(n2->data, strlen(n1->data) + 1); + if (n2->data) + strcpy(n2->data, n1->data); n1->value = value; - n1->data = realloc(n1->data, strlen(data)); - n1->data = strdup(data); + n1->data = realloc(n1->data, strlen(data) + 1); + if (n1->data) + strcpy(n1->data, data); free(data); return 0; @@ -78,15 +78,15 @@ int list_replace(struct list *l, int pos, char *data, int value) { } current->value = value; - current->data = realloc(current->data, strlen(data)); - current->data = strdup(data); + current->data = realloc(current->data, strlen(data) + 1); + if (current->data) + strcpy(current->data, data); return 0; } int list_push(struct list *l, char *data, int value) { struct node *n = malloc(sizeof(struct node)); n->value = value; - n->data = malloc(strlen(data)); n->data = strdup(data); n->next = NULL; diff --git a/src/mpd_client.c b/src/mpd_client.c index dbc5a42..798a07c 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -55,7 +55,7 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) { size_t n = 0; char *cmd; unsigned int uint_buf1, uint_buf2, uint_rc; - int je, int_buf1, int_buf2, int_rc; + int je, int_buf1, int_rc; float float_buf; char *p_charbuf1, *p_charbuf2, *p_charbuf3, *p_charbuf4; char p_char[4]; From 6d549853b48d6ce5afd2e7932536ae13a7f8f4f8 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Mon, 8 Oct 2018 23:54:56 +0100 Subject: [PATCH 15/20] Fix: update minified files --- dist/htdocs/js/mympd.min.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/htdocs/js/mympd.min.js b/dist/htdocs/js/mympd.min.js index 32eda44..44205af 100644 --- a/dist/htdocs/js/mympd.min.js +++ b/dist/htdocs/js/mympd.min.js @@ -67,8 +67,8 @@ function setCounter(a,b,c){currentSong.totalTime=b;currentSong.elapsedTime=c;cur c.getAttribute("data-songpos"),c.classList.remove("font-weight-bold"));if(c=document.getElementById("queueTrackId"+a))d=c.getElementsByTagName("td"),d[4].innerText=b,d[0].classList.add("material-icons"),d[0].innerText="play_arrow",c.classList.add("font-weight-bold");progressTimer&&clearTimeout(progressTimer);"play"==playstate&&(progressTimer=setTimeout(function(){currentSong.elapsedTime++;setCounter(currentSong.currentSongId,currentSong.totalTime,currentSong.elapsedTime)},1E3))} function parseState(a){if(JSON.stringify(a)!==JSON.stringify(lastState)){if(1==a.data.state){for(var b=0;b=a.data.songPos?domCache.btnPrev.setAttribute("disabled","disabled"):domCache.btnPrev.removeAttribute("disabled");if(0==a.data.queueLength)for(b=0;ba.data.volume?"volume_down":"volume_up");domCache.volumeBar.value=a.data.volume;setCounter(a.data.currentSongId,a.data.totalTime,a.data.elapsedTime);sendAPI({cmd:"MPD_API_PLAYER_CURRENT_SONG"},songChange);"-1"==a.data.songPos&&(domCache.currentTrack.innerText="Not playing",domCache.currentAlbum.innerText="",domCache.currentArtist.innerText="",domCache.currentCover.style.backgroundImage= -"");lastState=a}}function getQueue(){2<=app.current.search.length?sendAPI({cmd:"MPD_API_QUEUE_SEARCH",data:{filter:app.current.filter,offset:app.current.page,searchstr:app.current.search}},parseQueue):sendAPI({cmd:"MPD_API_QUEUE_LIST",data:{offset:app.current.page}},parseQueue)} +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;setCounter(a.data.currentSongId,a.data.totalTime,a.data.elapsedTime);lastState&&lastState.data.currentSongId!=a.data.currentSongId&&sendAPI({cmd:"MPD_API_PLAYER_CURRENT_SONG"},songChange);"-1"==a.data.songPos&&(domCache.currentTrack.innerText="Not playing",domCache.currentAlbum.innerText="",domCache.currentArtist.innerText= +"",domCache.currentCover.style.backgroundImage="");lastState=a}}function getQueue(){2<=app.current.search.length?sendAPI({cmd:"MPD_API_QUEUE_SEARCH",data:{filter:app.current.filter,offset:app.current.page,searchstr:app.current.search}},parseQueue):sendAPI({cmd:"MPD_API_QUEUE_LIST",data:{offset:app.current.page}},parseQueue)} function parseQueue(a){if("Queue"===app.current.app){0g?"0":"")+g;g=document.createElement("tr");g.setAttribute("draggable","true");g.setAttribute("data-trackid",a.data[e].id);g.setAttribute("id","queueTrackId"+a.data[e].id); g.setAttribute("data-songpos",a.data[e].pos+1);g.setAttribute("data-duration",f);g.setAttribute("data-uri",a.data[e].uri);g.innerHTML=""+(a.data[e].pos+1)+""+a.data[e].title+""+a.data[e].artist+""+a.data[e].album+""+f+'playlist_add';e=b;e--)d[e].remove();"queuesearch"==a.type&&0==b?c.innerHTML='error_outlineNo results, please refine your search!': From b8d422e5645476cc707f4d47d8966ed11ac48a0c Mon Sep 17 00:00:00 2001 From: jcorporation Date: Tue, 9 Oct 2018 22:51:47 +0100 Subject: [PATCH 16/20] Feat: replace static tag list with dynamic list, this adds support of all mpd tags to myMPD --- htdocs/js/mympd.js | 28 +++++++------- src/list.c | 14 ++++++- src/list.h | 2 +- src/mpd_client.c | 95 ++++++++++------------------------------------ src/mpd_client.h | 13 ++----- src/mympd.c | 5 +++ 6 files changed, 55 insertions(+), 102 deletions(-) diff --git a/htdocs/js/mympd.js b/htdocs/js/mympd.js index 90a56de..26e583f 100644 --- a/htdocs/js/mympd.js +++ b/htdocs/js/mympd.js @@ -1535,16 +1535,14 @@ function parseSongDetails(obj) { modal.getElementsByTagName('h1')[0].innerText = obj.data.title; var songDetails = ''; - for (var key in settings.tags) { - if (settings.tags[key] == true) { - var value = obj.data[key.toLowerCase()]; - if (key == 'duration') { - var minutes = Math.floor(value / 60); - var seconds = value - minutes * 60; - value = minutes + ':' + (seconds < 10 ? '0' : '') + seconds; - } - songDetails += '' + key + '' + value + ''; + for (var i = 0; i < settings.tags.length; i++) { + var value = obj.data[settings.tags[i].toLowerCase()]; + if (settings.tags[i] == 'duration') { + var minutes = Math.floor(value / 60); + var seconds = value - minutes * 60; + value = minutes + ':' + (seconds < 10 ? '0' : '') + seconds; } + songDetails += '' + settings.tags[i] + '' + value + ''; } songDetails += 'Uri' + obj.data.uri + ''; @@ -1676,9 +1674,9 @@ function parseSmartPlaylist(obj) { document.getElementById('saveSmartPlaylistSticker').classList.add('hide'); document.getElementById('saveSmartPlaylistNewest').classList.add('hide'); var tagList = ''; - for (var key in settings.tags) { - if (settings.tags[key] == true && key != 'Track') { - tagList += ''; + for (var i = 0; i < settings.tags.length; i++) { + if (settings.tags[i] != 'Track') { + tagList += ''; } } document.getElementById('selectSaveSmartPlaylistTag').innerHTML = tagList; @@ -2398,9 +2396,9 @@ function addTagList(x, any) { var tagList = ''; if (any == true) tagList += ''; - for (var key in settings.tags) { - if (settings.tags[key] == true && key != 'Track') { - tagList += ''; + for (var i = 0; i < settings.tags.length; i++) { + if (settings.tags[i] != 'Track') { + tagList += ''; } } var tagListEl = document.getElementById(x); diff --git a/src/list.c b/src/list.c index a9ecd44..9652ab5 100644 --- a/src/list.c +++ b/src/list.c @@ -10,8 +10,20 @@ int list_init(struct list *l) { return 0; } +int list_get_value(const struct list *l, char *data) { + int value = 0; + struct node *current = l->list; + while (current != NULL) { + if (strcmp(current->data, data) == 0) { + value = current->value; + break; + } + current = current->next; + } + return value; +} -struct node *list_node_at(const struct list * l, unsigned index) { +struct node *list_node_at(const struct list *l, unsigned index) { /* if there's no data in the list, fail */ if (l->list == NULL) { return NULL; } struct node * current = l->list; diff --git a/src/list.h b/src/list.h index 07b09ce..1e11da9 100644 --- a/src/list.h +++ b/src/list.h @@ -15,7 +15,7 @@ int list_init(struct list *l); int list_push(struct list *l, char *data, int value); int list_replace(struct list *l, int pos, char *data, int value); int list_free(struct list *l); - +int list_get_value(const struct list *l, char *data); int list_shuffle(struct list *l); int list_swap_item(struct node *n1, struct node *n2); struct node *list_node_at(const struct list * l, unsigned index); diff --git a/src/mpd_client.c b/src/mpd_client.c index 798a07c..378ee1c 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -33,7 +33,6 @@ #include #include "mpd_client.h" -#include "list.h" #include "config.h" #include "../dist/src/frozen/frozen.h" @@ -681,15 +680,6 @@ void mympd_mpd_features() { // Defaults mpd.feat_sticker = false; - mpd.tag_artist = false; - mpd.tag_album = false; - mpd.tag_album_artist = false; - mpd.tag_title = false; - mpd.tag_track = false; - mpd.tag_genre = false; - mpd.tag_date = false; - mpd.tag_composer = false; - mpd.tag_performer = false; mpd_send_allowed_commands(mpd.conn); while ((pair = mpd_recv_command_pair(mpd.conn)) != NULL) { @@ -709,69 +699,22 @@ void mympd_mpd_features() { } printf("MPD supported tags: "); + list_free(&mpd_tags); mpd_send_list_tag_types(mpd.conn); while ((pair = mpd_recv_tag_type_pair(mpd.conn)) != NULL) { printf("%s ", pair->value); - if (strcmp(pair->value, "Artist") == 0) - mpd.tag_artist = true; - else if (strcmp(pair->value, "Album") == 0) - mpd.tag_album = true; - else if (strcmp(pair->value, "AlbumArtist") == 0) - mpd.tag_album_artist = true; - else if (strcmp(pair->value, "Title") == 0) - mpd.tag_title = true; - else if (strcmp(pair->value, "Track") == 0) - mpd.tag_track = true; - else if (strcmp(pair->value, "Genre") == 0) - mpd.tag_genre = true; - else if (strcmp(pair->value, "Date") == 0) - mpd.tag_date = true; - else if (strcmp(pair->value, "Composer") == 0) - mpd.tag_composer = true; - else if (strcmp(pair->value, "Performer") == 0) - mpd.tag_performer = true; + list_push(&mpd_tags, pair->value, 1); mpd_return_pair(mpd.conn, pair); } mpd_response_finish(mpd.conn); printf("\nmyMPD enabled tags: "); + list_free(&mympd_tags); token = strtok(str, s); while (token != NULL) { - if (strcmp(token, "Artist") == 0) { - if (mpd.tag_artist == true) printf("%s ", token); - else mpd.tag_artist = false; - } - else if (strcmp(token, "Album") == 0) { - if (mpd.tag_album == true) printf("%s ", token); - else mpd.tag_album = false; - } - else if (strcmp(token, "AlbumArtist") == 0) { - if (mpd.tag_album_artist == true) printf("%s ", token); - else mpd.tag_album_artist = false; - } - else if (strcmp(token, "Title") == 0) { - if (mpd.tag_title == true) printf("%s ", token); - else mpd.tag_title = false; - } - else if (strcmp(token, "Track") == 0) { - if (mpd.tag_track == true) printf("%s ", token); - else mpd.tag_track = false; - } - else if (strcmp(token, "Genre") == 0) { - if (mpd.tag_genre == true) printf("%s ", token); - else mpd.tag_genre = false; - } - else if (strcmp(token, "Date") == 0) { - if (mpd.tag_date == true) printf("%s ", token); - else mpd.tag_date = false; - } - else if (strcmp(token, "Composer") == 0) { - if (mpd.tag_composer == true) printf("%s ", token); - else mpd.tag_composer = false; - } - else if (strcmp(token, "Performer") == 0) { - if (mpd.tag_performer == true) printf("%s ", token); - else mpd.tag_performer = false; + if (list_get_value(&mpd_tags, token) == 1) { + list_push(&mympd_tags, token, 1); + printf("%s ", token); } token = strtok(NULL, s); } @@ -1257,6 +1200,7 @@ int mympd_put_settings(char *buffer) { struct mpd_status *status; char *replaygain = strdup(""); int len; + int nr = 0; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); status = mpd_run_status(mpd.conn); @@ -1279,9 +1223,7 @@ int mympd_put_settings(char *buffer) { "mixrampdb: %f, mixrampdelay: %f, mpdhost: %Q, mpdport: %d, passwort_set: %B, " "streamport: %d, coverimage: %Q, stickers: %B, mixramp: %B, smartpls: %B, maxElementsPerPage: %d, " "replaygain: %Q, notificationWeb: %B, notificationPage: %B, jukeboxMode: %d, jukeboxPlaylist: %Q, jukeboxQueueLength: %d, " - "tags: { Artist: %B, Album: %B, AlbumArtist: %B, Title: %B, Track: %B, Genre: %B, Date: %B," - "Composer: %B, Performer: %B }" - "}}", + "tags: [", mpd_status_get_repeat(status), mpd_status_get_single(status), mpd_status_get_crossfade(status), @@ -1303,19 +1245,20 @@ int mympd_put_settings(char *buffer) { mympd_state.notificationPage, mympd_state.jukeboxMode, mympd_state.jukeboxPlaylist, - mympd_state.jukeboxQueueLength, - mpd.tag_artist, - mpd.tag_album, - mpd.tag_album_artist, - mpd.tag_title, - mpd.tag_track, - mpd.tag_genre, - mpd.tag_date, - mpd.tag_composer, - mpd.tag_performer + mympd_state.jukeboxQueueLength ); mpd_status_free(status); free(replaygain); + + struct node *current = mympd_tags.list; + while (current != NULL) { + if (nr ++) + len += json_printf(&out, ","); + len += json_printf(&out, "%Q", current->data); + current = current->next; + } + + len += json_printf(&out, "]}}"); if (len > MAX_SIZE) printf("Buffer truncated\n"); diff --git a/src/mpd_client.h b/src/mpd_client.h index a34a2b5..472dbbe 100644 --- a/src/mpd_client.h +++ b/src/mpd_client.h @@ -26,6 +26,7 @@ #define __MPD_CLIENT_H__ #include "../dist/src/mongoose/mongoose.h" +#include "list.h" #define RETURN_ERROR_AND_RECOVER(X) do { \ printf("MPD X: %s\n", mpd_connection_get_error_message(mpd.conn)); \ @@ -137,17 +138,11 @@ struct t_mpd { const unsigned* protocol; // Supported tags bool feat_sticker; - bool tag_artist; - bool tag_album; - bool tag_album_artist; - bool tag_title; - bool tag_track; - bool tag_genre; - bool tag_date; - bool tag_composer; - bool tag_performer; } mpd; +struct list mpd_tags; +struct list mympd_tags; + typedef struct { long mpdport; const char* mpdhost; diff --git a/src/mympd.c b/src/mympd.c index 1c67c1c..94b9769 100644 --- a/src/mympd.c +++ b/src/mympd.c @@ -371,6 +371,9 @@ int main(int argc, char **argv) { return EXIT_FAILURE; read_statefiles(); + + list_init(&mpd_tags); + list_init(&mympd_tags); if (config.ssl == true) mg_set_protocol_http_websocket(nc_http); @@ -388,6 +391,8 @@ int main(int argc, char **argv) { mympd_idle(&mgr, 0); } mg_mgr_free(&mgr); + list_free(&mpd_tags); + list_free(&mympd_tags); mympd_disconnect(); return EXIT_SUCCESS; } From 53dd32c7d86a4fdd17d4c0a631948de5eadc54d3 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Tue, 9 Oct 2018 23:14:16 +0100 Subject: [PATCH 17/20] Fix: filter tag list in "browse by"-button (hide track, title, etc.) --- htdocs/js/mympd.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/htdocs/js/mympd.js b/htdocs/js/mympd.js index 26e583f..7b89c2e 100644 --- a/htdocs/js/mympd.js +++ b/htdocs/js/mympd.js @@ -2394,12 +2394,15 @@ function selectTag(btnsEl, desc, setTo) { function addTagList(x, any) { var tagList = ''; + var tagBlacklist = ["Title", "MUSICBRAINZ_TRACKID", "Count", "Disc", "Comment", "Name"]; if (any == true) tagList += ''; for (var i = 0; i < settings.tags.length; i++) { - if (settings.tags[i] != 'Track') { - tagList += ''; - } + if (settings.tags[i] == 'Track') + continue; + if (any == false && tagBlacklist.indexOf(settings.tags[i]) > -1) + continue; + tagList += ''; } var tagListEl = document.getElementById(x); tagListEl.innerHTML = tagList; From 322778655a07416716a2e49f74fdbb6264aa6d3f Mon Sep 17 00:00:00 2001 From: jcorporation Date: Tue, 9 Oct 2018 23:22:54 +0100 Subject: [PATCH 18/20] Fix: reflect taglist behaviour in mympd.conf --- contrib/mympd.conf.dist | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/mympd.conf.dist b/contrib/mympd.conf.dist index 09e5360..89ead6e 100644 --- a/contrib/mympd.conf.dist +++ b/contrib/mympd.conf.dist @@ -33,7 +33,6 @@ mixramp = false stickers = true #List of tags in myMPD gui -#Supported tags: Artist,Album,AlbumArtist,Title,Track,Genre,Date,Composer,Performer taglist = Artist,Album,AlbumArtist,Title,Track,Genre,Date,Composer,Performer #Enable smart playlists From 5e4d10a8ce14160d701394bd0d60c4574a983339 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Wed, 10 Oct 2018 21:02:46 +0100 Subject: [PATCH 19/20] Fix: set date in debian changelog --- mkdebian.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdebian.sh b/mkdebian.sh index 993bd9a..234829e 100755 --- a/mkdebian.sh +++ b/mkdebian.sh @@ -7,7 +7,7 @@ mympd (${VERSION}-1) stable; urgency=medium * Release from master - -- Juergen Mang Mon, 02 Oct 2018 00:04:00 +0200 + -- Juergen Mang $(date +"%a, %d %b %Y %H:%m:%S %z") EOL ./mkclean.sh From bfec07c86ac533b3f0f485627e2837014e586eab Mon Sep 17 00:00:00 2001 From: jcorporation Date: Wed, 10 Oct 2018 21:03:10 +0100 Subject: [PATCH 20/20] Fix: update minified files --- dist/htdocs/js/mympd.min.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/dist/htdocs/js/mympd.min.js b/dist/htdocs/js/mympd.min.js index 44205af..23c3057 100644 --- a/dist/htdocs/js/mympd.min.js +++ b/dist/htdocs/js/mympd.min.js @@ -98,9 +98,9 @@ document.getElementById(c+"ButtonsBottom").classList.add("hide"));0d?"0":"")+d}c+=""+f+""+d+""}c+='Uri'+a.data.uri+"";if(1==settings.stickers){var f="not voted";0==a.data.like?f='thumb_down_alt':2==a.data.like&&(f='thumb_up_alt');c+='StatisticsPlay count'+a.data.playCount+"Skip count"+a.data.skipCount+"Last played"+(0==a.data.lastPlayed?"never":(new Date(1E3*a.data.lastPlayed)).toUTCString())+"Like"+ -f+""}b.getElementsByTagName("tbody")[0].innerHTML=c}function playlistDetails(a){document.getElementById("BrowsePlaylistsAllList").classList.add("opacity05");appGoto("Browse","Playlists","Detail","0/-/"+a)} +function parseSongDetails(a){var b=document.getElementById("modalSongDetails");b.getElementsByClassName("album-cover")[0].style.backgroundImage='url("'+a.data.cover+'")';b.getElementsByTagName("h1")[0].innerText=a.data.title;for(var c="",d=0;de?"0":"")+e}c+=""+settings.tags[d]+""+e+""}c+='Uri'+a.data.uri+"";1==settings.stickers&&(d="not voted",0==a.data.like?d='thumb_down_alt':2==a.data.like&&(d='thumb_up_alt'),c+='StatisticsPlay count'+a.data.playCount+"Skip count"+a.data.skipCount+"Last played"+(0==a.data.lastPlayed?"never":(new Date(1E3*a.data.lastPlayed)).toUTCString())+"Like"+ +d+"");b.getElementsByTagName("tbody")[0].innerHTML=c}function playlistDetails(a){document.getElementById("BrowsePlaylistsAllList").classList.add("opacity05");appGoto("Browse","Playlists","Detail","0/-/"+a)} function removeFromPlaylist(a,b){b--;sendAPI({cmd:"MPD_API_PLAYLIST_RM_TRACK",data:{uri:a,track:b}});document.getElementById("BrowsePlaylistsDetailList").classList.add("opacity05");sendAPI({cmd:"MPD_API_PLAYLIST_CONTENT_LIST",data:{offset:app.current.page,filter:app.current.filter,uri:app.current.search}},parsePlaylists)} function playlistClear(){var a=document.getElementById("BrowsePlaylistsDetailList").getAttribute("data-uri");sendAPI({cmd:"MPD_API_PLAYLIST_CLEAR",data:{uri:a}});document.getElementById("BrowsePlaylistsDetailList").classList.add("opacity05");sendAPI({cmd:"MPD_API_PLAYLIST_CONTENT_LIST",data:{offset:app.current.page,filter:app.current.filter,uri:app.current.search}},parsePlaylists)} function getAllPlaylists(a){var b=a.data.length,c="";0==a.offset&&("addToPlaylistPlaylist"==playlistEl?c="":"selectJukeboxPlaylist"==playlistEl&&(c=""));for(var d=0;d";0==a.offset?document.getElementById(playlistEl).innerHTML=c:document.getElementById(playlistEl).innerHTML+=c;a.totalEntities> @@ -111,8 +111,8 @@ function setVoteSongBtns(a,b){""==b||0==b.indexOf("http://")||0==b.indexOf("http function toggleAddToPlaylistFrm(){var a=document.getElementById("toggleAddToPlaylistBtn");toggleBtn("toggleAddToPlaylistBtn");a.classList.contains("active")?(document.getElementById("addToPlaylistFrm").classList.remove("hide"),document.getElementById("addStreamFooter").classList.add("hide"),document.getElementById("addToPlaylistFooter").classList.remove("hide")):(document.getElementById("addToPlaylistFrm").classList.add("hide"),document.getElementById("addStreamFooter").classList.remove("hide"),document.getElementById("addToPlaylistFooter").classList.add("hide"))} function saveSearchAsSmartPlaylist(){parseSmartPlaylist({type:"smartpls",data:{playlist:"",type:"search",tag:app.current.filter,searchstr:app.current.search}})} function parseSmartPlaylist(a){var b=document.getElementById("saveSmartPlaylistName");b.value=a.data.playlist;b.classList.remove("is-invalid");document.getElementById("saveSmartPlaylistType").value=a.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 c='',d;for(d in settings.tags)1==settings.tags[d]&&"Track"!=d&&(c+='");document.getElementById("selectSaveSmartPlaylistTag").innerHTML=c;"search"==a.data.type?(document.getElementById("saveSmartPlaylistSearch").classList.remove("hide"),document.getElementById("selectSaveSmartPlaylistTag").value=a.data.tag,document.getElementById("inputSaveSmartPlaylistSearchstr").value=a.data.searchstr):"sticker"==a.data.type?(document.getElementById("saveSmartPlaylistSticker").classList.remove("hide"), -document.getElementById("selectSaveSmartPlaylistSticker").value=a.data.sticker,document.getElementById("inputSaveSmartPlaylistStickerMaxentries").value=a.data.maxentries):"newest"==a.data.type&&(document.getElementById("saveSmartPlaylistNewest").classList.remove("hide"),a=a.data.timerange/24/60/60,document.getElementById("inputSaveSmartPlaylistNewestTimerange").value=a);modalSaveSmartPlaylist.show();b.focus()} +for(var c='',d=0;d'+settings.tags[d]+"");document.getElementById("selectSaveSmartPlaylistTag").innerHTML=c;"search"==a.data.type?(document.getElementById("saveSmartPlaylistSearch").classList.remove("hide"),document.getElementById("selectSaveSmartPlaylistTag").value=a.data.tag,document.getElementById("inputSaveSmartPlaylistSearchstr").value=a.data.searchstr):"sticker"== +a.data.type?(document.getElementById("saveSmartPlaylistSticker").classList.remove("hide"),document.getElementById("selectSaveSmartPlaylistSticker").value=a.data.sticker,document.getElementById("inputSaveSmartPlaylistStickerMaxentries").value=a.data.maxentries):"newest"==a.data.type&&(document.getElementById("saveSmartPlaylistNewest").classList.remove("hide"),a=a.data.timerange/24/60/60,document.getElementById("inputSaveSmartPlaylistNewestTimerange").value=a);modalSaveSmartPlaylist.show();b.focus()} function chkInt(a,b){if(""!=a.value.replace(/\d/g,""))return a.classList.add("is-invalid"),b.classList.add("was-validated"),!1;a.classList.remove("is-invalid");return!0} function saveSmartPlaylist(){var a=document.getElementById("saveSmartPlaylistName").value,b=document.getElementById("saveSmartPlaylistType").value,c=a.replace(/[\w\-]/g,""),d=document.getElementById("saveSmartPlaylistFrm");if(""!=a&&""==c){if("search"==b)d=document.getElementById("selectSaveSmartPlaylistTag"),d=d.options[d.selectedIndex].value,c=document.getElementById("inputSaveSmartPlaylistSearchstr").value,sendAPI({cmd:"MPD_API_SMARTPLS_SAVE",data:{type:b,playlist:a,tag:d,searchstr:c}});else if("sticker"== b){c=document.getElementById("selectSaveSmartPlaylistSticker");c=c.options[c.selectedIndex].value;var e=document.getElementById("inputSaveSmartPlaylistStickerMaxentries");if(!chkInt(e,d))return;sendAPI({cmd:"MPD_API_SMARTPLS_SAVE",data:{type:b,playlist:a,sticker:c,maxentries:e.value}})}else if("newest"==b){c=document.getElementById("inputSaveSmartPlaylistNewestTimerange");if(!chkInt(c,d))return;d=86400*parseInt(c.value);sendAPI({cmd:"MPD_API_SMARTPLS_SAVE",data:{type:b,playlist:a,timerange:d}})}else{document.getElementById("saveSmartPlaylistType").classList.add("is-invalid"); @@ -159,5 +159,6 @@ domCache.currentArtist.innerText="";"undefined"!=typeof a.data.album&&0=c;c++)b+='";a=document.getElementById(a);a.innerHTML=b;a.addEventListener("click",function(a){switch(a.target.innerText){case "delete":b="-";break;case "#":b="0";break;default:b=a.target.innerText}appGoto(app.current.app, app.current.tab,app.current.view,"0/"+b+"/"+app.current.search)},!1)}function selectTag(a,b,c){a=document.getElementById(a);var d=a.querySelector(".active");d&&d.classList.remove("active");if(d=a.querySelector("[data-tag="+c+"]"))d.classList.add("active"),document.getElementById(b).innerText=d.innerText} -function addTagList(a,b){var c="";1==b&&(c+='');for(var d in settings.tags)1==settings.tags[d]&&"Track"!=d&&(c+='");document.getElementById(a).innerHTML=c}function gotoTagList(){appGoto(app.current.app,app.current.tab,app.current.view,"0/-/")} -function chVolume(a){a=parseInt(domCache.volumeBar.value)+a;0>a?a=0:100d?"0":""):"")+d+"\u2009m "+(10>a?"0":"")+a+"\u2009s"}function genId(a){return"id"+a.replace(/[^\w\-]/g,"")}appInit(); +function addTagList(a,b){var c="",d="Title MUSICBRAINZ_TRACKID Count Disc Comment Name".split(" ");1==b&&(c+='');for(var e=0;e'+settings.tags[e]+""));document.getElementById(a).innerHTML=c} +function gotoTagList(){appGoto(app.current.app,app.current.tab,app.current.view,"0/-/")}function chVolume(a){a=parseInt(domCache.volumeBar.value)+a;0>a?a=0:100d?"0":""):"")+d+"\u2009m "+(10>a?"0":"")+a+"\u2009s"} +function genId(a){return"id"+a.replace(/[^\w\-]/g,"")}appInit();