From 03dcfb1269d712d02d9d254c476dd1e0b255173c Mon Sep 17 00:00:00 2001 From: jcorporation Date: Mon, 3 Sep 2018 19:02:12 +0100 Subject: [PATCH 01/24] Fix: central search backend - MPD_API_DATABASE_SEARCH removed: MPD_API_DATABASE_SEARCH_ADD_PLAYLIST removed: MPD_API_DATABASE_SEARCH_ADD_QUEUE --- htdocs/index.html | 16 ++--- htdocs/js/mympd.js | 24 ++++---- src/mpd_client.c | 144 +++++++++++++-------------------------------- src/mpd_client.h | 6 +- 4 files changed, 60 insertions(+), 130 deletions(-) diff --git a/htdocs/index.html b/htdocs/index.html index d8af53f..d1d17dd 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -135,10 +135,10 @@ @@ -438,10 +438,10 @@ diff --git a/htdocs/js/mympd.js b/htdocs/js/mympd.js index 055c0c2..5af0907 100644 --- a/htdocs/js/mympd.js +++ b/htdocs/js/mympd.js @@ -36,7 +36,7 @@ var dragEl; var app = {}; app.apps = { "Playback": { "state": "0/-/", "scrollPos": 0 }, - "Queue": { "state": "0/Any Tag/", "scrollPos": 0 }, + "Queue": { "state": "0/any/", "scrollPos": 0 }, "Browse": { "active": "Database", "tabs": { "Filesystem": { "state": "0/-/", "scrollPos": 0 }, @@ -54,7 +54,7 @@ app.apps = { "Playback": { "state": "0/-/", "scrollPos": 0 }, } } }, - "Search": { "state": "0/Any Tag/", "scrollPos": 0 } + "Search": { "state": "0/any/", "scrollPos": 0 } }; app.current = { "app": "Playback", "tab": undefined, "view": undefined, "page": 0, "filter": "", "search": "", "scrollPos": 0 }; @@ -197,7 +197,7 @@ function appRoute() { var btnsLen = btns.length; for (var i = 0; i < btnsLen; i++) { btns[i].classList.remove('active'); - if (btns[i].innerText == app.current.filter) { + if (btns[i].getAttribute('data-tag') == app.current.filter) { btns[i].classList.add('active'); document.getElementById('searchqueuetagdesc').innerText = btns[i].innerText; } @@ -266,7 +266,7 @@ function appRoute() { } if (app.current.search.length >= 2) { - sendAPI({"cmd": "MPD_API_DATABASE_SEARCH", "data": { "mpdtag": app.current.filter, "offset": app.current.page, "searchstr": app.current.search}}, parseSearch); + sendAPI({"cmd": "MPD_API_DATABASE_SEARCH", "data": { "plist": "", "offset": app.current.page, "filter": app.current.filter, "searchstr": app.current.search}}, parseSearch); } else { document.getElementById('SearchList').getElementsByTagName('tbody')[0].innerHTML = ''; document.getElementById('searchAddAllSongs').setAttribute('disabled', 'disabled'); @@ -280,7 +280,7 @@ function appRoute() { var btnsLen = btns.length; for (var i = 0; i < btnsLen; i++) { btns[i].classList.remove('active'); - if (btns[i].innerText == app.current.filter) { + if (btns[i].getAttribute('data-tag') == app.current.filter) { btns[i].classList.add('active'); document.getElementById('searchtagsdesc').innerText = btns[i].innerText; } @@ -486,7 +486,7 @@ function appInit() { document.getElementById('searchtags').addEventListener('click', function(event) { if (event.target.nodeName == 'BUTTON') - appGoto(app.current.app, app.current.tab, app.current.view, '0/' + event.target.innerText + '/' + app.current.search); + appGoto(app.current.app, app.current.tab, app.current.view, '0/' + event.target.getAttribute('data-tag') + '/' + app.current.search); }, false); document.getElementById('searchqueuestr').addEventListener('keyup', function(event) { @@ -495,7 +495,7 @@ function appInit() { document.getElementById('searchqueuetag').addEventListener('click', function (event) { if (event.target.nodeName == 'BUTTON') - appGoto(app.current.app, app.current.tab, app.current.view, app.current.page + '/' + event.target.innerText + '/' + app.current.search); + appGoto(app.current.app, app.current.tab, app.current.view, app.current.page + '/' + event.target.getAttribute('data-tag') + '/' + app.current.search); }, false); document.getElementById('search').addEventListener('submit', function () { @@ -980,7 +980,7 @@ function parseState(obj) { function getQueue() { if (app.current.search.length >= 2) - sendAPI({"cmd": "MPD_API_QUEUE_SEARCH", "data": {"mpdtag": app.current.filter, "offset": app.current.page, "searchstr": app.current.search}}, parseQueue); + sendAPI({"cmd": "MPD_API_QUEUE_SEARCH", "data": {"filter": app.current.filter, "offset": app.current.page, "searchstr": app.current.search}}, parseQueue); else { sendAPI({"cmd": "MPD_API_QUEUE_LIST", "data": {"offset": app.current.page}}, parseQueue); } @@ -1890,18 +1890,14 @@ function addAllFromBrowse() { function addAllFromSearch() { if (app.current.search.length >= 2) { - sendAPI({"cmd": "MPD_API_DATABASE_SEARCH_ADD_QUEUE", "data":{"filter": app.current.filter, "searchstr": app.current.search}}); + sendAPI({"cmd": "MPD_API_DATABASE_SEARCH", "data": {"plist": "queue", "filter": app.current.filter, "searchstr": app.current.search, "offset": 0}}); showNotification('Added '+ parseInt(document.getElementById('panel-heading-search').innerText) +' songs from search', '', '', 'success'); } } function addAllFromSearchPlist(plist) { if (app.current.search.length >= 2) { - var filter = app.current.filter; - if (filter == 'Any Tag') - filter = 'any'; - - sendAPI({"cmd": "MPD_API_DATABASE_SEARCH_ADD_PLAYLIST", "data":{"plist": plist, "filter": filter, "searchstr": app.current.search}}); + sendAPI({"cmd": "MPD_API_DATABASE_SEARCH", "data": {"plist": plist, "filter": app.current.filter, "searchstr": app.current.search, "offset": 0}}); showNotification('Added '+ parseInt(document.getElementById('panel-heading-search').innerText) +' songs from search to ' + plist, '', '', 'success'); } } diff --git a/src/mpd_client.c b/src/mpd_client.c index cb2c929..7d2c10f 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -431,38 +431,17 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) { } break; case MPD_API_QUEUE_SEARCH: - je = json_scanf(msg.p, msg.len, "{data: {offset:%u, mpdtag:%Q, searchstr:%Q}}", &uint_buf1, &p_charbuf1, &p_charbuf2); + je = json_scanf(msg.p, msg.len, "{data: {offset:%u, filter:%Q, searchstr:%Q}}", &uint_buf1, &p_charbuf1, &p_charbuf2); if (je == 3) { n = mympd_search_queue(mpd.buf, p_charbuf1, uint_buf1, p_charbuf2); free(p_charbuf1); free(p_charbuf2); } break; - case MPD_API_DATABASE_SEARCH_ADD_QUEUE: - je = json_scanf(msg.p, msg.len, "{data: {filter:%Q, searchstr:%Q}}", &p_charbuf1, &p_charbuf2); - if (je == 2) { - n = mympd_search_add(mpd.buf, p_charbuf1, p_charbuf2); - free(p_charbuf1); - free(p_charbuf2); - if (n == 0) - n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); - } - break; - case MPD_API_DATABASE_SEARCH_ADD_PLAYLIST: - je = json_scanf(msg.p, msg.len, "{data: {plist:%Q, filter:%Q, searchstr:%Q}}", &p_charbuf1, &p_charbuf2, &p_charbuf3); - if (je == 3) { - n = mympd_search_add_plist(p_charbuf1, p_charbuf2, p_charbuf3); - free(p_charbuf1); - free(p_charbuf2); - free(p_charbuf3); - if (n == 0) - n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); - } - break; case MPD_API_DATABASE_SEARCH: - je = json_scanf(msg.p, msg.len, "{data: {offset:%u, mpdtag:%Q, searchstr:%Q}}", &uint_buf1, &p_charbuf1, &p_charbuf2); - if (je == 3) { - n = mympd_search(mpd.buf, p_charbuf1, uint_buf1, p_charbuf2); + je = json_scanf(msg.p, msg.len, "{data: {searchstr:%Q, filter:%Q, plist:%Q, offset:%u}}", &p_charbuf1, &p_charbuf2, &p_charbuf3, &uint_buf1); + if (je == 4) { + n = mympd_search(mpd.buf, p_charbuf1, p_charbuf2, p_charbuf3, uint_buf1); free(p_charbuf1); free(p_charbuf2); } @@ -1503,31 +1482,29 @@ int mympd_put_playlist_list(char *buffer, char *uri, unsigned int offset, char * return len; } -int mympd_search(char *buffer, char *mpdtagtype, unsigned int offset, char *searchstr) { +int mympd_search(char *buffer, char *searchstr, char *filter, char *plist, unsigned int offset) { struct mpd_song *song; unsigned long entity_count = 0; unsigned long entities_returned = 0; int len; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); - - if (mpd_search_db_songs(mpd.conn, false) == false) - RETURN_ERROR_AND_RECOVER("mpd_search_db_songs"); - if (mpd_tag_name_parse(mpdtagtype) != MPD_TAG_UNKNOWN) { - if (mpd_search_add_tag_constraint(mpd.conn, MPD_OPERATOR_DEFAULT, mpd_tag_name_parse(mpdtagtype), searchstr) == false) - RETURN_ERROR_AND_RECOVER("mpd_search_add_tag_constraint"); + if (strcmp(plist, "") == 0) { + if (mpd_send_command(mpd.conn, "search", filter, searchstr, NULL) == false) + RETURN_ERROR_AND_RECOVER("mpd_search"); + len = json_printf(&out, "{type: search, data: ["); + } + else if (strcmp(plist, "queue") == 0) { + if (mpd_send_command(mpd.conn, "searchadd", filter, searchstr, NULL) == false) + RETURN_ERROR_AND_RECOVER("mpd_searchadd"); } else { - if (mpd_search_add_any_tag_constraint(mpd.conn, MPD_OPERATOR_DEFAULT, searchstr) == false) - RETURN_ERROR_AND_RECOVER("mpd_search_add_any_tag_constraint"); - } - - if (mpd_search_commit(mpd.conn) == false) - RETURN_ERROR_AND_RECOVER("mpd_search_commit"); - else { - len = json_printf(&out, "{type: search, data: ["); + if (mpd_send_command(mpd.conn, "searchaddpl", plist, filter, searchstr, NULL) == false) + RETURN_ERROR_AND_RECOVER("mpd_searchaddpl"); + } - while((song = mpd_recv_song(mpd.conn)) != NULL) { + if (strcmp(plist, "") == 0) { + while ((song = mpd_recv_song(mpd.conn)) != NULL) { entity_count ++; if (entity_count > offset && entity_count <= offset + MAX_ELEMENTS_PER_PAGE) { if (entities_returned ++) @@ -1543,59 +1520,20 @@ int mympd_search(char *buffer, char *mpdtagtype, unsigned int offset, char *sear } mpd_song_free(song); } + } + else + mpd_response_finish(mpd.conn); - len += json_printf(&out, "], totalEntities: %d, offset: %d, returnedEntities: %d, mpdtagtype: %Q}", + if (strcmp(plist, "") == 0) { + len += json_printf(&out, "], totalEntities: %d, offset: %d, returnedEntities: %d, searchstr: %Q}", entity_count, offset, entities_returned, - mpdtagtype + searchstr ); - } - - if (len > MAX_SIZE) - printf("Buffer truncated\n"); - return len; -} - -int mympd_search_add(char *buffer, char *mpdtagtype, char *searchstr) { - int len = 0; - struct mpd_song *song; - struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); - - if (mpd_search_add_db_songs(mpd.conn, false) == false) { - RETURN_ERROR_AND_RECOVER("mpd_search_add_db_songs"); - } - - if (mpd_tag_name_parse(mpdtagtype) != MPD_TAG_UNKNOWN) { - if (mpd_search_add_tag_constraint(mpd.conn, MPD_OPERATOR_DEFAULT, mpd_tag_name_parse(mpdtagtype), searchstr) == false) - RETURN_ERROR_AND_RECOVER("mpd_search_add_tag_constraint"); - } - else { - if (mpd_search_add_any_tag_constraint(mpd.conn, MPD_OPERATOR_DEFAULT, searchstr) == false) - RETURN_ERROR_AND_RECOVER("mpd_search_add_any_tag_constraint"); - } - - if (mpd_search_commit(mpd.conn) == false) - RETURN_ERROR_AND_RECOVER("mpd_search_commit"); - - while((song = mpd_recv_song(mpd.conn)) != NULL) { - mpd_song_free(song); - } - - if (len > MAX_SIZE) - printf("Buffer truncated\n"); - return len; -} - -int mympd_search_add_plist(char *plist, char *mpdtagtype, char *searchstr) { - int len = 0; - struct mpd_pair *pair; - - mpd_send_command(mpd.conn, "searchaddpl", plist, mpdtagtype, searchstr, NULL); - - while ((pair = mpd_recv_pair(mpd.conn)) != NULL) { - mpd_return_pair(mpd.conn, pair); - } + } + else + len = json_printf(&out, "{type: result, data: ok}"); if (len > MAX_SIZE) printf("Buffer truncated\n"); @@ -1657,20 +1595,20 @@ int mympd_search_queue(char *buffer, char *mpdtagtype, unsigned int offset, char len = json_printf(&out, "{type: queuesearch, data: ["); while((song = mpd_recv_song(mpd.conn)) != NULL) { - entity_count ++; - if (entity_count > offset && entity_count <= offset + MAX_ELEMENTS_PER_PAGE) { - if (entities_returned ++) - len += json_printf(&out, ", "); - len += json_printf(&out, "{type: song, id: %d, pos: %d, album: %Q, artist: %Q, duration: %d, title: %Q}", - mpd_song_get_id(song), - mpd_song_get_pos(song), - mympd_get_tag(song, MPD_TAG_ALBUM), - mympd_get_tag(song, MPD_TAG_ARTIST), - mpd_song_get_duration(song), - mympd_get_tag(song, MPD_TAG_TITLE) - ); - mpd_song_free(song); - } + entity_count ++; + if (entity_count > offset && entity_count <= offset + MAX_ELEMENTS_PER_PAGE) { + if (entities_returned ++) + len += json_printf(&out, ", "); + len += json_printf(&out, "{type: song, id: %d, pos: %d, album: %Q, artist: %Q, duration: %d, title: %Q}", + mpd_song_get_id(song), + mpd_song_get_pos(song), + mympd_get_tag(song, MPD_TAG_ALBUM), + mympd_get_tag(song, MPD_TAG_ARTIST), + mpd_song_get_duration(song), + mympd_get_tag(song, MPD_TAG_TITLE) + ); + mpd_song_free(song); + } } len += json_printf(&out, "], totalEntities: %d, offset: %d, returnedEntities: %d, mpdtagtype: %Q}", diff --git a/src/mpd_client.h b/src/mpd_client.h index 1e1feaa..7764782 100644 --- a/src/mpd_client.h +++ b/src/mpd_client.h @@ -72,8 +72,6 @@ X(MPD_API_PLAYLIST_RM_TRACK) \ X(MPD_API_PLAYLIST_LIST) \ X(MPD_API_PLAYLIST_CONTENT_LIST) \ - X(MPD_API_DATABASE_SEARCH_ADD_PLAYLIST) \ - X(MPD_API_DATABASE_SEARCH_ADD_QUEUE) \ X(MPD_API_DATABASE_SEARCH) \ X(MPD_API_DATABASE_UPDATE) \ X(MPD_API_DATABASE_FILESYSTEM_LIST) \ @@ -177,9 +175,7 @@ int mympd_put_outputs(char *buffer); int mympd_put_current_song(char *buffer); int mympd_put_queue(char *buffer, unsigned int offset, unsigned *queue_version, unsigned *queue_length); int mympd_put_browse(char *buffer, char *path, unsigned int offset, char *filter); -int mympd_search(char *buffer, char *mpdtagtype, unsigned int offset, char *searchstr); -int mympd_search_add(char *buffer, char *mpdtagtype, char *searchstr); -int mympd_search_add_plist(char *plist, char *mpdtagtype, char *searchstr); +int mympd_search(char *buffer, char *searchstr, char *filter, char *plist, unsigned int offset); int mympd_search_queue(char *buffer, char *mpdtagtype, unsigned int offset, char *searchstr); int mympd_put_welcome(char *buffer); int mympd_put_stats(char *buffer); From 75af2ada6091578f50b74af321304a4bc544319d Mon Sep 17 00:00:00 2001 From: jcorporation Date: Mon, 3 Sep 2018 21:01:50 +0100 Subject: [PATCH 02/24] Feat: Album actions in menu in search card #42 --- dist/htdocs/css/mympd.min.css | 2 +- dist/htdocs/index.html | 2 +- dist/htdocs/js/mympd.min.js | 65 +++++++++++---------- htdocs/css/mympd.css | 8 +++ htdocs/index.html | 34 +++++------ htdocs/js/mympd.js | 104 +++++++++++++++++++++------------- src/mpd_client.c | 2 +- 7 files changed, 129 insertions(+), 88 deletions(-) diff --git a/dist/htdocs/css/mympd.min.css b/dist/htdocs/css/mympd.min.css index 5c15b83..790bf06 100644 --- a/dist/htdocs/css/mympd.min.css +++ b/dist/htdocs/css/mympd.min.css @@ -1 +1 @@ -html{position:relative;min-height:100%}body{margin-bottom:60px;padding-top:50px;padding-bottom:50px;background-color:#888}main{padding-top:20px}footer{position:absolute;bottom:0}button{overflow:hidden}#BrowseBreadrumb{overflow:auto;white-space:nowrap}#BrowseBreadcrumb>li>a{cursor:pointer}.card{min-height:350px}@media only screen and (max-width:576px){.header-logo{display:none!important}}.clickable{cursor:pointer}.tblnum,.tblaction{width:30px}small{color:#aaa}.card-footer-playback{padding:0}.album-cover{background-size:cover;border:1px solid black;border-radius:5px;overflow:hidden;width:240px;height:240px;background-color:#eee;float:left;margin-right:20px;margin-bottom:20px}.album-desc{min-width:240px;float:left}.hide{display:none!important}.pull-right{float:right!important}.card-toolbar{margin-bottom:10px}.card-toolbar>div,.card-toolbar>form{margin-bottom:5px}@font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(/assets/MaterialIcons-Regular.eot);src:local('Material Icons'),local('MaterialIcons-Regular');src:url(/assets/MaterialIcons-Regular.woff2) format('woff2'),url(/assets/MaterialIcons-Regular.woff) format('woff'),url(/assets/MaterialIcons-Regular.ttf) format('truetype')}.material-icons{font-family:'Material Icons';font-weight:normal;font-style:normal;font-size:18px;display:inline-block;line-height:1;text-transform:none;letter-spacing:normal;word-wrap:normal;white-space:nowrap;direction:ltr;vertical-align:top;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;font-feature-settings:'liga'}.material-icons-small{font-size:16px}.color-darkgrey,.color-darkgrey:hover{color:#6c757d!important}#btn-outputs-block>button{margin-bottom:10px}#btn-outputs-block>button:last-child{margin-bottom:0}.card-body{overflow-x:hidden}.progressBarPlay{font-size:22px}#counter{cursor:text}#volumeBar{margin-top:2px;width:160px}.title-icon{float:left;margin-right:5px;font-size:1.8rem}.header-logo{font-size:2rem;float:left;margin-right:5px}.letters>button{width:28px;height:28px}.col-md{max-width:250px;min-width:250px}a.card-img-top{overflow:hidden;display:block}button.active{color:#fff;background-color:#28a745!important;border-color:#28a745!important}button.active-fg-green{color:#28a745!important}button.active-fg-red{color:#bd2130!important}div#alertBox{position:fixed;top:50px;right:10px;width:80%;max-width:400px;z-index:1000;opacity:0;visibility:visible;transition:opacity .5s ease-in}div.alertBoxActive{opacity:1!important;visibility:visible!important;transition:opacity .5s ease-in}.popover-content{padding-top:4px;padding-bottom:4px}.opacity05{opacity:.5}caption{caption-side:top;font-size:120%;font-weight:bold;color:black}.dragover>td{border-top:25px solid transparent}[draggable]{-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;user-select:none;-khtml-user-drag:element;-webkit-user-drag:element}@keyframes changewidth{0%{margin-left:-20px}to{margin-left:100%}}#updateDBprogress{width:20px}.updateDBprogressAnimate{animation-duration:2s;animation-name:changewidth;animation-iteration-count:infinite} \ No newline at end of file +html{position:relative;min-height:100%}body{margin-bottom:60px;padding-top:50px;padding-bottom:50px;background-color:#888}main{padding-top:20px}footer{position:absolute;bottom:0}button{overflow:hidden}#BrowseBreadrumb{overflow:auto;white-space:nowrap}#BrowseBreadcrumb>li>a{cursor:pointer}.card{min-height:350px}@media only screen and (max-width:576px){.header-logo{display:none!important}}.clickable{cursor:pointer}.tblnum,.tblaction{width:30px}small{color:#aaa}.card-footer-playback{padding:0}.album-cover{background-size:cover;border:1px solid black;border-radius:5px;overflow:hidden;width:240px;height:240px;background-color:#eee;float:left;margin-right:20px;margin-bottom:20px}.album-desc{min-width:240px;float:left}.hide{display:none!important}.pull-right{float:right!important}.card-toolbar{margin-bottom:10px}.card-toolbar>div,.card-toolbar>form{margin-bottom:5px}@font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(/assets/MaterialIcons-Regular.eot);src:local('Material Icons'),local('MaterialIcons-Regular');src:url(/assets/MaterialIcons-Regular.woff2) format('woff2'),url(/assets/MaterialIcons-Regular.woff) format('woff'),url(/assets/MaterialIcons-Regular.ttf) format('truetype')}.material-icons{font-family:'Material Icons';font-weight:normal;font-style:normal;font-size:18px;display:inline-block;line-height:1;text-transform:none;letter-spacing:normal;word-wrap:normal;white-space:nowrap;direction:ltr;vertical-align:top;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;font-feature-settings:'liga'}.material-icons-small{font-size:16px}.color-darkgrey,.color-darkgrey:hover{color:#6c757d!important}#btn-outputs-block>button{margin-bottom:10px}#btn-outputs-block>button:last-child{margin-bottom:0}.card-body{overflow-x:hidden}.progressBarPlay{font-size:22px}#counter{cursor:text}#volumeBar{margin-top:2px;width:160px}.title-icon{float:left;margin-right:5px;font-size:1.8rem}.header-logo{font-size:2rem;float:left;margin-right:5px}.letters>button{width:28px;height:28px}.col-md{max-width:250px;min-width:250px}a.card-img-top{overflow:hidden;display:block}button.active{color:#fff;background-color:#28a745!important;border-color:#28a745!important}button.active-fg-green{color:#28a745!important}button.active-fg-red{color:#bd2130!important}div#alertBox{position:fixed;top:50px;right:10px;width:80%;max-width:400px;z-index:1000;opacity:0;visibility:visible;transition:opacity .5s ease-in}div.alertBoxActive{opacity:1!important;visibility:visible!important;transition:opacity .5s ease-in}.popover-content{padding-top:4px;padding-bottom:4px}.opacity05{opacity:.5}caption{caption-side:top;font-size:120%;font-weight:bold;color:black}.dragover>td{border-top:25px solid transparent}[draggable]{-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;user-select:none;-khtml-user-drag:element;-webkit-user-drag:element}@keyframes changewidth{0%{margin-left:-20px}to{margin-left:100%}}#updateDBprogress{width:20px}.updateDBprogressAnimate{animation-duration:2s;animation-name:changewidth;animation-iteration-count:infinite}.modal-body{overflow-x:hidden}.modal-body .album-cover{float:none} \ No newline at end of file diff --git a/dist/htdocs/index.html b/dist/htdocs/index.html index e328c3b..142f73d 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 6cb1c2b..99eede7 100644 --- a/dist/htdocs/js/mympd.min.js +++ b/dist/htdocs/js/mympd.min.js @@ -5,7 +5,7 @@ $jscomp.iteratorPrototype=function(a){$jscomp.initSymbolIterator();a={next:a};a[ $jscomp.checkStringArgs=function(a,b,c){if(null==a)throw new TypeError("The 'this' value for String.prototype."+c+" must not be null or undefined");if(b instanceof RegExp)throw new TypeError("First argument to String.prototype."+c+" must not be a regular expression");return a+""}; $jscomp.polyfill=function(a,b,c,e){if(b){c=$jscomp.global;a=a.split(".");for(e=0;ea||1342177279>>=1)b+=b;return e}},"es6","es3"); -var socket,lastSong="",lastState,currentSong={},playstate="",settings={},alertTimeout,progressTimer,deferredPrompt,dragEl,app={apps:{Playback:{state:"0/-/",scrollPos:0},Queue:{state:"0/Any Tag/",scrollPos:0},Browse:{active:"Database",tabs:{Filesystem:{state:"0/-/",scrollPos:0},Playlists:{active:"All",views:{All:{state:"0/-/",scrollPos:0},Detail:{state:"0/-/",scrollPos:0}}},Database:{active:"Artist",views:{Artist:{state:"0/-/",scrollPos:0},Album:{state:"0/-/",scrollPos:0}}}}},Search:{state:"0/Any Tag/", +var socket,lastSong="",lastState,currentSong={},playstate="",settings={},alertTimeout,progressTimer,deferredPrompt,dragEl,popoverInit,app={apps:{Playback:{state:"0/-/",scrollPos:0},Queue:{state:"0/any/",scrollPos:0},Browse:{active:"Database",tabs:{Filesystem:{state:"0/-/",scrollPos:0},Playlists:{active:"All",views:{All:{state:"0/-/",scrollPos:0},Detail:{state:"0/-/",scrollPos:0}}},Database:{active:"Artist",views:{Artist:{state:"0/-/",scrollPos:0},Album:{state:"0/-/",scrollPos:0}}}}},Search:{state:"0/any/", scrollPos:0}},current:{app:"Playback",tab:void 0,view:void 0,page:0,filter:"",search:"",scrollPos:0},last:{app:void 0,tab:void 0,view:void 0,filter:"",search:"",scrollPos:0}},domCache={};domCache.navbarBottomBtns=document.getElementById("navbar-bottom").getElementsByTagName("div");domCache.navbarBottomBtnsLen=domCache.navbarBottomBtns.length;domCache.panelHeadingBrowse=document.getElementById("panel-heading-browse").getElementsByTagName("a");domCache.panelHeadingBrowseLen=domCache.panelHeadingBrowse.length; domCache.counter=document.getElementById("counter");domCache.volumePrct=document.getElementById("volumePrct");domCache.volumeControl=document.getElementById("volumeControl");domCache.volumeIcon=document.getElementById("volumeIcon");domCache.btnsPlay=document.getElementsByClassName("btnPlay");domCache.btnsPlayLen=domCache.btnsPlay.length;domCache.btnPrev=document.getElementById("btnPrev");domCache.btnNext=document.getElementById("btnNext");domCache.progressBar=document.getElementById("progressBar"); domCache.volumeBar=document.getElementById("volumeBar");domCache.outputs=document.getElementById("outputs");domCache.btnAdd=document.getElementById("nav-add2homescreen");domCache.currentTrack=document.getElementById("currentTrack");domCache.currentArtist=document.getElementById("currentArtist");domCache.currentAlbum=document.getElementById("currentAlbum");domCache.currentCover=document.getElementById("currentCover");domCache.btnVoteUp=document.getElementById("btnVoteUp");domCache.btnVoteDown=document.getElementById("btnVoteDown"); @@ -17,30 +17,30 @@ function appGoto(a,b,c,e){var d=document.body.scrollTop?document.body.scrollTop: (void 0==b&&(b=app.apps[a].active),app.apps[a].tabs[b].views?(void 0==c&&(c=app.apps[a].tabs[b].active),a="/"+a+"/"+b+"/"+c+"!"+(void 0==e?app.apps[a].tabs[b].views[c].state:e)):a="/"+a+"/"+b+"!"+(void 0==e?app.apps[a].tabs[b].state:e)):a="/"+a+"!"+(void 0==e?app.apps[a].state:e);location.hash=a} function appRoute(){var a;if(a=decodeURI(location.hash).match(/^#\/(\w+)\/?(\w+)?\/?(\w+)?!((\d+)\/([^\/]+)\/(.*))$/)){app.current.app=a[1];app.current.tab=a[2];app.current.view=a[3];app.apps[app.current.app].state?(app.apps[app.current.app].state=a[4],app.current.scrollPos=app.apps[app.current.app].scrollPos):app.apps[app.current.app].tabs[app.current.tab].state?(app.apps[app.current.app].tabs[app.current.tab].state=a[4],app.apps[app.current.app].active=app.current.tab,app.current.scrollPos=app.apps[app.current.app].tabs[app.current.tab].scrollPos): app.apps[app.current.app].tabs[app.current.tab].views[app.current.view].state&&(app.apps[app.current.app].tabs[app.current.tab].views[app.current.view].state=a[4],app.apps[app.current.app].active=app.current.tab,app.apps[app.current.app].tabs[app.current.tab].active=app.current.view,app.current.scrollPos=app.apps[app.current.app].tabs[app.current.tab].views[app.current.view].scrollPos);app.current.page=parseInt(a[5]);app.current.filter=a[6];app.current.search=a[7];appPrepare(app.current.scrollPos); -if("Playback"==app.current.app)sendAPI({cmd:"MPD_API_PLAYER_CURRENT_SONG"},songChange);else if("Queue"==app.current.app){var b=document.getElementById("searchqueuetag").getElementsByTagName("button"),c=b.length;for(a=0;a'+c[a]+"";break}d+=c[a];b+='";d+="/"}a=document.getElementById("BrowseBreadcrumb");a.innerHTML=b;b=a.getElementsByTagName("a");c=b.length;for(a=0;asearchSearching...'),2<=app.current.search.length?sendAPI({cmd:"MPD_API_DATABASE_SEARCH",data:{mpdtag:app.current.filter, -offset:app.current.page,searchstr:app.current.search}},parseSearch):(document.getElementById("SearchList").getElementsByTagName("tbody")[0].innerHTML="",document.getElementById("searchAddAllSongs").setAttribute("disabled","disabled"),document.getElementById("searchAddAllSongsBtn").setAttribute("disabled","disabled"),document.getElementById("panel-heading-search").innerText="",document.getElementById("SearchList").classList.remove("opacity05"),setPagination(0)),b=document.getElementById("searchtags").getElementsByTagName("button"), -c=b.length,a=0;asearchSearching...'),2<=app.current.search.length?sendAPI({cmd:"MPD_API_DATABASE_SEARCH",data:{plist:"",offset:app.current.page, +filter:app.current.filter,searchstr:app.current.search}},parseSearch):(document.getElementById("SearchList").getElementsByTagName("tbody")[0].innerHTML="",document.getElementById("searchAddAllSongs").setAttribute("disabled","disabled"),document.getElementById("searchAddAllSongsBtn").setAttribute("disabled","disabled"),document.getElementById("panel-heading-search").innerText="",document.getElementById("SearchList").classList.remove("opacity05"),setPagination(0)),b=document.getElementById("searchtags").getElementsByTagName("button"), +c=b.length,a=0;a=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:{mpdtag: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 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[d].id);g.setAttribute("id","queueTrackId"+a.data[d].id);g.setAttribute("data-songpos",a.data[d].pos+1);g.setAttribute("data-duration", f);g.setAttribute("data-uri",a.data[d].uri);g.innerHTML=""+(a.data[d].pos+1)+""+a.data[d].title+""+a.data[d].artist+""+a.data[d].album+""+f+'playlist_add';d=b;d--)e[d].remove();"queuesearch"==a.type&&0==b?c.innerHTML='error_outlineNo results, please refine your search!': @@ -83,10 +83,10 @@ document.getElementById("BrowseDatabaseArtistList").classList.remove("opacity05" f||(g=document.createElement("div"),g.classList.add("col-md"),g.classList.add("mr-0"),g.setAttribute("id",f),g.innerHTML='
'+a.searchstr+'

'+a.data[d].value+'

',d=b;d--)e[d].remove();setPagination(a.totalEntities);document.getElementById("BrowseDatabaseAlbumList").classList.remove("opacity05")}} function parseListTitles(a){if("Browse"===app.current.app||"Database"===app.current.tab||"Album"===app.current.view){var b=genId(a.album),c=document.getElementById("card"+b);b=c.getElementsByTagName("tbody")[0];var e=c.getElementsByTagName("img")[0];c=e.parentNode;e.setAttribute("src",a.cover);c.setAttribute("data-uri",encodeURI(a.data[0].uri.replace(/\/[^\/]+$/,"")));c.setAttribute("data-name",a.album);c.setAttribute("data-type","dir");e="";for(var d=a.data.length,f=0;f'+a.data[f].track+""+a.data[f].title+'playlist_add';b.innerHTML=e;c.addEventListener("click",function(a){a.preventDefault();showMenu(this)},!1);b.parentNode.addEventListener("click",function(a){"TD"==a.target.nodeName?appendQueue("song",decodeURI(a.target.parentNode.getAttribute("data-uri")),a.target.parentNode.getAttribute("data-name")):"A"==a.target.nodeName&& -(a.preventDefault(),showMenu(a.target))},!1)}} -function setPagination(a){var b=Math.ceil(a/settings.maxElementsPerPage),c=app.current.app+(void 0==app.current.tab?"":app.current.tab);0==b&&(b=1);for(var e=["PaginationTop","PaginationBottom"],d=0;2>d;d++){document.getElementById(c+e[d]+"Page").innerText=app.current.page/settings.maxElementsPerPage+1+" / "+b;if(1'+ -(g+1)+"";document.getElementById(c+e[d]+"Pages").innerHTML=f}else document.getElementById(c+e[d]+"Page").setAttribute("disabled","disabled");a>app.current.page+settings.maxElementsPerPage?(document.getElementById(c+e[d]+"Next").removeAttribute("disabled"),document.getElementById(c+e[d]).classList.remove("hide"),document.getElementById(c+"ButtonsBottom").classList.remove("hide")):(document.getElementById(c+e[d]+"Next").setAttribute("disabled","disabled"),document.getElementById(c+e[d]).classList.add("hide"), +a.data[f].title+'" data-uri="'+encodeURI(a.data[f].uri)+'">'+a.data[f].track+""+a.data[f].title+'playlist_add';b.innerHTML=e;c.addEventListener("click",function(a){showMenu(this,a)},!1);b.parentNode.addEventListener("click",function(a){"TD"==a.target.nodeName?appendQueue("song",decodeURI(a.target.parentNode.getAttribute("data-uri")),a.target.parentNode.getAttribute("data-name")):"A"==a.target.nodeName&&showMenu(a.target, +a)},!1)}} +function setPagination(a){var b=Math.ceil(a/settings.maxElementsPerPage),c=app.current.app+(void 0==app.current.tab?"":app.current.tab);0==b&&(b=1);for(var e=["PaginationTop","PaginationBottom"],d=0;2>d;d++){document.getElementById(c+e[d]+"Page").innerText=app.current.page/settings.maxElementsPerPage+1+" / "+b;if(1'+(g+ +1)+"";document.getElementById(c+e[d]+"Pages").innerHTML=f}else document.getElementById(c+e[d]+"Page").setAttribute("disabled","disabled");a>app.current.page+settings.maxElementsPerPage?(document.getElementById(c+e[d]+"Next").removeAttribute("disabled"),document.getElementById(c+e[d]).classList.remove("hide"),document.getElementById(c+"ButtonsBottom").classList.remove("hide")):(document.getElementById(c+e[d]+"Next").setAttribute("disabled","disabled"),document.getElementById(c+e[d]).classList.add("hide"), document.getElementById(c+"ButtonsBottom").classList.add("hide"));0Append to queue"+("song"==b?"Add after current playing song":"")+"Replace queue"+("plist"!=b?"
Add to playlist":"")+("dir"!=b?'':"")+("song"==b?"Songdetails':"")+("plist"==b?"Show playlist":""):"Browse"==app.current.app&&"Playlists"==app.current.tab&&"All"==app.current.view?f+="Append to queueReplace queue
Edit playlistRename playlistDelete playlist":"Browse"==app.current.app&&"Playlists"==app.current.tab&&"Detail"==app.current.view?f+="Append to queueReplace queue"+("false"==document.getElementById("BrowsePlaylistsDetailList").getAttribute("data-ro")?"
Remove":"")+("plist"!=b?"
Add to playlist":""):"Queue"==app.current.app&&(f+="RemoveRemove all upwardsRemove all downwards'+(-1==c.indexOf("http")?"Songdetails':""));void 0==a.Popover&&(new Popover(a,{trigger:"click",template:'"}),b=a.Popover,a.addEventListener("shown.bs.popover",function(a){document.getElementsByClassName("popover-content")[0].addEventListener("click",function(a){a.preventDefault();a.stopPropagation();if("A"==a.target.nodeName&&(a=JSON.parse(a.target.getAttribute("data-href").replace(/'/g,'"')),"function"=== -typeof window[a.cmd]))switch(a.cmd){case "sendAPI":sendAPI.apply(null,$jscomp.arrayFromIterable(a.options));break;default:window[a.cmd].apply(null,$jscomp.arrayFromIterable(a.options))}},!1)},!1),b.show())} +function dirname(a){return a.replace(/\/[^\/]*$/,"")} +function showMenu(a,b){b.preventDefault();b.stopPropagation();(b=document.getElementsByClassName("popover")[0])&&b.remove();b=a.getAttribute("data-type");var c=decodeURI(a.getAttribute("data-uri")),e=a.getAttribute("data-name"),d=0;if(null==b||null==c)b=a.parentNode.parentNode.getAttribute("data-type"),c=decodeURI(a.parentNode.parentNode.getAttribute("data-uri")),e=a.parentNode.parentNode.getAttribute("data-name");lastState&&(d=lastState.data.nextsongpos);var f="";"Browse"==app.current.app&&"Filesystem"== +app.current.tab||"Search"==app.current.app||"Browse"==app.current.app&&"Database"==app.current.tab&&"Album"==app.current.view?(f+="Append to queue"+("song"==b?"Add after current playing song":"")+"Replace queue"+("plist"!=b?"Add to playlist":"")+("song"==b?"Songdetails':"")+("plist"==b?"Show playlist":""),"Search"==app.current.app&&(c=dirname(c),f+='Album actions")):"Browse"==app.current.app&&"Playlists"== +app.current.tab&&"All"==app.current.view?f+="Append to queueReplace queue
Edit playlistRename playlistDelete playlist":"Browse"==app.current.app&&"Playlists"==app.current.tab&&"Detail"==app.current.view?f+="Append to queueReplace queue"+("false"== +document.getElementById("BrowsePlaylistsDetailList").getAttribute("data-ro")?"
Remove":"")+("plist"!=b?"
Add to playlist":""):"Queue"==app.current.app&&(f+="RemoveRemove all upwardsRemove all downwards'+(-1==c.indexOf("http")?"Songdetails':""));new Popover(a,{trigger:"click",delay:0,dismissible:!0,template:'"});popoverInit=a.Popover;a.addEventListener("shown.bs.popover", +function(a){document.getElementsByClassName("popover-content")[0].addEventListener("click",function(a){a.preventDefault();a.stopPropagation();if("A"==a.target.nodeName&&(a=a.target.getAttribute("data-href"))){a=JSON.parse(a.replace(/'/g,'"'));if("function"===typeof window[a.cmd])switch(a.cmd){case "sendAPI":sendAPI.apply(null,$jscomp.arrayFromIterable(a.options));break;default:window[a.cmd].apply(null,$jscomp.arrayFromIterable(a.options))}popoverInit.hide()}},!1);(a=document.getElementById("advancedMenuLink"))&& +new Collapse(a)},!1);popoverInit.show()} function sendAPI(a,b){var c=new XMLHttpRequest;c.open("POST","/api",!0);c.setRequestHeader("Content-type","application/json");c.onreadystatechange=function(){if(4==c.readyState)if(""!=c.responseText){var e=JSON.parse(c.responseText);"error"==e.type?(showNotification("Error",e.data,e.data,"danger"),console.log("Error: "+e.data)):"result"==e.type&&"ok"!=e.data?showNotification(e.data,"","","success"):void 0!=b&&"function"==typeof b&&b(e)}else console.log("Empty response for request: "+JSON.stringify(a))}; c.send(JSON.stringify(a))}function openLocalPlayer(){window.open("/player.html#"+settings.mpdstream,"LocalPlayer")}function updateDB(){sendAPI({cmd:"MPD_API_DATABASE_UPDATE"});updateDBstarted(!0)} function updateDBstarted(a){1==a?(document.getElementById("updateDBfinished").innerText="",document.getElementById("updateDBfooter").classList.add("hide"),updateDBprogress.style.width="20px",updateDBprogress.style.marginLeft="-20px",modalUpdateDB.show(),document.getElementById("updateDBprogress").classList.add("updateDBprogressAnimate")):showNotification("Database update started","","","success")} @@ -126,8 +129,8 @@ function delQueueSong(a,b,c){"range"==a?sendAPI({cmd:"MPD_API_QUEUE_RM_RANGE",da function confirmSettings(){var a=!0,b=document.getElementById("inputCrossfade");if(!b.getAttribute("disabled")){var c=parseInt(b.value);isNaN(c)?(b.classList.add("is-invalid"),a=!1):b.value=c}settings.mixramp&&(b=document.getElementById("inputMixrampdb"),b.getAttribute("disabled")||(c=parseFloat(b.value),isNaN(c)?(b.classList.add("is-invalid"),a=!1):b.value=c),b=document.getElementById("inputMixrampdelay"),b.getAttribute("disabled")||("nan"==b.value&&(b.value="-1"),c=parseFloat(b.value),isNaN(c)? (b.classList.add("is-invalid"),a=!1):b.value=c));1==a?(a=document.getElementById("selectReplaygain"),sendAPI({cmd:"MPD_API_SETTINGS_SET",data:{consume:document.getElementById("btnConsume").classList.contains("active")?1:0,random:document.getElementById("btnRandom").classList.contains("active")?1:0,single:document.getElementById("btnSingle").classList.contains("active")?1:0,repeat:document.getElementById("btnRepeat").classList.contains("active")?1:0,replaygain:a.options[a.selectedIndex].value,crossfade:document.getElementById("inputCrossfade").value, mixrampdb:1==settings.mixramp?document.getElementById("inputMixrampdb").value:settings.mixrampdb,mixrampdelay:1==settings.mixramp?document.getElementById("inputMixrampdelay").value:settings.mixrampdelay,notificationWeb:document.getElementById("btnnotifyWeb").classList.contains("active")?1:0,notificationPage:document.getElementById("btnnotifyPage").classList.contains("active")?1:0}},getSettings),modalSettings.hide()):document.getElementById("settingsFrm").classList.add("was-validated")} -function addAllFromBrowse(){sendAPI({cmd:"MPD_API_QUEUE_ADD_TRACK",data:{uri:app.current.search}});showNotification("Added all songs","","","success")}function addAllFromSearch(){2<=app.current.search.length&&(sendAPI({cmd:"MPD_API_DATABASE_SEARCH_ADD_QUEUE",data:{filter:app.current.filter,searchstr:app.current.search}}),showNotification("Added "+parseInt(document.getElementById("panel-heading-search").innerText)+" songs from search","","","success"))} -function addAllFromSearchPlist(a){if(2<=app.current.search.length){var b=app.current.filter;"Any Tag"==b&&(b="any");sendAPI({cmd:"MPD_API_DATABASE_SEARCH_ADD_PLAYLIST",data:{plist:a,filter:b,searchstr:app.current.search}});showNotification("Added "+parseInt(document.getElementById("panel-heading-search").innerText)+" songs from search to "+a,"","","success")}}function scrollTo(a){document.body.scrollTop=a;document.documentElement.scrollTop=a} +function addAllFromBrowse(){sendAPI({cmd:"MPD_API_QUEUE_ADD_TRACK",data:{uri:app.current.search}});showNotification("Added all songs","","","success")}function addAllFromSearch(){2<=app.current.search.length&&(sendAPI({cmd:"MPD_API_DATABASE_SEARCH",data:{plist:"queue",filter:app.current.filter,searchstr:app.current.search,offset:0}}),showNotification("Added "+parseInt(document.getElementById("panel-heading-search").innerText)+" songs from search","","","success"))} +function addAllFromSearchPlist(a){2<=app.current.search.length&&(sendAPI({cmd:"MPD_API_DATABASE_SEARCH",data:{plist:a,filter:app.current.filter,searchstr:app.current.search,offset:0}}),showNotification("Added "+parseInt(document.getElementById("panel-heading-search").innerText)+" songs from search to "+a,"","","success"))}function scrollTo(a){document.body.scrollTop=a;document.documentElement.scrollTop=a} function gotoPage(a){switch(a){case "next":app.current.page+=settings.maxElementsPerPage;break;case "prev":app.current.page-=settings.maxElementsPerPage;0>app.current.page&&(app.current.page=0);break;default:app.current.page=a}appGoto(app.current.app,app.current.tab,app.current.view,app.current.page+"/"+app.current.filter+"/"+app.current.search)} function saveQueue(){var a=document.getElementById("saveQueueName").value,b=a.replace(/\w/g,"");""!=a&&""==b?(sendAPI({cmd:"MPD_API_QUEUE_SAVE",data:{plist:a}}),modalSavequeue.hide()):(document.getElementById("saveQueueName").classList.add("is-invalid"),document.getElementById("saveQueueFrm").classList.add("was-validated"))} function showNotification(a,b,c,e){1==settings.notificationWeb&&(b=new Notification(a,{icon:"assets/favicon.ico",body:b}),setTimeout(function(a){a.close()},3E3,b));1==settings.notificationPage&&(document.getElementById("alertBox")?b=document.getElementById("alertBox"):(b=document.createElement("div"),b.setAttribute("id","alertBox"),b.addEventListener("click",function(){hideNotification()},!1)),b.classList.remove("alert-success","alert-danger"),b.classList.add("alert","alert-"+e),b.innerHTML="
"+ diff --git a/htdocs/css/mympd.css b/htdocs/css/mympd.css index 3311a0a..d54168c 100644 --- a/htdocs/css/mympd.css +++ b/htdocs/css/mympd.css @@ -263,3 +263,11 @@ caption { animation-name: changewidth; animation-iteration-count: infinite; } + +.modal-body { + overflow-x: hidden; +} + +.modal-body .album-cover { + float:none; +} \ No newline at end of file diff --git a/htdocs/index.html b/htdocs/index.html index d1d17dd..93c1dba 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -794,22 +794,24 @@ ' + ( uri.indexOf('http') == -1 ? 'Songdetails' : ''); } - if (el.Popover == undefined) { - new Popover(el, { trigger: 'click', template: ''}); - var popoverInit = el.Popover; - el.addEventListener('shown.bs.popover', function(event) { - document.getElementsByClassName('popover-content')[0].addEventListener('click', function(event) { - event.preventDefault(); - event.stopPropagation(); - if (event.target.nodeName == 'A') { - var cmd = JSON.parse(event.target.getAttribute('data-href').replace(/\'/g, '"')); + new Popover(el, { trigger: 'click', delay: 0, dismissible: true, template: ''}); + popoverInit = el.Popover; + el.addEventListener('shown.bs.popover', function(event) { + document.getElementsByClassName('popover-content')[0].addEventListener('click', function(event) { + event.preventDefault(); + event.stopPropagation(); + if (event.target.nodeName == 'A') { + var dh = event.target.getAttribute('data-href'); + if (dh) { + var cmd = JSON.parse(dh.replace(/\'/g, '"')); if (typeof window[cmd.cmd] === 'function') { switch(cmd.cmd) { case 'sendAPI': @@ -1721,11 +1744,16 @@ function showMenu(el) { window[cmd.cmd](... cmd.options); } } + popoverInit.hide(); } - }, false); - }, false); - popoverInit.show(); - } + } + }, false); + var collapseLink = document.getElementById('advancedMenuLink'); + if (collapseLink) { + var myCollapseInit = new Collapse(collapseLink); + } + }, false); + popoverInit.show(); } function sendAPI(request, callback) { diff --git a/src/mpd_client.c b/src/mpd_client.c index 7d2c10f..0e204d3 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -1486,7 +1486,7 @@ int mympd_search(char *buffer, char *searchstr, char *filter, char *plist, unsig struct mpd_song *song; unsigned long entity_count = 0; unsigned long entities_returned = 0; - int len; + int len = 0; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); if (strcmp(plist, "") == 0) { From 49a1413e4f1dcec0c9a07040b1c78b93498e7435 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Mon, 3 Sep 2018 22:48:27 +0100 Subject: [PATCH 03/24] Fix: bump version to 4.1.0 --- CMakeLists.txt | 2 +- htdocs/sw.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bd78029..ca86516 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 2.6) 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 "0") +set(CPACK_PACKAGE_VERSION_MINOR "1") set(CPACK_PACKAGE_VERSION_PATCH "0") if(CMAKE_BUILD_TYPE MATCHES RELEASE) diff --git a/htdocs/sw.js b/htdocs/sw.js index c8c5c51..9e8ca6b 100644 --- a/htdocs/sw.js +++ b/htdocs/sw.js @@ -1,4 +1,4 @@ -var CACHE = 'myMPD-cache-v4.0.0'; +var CACHE = 'myMPD-cache-v4.1.0'; var urlsToCache = [ '/', '/player.html', From eee5e80a9138d58581867637273fdadbe376c7e0 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Mon, 3 Sep 2018 22:49:04 +0100 Subject: [PATCH 04/24] Feat: add composer and performer tag #36 --- dist/htdocs/css/mympd.min.css | 2 +- dist/htdocs/js/mympd.min.js | 18 +++++++++--------- dist/htdocs/sw.min.js | 2 +- htdocs/css/mympd.css | 5 +++++ htdocs/index.html | 6 ++++++ htdocs/js/mympd.js | 24 ++++++++++++++---------- 6 files changed, 36 insertions(+), 21 deletions(-) diff --git a/dist/htdocs/css/mympd.min.css b/dist/htdocs/css/mympd.min.css index 790bf06..628abc2 100644 --- a/dist/htdocs/css/mympd.min.css +++ b/dist/htdocs/css/mympd.min.css @@ -1 +1 @@ -html{position:relative;min-height:100%}body{margin-bottom:60px;padding-top:50px;padding-bottom:50px;background-color:#888}main{padding-top:20px}footer{position:absolute;bottom:0}button{overflow:hidden}#BrowseBreadrumb{overflow:auto;white-space:nowrap}#BrowseBreadcrumb>li>a{cursor:pointer}.card{min-height:350px}@media only screen and (max-width:576px){.header-logo{display:none!important}}.clickable{cursor:pointer}.tblnum,.tblaction{width:30px}small{color:#aaa}.card-footer-playback{padding:0}.album-cover{background-size:cover;border:1px solid black;border-radius:5px;overflow:hidden;width:240px;height:240px;background-color:#eee;float:left;margin-right:20px;margin-bottom:20px}.album-desc{min-width:240px;float:left}.hide{display:none!important}.pull-right{float:right!important}.card-toolbar{margin-bottom:10px}.card-toolbar>div,.card-toolbar>form{margin-bottom:5px}@font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(/assets/MaterialIcons-Regular.eot);src:local('Material Icons'),local('MaterialIcons-Regular');src:url(/assets/MaterialIcons-Regular.woff2) format('woff2'),url(/assets/MaterialIcons-Regular.woff) format('woff'),url(/assets/MaterialIcons-Regular.ttf) format('truetype')}.material-icons{font-family:'Material Icons';font-weight:normal;font-style:normal;font-size:18px;display:inline-block;line-height:1;text-transform:none;letter-spacing:normal;word-wrap:normal;white-space:nowrap;direction:ltr;vertical-align:top;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;font-feature-settings:'liga'}.material-icons-small{font-size:16px}.color-darkgrey,.color-darkgrey:hover{color:#6c757d!important}#btn-outputs-block>button{margin-bottom:10px}#btn-outputs-block>button:last-child{margin-bottom:0}.card-body{overflow-x:hidden}.progressBarPlay{font-size:22px}#counter{cursor:text}#volumeBar{margin-top:2px;width:160px}.title-icon{float:left;margin-right:5px;font-size:1.8rem}.header-logo{font-size:2rem;float:left;margin-right:5px}.letters>button{width:28px;height:28px}.col-md{max-width:250px;min-width:250px}a.card-img-top{overflow:hidden;display:block}button.active{color:#fff;background-color:#28a745!important;border-color:#28a745!important}button.active-fg-green{color:#28a745!important}button.active-fg-red{color:#bd2130!important}div#alertBox{position:fixed;top:50px;right:10px;width:80%;max-width:400px;z-index:1000;opacity:0;visibility:visible;transition:opacity .5s ease-in}div.alertBoxActive{opacity:1!important;visibility:visible!important;transition:opacity .5s ease-in}.popover-content{padding-top:4px;padding-bottom:4px}.opacity05{opacity:.5}caption{caption-side:top;font-size:120%;font-weight:bold;color:black}.dragover>td{border-top:25px solid transparent}[draggable]{-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;user-select:none;-khtml-user-drag:element;-webkit-user-drag:element}@keyframes changewidth{0%{margin-left:-20px}to{margin-left:100%}}#updateDBprogress{width:20px}.updateDBprogressAnimate{animation-duration:2s;animation-name:changewidth;animation-iteration-count:infinite}.modal-body{overflow-x:hidden}.modal-body .album-cover{float:none} \ No newline at end of file +html{position:relative;min-height:100%}body{margin-bottom:60px;padding-top:50px;padding-bottom:50px;background-color:#888}main{padding-top:20px}footer{position:absolute;bottom:0}button{overflow:hidden}#BrowseBreadrumb{overflow:auto;white-space:nowrap}#BrowseBreadcrumb>li>a{cursor:pointer}.card{min-height:350px}@media only screen and (max-width:576px){.header-logo{display:none!important}}.clickable{cursor:pointer}.tblnum,.tblaction{width:30px}small{color:#aaa}.card-footer-playback{padding:0}.album-cover{background-size:cover;border:1px solid black;border-radius:5px;overflow:hidden;width:240px;height:240px;background-color:#eee;float:left;margin-right:20px;margin-bottom:20px}.album-desc{min-width:240px;float:left}.hide{display:none!important}.pull-right{float:right!important}.card-toolbar{margin-bottom:10px}.card-toolbar>div,.card-toolbar>form{margin-bottom:5px}@font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(/assets/MaterialIcons-Regular.eot);src:local('Material Icons'),local('MaterialIcons-Regular');src:url(/assets/MaterialIcons-Regular.woff2) format('woff2'),url(/assets/MaterialIcons-Regular.woff) format('woff'),url(/assets/MaterialIcons-Regular.ttf) format('truetype')}.material-icons{font-family:'Material Icons';font-weight:normal;font-style:normal;font-size:18px;display:inline-block;line-height:1;text-transform:none;letter-spacing:normal;word-wrap:normal;white-space:nowrap;direction:ltr;vertical-align:top;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;font-feature-settings:'liga'}.material-icons-small{font-size:16px}.material-icons-small-left{font-size:1rem;margin-left:-1em}.color-darkgrey,.color-darkgrey:hover{color:#6c757d!important}#btn-outputs-block>button{margin-bottom:10px}#btn-outputs-block>button:last-child{margin-bottom:0}.card-body{overflow-x:hidden}.progressBarPlay{font-size:22px}#counter{cursor:text}#volumeBar{margin-top:2px;width:160px}.title-icon{float:left;margin-right:5px;font-size:1.8rem}.header-logo{font-size:2rem;float:left;margin-right:5px}.letters>button{width:28px;height:28px}.col-md{max-width:250px;min-width:250px}a.card-img-top{overflow:hidden;display:block}button.active{color:#fff;background-color:#28a745!important;border-color:#28a745!important}button.active-fg-green{color:#28a745!important}button.active-fg-red{color:#bd2130!important}div#alertBox{position:fixed;top:50px;right:10px;width:80%;max-width:400px;z-index:1000;opacity:0;visibility:visible;transition:opacity .5s ease-in}div.alertBoxActive{opacity:1!important;visibility:visible!important;transition:opacity .5s ease-in}.popover-content{padding-top:4px;padding-bottom:4px}.opacity05{opacity:.5}caption{caption-side:top;font-size:120%;font-weight:bold;color:black}.dragover>td{border-top:25px solid transparent}[draggable]{-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;user-select:none;-khtml-user-drag:element;-webkit-user-drag:element}@keyframes changewidth{0%{margin-left:-20px}to{margin-left:100%}}#updateDBprogress{width:20px}.updateDBprogressAnimate{animation-duration:2s;animation-name:changewidth;animation-iteration-count:infinite}.modal-body{overflow-x:hidden}.modal-body .album-cover{float:none} \ No newline at end of file diff --git a/dist/htdocs/js/mympd.min.js b/dist/htdocs/js/mympd.min.js index 99eede7..8964b10 100644 --- a/dist/htdocs/js/mympd.min.js +++ b/dist/htdocs/js/mympd.min.js @@ -5,8 +5,8 @@ $jscomp.iteratorPrototype=function(a){$jscomp.initSymbolIterator();a={next:a};a[ $jscomp.checkStringArgs=function(a,b,c){if(null==a)throw new TypeError("The 'this' value for String.prototype."+c+" must not be null or undefined");if(b instanceof RegExp)throw new TypeError("First argument to String.prototype."+c+" must not be a regular expression");return a+""}; $jscomp.polyfill=function(a,b,c,e){if(b){c=$jscomp.global;a=a.split(".");for(e=0;ea||1342177279>>=1)b+=b;return e}},"es6","es3"); -var socket,lastSong="",lastState,currentSong={},playstate="",settings={},alertTimeout,progressTimer,deferredPrompt,dragEl,popoverInit,app={apps:{Playback:{state:"0/-/",scrollPos:0},Queue:{state:"0/any/",scrollPos:0},Browse:{active:"Database",tabs:{Filesystem:{state:"0/-/",scrollPos:0},Playlists:{active:"All",views:{All:{state:"0/-/",scrollPos:0},Detail:{state:"0/-/",scrollPos:0}}},Database:{active:"Artist",views:{Artist:{state:"0/-/",scrollPos:0},Album:{state:"0/-/",scrollPos:0}}}}},Search:{state:"0/any/", -scrollPos:0}},current:{app:"Playback",tab:void 0,view:void 0,page:0,filter:"",search:"",scrollPos:0},last:{app:void 0,tab:void 0,view:void 0,filter:"",search:"",scrollPos:0}},domCache={};domCache.navbarBottomBtns=document.getElementById("navbar-bottom").getElementsByTagName("div");domCache.navbarBottomBtnsLen=domCache.navbarBottomBtns.length;domCache.panelHeadingBrowse=document.getElementById("panel-heading-browse").getElementsByTagName("a");domCache.panelHeadingBrowseLen=domCache.panelHeadingBrowse.length; +var socket,lastSong="",lastState,currentSong={},playstate="",settings={},alertTimeout,progressTimer,deferredPrompt,dragEl,app={apps:{Playback:{state:"0/-/",scrollPos:0},Queue:{state:"0/any/",scrollPos:0},Browse:{active:"Database",tabs:{Filesystem:{state:"0/-/",scrollPos:0},Playlists:{active:"All",views:{All:{state:"0/-/",scrollPos:0},Detail:{state:"0/-/",scrollPos:0}}},Database:{active:"Artist",views:{Artist:{state:"0/-/",scrollPos:0},Album:{state:"0/-/",scrollPos:0}}}}},Search:{state:"0/any/",scrollPos:0}}, +current:{app:"Playback",tab:void 0,view:void 0,page:0,filter:"",search:"",scrollPos:0},last:{app:void 0,tab:void 0,view:void 0,filter:"",search:"",scrollPos:0}},domCache={};domCache.navbarBottomBtns=document.getElementById("navbar-bottom").getElementsByTagName("div");domCache.navbarBottomBtnsLen=domCache.navbarBottomBtns.length;domCache.panelHeadingBrowse=document.getElementById("panel-heading-browse").getElementsByTagName("a");domCache.panelHeadingBrowseLen=domCache.panelHeadingBrowse.length; domCache.counter=document.getElementById("counter");domCache.volumePrct=document.getElementById("volumePrct");domCache.volumeControl=document.getElementById("volumeControl");domCache.volumeIcon=document.getElementById("volumeIcon");domCache.btnsPlay=document.getElementsByClassName("btnPlay");domCache.btnsPlayLen=domCache.btnsPlay.length;domCache.btnPrev=document.getElementById("btnPrev");domCache.btnNext=document.getElementById("btnNext");domCache.progressBar=document.getElementById("progressBar"); domCache.volumeBar=document.getElementById("volumeBar");domCache.outputs=document.getElementById("outputs");domCache.btnAdd=document.getElementById("nav-add2homescreen");domCache.currentTrack=document.getElementById("currentTrack");domCache.currentArtist=document.getElementById("currentArtist");domCache.currentAlbum=document.getElementById("currentAlbum");domCache.currentCover=document.getElementById("currentCover");domCache.btnVoteUp=document.getElementById("btnVoteUp");domCache.btnVoteDown=document.getElementById("btnVoteDown"); var modalConnectionError=new Modal(document.getElementById("modalConnectionError")),modalSettings=new Modal(document.getElementById("modalSettings")),modalSavequeue=new Modal(document.getElementById("modalSaveQueue")),modalSongDetails=new Modal(document.getElementById("modalSongDetails")),modalAddToPlaylist=new Modal(document.getElementById("modalAddToPlaylist")),modalRenamePlaylist=new Modal(document.getElementById("modalRenamePlaylist")),modalUpdateDB=new Modal(document.getElementById("modalUpdateDB")); @@ -29,7 +29,7 @@ function appInit(){getSettings();sendAPI({cmd:"MPD_API_PLAYER_STATE"},parseState data:{songid:currentSong.currentSongId,seek:Math.ceil(domCache.progressBar.value/100*currentSong.totalTime)}})},!1);document.getElementById("volumeIcon").parentNode.addEventListener("show.bs.dropdown",function(){sendAPI({cmd:"MPD_API_PLAYER_OUTPUT_LIST"},parseOutputs)});document.getElementById("modalAbout").addEventListener("shown.bs.modal",function(){sendAPI({cmd:"MPD_API_DATABASE_STATS"},parseStats)});document.getElementById("modalUpdateDB").addEventListener("hidden.bs.modal",function(){document.getElementById("updateDBprogress").classList.remove("updateDBprogressAnimate")}); document.getElementById("modalSaveQueue").addEventListener("shown.bs.modal",function(){var a=document.getElementById("saveQueueName");a.focus();a.value="";a.classList.remove("is-invalid");document.getElementById("saveQueueFrm").classList.remove("was-validated")});document.getElementById("modalSettings").addEventListener("shown.bs.modal",function(){getSettings();document.getElementById("settingsFrm").classList.remove("was-validated");document.getElementById("inputCrossfade").classList.remove("is-invalid"); document.getElementById("inputMixrampdb").classList.remove("is-invalid");document.getElementById("inputMixrampdelay").classList.remove("is-invalid")});document.getElementById("addToPlaylistPlaylist").addEventListener("change",function(a){"New Playlist"==this.options[this.selectedIndex].text?(document.getElementById("addToPlaylistNewPlaylistDiv").classList.remove("hide"),document.getElementById("addToPlaylistNewPlaylist").focus()):document.getElementById("addToPlaylistNewPlaylistDiv").classList.add("hide")}, -!1);addFilterLetter("BrowseFilesystemFilterLetters");addFilterLetter("BrowseDatabaseFilterLetters");addFilterLetter("BrowsePlaylistsFilterLetters");for(var a=document.querySelectorAll("[data-href]"),b=a.length,c=0;cAppend to queue"+("song"==b?"Add after current playing song":"")+"Replace queue"+("plist"!=b?"Add to playlist":"")+("song"==b?"Songdetails':"")+("plist"==b?"Show playlist":""),"Search"==app.current.app&&(c=dirname(c),f+='Album actions
Replace queue"+("plist"!=b?"Add to playlist":"")+("song"==b?"Songdetails':"")+("plist"==b?"Show playlist":""),"Search"==app.current.app&&(c=dirname(c),f+='keyboard_arrow_rightAlbum actions")):"Browse"==app.current.app&&"Playlists"== app.current.tab&&"All"==app.current.view?f+="Append to queueReplace queue
Edit playlistRename playlistDelete playlist":"Browse"==app.current.app&&"Playlists"==app.current.tab&&"Detail"==app.current.view?f+="Append to queueReplace queue"+("false"== document.getElementById("BrowsePlaylistsDetailList").getAttribute("data-ro")?"
Remove":"")+("plist"!=b?"
Add to playlist":""):"Queue"==app.current.app&&(f+="RemoveRemove all upwardsRemove all downwards'+(-1==c.indexOf("http")?"Songdetails':""));new Popover(a,{trigger:"click",delay:0,dismissible:!0,template:'"});popoverInit=a.Popover;a.addEventListener("shown.bs.popover", -function(a){document.getElementsByClassName("popover-content")[0].addEventListener("click",function(a){a.preventDefault();a.stopPropagation();if("A"==a.target.nodeName&&(a=a.target.getAttribute("data-href"))){a=JSON.parse(a.replace(/'/g,'"'));if("function"===typeof window[a.cmd])switch(a.cmd){case "sendAPI":sendAPI.apply(null,$jscomp.arrayFromIterable(a.options));break;default:window[a.cmd].apply(null,$jscomp.arrayFromIterable(a.options))}popoverInit.hide()}},!1);(a=document.getElementById("advancedMenuLink"))&& -new Collapse(a)},!1);popoverInit.show()} +(parseInt(a.parentNode.parentNode.getAttribute("data-songpos"))-1)+',-1]}">Remove all downwards'+(-1==c.indexOf("http")?"Songdetails':""));new Popover(a,{trigger:"click",delay:0,dismissible:!0,template:'"});var g=a.Popover;a.addEventListener("shown.bs.popover", +function(a){document.getElementsByClassName("popover-content")[0].addEventListener("click",function(a){a.preventDefault();a.stopPropagation();if("A"==a.target.nodeName&&(a=a.target.getAttribute("data-href"))){a=JSON.parse(a.replace(/'/g,'"'));if("function"===typeof window[a.cmd])switch(a.cmd){case "sendAPI":sendAPI.apply(null,$jscomp.arrayFromIterable(a.options));break;default:window[a.cmd].apply(null,$jscomp.arrayFromIterable(a.options))}g.hide()}},!1);a=document.getElementById("advancedMenuLink"); +a.addEventListener("click",function(a){a=this.getElementsByTagName("span")[0];a.innerText="keyboard_arrow_right"==a.innerText?"keyboard_arrow_down":"keyboard_arrow_right"},!1);a&&new Collapse(a)},!1);g.show()} function sendAPI(a,b){var c=new XMLHttpRequest;c.open("POST","/api",!0);c.setRequestHeader("Content-type","application/json");c.onreadystatechange=function(){if(4==c.readyState)if(""!=c.responseText){var e=JSON.parse(c.responseText);"error"==e.type?(showNotification("Error",e.data,e.data,"danger"),console.log("Error: "+e.data)):"result"==e.type&&"ok"!=e.data?showNotification(e.data,"","","success"):void 0!=b&&"function"==typeof b&&b(e)}else console.log("Empty response for request: "+JSON.stringify(a))}; c.send(JSON.stringify(a))}function openLocalPlayer(){window.open("/player.html#"+settings.mpdstream,"LocalPlayer")}function updateDB(){sendAPI({cmd:"MPD_API_DATABASE_UPDATE"});updateDBstarted(!0)} function updateDBstarted(a){1==a?(document.getElementById("updateDBfinished").innerText="",document.getElementById("updateDBfooter").classList.add("hide"),updateDBprogress.style.width="20px",updateDBprogress.style.marginLeft="-20px",modalUpdateDB.show(),document.getElementById("updateDBprogress").classList.add("updateDBprogressAnimate")):showNotification("Database update started","","","success")} diff --git a/dist/htdocs/sw.min.js b/dist/htdocs/sw.min.js index 20593dc..57de4f4 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;aTitle + +
@@ -442,6 +444,8 @@ + + @@ -801,6 +805,8 @@ Album Track Albumartist + Composer + Performer Genre Date Uri diff --git a/htdocs/js/mympd.js b/htdocs/js/mympd.js index 1d53fc4..c69a4bb 100644 --- a/htdocs/js/mympd.js +++ b/htdocs/js/mympd.js @@ -33,7 +33,6 @@ var alertTimeout; var progressTimer; let deferredPrompt; var dragEl; -var popoverInit; var app = {}; app.apps = { "Playback": { "state": "0/-/", "scrollPos": 0 }, @@ -367,7 +366,7 @@ function appInit() { hrefs[i].classList.add('clickable'); hrefs[i].addEventListener('click', function(event) { event.preventDefault(); - event.stopPropagation(); + //event.stopPropagation(); var cmd = JSON.parse(this.getAttribute('data-href').replace(/\'/g, '"')); if (typeof window[cmd.cmd] === 'function') { switch(cmd.cmd) { @@ -508,8 +507,9 @@ function appInit() { document.getElementsByTagName('body')[0].addEventListener('click', function(event) { - if (popoverInit) - popoverInit.hide(); + var oldPopover = document.getElementsByClassName('popover')[0]; + if (oldPopover) + oldPopover.remove(); }, false); dragAndDropTable('QueueList'); @@ -1678,7 +1678,7 @@ function showMenu(el, event) { if (app.current.app == 'Search') { var baseuri = dirname(uri); menu += '' + - 'Album actions' + + 'keyboard_arrow_rightAlbum actions' + '
' + 'Append to queue' + @@ -1695,7 +1695,6 @@ function showMenu(el, event) { uri + '\',\'' + name + '\']}">Append to queue' + 'Replace queue' + - '' + 'Edit playlist' + 'Rename playlist' + 'Replace queue' + ( document.getElementById('BrowsePlaylistsDetailList').getAttribute('data-ro') == 'false' ? - '' + 'Remove' : '') + - ( type != 'plist' ? 'Add to playlist' : ''); + ( type != 'plist' ? 'Add to playlist' : ''); } else if (app.current.app == 'Queue') { menu += 'Remove all upwards' + 'Remove all downwards' + - '' + ( uri.indexOf('http') == -1 ? 'Songdetails' : ''); } new Popover(el, { trigger: 'click', delay: 0, dismissible: true, template: ''}); - popoverInit = el.Popover; + var popoverInit = el.Popover; el.addEventListener('shown.bs.popover', function(event) { document.getElementsByClassName('popover-content')[0].addEventListener('click', function(event) { event.preventDefault(); @@ -1750,6 +1747,13 @@ function showMenu(el, event) { }, false); var collapseLink = document.getElementById('advancedMenuLink'); if (collapseLink) { + collapseLink.addEventListener('click', function(event) { + var icon = this.getElementsByTagName('span')[0]; + if (icon.innerText == 'keyboard_arrow_right') + icon.innerText = 'keyboard_arrow_down'; + else + icon.innerText = 'keyboard_arrow_right'; + }, false); var myCollapseInit = new Collapse(collapseLink); } }, false); From 649ef2fb33f4d0a30ea144d7d788ebdf0d5c97fc Mon Sep 17 00:00:00 2001 From: jcorporation Date: Mon, 3 Sep 2018 22:49:55 +0100 Subject: [PATCH 05/24] Feat: mpd feature detection #44 --- src/mpd_client.c | 26 ++++++++++++++++++++++++-- src/mpd_client.h | 11 ++++++++--- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/mpd_client.c b/src/mpd_client.c index 0e204d3..71d71bc 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -577,6 +577,25 @@ void mympd_parse_idle(struct mg_mgr *s, int idle_bitmask) { } } +void mympd_mpd_features() { + struct mpd_pair *pair; + + mpd.feat_protocol = mpd_connection_get_server_version(mpd.conn); + mpd.feat_sticker = false; + + mpd_send_allowed_commands(mpd.conn); + while ((pair = mpd_recv_command_pair(mpd.conn)) != NULL) { + if (strcmp(pair->value, "sticker") == 0) + mpd.feat_sticker = true; + mpd_return_pair(mpd.conn, pair); + } + mpd_response_finish(mpd.conn); + printf("MPD protocoll version: %i.%i.%i\n", mpd.feat_protocol[0], mpd.feat_protocol[1], mpd.feat_protocol[2]); + if (mpd.feat_sticker == false && config.stickers == true) { + printf("MPD don't support stickers, disabling myMPD feature\n"); + config.stickers = false; + } +} void mympd_idle(struct mg_mgr *s, int timeout) { struct pollfd fds[1]; @@ -614,6 +633,7 @@ void mympd_idle(struct mg_mgr *s, int timeout) { printf("MPD connected.\n"); mpd_connection_set_timeout(mpd.conn, mpd.timeout); mpd.conn_state = MPD_CONNECTED; + mympd_mpd_features(); mpd_send_idle(mpd.conn); break; @@ -1070,7 +1090,7 @@ int mympd_put_songdetails(char *buffer, char *uri) { mympd_get_cover(uri, cover, 500); len += json_printf(&out, "duration: %d, artist: %Q, album: %Q, title: %Q, albumartist: %Q, cover: %Q, uri: %Q, " - "genre: %Q, track: %Q, date: %Q", + "genre: %Q, track: %Q, date: %Q, composer: %Q, performer: %Q", mpd_song_get_duration(song), mympd_get_tag(song, MPD_TAG_ARTIST), mympd_get_tag(song, MPD_TAG_ALBUM), @@ -1080,7 +1100,9 @@ int mympd_put_songdetails(char *buffer, char *uri) { uri, mympd_get_tag(song, MPD_TAG_GENRE), mympd_get_tag(song, MPD_TAG_TRACK), - mympd_get_tag(song, MPD_TAG_DATE) + mympd_get_tag(song, MPD_TAG_DATE), + mympd_get_tag(song, MPD_TAG_COMPOSER), + mympd_get_tag(song, MPD_TAG_PERFORMER) ); mpd_entity_free(entity); } diff --git a/src/mpd_client.h b/src/mpd_client.h index 7764782..dd730fa 100644 --- a/src/mpd_client.h +++ b/src/mpd_client.h @@ -112,21 +112,26 @@ enum mpd_conn_states { }; struct t_mpd { + // Connection struct mpd_connection *conn; enum mpd_conn_states conn_state; + int timeout; - /* Reponse Buffer */ + // Reponse Buffer char buf[MAX_SIZE]; size_t buf_size; + // States int song_id; int next_song_id; int last_song_id; unsigned queue_version; unsigned queue_length; - int timeout; - int last_update_sticker_song_id; + + // Features + const unsigned* feat_protocol; + bool feat_sticker; } mpd; typedef struct { From 3301d2f1b08c91eb3dbcf8026d864a7af74fc202 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Mon, 3 Sep 2018 23:20:28 +0100 Subject: [PATCH 06/24] Feat: check supported mpd tag types #44 --- src/mpd_client.c | 70 ++++++++++++++++++++++++++++++++++++++++++++---- src/mpd_client.h | 10 ++++++- 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/src/mpd_client.c b/src/mpd_client.c index 71d71bc..afcf8d0 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -580,8 +580,18 @@ void mympd_parse_idle(struct mg_mgr *s, int idle_bitmask) { void mympd_mpd_features() { struct mpd_pair *pair; - mpd.feat_protocol = mpd_connection_get_server_version(mpd.conn); + mpd.protocol = mpd_connection_get_server_version(mpd.conn); + + // Defaults mpd.feat_sticker = false; + mpd.tag_artist = 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) { @@ -590,11 +600,52 @@ void mympd_mpd_features() { mpd_return_pair(mpd.conn, pair); } mpd_response_finish(mpd.conn); - printf("MPD protocoll version: %i.%i.%i\n", mpd.feat_protocol[0], mpd.feat_protocol[1], mpd.feat_protocol[2]); + printf("MPD protocoll version: %i.%i.%i\n", mpd.protocol[0], mpd.protocol[1], mpd.protocol[2]); if (mpd.feat_sticker == false && config.stickers == true) { printf("MPD don't support stickers, disabling myMPD feature\n"); config.stickers = false; } + + printf("MPD supported 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, "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; + mpd_return_pair(mpd.conn, pair); + } + mpd_response_finish(mpd.conn); + printf("\n"); + if (mpd.tag_artist == false) + printf("WARNING: Artist tag not enabled in mpd\n"); + if (mpd.tag_album_artist == false) + printf("WARNING: Albumartist tag not enabled in mpd\n"); + if (mpd.tag_title == false) + printf("WARNING: Title tag not enabled in mpd\n"); + if (mpd.tag_track == false) + printf("WARNING: Track tag not enabled in mpd\n"); + if (mpd.tag_genre == false) + printf("WARNING: Genre tag not enabled in mpd\n"); + if (mpd.tag_date == false) + printf("WARNING: Date tag not enabled in mpd\n"); + if (mpd.tag_composer == false) + printf("WARNING: Composer tag not enabled in mpd\n"); + if (mpd.tag_performer == false) + printf("WARNING: Performer tag not enabled in mpd\n"); } void mympd_idle(struct mg_mgr *s, int timeout) { @@ -922,8 +973,9 @@ int mympd_put_settings(char *buffer) { "repeat: %d, single: %d, crossfade: %d, consume: %d, random: %d, " "mixrampdb: %f, mixrampdelay: %f, mpdhost: %Q, mpdport: %d, passwort_set: %B, " "streamport: %d, coverimage: %Q, stickers: %B, mixramp: %B, " - "maxElementsPerPage: %d, replaygain: %Q," - "notificationWeb: %d, notificationPage: %d" + "maxElementsPerPage: %d, replaygain: %Q, notificationWeb: %d, notificationPage: %d, " + "tags: { Artist: %B, AlbumArtist: %B, Title: %B, Track: %B, Genre: %B, Date: %B," + "Composer: %B, Performer: %B }" "}}", mpd_status_get_repeat(status), mpd_status_get_single(status), @@ -942,7 +994,15 @@ int mympd_put_settings(char *buffer) { MAX_ELEMENTS_PER_PAGE, replaygain, state.a, - state.b + state.b, + mpd.tag_artist, + mpd.tag_album_artist, + mpd.tag_title, + mpd.tag_track, + mpd.tag_genre, + mpd.tag_date, + mpd.tag_composer, + mpd.tag_performer ); mpd_status_free(status); free(replaygain); diff --git a/src/mpd_client.h b/src/mpd_client.h index dd730fa..c1adf3f 100644 --- a/src/mpd_client.h +++ b/src/mpd_client.h @@ -130,8 +130,16 @@ struct t_mpd { int last_update_sticker_song_id; // Features - const unsigned* feat_protocol; + const unsigned* protocol; bool feat_sticker; + bool tag_artist; + bool tag_album_artist; + bool tag_title; + bool tag_track; + bool tag_genre; + bool tag_date; + bool tag_composer; + bool tag_performer; } mpd; typedef struct { From 83ad1645212848e2b3b11dbc8e880b5e4647e792 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Mon, 3 Sep 2018 23:35:40 +0100 Subject: [PATCH 07/24] Fix: update minified files --- dist/htdocs/index.html | 2 +- dist/htdocs/js/mympd.min.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dist/htdocs/index.html b/dist/htdocs/index.html index 142f73d..11db732 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 8964b10..f7d5e8a 100644 --- a/dist/htdocs/js/mympd.min.js +++ b/dist/htdocs/js/mympd.min.js @@ -113,13 +113,13 @@ function showMenu(a,b){b.preventDefault();b.stopPropagation();(b=document.getEle app.current.tab||"Search"==app.current.app||"Browse"==app.current.app&&"Database"==app.current.tab&&"Album"==app.current.view?(f+="Append to queue"+("song"==b?"Add after current playing song":"")+"Replace queue"+("plist"!=b?"Add to playlist":"")+("song"==b?"Songdetails':"")+("plist"==b?"Show playlist":""),"Search"==app.current.app&&(c=dirname(c),f+='keyboard_arrow_rightAlbum actions")):"Browse"==app.current.app&&"Playlists"== -app.current.tab&&"All"==app.current.view?f+="Append to queueReplace queue
Edit playlistAppend to queueReplace queueEdit playlistRename playlistDelete playlist":"Browse"==app.current.app&&"Playlists"==app.current.tab&&"Detail"==app.current.view?f+="Append to queueReplace queue"+("false"== -document.getElementById("BrowsePlaylistsDetailList").getAttribute("data-ro")?"
Remove":"")+("plist"!=b?"
Add to playlist":""):"Queue"==app.current.app&&(f+="RemoveRemove all upwardsRemove all downwards'+(-1==c.indexOf("http")?"Songdetails':""));new Popover(a,{trigger:"click",delay:0,dismissible:!0,template:'"});var g=a.Popover;a.addEventListener("shown.bs.popover", -function(a){document.getElementsByClassName("popover-content")[0].addEventListener("click",function(a){a.preventDefault();a.stopPropagation();if("A"==a.target.nodeName&&(a=a.target.getAttribute("data-href"))){a=JSON.parse(a.replace(/'/g,'"'));if("function"===typeof window[a.cmd])switch(a.cmd){case "sendAPI":sendAPI.apply(null,$jscomp.arrayFromIterable(a.options));break;default:window[a.cmd].apply(null,$jscomp.arrayFromIterable(a.options))}g.hide()}},!1);a=document.getElementById("advancedMenuLink"); -a.addEventListener("click",function(a){a=this.getElementsByTagName("span")[0];a.innerText="keyboard_arrow_right"==a.innerText?"keyboard_arrow_down":"keyboard_arrow_right"},!1);a&&new Collapse(a)},!1);g.show()} +document.getElementById("BrowsePlaylistsDetailList").getAttribute("data-ro")?"Remove":"")+("plist"!=b?"Add to playlist":""):"Queue"==app.current.app&& +(f+="RemoveRemove all upwardsRemove all downwards'+(-1==c.indexOf("http")?"Songdetails':""));new Popover(a,{trigger:"click",delay:0,dismissible:!0,template:'"});var g=a.Popover;a.addEventListener("shown.bs.popover",function(a){document.getElementsByClassName("popover-content")[0].addEventListener("click",function(a){a.preventDefault(); +a.stopPropagation();if("A"==a.target.nodeName&&(a=a.target.getAttribute("data-href"))){a=JSON.parse(a.replace(/'/g,'"'));if("function"===typeof window[a.cmd])switch(a.cmd){case "sendAPI":sendAPI.apply(null,$jscomp.arrayFromIterable(a.options));break;default:window[a.cmd].apply(null,$jscomp.arrayFromIterable(a.options))}g.hide()}},!1);if(a=document.getElementById("advancedMenuLink"))a.addEventListener("click",function(a){a=this.getElementsByTagName("span")[0];a.innerText="keyboard_arrow_right"==a.innerText? +"keyboard_arrow_down":"keyboard_arrow_right"},!1),new Collapse(a)},!1);g.show()} function sendAPI(a,b){var c=new XMLHttpRequest;c.open("POST","/api",!0);c.setRequestHeader("Content-type","application/json");c.onreadystatechange=function(){if(4==c.readyState)if(""!=c.responseText){var e=JSON.parse(c.responseText);"error"==e.type?(showNotification("Error",e.data,e.data,"danger"),console.log("Error: "+e.data)):"result"==e.type&&"ok"!=e.data?showNotification(e.data,"","","success"):void 0!=b&&"function"==typeof b&&b(e)}else console.log("Empty response for request: "+JSON.stringify(a))}; c.send(JSON.stringify(a))}function openLocalPlayer(){window.open("/player.html#"+settings.mpdstream,"LocalPlayer")}function updateDB(){sendAPI({cmd:"MPD_API_DATABASE_UPDATE"});updateDBstarted(!0)} function updateDBstarted(a){1==a?(document.getElementById("updateDBfinished").innerText="",document.getElementById("updateDBfooter").classList.add("hide"),updateDBprogress.style.width="20px",updateDBprogress.style.marginLeft="-20px",modalUpdateDB.show(),document.getElementById("updateDBprogress").classList.add("updateDBprogressAnimate")):showNotification("Database update started","","","success")} From d799fe1e879d09963f3c9d338b9116b33f863c77 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Tue, 4 Sep 2018 21:36:04 +0200 Subject: [PATCH 08/24] Fix: improved package building --- CMakeLists.txt | 2 +- contrib/myMPD.spec | 7 +++++-- mkrelease.sh | 9 +++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ca86516..def99a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,7 @@ target_link_libraries(mympd ${LIBMPDCLIENT_LIBRARY} ${OPENSSL_LIBRARIES}) install(TARGETS mympd DESTINATION bin) install(FILES contrib/mympd.1 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1) -install(FILES contrib/crcert.sh DESTINATION ${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME}/) +install(PROGRAMS contrib/crcert.sh DESTINATION ${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME}/) install(FILES contrib/mympd.service DESTINATION ${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME}/) install(FILES contrib/mympd.conf DESTINATION /etc/${PROJECT_NAME}/) install(FILES htdocs/mympd.webmanifest DESTINATION share/${PROJECT_NAME}/htdocs/) diff --git a/contrib/myMPD.spec b/contrib/myMPD.spec index dd97d28..e43aabc 100644 --- a/contrib/myMPD.spec +++ b/contrib/myMPD.spec @@ -36,7 +36,10 @@ make %install cd release make install DESTDIR=%{buildroot} -chmod 755 %{buildroot}/usr/share/mympd/crcert.sh + +%post +/usr/share/mympd/crcert.sh +chown nobody /var/lib/mympd %files %defattr(-,root,root,-) @@ -48,5 +51,5 @@ chmod 755 %{buildroot}/usr/share/mympd/crcert.sh /var/lib/mympd %changelog -* Tue Aug 28 2018 Juergen Mang - master +* Tue Sep 04 2018 Juergen Mang - master - Version from master diff --git a/mkrelease.sh b/mkrelease.sh index 48d8202..93c53b2 100755 --- a/mkrelease.sh +++ b/mkrelease.sh @@ -55,18 +55,19 @@ sudo chown nobody /var/lib/mympd echo "Trying to link musicdir to library" if [ -f /etc/mpd.conf ] then - LIBRARY=$(grep ^music_directory /etc/mpd.conf | awk {'print $2'} | sed -e 's/"//g') + LIBRARY=$(sudo grep ^music_directory /etc/mpd.conf | awk {'print $2'} | sed -e 's/"//g') [ "$LIBRARY" != "" ] && [ ! -e /usr/share/mympd/htdocs/library ] && sudo ln -s "$LIBRARY" /usr/share/mympd/htdocs/library else echo "/etc/mpd.conf not found, you must link your music_directory manually to /usr/share/mympd/htdocs/library" fi echo "Installing systemd service" -if [ -d /etc/systemd/system ] +if [ -d /usr/lib/systemd/ ] then - if [ contrib/mympd.service -nt /etc/systemd/system/mympd.service ] + [ -d /usr/lib/systemd/system ] || sudo mkdir /usr/lib/systemd/system + if [ contrib/mympd.service -nt /usr/lib/systemd/system/mympd.service ] then - sudo cp contrib/mympd.service /etc/systemd/system/ + sudo cp contrib/mympd.service /usr/lib/systemd/system/ sudo systemctl daemon-reload fi sudo systemctl enable mympd From 8490303b976d5d4b92c4182fee13ff65abbfeeab Mon Sep 17 00:00:00 2001 From: jcorporation Date: Tue, 4 Sep 2018 22:07:30 +0200 Subject: [PATCH 09/24] Fix: run myMPD under myMPD user --- contrib/crcert.sh | 3 +++ contrib/myMPD.spec | 11 ++++++++--- contrib/mympd.conf | 2 +- mkrelease.sh | 6 +++++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/contrib/crcert.sh b/contrib/crcert.sh index a6a8ba2..b6d0e22 100755 --- a/contrib/crcert.sh +++ b/contrib/crcert.sh @@ -7,6 +7,7 @@ then fi mkdir -p /etc/mympd/ssl/ca/certs +chmod 700 /etc/mympd/ssl cd /etc/mympd/ssl/ca echo '01' > serial @@ -98,3 +99,5 @@ openssl ca -in server.csr -cert ca/ca.pem -keyfile ca/ca.key -config ca/ca.cnf \ rm server.csr rm ca/ca.cnf rm req.cnf + +chown -R mympd.mympd /etc/mympd/ \ No newline at end of file diff --git a/contrib/myMPD.spec b/contrib/myMPD.spec index e43aabc..ffd3a0d 100644 --- a/contrib/myMPD.spec +++ b/contrib/myMPD.spec @@ -4,13 +4,13 @@ # (c) 2018 Juergen Mang /dev/null +[ "$?" == "2" ] && groupadd mympd +getent passwd mympd > /dev/null +[ "$?" == "2" ] && useradd mympd -g mympd +chown -R mympd /var/lib/mympd + %files %defattr(-,root,root,-) diff --git a/contrib/mympd.conf b/contrib/mympd.conf index c1bc41a..edda539 100644 --- a/contrib/mympd.conf +++ b/contrib/mympd.conf @@ -15,7 +15,7 @@ sslcert = /etc/mympd/ssl/server.pem sslkey = /etc/mympd/ssl/server.key #myMPD user -user = nobody +user = mympd #Port for mpd http stream streamport = 8000 diff --git a/mkrelease.sh b/mkrelease.sh index 93c53b2..f93622a 100755 --- a/mkrelease.sh +++ b/mkrelease.sh @@ -50,7 +50,11 @@ sudo make install cd .. echo "Fixing ownership of /var/lib/mympd" -sudo chown nobody /var/lib/mympd +getent group mympd > /dev/null +[ "$?" == "2" ] && sudo groupadd mympd +getent passwd mympd > /dev/null +[ "$?" == "2" ] && sudo useradd mympd -g mympd +sudo chown -R mympd.mympd /var/lib/mympd echo "Trying to link musicdir to library" if [ -f /etc/mpd.conf ] From 313f6900034f0cd9a4e92736d0253ab8a690138f Mon Sep 17 00:00:00 2001 From: jcorporation Date: Wed, 5 Sep 2018 20:36:23 +0200 Subject: [PATCH 10/24] Fix: set exit status to 0 for rpmbuild --- contrib/crcert.sh | 2 +- contrib/myMPD.spec | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/contrib/crcert.sh b/contrib/crcert.sh index b6d0e22..ccc523c 100755 --- a/contrib/crcert.sh +++ b/contrib/crcert.sh @@ -3,7 +3,7 @@ if [ -d /etc/mympd/ssl ] then echo "SSL directory exists, to recreate certificates: \"rm -r /etc/mympd/ssl\"" - exit 1 + exit 0 fi mkdir -p /etc/mympd/ssl/ca/certs diff --git a/contrib/myMPD.spec b/contrib/myMPD.spec index ffd3a0d..57fc295 100644 --- a/contrib/myMPD.spec +++ b/contrib/myMPD.spec @@ -38,13 +38,17 @@ cd release make install DESTDIR=%{buildroot} %post -/usr/share/mympd/crcert.sh getent group mympd > /dev/null [ "$?" == "2" ] && groupadd mympd getent passwd mympd > /dev/null [ "$?" == "2" ] && useradd mympd -g mympd +if [ -d /usr/lib/systemd/ ] +then + [ -d /usr/lib/systemd/system ] || sudo mkdir /usr/lib/systemd/system + cp /usr/share/mympd/mympd.service /usr/lib/systemd/system/ +fi chown -R mympd /var/lib/mympd - +/usr/share/mympd/crcert.sh %files %defattr(-,root,root,-) @@ -56,5 +60,5 @@ chown -R mympd /var/lib/mympd /var/lib/mympd %changelog -* Tue Sep 04 2018 Juergen Mang - master +* Wed Sep 05 2018 Juergen Mang - master - Version from master From 1d383637939f94332657e1b7647d6a322af16448 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Wed, 5 Sep 2018 20:46:40 +0200 Subject: [PATCH 11/24] Fix: link mpd music_directory to mympd docroot --- contrib/myMPD.spec | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contrib/myMPD.spec b/contrib/myMPD.spec index 57fc295..ef4744b 100644 --- a/contrib/myMPD.spec +++ b/contrib/myMPD.spec @@ -47,6 +47,11 @@ then [ -d /usr/lib/systemd/system ] || sudo mkdir /usr/lib/systemd/system cp /usr/share/mympd/mympd.service /usr/lib/systemd/system/ fi +if [ -f /etc/mpd.conf ] +then + LIBRARY=$(grep ^music_directory /etc/mpd.conf | awk {'print $2'} | sed -e 's/"//g') + [ "$LIBRARY" != "" ] && [ ! -e /usr/share/mympd/htdocs/library ] && ln -s "$LIBRARY" /usr/share/mympd/htdocs/library +fi chown -R mympd /var/lib/mympd /usr/share/mympd/crcert.sh From c293e87b3bebb8db90fb7f04ab6a61a2405fadd2 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Wed, 5 Sep 2018 21:23:39 +0200 Subject: [PATCH 12/24] Fix: disable debug_package --- contrib/myMPD.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/myMPD.spec b/contrib/myMPD.spec index ef4744b..ecd8a1d 100644 --- a/contrib/myMPD.spec +++ b/contrib/myMPD.spec @@ -15,11 +15,11 @@ BuildRequires: gcc BuildRequires: cmake BuildRequires: unzip BuildRequires: libmpdclient-devel -BuildRequires: libmpdclient2 BuildRequires: pkgconfig BuildRequires: openssl-devel BuildRoot: %{_tmppath}/%{name}-%{version}-build +%global debug_package %{nil} %description myMPD is a standalone and mobile friendly web mpdclient. From a9dcff313548c18b18cc5bc8ba4693094e36de45 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Fri, 7 Sep 2018 00:10:40 +0200 Subject: [PATCH 13/24] Feat: add debian packaging --- CMakeLists.txt | 10 +++++----- contrib/myMPD.spec | 4 ++-- debian/changelog | 5 +++++ debian/control | 12 ++++++++++++ debian/postinst | 39 +++++++++++++++++++++++++++++++++++++++ debian/rules | 25 +++++++++++++++++++++++++ debian/source/format | 1 + mkclean.sh | 2 ++ mkrelease.sh | 4 ++-- 9 files changed, 93 insertions(+), 9 deletions(-) create mode 100644 debian/changelog create mode 100644 debian/control create mode 100755 debian/postinst create mode 100755 debian/rules create mode 100644 debian/source/format diff --git a/CMakeLists.txt b/CMakeLists.txt index def99a3..3d30d15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,10 +40,10 @@ add_executable(mympd ${SOURCES}) target_link_libraries(mympd ${LIBMPDCLIENT_LIBRARY} ${OPENSSL_LIBRARIES}) install(TARGETS mympd DESTINATION bin) -install(FILES contrib/mympd.1 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1) -install(PROGRAMS contrib/crcert.sh DESTINATION ${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME}/) -install(FILES contrib/mympd.service DESTINATION ${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME}/) -install(FILES contrib/mympd.conf DESTINATION /etc/${PROJECT_NAME}/) +install(FILES contrib/mympd.1 DESTINATION share/man/man1) +install(PROGRAMS contrib/crcert.sh DESTINATION share/${PROJECT_NAME}/) +install(FILES contrib/mympd.service DESTINATION share/${PROJECT_NAME}/) +install(FILES contrib/mympd.conf DESTINATION ../etc/${PROJECT_NAME}/) install(FILES htdocs/mympd.webmanifest DESTINATION share/${PROJECT_NAME}/htdocs/) install(FILES dist/htdocs/index.html DESTINATION share/${PROJECT_NAME}/htdocs/) install(FILES dist/htdocs/player.html DESTINATION share/${PROJECT_NAME}/htdocs/) @@ -55,4 +55,4 @@ install(FILES dist/htdocs/css/bootstrap.min.css DESTINATION share/${PROJECT_NAME install(FILES dist/htdocs/css/mympd.min.css DESTINATION share/${PROJECT_NAME}/htdocs/css/) install(DIRECTORY htdocs/assets DESTINATION share/${PROJECT_NAME}/htdocs) install(DIRECTORY DESTINATION share/${PROJECT_NAME}/htdocs/pics) -install(DIRECTORY DESTINATION /var/lib/${PROJECT_NAME}/) +install(DIRECTORY DESTINATION ../var/lib/${PROJECT_NAME}/) diff --git a/contrib/myMPD.spec b/contrib/myMPD.spec index ecd8a1d..78c1fe8 100644 --- a/contrib/myMPD.spec +++ b/contrib/myMPD.spec @@ -39,9 +39,9 @@ make install DESTDIR=%{buildroot} %post getent group mympd > /dev/null -[ "$?" == "2" ] && groupadd mympd +[ "$?" = "2" ] && groupadd mympd getent passwd mympd > /dev/null -[ "$?" == "2" ] && useradd mympd -g mympd +[ "$?" = "2" ] && useradd mympd -g mympd if [ -d /usr/lib/systemd/ ] then [ -d /usr/lib/systemd/system ] || sudo mkdir /usr/lib/systemd/system diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..b09c69b --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +mympd (4.1.0-1) unstable; urgency=medium + + * Initial release + + -- Juergen Mang Thu, 06 Sep 2018 22:57:18 +0200 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..5ea97ac --- /dev/null +++ b/debian/control @@ -0,0 +1,12 @@ +Source: mympd +Section: unknown +Priority: optional +Maintainer: Juergen Mang +Build-Depends: debhelper (>= 10) +Standards-Version: 4.1.2 +Homepage: https://github.com/jcorporation/myMPD + +Package: mympd +Architecture: any +Depends: libmpdclient2, openssl +Description: myMPD is a standalone and modern web mpdclient. diff --git a/debian/postinst b/debian/postinst new file mode 100755 index 0000000..65c7559 --- /dev/null +++ b/debian/postinst @@ -0,0 +1,39 @@ +#/bin/bash + +echo "Fixing ownership of /var/lib/mympd" +getent group mympd > /dev/null +[ "$?" = "2" ] && groupadd mympd +getent passwd mympd > /dev/null +[ "$?" = "2" ] && useradd mympd -g mympd + +chown -R mympd.mympd /var/lib/mympd + +echo "Trying to link musicdir to library" +if [ -f /etc/mpd.conf ] +then + LIBRARY=$(grep ^music_directory /etc/mpd.conf | awk {'print $2'} | sed -e 's/"//g') + [ "$LIBRARY" != "" ] && [ ! -e /usr/share/mympd/htdocs/library ] && ln -s "$LIBRARY" /usr/share/mympd/htdocs/library +else + echo "/etc/mpd.conf not found, you must link your music_directory manually to /usr/share/mympd/htdocs/library" +fi + +if [ -d /usr/lib/systemd/ ] +then + echo "Installing systemd service" + [ -d /usr/lib/systemd/system ] || mkdir /usr/lib/systemd/system + if [ contrib/mympd.service -nt /usr/lib/systemd/system/mympd.service ] + then + cp contrib/mympd.service /usr/lib/systemd/system/ + fi +fi + +if [ -d /etc/mympd/ssl ] +then + echo "Certificates already created" +else + echo "Creating certificates" + sudo contrib/crcert.sh +fi + +echo "myMPD installed" +echo "Edit /etc/mympd/mympd.conf before starting myMPD" diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..132d6ee --- /dev/null +++ b/debian/rules @@ -0,0 +1,25 @@ +#!/usr/bin/make -f +export DH_VERBOSE = 1 + +BUILDDIR = release + +build: + mkdir $(BUILDDIR) + cd $(BUILDDIR); cmake -DCMAKE_INSTALL_PREFIX:PATH=../debian/tmp/usr -DCMAKE_BUILD_TYPE=RELEASE .. + make -C $(BUILDDIR) + +binary: binary-indep binary-arch + +binary-indep: + +binary-arch: + cd $(BUILDDIR); cmake -P cmake_install.cmake + mkdir debian/tmp/DEBIAN + cp debian/postinst debian/tmp/DEBIAN + dpkg-gencontrol -pmympd + dpkg --build debian/tmp .. + +clean: + rm -rf $(BUILDDIR) + +.PHONY: binary binary-arch binary-indep clean diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/mkclean.sh b/mkclean.sh index fd7d70a..0ccc345 100755 --- a/mkclean.sh +++ b/mkclean.sh @@ -1,6 +1,8 @@ #!/bin/sh rm -rf release rm -rf debug +rm -rf debian/tmp +rm -f debian/files rm -f htdocs/js/bootstrap-native-v4.min.js rm -f htdocs/css/bootstrap.min.css find ./ -name \*~ -delete diff --git a/mkrelease.sh b/mkrelease.sh index f93622a..a952eb5 100755 --- a/mkrelease.sh +++ b/mkrelease.sh @@ -51,9 +51,9 @@ cd .. echo "Fixing ownership of /var/lib/mympd" getent group mympd > /dev/null -[ "$?" == "2" ] && sudo groupadd mympd +[ "$?" = "2" ] && sudo groupadd mympd getent passwd mympd > /dev/null -[ "$?" == "2" ] && sudo useradd mympd -g mympd +[ "$?" = "2" ] && sudo useradd mympd -g mympd sudo chown -R mympd.mympd /var/lib/mympd echo "Trying to link musicdir to library" From be5c2f908647102f4b10542da181dcc847f60497 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Fri, 7 Sep 2018 00:15:38 +0200 Subject: [PATCH 14/24] Fix: add debian build dependencies --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 5ea97ac..df77137 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: mympd Section: unknown Priority: optional Maintainer: Juergen Mang -Build-Depends: debhelper (>= 10) +Build-Depends: debhelper (>= 10), libmpdclient-dev, cmake, libssl-dev Standards-Version: 4.1.2 Homepage: https://github.com/jcorporation/myMPD From 860651dd53f5b374bc6929a2a49b6378e7a70d8d Mon Sep 17 00:00:00 2001 From: jcorporation Date: Fri, 7 Sep 2018 00:31:37 +0200 Subject: [PATCH 15/24] Fix: add gnupg as build requirement --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index df77137..fbae910 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: mympd Section: unknown Priority: optional Maintainer: Juergen Mang -Build-Depends: debhelper (>= 10), libmpdclient-dev, cmake, libssl-dev +Build-Depends: debhelper (>= 10), libmpdclient-dev, cmake, libssl-dev, gnupg Standards-Version: 4.1.2 Homepage: https://github.com/jcorporation/myMPD From 8958fe2fd4546c08df67e8715864cd215bbe26d4 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Fri, 7 Sep 2018 00:40:46 +0200 Subject: [PATCH 16/24] Fix: requirements --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index fbae910..df77137 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: mympd Section: unknown Priority: optional Maintainer: Juergen Mang -Build-Depends: debhelper (>= 10), libmpdclient-dev, cmake, libssl-dev, gnupg +Build-Depends: debhelper (>= 10), libmpdclient-dev, cmake, libssl-dev Standards-Version: 4.1.2 Homepage: https://github.com/jcorporation/myMPD From 0a9e6deebe624c7ec55aa8cd9d7f6e1e1e76602c Mon Sep 17 00:00:00 2001 From: jcorporation Date: Fri, 7 Sep 2018 00:52:43 +0200 Subject: [PATCH 17/24] Fix: ignore .git and .github directory --- debian/source/options | 1 + 1 file changed, 1 insertion(+) create mode 100644 debian/source/options diff --git a/debian/source/options b/debian/source/options new file mode 100644 index 0000000..5033734 --- /dev/null +++ b/debian/source/options @@ -0,0 +1 @@ +extend-diff-ignore = "(\.git\/|\.github\/)" \ No newline at end of file From 49d67c49c8aa6b8d91badb712035b0beb61598c2 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Fri, 7 Sep 2018 01:00:00 +0200 Subject: [PATCH 18/24] Fix: add mympd user with no shell and home /var/lib/mympd --- contrib/myMPD.spec | 2 +- debian/postinst | 2 +- mkrelease.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/myMPD.spec b/contrib/myMPD.spec index 78c1fe8..47ac151 100644 --- a/contrib/myMPD.spec +++ b/contrib/myMPD.spec @@ -41,7 +41,7 @@ make install DESTDIR=%{buildroot} getent group mympd > /dev/null [ "$?" = "2" ] && groupadd mympd getent passwd mympd > /dev/null -[ "$?" = "2" ] && useradd mympd -g mympd +[ "$?" = "2" ] && useradd mympd -g mympd -d /var/lib/mympd -s /usr/sbin/nologin if [ -d /usr/lib/systemd/ ] then [ -d /usr/lib/systemd/system ] || sudo mkdir /usr/lib/systemd/system diff --git a/debian/postinst b/debian/postinst index 65c7559..786464b 100755 --- a/debian/postinst +++ b/debian/postinst @@ -4,7 +4,7 @@ echo "Fixing ownership of /var/lib/mympd" getent group mympd > /dev/null [ "$?" = "2" ] && groupadd mympd getent passwd mympd > /dev/null -[ "$?" = "2" ] && useradd mympd -g mympd +[ "$?" = "2" ] && useradd mympd -g mympd-d /var/lib/mympd -s /usr/sbin/nologin chown -R mympd.mympd /var/lib/mympd diff --git a/mkrelease.sh b/mkrelease.sh index a952eb5..0270f73 100755 --- a/mkrelease.sh +++ b/mkrelease.sh @@ -53,7 +53,7 @@ echo "Fixing ownership of /var/lib/mympd" getent group mympd > /dev/null [ "$?" = "2" ] && sudo groupadd mympd getent passwd mympd > /dev/null -[ "$?" = "2" ] && sudo useradd mympd -g mympd +[ "$?" = "2" ] && sudo useradd mympd -g mympd -d /var/lib/mympd -s /usr/sbin/nologin sudo chown -R mympd.mympd /var/lib/mympd echo "Trying to link musicdir to library" From f2489601c1000320413987f729b53f429cf53cd5 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Mon, 10 Sep 2018 22:32:15 +0200 Subject: [PATCH 19/24] Feat: browse and search database by more tags #43 #36 --- htdocs/index.html | 54 ++++++++++------ htdocs/js/mympd.js | 154 +++++++++++++++++++++++++++------------------ src/mpd_client.c | 48 +++++++------- src/mpd_client.h | 8 +-- src/mympd.c | 2 + 5 files changed, 161 insertions(+), 105 deletions(-) diff --git a/htdocs/index.html b/htdocs/index.html index 470cc6f..5809b80 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -120,8 +120,8 @@
@@ -135,12 +135,15 @@ @@ -296,8 +299,20 @@
+
+ + +
- +
@@ -316,7 +331,7 @@
- +
@@ -363,8 +378,8 @@ @@ -440,12 +455,15 @@ diff --git a/htdocs/js/mympd.js b/htdocs/js/mympd.js index c69a4bb..b822908 100644 --- a/htdocs/js/mympd.js +++ b/htdocs/js/mympd.js @@ -47,9 +47,14 @@ app.apps = { "Playback": { "state": "0/-/", "scrollPos": 0 }, } }, "Database": { - "active": "Artist", - "views": { "Artist": { "state": "0/-/", "scrollPos": 0 }, - "Album": { "state": "0/-/", "scrollPos": 0 } + "active": "AlbumArtist", + "views": { "AlbumArtist": { "state": "0/-/", "scrollPos": 0 }, + "Genre": { "state": "0/-/", "scrollPos": 0 }, + "Artist": { "state": "0/-/", "scrollPos": 0 }, + "Composer": { "state": "0/-/", "scrollPos": 0 }, + "Performer": { "state": "0/-/", "scrollPos": 0 }, + "Date": { "state": "0/-/", "scrollPos": 0 }, + "Album": { "state": "0/-/", "scrollPos": 0 }, } } } @@ -212,13 +217,25 @@ function appRoute() { sendAPI({"cmd": "MPD_API_PLAYLIST_CONTENT_LIST", "data": {"offset": app.current.page, "filter": app.current.filter, "uri": app.current.search}}, parsePlaylists); doSetFilterLetter('BrowsePlaylistsFilter'); } - else if (app.current.app == 'Browse' && app.current.tab == 'Database' && app.current.view == 'Artist') { - sendAPI({"cmd": "MPD_API_DATABASE_ARTIST_LIST","data": {"offset": app.current.page, "filter": app.current.filter}}, parseListDBtags); - doSetFilterLetter('BrowseDatabaseFilter'); - } - else if (app.current.app == 'Browse' && app.current.tab == 'Database' && app.current.view == 'Album') { - sendAPI({"cmd": "MPD_API_DATABASE_ARTISTALBUM_LIST", "data": {"offset": app.current.page, "filter": app.current.filter, "albumartist": app.current.search}}, parseListDBtags); - doSetFilterLetter('BrowseDatabaseFilter'); + + else if (app.current.app == 'Browse' && app.current.tab == 'Database') { + if (app.current.search != '') { + sendAPI({"cmd": "MPD_API_DATABASE_TAG_ALBUM_LIST", "data": {"offset": app.current.page, "filter": app.current.filter, "search": app.current.search, "tag": app.current.view}}, parseListDBtags); + doSetFilterLetter('BrowseDatabaseFilter'); + } + else { + sendAPI({"cmd": "MPD_API_DATABASE_TAG_LIST","data": {"offset": app.current.page, "filter": app.current.filter, "tag": app.current.view}}, parseListDBtags); + doSetFilterLetter('BrowseDatabaseFilter'); + var btns = document.getElementById('BrowseDatabaseByTagDropdown').getElementsByTagName('button'); + var btnsLen = btns.length; + for (var i = 0; i < btnsLen; i++) { + btns[i].classList.remove('active'); + if (btns[i].getAttribute('data-tag') == app.current.view) { + btns[i].classList.add('active'); + document.getElementById('btnBrowseDatabaseByTag').innerText = btns[i].innerText; + } + } + } } else if (app.current.app == 'Browse' && app.current.tab == 'Filesystem') { sendAPI({"cmd": "MPD_API_DATABASE_FILESYSTEM_LIST", "data": {"offset": app.current.page, "path": (app.current.search ? app.current.search : "/"), "filter": app.current.filter}}, parseFilesystem); @@ -442,9 +459,9 @@ function appInit() { } }, false); - document.getElementById('BrowseDatabaseArtistList').addEventListener('click', function(event) { + document.getElementById('BrowseDatabaseTagList').addEventListener('click', function(event) { if (event.target.nodeName == 'TD') { - appGoto('Browse', 'Database', 'Album', '0/-/' + event.target.parentNode.getAttribute('data-uri')); + appGoto('Browse', 'Database', app.current.view, '0/-/' + event.target.parentNode.getAttribute('data-uri')); } }, false); @@ -505,6 +522,10 @@ function appInit() { appGoto('Search', undefined, undefined, '0/' + app.current.filter + '/' + this.value); }, false); + document.getElementById('BrowseDatabaseByTagDropdown').addEventListener('click', function(event) { + if (event.target.nodeName == 'BUTTON') + appGoto(app.current.app, app.current.tab, event.target.getAttribute('data-tag') , '0/' + app.current.filter + '/' + app.current.search); + }, false); document.getElementsByTagName('body')[0].addEventListener('click', function(event) { var oldPopover = document.getElementsByClassName('popover')[0]; @@ -1212,14 +1233,60 @@ function parsePlaylists(obj) { } function parseListDBtags(obj) { - if (app.current.app !== 'Browse' && app.current.tab !== 'Database' && app.current.view !== 'Artist') return; - - if (obj.tagtype == 'AlbumArtist') { - document.getElementById('BrowseDatabaseAlbumList').classList.add('hide'); - document.getElementById('BrowseDatabaseArtistList').classList.remove('hide'); - document.getElementById('btnBrowseDatabaseArtist').parentNode.classList.add('hide'); +// if (app.current.app !== 'Browse' && app.current.tab !== 'Database' && app.current.view !== 'AlbumArtist') +// return; + if (app.current.search != '') { + document.getElementById('BrowseDatabaseAlbumList').classList.remove('hide'); + document.getElementById('BrowseDatabaseTagList').classList.add('hide'); + document.getElementById('btnBrowseDatabaseByTag').parentNode.classList.add('hide'); + document.getElementById('btnBrowseDatabaseTag').parentNode.classList.remove('hide'); + document.getElementById('btnBrowseDatabaseTag').innerHTML = '« ' + app.current.view; var nrItems = obj.data.length; - var tbody = document.getElementById(app.current.app + app.current.tab + app.current.view + 'List').getElementsByTagName('tbody')[0]; + if (nrItems == 1 && obj.data[0].value == '') + nrItems = 0; + var cardContainer = document.getElementById('BrowseDatabaseAlbumList'); + var cards = cardContainer.getElementsByClassName('col-md'); + for (var i = 0; i < nrItems; i++) { + var id=genId(obj.data[i].value); + if (cards[i]) + if (cards[i].getAttribute('id') == id) + continue; + var card=document.createElement('div'); + card.classList.add('col-md'); + card.classList.add('mr-0'); + card.setAttribute('id', id); + card.innerHTML = '
' + + ' ' + + '
' + + '
' + obj.searchstr + '
' + + '

' + obj.data[i].value + '

' + + '
'+ + ''; + + if (i < cards.length) + cards[i].replaceWith(card); + else + cardContainer.append(card); + + sendAPI({"cmd": "MPD_API_DATABASE_TAG_ALBUM_TITLE_LIST", "data": { "album": obj.data[i].value, "search": app.current.search, "tag": app.current.view}}, parseListTitles); + } + var cardsLen = cards.length - 1; + for (var i = cardsLen; i >= nrItems; i --) { + cards[i].remove(); + } + setPagination(obj.totalEntities); + document.getElementById('BrowseDatabaseAlbumList').classList.remove('opacity05'); + } + else { + document.getElementById('BrowseDatabaseAlbumList').classList.add('hide'); + document.getElementById('BrowseDatabaseTagList').classList.remove('hide'); + document.getElementById('btnBrowseDatabaseByTag').parentNode.classList.remove('hide'); + document.getElementById('btnBrowseDatabaseTag').parentNode.classList.add('hide'); + var nrItems = obj.data.length; + if (nrItems == 1 && obj.data[0].value == '') + nrItems = 0; + var tbody = document.getElementById(app.current.app + app.current.tab + 'TagList').getElementsByTagName('tbody')[0]; var tr = tbody.getElementsByTagName('tr'); for (var i = 0; i < nrItems; i++) { var uri = encodeURI(obj.data[i].value); @@ -1247,52 +1314,13 @@ function parseListDBtags(obj) { if (nrItems == 0) tbody.innerHTML = '' + ''; - document.getElementById('BrowseDatabaseArtistList').classList.remove('opacity05'); - - } else if (obj.tagtype == 'Album') { - document.getElementById('BrowseDatabaseAlbumList').classList.remove('hide'); - document.getElementById('BrowseDatabaseArtistList').classList.add('hide'); - document.getElementById('btnBrowseDatabaseArtist').parentNode.classList.remove('hide'); - var nrItems = obj.data.length; - var cardContainer = document.getElementById('BrowseDatabaseAlbumList'); - var cards = cardContainer.getElementsByClassName('col-md'); - for (var i = 0; i < nrItems; i++) { - var id=genId(obj.data[i].value); - if (cards[i]) - if (cards[i].getAttribute('id') == id) - continue; - var card=document.createElement('div'); - card.classList.add('col-md'); - card.classList.add('mr-0'); - card.setAttribute('id', id); - card.innerHTML = '
' + - ' ' + - '
' + - '
' + obj.searchstr + '
' + - '

' + obj.data[i].value + '

' + - '
error_outlineNo entries found.
'+ - ''; - - if (i < cards.length) - cards[i].replaceWith(card); - else - cardContainer.append(card); - - sendAPI({"cmd": "MPD_API_DATABASE_ARTISTALBUMTITLE_LIST", "data": { "albumartist": obj.searchstr, "album": obj.data[i].value}}, parseListTitles); - } - var cardsLen = cards.length - 1; - for (var i = cardsLen; i >= nrItems; i --) { - cards[i].remove(); - } - setPagination(obj.totalEntities); - document.getElementById('BrowseDatabaseAlbumList').classList.remove('opacity05'); + document.getElementById('BrowseDatabaseTagList').classList.remove('opacity05'); } } function parseListTitles(obj) { - if (app.current.app !== 'Browse' && app.current.tab !== 'Database' && app.current.view !== 'Album') - return; +// if (app.current.app !== 'Browse' && app.current.tab !== 'Database' && app.current.view !== 'Album') +// return; var id = genId(obj.album); var card = document.getElementById('card' + id) @@ -2114,6 +2142,10 @@ function addFilterLetter(x) { }, false); } +function gotoTagList() { + appGoto(app.current.app, app.current.tab, app.current.view, '0/-/'); +} + function chVolume(increment) { var newValue = parseInt(domCache.volumeBar.value) + increment; if (newValue < 0) diff --git a/src/mpd_client.c b/src/mpd_client.c index afcf8d0..100d5be 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -162,14 +162,6 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) { } n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); break; - case MPD_API_DATABASE_ARTISTALBUMTITLE_LIST: - je = json_scanf(msg.p, msg.len, "{data: {albumartist: %Q, album: %Q}}", &p_charbuf1, &p_charbuf2); - if (je == 2) { - n = mympd_put_songs_in_album(mpd.buf, p_charbuf1, p_charbuf2); - free(p_charbuf1); - free(p_charbuf2); - } - break; case MPD_API_WELCOME: n = mympd_put_welcome(mpd.buf); break; @@ -295,21 +287,32 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) { free(p_charbuf1); } break; - case MPD_API_DATABASE_ARTIST_LIST: - je = json_scanf(msg.p, msg.len, "{data: {offset: %u, filter: %Q}}", &uint_buf1, &p_charbuf1); - if (je == 2) { - n = mympd_put_db_tag(mpd.buf, uint_buf1, "AlbumArtist", "", "", p_charbuf1); - free(p_charbuf1); - } - break; - case MPD_API_DATABASE_ARTISTALBUM_LIST: - je = json_scanf(msg.p, msg.len, "{data: {offset: %u, filter: %Q, albumartist: %Q}}", &uint_buf1, &p_charbuf1, &p_charbuf2); + case MPD_API_DATABASE_TAG_LIST: + je = json_scanf(msg.p, msg.len, "{data: {offset: %u, filter: %Q, tag: %Q}}", &uint_buf1, &p_charbuf1, &p_charbuf2); if (je == 3) { - n = mympd_put_db_tag(mpd.buf, uint_buf1, "Album", "AlbumArtist", p_charbuf2, p_charbuf1); + n = mympd_put_db_tag(mpd.buf, uint_buf1, p_charbuf2, "", "", p_charbuf1); free(p_charbuf1); free(p_charbuf2); } break; + case MPD_API_DATABASE_TAG_ALBUM_LIST: + je = json_scanf(msg.p, msg.len, "{data: {offset: %u, filter: %Q, search: %Q, tag: %Q}}", &uint_buf1, &p_charbuf1, &p_charbuf2, &p_charbuf3); + if (je == 4) { + n = mympd_put_db_tag(mpd.buf, uint_buf1, "Album", p_charbuf3, p_charbuf2, p_charbuf1); + free(p_charbuf1); + free(p_charbuf2); + free(p_charbuf3); + } + break; + case MPD_API_DATABASE_TAG_ALBUM_TITLE_LIST: + je = json_scanf(msg.p, msg.len, "{data: {album: %Q, search: %Q, tag: %Q}}", &p_charbuf1, &p_charbuf2, &p_charbuf3); + if (je == 3) { + n = mympd_put_songs_in_album(mpd.buf, p_charbuf1, p_charbuf2, p_charbuf3); + free(p_charbuf1); + free(p_charbuf2); + free(p_charbuf3); + } + break; case MPD_API_PLAYLIST_RENAME: je = json_scanf(msg.p, msg.len, "{data: {from: %Q, to: %Q}}", &p_charbuf1, &p_charbuf2); if (je == 2) { @@ -1410,7 +1413,7 @@ int mympd_put_db_tag(char *buffer, unsigned int offset, char *mpdtagtype, char * return len; } -int mympd_put_songs_in_album(char *buffer, char *albumartist, char *album) { +int mympd_put_songs_in_album(char *buffer, char *album, char *search, char *tag) { struct mpd_song *song; unsigned long entity_count = 0; unsigned long entities_returned = 0; @@ -1421,7 +1424,7 @@ int mympd_put_songs_in_album(char *buffer, char *albumartist, char *album) { if (mpd_search_db_songs(mpd.conn, true) == false) RETURN_ERROR_AND_RECOVER("mpd_search_db_songs"); - if (mpd_search_add_tag_constraint(mpd.conn, MPD_OPERATOR_DEFAULT, MPD_TAG_ALBUM_ARTIST, albumartist) == false) + if (mpd_search_add_tag_constraint(mpd.conn, MPD_OPERATOR_DEFAULT, mpd_tag_name_parse(tag), search) == false) RETURN_ERROR_AND_RECOVER("mpd_search_add_tag_constraint"); if (mpd_search_add_tag_constraint(mpd.conn, MPD_OPERATOR_DEFAULT, MPD_TAG_ALBUM, album) == false) @@ -1450,11 +1453,12 @@ int mympd_put_songs_in_album(char *buffer, char *albumartist, char *album) { mpd_song_free(song); } - len += json_printf(&out, "], totalEntities: %d, returnedEntities: %d, albumartist: %Q, album: %Q, cover: %Q}", + len += json_printf(&out, "], totalEntities: %d, returnedEntities: %d, album: %Q, search: %Q, tag: %Q, cover: %Q}", entity_count, entities_returned, - albumartist, album, + search, + tag, cover ); } diff --git a/src/mpd_client.h b/src/mpd_client.h index c1adf3f..d39cc27 100644 --- a/src/mpd_client.h +++ b/src/mpd_client.h @@ -75,9 +75,9 @@ X(MPD_API_DATABASE_SEARCH) \ X(MPD_API_DATABASE_UPDATE) \ X(MPD_API_DATABASE_FILESYSTEM_LIST) \ - X(MPD_API_DATABASE_ARTISTALBUM_LIST) \ - X(MPD_API_DATABASE_ARTISTALBUMTITLE_LIST) \ - X(MPD_API_DATABASE_ARTIST_LIST) \ + X(MPD_API_DATABASE_TAG_LIST) \ + X(MPD_API_DATABASE_TAG_ALBUM_LIST) \ + X(MPD_API_DATABASE_TAG_ALBUM_TITLE_LIST) \ X(MPD_API_DATABASE_STATS) \ X(MPD_API_DATABASE_SONGDETAILS) \ X(MPD_API_PLAYER_PLAY_TRACK) \ @@ -194,7 +194,7 @@ int mympd_put_welcome(char *buffer); int mympd_put_stats(char *buffer); int mympd_put_settings(char *buffer); int mympd_put_db_tag(char *buffer, unsigned int offset, char *mpdtagtype, char *mpdsearchtagtype, char *searchstr, char *filter); -int mympd_put_songs_in_album(char *buffer, char *albumartist, char *album); +int mympd_put_songs_in_album(char *buffer, char *album, char *search, char *tag); int mympd_put_playlists(char *buffer, unsigned int offset, char *filter); int mympd_put_playlist_list(char *buffer, char *uri, unsigned int offset, char *filter); int mympd_put_songdetails(char *buffer, char *uri); diff --git a/src/mympd.c b/src/mympd.c index be7a21d..d5312d9 100644 --- a/src/mympd.c +++ b/src/mympd.c @@ -229,6 +229,7 @@ int main(int argc, char **argv) { nc = mg_bind_opt(&mgr, config.sslport, ev_handler, bind_opts); if (nc == NULL) { printf("Error listening on port %s: %s\n", config.sslport, err); + mg_mgr_free(&mgr); return EXIT_FAILURE; } } @@ -236,6 +237,7 @@ int main(int argc, char **argv) { nc = mg_bind(&mgr, config.webport, ev_handler); if (nc == NULL) { printf("Error listening on port %s\n", config.webport); + mg_mgr_free(&mgr); return EXIT_FAILURE; } } From 5eb16aa17c62e56eb25f59ee38b92b09cc647381 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Mon, 10 Sep 2018 22:51:53 +0200 Subject: [PATCH 20/24] Feat: "add all" button in browse database detail views (backend to be done) #43 --- htdocs/index.html | 17 ++++++++++++++--- htdocs/js/mympd.js | 4 +++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/htdocs/index.html b/htdocs/index.html index 5809b80..d0a4e9a 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -319,6 +319,17 @@ +
+
+ + + +
+
+
@@ -375,7 +386,7 @@
- +
diff --git a/htdocs/js/mympd.js b/htdocs/js/mympd.js index b822908..43787fd 100644 --- a/htdocs/js/mympd.js +++ b/htdocs/js/mympd.js @@ -1240,6 +1240,7 @@ function parseListDBtags(obj) { document.getElementById('BrowseDatabaseTagList').classList.add('hide'); document.getElementById('btnBrowseDatabaseByTag').parentNode.classList.add('hide'); document.getElementById('btnBrowseDatabaseTag').parentNode.classList.remove('hide'); + document.getElementById('BrowseDatabaseAddAllSongs').parentNode.parentNode.classList.remove('hide'); document.getElementById('btnBrowseDatabaseTag').innerHTML = '« ' + app.current.view; var nrItems = obj.data.length; if (nrItems == 1 && obj.data[0].value == '') @@ -1282,6 +1283,7 @@ function parseListDBtags(obj) { document.getElementById('BrowseDatabaseAlbumList').classList.add('hide'); document.getElementById('BrowseDatabaseTagList').classList.remove('hide'); document.getElementById('btnBrowseDatabaseByTag').parentNode.classList.remove('hide'); + document.getElementById('BrowseDatabaseAddAllSongs').parentNode.parentNode.classList.add('hide'); document.getElementById('btnBrowseDatabaseTag').parentNode.classList.add('hide'); var nrItems = obj.data.length; if (nrItems == 1 && obj.data[0].value == '') @@ -1943,7 +1945,7 @@ function confirmSettings() { document.getElementById('settingsFrm').classList.add('was-validated'); } -function addAllFromBrowse() { +function addAllFromBrowseFilesystem() { sendAPI({"cmd": "MPD_API_QUEUE_ADD_TRACK", "data": {"uri": app.current.search}}); showNotification('Added all songs', '', '', 'success'); } From 1e39e7346dcb50acd1a3a389866a54ca7b557bc1 Mon Sep 17 00:00:00 2001 From: jcorporation Date: Tue, 11 Sep 2018 19:59:22 +0100 Subject: [PATCH 21/24] Feat: "Add all" button in database browse mode #43 Feat: generate taglist from mpd setting "metadata_to_use" --- htdocs/css/mympd.css | 7 ++- htdocs/index.html | 31 ++---------- htdocs/js/mympd.js | 109 ++++++++++++++++++++++++++----------------- src/mpd_client.c | 16 +++++-- 4 files changed, 85 insertions(+), 78 deletions(-) diff --git a/htdocs/css/mympd.css b/htdocs/css/mympd.css index 1f5064f..65e5cbf 100644 --- a/htdocs/css/mympd.css +++ b/htdocs/css/mympd.css @@ -275,4 +275,9 @@ caption { .modal-body .album-cover { float:none; -} \ No newline at end of file +} + +#BrowseDatabaseAlbumListCaption { + width:100%; + margin-left: 15px; +} diff --git a/htdocs/index.html b/htdocs/index.html index d0a4e9a..3219552 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -134,16 +134,6 @@ Any Tag
@@ -302,13 +292,6 @@
@@ -356,7 +339,9 @@
-
+
+

+
@@ -465,16 +450,6 @@ Any Tag
diff --git a/htdocs/js/mympd.js b/htdocs/js/mympd.js index 43787fd..d90682c 100644 --- a/htdocs/js/mympd.js +++ b/htdocs/js/mympd.js @@ -198,15 +198,7 @@ function appRoute() { sendAPI({"cmd": "MPD_API_PLAYER_CURRENT_SONG"}, songChange); } else if (app.current.app == 'Queue' ) { - var btns = document.getElementById('searchqueuetag').getElementsByTagName('button'); - var btnsLen = btns.length; - for (var i = 0; i < btnsLen; i++) { - btns[i].classList.remove('active'); - if (btns[i].getAttribute('data-tag') == app.current.filter) { - btns[i].classList.add('active'); - document.getElementById('searchqueuetagdesc').innerText = btns[i].innerText; - } - } + selectTag('searchqueuetag', 'searchqueuetagdesc', app.current.filter); getQueue(); } else if (app.current.app == 'Browse' && app.current.tab == 'Playlists' && app.current.view == 'All') { @@ -226,15 +218,7 @@ function appRoute() { else { sendAPI({"cmd": "MPD_API_DATABASE_TAG_LIST","data": {"offset": app.current.page, "filter": app.current.filter, "tag": app.current.view}}, parseListDBtags); doSetFilterLetter('BrowseDatabaseFilter'); - var btns = document.getElementById('BrowseDatabaseByTagDropdown').getElementsByTagName('button'); - var btnsLen = btns.length; - for (var i = 0; i < btnsLen; i++) { - btns[i].classList.remove('active'); - if (btns[i].getAttribute('data-tag') == app.current.view) { - btns[i].classList.add('active'); - document.getElementById('btnBrowseDatabaseByTag').innerText = btns[i].innerText; - } - } + selectTag('BrowseDatabaseByTagDropdown', 'btnBrowseDatabaseByTag', app.current.view); } } else if (app.current.app == 'Browse' && app.current.tab == 'Filesystem') { @@ -292,16 +276,7 @@ function appRoute() { document.getElementById('SearchList').classList.remove('opacity05'); setPagination(0); } - - var btns = document.getElementById('searchtags').getElementsByTagName('button'); - var btnsLen = btns.length; - for (var i = 0; i < btnsLen; i++) { - btns[i].classList.remove('active'); - if (btns[i].getAttribute('data-tag') == app.current.filter) { - btns[i].classList.add('active'); - document.getElementById('searchtagsdesc').innerText = btns[i].innerText; - } - } + selectTag('searchtags', 'searchtagsdesc', app.current.filter); } else { appGoto("Playback"); @@ -488,13 +463,24 @@ function appInit() { document.getElementById('searchAddAllSongsDropdown').addEventListener('click', function(event) { if (event.target.nodeName == 'BUTTON') { if (event.target.innerText == 'Add all to queue') { - addAllFromSearch(); + addAllFromSearchPlist('queue'); } else if (event.target.innerText == 'Add all to playlist') { showAddToPlaylist('SEARCH'); } } }, false); + + document.getElementById('BrowseDatabaseAddAllSongsDropdown').addEventListener('click', function(event) { + if (event.target.nodeName == 'BUTTON') { + if (event.target.innerText == 'Add all to queue') { + addAllFromBrowseDatabasePlist('queue'); + } + else if (event.target.innerText == 'Add all to playlist') { + showAddToPlaylist('DATABASE'); + } + } + }, false); document.getElementById('searchtags').addEventListener('click', function(event) { if (event.target.nodeName == 'BUTTON') @@ -862,13 +848,17 @@ function parseSettings(obj) { document.getElementsByClassName('mixramp')[0].style.display = 'none'; } - settings=obj.data; + settings = obj.data; settings.mpdstream = 'http://'; if (settings.mpdhost == '127.0.0.1' || settings.mpdhost == 'localhost') settings.mpdstream += window.location.hostname; else settings.mpdstream += settings.mpdhost; settings.mpdstream += ':' + settings.streamport + '/'; + + addTagList('BrowseDatabaseByTagDropdown', false); + addTagList('searchqueuetag', true); + addTagList('searchtags', true); } function getSettings() { @@ -1242,6 +1232,7 @@ function parseListDBtags(obj) { document.getElementById('btnBrowseDatabaseTag').parentNode.classList.remove('hide'); document.getElementById('BrowseDatabaseAddAllSongs').parentNode.parentNode.classList.remove('hide'); document.getElementById('btnBrowseDatabaseTag').innerHTML = '« ' + app.current.view; + document.getElementById('BrowseDatabaseAlbumListCaption').innerText = obj.searchtagtype + ': ' + obj.searchstr; var nrItems = obj.data.length; if (nrItems == 1 && obj.data[0].value == '') nrItems = 0; @@ -1259,7 +1250,7 @@ function parseListDBtags(obj) { card.innerHTML = '
' + ' ' + '
' + - '
' + obj.searchstr + '
' + + '
' + '

' + obj.data[i].value + '

' + ' '+ @@ -1285,11 +1276,13 @@ function parseListDBtags(obj) { document.getElementById('btnBrowseDatabaseByTag').parentNode.classList.remove('hide'); document.getElementById('BrowseDatabaseAddAllSongs').parentNode.parentNode.classList.add('hide'); document.getElementById('btnBrowseDatabaseTag').parentNode.classList.add('hide'); + + if (obj.data[0] && obj.data[0].value == '') + obj.data.shift(); var nrItems = obj.data.length; - if (nrItems == 1 && obj.data[0].value == '') - nrItems = 0; var tbody = document.getElementById(app.current.app + app.current.tab + 'TagList').getElementsByTagName('tbody')[0]; var tr = tbody.getElementsByTagName('tr'); + var skipped = 0; for (var i = 0; i < nrItems; i++) { var uri = encodeURI(obj.data[i].value); if (tr[i]) @@ -1333,6 +1326,7 @@ function parseListTitles(obj) { imga.setAttribute('data-uri', encodeURI(obj.data[0].uri.replace(/\/[^\/]+$/, ''))); imga.setAttribute('data-name', obj.album); imga.setAttribute('data-type', 'dir'); + document.getElementById('albumartist' + id).innerText = obj.albumartist; var titleList = ''; var nrItems = obj.data.length; @@ -1622,10 +1616,12 @@ function addToPlaylist() { } } if (plist != '') { - if (uri != 'SEARCH') - sendAPI({"cmd": "MPD_API_PLAYLIST_ADD_TRACK", "data": {"uri": uri, "plist": plist}}); + if (uri == 'SEARCH') + addAllFromSearchPlist(plist); + else if (uri == 'DATABASE') + addAllFromBrowseDatabasePlist(plist); else - addAllFromSearchPlist(plist); + sendAPI({"cmd": "MPD_API_PLAYLIST_ADD_TRACK", "data": {"uri": uri, "plist": plist}}); modalAddToPlaylist.hide(); } else { @@ -1950,13 +1946,6 @@ function addAllFromBrowseFilesystem() { showNotification('Added all songs', '', '', 'success'); } -function addAllFromSearch() { - if (app.current.search.length >= 2) { - sendAPI({"cmd": "MPD_API_DATABASE_SEARCH", "data": {"plist": "queue", "filter": app.current.filter, "searchstr": app.current.search, "offset": 0}}); - showNotification('Added '+ parseInt(document.getElementById('panel-heading-search').innerText) +' songs from search', '', '', 'success'); - } -} - function addAllFromSearchPlist(plist) { if (app.current.search.length >= 2) { sendAPI({"cmd": "MPD_API_DATABASE_SEARCH", "data": {"plist": plist, "filter": app.current.filter, "searchstr": app.current.search, "offset": 0}}); @@ -1964,6 +1953,13 @@ function addAllFromSearchPlist(plist) { } } +function addAllFromBrowseDatabasePlist(plist) { + if (app.current.search.length >= 2) { + sendAPI({"cmd": "MPD_API_DATABASE_SEARCH", "data": {"plist": plist, "filter": app.current.view, "searchstr": app.current.search, "offset": 0}}); + showNotification('Added songs from database selection to ' + plist, '', '', 'success'); + } +} + function scrollTo(pos) { document.body.scrollTop = pos; // For Safari document.documentElement.scrollTop = pos; // For Chrome, Firefox, IE and Opera @@ -2144,6 +2140,31 @@ function addFilterLetter(x) { }, false); } +function selectTag(btnsEl, desc, setTo) { + var btns = document.getElementById(btnsEl); + var aBtn = btns.querySelector('.active') + if (aBtn) + aBtn.classList.remove('active'); + aBtn = btns.querySelector('[data-tag=' + setTo + ']'); + if (aBtn) { + aBtn.classList.add('active'); + document.getElementById(desc).innerText = aBtn.innerText; + } +} + +function addTagList(x, any) { + var tagList = ''; + if (any == true) + tagList += ''; + for (var key in settings.tags) { + if (settings.tags[key] == true && key != 'Track') { + tagList += ''; + } + } + var tagListEl = document.getElementById(x); + tagListEl.innerHTML = tagList; +} + function gotoTagList() { appGoto(app.current.app, app.current.tab, app.current.view, '0/-/'); } @@ -2170,7 +2191,7 @@ function beautifyDuration(x) { } function genId(x) { - return 'id' + x.replace(/[^\w]/g, ''); + return 'id' + x.replace(/[^\w\-\_]/g, ''); } //Init app diff --git a/src/mpd_client.c b/src/mpd_client.c index 100d5be..b44ee22 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -636,7 +636,7 @@ void mympd_mpd_features() { if (mpd.tag_artist == false) printf("WARNING: Artist tag not enabled in mpd\n"); if (mpd.tag_album_artist == false) - printf("WARNING: Albumartist tag not enabled in mpd\n"); + printf("WARNING: AlbumArtist tag not enabled in mpd\n"); if (mpd.tag_title == false) printf("WARNING: Title tag not enabled in mpd\n"); if (mpd.tag_track == false) @@ -868,6 +868,8 @@ char* mympd_get_tag(struct mpd_song const *song, enum mpd_tag_type tag) { if (str == NULL) { if (tag == MPD_TAG_TITLE) str = basename((char *)mpd_song_get_uri(song)); + else if (tag == MPD_TAG_ALBUM_ARTIST) + str = (char *)mpd_song_get_tag(song, MPD_TAG_ARTIST, 0); else str = "-"; } @@ -1419,6 +1421,7 @@ int mympd_put_songs_in_album(char *buffer, char *album, char *search, char *tag) unsigned long entities_returned = 0; int len; char cover[500]; + char *albumartist; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); if (mpd_search_db_songs(mpd.conn, true) == false) @@ -1440,9 +1443,10 @@ int mympd_put_songs_in_album(char *buffer, char *album, char *search, char *tag) if (entity_count <= MAX_ELEMENTS_PER_PAGE) { if (entities_returned ++) len += json_printf(&out, ", "); - else + else { mympd_get_cover(mpd_song_get_uri(song), cover, 500); - + albumartist = strdup(mympd_get_tag(song, MPD_TAG_ALBUM_ARTIST)); + } len += json_printf(&out, "{type: song, uri: %Q, duration: %d, title: %Q, track: %Q}", mpd_song_get_uri(song), mpd_song_get_duration(song), @@ -1453,15 +1457,17 @@ int mympd_put_songs_in_album(char *buffer, char *album, char *search, char *tag) mpd_song_free(song); } - len += json_printf(&out, "], totalEntities: %d, returnedEntities: %d, album: %Q, search: %Q, tag: %Q, cover: %Q}", + len += json_printf(&out, "], totalEntities: %d, returnedEntities: %d, album: %Q, search: %Q, tag: %Q, cover: %Q, albumartist: %Q}", entity_count, entities_returned, album, search, tag, - cover + cover, + albumartist ); } + free(albumartist); if (len > MAX_SIZE) printf("Buffer truncated\n"); From c4bd90609eede06ee9b07d602c7578b47743be4e Mon Sep 17 00:00:00 2001 From: jcorporation Date: Tue, 11 Sep 2018 20:59:33 +0100 Subject: [PATCH 22/24] Fix: use mpd taglist in songdetails modal Feat: link album in playback card --- htdocs/index.html | 16 +----------- htdocs/js/mympd.js | 63 +++++++++++++++++++++++++--------------------- src/mpd_client.c | 8 +++++- src/mpd_client.h | 2 ++ 4 files changed, 45 insertions(+), 44 deletions(-) diff --git a/htdocs/index.html b/htdocs/index.html index 3219552..0b261e0 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -87,7 +87,7 @@ Artist

Album -

+

- - - - - - - - - - - - - -
Artist
Album
Track
Albumartist
Composer
Performer
Genre
Date
Uri
Statistics
Play count
Skip count
Last played
Like
diff --git a/htdocs/js/mympd.js b/htdocs/js/mympd.js index d90682c..130d122 100644 --- a/htdocs/js/mympd.js +++ b/htdocs/js/mympd.js @@ -1438,7 +1438,13 @@ function songClick() { function artistClick() { var albumartist = domCache.currentArtist.getAttribute('data-albumartist'); if (albumartist != '') - appGoto('Browse', 'Database', 'Album', '0/-/' + albumartist); + appGoto('Browse', 'Database', 'AlbumArtist', '0/-/' + albumartist); +} + +function albumClick() { + var album = domCache.currentAlbum.getAttribute('data-album'); + if (album != '') + appGoto('Browse', 'Database', 'Album', '0/-/' + album); } function songDetails(uri) { @@ -1450,36 +1456,36 @@ function parseSongDetails(obj) { var modal = document.getElementById('modalSongDetails'); modal.getElementsByClassName('album-cover')[0].style.backgroundImage = 'url("' + obj.data.cover + '")'; modal.getElementsByTagName('h1')[0].innerText = obj.data.title; - var tr = modal.getElementsByTagName('tr'); - var trLen = tr.length; - for (var i = 0; i < trLen; i++) { - var key = tr[i].getAttribute('data-name'); - if (!key) - continue; - var value = obj.data[key]; - if (key == 'duration') { - var minutes = Math.floor(value / 60); - var seconds = value - minutes * 60; - value = minutes + ':' + (seconds < 10 ? '0' : '') + seconds; - } - else if (key == 'lastPlayed') { - if (value == 0) - value = 'never'; - else { - var d = new Date(value * 1000); - value = d.toUTCString(); + + 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 + ''; } - else if (key == 'like') { - if (value == 0) value = 'thumb_down_alt'; - else if (value == 2) value = 'thumb_up_alt'; - else value = 'not voted'; - } - else if (key == 'uri') { - value = '' + value + ''; - } - tr[i].getElementsByTagName('td')[0].innerHTML = value; } + + songDetails += 'Uri' + obj.data.uri + ''; + + if (settings.stickers == true) { + var like = 'not voted'; + if (obj.data.like == 0) + like = 'thumb_down_alt'; + else if (obj.data.like == 2) + 'thumb_up_alt'; + songDetails += 'Statistics' + + 'Play count' + obj.data.playCount + '' + + 'Skip count' + obj.data.skipCount + '' + + 'Last played' + (obj.data.lastPlayed == 0 ? 'never' : new Date(value * 1000).toUTCString()) + '' + + 'Like' + like + ''; + } + + modal.getElementsByTagName('tbody')[0].innerHTML = songDetails; } function playlistDetails(uri) { @@ -2066,6 +2072,7 @@ function songChange(obj) { textNotification += ' - ' + obj.data.album; htmlNotification += '
' + obj.data.album; domCache.currentAlbum.innerText = obj.data.album; + domCache.currentAlbum.setAttribute('data-album', obj.data.album); } else domCache.currentAlbum.innerText = ''; diff --git a/src/mpd_client.c b/src/mpd_client.c index b44ee22..7483b47 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -588,6 +588,7 @@ 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; @@ -615,6 +616,8 @@ void mympd_mpd_features() { 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) @@ -635,6 +638,8 @@ void mympd_mpd_features() { printf("\n"); if (mpd.tag_artist == false) printf("WARNING: Artist tag not enabled in mpd\n"); + if (mpd.tag_album == false) + printf("WARNING: Album tag not enabled in mpd\n"); if (mpd.tag_album_artist == false) printf("WARNING: AlbumArtist tag not enabled in mpd\n"); if (mpd.tag_title == false) @@ -979,7 +984,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, " "maxElementsPerPage: %d, replaygain: %Q, notificationWeb: %d, notificationPage: %d, " - "tags: { Artist: %B, AlbumArtist: %B, Title: %B, Track: %B, Genre: %B, Date: %B," + "tags: { Artist: %B, Album: %B, AlbumArtist: %B, Title: %B, Track: %B, Genre: %B, Date: %B," "Composer: %B, Performer: %B }" "}}", mpd_status_get_repeat(status), @@ -1001,6 +1006,7 @@ int mympd_put_settings(char *buffer) { state.a, state.b, mpd.tag_artist, + mpd.tag_album, mpd.tag_album_artist, mpd.tag_title, mpd.tag_track, diff --git a/src/mpd_client.h b/src/mpd_client.h index d39cc27..b2aacf1 100644 --- a/src/mpd_client.h +++ b/src/mpd_client.h @@ -131,8 +131,10 @@ struct t_mpd { // Features const unsigned* protocol; + // Supported tags bool feat_sticker; bool tag_artist; + bool tag_album; bool tag_album_artist; bool tag_title; bool tag_track; From 0e9cc45f5f987eed819d28e5fbec3c40e69dc99f Mon Sep 17 00:00:00 2001 From: jcorporation Date: Tue, 11 Sep 2018 21:08:48 +0100 Subject: [PATCH 23/24] Fix: display of like in songdetails --- htdocs/js/mympd.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/js/mympd.js b/htdocs/js/mympd.js index 130d122..22bf15e 100644 --- a/htdocs/js/mympd.js +++ b/htdocs/js/mympd.js @@ -1477,8 +1477,8 @@ function parseSongDetails(obj) { if (obj.data.like == 0) like = 'thumb_down_alt'; else if (obj.data.like == 2) - 'thumb_up_alt'; - songDetails += 'Statistics' + + like = 'thumb_up_alt'; + songDetails += 'Statistics' + 'Play count' + obj.data.playCount + '' + 'Skip count' + obj.data.skipCount + '' + 'Last played' + (obj.data.lastPlayed == 0 ? 'never' : new Date(value * 1000).toUTCString()) + '' + From 8f16fabdb36e56147f67c4b2e2cd6d9339710fde Mon Sep 17 00:00:00 2001 From: jcorporation Date: Tue, 11 Sep 2018 21:13:55 +0100 Subject: [PATCH 24/24] Fix: update minified files --- dist/htdocs/css/mympd.min.css | 2 +- dist/htdocs/index.html | 2 +- dist/htdocs/js/mympd.min.js | 145 +++++++++++++++++----------------- 3 files changed, 76 insertions(+), 73 deletions(-) diff --git a/dist/htdocs/css/mympd.min.css b/dist/htdocs/css/mympd.min.css index 628abc2..88b784e 100644 --- a/dist/htdocs/css/mympd.min.css +++ b/dist/htdocs/css/mympd.min.css @@ -1 +1 @@ -html{position:relative;min-height:100%}body{margin-bottom:60px;padding-top:50px;padding-bottom:50px;background-color:#888}main{padding-top:20px}footer{position:absolute;bottom:0}button{overflow:hidden}#BrowseBreadrumb{overflow:auto;white-space:nowrap}#BrowseBreadcrumb>li>a{cursor:pointer}.card{min-height:350px}@media only screen and (max-width:576px){.header-logo{display:none!important}}.clickable{cursor:pointer}.tblnum,.tblaction{width:30px}small{color:#aaa}.card-footer-playback{padding:0}.album-cover{background-size:cover;border:1px solid black;border-radius:5px;overflow:hidden;width:240px;height:240px;background-color:#eee;float:left;margin-right:20px;margin-bottom:20px}.album-desc{min-width:240px;float:left}.hide{display:none!important}.pull-right{float:right!important}.card-toolbar{margin-bottom:10px}.card-toolbar>div,.card-toolbar>form{margin-bottom:5px}@font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(/assets/MaterialIcons-Regular.eot);src:local('Material Icons'),local('MaterialIcons-Regular');src:url(/assets/MaterialIcons-Regular.woff2) format('woff2'),url(/assets/MaterialIcons-Regular.woff) format('woff'),url(/assets/MaterialIcons-Regular.ttf) format('truetype')}.material-icons{font-family:'Material Icons';font-weight:normal;font-style:normal;font-size:18px;display:inline-block;line-height:1;text-transform:none;letter-spacing:normal;word-wrap:normal;white-space:nowrap;direction:ltr;vertical-align:top;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;font-feature-settings:'liga'}.material-icons-small{font-size:16px}.material-icons-small-left{font-size:1rem;margin-left:-1em}.color-darkgrey,.color-darkgrey:hover{color:#6c757d!important}#btn-outputs-block>button{margin-bottom:10px}#btn-outputs-block>button:last-child{margin-bottom:0}.card-body{overflow-x:hidden}.progressBarPlay{font-size:22px}#counter{cursor:text}#volumeBar{margin-top:2px;width:160px}.title-icon{float:left;margin-right:5px;font-size:1.8rem}.header-logo{font-size:2rem;float:left;margin-right:5px}.letters>button{width:28px;height:28px}.col-md{max-width:250px;min-width:250px}a.card-img-top{overflow:hidden;display:block}button.active{color:#fff;background-color:#28a745!important;border-color:#28a745!important}button.active-fg-green{color:#28a745!important}button.active-fg-red{color:#bd2130!important}div#alertBox{position:fixed;top:50px;right:10px;width:80%;max-width:400px;z-index:1000;opacity:0;visibility:visible;transition:opacity .5s ease-in}div.alertBoxActive{opacity:1!important;visibility:visible!important;transition:opacity .5s ease-in}.popover-content{padding-top:4px;padding-bottom:4px}.opacity05{opacity:.5}caption{caption-side:top;font-size:120%;font-weight:bold;color:black}.dragover>td{border-top:25px solid transparent}[draggable]{-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;user-select:none;-khtml-user-drag:element;-webkit-user-drag:element}@keyframes changewidth{0%{margin-left:-20px}to{margin-left:100%}}#updateDBprogress{width:20px}.updateDBprogressAnimate{animation-duration:2s;animation-name:changewidth;animation-iteration-count:infinite}.modal-body{overflow-x:hidden}.modal-body .album-cover{float:none} \ No newline at end of file +html{position:relative;min-height:100%}body{margin-bottom:60px;padding-top:50px;padding-bottom:50px;background-color:#888}main{padding-top:20px}footer{position:absolute;bottom:0}button{overflow:hidden}#BrowseBreadrumb{overflow:auto;white-space:nowrap}#BrowseBreadcrumb>li>a{cursor:pointer}.card{min-height:350px}@media only screen and (max-width:576px){.header-logo{display:none!important}}.clickable{cursor:pointer}.tblnum,.tblaction{width:30px}small{color:#aaa}.card-footer-playback{padding:0}.album-cover{background-size:cover;border:1px solid black;border-radius:5px;overflow:hidden;width:240px;height:240px;background-color:#eee;float:left;margin-right:20px;margin-bottom:20px}.album-desc{min-width:240px;float:left}.hide{display:none!important}.pull-right{float:right!important}.card-toolbar{margin-bottom:10px}.card-toolbar>div,.card-toolbar>form{margin-bottom:5px}@font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(/assets/MaterialIcons-Regular.eot);src:local('Material Icons'),local('MaterialIcons-Regular');src:url(/assets/MaterialIcons-Regular.woff2) format('woff2'),url(/assets/MaterialIcons-Regular.woff) format('woff'),url(/assets/MaterialIcons-Regular.ttf) format('truetype')}.material-icons{font-family:'Material Icons';font-weight:normal;font-style:normal;font-size:18px;display:inline-block;line-height:1;text-transform:none;letter-spacing:normal;word-wrap:normal;white-space:nowrap;direction:ltr;vertical-align:top;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;font-feature-settings:'liga'}.material-icons-small{font-size:16px}.material-icons-small-left{font-size:1rem;margin-left:-1em}.color-darkgrey,.color-darkgrey:hover{color:#6c757d!important}#btn-outputs-block>button{margin-bottom:10px}#btn-outputs-block>button:last-child{margin-bottom:0}.card-body{overflow-x:hidden}.progressBarPlay{font-size:22px}#counter{cursor:text}#volumeBar{margin-top:2px;width:160px}.title-icon{float:left;margin-right:5px;font-size:1.8rem}.header-logo{font-size:2rem;float:left;margin-right:5px}.letters>button{width:28px;height:28px}.col-md{max-width:250px;min-width:250px}a.card-img-top{overflow:hidden;display:block}button.active{color:#fff;background-color:#28a745!important;border-color:#28a745!important}button.active-fg-green{color:#28a745!important}button.active-fg-red{color:#bd2130!important}div#alertBox{position:fixed;top:50px;right:10px;width:80%;max-width:400px;z-index:1000;opacity:0;visibility:visible;transition:opacity .5s ease-in}div.alertBoxActive{opacity:1!important;visibility:visible!important;transition:opacity .5s ease-in}.popover-content{padding-top:4px;padding-bottom:4px}.opacity05{opacity:.5}caption{caption-side:top;font-size:120%;font-weight:bold;color:black}.dragover>td{border-top:25px solid transparent}[draggable]{-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;user-select:none;-khtml-user-drag:element;-webkit-user-drag:element}@keyframes changewidth{0%{margin-left:-20px}to{margin-left:100%}}#updateDBprogress{width:20px}.updateDBprogressAnimate{animation-duration:2s;animation-name:changewidth;animation-iteration-count:infinite}.modal-body{overflow-x:hidden}.modal-body .album-cover{float:none}#BrowseDatabaseAlbumListCaption{width:100%;margin-left:15px} \ No newline at end of file diff --git a/dist/htdocs/index.html b/dist/htdocs/index.html index 11db732..806b702 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 f7d5e8a..2a401e4 100644 --- a/dist/htdocs/js/mympd.min.js +++ b/dist/htdocs/js/mympd.min.js @@ -3,28 +3,28 @@ $jscomp.initSymbol=function(){$jscomp.initSymbol=function(){};$jscomp.global.Sym $jscomp.initSymbolIterator=function(){$jscomp.initSymbol();var a=$jscomp.global.Symbol.iterator;a||(a=$jscomp.global.Symbol.iterator=$jscomp.global.Symbol("iterator"));"function"!=typeof Array.prototype[a]&&$jscomp.defineProperty(Array.prototype,a,{configurable:!0,writable:!0,value:function(){return $jscomp.arrayIterator(this)}});$jscomp.initSymbolIterator=function(){}};$jscomp.arrayIterator=function(a){var b=0;return $jscomp.iteratorPrototype(function(){return ba||1342177279>>=1)b+=b;return e}},"es6","es3"); -var socket,lastSong="",lastState,currentSong={},playstate="",settings={},alertTimeout,progressTimer,deferredPrompt,dragEl,app={apps:{Playback:{state:"0/-/",scrollPos:0},Queue:{state:"0/any/",scrollPos:0},Browse:{active:"Database",tabs:{Filesystem:{state:"0/-/",scrollPos:0},Playlists:{active:"All",views:{All:{state:"0/-/",scrollPos:0},Detail:{state:"0/-/",scrollPos:0}}},Database:{active:"Artist",views:{Artist:{state:"0/-/",scrollPos:0},Album:{state:"0/-/",scrollPos:0}}}}},Search:{state:"0/any/",scrollPos:0}}, -current:{app:"Playback",tab:void 0,view:void 0,page:0,filter:"",search:"",scrollPos:0},last:{app:void 0,tab:void 0,view:void 0,filter:"",search:"",scrollPos:0}},domCache={};domCache.navbarBottomBtns=document.getElementById("navbar-bottom").getElementsByTagName("div");domCache.navbarBottomBtnsLen=domCache.navbarBottomBtns.length;domCache.panelHeadingBrowse=document.getElementById("panel-heading-browse").getElementsByTagName("a");domCache.panelHeadingBrowseLen=domCache.panelHeadingBrowse.length; -domCache.counter=document.getElementById("counter");domCache.volumePrct=document.getElementById("volumePrct");domCache.volumeControl=document.getElementById("volumeControl");domCache.volumeIcon=document.getElementById("volumeIcon");domCache.btnsPlay=document.getElementsByClassName("btnPlay");domCache.btnsPlayLen=domCache.btnsPlay.length;domCache.btnPrev=document.getElementById("btnPrev");domCache.btnNext=document.getElementById("btnNext");domCache.progressBar=document.getElementById("progressBar"); -domCache.volumeBar=document.getElementById("volumeBar");domCache.outputs=document.getElementById("outputs");domCache.btnAdd=document.getElementById("nav-add2homescreen");domCache.currentTrack=document.getElementById("currentTrack");domCache.currentArtist=document.getElementById("currentArtist");domCache.currentAlbum=document.getElementById("currentAlbum");domCache.currentCover=document.getElementById("currentCover");domCache.btnVoteUp=document.getElementById("btnVoteUp");domCache.btnVoteDown=document.getElementById("btnVoteDown"); +$jscomp.polyfill=function(a,b,c,d){if(b){c=$jscomp.global;a=a.split(".");for(d=0;da||1342177279>>=1)b+=b;return d}},"es6","es3"); +var socket,lastSong="",lastState,currentSong={},playstate="",settings={},alertTimeout,progressTimer,deferredPrompt,dragEl,app={apps:{Playback:{state:"0/-/",scrollPos:0},Queue:{state:"0/any/",scrollPos:0},Browse:{active:"Database",tabs:{Filesystem:{state:"0/-/",scrollPos:0},Playlists:{active:"All",views:{All:{state:"0/-/",scrollPos:0},Detail:{state:"0/-/",scrollPos:0}}},Database:{active:"AlbumArtist",views:{AlbumArtist:{state:"0/-/",scrollPos:0},Genre:{state:"0/-/",scrollPos:0},Artist:{state:"0/-/", +scrollPos:0},Composer:{state:"0/-/",scrollPos:0},Performer:{state:"0/-/",scrollPos:0},Date:{state:"0/-/",scrollPos:0},Album:{state:"0/-/",scrollPos:0}}}}},Search:{state:"0/any/",scrollPos:0}},current:{app:"Playback",tab:void 0,view:void 0,page:0,filter:"",search:"",scrollPos:0},last:{app:void 0,tab:void 0,view:void 0,filter:"",search:"",scrollPos:0}},domCache={};domCache.navbarBottomBtns=document.getElementById("navbar-bottom").getElementsByTagName("div");domCache.navbarBottomBtnsLen=domCache.navbarBottomBtns.length; +domCache.panelHeadingBrowse=document.getElementById("panel-heading-browse").getElementsByTagName("a");domCache.panelHeadingBrowseLen=domCache.panelHeadingBrowse.length;domCache.counter=document.getElementById("counter");domCache.volumePrct=document.getElementById("volumePrct");domCache.volumeControl=document.getElementById("volumeControl");domCache.volumeIcon=document.getElementById("volumeIcon");domCache.btnsPlay=document.getElementsByClassName("btnPlay");domCache.btnsPlayLen=domCache.btnsPlay.length; +domCache.btnPrev=document.getElementById("btnPrev");domCache.btnNext=document.getElementById("btnNext");domCache.progressBar=document.getElementById("progressBar");domCache.volumeBar=document.getElementById("volumeBar");domCache.outputs=document.getElementById("outputs");domCache.btnAdd=document.getElementById("nav-add2homescreen");domCache.currentTrack=document.getElementById("currentTrack");domCache.currentArtist=document.getElementById("currentArtist");domCache.currentAlbum=document.getElementById("currentAlbum"); +domCache.currentCover=document.getElementById("currentCover");domCache.btnVoteUp=document.getElementById("btnVoteUp");domCache.btnVoteDown=document.getElementById("btnVoteDown"); var modalConnectionError=new Modal(document.getElementById("modalConnectionError")),modalSettings=new Modal(document.getElementById("modalSettings")),modalSavequeue=new Modal(document.getElementById("modalSaveQueue")),modalSongDetails=new Modal(document.getElementById("modalSongDetails")),modalAddToPlaylist=new Modal(document.getElementById("modalAddToPlaylist")),modalRenamePlaylist=new Modal(document.getElementById("modalRenamePlaylist")),modalUpdateDB=new Modal(document.getElementById("modalUpdateDB")); function appPrepare(a){if(app.current.app!=app.last.app||app.current.tab!=app.last.tab||app.current.view!=app.last.view){for(var b=0;broot';c=app.current.search.split("/");var e=c.length,d="";for(a=0;a'+c[a]+"";break}d+=c[a];b+='";d+="/"}a=document.getElementById("BrowseBreadcrumb");a.innerHTML=b;b=a.getElementsByTagName("a");c=b.length;for(a=0;asearchSearching...'),2<=app.current.search.length?sendAPI({cmd:"MPD_API_DATABASE_SEARCH",data:{plist:"",offset:app.current.page, -filter:app.current.filter,searchstr:app.current.search}},parseSearch):(document.getElementById("SearchList").getElementsByTagName("tbody")[0].innerHTML="",document.getElementById("searchAddAllSongs").setAttribute("disabled","disabled"),document.getElementById("searchAddAllSongsBtn").setAttribute("disabled","disabled"),document.getElementById("panel-heading-search").innerText="",document.getElementById("SearchList").classList.remove("opacity05"),setPagination(0)),b=document.getElementById("searchtags").getElementsByTagName("button"), -c=b.length,a=0;a'+c[a]+"";break}e+=c[a];b+='";e+="/"}a=document.getElementById("BrowseBreadcrumb");a.innerHTML=b;b=a.getElementsByTagName("a");c=b.length;for(a=0;asearchSearching...'),2<=app.current.search.length?sendAPI({cmd:"MPD_API_DATABASE_SEARCH",data:{plist:"",offset:app.current.page,filter:app.current.filter,searchstr:app.current.search}},parseSearch):(document.getElementById("SearchList").getElementsByTagName("tbody")[0].innerHTML="",document.getElementById("searchAddAllSongs").setAttribute("disabled", +"disabled"),document.getElementById("searchAddAllSongsBtn").setAttribute("disabled","disabled"),document.getElementById("panel-heading-search").innerText="",document.getElementById("SearchList").classList.remove("opacity05"),setPagination(0)),selectTag("searchtags","searchtagsdesc",app.current.filter)):appGoto("Playback");app.last.app=app.current.app;app.last.tab=app.current.tab;app.last.view=app.current.view}else appGoto("Playback")} function appInit(){getSettings();sendAPI({cmd:"MPD_API_PLAYER_STATE"},parseState);webSocketConnect();domCache.volumeBar.value=0;domCache.volumeBar.addEventListener("click",function(a){a.stopPropagation()},!1);domCache.volumeBar.addEventListener("change",function(a){sendAPI({cmd:"MPD_API_PLAYER_VOLUME",data:{volume:domCache.volumeBar.value}})},!1);domCache.progressBar.value=0;domCache.progressBar.addEventListener("change",function(a){currentSong&&0<=currentSong.currentSongId&&sendAPI({cmd:"MPD_API_PLAYER_SEEK", data:{songid:currentSong.currentSongId,seek:Math.ceil(domCache.progressBar.value/100*currentSong.totalTime)}})},!1);document.getElementById("volumeIcon").parentNode.addEventListener("show.bs.dropdown",function(){sendAPI({cmd:"MPD_API_PLAYER_OUTPUT_LIST"},parseOutputs)});document.getElementById("modalAbout").addEventListener("shown.bs.modal",function(){sendAPI({cmd:"MPD_API_DATABASE_STATS"},parseStats)});document.getElementById("modalUpdateDB").addEventListener("hidden.bs.modal",function(){document.getElementById("updateDBprogress").classList.remove("updateDBprogressAnimate")}); document.getElementById("modalSaveQueue").addEventListener("shown.bs.modal",function(){var a=document.getElementById("saveQueueName");a.focus();a.value="";a.classList.remove("is-invalid");document.getElementById("saveQueueFrm").classList.remove("was-validated")});document.getElementById("modalSettings").addEventListener("shown.bs.modal",function(){getSettings();document.getElementById("settingsFrm").classList.remove("was-validated");document.getElementById("inputCrossfade").classList.remove("is-invalid"); @@ -33,18 +33,19 @@ document.getElementById("inputMixrampdb").classList.remove("is-invalid");documen break;default:window[a.cmd].apply(null,$jscomp.arrayFromIterable(a.options))}},!1);a=document.getElementsByClassName("pages");b=a.length;for(c=0;c";domCache.outputs.innerHTML=b} -function setCounter(a,b,c){currentSong.totalTime=b;currentSong.elapsedTime=c;currentSong.currentSongId=a;var e=Math.floor(b/60),d=b-60*e,f=Math.floor(c/60),g=c-60*f;domCache.progressBar.value=Math.floor(100*c/b);b=f+":"+(10>g?"0":"")+g+" / "+e+":"+(10>d?"0":"")+d;domCache.counter.innerText=b;lastState&&(c=document.getElementById("queueTrackId"+lastState.data.currentSongId))&&(e=c.getElementsByTagName("td"),e[4].innerText=c.getAttribute("data-duration"),e[0].classList.remove("material-icons"),e[0].innerText= -c.getAttribute("data-songpos"),c.classList.remove("font-weight-bold"));if(c=document.getElementById("queueTrackId"+a))e=c.getElementsByTagName("td"),e[4].innerText=b,e[0].classList.add("material-icons"),e[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))} +b.length,d=1==a.data.stickers?"":"none",e=0;e";domCache.outputs.innerHTML=b} +function setCounter(a,b,c){currentSong.totalTime=b;currentSong.elapsedTime=c;currentSong.currentSongId=a;var d=Math.floor(b/60),e=b-60*d,f=Math.floor(c/60),g=c-60*f;domCache.progressBar.value=Math.floor(100*c/b);b=f+":"+(10>g?"0":"")+g+" / "+d+":"+(10>e?"0":"")+e;domCache.counter.innerText=b;lastState&&(c=document.getElementById("queueTrackId"+lastState.data.currentSongId))&&(d=c.getElementsByTagName("td"),d[4].innerText=c.getAttribute("data-duration"),d[0].classList.remove("material-icons"),d[0].innerText= +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)} 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[d].id);g.setAttribute("id","queueTrackId"+a.data[d].id);g.setAttribute("data-songpos",a.data[d].pos+1);g.setAttribute("data-duration", -f);g.setAttribute("data-uri",a.data[d].uri);g.innerHTML=""+(a.data[d].pos+1)+""+a.data[d].title+""+a.data[d].artist+""+a.data[d].album+""+f+'playlist_add';d=b;d--)e[d].remove();"queuesearch"==a.type&&0==b?c.innerHTML='error_outlineNo results, please refine your search!': +c=c.getElementsByTagName("tbody")[0];for(var d=c.getElementsByTagName("tr"),e=0;eg?"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!': "queue"==a.type&&0==b&&(c.innerHTML='error_outlineEmpty queue');setPagination(a.totalEntities);document.getElementById("QueueList").classList.remove("opacity05")}} function parseSearch(a){"Search"===app.current.app&&(document.getElementById("panel-heading-search").innerHTML=a.totalEntities+" Songs found",0playlist_add';break;case "song":f=Math.floor(a.data[d].duration/60);var h=a.data[d].duration-60*f;g.innerHTML='music_note'+a.data[d].title+""+a.data[d].artist+""+a.data[d].album+""+f+":"+(10>h?"0":"")+h+'playlist_add'; -break;case "plist":g.innerHTML='list'+a.data[d].name+'playlist_add'}d=b;d--)e[d].remove();setPagination(a.totalEntities);0==b&&(c.innerHTML='error_outlineNo results');document.getElementById(app.current.app+(void 0==app.current.tab?"": +function parseFilesystem(a){if("Browse"===app.current.app||"Filesystem"===app.current.tab||"Search"===app.current.app){for(var b=a.data.length,c=document.getElementById(app.current.app+(void 0==app.current.tab?"":app.current.tab)+"List").getElementsByTagName("tbody")[0],d=c.getElementsByTagName("tr"),e=0;eplaylist_add';break;case "song":f=Math.floor(a.data[e].duration/60);var h=a.data[e].duration-60*f;g.innerHTML='music_note'+a.data[e].title+""+a.data[e].artist+""+a.data[e].album+""+f+":"+(10>h?"0":"")+h+'playlist_add'; +break;case "plist":g.innerHTML='list'+a.data[e].name+'playlist_add'}e=b;e--)d[e].remove();setPagination(a.totalEntities);0==b&&(c.innerHTML='error_outlineNo results');document.getElementById(app.current.app+(void 0==app.current.tab?"": app.current.tab)+"List").classList.remove("opacity05")}} function parsePlaylists(a){if("Browse"===app.current.app||"Playlists"===app.current.tab){"All"==app.current.view?(document.getElementById("BrowsePlaylistsAllList").classList.remove("hide"),document.getElementById("BrowsePlaylistsDetailList").classList.add("hide"),document.getElementById("btnBrowsePlaylistsAll").parentNode.classList.add("hide"),document.getElementById("btnPlaylistClear").parentNode.classList.add("hide")):(-1"+g.toUTCString()+'playlist_add';d"+g+""+a.data[d].title+""+a.data[d].artist+""+a.data[d].album+""+f+":"+(10>k?"0":"")+k+'playlist_add'; -d=b;d--)e[d].remove();setPagination(a.totalEntities);0==b&&(c.innerHTML="All"==app.current.view?'error_outlineNo playlists found.':'error_outlineEmpty playlist.');document.getElementById(app.current.app+app.current.tab+app.current.view+"List").classList.remove("opacity05")}} -function parseListDBtags(a){if("Browse"===app.current.app||"Database"===app.current.tab||"Artist"===app.current.view)if("AlbumArtist"==a.tagtype){document.getElementById("BrowseDatabaseAlbumList").classList.add("hide");document.getElementById("BrowseDatabaseArtistList").classList.remove("hide");document.getElementById("btnBrowseDatabaseArtist").parentNode.classList.add("hide");for(var b=a.data.length,c=document.getElementById(app.current.app+app.current.tab+app.current.view+"List").getElementsByTagName("tbody")[0], -e=c.getElementsByTagName("tr"),d=0;dalbum'+a.data[d].value+"";d=b;d--)e[d].remove();setPagination(a.totalEntities);0==b&&(c.innerHTML='error_outlineNo entries found.'); -document.getElementById("BrowseDatabaseArtistList").classList.remove("opacity05")}else if("Album"==a.tagtype){document.getElementById("BrowseDatabaseAlbumList").classList.remove("hide");document.getElementById("BrowseDatabaseArtistList").classList.add("hide");document.getElementById("btnBrowseDatabaseArtist").parentNode.classList.remove("hide");b=a.data.length;c=document.getElementById("BrowseDatabaseAlbumList");e=c.getElementsByClassName("col-md");for(d=0;d
'+a.searchstr+'

'+a.data[d].value+'

',d=b;d--)e[d].remove();setPagination(a.totalEntities);document.getElementById("BrowseDatabaseAlbumList").classList.remove("opacity05")}} -function parseListTitles(a){if("Browse"===app.current.app||"Database"===app.current.tab||"Album"===app.current.view){var b=genId(a.album),c=document.getElementById("card"+b);b=c.getElementsByTagName("tbody")[0];var e=c.getElementsByTagName("img")[0];c=e.parentNode;e.setAttribute("src",a.cover);c.setAttribute("data-uri",encodeURI(a.data[0].uri.replace(/\/[^\/]+$/,"")));c.setAttribute("data-name",a.album);c.setAttribute("data-type","dir");e="";for(var d=a.data.length,f=0;f'+a.data[f].track+""+a.data[f].title+'playlist_add';b.innerHTML=e;c.addEventListener("click",function(a){showMenu(this,a)},!1);b.parentNode.addEventListener("click",function(a){"TD"==a.target.nodeName?appendQueue("song",decodeURI(a.target.parentNode.getAttribute("data-uri")),a.target.parentNode.getAttribute("data-name")):"A"==a.target.nodeName&&showMenu(a.target, -a)},!1)}} -function setPagination(a){var b=Math.ceil(a/settings.maxElementsPerPage),c=app.current.app+(void 0==app.current.tab?"":app.current.tab);0==b&&(b=1);for(var e=["PaginationTop","PaginationBottom"],d=0;2>d;d++){document.getElementById(c+e[d]+"Page").innerText=app.current.page/settings.maxElementsPerPage+1+" / "+b;if(1'+(g+ -1)+"";document.getElementById(c+e[d]+"Pages").innerHTML=f}else document.getElementById(c+e[d]+"Page").setAttribute("disabled","disabled");a>app.current.page+settings.maxElementsPerPage?(document.getElementById(c+e[d]+"Next").removeAttribute("disabled"),document.getElementById(c+e[d]).classList.remove("hide"),document.getElementById(c+"ButtonsBottom").classList.remove("hide")):(document.getElementById(c+e[d]+"Next").setAttribute("disabled","disabled"),document.getElementById(c+e[d]).classList.add("hide"), -document.getElementById(c+"ButtonsBottom").classList.add("hide"));0"+g.toUTCString()+'playlist_add';e"+g+""+a.data[e].title+""+a.data[e].artist+""+a.data[e].album+""+f+":"+(10>k?"0":"")+k+'playlist_add'; +e=b;e--)d[e].remove();setPagination(a.totalEntities);0==b&&(c.innerHTML="All"==app.current.view?'error_outlineNo playlists found.':'error_outlineEmpty playlist.');document.getElementById(app.current.app+app.current.tab+app.current.view+"List").classList.remove("opacity05")}} +function parseListDBtags(a){if(""!=app.current.search){document.getElementById("BrowseDatabaseAlbumList").classList.remove("hide");document.getElementById("BrowseDatabaseTagList").classList.add("hide");document.getElementById("btnBrowseDatabaseByTag").parentNode.classList.add("hide");document.getElementById("btnBrowseDatabaseTag").parentNode.classList.remove("hide");document.getElementById("BrowseDatabaseAddAllSongs").parentNode.parentNode.classList.remove("hide");document.getElementById("btnBrowseDatabaseTag").innerHTML= +"« "+app.current.view;document.getElementById("BrowseDatabaseAlbumListCaption").innerText=a.searchtagtype+": "+a.searchstr;var b=a.data.length;1==b&&""==a.data[0].value&&(b=0);for(var c=document.getElementById("BrowseDatabaseAlbumList"),d=c.getElementsByClassName("col-md"),e=0;e

'+a.data[e].value+'

';e=b;e--)d[e].remove();setPagination(a.totalEntities);document.getElementById("BrowseDatabaseAlbumList").classList.remove("opacity05")}else{document.getElementById("BrowseDatabaseAlbumList").classList.add("hide");document.getElementById("BrowseDatabaseTagList").classList.remove("hide");document.getElementById("btnBrowseDatabaseByTag").parentNode.classList.remove("hide");document.getElementById("BrowseDatabaseAddAllSongs").parentNode.parentNode.classList.add("hide");document.getElementById("btnBrowseDatabaseTag").parentNode.classList.add("hide"); +a.data[0]&&""==a.data[0].value&&a.data.shift();b=a.data.length;c=document.getElementById(app.current.app+app.current.tab+"TagList").getElementsByTagName("tbody")[0];d=c.getElementsByTagName("tr");for(e=0;ealbum'+a.data[e].value+"",e=b;e--)d[e].remove(); +setPagination(a.totalEntities);0==b&&(c.innerHTML='error_outlineNo entries found.');document.getElementById("BrowseDatabaseTagList").classList.remove("opacity05")}} +function parseListTitles(a){var b=genId(a.album),c=document.getElementById("card"+b),d=c.getElementsByTagName("tbody")[0],e=c.getElementsByTagName("img")[0];c=e.parentNode;e.setAttribute("src",a.cover);c.setAttribute("data-uri",encodeURI(a.data[0].uri.replace(/\/[^\/]+$/,"")));c.setAttribute("data-name",a.album);c.setAttribute("data-type","dir");document.getElementById("albumartist"+b).innerText=a.albumartist;b="";e=a.data.length;for(var f=0;f'+a.data[f].track+""+a.data[f].title+'playlist_add';d.innerHTML=b;c.addEventListener("click",function(a){showMenu(this,a)},!1);d.parentNode.addEventListener("click",function(a){"TD"==a.target.nodeName?appendQueue("song",decodeURI(a.target.parentNode.getAttribute("data-uri")),a.target.parentNode.getAttribute("data-name")):"A"==a.target.nodeName&&showMenu(a.target,a)},!1)} +function setPagination(a){var b=Math.ceil(a/settings.maxElementsPerPage),c=app.current.app+(void 0==app.current.tab?"":app.current.tab);0==b&&(b=1);for(var d=["PaginationTop","PaginationBottom"],e=0;2>e;e++){document.getElementById(c+d[e]+"Page").innerText=app.current.page/settings.maxElementsPerPage+1+" / "+b;if(1'+ +(g+1)+"";document.getElementById(c+d[e]+"Pages").innerHTML=f}else document.getElementById(c+d[e]+"Page").setAttribute("disabled","disabled");a>app.current.page+settings.maxElementsPerPage?(document.getElementById(c+d[e]+"Next").removeAttribute("disabled"),document.getElementById(c+d[e]).classList.remove("hide"),document.getElementById(c+"ButtonsBottom").classList.remove("hide")):(document.getElementById(c+d[e]+"Next").setAttribute("disabled","disabled"),document.getElementById(c+d[e]).classList.add("hide"), +document.getElementById(c+"ButtonsBottom").classList.add("hide"));0f?"0":"")+f):"lastPlayed"==d?f=0==f?"never":(new Date(1E3*f)).toUTCString():"like"==d?f=0==f?'thumb_down_alt': -2==f?'thumb_up_alt':"not voted":"uri"==d&&(f=''+f+"");b[e].getElementsByTagName("td")[0].innerHTML=f}}}function playlistDetails(a){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 artistClick(){var a=domCache.currentArtist.getAttribute("data-albumartist");""!=a&&appGoto("Browse","Database","AlbumArtist","0/-/"+a)}function albumClick(){var a=domCache.currentAlbum.getAttribute("data-album");""!=a&&appGoto("Browse","Database","Album","0/-/"+a)}function songDetails(a){sendAPI({cmd:"MPD_API_DATABASE_SONGDETAILS",data:{uri:a}},parseSongDetails);modalSongDetails.show()} +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;var c="";for(f in settings.tags)if(1==settings.tags[f]){var d=a.data[f.toLowerCase()];if("duration"==f){var e=Math.floor(d/60);d-=60*e;d=e+":"+(10>d?"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*d)).toUTCString())+"Like"+ +f+""}b.getElementsByTagName("tbody")[0].innerHTML=c}function playlistDetails(a){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){for(var b=a.data.length,c="",e=0;e"+a.data[e].uri+"";document.getElementById("addToPlaylistPlaylist").innerHTML+=c;a.totalEntities>a.returnedEntities&&(a.offset+=settings.maxElementsPerPage,sendAPI({cmd:"MPD_API_PLAYLIST_LIST",data:{offset:a.offset,filter:"-"}},getAllPlaylists))} +function getAllPlaylists(a){for(var b=a.data.length,c="",d=0;d"+a.data[d].uri+"";document.getElementById("addToPlaylistPlaylist").innerHTML+=c;a.totalEntities>a.returnedEntities&&(a.offset+=settings.maxElementsPerPage,sendAPI({cmd:"MPD_API_PLAYLIST_LIST",data:{offset:a.offset,filter:"-"}},getAllPlaylists))} function voteSong(a){var b=domCache.currentTrack.getAttribute("data-uri");""!=b&&(2==a&&domCache.btnVoteUp.classList.contains("active-fg-green")?a=1:0==a&&domCache.btnVoteDown.classList.contains("active-fg-red")&&(a=1),sendAPI({cmd:"MPD_API_LIKE",data:{uri:b,like:a}}),setVoteSongBtns(a,b))} function setVoteSongBtns(a,b){""==b||0==b.indexOf("http://")||0==b.indexOf("https://")?(domCache.btnVoteUp.setAttribute("disabled","disabled"),domCache.btnVoteDown.setAttribute("disabled","disabled")):(domCache.btnVoteUp.removeAttribute("disabled"),domCache.btnVoteDown.removeAttribute("disabled"));0==a?(domCache.btnVoteUp.classList.remove("active-fg-green"),domCache.btnVoteDown.classList.add("active-fg-red")):1==a?(domCache.btnVoteUp.classList.remove("active-fg-green"),domCache.btnVoteDown.classList.remove("active-fg-red")): 2==a&&(domCache.btnVoteUp.classList.add("active-fg-green"),domCache.btnVoteDown.classList.remove("active-fg-red"))} @@ -104,23 +106,23 @@ function showAddToPlaylist(a){document.getElementById("addToPlaylistUri").value= 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();sendAPI({cmd:"MPD_API_PLAYLIST_LIST",data:{offset:0,filter:"-"}},getAllPlaylists)} function addToPlaylist(){var a=document.getElementById("addToPlaylistUri").value;if("stream"==a&&(a=document.getElementById("streamUrl").value,""==a||-1==a.indexOf("http"))){document.getElementById("streamUrl").classList.add("is-invalid");document.getElementById("addStreamFrm").classList.add("was-validated");return}var b=document.getElementById("addToPlaylistPlaylist");b=b.options[b.selectedIndex].text;if("New Playlist"==b){b=document.getElementById("addToPlaylistNewPlaylist").value;var c=b.replace(/\w/g, -"");if(""==b||""!=c){document.getElementById("addToPlaylistNewPlaylist").classList.add("is-invalid");document.getElementById("addToPlaylistFrm").classList.add("was-validated");return}}""!=b?("SEARCH"!=a?sendAPI({cmd:"MPD_API_PLAYLIST_ADD_TRACK",data:{uri:a,plist:b}}):addAllFromSearchPlist(b),modalAddToPlaylist.hide()):(document.getElementById("addToPlaylistPlaylist").classList.add("is-invalid"),document.getElementById("addToPlaylistFrm").classList.add("was-validated"))} +"");if(""==b||""!=c){document.getElementById("addToPlaylistNewPlaylist").classList.add("is-invalid");document.getElementById("addToPlaylistFrm").classList.add("was-validated");return}}""!=b?("SEARCH"==a?addAllFromSearchPlist(b):"DATABASE"==a?addAllFromBrowseDatabasePlist(b):sendAPI({cmd:"MPD_API_PLAYLIST_ADD_TRACK",data:{uri:a,plist:b}}),modalAddToPlaylist.hide()):(document.getElementById("addToPlaylistPlaylist").classList.add("is-invalid"),document.getElementById("addToPlaylistFrm").classList.add("was-validated"))} function addStream(){var a=document.getElementById("streamUrl").value;""!=a&&0==a.indexOf("http")?(sendAPI({cmd:"MPD_API_QUEUE_ADD_TRACK",data:{uri:a}}),modalAddToPlaylist.hide(),showNotification("Added stream "+a+"to queue","","","success")):(document.getElementById("streamUrl").classList.add("is-invalid"),document.getElementById("addStreamFrm").classList.add("was-validated"))} function showRenamePlaylist(a){document.getElementById("renamePlaylistFrm").classList.remove("was-validated");document.getElementById("renamePlaylistTo").classList.remove("is-invalid");modalRenamePlaylist.show();document.getElementById("renamePlaylistFrom").value=a;document.getElementById("renamePlaylistTo").value=""} function renamePlaylist(){var a=document.getElementById("renamePlaylistFrom").value,b=document.getElementById("renamePlaylistTo").value,c=b.replace(/\w/g,"");""!=b&&b!=a&&""==c?(sendAPI({cmd:"MPD_API_PLAYLIST_RENAME",data:{from:a,to:b}}),modalRenamePlaylist.hide(),sendAPI({cmd:"MPD_API_PLAYLIST_LIST",data:{offset:app.current.page,filter:app.current.filter}},parsePlaylists)):(document.getElementById("renamePlaylistTo").classList.add("is-invalid"),document.getElementById("renamePlaylistFrm").classList.add("was-validated"))} function dirname(a){return a.replace(/\/[^\/]*$/,"")} -function showMenu(a,b){b.preventDefault();b.stopPropagation();(b=document.getElementsByClassName("popover")[0])&&b.remove();b=a.getAttribute("data-type");var c=decodeURI(a.getAttribute("data-uri")),e=a.getAttribute("data-name"),d=0;if(null==b||null==c)b=a.parentNode.parentNode.getAttribute("data-type"),c=decodeURI(a.parentNode.parentNode.getAttribute("data-uri")),e=a.parentNode.parentNode.getAttribute("data-name");lastState&&(d=lastState.data.nextsongpos);var f="";"Browse"==app.current.app&&"Filesystem"== -app.current.tab||"Search"==app.current.app||"Browse"==app.current.app&&"Database"==app.current.tab&&"Album"==app.current.view?(f+="Append to queue"+("song"==b?"Add after current playing song":"")+"Replace queue"+("plist"!=b?"Add to playlist":"")+("song"==b?"Songdetails':"")+("plist"==b?"Show playlist":""),"Search"==app.current.app&&(c=dirname(c),f+='keyboard_arrow_rightAlbum actions")):"Browse"==app.current.app&&"Playlists"== -app.current.tab&&"All"==app.current.view?f+="Append to queueReplace queueEdit playlistRename playlistDelete playlist":"Browse"==app.current.app&&"Playlists"==app.current.tab&&"Detail"==app.current.view?f+="Append to queueReplace queue"+("false"== +function showMenu(a,b){b.preventDefault();b.stopPropagation();(b=document.getElementsByClassName("popover")[0])&&b.remove();b=a.getAttribute("data-type");var c=decodeURI(a.getAttribute("data-uri")),d=a.getAttribute("data-name"),e=0;if(null==b||null==c)b=a.parentNode.parentNode.getAttribute("data-type"),c=decodeURI(a.parentNode.parentNode.getAttribute("data-uri")),d=a.parentNode.parentNode.getAttribute("data-name");lastState&&(e=lastState.data.nextsongpos);var f="";"Browse"==app.current.app&&"Filesystem"== +app.current.tab||"Search"==app.current.app||"Browse"==app.current.app&&"Database"==app.current.tab&&"Album"==app.current.view?(f+="Append to queue"+("song"==b?"Add after current playing song":"")+"Replace queue"+("plist"!=b?"Add to playlist":"")+("song"==b?"Songdetails':"")+("plist"==b?"Show playlist":""),"Search"==app.current.app&&(c=dirname(c),f+='keyboard_arrow_rightAlbum actions")):"Browse"==app.current.app&&"Playlists"== +app.current.tab&&"All"==app.current.view?f+="Append to queueReplace queueEdit playlistRename playlistDelete playlist":"Browse"==app.current.app&&"Playlists"==app.current.tab&&"Detail"==app.current.view?f+="Append to queueReplace queue"+("false"== document.getElementById("BrowsePlaylistsDetailList").getAttribute("data-ro")?"Remove":"")+("plist"!=b?"Add to playlist":""):"Queue"==app.current.app&& (f+="RemoveRemove all upwardsRemove all downwards'+(-1==c.indexOf("http")?"Songdetails':""));new Popover(a,{trigger:"click",delay:0,dismissible:!0,template:'"});var g=a.Popover;a.addEventListener("shown.bs.popover",function(a){document.getElementsByClassName("popover-content")[0].addEventListener("click",function(a){a.preventDefault(); a.stopPropagation();if("A"==a.target.nodeName&&(a=a.target.getAttribute("data-href"))){a=JSON.parse(a.replace(/'/g,'"'));if("function"===typeof window[a.cmd])switch(a.cmd){case "sendAPI":sendAPI.apply(null,$jscomp.arrayFromIterable(a.options));break;default:window[a.cmd].apply(null,$jscomp.arrayFromIterable(a.options))}g.hide()}},!1);if(a=document.getElementById("advancedMenuLink"))a.addEventListener("click",function(a){a=this.getElementsByTagName("span")[0];a.innerText="keyboard_arrow_right"==a.innerText? "keyboard_arrow_down":"keyboard_arrow_right"},!1),new Collapse(a)},!1);g.show()} -function sendAPI(a,b){var c=new XMLHttpRequest;c.open("POST","/api",!0);c.setRequestHeader("Content-type","application/json");c.onreadystatechange=function(){if(4==c.readyState)if(""!=c.responseText){var e=JSON.parse(c.responseText);"error"==e.type?(showNotification("Error",e.data,e.data,"danger"),console.log("Error: "+e.data)):"result"==e.type&&"ok"!=e.data?showNotification(e.data,"","","success"):void 0!=b&&"function"==typeof b&&b(e)}else console.log("Empty response for request: "+JSON.stringify(a))}; +function sendAPI(a,b){var c=new XMLHttpRequest;c.open("POST","/api",!0);c.setRequestHeader("Content-type","application/json");c.onreadystatechange=function(){if(4==c.readyState)if(""!=c.responseText){var d=JSON.parse(c.responseText);"error"==d.type?(showNotification("Error",d.data,d.data,"danger"),console.log("Error: "+d.data)):"result"==d.type&&"ok"!=d.data?showNotification(d.data,"","","success"):void 0!=b&&"function"==typeof b&&b(d)}else console.log("Empty response for request: "+JSON.stringify(a))}; c.send(JSON.stringify(a))}function openLocalPlayer(){window.open("/player.html#"+settings.mpdstream,"LocalPlayer")}function updateDB(){sendAPI({cmd:"MPD_API_DATABASE_UPDATE"});updateDBstarted(!0)} function updateDBstarted(a){1==a?(document.getElementById("updateDBfinished").innerText="",document.getElementById("updateDBfooter").classList.add("hide"),updateDBprogress.style.width="20px",updateDBprogress.style.marginLeft="-20px",modalUpdateDB.show(),document.getElementById("updateDBprogress").classList.add("updateDBprogressAnimate")):showNotification("Database update started","","","success")} function updateDBfinished(a){document.getElementById("modalUpdateDB").classList.contains("show")?("update_database"==a?document.getElementById("updateDBfinished").innerText="Database successfully updated.":"update_finished"==a&&(document.getElementById("updateDBfinished").innerText="Database update finished."),a=document.getElementById("updateDBprogress"),a.classList.remove("updateDBprogressAnimate"),a.style.width="100%",a.style.marginLeft="0px",document.getElementById("updateDBfooter").classList.remove("hide")): @@ -129,17 +131,18 @@ function delQueueSong(a,b,c){"range"==a?sendAPI({cmd:"MPD_API_QUEUE_RM_RANGE",da function confirmSettings(){var a=!0,b=document.getElementById("inputCrossfade");if(!b.getAttribute("disabled")){var c=parseInt(b.value);isNaN(c)?(b.classList.add("is-invalid"),a=!1):b.value=c}settings.mixramp&&(b=document.getElementById("inputMixrampdb"),b.getAttribute("disabled")||(c=parseFloat(b.value),isNaN(c)?(b.classList.add("is-invalid"),a=!1):b.value=c),b=document.getElementById("inputMixrampdelay"),b.getAttribute("disabled")||("nan"==b.value&&(b.value="-1"),c=parseFloat(b.value),isNaN(c)? (b.classList.add("is-invalid"),a=!1):b.value=c));1==a?(a=document.getElementById("selectReplaygain"),sendAPI({cmd:"MPD_API_SETTINGS_SET",data:{consume:document.getElementById("btnConsume").classList.contains("active")?1:0,random:document.getElementById("btnRandom").classList.contains("active")?1:0,single:document.getElementById("btnSingle").classList.contains("active")?1:0,repeat:document.getElementById("btnRepeat").classList.contains("active")?1:0,replaygain:a.options[a.selectedIndex].value,crossfade:document.getElementById("inputCrossfade").value, mixrampdb:1==settings.mixramp?document.getElementById("inputMixrampdb").value:settings.mixrampdb,mixrampdelay:1==settings.mixramp?document.getElementById("inputMixrampdelay").value:settings.mixrampdelay,notificationWeb:document.getElementById("btnnotifyWeb").classList.contains("active")?1:0,notificationPage:document.getElementById("btnnotifyPage").classList.contains("active")?1:0}},getSettings),modalSettings.hide()):document.getElementById("settingsFrm").classList.add("was-validated")} -function addAllFromBrowse(){sendAPI({cmd:"MPD_API_QUEUE_ADD_TRACK",data:{uri:app.current.search}});showNotification("Added all songs","","","success")}function addAllFromSearch(){2<=app.current.search.length&&(sendAPI({cmd:"MPD_API_DATABASE_SEARCH",data:{plist:"queue",filter:app.current.filter,searchstr:app.current.search,offset:0}}),showNotification("Added "+parseInt(document.getElementById("panel-heading-search").innerText)+" songs from search","","","success"))} -function addAllFromSearchPlist(a){2<=app.current.search.length&&(sendAPI({cmd:"MPD_API_DATABASE_SEARCH",data:{plist:a,filter:app.current.filter,searchstr:app.current.search,offset:0}}),showNotification("Added "+parseInt(document.getElementById("panel-heading-search").innerText)+" songs from search to "+a,"","","success"))}function scrollTo(a){document.body.scrollTop=a;document.documentElement.scrollTop=a} +function addAllFromBrowseFilesystem(){sendAPI({cmd:"MPD_API_QUEUE_ADD_TRACK",data:{uri:app.current.search}});showNotification("Added all songs","","","success")}function addAllFromSearchPlist(a){2<=app.current.search.length&&(sendAPI({cmd:"MPD_API_DATABASE_SEARCH",data:{plist:a,filter:app.current.filter,searchstr:app.current.search,offset:0}}),showNotification("Added "+parseInt(document.getElementById("panel-heading-search").innerText)+" songs from search to "+a,"","","success"))} +function addAllFromBrowseDatabasePlist(a){2<=app.current.search.length&&(sendAPI({cmd:"MPD_API_DATABASE_SEARCH",data:{plist:a,filter:app.current.view,searchstr:app.current.search,offset:0}}),showNotification("Added songs from database selection to "+a,"","","success"))}function scrollTo(a){document.body.scrollTop=a;document.documentElement.scrollTop=a} function gotoPage(a){switch(a){case "next":app.current.page+=settings.maxElementsPerPage;break;case "prev":app.current.page-=settings.maxElementsPerPage;0>app.current.page&&(app.current.page=0);break;default:app.current.page=a}appGoto(app.current.app,app.current.tab,app.current.view,app.current.page+"/"+app.current.filter+"/"+app.current.search)} function saveQueue(){var a=document.getElementById("saveQueueName").value,b=a.replace(/\w/g,"");""!=a&&""==b?(sendAPI({cmd:"MPD_API_QUEUE_SAVE",data:{plist:a}}),modalSavequeue.hide()):(document.getElementById("saveQueueName").classList.add("is-invalid"),document.getElementById("saveQueueFrm").classList.add("was-validated"))} -function showNotification(a,b,c,e){1==settings.notificationWeb&&(b=new Notification(a,{icon:"assets/favicon.ico",body:b}),setTimeout(function(a){a.close()},3E3,b));1==settings.notificationPage&&(document.getElementById("alertBox")?b=document.getElementById("alertBox"):(b=document.createElement("div"),b.setAttribute("id","alertBox"),b.addEventListener("click",function(){hideNotification()},!1)),b.classList.remove("alert-success","alert-danger"),b.classList.add("alert","alert-"+e),b.innerHTML="
"+ +function showNotification(a,b,c,d){1==settings.notificationWeb&&(b=new Notification(a,{icon:"assets/favicon.ico",body:b}),setTimeout(function(a){a.close()},3E3,b));1==settings.notificationPage&&(document.getElementById("alertBox")?b=document.getElementById("alertBox"):(b=document.createElement("div"),b.setAttribute("id","alertBox"),b.addEventListener("click",function(){hideNotification()},!1)),b.classList.remove("alert-success","alert-danger"),b.classList.add("alert","alert-"+d),b.innerHTML="
"+ a+"
"+c+"
",document.getElementsByTagName("main")[0].append(b),document.getElementById("alertBox").classList.add("alertBoxActive"),alertTimeout&&clearTimeout(alertTimeout),alertTimeout=setTimeout(function(){hideNotification()},3E3))}function hideNotification(){document.getElementById("alertBox")&&(document.getElementById("alertBox").classList.remove("alertBoxActive"),setTimeout(function(){var a=document.getElementById("alertBox");a&&a.remove()},600))} function notificationsSupported(){return"Notification"in window} -function songChange(a){if("error"!=a.type&&"result"!=a.type){var b=a.data.title+a.data.artist+a.data.album+a.data.uri+a.data.currentSongId;if(lastSong!=b){var c="",e="",d="myMPD: ";domCache.currentCover.style.backgroundImage='url("'+a.data.cover+'")';"undefined"!=typeof a.data.artist&&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 chVolume(a){a=parseInt(domCache.volumeBar.value)+a;0>a?a=0:100e?"0":""):"")+e+"\u2009m "+(10>a?"0":"")+a+"\u2009s"} -function genId(a){return"id"+a.replace(/[^\w]/g,"")}appInit(); +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();