1
0
mirror of https://github.com/SuperBFG7/ympd synced 2025-05-07 18:04:05 +00:00

Merge pull request #19 from jcorporation/devel

Merge devel into master
This commit is contained in:
Jürgen Mang 2018-07-05 22:20:13 +02:00 committed by GitHub
commit 876df158c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 1460 additions and 1372 deletions

View File

@ -3,8 +3,8 @@ cmake_minimum_required(VERSION 2.6)
project (mympd C) project (mympd C)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
set(CPACK_PACKAGE_VERSION_MAJOR "3") set(CPACK_PACKAGE_VERSION_MAJOR "3")
set(CPACK_PACKAGE_VERSION_MINOR "0") set(CPACK_PACKAGE_VERSION_MINOR "1")
set(CPACK_PACKAGE_VERSION_PATCH "2") set(CPACK_PACKAGE_VERSION_PATCH "0")
if(CMAKE_BUILD_TYPE MATCHES RELEASE) if(CMAKE_BUILD_TYPE MATCHES RELEASE)
set(ASSETS_PATH "${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME}/htdocs") set(ASSETS_PATH "${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME}/htdocs")
@ -12,6 +12,7 @@ if(CMAKE_BUILD_TYPE MATCHES RELEASE)
else() else()
set(ASSETS_PATH "${PROJECT_SOURCE_DIR}/htdocs") set(ASSETS_PATH "${PROJECT_SOURCE_DIR}/htdocs")
set(DEBUG "ON") set(DEBUG "ON")
set(CS_NDEBUG "ON")
endif() endif()
find_package(LibMPDClient REQUIRED) find_package(LibMPDClient REQUIRED)
@ -22,13 +23,9 @@ include_directories(${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR} ${LIBMPDCLIENT_I
include(CheckCSourceCompiles) include(CheckCSourceCompiles)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -Wextra -pedantic ") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -Wextra -pedantic -D MG_DISABLE_SSL -D MG_ENABLE_IPV6 -D MG_DISABLE_MQTT -D MG_DISABLE_MQTT_BROKER -D MG_DISABLE_DNS_SERVER -D MG_DISABLE_COAP -D MG_DISABLE_HTTP_CGI -D MG_DISABLE_HTTP_SSI -D MG_DISABLE_HTTP_WEBDAV")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -ggdb -D_FORTIFY_SOURCE=2 -fstack-protector -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined -fsanitize=shift -fsanitize=integer-divide-by-zero -fsanitize=unreachable -fsanitize=vla-bound -fsanitize=null -fsanitize=return -fsanitize=signed-integer-overflow -fsanitize=bounds -fsanitize=bounds-strict -fsanitize=alignment -fsanitize=object-size -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fsanitize=nonnull-attribute -fsanitize=returns-nonnull-attribute -fsanitize=bool -fsanitize=enum -fsanitize=vptr -static-libasan") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -ggdb -D_FORTIFY_SOURCE=2 -fstack-protector -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined -fsanitize=shift -fsanitize=integer-divide-by-zero -fsanitize=unreachable -fsanitize=vla-bound -fsanitize=null -fsanitize=return -fsanitize=signed-integer-overflow -fsanitize=bounds -fsanitize=bounds-strict -fsanitize=alignment -fsanitize=object-size -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fsanitize=nonnull-attribute -fsanitize=returns-nonnull-attribute -fsanitize=bool -fsanitize=enum -fsanitize=vptr -static-libasan")
if(WITH_IPV6)
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS)
endif()
set(SOURCES set(SOURCES
src/mympd.c src/mympd.c
src/mpd_client.c src/mpd_client.c
@ -43,15 +40,10 @@ install(TARGETS mympd DESTINATION bin)
install(FILES mympd.1 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1) install(FILES mympd.1 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1)
install(FILES htdocs/index.html DESTINATION share/${PROJECT_NAME}/htdocs/) install(FILES htdocs/index.html DESTINATION share/${PROJECT_NAME}/htdocs/)
install(FILES htdocs/player.html DESTINATION share/${PROJECT_NAME}/htdocs/) install(FILES htdocs/player.html DESTINATION share/${PROJECT_NAME}/htdocs/)
install(FILES htdocs/js/modernizr-custom.min.js DESTINATION share/${PROJECT_NAME}/htdocs/js/)
install(FILES htdocs/js/player.min.js DESTINATION share/${PROJECT_NAME}/htdocs/js/) install(FILES htdocs/js/player.min.js DESTINATION share/${PROJECT_NAME}/htdocs/js/)
install(FILES htdocs/js/bootstrap.bundle.min.js DESTINATION share/${PROJECT_NAME}/htdocs/js/) install(FILES htdocs/js/bootstrap-native-v4.min.js DESTINATION share/${PROJECT_NAME}/htdocs/js/)
install(FILES htdocs/js/bootstrap-notify.min.js DESTINATION share/${PROJECT_NAME}/htdocs/js/)
install(FILES htdocs/js/bootstrap-slider.min.js DESTINATION share/${PROJECT_NAME}/htdocs/js/)
install(FILES htdocs/js/jquery-3.3.1.min.js DESTINATION share/${PROJECT_NAME}/htdocs/js/)
install(FILES htdocs/js/mpd.min.js DESTINATION share/${PROJECT_NAME}/htdocs/js/) install(FILES htdocs/js/mpd.min.js DESTINATION share/${PROJECT_NAME}/htdocs/js/)
install(FILES htdocs/css/bootstrap.min.css DESTINATION share/${PROJECT_NAME}/htdocs/css/) install(FILES htdocs/css/bootstrap.min.css DESTINATION share/${PROJECT_NAME}/htdocs/css/)
install(FILES htdocs/css/bootstrap-slider.min.css DESTINATION share/${PROJECT_NAME}/htdocs/css/)
install(FILES htdocs/css/mpd.min.css DESTINATION share/${PROJECT_NAME}/htdocs/css/) install(FILES htdocs/css/mpd.min.css DESTINATION share/${PROJECT_NAME}/htdocs/css/)
install(DIRECTORY htdocs/assets DESTINATION share/${PROJECT_NAME}/htdocs) install(DIRECTORY htdocs/assets DESTINATION share/${PROJECT_NAME}/htdocs)
install(DIRECTORY DESTINATION /var/lib/${PROJECT_NAME}/) install(DIRECTORY DESTINATION /var/lib/${PROJECT_NAME}/)

View File

@ -12,10 +12,8 @@ This fork provides a reworked ui based on Bootstrap 4 and a modernized backend.
UI Components UI Components
------------- -------------
- Bootstrap 4: https://getbootstrap.com/ - Bootstrap 4: https://getbootstrap.com/
- Bootstrap Notify: http://bootstrap-notify.remabledesigns.com/
- Bootstrap Slider: https://github.com/seiyria/bootstrap-slider
- Material Design Icons: https://material.io/tools/icons/?style=baseline - Material Design Icons: https://material.io/tools/icons/?style=baseline
- jQuery: https://jquery.com/ - Bootstrap Native: http://thednp.github.io/bootstrap.native/
Backend Backend
------- -------

File diff suppressed because one or more lines are too long

View File

@ -17,10 +17,6 @@ body {
background-color:#888; background-color:#888;
} }
#volumeslider {
width: 104px;
}
button { button {
overflow: hidden; overflow: hidden;
} }
@ -36,7 +32,6 @@ button {
#counter { #counter {
font-size: 22px; font-size: 22px;
margin-top: -2px;
margin-left: 10px; margin-left: 10px;
min-width: 50px; min-width: 50px;
} }
@ -127,6 +122,10 @@ tbody {
font-feature-settings: 'liga'; font-feature-settings: 'liga';
} }
.material-icons-small {
font-size: 16px;
}
main { main {
padding-top:20px; padding-top:20px;
} }
@ -150,30 +149,16 @@ main {
overflow-x:hidden; overflow-x:hidden;
} }
.slider-selection { #progressBar {
background:#28a745 !important;
}
#progressbar .slider-track {
height: 20px !important;
}
#progressbar {
width:100%; width:100%;
margin-top:8px;
} }
#volumebar { #volumeBar {
margin-top:2px;
width:160px; width:160px;
} }
.slider-handle {
visibility:hidden !important;
}
[data-notify="title"] {
font-size:120%;
}
.header-logo { .header-logo {
font-size:2rem; font-size:2rem;
float:left; float:left;
@ -184,7 +169,7 @@ main {
#BrowseDatabaseFilterLetters > button, #BrowseDatabaseFilterLetters > button,
#BrowsePlaylistsFilterLetters > button #BrowsePlaylistsFilterLetters > button
{ {
min-width:28px; width:28px;
} }
.col-md { .col-md {
@ -196,7 +181,6 @@ main {
min-height:250px; min-height:250px;
background-repeat:no-repeat; background-repeat:no-repeat;
background-color:#eee; background-color:#eee;
cursor:pointer;
} }
button.active { button.active {
@ -204,3 +188,26 @@ button.active {
background-color: #28a745 !important; background-color: #28a745 !important;
border-color: #28a745 !important; border-color: #28a745 !important;
} }
div#alertBox {
position:fixed;
top: 50px;
right:10px;
width:80%;
max-width:400px;
z-index:1000;
opacity:0;
visibility:visible;
transition:opacity 0.5s ease-in;
}
div.alertBoxActive {
opacity:1 !important;
visibility:visible !important;
transition:opacity 0.5s ease-in;
}
.popover-content {
padding-top:4px;
padding-bottom:4px;
}

View File

@ -1 +1 @@
html{position:relative;min-height:100%}body{margin-bottom:60px}footer{position:absolute;bottom:0}body{padding-top:50px;padding-bottom:50px;background-color:#888}#volumeslider{width:104px}button{overflow:hidden}#BrowseBreadrumb{overflow:auto;white-space:nowrap}#BrowseBreadcrumb>li>a{cursor:pointer}#counter{font-size:22px;margin-top:-2px;margin-left:10px;min-width:50px}#search{width:200px}.card{min-height:350px}@media only screen and (max-width:576px){.header-logo{display:none!important}}tbody{cursor:pointer}.tblnum,.tblaction{width:30px}#album-cover{background-size:cover;border:1px solid black;border-radius:5px;overflow:hidden;margin-bottom:20px;width:240px;height:240px;background-color:#eee}.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'}main{padding-top:20px}.color-darkgrey{color:#6c757d}.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}.slider-selection{background:#28a745!important}#progressbar .slider-track{height:20px!important}#progressbar{width:100%}#volumebar{width:160px}.slider-handle{visibility:hidden!important}[data-notify="title"]{font-size:120%}.header-logo{font-size:2rem;float:left;margin-right:5px}#BrowseFilesystemFilterLetters>button,#BrowseDatabaseFilterLetters>button,#BrowsePlaylistsFilterLetters>button{min-width:28px}.col-md{min-width:260px;max-width:260px}.card-img-top{min-height:250px;background-repeat:no-repeat;background-color:#eee;cursor:pointer}button.active{color:#fff;background-color:#28a745!important;border-color:#28a745!important} html{position:relative;min-height:100%}body{margin-bottom:60px}footer{position:absolute;bottom:0}body{padding-top:50px;padding-bottom:50px;background-color:#888}button{overflow:hidden}#BrowseBreadrumb{overflow:auto;white-space:nowrap}#BrowseBreadcrumb>li>a{cursor:pointer}#counter{font-size:22px;margin-left:10px;min-width:50px}#search{width:200px}.card{min-height:350px}@media only screen and (max-width:576px){.header-logo{display:none!important}}tbody{cursor:pointer}.tblnum,.tblaction{width:30px}#album-cover{background-size:cover;border:1px solid black;border-radius:5px;overflow:hidden;margin-bottom:20px;width:240px;height:240px;background-color:#eee}.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}main{padding-top:20px}.color-darkgrey{color:#6c757d}.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}#progressBar{width:100%;margin-top:8px}#volumeBar{margin-top:2px;width:160px}.header-logo{font-size:2rem;float:left;margin-right:5px}#BrowseFilesystemFilterLetters>button,#BrowseDatabaseFilterLetters>button,#BrowsePlaylistsFilterLetters>button{width:28px}.col-md{min-width:260px;max-width:260px}.card-img-top{min-height:250px;background-repeat:no-repeat;background-color:#eee;cursor:pointer}button.active{color:#fff;background-color:#28a745!important;border-color:#28a745!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}

View File

@ -6,13 +6,9 @@
<meta name="description" content="myMPD - fast and lightweight MPD webclient"> <meta name="description" content="myMPD - fast and lightweight MPD webclient">
<meta name="author" content="mail@jcgames.de"> <meta name="author" content="mail@jcgames.de">
<title>myMPD</title> <title>myMPD</title>
<link href="css/bootstrap.min.css" rel="stylesheet"> <link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/bootstrap-slider.min.css" rel="stylesheet">
<link href="css/mpd.css" rel="stylesheet"> <link href="css/mpd.css" rel="stylesheet">
<link href="assets/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon"> <link href="assets/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon">
<script src="js/modernizr-custom.min.js"></script>
<meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black"/> <meta name="apple-mobile-web-app-status-bar-style" content="black"/>
<link rel="apple-touch-icon" href="assets/appicon.png"/> <link rel="apple-touch-icon" href="assets/appicon.png"/>
@ -26,51 +22,51 @@
</a> </a>
<div class="dropdown-menu bg-dark"> <div class="dropdown-menu bg-dark">
<form id="search" class="px-4 py-3" role="search"> <form id="search" class="px-4 py-3" role="search">
<input type="text" class="form-control" placeholder="Search"> <input id="inputSearch" type="text" class="form-control" placeholder="Search">
</form> </form>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<a id="nav-addstream" class="dropdown-item text-light bg-dark" href="#" data-toggle="modal" data-target="#addstream">Add Stream</a> <a id="nav-addstream" class="dropdown-item text-light bg-dark" href="#" data-toggle="modal" data-target="#modalAddstream">Add Stream</a>
<a id="nav-updatedb" class="dropdown-item text-light bg-dark" href="#" onclick="updateDB(event);">Update Database</a> <a id="nav-updatedb" class="dropdown-item text-light bg-dark" href="#" data-href="{'cmd':'updateDB','options':[]}">Update Database</a>
<a id="nav-localplayer" class="dropdown-item text-light bg-dark" href="#" data-toggle="dropdown" onclick="window.open('/player.html#'+settings.mpdstream,'LocalPlayer');">Local Player</a> <a id="nav-localplayer" class="dropdown-item text-light bg-dark" href="#" data-href="{'cmd':'openLocalPlayer','options':[]}">Local Player</a>
<a id="nav-settings" class="dropdown-item text-light bg-dark" href="#" data-toggle="modal" data-target="#settings">Settings</a> <a id="nav-settings" class="dropdown-item text-light bg-dark" href="#" data-toggle="modal" data-target="#modalSettings">Settings</a>
<a id="nav-about" class="dropdown-item text-light bg-dark" href="#" data-toggle="modal" data-target="#about">About</a> <a id="nav-about" class="dropdown-item text-light bg-dark" href="#" data-toggle="modal" data-target="#modalAbout">About</a>
</div> </div>
</div> </div>
<div class="btn-toolbar col-auto pl-0 pr-0" role="toolbar"> <div class="btn-toolbar col-auto pl-0 pr-0" role="toolbar">
<div class="btn-group mr-2" role="group"> <div class="btn-group mr-2" role="group" id="playControlBtns">
<button id="btnPrev" type="button" class="btn btn-secondary pl-2 pr-2" onclick="clickPrev();;"> <button data-href="{'cmd':'clickPrev','options':[]}" id="btnPrev" type="button" class="btn btn-secondary pl-2 pr-2 material-icons">
<span class="material-icons">skip_previous</span> skip_previous
</button> </button>
<button id="btnStop" type="button" class="btn btn-secondary pl-2 pr-2" onclick="clickStop();"> <button data-href="{'cmd':'clickStop','options':[]}" id="btnStop" type="button" class="btn btn-secondary pl-2 pr-2 material-icons">
<span class="material-icons">stop</span> stop
</button> </button>
<button id="btnPlay" type="button" class="btn btn-secondary pl-2 pr-2" onclick="clickPlay();"> <button data-href="{'cmd':'clickPlay','options':[]}" id="btnPlay" type="button" class="btn btn-secondary pl-2 pr-2 material-icons">
<span class="material-icons">pause</span> pause
</button> </button>
<button id="btnNext" type="button" class="btn btn-secondary pl-2 pr-2" onclick="clickNext();"> <button data-href="{'cmd':'clickNext','options':[]}" id="btnNext" type="button" class="btn btn-secondary pl-2 pr-2 material-icons">
<span class="material-icons">skip_next</span> skip_next
</button> </button>
</div> </div>
<div class="btn-group" role="group"> <div class="btn-group" role="group">
<button class="btn btn-secondary dropdown-toggle pl-2 pr-2" type="button" data-toggle="dropdown"> <button id="volumeIcon" class="btn btn-secondary dropdown-toggle pl-2 pr-2 material-icons" type="button" data-toggle="dropdown">
<span id="volume-icon" class="material-icons">volume_up</span> volume_up
</button> </button>
<div class="dropdown-menu dropdown-menu-right bg-dark"> <div class="dropdown-menu dropdown-menu-right bg-dark">
<h2 class="dropdown-header text-light">Volume: <span id="volumePrct"></span></h2> <h2 class="dropdown-header text-light">Volume: <span id="volumePrct"></span></h2>
<form class="px-4 py-0 pb-3" id="volumeControl"> <form class="px-4 py-0 pb-3" id="volumeControl">
<div class="btn-group" role="group"> <div class="btn-group" role="group">
<input type="button" class="btn btn-secondary" value="&minus;" onclick="chVolume(-5)"/> <button data-href="{'cmd':'chVolume','options':[-5]}" class="btn btn-secondary">&minus;</button>
<div class="btn btn-secondary"> <div class="btn btn-secondary">
<input id="volumebar" data-slider-id="volumebar" data-slider-handle="custom" type="text" data-slider-min="0" data-slider-max="100" data-slider-step="1" data-slider-value="0"/> <input type="range" min="0" max="100" step="1" class="form-control-range" id="volumeBar">
</div> </div>
<input type="button" class="btn btn-secondary" value="+" onclick="chVolume(5)"/> <button data-href="{'cmd':'chVolume','options':[5]}" id="chVolumePlus" class="btn btn-secondary">+</button>
</div> </div>
</form> </form>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<form id="btn-outputs-block" class="px-4 py-3"></form> <form id="outputs" class="px-4 py-3"></form>
</div> </div>
</div> </div>
</div> </div>
</nav> </nav>
</header> </header>
<main class="container"> <main class="container">
@ -86,7 +82,7 @@
<h4 id="album"></h4> <h4 id="album"></h4>
<div class="row"> <div class="row">
<div class="col-8"> <div class="col-8">
<input id="progressbar" data-slider-id='progressbar' data-slider-handle='custom' type="text" data-slider-min="0" data-slider-max="100" data-slider-step="1" data-slider-value="0"/> <input type="range" min="0" max="100" step="1" class="form-control-range" id="progressBar">
</div> </div>
<div class="col-4"> <div class="col-4">
<p id="counter" class="text">&nbsp;&nbsp;</p> <p id="counter" class="text">&nbsp;&nbsp;</p>
@ -95,40 +91,21 @@
</div> </div>
</div> </div>
<div class="card hide" id="cardQueue"> <div class="card hide" id="cardQueue">
<div class="card-header"> <div class="card-header">
<a href="#" data-toggle="collapse" data-target="#queue-buttons" class="text-dark">Queue</a> <a href="#" data-target="#queue-buttons" class="text-dark">Queue</a>
<span id="panel-heading-queue" class="text pull-right"></span> <span id="panel-heading-queue" class="text pull-right"></span>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="btn-toolbar collapse show card-toolbar" id="queue-buttons" role="toolbar"> <div class="btn-toolbar card-toolbar" id="queue-buttons" role="toolbar">
<div id="trashmode" class="btn-group mr-2">
<button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown"><span class="material-icons">delete</span></button>
<div class="dropdown-menu bg-dark px-2" id="trashmodebtns">
<h6 class="dropdown-header text-light">Trashmode</h6>
<button id="btntrashmodeup" type="button" class="btn btn-secondary btn-block">
<span class="material-icons float-left">vertical_align_top</span>
<span class="ml-3">Delete upward</span>
</button>
<button id="btntrashmodesingle" type="button" class="btn btn-secondary active btn-block">
<span class="material-icons float-left">delete</span>
<span class="ml-3">Delete single</span>
</button>
<button id="btntrashmodedown" type="button" class="btn btn-secondary btn-block">
<span class="material-icons float-left">vertical_align_bottom</span>
<span class="ml-3">Delete downward</span>
</button>
</div>
</div>
<div id="queue-actions" class="btn-group mr-2"> <div id="queue-actions" class="btn-group mr-2">
<button type="button" class="btn btn-secondary" onclick="shuffleQueue();" title="Shuffle queue"> <button type="button" class="btn btn-secondary" data-href="{'cmd': 'sendAPI', 'options': [{'cmd':'MPD_API_SEND_SHUFFLE'}]}" title="Shuffle queue">
<span class="material-icons">shuffle</span> <span class="material-icons">shuffle</span>
</button> </button>
<button type="button" class="btn btn-secondary" onclick="clearQueue();" title="Clear queue"> <button type="button" class="btn btn-secondary" data-href="{'cmd': 'sendAPI', 'options': [{'cmd':'MPD_API_RM_ALL'}]}" title="Clear queue">
<span class="material-icons">clear_all</span> <span class="material-icons">clear_all</span>
</button> </button>
<button type="button" class="btn btn-secondary" data-toggle="modal" data-target="#savequeue" title="Save queue"> <button type="button" class="btn btn-secondary" data-toggle="modal" data-target="#modalSavequeue" title="Save queue">
<span class="material-icons">save</span> <span class="material-icons">save</span>
</button> </button>
</div> </div>
@ -151,13 +128,13 @@
</div> </div>
</form> </form>
<div id="QueuePaginationTop" class="btn-group mr-2"> <div id="QueuePaginationTop" class="btn-group mr-2">
<button onclick="gotoPage('prev',this,event)" id="QueuePaginationTopPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="QueuePaginationTopPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button>
<div class="input-group-append"> <div class="input-group-append">
<button id="QueuePaginationTopPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button> <button id="QueuePaginationTopPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="QueuePaginationTopPages"> <div class="dropdown-menu bg-dark px-2 pages" id="QueuePaginationTopPages">
</div> </div>
</div> </div>
<button onclick="gotoPage('next',this,event)" id="QueuePaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="QueuePaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button>
</div> </div>
</div> </div>
@ -183,20 +160,20 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="btn-toolbar" id="queueButtonsBottom" role="toolbar"> <div class="btn-toolbar" id="QueueButtonsBottom" role="toolbar">
<div class="btn-group mr-2"> <div class="btn-group mr-2">
<button type="button" class="btn btn-secondary" onclick="scrollToTop()" title="To top"> <button type="button" class="btn btn-secondary" data-href="{'cmd':'scrollToTop','options':[]}" title="To top">
<span class="material-icons">keyboard_arrow_up</span> <span class="material-icons">keyboard_arrow_up</span>
</button> </button>
</div> </div>
<div id="QueuePaginationBottom" class="btn-group mr-2 dropup"> <div id="QueuePaginationBottom" class="btn-group mr-2 dropup">
<button onclick="gotoPage('prev',this,event)" id="QueuePaginationBottomPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="QueuePaginationBottomPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button>
<div class="input-group-append"> <div class="input-group-append">
<button id="QueuePaginationBottomPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button> <button id="QueuePaginationBottomPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="QueuePaginationBottomPages"> <div class="dropdown-menu bg-dark px-2 pages" id="QueuePaginationBottomPages">
</div> </div>
</div> </div>
<button onclick="gotoPage('next',this,event)" id="QueuePaginationBottomNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="QueuePaginationBottomNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button>
</div> </div>
</div> </div>
</div> </div>
@ -206,32 +183,32 @@
<div class="card-header" id="panel-heading-browse"> <div class="card-header" id="panel-heading-browse">
<ul class="nav nav-tabs card-header-tabs"> <ul class="nav nav-tabs card-header-tabs">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link text-dark" href="#" id="cardBrowseNavDatabase">Database</a> <a data-href="{'cmd': 'appGoto', 'options': ['Browse','Database']}" class="nav-link text-dark" href="#" id="cardBrowseNavDatabase">Database</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link text-dark" href="#" id="cardBrowseNavPlaylists">Playlists</a> <a data-href="{'cmd': 'appGoto', 'options': ['Browse','Playlists']}" class="nav-link text-dark" href="#" id="cardBrowseNavPlaylists">Playlists</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link text-dark" href="#" id="cardBrowseNavFilesystem">Filesystem</a> <a data-href="{'cmd': 'appGoto', 'options': ['Browse','Filesystem']}" class="nav-link text-dark" href="#" id="cardBrowseNavFilesystem">Filesystem</a>
</li> </li>
</ul> </ul>
</div> </div>
<div class="card-body hide" id="cardBrowsePlaylists"> <div class="card-body hide" id="cardBrowsePlaylists">
<div class="btn-toolbar collapse show card-toolbar" id="BrowsePlaylistsButtons" role="toolbar"> <div class="btn-toolbar card-toolbar" id="BrowsePlaylistsButtons" role="toolbar">
<div class="btn-group mr-2"> <div class="btn-group mr-2">
<button id="BrowsePlaylistsFilter" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Filter</button> <button id="BrowsePlaylistsFilter" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Filter</button>
<div class="dropdown-menu bg-dark px-2" id="BrowsePlaylistsFilterLetters"> <div class="dropdown-menu bg-dark px-2" id="BrowsePlaylistsFilterLetters">
</div> </div>
</div> </div>
<div id="BrowsePlaylistsPaginationTop" class="btn-group mr-2"> <div id="BrowsePlaylistsPaginationTop" class="btn-group mr-2">
<button onclick="gotoPage('prev',this,event)" id="BrowsePlaylistsPaginationTopPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="BrowsePlaylistsPaginationTopPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button>
<div class="input-group-append"> <div class="input-group-append">
<button id="BrowsePlaylistsPaginationTopPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button> <button id="BrowsePlaylistsPaginationTopPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="BrowsePlaylistsPaginationTopPages"> <div class="dropdown-menu bg-dark px-2 pages" id="BrowsePlaylistsPaginationTopPages">
</div> </div>
</div> </div>
<button onclick="gotoPage('next',this,event)" id="BrowsePlaylistsPaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="BrowsePlaylistsPaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button>
</div> </div>
</div> </div>
@ -255,27 +232,27 @@
</div> </div>
<div class="btn-toolbar" id="BrowsePlaylistsButtonsBottom" role="toolbar"> <div class="btn-toolbar" id="BrowsePlaylistsButtonsBottom" role="toolbar">
<div class="btn-group mr-2"> <div class="btn-group mr-2">
<button type="button" class="btn btn-secondary" onclick="scrollToTop()" title="To top"> <button type="button" class="btn btn-secondary" data-href="{'cmd': 'scrollToTop', 'options': []}" title="To top">
<span class="material-icons">keyboard_arrow_up</span> <span class="material-icons">keyboard_arrow_up</span>
</button> </button>
</div> </div>
<div id="BrowsePlaylistsPaginationBottom" class="btn-group mr-2 dropup"> <div id="BrowsePlaylistsPaginationBottom" class="btn-group mr-2 dropup">
<button onclick="gotoPage('prev',this,event)" id="BrowsePlaylistsPaginationBottomPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="BrowsePlaylistsPaginationBottomPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button>
<div class="input-group-append"> <div class="input-group-append">
<button id="BrowsePlaylistsPaginationBottomPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button> <button id="BrowsePlaylistsPaginationBottomPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="BrowsePlaylistsPaginationBottomPages"> <div class="dropdown-menu bg-dark px-2 pages" id="BrowsePlaylistsPaginationBottomPages">
</div> </div>
</div> </div>
<button onclick="gotoPage('next',this,event)" id="BrowsePlaylistsPaginationBottomNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="BrowsePlaylistsPaginationBottomNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button>
</div> </div>
</div> </div>
</div> </div>
<div class="card-body hide" id="cardBrowseDatabase"> <div class="card-body hide" id="cardBrowseDatabase">
<div class="btn-toolbar collapse show card-toolbar" id="BrowseDatabaseButtons" role="toolbar"> <div class="btn-toolbar card-toolbar" id="BrowseDatabaseButtons" role="toolbar">
<div class="btn-group mr-2"> <div class="btn-group mr-2">
<button id="btnBrowseDatabaseArtist" type="button" class="btn btn-secondary hide">&laquo; Artists</button> <button data-href="{'cmd': 'appGoto', 'options': ['Browse','Database','Artist']}" id="btnBrowseDatabaseArtist" type="button" class="btn btn-secondary hide">&laquo; Artists</button>
</div> </div>
<div class="btn-group mr-2"> <div class="btn-group mr-2">
<button id="BrowseDatabaseFilter" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Filter</button> <button id="BrowseDatabaseFilter" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Filter</button>
@ -283,13 +260,13 @@
</div> </div>
</div> </div>
<div id="BrowseDatabasePaginationTop" class="btn-group mr-2"> <div id="BrowseDatabasePaginationTop" class="btn-group mr-2">
<button onclick="gotoPage('prev',this,event)" id="BrowseDatabasePaginationTopPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="BrowseDatabasePaginationTopPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button>
<div class="input-group-append"> <div class="input-group-append">
<button id="BrowseDatabasePaginationTopPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button> <button id="BrowseDatabasePaginationTopPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="BrowseDatabasePaginationTopPages"> <div class="dropdown-menu bg-dark px-2 pages" id="BrowseDatabasePaginationTopPages">
</div> </div>
</div> </div>
<button onclick="gotoPage('next',this,event)" id="BrowseDatabasePaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="BrowseDatabasePaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button>
</div> </div>
</div> </div>
@ -314,27 +291,27 @@
<div class="btn-toolbar" id="BrowseDatabaseButtonsBottom" role="toolbar"> <div class="btn-toolbar" id="BrowseDatabaseButtonsBottom" role="toolbar">
<div class="btn-group mr-2"> <div class="btn-group mr-2">
<button type="button" class="btn btn-secondary" onclick="scrollToTop()" title="To top"> <button type="button" class="btn btn-secondary" data-href="{'cmd': 'scrollToTop', 'options': []}" title="To top">
<span class="material-icons">keyboard_arrow_up</span> <span class="material-icons">keyboard_arrow_up</span>
</button> </button>
</div> </div>
<div id="BrowseDatabasePaginationBottom" class="btn-group mr-2 dropup"> <div id="BrowseDatabasePaginationBottom" class="btn-group mr-2 dropup">
<button onclick="gotoPage('prev',this,event)" id="BrowseDatabasePaginationBottomPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="BrowseDatabasePaginationBottomPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button>
<div class="input-group-append"> <div class="input-group-append">
<button id="BrowseDatabasePaginationBottomPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button> <button id="BrowseDatabasePaginationBottomPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="BrowseDatabasePaginationBottomPages"> <div class="dropdown-menu bg-dark px-2 pages" id="BrowseDatabasePaginationBottomPages">
</div> </div>
</div> </div>
<button onclick="gotoPage('next',this,event)" id="BrowseDatabasePaginationBottomNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="BrowseDatabasePaginationBottomNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button>
</div> </div>
</div> </div>
</div> </div>
<div class="card-body hide" id="cardBrowseFilesystem"> <div class="card-body hide" id="cardBrowseFilesystem">
<div class="btn-toolbar collapse show card-toolbar" id="BrowseFilesystemButtons" role="toolbar"> <div class="btn-toolbar card-toolbar" id="BrowseFilesystemButtons" role="toolbar">
<div class="btn-group mr-2 pull-right"> <div class="btn-group mr-2 pull-right">
<button id="BrowseFilesystemAddAllSongs" class="btn btn-secondary">Add all</button> <button data-href="{'cmd': 'addAllFromBrowse', 'options': []}" id="BrowseFilesystemAddAllSongs" class="btn btn-secondary">Add all</button>
</div> </div>
<div class="btn-group mr-2"> <div class="btn-group mr-2">
<button id="BrowseFilesystemFilter" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Filter</button> <button id="BrowseFilesystemFilter" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Filter</button>
@ -342,13 +319,13 @@
</div> </div>
</div> </div>
<div id="BrowseFilesystemPaginationTop" class="btn-group mr-2"> <div id="BrowseFilesystemPaginationTop" class="btn-group mr-2">
<button onclick="gotoPage('prev',this,event)" id="BrowseFilesystemPaginationTopPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="BrowseFilesystemPaginationTopPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button>
<div class="input-group-append"> <div class="input-group-append">
<button id="BrowseFilesystemPaginationTopPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button> <button id="BrowseFilesystemPaginationTopPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="BrowseFilesystemPaginationTopPages"> <div class="dropdown-menu bg-dark px-2 pages" id="BrowseFilesystemPaginationTopPages">
</div> </div>
</div> </div>
<button onclick="gotoPage('next',this,event)" id="BrowseFilesystemPaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="BrowseFilesystemPaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button>
</div> </div>
</div> </div>
@ -379,18 +356,18 @@
</div> </div>
<div class="btn-toolbar" id="BrowseFilesystemButtonsBottom" role="toolbar"> <div class="btn-toolbar" id="BrowseFilesystemButtonsBottom" role="toolbar">
<div class="btn-group mr-2"> <div class="btn-group mr-2">
<button type="button" class="btn btn-secondary" onclick="scrollToTop()" title="To top"> <button type="button" class="btn btn-secondary" data-href="{'cmd': 'scrollToTop', 'options': []}" title="To top">
<span class="material-icons">keyboard_arrow_up</span> <span class="material-icons">keyboard_arrow_up</span>
</button> </button>
</div> </div>
<div id="BrowseFilesystemPaginationBottom" class="btn-group mr-2 dropup"> <div id="BrowseFilesystemPaginationBottom" class="btn-group mr-2 dropup">
<button onclick="gotoPage('prev',this,event)" id="BrowseFilesystemPaginationBottomPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="BrowseFilesystemPaginationBottomPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button>
<div class="input-group-append"> <div class="input-group-append">
<button id="BrowseFilesystemPaginationBottomPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button> <button id="BrowseFilesystemPaginationBottomPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="BrowseFilesystemPaginationBottomPages"> <div class="dropdown-menu bg-dark px-2 pages" id="BrowseFilesystemPaginationBottomPages">
</div> </div>
</div> </div>
<button onclick="gotoPage('next',this,event)" id="BrowseFilesystemPaginationBottomNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="BrowseFilesystemPaginationBottomNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button>
</div> </div>
</div> </div>
</div> </div>
@ -401,7 +378,7 @@
<span id="panel-heading-search" class="text pull-right"></span> <span id="panel-heading-search" class="text pull-right"></span>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="btn-toolbar collapse show card-toolbar" id="SearchButtons" role="toolbar"> <div class="btn-toolbar card-toolbar" id="SearchButtons" role="toolbar">
<form id="search2" role="search"> <form id="search2" role="search">
<div class="input-group mr-2"> <div class="input-group mr-2">
<input type="text" class="form-control" placeholder="Search" id="searchstr2"/> <input type="text" class="form-control" placeholder="Search" id="searchstr2"/>
@ -421,16 +398,16 @@
</div> </div>
</form> </form>
<div class="btn-group mr-2 pull-right"> <div class="btn-group mr-2 pull-right">
<button id="searchAddAllSongs" class="btn btn-secondary" onclick="addAllFromSearch();">Add all</button> <button id="searchAddAllSongs" class="btn btn-secondary" data-href="{'cmd': 'addAllFromSearch', 'options': []}">Add all</button>
</div> </div>
<div id="AearchPaginationTop" class="btn-group mr-2"> <div id="AearchPaginationTop" class="btn-group mr-2">
<button onclick="gotoPage('prev',this,event)" id="SearchPaginationTopPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="SearchPaginationTopPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button>
<div class="input-group-append"> <div class="input-group-append">
<button id="SearchPaginationTopPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button> <button id="SearchPaginationTopPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="SearchPaginationTopPages"> <div class="dropdown-menu bg-dark px-2 pages" id="SearchPaginationTopPages">
</div> </div>
</div> </div>
<button onclick="gotoPage('next',this,event)" id="SearchPaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="SearchPaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button>
</div> </div>
</div> </div>
<div class="table-responsive-md"> <div class="table-responsive-md">
@ -457,18 +434,18 @@
</div> </div>
<div class="btn-toolbar" id="SearchButtonsBottom" role="toolbar"> <div class="btn-toolbar" id="SearchButtonsBottom" role="toolbar">
<div class="btn-group mr-2"> <div class="btn-group mr-2">
<button type="button" class="btn btn-secondary" onclick="scrollToTop()" title="To top"> <button type="button" class="btn btn-secondary" data-href="{'cmd': 'scrollToTop', 'options': []}" title="To top">
<span class="material-icons">keyboard_arrow_up</span> <span class="material-icons">keyboard_arrow_up</span>
</button> </button>
</div> </div>
<div id="SearchPaginationBottom" class="btn-group mr-2 dropup"> <div id="SearchPaginationBottom" class="btn-group mr-2 dropup">
<button onclick="gotoPage('prev',this,event)" id="SearchPaginationBottomPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="SearchPaginationBottomPrev" title="Previous Page" type="button" class="btn btn-secondary">&laquo;</button>
<div class="input-group-append"> <div class="input-group-append">
<button id="SearchPaginationBottomPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button> <button id="SearchPaginationBottomPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="SearchPaginationBottomPages"> <div class="dropdown-menu bg-dark px-2 pages" id="SearchPaginationBottomPages">
</div> </div>
</div> </div>
<button onclick="gotoPage('next',this,event)" id="SearchPaginationBottomNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button> <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="SearchPaginationBottomNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">&raquo;</button>
</div> </div>
</div> </div>
</div> </div>
@ -478,13 +455,14 @@
<footer class="footer"> <footer class="footer">
<nav class="navbar navbar-expand navbar-dark fixed-bottom bg-dark"> <nav class="navbar navbar-expand navbar-dark fixed-bottom bg-dark">
<div class="d-flex flex-fill navbar-nav" id="navbar-bottom"> <div class="d-flex flex-fill navbar-nav" id="navbar-bottom">
<div class="nav-item flex-fill text-center" id="navPlayback"><a class="nav-link" href="#">Playback</a></div> <div id="navPlayback" class="nav-item flex-fill text-center"><a data-href="{'cmd': 'appGoto', 'options': ['Playback']}" class="nav-link" href="#">Playback</a></div>
<div class="nav-item flex-fill text-center" id="navQueue"><a class="nav-link" href="#">Queue</a></div> <div id="navQueue" class="nav-item flex-fill text-center"><a data-href="{'cmd': 'appGoto', 'options': ['Queue']}" class="nav-link" href="#">Queue</a></div>
<div class="nav-item flex-fill text-center" id="navBrowse"><a class="nav-link" href="#">Browse</a></div> <div class="nav-item flex-fill text-center" id="navBrowse"><a data-href="{'cmd': 'appGoto', 'options': ['Browse']}" class="nav-link" href="#">Browse</a></div>
<div class="nav-item flex-fill text-center" id="navSearch"><a class="nav-link" href="#">Search</a></div> <div class="nav-item flex-fill text-center" id="navSearch"><a data-href="{'cmd': 'appGoto', 'options': ['Search']}" class="nav-link" href="#">Search</a></div>
</div> </div>
</nav> </nav>
</footer> </footer>
<!-- Modal --> <!-- Modal -->
<div class="modal" id="modalConnectionError" role="dialog"> <div class="modal" id="modalConnectionError" role="dialog">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
@ -500,7 +478,7 @@
</div> </div>
<!-- Modal --> <!-- Modal -->
<div class="modal fade" id="settings" tabindex="-1" role="dialog" aria-labelledby="settingsLabel" aria-hidden="true"> <div class="modal fade" id="modalSettings" tabindex="-1" role="dialog" aria-labelledby="settingsLabel" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
@ -512,25 +490,25 @@
<div class="modal-body"> <div class="modal-body">
<form class="needs-validation" id="settingsFrm" novalidate> <form class="needs-validation" id="settingsFrm" novalidate>
<div class="row"> <div class="row">
<div class="form-group col-md-6" data-toggle="buttons"> <div class="form-group col-md-6">
<button id="btnrandom" type="button" class="btn btn-secondary btn-block" title="Random"> <button data-href="{'cmd':'toggleBtn','options':['btnRandom']}" id="btnRandom" type="button" class="btn btn-secondary btn-block" title="Random">
Random Random
</button> </button>
</div> </div>
<div class="form-group col-md-6" data-toggle="buttons"> <div class="form-group col-md-6" data-toggle="buttons">
<button id="btnconsume" type="button" class="btn btn-secondary btn-block" title="Consume"> <button data-href="{'cmd':'toggleBtn','options':['btnConsume']}" id="btnConsume" type="button" class="btn btn-secondary btn-block" title="Consume">
Consume Consume
</button> </button>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="form-group col-md-6" data-toggle="buttons"> <div class="form-group col-md-6" data-toggle="buttons">
<button id="btnsingle" type="button" class="btn btn-secondary btn-block" title="Single"> <button data-href="{'cmd':'toggleBtn','options':['btnSingle']}" id="btnSingle" type="button" class="btn btn-secondary btn-block" title="Single">
Single Single
</button> </button>
</div> </div>
<div class="form-group col-md-6" data-toggle="buttons"> <div class="form-group col-md-6" data-toggle="buttons">
<button id="btnrepeat" type="button" class="btn btn-secondary btn-block" title="Repeat"> <button data-href="{'cmd':'toggleBtn','options':['btnRepeat']}" id="btnRepeat" type="button" class="btn btn-secondary btn-block" title="Repeat">
Repeat Repeat
</button> </button>
</div> </div>
@ -573,12 +551,12 @@
<hr/> <hr/>
<div class="row"> <div class="row">
<div class="form-group col-md-6" data-toggle="buttons"> <div class="form-group col-md-6" data-toggle="buttons">
<button type="button" class="btn btn-secondary btn-block" id="btnnotifyPage"> <button data-href="{'cmd':'toggleBtn','options':['btnnotifyPage']}" type="button" class="btn btn-secondary btn-block" id="btnnotifyPage">
Page Notifications Page Notifications
</button> </button>
</div> </div>
<div class="form-group col-md-6" data-toggle="buttons"> <div class="form-group col-md-6" data-toggle="buttons">
<button type="button" class="btn btn-secondary btn-block" id="btnnotifyWeb"> <button data-href="{'cmd':'toggleBtn','options':['btnnotifyWeb']}" type="button" class="btn btn-secondary btn-block" id="btnnotifyWeb">
Web Notifications Web Notifications
</button> </button>
</div> </div>
@ -587,14 +565,14 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-success" onclick="confirmSettings();">Save</button> <button type="button" class="btn btn-success" data-href="{'cmd': 'confirmSettings', 'options': []}">Save</button>
</div> </div>
</div><!-- /.modal-content --> </div><!-- /.modal-content -->
</div><!-- /.modal-dialog --> </div><!-- /.modal-dialog -->
</div><!-- /.modal --> </div><!-- /.modal -->
<!-- Modal --> <!-- Modal -->
<div class="modal fade" id="about" tabindex="-1" role="dialog" aria-labelledby="settingsLabel" aria-hidden="true"> <div class="modal fade" id="modalAbout" tabindex="-1" role="dialog" aria-labelledby="settingsLabel" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
@ -637,7 +615,7 @@
</div><!-- /.modal --> </div><!-- /.modal -->
<!-- Modal --> <!-- Modal -->
<div class="modal fade" id="addstream" tabindex="-1" role="dialog" aria-labelledby="addstreamLabel" aria-hidden="true"> <div class="modal fade" id="modalAddstream" tabindex="-1" role="dialog" aria-labelledby="addstreamLabel" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
@ -647,7 +625,7 @@
</button> </button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form> <form id="addstreamFrm">
<div class="row"> <div class="row">
<div class="form-group col-md-12"> <div class="form-group col-md-12">
<label class="control-label" for="streamurl">Stream URL</label> <label class="control-label" for="streamurl">Stream URL</label>
@ -658,13 +636,13 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-success" onclick="addStream();">Add Stream</button> <button type="button" class="btn btn-success" data-href="{'cmd': 'addStream', 'options': []}">Add Stream</button>
</div> </div>
</div><!-- /.modal-content --> </div><!-- /.modal-content -->
</div><!-- /.modal-dialog --> </div><!-- /.modal-dialog -->
</div><!-- /.modal --> </div><!-- /.modal -->
<div class="modal fade" id="savequeue" tabindex="-1" role="dialog" aria-labelledby="savequeueLabel" aria-hidden="true"> <div class="modal fade" id="modalSavequeue" tabindex="-1" role="dialog" aria-labelledby="savequeueLabel" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
@ -685,15 +663,12 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-success" onclick="saveQueue();">Save Queue</button> <button type="button" class="btn btn-success" data-href="{'cmd': 'saveQueue', 'options': []}">Save Queue</button>
</div> </div>
</div><!-- /.modal-content --> </div><!-- /.modal-content -->
</div><!-- /.modal-dialog --> </div><!-- /.modal-dialog -->
</div><!-- /.modal --> </div><!-- /.modal -->
<script src="js/jquery-3.3.1.min.js"></script> <script src="js/bootstrap-native-v4.min.js"></script>
<script src="js/bootstrap.bundle.min.js"></script>
<script src="js/bootstrap-slider.min.js"></script>
<script src="js/bootstrap-notify.min.js"></script>
<script src="js/mpd.js"></script> <script src="js/mpd.js"></script>
</body> </body>
</html> </html>

2
htdocs/js/bootstrap-native-v4.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

165
htdocs/js/mpd.min.js vendored
View File

@ -1,86 +1,87 @@
var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){a!=Array.prototype&&a!=Object.prototype&&(a[b]=c.value)};$jscomp.getGlobal=function(a){return"undefined"!=typeof window&&window===a?a:"undefined"!=typeof global&&null!=global?global:a};$jscomp.global=$jscomp.getGlobal(this);$jscomp.SYMBOL_PREFIX="jscomp_symbol_"; var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){a!=Array.prototype&&a!=Object.prototype&&(a[b]=c.value)};$jscomp.getGlobal=function(a){return"undefined"!=typeof window&&window===a?a:"undefined"!=typeof global&&null!=global?global:a};$jscomp.global=$jscomp.getGlobal(this);$jscomp.SYMBOL_PREFIX="jscomp_symbol_";
$jscomp.initSymbol=function(){$jscomp.initSymbol=function(){};$jscomp.global.Symbol||($jscomp.global.Symbol=$jscomp.Symbol)};$jscomp.Symbol=function(){var a=0;return function(b){return $jscomp.SYMBOL_PREFIX+(b||"")+a++}}(); $jscomp.initSymbol=function(){$jscomp.initSymbol=function(){};$jscomp.global.Symbol||($jscomp.global.Symbol=$jscomp.Symbol)};$jscomp.Symbol=function(){var a=0;return function(b){return $jscomp.SYMBOL_PREFIX+(b||"")+a++}}();
$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 b<a.length?{done:!1,value:a[b++]}:{done:!0}})}; $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 b<a.length?{done:!1,value:a[b++]}:{done:!0}})};
$jscomp.iteratorPrototype=function(a){$jscomp.initSymbolIterator();a={next:a};a[$jscomp.global.Symbol.iterator]=function(){return this};return a};$jscomp.iteratorFromArray=function(a,b){$jscomp.initSymbolIterator();a instanceof String&&(a+="");var c=0,d={next:function(){if(c<a.length){var e=c++;return{value:b(e,a[e]),done:!1}}d.next=function(){return{done:!0,value:void 0}};return d.next()}};d[Symbol.iterator]=function(){return d};return d}; $jscomp.iteratorPrototype=function(a){$jscomp.initSymbolIterator();a={next:a};a[$jscomp.global.Symbol.iterator]=function(){return this};return a};$jscomp.makeIterator=function(a){$jscomp.initSymbolIterator();var b=a[Symbol.iterator];return b?b.call(a):$jscomp.arrayIterator(a)};$jscomp.arrayFromIterator=function(a){for(var b,c=[];!(b=a.next()).done;)c.push(b.value);return c};$jscomp.arrayFromIterable=function(a){return a instanceof Array?a:$jscomp.arrayFromIterator($jscomp.makeIterator(a))};
$jscomp.polyfill=function(a,b,c,d){if(b){c=$jscomp.global;a=a.split(".");for(d=0;d<a.length-1;d++){var e=a[d];e in c||(c[e]={});c=c[e]}a=a[a.length-1];d=c[a];b=b(d);b!=d&&null!=b&&$jscomp.defineProperty(c,a,{configurable:!0,writable:!0,value:b})}};$jscomp.polyfill("Array.prototype.keys",function(a){return a?a:function(){return $jscomp.iteratorFromArray(this,function(a){return a})}},"es6","es3"); $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.findInternal=function(a,b,c){a instanceof String&&(a=String(a));for(var d=a.length,e=0;e<d;e++){var f=a[e];if(b.call(c,f,e,a))return{i:e,v:f}}return{i:-1,v:void 0}};$jscomp.polyfill("Array.prototype.find",function(a){return a?a:function(a,c){return $jscomp.findInternal(this,a,c).v}},"es6","es3"); $jscomp.polyfill=function(a,b,c,e){if(b){c=$jscomp.global;a=a.split(".");for(e=0;e<a.length-1;e++){var d=a[e];d in c||(c[d]={});c=c[d]}a=a[a.length-1];e=c[a];b=b(e);b!=e&&null!=b&&$jscomp.defineProperty(c,a,{configurable:!0,writable:!0,value:b})}};
var socket,last_song="",last_state,last_outputs,current_song={},isTouch=Modernizr.touch?1:0,playstate="",progressBar,volumeBar,settings={},app={apps:{Playback:{state:"0/-/"},Queue:{state:"0/Any Tag/"},Browse:{active:"Database",tabs:{Filesystem:{state:"0/-/"},Playlists:{state:"0/-/"},Database:{active:"Artist",views:{Artist:{state:"0/-/"},Album:{state:"0/-/"}}}}},Search:{state:"0/Any Tag/"}},current:{app:"Playback",tab:void 0,view:void 0,page:0,filter:"",search:""},last:{app:void 0,tab:void 0,view:void 0}, $jscomp.polyfill("String.prototype.repeat",function(a){return a?a:function(a){var b=$jscomp.checkStringArgs(this,null,"repeat");if(0>a||1342177279<a)throw new RangeError("Invalid count value");a|=0;for(var e="";a;)if(a&1&&(e+=b),a>>>=1)b+=b;return e}},"es6","es3");
prepare:function(){if(app.current.app!=app.last.app||app.current.tab!=app.last.tab||app.current.view!=app.last.view)$("#navbar-bottom > div").removeClass("active"),$("#cardPlayback").addClass("hide"),$("#cardQueue").addClass("hide"),$("#cardBrowse").addClass("hide"),$("#cardSearch").addClass("hide"),$("#panel-heading-browse > ul > li > a").removeClass("active"),$("#cardBrowsePlaylists").addClass("hide"),$("#cardBrowseDatabase").addClass("hide"),$("#cardBrowseFilesystem").addClass("hide"),$("#card"+ var socket,last_song="",last_state,current_song={},playstate="",settings={},timeOut,app={apps:{Playback:{state:"0/-/"},Queue:{state:"0/Any Tag/"},Browse:{active:"Database",tabs:{Filesystem:{state:"0/-/"},Playlists:{state:"0/-/"},Database:{active:"Artist",views:{Artist:{state:"0/-/"},Album:{state:"0/-/"}}}}},Search:{state:"0/Any Tag/"}},current:{app:"Playback",tab:void 0,view:void 0,page:0,filter:"",search:""},last:{app:void 0,tab:void 0,view:void 0}},domCache={};domCache.navbarBottomBtns=document.getElementById("navbar-bottom").getElementsByTagName("div");
app.current.app).removeClass("hide"),$("#nav"+app.current.app).addClass("active"),void 0!=app.current.tab&&($("#card"+app.current.app+app.current.tab).removeClass("hide"),$("#card"+app.current.app+"Nav"+app.current.tab).addClass("active"))},goto:function(a,b,c,d){app.apps[a].tabs?(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==d?app.apps[a].tabs[b].views[c].state:d)):a="/"+a+"/"+b+"!"+(void 0==d?app.apps[a].tabs[b].state: 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.btnPlay=document.getElementById("btnPlay");
d)):a="/"+a+"!"+(void 0==d?app.apps[a].state:d);location.hash=a},route:function(){if(params=decodeURI(location.hash).match(/^#\/(\w+)\/?(\w+)?\/?(\w+)?!((\d+)\/([^\/]+)\/(.*))$/)){app.current.app=params[1];app.current.tab=params[2];app.current.view=params[3];app.apps[app.current.app].state?app.apps[app.current.app].state=params[4]:app.apps[app.current.app].tabs[app.current.tab].state?(app.apps[app.current.app].tabs[app.current.tab].state=params[4],app.apps[app.current.app].active=app.current.tab): 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");
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=params[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.page=parseInt(params[5]);app.current.filter=params[6];app.current.search=params[7];app.prepare();if("Playback"==app.current.app)sendAPI({cmd:"MPD_API_GET_CURRENT_SONG"},songChange);else if("Queue"==app.current.app)app.last.app!= var modalConnectionError=new Modal(document.getElementById("modalConnectionError")),modalSettings=new Modal(document.getElementById("modalSettings")),modalAddstream=new Modal(document.getElementById("modalAddstream")),modalSavequeue=new Modal(document.getElementById("modalSavequeue")),mainMenu=new Dropdown(document.getElementById("mainMenu"));
app.current.app&&(2>app.current.search.length&&setPagination(app.current.page),$("#searchqueuetag > button").each(function(){$(this).removeClass("active");$(this).text()==app.current.filter&&($(this).addClass("active"),$("#searchqueuetagdesc").text($(this).text()))})),getQueue();else if("Browse"==app.current.app&&"Playlists"==app.current.tab)sendAPI({cmd:"MPD_API_GET_PLAYLISTS",data:{offset:app.current.page,filter:app.current.filter}},parsePlaylists);else if("Browse"==app.current.app&&"Database"== function appPrepare(){if(app.current.app!=app.last.app||app.current.tab!=app.last.tab||app.current.view!=app.last.view){for(var a=0;a<domCache.navbarBottomBtnsLen;a++)domCache.navbarBottomBtns[a].classList.remove("active");document.getElementById("cardPlayback").classList.add("hide");document.getElementById("cardQueue").classList.add("hide");document.getElementById("cardBrowse").classList.add("hide");document.getElementById("cardSearch").classList.add("hide");for(a=0;a<domCache.panelHeadingBrowseLen;a++)domCache.panelHeadingBrowse[a].classList.remove("active");
app.current.tab&&"Artist"==app.current.view)sendAPI({cmd:"MPD_API_GET_ARTISTS",data:{offset:app.current.page,filter:app.current.filter}},parseListDBtags);else if("Browse"==app.current.app&&"Database"==app.current.tab&&"Album"==app.current.view)sendAPI({cmd:"MPD_API_GET_ARTISTALBUMS",data:{offset:app.current.page,filter:app.current.filter,albumartist:app.current.search}},parseListDBtags);else if("Browse"==app.current.app&&"Filesystem"==app.current.tab){$("#BrowseBreadcrumb").empty().append('<li class="breadcrumb-item"><a uri="">root</a></li>'); document.getElementById("cardBrowsePlaylists").classList.add("hide");document.getElementById("cardBrowseDatabase").classList.add("hide");document.getElementById("cardBrowseFilesystem").classList.add("hide");document.getElementById("card"+app.current.app).classList.remove("hide");document.getElementById("nav"+app.current.app).classList.add("active");void 0!=app.current.tab&&(document.getElementById("card"+app.current.app+app.current.tab).classList.remove("hide"),document.getElementById("card"+app.current.app+
sendAPI({cmd:"MPD_API_GET_FILESYSTEM",data:{offset:app.current.page,path:app.current.search?app.current.search:"/",filter:app.current.filter}},parseFilesystem);var a=$("#browseFilesystemAddAllSongs");app.current.search?(a.off(),a.on("click",function(){sendAPI({cmd:"MPD_API_ADD_TRACK",data:{uri:app.current.search}})}),a.removeAttr("disabled").removeClass("disabled")):a.attr("disabled","disabled").addClass("disabled");var b=app.current.search.split("/"),c="";$.each(b,function(a,e){b.length-1==a?$("#BrowseBreadcrumb").append('<li class="breadcrumb-item active">'+ "Nav"+app.current.tab).classList.add("active"))}}function appGoto(a,b,c,e){app.apps[a].tabs?(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}
e+"</li>"):(c+=e,$("#BrowseBreadcrumb").append('<li class="breadcrumb-item"><a uri="'+c+'">'+e+"</a></li>"),c+="/")})}else"Search"==app.current.app?(app.last.app!=app.current.app&&(""!=app.current.search?$("#SearchList > tbody").append('<tr><td><span class="material-icons">search</span></td><td colspan="3">Searching</td><td></td><td></td></tr>'):setPagination(app.current.page),$("#searchstr2").val(app.current.search)),$("#searchtags2 > button").each(function(){$(this).removeClass("active");$(this).text()== function appRoute(){if(params=decodeURI(location.hash).match(/^#\/(\w+)\/?(\w+)?\/?(\w+)?!((\d+)\/([^\/]+)\/(.*))$/)){app.current.app=params[1];app.current.tab=params[2];app.current.view=params[3];app.apps[app.current.app].state?app.apps[app.current.app].state=params[4]:app.apps[app.current.app].tabs[app.current.tab].state?(app.apps[app.current.app].tabs[app.current.tab].state=params[4],app.apps[app.current.app].active=app.current.tab):app.apps[app.current.app].tabs[app.current.tab].views[app.current.view].state&&
app.current.filter&&($(this).addClass("active"),$("#searchtags2desc").text($(this).text()))}),2<=app.current.search.length?sendAPI({cmd:"MPD_API_SEARCH",data:{mpdtag:app.current.filter,offset:app.current.page,searchstr:app.current.search}},parseSearch):($("#SearchList > tbody").empty(),$("#searchAddAllSongs").attr("disabled","disabled").addClass("disabled"))):app.goto("Playback");app.last.app=app.current.app;app.last.tab=app.current.tab;app.last.view=app.current.view}else app.goto("Playback")}}; (app.apps[app.current.app].tabs[app.current.tab].views[app.current.view].state=params[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.page=parseInt(params[5]);app.current.filter=params[6];app.current.search=params[7];appPrepare();if("Playback"==app.current.app)sendAPI({cmd:"MPD_API_GET_CURRENT_SONG"},songChange);else if("Queue"==app.current.app){app.last.app!=app.current.app&&2>app.current.search.length&&setPagination(app.current.page);
$(document).ready(function(){getSettings();sendAPI({cmd:"MPD_API_GET_OUTPUTNAMES"},parseOutputnames);webSocketConnect();volumeBar=$("#volumebar").slider();volumeBar.slider("setValue",0);volumeBar.slider("on","slideStop",function(a){sendAPI({cmd:"MPD_API_SET_VOLUME",data:{volume:a}})});progressBar=$("#progressbar").slider();progressBar.slider("setValue",0);progressBar.slider("on","slideStop",function(a){current_song&&0<=current_song.currentSongId&&sendAPI({cmd:"MPD_API_SET_SEEK",data:{songid:current_song.currentSongId, for(var a=document.getElementById("searchqueuetag").getElementsByTagName("button"),b=0;b<a.length;b++)a[b].classList.remove("active"),a[b].innerText==app.current.filter&&(a[b].classList.add("active"),document.getElementById("searchqueuetagdesc").innerText=a[b].innerText);getQueue()}else if("Browse"==app.current.app&&"Playlists"==app.current.tab)sendAPI({cmd:"MPD_API_GET_PLAYLISTS",data:{offset:app.current.page,filter:app.current.filter}},parsePlaylists),doSetFilterLetter("BrowsePlaylistsFilter");
seek:Math.ceil(a/100*current_song.totalTime)}})});$("#about").on("shown.bs.modal",function(){sendAPI({cmd:"MPD_API_GET_STATS"},parseStats)});$("#settings").on("shown.bs.modal",function(){sendAPI({cmd:"MPD_API_GET_SETTINGS"},parseSettings);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")}); else if("Browse"==app.current.app&&"Database"==app.current.tab&&"Artist"==app.current.view)sendAPI({cmd:"MPD_API_GET_ARTISTS",data:{offset:app.current.page,filter:app.current.filter}},parseListDBtags),doSetFilterLetter("BrowseDatabaseFilter");else if("Browse"==app.current.app&&"Database"==app.current.tab&&"Album"==app.current.view)sendAPI({cmd:"MPD_API_GET_ARTISTALBUMS",data:{offset:app.current.page,filter:app.current.filter,albumartist:app.current.search}},parseListDBtags),doSetFilterLetter("BrowseDatabaseFilter");
$("#addstream").on("shown.bs.modal",function(){$("#streamurl").focus()});$("#addstream form").on("submit",function(a){addStream()});$("#mainMenu").on("shown.bs.dropdown",function(){$("#search > input").val("");$("#search > input").focus()});add_filter("#BrowseFilesystemFilterLetters");add_filter("#BrowseDatabaseFilterLetters");add_filter("#BrowsePlaylistsFilterLetters");window.addEventListener("hashchange",app.route,!1)}); else if("Browse"==app.current.app&&"Filesystem"==app.current.tab){sendAPI({cmd:"MPD_API_GET_FILESYSTEM",data:{offset:app.current.page,path:app.current.search?app.current.search:"/",filter:app.current.filter}},parseFilesystem);app.current.search?document.getElementById("BrowseFilesystemAddAllSongs").removeAttribute("disabled"):document.getElementById("BrowseFilesystemAddAllSongs").setAttribute("disabled","disabled");a='<li class="breadcrumb-item"><a data-uri="">root</a></li>';var c=app.current.search.split("/"),
function webSocketConnect(){socket="undefined"!=typeof MozWebSocket?new MozWebSocket(get_appropriate_ws_url()):new WebSocket(get_appropriate_ws_url());try{socket.onopen=function(){console.log("connected");showNotification("Connected to myMPD","","","success");$("#modalConnectionError").modal("hide");app.route()},socket.onmessage=function(a){if(a.data!==last_state&&0!=a.data.length){try{var b=JSON.parse(a.data)}catch(c){console.log("Invalid JSON data received: "+a.data)}switch(b.type){case "state":parseState(b); e=c.length,d="";for(b=0;b<e;b++){if(e-1==b){a+='<li class="breadcrumb-item active">'+c[b]+"</li>";break}d+=c[b];a+='<li class="breadcrumb-item"><a data-uri="'+d+'">'+c[b]+"</a></li>";d+="/"}b=document.getElementById("BrowseBreadcrumb");b.innerHTML=a;a=b.getElementsByTagName("a");c=a.length;for(b=0;b<c;b++)a[b].addEventListener("click",function(){appGoto("Browse","Filesystem",void 0,"0/"+app.current.filter+"/"+this.getAttribute("data-uri"))},!1);doSetFilterLetter("BrowseFilesystemFilter")}else if("Search"==
break;case "disconnected":showNotification("myMPD lost connection to MPD","","","danger");break;case "update_queue":"Queue"===app.current.app&&getQueue();break;case "song_change":songChange(b);break;case "error":showNotification(b.data,"","","danger")}}},socket.onclose=function(){console.log("disconnected");$("#modalConnectionError").modal("show");setTimeout(function(){console.log("reconnect");webSocketConnect()},3E3)}}catch(a){alert("<p>Error"+a)}} app.current.app)for(app.last.app!=app.current.app&&(""!=app.current.search?document.getElementById("SearchList").getElementsByTagName("tbody")[0].innerHTML='<tr><td><span class="material-icons">search</span></td><td colspan="5">Searching...</td></tr>':setPagination(app.current.page),document.getElementById("searchstr2").value=app.current.search),2<=app.current.search.length?sendAPI({cmd:"MPD_API_SEARCH",data:{mpdtag:app.current.filter,offset:app.current.page,searchstr:app.current.search}},parseSearch):
(document.getElementById("SearchList").getElementsByTagName("tbody")[0].innerHTML="",document.getElementById("searchAddAllSongs").setAttribute("disabled","disabled"),document.getElementById("panel-heading-search").innerText="",setPagination(app.current.page)),a=document.getElementById("searchtags2").getElementsByTagName("button"),c=a.length,b=0;b<c;b++)a[b].classList.remove("active"),a[b].innerText==app.current.filter&&(a[b].classList.add("active"),document.getElementById("searchtags2desc").innerText=
a[b].innerText);else 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_GET_OUTPUTNAMES"},parseOutputnames);webSocketConnect();domCache.volumeBar.value=0;domCache.volumeBar.addEventListener("change",function(a){sendAPI({cmd:"MPD_API_SET_VOLUME",data:{volume:domCache.volumeBar.value}})},!1);domCache.progressBar.value=0;domCache.progressBar.addEventListener("change",function(a){current_song&&0<=current_song.currentSongId&&sendAPI({cmd:"MPD_API_SET_SEEK",data:{songid:current_song.currentSongId,seek:Math.ceil(domCache.progressBar.value/
100*current_song.totalTime)}})},!1);document.getElementById("modalAbout").addEventListener("shown.bs.modal",function(){sendAPI({cmd:"MPD_API_GET_STATS"},parseStats)});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("modalAddstream").addEventListener("shown.bs.modal",function(){document.getElementById("streamurl").focus()});document.getElementById("addstreamFrm").addEventListener("submit",function(){addStream()});document.getElementById("mainMenu").addEventListener("shown.bs.dropdown",function(){var a=document.getElementById("inputSearch");a.value="";a.focus()});document.getElementById("inputSearch").addEventListener("click",function(a){a.stopPropagation()});addFilterLetter("BrowseFilesystemFilterLetters");
addFilterLetter("BrowseDatabaseFilterLetters");addFilterLetter("BrowsePlaylistsFilterLetters");for(var a=document.querySelectorAll("button[data-href], a[data-href]"),b=a.length,c=0;c<b;c++)a[c].addEventListener("click",function(a){a.preventDefault();a.stopPropagation();a=JSON.parse(this.getAttribute("data-href").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))}},
!1);a=document.querySelectorAll(".pages");b=a.length;for(c=0;c<b;c++)a[c].addEventListener("click",function(a){"BUTTON"==a.target.nodeName&&gotoPage(a.target.getAttribute("data-page"))},!1);document.getElementById("outputs").addEventListener("click",function(a){"BUTTON"==a.target.nodeName&&a.stopPropagation();sendAPI({cmd:"MPD_API_TOGGLE_OUTPUT",data:{output:a.target.getAttribute("data-output-id"),state:a.target.classList.contains("active")?0:1}})},!1);document.getElementById("QueueList").addEventListener("click",
function(a){"TD"==a.target.nodeName?sendAPI({cmd:"MPD_API_PLAY_TRACK",data:{track:a.target.parentNode.getAttribute("data-trackid")}}):"A"==a.target.nodeName&&(a.preventDefault(),showMenu(a.target))},!1);document.getElementById("BrowseFilesystemList").addEventListener("click",function(a){if("TD"==a.target.nodeName)switch(a.target.parentNode.getAttribute("data-type")){case "dir":appGoto("Browse","Filesystem",void 0,"0/"+app.current.filter+"/"+decodeURI(a.target.parentNode.getAttribute("data-uri")));
break;case "song":appendQueue("song",decodeURI(this.getAttribute("data-uri")),a.target.parentNode.getAttribute("data-name"));break;case "plist":appendQueue("plist",decodeURI(this.getAttribute("data-uri")),a.target.parentNode.getAttribute("data-name"))}else"A"==a.target.nodeName&&(a.preventDefault(),showMenu(a.target))},!1);document.getElementById("BrowsePlaylistsList").addEventListener("click",function(a){"TD"==a.target.nodeName?appendQueue("plist",decodeURI(a.target.parentNode.getAttribute("data-uri")),
a.target.parentNode.getAttribute("data-name")):"A"==a.target.nodeName&&(a.preventDefault(),showMenu(a.target))},!1);document.getElementById("BrowseDatabaseArtistList").addEventListener("click",function(a){"TD"==a.target.nodeName&&appGoto("Browse","Database","Album","0/-/"+a.target.parentNode.getAttribute("data-uri"))},!1);document.getElementById("SearchList").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);document.getElementById("searchtags2").addEventListener("click",function(a){"BUTTON"==a.target.nodeName&&appGoto(app.current.app,app.current.tab,app.current.view,"0/"+a.target.innerText+"/"+app.current.search)},!1);document.getElementById("searchqueuestr").addEventListener("keyup",function(a){appGoto(app.current.app,app.current.tab,app.current.view,"0/"+app.current.filter+"/"+this.value)},!1);document.getElementById("searchqueuetag").addEventListener("click",
function(a){"BUTTON"==a.target.nodeName&&appGoto(app.current.app,app.current.tab,app.current.view,app.current.page+"/"+a.target.innerText+"/"+app.current.search)},!1);document.getElementById("inputSearch").addEventListener("keypress",function(a){13==a.which&&mainMenu.toggle()},!1);document.getElementById("search").addEventListener("submit",function(){var a=document.getElementById("inputSearch").value;appGoto("Search",void 0,void 0,app.current.page+"/Any Tag/"+a);document.getElementById("searchstr2").value=
a;return!1},!1);document.getElementById("search2").addEventListener("submit",function(){return!1},!1);document.getElementById("searchqueue").addEventListener("submit",function(){return!1},!1);document.getElementById("searchstr2").addEventListener("keyup",function(a){appGoto("Search",void 0,void 0,"0/"+app.current.filter+"/"+this.value)},!1);window.addEventListener("hashchange",appRoute,!1);document.addEventListener("keydown",function(a){if("INPUT"!=a.target.tagName){switch(a.which){case 37:clickPrev();
break;case 39:clickNext();break;case 32:clickPlay();break;default:return}a.preventDefault()}},!1)}
function webSocketConnect(){socket=new WebSocket(get_appropriate_ws_url());try{socket.onopen=function(){console.log("connected");showNotification("Connected to myMPD","","","success");modalConnectionError.hide();appRoute()},socket.onmessage=function(a){if(a.data!==last_state&&0!=a.data.length){try{var b=JSON.parse(a.data)}catch(c){console.log("Invalid JSON data received: "+a.data)}switch(b.type){case "state":parseState(b);break;case "disconnected":showNotification("myMPD lost connection to MPD","",
"","danger");break;case "update_queue":"Queue"===app.current.app&&getQueue();break;case "song_change":songChange(b);break;case "error":showNotification(b.data,"","","danger")}}},socket.onclose=function(){console.log("disconnected");modalConnectionError.show();setTimeout(function(){console.log("reconnect");webSocketConnect()},3E3)}}catch(a){alert("Error: "+a)}}
function get_appropriate_ws_url(){var a=document.URL;if("https"==a.substring(0,5)){var b="wss://";a=a.substr(8)}else b="ws://","http"==a.substring(0,4)&&(a=a.substr(7));a=a.split("#");var c=/\/$/.test(a[0])?"":"/";return b+a[0]+c+"ws"} function get_appropriate_ws_url(){var a=document.URL;if("https"==a.substring(0,5)){var b="wss://";a=a.substr(8)}else b="ws://","http"==a.substring(0,4)&&(a=a.substr(7));a=a.split("#");var c=/\/$/.test(a[0])?"":"/";return b+a[0]+c+"ws"}
function parseStats(a){$("#mpdstats_artists").text(a.data.artists);$("#mpdstats_albums").text(a.data.albums);$("#mpdstats_songs").text(a.data.songs);$("#mpdstats_dbplaytime").text(beautifyDuration(a.data.dbplaytime));$("#mpdstats_playtime").text(beautifyDuration(a.data.playtime));$("#mpdstats_uptime").text(beautifyDuration(a.data.uptime));var b=new Date(1E3*a.data.dbupdated);$("#mpdstats_dbupdated").text(b.toUTCString());$("#mympdVersion").text(a.data.mympd_version);$("#mpdVersion").text(a.data.mpd_version)} function parseStats(a){document.getElementById("mpdstats_artists").innerText=a.data.artists;document.getElementById("mpdstats_albums").innerText=a.data.albums;document.getElementById("mpdstats_songs").innerText=a.data.songs;document.getElementById("mpdstats_dbplaytime").innerText=beautifyDuration(a.data.dbplaytime);document.getElementById("mpdstats_playtime").innerText=beautifyDuration(a.data.playtime);document.getElementById("mpdstats_uptime").innerText=beautifyDuration(a.data.uptime);var b=new Date(1E3*
function parseSettings(a){a.data.random?$("#btnrandom").addClass("active").attr("aria-pressed","true"):$("#btnrandom").removeClass("active").attr("aria-pressed","false");a.data.consume?$("#btnconsume").addClass("active").attr("aria-pressed","true"):$("#btnconsume").removeClass("active").attr("aria-pressed","false");a.data.single?$("#btnsingle").addClass("active").attr("aria-pressed","true"):$("#btnsingle").removeClass("active").attr("aria-pressed","false");a.data.repeat?$("#btnrepeat").addClass("active").attr("aria-pressed", a.data.dbupdated);document.getElementById("mpdstats_dbupdated").innerText=b.toUTCString();document.getElementById("mympdVersion").innerText=a.data.mympd_version;document.getElementById("mpdVersion").innerText=a.data.mpd_version}function toggleBtn(a,b){a=document.getElementById(a);void 0==b&&(b=a.classList.contains("active")?0:1);1==b?(a.classList.add("active"),a.setAttribute("aria-pressed","true")):(a.classList.remove("active"),a.setAttribute("aria-pressed","false"))}
"true"):$("#btnrepeat").removeClass("active").attr("aria-pressed","false");void 0!=a.data.crossfade?$("#inputCrossfade").removeAttr("disabled").val(a.data.crossfade):$("#inputCrossfade").attr("disabled","disabled");void 0!=a.data.mixrampdb?$("#inputMixrampdb").removeAttr("disabled").val(a.data.mixrampdb):$("#inputMixrampdb").attr("disabled","disabled");void 0!=a.data.mixrampdelay?$("#inputMixrampdelay").removeAttr("disabled").val(a.data.mixrampdelay):$("#inputMixrampdb").attr("disabled","disabled"); function parseSettings(a){toggleBtn("btnRandom",a.data.random);toggleBtn("btnConsume",a.data.consume);toggleBtn("btnSingle",a.data.single);toggleBtn("btnRepeat",a.data.repeat);void 0!=a.data.crossfade?(document.getElementById("inputCrossfade").removeAttribute("disabled"),document.getElementById("inputCrossfade").value=a.data.crossfade):document.getElementById("inputCrossfade").setAttribute("disabled","disabled");void 0!=a.data.mixrampdb?(document.getElementById("inputMixrampdb").removeAttribute("disabled"),
$("#selectReplaygain").val(a.data.replaygain);notificationsSupported()?a.data.notificationWeb?($("#btnnotifyWeb").addClass("active").attr("aria-pressed","true"),Notification.requestPermission(function(b){"permission"in Notification||(Notification.permission=b);"granted"===b?$("#btnnotifyWeb").addClass("active").attr("aria-pressed","true"):($("#btnnotifyWeb").removeClass("active").attr("aria-pressed","false"),a.data.notificationWeb=0)})):$("#btnnotifyWeb").removeClass("active").attr("aria-pressed", document.getElementById("inputMixrampdb").value=a.data.mixrampdb):document.getElementById("inputMixrampdb").setAttribute("disabled","disabled");void 0!=a.data.mixrampdelay?(document.getElementById("inputMixrampdelay").removeAttribute("disabled"),document.getElementById("inputMixrampdelay").value=a.data.mixrampdelay):document.getElementById("inputMixrampdelay").setAttribute("disabled","disabled");document.getElementById("selectReplaygain").value=a.data.replaygain;var b=document.getElementById("btnnotifyWeb");
"false"):($("#btnnotifyWeb").addClass("disabled"),$("#btnnotifyWeb").removeClass("active").attr("aria-pressed","false"));a.data.notificationPage?$("#btnnotifyPage").addClass("active").attr("aria-pressed","true"):$("#btnnotifyPage").removeClass("active").attr("aria-pressed","false");settings=a.data;setLocalStream(a.data.mpdhost,a.data.streamport)}function getSettings(){sendAPI({cmd:"MPD_API_GET_SETTINGS"},parseSettings)} notificationsSupported()?a.data.notificationWeb?(toggleBtn("btnnotifyWeb",a.data.notificationWeb),Notification.requestPermission(function(b){"permission"in Notification||(Notification.permission=b);"granted"===b?toggleBtn("btnnotifyWeb",1):(toggleBtn("btnnotifyWeb",0),a.data.notificationWeb=0)})):toggleBtn("btnnotifyWeb",0):(b.setAttribute("disabled","disabled"),toggleBtn("btnnotifyWeb",0));toggleBtn("btnnotifyPage",a.data.notificationPage);settings=a.data;settings.mpdstream="http://";settings.mpdstream=
function parseOutputnames(a){$("#btn-outputs-block button").remove();Object.keys(a.data).length?$.each(a.data,function(a,c){$('<button id="btnoutput'+a+'" class="btn btn-secondary btn-block" onclick="toggleoutput(this, '+a+')"><span class="material-icons float-left">volume_up</span> '+c+"</button>").appendTo($("#btn-outputs-block"))}):$("#btn-outputs-block").addClass("hide");last_outputs=""} "127.0.0.1"==settings.mpdhost||"localhost"==settings.mpdhost?settings.mpdstream+window.location.hostname:settings.mpdstream+settings.mpdhost;settings.mpdstream+=":"+settings.streamport+"/"}function getSettings(){sendAPI({cmd:"MPD_API_GET_SETTINGS"},parseSettings)}
function parseState(a){updatePlayIcon(a);updateVolumeIcon(a.data.volume);if(JSON.stringify(a)!==JSON.stringify(last_state)){current_song.totalTime=a.data.totalTime;current_song.currentSongId=a.data.currentsongid;var b=Math.floor(a.data.totalTime/60),c=a.data.totalTime-60*b,d=Math.floor(a.data.elapsedTime/60),e=a.data.elapsedTime-60*d;volumeBar.slider("setValue",a.data.volume);progressBar.slider("setValue",Math.floor(100*a.data.elapsedTime/a.data.totalTime));b=d+":"+(10>e?"0":"")+e+" / "+b+":"+(10> function parseOutputnames(a){for(var b="",c=a.data.outputs.length,e=0;e<c;e++)b+='<button id="btnoutput'+a.data.outputs[e].id+'" data-output-id="'+a.data.outputs[e].id+'" class="btn btn-secondary btn-block"><span class="material-icons float-left">volume_up</span> '+a.data.outputs[e].name+"</button>";domCache.outputs.innerHTML=b}
c?"0":"")+c;$("#counter").text(b);last_state&&($("#QueueList > tbody > tr[trackid="+last_state.data.currentsongid+"] > td").eq(4).text(last_state.data.totalTime),$("#QueueList > tbody > tr[trackid="+last_state.data.currentsongid+"] > td").eq(0).removeClass("material-icons").text(last_state.data.songpos));$("#QueueList > tbody > tr").removeClass("active").removeClass("font-weight-bold");$("#QueueList > tbody > tr[trackid="+a.data.currentsongid+"] > td").eq(4).text(b);$("#QueueList > tbody > tr[trackid="+ function parseState(a){if(JSON.stringify(a)!==JSON.stringify(last_state)){1==a.data.state?(domCache.btnPlay.innerText="play_arrow",playstate="stop"):2==a.data.state?(domCache.btnPlay.innerText="pause",playstate="play"):(domCache.btnPlay.innerText="play_arrow",playstate="pause");-1==a.data.nextsongpos?domCache.btnNext.setAttribute("disabled","disabled"):domCache.btnNext.removeAttribute("disabled");0>=a.data.songpos?domCache.btnPrev.setAttribute("disabled","disabled"):domCache.btnPrev.removeAttribute("disabled");
a.data.currentsongid+"] > td").eq(0).addClass("material-icons").text("play_arrow");$("#QueueList > tbody > tr[trackid="+a.data.currentsongid+"]").addClass("active").addClass("font-weight-bold");void 0!=last_state&&a.data.queue_version==last_state.data.queue_version||sendAPI({cmd:"MPD_API_GET_CURRENT_SONG"},songChange);last_state=a;$.each(a.data.outputs,function(a,b){b?$("#btnoutput"+a).addClass("active"):$("#btnoutput"+a).removeClass("active")});last_outputs=a.data.outputs}} 0==a.data.queue_length?domCache.btnPlay.setAttribute("disabled","disabled"):domCache.btnPlay.removeAttribute("disabled");-1==a.data.volume?(domCache.volumePrct.innerText("Volumecontrol disabled"),domCache.volumeControl.classList.add("hide")):(domCache.volumeControl.classList.remove("hide"),domCache.volumePrct.innerText=a.data.volume+" %",domCache.volumeIcon.innerText=0==a.data.volume?"volume_off":50>a.data.volume?"volume_down":"volume_up");domCache.volumeBar.value=a.data.volume;current_song.totalTime=
function getQueue(){2<=app.current.search.length?sendAPI({cmd:"MPD_API_SEARCH_QUEUE",data:{mpdtag:app.current.filter,offset:app.current.page,searchstr:app.current.search}},parseQueue):sendAPI({cmd:"MPD_API_GET_QUEUE",data:{offset:app.current.page}},parseQueue)} a.data.totalTime;current_song.currentSongId=a.data.currentsongid;var b=Math.floor(a.data.totalTime/60),c=a.data.totalTime-60*b,e=Math.floor(a.data.elapsedTime/60),d=a.data.elapsedTime-60*e;domCache.progressBar.value=Math.floor(100*a.data.elapsedTime/a.data.totalTime);b=e+":"+(10>d?"0":"")+d+" / "+b+":"+(10>c?"0":"")+c;domCache.counter.innerText=b;last_state&&(c=document.getElementById("queueTrackId"+last_state.data.currentsongid))&&(e=c.getElementsByTagName("td"),e[4].innerText=c.getAttribute("data-duration"),
function parseQueue(a){if("Queue"===app.current.app){$("#panel-heading-queue").empty();0<a.totalEntities&&$("#panel-heading-queue").text(a.totalEntities+" Songs");0<a.totalTime&&$("#panel-heading-queue").append(" \u2013 "+beautifyDuration(a.totalTime));var b=0,c=document.getElementById(app.current.app+"List").getElementsByTagName("tbody")[0].getElementsByTagName("tr"),d;for(d in a.data){b++;var e=Math.floor(a.data[d].duration/60),f=a.data[d].duration-60*e;e='<tr trackid="'+a.data[d].id+'"><td>'+(a.data[d].pos+ 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.data.currentsongid))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");void 0!=last_state&&a.data.queue_version==last_state.data.queue_version||sendAPI({cmd:"MPD_API_GET_CURRENT_SONG"},songChange);b=a.data.outputs.length;for(c=0;c<
1)+"</td><td>"+a.data[d].title+"</td><td>"+a.data[d].artist+"</td><td>"+a.data[d].album+"</td><td>"+e+":"+(10>f?"0":"")+f+"</td><td></td></tr>";b<=c.length?$(c[b-1]).attr("trackid")!=a.data[d].id&&$(c[b-1]).replaceWith(e):$("#"+app.current.app+"List > tbody").append(e)}for(d=c.length;d>b;d--)$(c[c.length-1]).remove();"queuesearch"==a.type&&0==b&&$("#QueueList > tbody").append('<tr><td><span class="material-icons">error_outline</span></td><td colspan="3">No results, please refine your search!</td><td></td><td></td></tr>'); b;c++)toggleBtn("btnoutput"+a.data.outputs[c].id,a.data.outputs[c].state);last_state=a}}function getQueue(){2<=app.current.search.length?sendAPI({cmd:"MPD_API_SEARCH_QUEUE",data:{mpdtag:app.current.filter,offset:app.current.page,searchstr:app.current.search}},parseQueue):sendAPI({cmd:"MPD_API_GET_QUEUE",data:{offset:app.current.page}},parseQueue)}
setPagination(a.totalEntities);if(isTouch)$("#QueueList > tbody > tr > td:last-child").append('<a class="pull-right btn-group-hover color-darkgrey" href="#/Queue!'+app.current.page+"/"+app.current.filter+"/"+app.current.search+'" onclick="delQueueSong($(this).parents(\'tr\'),event);"><span class="material-icons">delete</span></a>');else $("#QueueList > tbody > tr").on({mouseover:function(){var a=$(this);$("#btntrashmodeup").hasClass("active")&&(a=$("#QueueList > tbody > tr:lt("+($(this).index()+1)+ function parseQueue(a){if("Queue"===app.current.app){0<a.totalTime?document.getElementById("panel-heading-queue").innerText=a.totalEntities+" Songs \u2013 "+beautifyDuration(a.totalTime):0<a.totalEntities?document.getElementById("panel-heading-queue").innerText=a.totalEntities+" Songs":document.getElementById("panel-heading-queue").innerText="";for(var b=a.data.length,c=document.getElementById(app.current.app+"List").getElementsByTagName("tbody")[0],e=c.getElementsByTagName("tr"),d=0;d<b;d++)if(!e[d]||
")"));$("#btntrashmodedown").hasClass("active")&&(a=$("#QueueList > tbody > tr:gt("+($(this).index()-1)+")"));$.each(a,function(){0==$(this).children().last().has("a").length&&$(this).children().last().append('<a class="pull-right btn-group-hover color-darkgrey" href="#/Queue!'+app.current.page+"/"+app.current.filter+"/"+app.current.search+'" onclick="delQueueSong($(this).parents(\'tr\'),event);"><span class="material-icons">delete</span></a>').find("a").fadeTo("fast",1)})},mouseleave:function(){var a= e[d].getAttribute("data-trackid")!=a.data[d].id){var g=Math.floor(a.data[d].duration/60),f=a.data[d].duration-60*g;g=g+":"+(10>f?"0":"")+f;f=document.createElement("tr");f.setAttribute("data-trackid",a.data[d].id);f.setAttribute("id","queueTrackId"+a.data[d].id);f.setAttribute("data-songpos",a.data[d].pos+1);f.setAttribute("data-duration",g);f.innerHTML="<td>"+(a.data[d].pos+1)+"</td><td>"+a.data[d].title+"</td><td>"+a.data[d].artist+"</td><td>"+a.data[d].album+"</td><td>"+g+'</td><td><a href="#" tabindex="0" class="material-icons">playlist_add</a></td>';
$(this);$("#btntrashmodeup").hasClass("active")&&(a=$("#QueueList > tbody > tr:lt("+($(this).index()+1)+")"));$("#btntrashmodedown").hasClass("active")&&(a=$("#QueueList > tbody > tr:gt("+($(this).index()-1)+")"));$.each(a,function(){$(this).children().last().find("a").stop().remove()})}});$("#QueueList > tbody > tr").on({click:function(){$("#queueList > tbody > tr").removeClass("active");sendAPI({cmd:"MPD_API_PLAY_TRACK",data:{track:$(this).attr("trackid")}});$(this).addClass("active")}})}} d<e.length?e[d].replaceWith(f):c.append(f)}for(d=e.length-1;d>=b;d--)e[d].remove();"queuesearch"==a.type&&0==b?c.innerHTML='<tr><td><span class="material-icons">error_outline</span></td><td colspan="5">No results, please refine your search!</td></tr>':"queue"==a.type&&0==b&&(c.innerHTML='<tr><td><span class="material-icons">error_outline</span></td><td colspan="5">Empty queue</td></tr>');setPagination(a.totalEntities)}}
function parseSearch(a){"Search"===app.current.app&&($("#panel-heading-search").text(a.totalEntities+" Songs found"),0<a.totalEntities?$("#searchAddAllSongs").removeAttr("disabled").removeClass("disabled"):$("#searchAddAllSongs").attr("disabled","disabled").addClass("disabled"),parseFilesystem(a))} function parseSearch(a){"Search"===app.current.app&&(document.getElementById("panel-heading-search").innerHTML=a.totalEntities+" Songs found",0<a.totalEntities?document.getElementById("searchAddAllSongs").removeAttribute("disabled"):document.getElementById("searchAddAllSongs").setAttribute("disabled","disabled"),parseFilesystem(a))}
function parseFilesystem(a){function b(a,b,c){$(a).html('<a role="button" class="pull-right btn-group-hover"><span class="material-icons">'+c+"</span></a>").find("a").click(function(a){a.stopPropagation();sendAPI({cmd:b,data:{uri:decodeURI($(this).parents("tr").attr("uri"))}});showNotification('"'+$("td:nth-last-child(3)",$(this).parents("tr")).text()+'" added',"","","success")})}if("Browse"===app.current.app||"Filesystem"===app.current.tab||"Search"===app.current.app){var c=0,d=document.getElementById(app.current.app+ 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],e=c.getElementsByTagName("tr"),d=0;d<b;d++){var g=encodeURI(a.data[d].uri);if(!e[d]||e[d].getAttribute("data-uri")!=g){var f=document.createElement("tr");f.setAttribute("data-type",a.data[d].type);f.setAttribute("data-uri",g);f.setAttribute("data-name",
(void 0==app.current.tab?"":app.current.tab)+"List").getElementsByTagName("tbody")[0].getElementsByTagName("tr"),e;for(e in a.data){c++;var f="",g="";switch(a.data[e].type){case "directory":g=encodeURI(a.data[e].dir);f='<tr uri="'+g+'" class="dir"><td><span class="material-icons">folder_open</span></td><td colspan="3"><a>'+basename(a.data[e].dir)+"</a></td><td></td><td></td></tr>";break;case "song":f=Math.floor(a.data[e].duration/60);var h=a.data[e].duration-60*f;g=encodeURI(a.data[e].uri);f='<tr uri="'+ a.data[d].name);switch(a.data[d].type){case "dir":f.innerHTML='<td><span class="material-icons">folder_open</span></td><td colspan="4">'+a.data[d].name+'</td><td><a href="#" class="material-icons">playlist_add</a></td>';break;case "song":g=Math.floor(a.data[d].duration/60);var h=a.data[d].duration-60*g;f.innerHTML='<td><span class="material-icons">music_note</span></td><td>'+a.data[d].title+"</td><td>"+a.data[d].artist+"</td><td>"+a.data[d].album+"</td><td>"+g+":"+(10>h?"0":"")+h+'</td><td><a href="#" class="material-icons">playlist_add</a></td>';
g+'" class="song"><td><span class="material-icons">music_note</span></td><td>'+a.data[e].title+"</td><td>"+a.data[e].artist+"</td><td>"+a.data[e].album+"</td><td>"+f+":"+(10>h?"0":"")+h+"</td><td></td></tr>";break;case "playlist":g=encodeURI(a.data[e].plist),f='<tr uri="'+g+'" class="plist"><td><span class="material-icons">list</span></td><td colspan="3"><a>'+basename(a.data[e].plist)+"</a></td><td></td><td></td></tr>"}c<=d.length?$(d[c-1]).attr("uri")!=g&&$(d[c-1]).replaceWith(f):$("#"+app.current.app+ break;case "plist":f.innerHTML='<td><span class="material-icons">list</span></td><td colspan="4">'+a.data[d].name+'</td><td><a href="#" class="material-icons">playlist_add</a></td>'}d<e.length?e[d].replaceWith(f):c.append(f)}}for(d=e.length-1;d>=b;d--)e[d].remove();setPagination(a.totalEntities);0==b&&(c.innerHTML='<tr><td><span class="material-icons">error_outline</span></td><td colspan="5">No results</td></tr>')}}
(void 0==app.current.tab?"":app.current.tab)+"List > tbody").append(f)}for(e=d.length;e>c;e--)$(d[d.length-1]).remove();setPagination(a.totalEntities);0==c&&$("#"+app.current.app+app.current.tab+"List > tbody").append('<tr><td><span class="material-icons">error_outline</span></td><td colspan="3">No results</td><td></td><td></td></tr>');if(isTouch)b($("#"+app.current.app+(void 0==app.current.tab?"":app.current.tab)+"List > tbody > tr.dir > td:last-child"),"MPD_API_ADD_TRACK","playlist_add"),b($("#"+ function parsePlaylists(a){if("Browse"===app.current.app||"Playlists"===app.current.tab){for(var b=a.data.length,c=document.getElementById(app.current.app+app.current.tab+"List").getElementsByTagName("tbody")[0],e=c.getElementsByTagName("tr"),d=0;d<b;d++){var g=encodeURI(a.data[d].uri);if(!e[d]||e[d].getAttribute("data-uri")!=g){var f=new Date(1E3*a.data[d].last_modified),h=document.createElement("tr");h.setAttribute("data-uri",g);h.setAttribute("data-type","plist");h.setAttribute("data-name",a.data[d].name);
app.current.app+(void 0==app.current.tab?"":app.current.tab)+"List > tbody > tr.song > td:last-child"),"MPD_API_ADD_TRACK","playlist_add");else $("#"+app.current.app+(void 0==app.current.tab?"":app.current.tab)+"List > tbody > tr").on({mouseenter:function(){$(this).is(".dir")?b($(this).children().last(),"MPD_API_ADD_TRACK","playlist_add"):$(this).is(".song")&&b($(this).children().last(),"MPD_API_ADD_TRACK","playlist_add")},mouseleave:function(){$(this).children().last().find("a").stop().remove()}}); h.innerHTML='<td><span class="material-icons">list</span></td><td>'+a.data[d].name+"</td><td>"+f.toUTCString()+'</td><td><a href="#" class="material-icons">playlist_add</a></td>';d<e.length?e[d].replaceWith(h):c.append(h)}}for(d=e.length-1;d>=b;d--)e[d].remove();setPagination(a.totalEntities);0==b&&(c.innerHTML='<tr><td><span class="material-icons">error_outline</span></td><td colspan="5">No playlists found.</td></tr>')}}
$("#"+app.current.app+(void 0==app.current.tab?"":app.current.tab)+"List > tbody > tr").on({click:function(){switch($(this).attr("class")){case "dir":app.current.page=0;app.current.search=$(this).attr("uri");$("#BrowseFilesystemList > a").attr("href","#/Browse/Filesystem!"+app.current.page+"/"+app.current.filter+"/"+app.current.search);app.goto("Browse","Filesystem",void 0,app.current.page+"/"+app.current.filter+"/"+app.current.search);break;case "song":sendAPI({cmd:"MPD_API_ADD_TRACK",data:{uri:decodeURI($(this).attr("uri"))}}); function parseListDBtags(a){if("Browse"===app.current.app||"Database"===app.current.tab||"Artist"===app.current.view)if("AlbumArtist"==a.tagtype){document.getElementById("BrowseDatabaseAlbumCards").classList.add("hide");document.getElementById("BrowseDatabaseArtistList").classList.remove("hide");document.getElementById("btnBrowseDatabaseArtist").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],
showNotification('"'+$("td:nth-last-child(5)",this).text()+'" added',"","","success");break;case "plist":sendAPI({cmd:"MPD_API_ADD_PLAYLIST",data:{plist:decodeURI($(this).attr("uri"))}}),showNotification('"'+$("td:nth-last-child(3)",this).text()+'" added',"","","success")}}});$("#BrowseBreadcrumb > li > a").on({click:function(){app.current.page=0;app.current.search=$(this).attr("uri");$("#BrowseFilesystemList > a").attr("href","#/Browse/Filesystem!"+app.current.page+"/"+app.current.filter+"/"+app.current.search); e=c.getElementsByTagName("tr"),d=0;d<b;d++){var g=encodeURI(a.data[d].value);if(!e[d]||e[d].getAttribute("data-uri")!=g){var f=document.createElement("tr");f.setAttribute("data-uri",g);f.innerHTML='<td><span class="material-icons">album</span></td><td>'+a.data[d].value+"</td>";d<e.length?e[d].replaceWith(f):c.append(f)}}for(d=e.length-1;d>=b;d--)e[d].remove();setPagination(a.totalEntities);0==b&&(c.innerHTML='<tr><td><span class="material-icons">error_outline</span></td><td colspan="5">No entries found.</td></tr>')}else if("Album"==
app.goto("Browse","Filesystem",void 0,app.current.page+"/"+app.current.filter+"/"+app.current.search)}});doSetFilterLetter("#BrowseFilesystemFilter")}} a.tagtype){document.getElementById("BrowseDatabaseAlbumCards").classList.remove("hide");document.getElementById("BrowseDatabaseArtistList").classList.add("hide");document.getElementById("btnBrowseDatabaseArtist").classList.remove("hide");b=a.data.length;c=document.getElementById("BrowseDatabaseAlbumCards");e=c.querySelectorAll(".col-md");for(d=0;d<b;d++)g=genId(a.data[d].value),e[d]&&e[d].getAttribute("id")==g||(f=document.createElement("div"),f.classList.add("col-md"),f.classList.add("mr-0"),f.setAttribute("id",
function parsePlaylists(a){if("Browse"===app.current.app||"Playlists"===app.current.tab){var b=0,c=document.getElementById(app.current.app+app.current.tab+"List").getElementsByTagName("tbody")[0].getElementsByTagName("tr"),d;for(d in a.data){b++;var e=new Date(1E3*a.data[d].last_modified),f=encodeURI(a.data[d].plist);e='<tr uri="'+f+'"><td><span class="material-icons">list</span></td><td><a>'+basename(a.data[d].plist)+"</a></td><td>"+e.toUTCString()+"</td><td></td></tr>";b<=c.length?$(c[b-1]).attr("uri")!= g),f.innerHTML='<div class="card mb-4" id="card'+g+'"> <img class="card-img-top" src="" > <div class="card-body"> <h5 class="card-title">'+a.searchstr+'</h5> <h4 class="card-title">'+a.data[d].value+'</h4> <table class="table table-sm table-hover" id="tbl'+g+'"><tbody></tbody></table </div></div>',d<e.length?e[d].replaceWith(f):c.append(f),sendAPI({cmd:"MPD_API_GET_ARTISTALBUMTITLES",data:{albumartist:a.searchstr,album:a.data[d].value}},parseListTitles));for(d=e.length-1;d>=b;d--)e[d].remove();
f&&$(c[b-1]).replaceWith(e):$("#"+app.current.app+app.current.tab+"List > tbody").append(e)}for(d=c.length;d>b;d--)$(c[c.length-1]).remove();setPagination(a.totalEntities);if(isTouch)$("#"+app.current.app+app.current.tab+"List > tbody > tr > td:last-child").append('<a class="pull-right btn-group-hover color-darkgrey" href="#/Browse/Playlists!'+app.current.page+"/"+app.current.filter+"/"+app.current.search+'" onclick="delPlaylist($(this).parents(\'tr\'));"><span class="material-icons">delete</span></a>'); setPagination(a.totalEntities)}}
else $("#"+app.current.app+app.current.tab+"List > tbody > tr").on({mouseover:function(){0==$(this).children().last().has("a").length&&$(this).children().last().append('<a class="pull-right btn-group-hover color-darkgrey" href="#/Browse/Playlists!'+app.current.page+"/"+app.current.filter+"/"+app.current.search+'" onclick="delPlaylist($(this).parents(\'tr\'));"><span class="material-icons">delete</span></a>')},mouseleave:function(){$(this);$(this).children().last().find("a").stop().remove()}});$("#"+ 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];c=c.getElementsByTagName("img")[0];c.setAttribute("src",a.cover);c.setAttribute("data-uri",a.data[0].uri.replace(/\/[^\/]+$/,""));c.setAttribute("data-name",encodeURI(a.album));c.setAttribute("data-type","album");for(var e="",d=a.data.length,g=0;g<d;g++)e+='<tr data-type="song" data-name="'+a.data[g].title+
app.current.app+app.current.tab+"List > tbody > tr").on({click:function(){sendAPI({cmd:"MPD_API_ADD_PLAYLIST",data:{plist:decodeURI($(this).attr("uri"))}});showNotification('"'+$("td:nth-last-child(3)",this).text()+'" added',"","","success")}});0==b&&$("#"+app.current.app+app.current.tab+"List > tbody").append('<tr><td><span class="material-icons">error_outline</span></td><td colspan="3">No playlists found.</td><td></td><td></td></tr>');doSetFilterLetter("#browsePlaylistsFilter")}} '" data-uri="'+encodeURI(a.data[g].uri)+'"><td>'+a.data[g].track+"</td><td>"+a.data[g].title+'</td><td><a href="#" class="material-icons">playlist_add</a></td></tr>';b.innerHTML=e;c.addEventListener("click",function(){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 parseListDBtags(a){if("Browse"===app.current.app||"Database"===app.current.tab||"Artist"===app.current.view){if("AlbumArtist"==a.tagtype){$("#BrowseDatabaseAlbumCards").addClass("hide");$("#BrowseDatabaseArtistList").removeClass("hide");$("#btnBrowseDatabaseArtist").addClass("hide");var b=0,c=document.getElementById(app.current.app+app.current.tab+app.current.view+"List").getElementsByTagName("tbody")[0].getElementsByTagName("tr"),d;for(d in a.data){b++;var e=encodeURI(a.data[d].value),f= function setPagination(a){var b=Math.ceil(a/settings.max_elements_per_page),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.max_elements_per_page+1+" / "+b;if(1<b){document.getElementById(c+e[d]+"Page").removeAttribute("disabled");for(var g="",f=0;f<b;f++)g+='<button data-page="'+f*settings.max_elements_per_page+'" type="button" class="mr-1 mb-1 btn-sm btn btn-secondary">'+
'<tr uri="'+e+'"><td><span class="material-icons">album</span></td><td><a>'+a.data[d].value+"</a></td></tr>";b<=c.length?$(c[b-1]).attr("uri")!=e&&$(c[b-1]).replaceWith(f):$("#"+app.current.app+app.current.tab+app.current.view+"List > tbody").append(f)}for(d=c.length;d>b;d--)$(c[c.length-1]).remove();setPagination(a.totalEntities);$("#"+app.current.app+app.current.tab+app.current.view+"List > tbody > tr").on({click:function(){app.goto("Browse","Database","Album","0/-/"+$(this).attr("uri"))}});0== (f+1)+"</button>";document.getElementById(c+e[d]+"Pages").innerHTML=g}else document.getElementById(c+e[d]+"Page").setAttribute("disabled","disabled");a>app.current.page+settings.max_elements_per_page?(document.getElementById(c+e[d]+"Next").removeAttribute("disabled"),document.getElementById(c+"ButtonsBottom").classList.remove("hide")):(document.getElementById(c+e[d]+"Next").setAttribute("disabled","disabled"),document.getElementById(c+"ButtonsBottom").classList.add("hide"));0<app.current.page?(document.getElementById(c+
b&&$("#"+app.current.app+app.current.tab+app.current.view+"List > tbody").append('<tr><td><span class="material-icons">error_outline</span></td><td colspan="3">No entries found.</td><td></td><td></td></tr>')}else if("Album"==a.tagtype){$("#BrowseDatabaseArtistList").addClass("hide");$("#BrowseDatabaseAlbumCards").removeClass("hide");$("#btnBrowseDatabaseArtist").removeClass("hide");b=0;c=document.getElementById("BrowseDatabaseAlbumCards").querySelectorAll(".col-md");for(d in a.data)b++,e=genId(a.data[d].value), e[d]+"Prev").removeAttribute("disabled"),document.getElementById(c+"ButtonsBottom").classList.remove("hide")):document.getElementById(c+e[d]+"Prev").setAttribute("disabled","disabled")}}function appendQueue(a,b,c){switch(a){case "song":sendAPI({cmd:"MPD_API_ADD_TRACK",data:{uri:b}});showNotification('"'+c+'" added',"","","success");break;case "plist":sendAPI({cmd:"MPD_API_ADD_PLAYLIST",data:{plist:b}}),showNotification('"'+c+'" added',"","","success")}}
f='<div class="col-md mr-0" id="'+e+'"><div class="card mb-4" id="card'+e+'"> <img class="card-img-top" src="" alt=""> <div class="card-body"> <h5 class="card-title">'+a.searchstr+'</h5> <h4 class="card-title">'+a.data[d].value+'</h4> <table class="table table-sm table-hover" id="tbl'+e+'"><tbody></tbody></table </div></div></div>',b<=c.length?c[b-1].id!=e&&$(c[b-1]).replaceWith(f):$("#BrowseDatabaseAlbumCards").append(f),(b>c.length||c[b-1].id!=e)&&sendAPI({cmd:"MPD_API_GET_ARTISTALBUMTITLES", function showMenu(a){var b=a.parentNode.parentNode.getAttribute("data-type");a.parentNode.parentNode.getAttribute("data-uri");("Browse"==app.current.app&&"Filesystem"==app.current.tab||"Search"==app.current.app||"Browse"==app.current.app&&"Database"==app.current.tab&&"Album"==app.current.view)&&new Popover(a,{content:'<a class="dropdown-item" href="#">Append to queue</a><a class="dropdown-item" href="#">Add after current playing song</a><a class="dropdown-item" href="#">Replace queue</a>'+("plist"!=
data:{albumartist:a.searchstr,album:a.data[d].value}},parseListTitles);for(d=c.length;d>b;d--)$(c[d-1]).remove();setPagination(a.totalEntities)}doSetFilterLetter("#BrowseDatabaseFilter")}} b?'<div class="dropdown-divider"></div><a class="dropdown-item" href="#">Add to playlist</a>':"")+("dir"!=b?'<div class="dropdown-divider"></div>':"")+("song"==b?'<a class="dropdown-item" href="#">Songdetails</a>':"")+("plist"==b?'<a class="dropdown-item" href="#">Show playlist</a>':"")});a.Popover.show()}
function parseListTitles(a){if("Browse"===app.current.app||"Database"===app.current.tab||"Album"===app.current.view){var b=genId(a.album),c=$("#card"+b+" > div > table > tbody");$("#card"+b+" > img").attr("src",a.cover).attr("uri",a.data[0].uri.replace(/\/[^\/]+$/,"")).attr("data-album",encodeURI(a.album));var d="",e;for(e in a.data)d+='<tr uri="'+encodeURI(a.data[e].uri)+'" class="song"><td>'+a.data[e].track+"</td><td>"+a.data[e].title+"</td></tr>";c.append(d);$("#card"+b+" > img").on({click:function(){sendAPI({cmd:"MPD_API_ADD_TRACK", function sendAPI(a,b){var c=new XMLHttpRequest;c.open("POST","/api",!0);c.setRequestHeader("Content-type","application/json");c.onreadystatechange=function(){4==c.readyState&&void 0!=b&&"function"==typeof b&&b(JSON.parse(c.responseText))};c.send(JSON.stringify(a))}function openLocalPlayer(){window.open("/player.html#"+settings.mpdstream,"LocalPlayer")}function updateDB(){sendAPI({cmd:"MPD_API_UPDATE_DB"});showNotification("Updating MPD Database...","","","success")}
data:{uri:decodeURI($(this).attr("uri"))}});showNotification('"'+decodeURI($(this).attr("data-album"))+'" added',"","","success")}});$("#tbl"+b+" > tbody > tr").on({click:function(){sendAPI({cmd:"MPD_API_ADD_TRACK",data:{uri:decodeURI($(this).attr("uri"))}});showNotification('"'+$("td:nth-last-child(1)",this).text()+'" added',"","","success")}})}} function clickPlay(){"play"!=playstate?sendAPI({cmd:"MPD_API_SET_PLAY"}):sendAPI({cmd:"MPD_API_SET_PAUSE"})}function clickStop(){sendAPI({cmd:"MPD_API_SET_STOP"})}function clickPrev(){sendAPI({cmd:"MPD_API_SET_PREV"})}function clickNext(){sendAPI({cmd:"MPD_API_SET_NEXT"})}function delQueueSong(a,b){b.stopPropagation()}function delPlaylist(a){sendAPI({cmd:"MPD_API_RM_PLAYLIST",data:{plist:decodeURI(a.attr("data-uri"))}});a.remove()}
function setPagination(a){var b=Math.ceil(a/settings.max_elements_per_page),c=app.current.app+(void 0==app.current.tab?"":app.current.tab);0==b&&(b=1);$("#"+c+"PaginationTopPage").text("Page "+(app.current.page/settings.max_elements_per_page+1)+" / "+b);$("#"+c+"PaginationBottomPage").text("Page "+(app.current.page/settings.max_elements_per_page+1)+" / "+b);if(1<b){$("#"+c+"PaginationTopPage").removeClass("disabled").removeAttr("disabled");$("#"+c+"PaginationBottomPage").removeClass("disabled").removeAttr("disabled"); 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}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"),
$("#"+c+"PaginationTopPages").empty();$("#"+c+"PaginationBottomPages").empty();for(var d=0;d<b;d++)$("#"+c+"PaginationTopPages").append('<button onclick="gotoPage('+d*settings.max_elements_per_page+',this,event)" type="button" class="mr-1 mb-1 btn-sm btn btn-secondary">'+(d+1)+"</button>"),$("#"+c+"PaginationBottomPages").append('<button onclick="gotoPage('+d*settings.max_elements_per_page+',this,event)" type="button" class="mr-1 mb-1 btn-sm btn btn-secondary">'+(d+1)+"</button>")}else $("#"+c+"PaginationTopPage").addClass("disabled").attr("disabled", a=!1):b.value=c);1==a?(a=document.getElementById("selectReplaygain"),sendAPI({cmd:"MPD_API_SET_SETTINGS",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,
"disabled"),$("#"+c+"PaginationBottomPage").addClass("disabled").attr("disabled","disabled");a>app.current.page+settings.max_elements_per_page?($("#"+c+"PaginationTopNext").removeClass("disabled").removeAttr("disabled"),$("#"+c+"PaginationBottomNext").removeClass("disabled").removeAttr("disabled"),$("#"+c+"ButtonsBottom").removeClass("hide")):($("#"+c+"PaginationTopNext").addClass("disabled").attr("disabled","disabled"),$("#"+c+"PaginationBottomNext").addClass("disabled").attr("disabled","disabled"), mixrampdb:document.getElementById("inputMixrampdb").value,mixrampdelay:document.getElementById("inputMixrampdelay").vaue,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")}
$("#"+c+"ButtonsBottom").addClass("hide"));0<app.current.page?($("#"+c+"PaginationTopPrev").removeClass("disabled").removeAttr("disabled"),$("#"+c+"PaginationBottomPrev").removeClass("disabled").removeAttr("disabled")):($("#"+c+"PaginationTopPrev").addClass("disabled").attr("disabled","disabled"),$("#"+c+"PaginationBottomPrev").addClass("disabled").attr("disabled","disabled"))} function addAllFromBrowse(){sendAPI({cmd:"MPD_API_ADD_TRACK",data:{uri:app.current.search}});showNotification("Added all songs","","","success")}function addAllFromSearch(){2<=app.current.search.length&&(sendAPI({cmd:"MPD_API_SEARCH_ADD",data:{filter:app.current.filter,searchstr:+app.current.search}}),showNotification("Added "+parseInt(document.getElementById("panel-heading-search").innerText)+" songs from search","","","success"))}
function updateVolumeIcon(a){-1==a?($("#volumePrct").text("Volumecontrol disabled"),$("#volumeControl").addClass("hide")):($("#volumeControl").removeClass("hidden"),$("#volumePrct").text(a+" %"),0==a?$("#volume-icon").text("volume_off"):50>a?$("#volume-icon").text("volume_down"):$("#volume-icon").text("volume_up"))} function scrollToTop(){document.body.scrollTop=0;document.documentElement.scrollTop=0}function gotoPage(a){switch(a){case "next":app.current.page+=settings.max_elements_per_page;break;case "prev":app.current.page-=settings.max_elements_per_page;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 updatePlayIcon(a){1==a.data.state?($("#btnPlay > span").text("play_arrow"),playstate="stop"):2==a.data.state?($("#btnPlay > span").text("pause"),playstate="play"):($("#btnPlay > span").text("play_arrow"),playstate="pause");-1==a.data.nextsongpos?$("#btnNext").addClass("disabled").attr("disabled","disabled"):$("#btnNext").removeClass("disabled").removeAttr("disabled");0>=a.data.songpos?$("#btnPrev").addClass("disabled").attr("disabled","disabled"):$("#btnPrev").removeClass("disabled").removeAttr("disabled"); function addStream(){var a=document.getElementById("streamurl");""!=a.value&&sendAPI({cmd:"MPD_API_ADD_TRACK",data:{uri:a.value}});a.value="";modalAddstream.hide()}function saveQueue(){var a=document.getElementById("playlistname");""!=a.value&&sendAPI({cmd:"MPD_API_SAVE_QUEUE",data:{plist:a.value}});a.value="";modalSavequeue.hide()}
0==a.data.queue_length?$("#btnPlay").addClass("disabled").attr("disabled","disabled"):$("#btnPlay").removeClass("disabled").removeAttr("disabled")}function shuffleQueue(){sendAPI({cmd:"MPD_API_SEND_SHUFFLE"})}function clearQueue(){sendAPI({cmd:"MPD_API_RM_ALL"})}function sendAPI(a,b){$.ajax({url:"/api",contentType:"application/json",method:"POST",data:JSON.stringify(a),success:b})} 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.classList.add("alert","alert-"+e),b.innerHTML="<div><strong>"+a+"</strong>"+c+"</div>",document.getElementsByTagName("main")[0].append(b),document.getElementById("alertBox").classList.add("alertBoxActive"),
function updateDB(a){sendAPI({cmd:"MPD_API_UPDATE_DB"});showNotification("Updating MPD Database...","","","success");a.preventDefault()}function clickPlay(){"play"!=playstate?sendAPI({cmd:"MPD_API_SET_PLAY"}):sendAPI({cmd:"MPD_API_SET_PAUSE"})}function clickStop(){sendAPI({cmd:"MPD_API_SET_STOP"})}function clickPrev(){sendAPI({cmd:"MPD_API_SET_PREV"})}function clickNext(){sendAPI({cmd:"MPD_API_SET_NEXT"})} timeOut&&clearTimeout(timeOut),timeOut=setTimeout(function(){document.getElementById("alertBox").classList.remove("alertBoxActive");setTimeout(function(){document.getElementById("alertBox").remove()},600)},3E3))}function notificationsSupported(){return"Notification"in window}
function setLocalStream(a,b){var c="http://";c="127.0.0.1"==a||"localhost"==a?c+window.location.hostname:c+a;settings.mpdstream=c+(":"+b+"/")} function songChange(a){var b=a.data.title+a.data.artist+a.data.album+a.data.uri+a.data.currentsongid;if(last_song!=b){var c="",e="",d="myMPD: ";document.getElementById("album-cover").style.backgroundImage='url("'+a.data.cover+'")';"undefined"!=typeof a.data.artist&&0<a.data.artist.length&&"-"!=a.data.artist?(c+=a.data.artist,e+="<br/>"+a.data.artist,d+=a.data.artist+" - ",document.getElementById("artist").innerText=a.data.artist):document.getElementById("artist").innerText="";"undefined"!=typeof a.data.album&&
function delQueueSong(a,b){b.stopPropagation();$("#btntrashmodeup").hasClass("active")?sendAPI({cmd:"MPD_API_RM_RANGE",data:{start:0,end:a.index()+1}}):$("#btntrashmodesingle").hasClass("active")?sendAPI({cmd:"MPD_API_RM_TRACK",data:{track:a.attr("trackid")}}):$("#btntrashmodedown").hasClass("active")&&sendAPI({cmd:"MPD_API_RM_RANGE",data:{start:a.index(),end:-1}})}function delPlaylist(a){sendAPI({cmd:"MPD_API_RM_PLAYLIST",data:{plist:decodeURI(a.attr("uri"))}});a.remove()} 0<a.data.album.length&&"-"!=a.data.album?(c+=" - "+a.data.album,e+="<br/>"+a.data.album,document.getElementById("album").innerText=a.data.album):document.getElementById("album").innerText="";"undefined"!=typeof a.data.title&&0<a.data.title.length?(d+=a.data.title,document.getElementById("currenttrack").innerText=a.data.title):document.getElementById("currenttrack").innerText="";document.title=d;showNotification(a.data.title,c,e,"success");last_song=b}}
function basename(a){return a.split("/").reverse()[0]}$("#cardBrowseNavFilesystem").on("click",function(a){app.goto("Browse","Filesystem");a.preventDefault()});$("#cardBrowseNavDatabase").on("click",function(a){app.goto("Browse","Database");a.preventDefault()});$("#btnBrowseDatabaseArtist").on("click",function(a){app.goto("Browse","Database","Artist");a.preventDefault()});$("#cardBrowseNavPlaylists").on("click",function(a){app.goto("Browse","Playlists");a.preventDefault()}); function doSetFilterLetter(a){var b=document.getElementById(a+"Letters").querySelector(".active");b&&b.classList.remove("active");b=app.current.filter;"0"==b&&(b="#");document.getElementById(a).innerText="Filter"+("-"!=b?": "+b:"");if("-"!=b){a=document.getElementById(a+"Letters").getElementsByTagName("button");for(var c=a.length,e=0;e<c;e++)if(a[e].innerText==b){a[e].classList.add("active");break}}}
$("#cardBrowseNavFilesystem").on("click",function(a){app.goto("Browse","Filesystem");a.preventDefault()});$("#navPlayback").on("click",function(a){app.goto("Playback");a.preventDefault()});$("#navQueue").on("click",function(a){app.goto("Queue");a.preventDefault()});$("#navBrowse").on("click",function(a){app.goto("Browse");a.preventDefault()});$("#navSearch").on("click",function(a){app.goto("Search");a.preventDefault()}); function addFilterLetter(a){var b='<button class="mr-1 mb-1 btn btn-sm btn-secondary material-icons material-icons-small">delete</button><button class="mr-1 mb-1 btn btn-sm btn-secondary">#</button>';for(i=65;90>=i;i++)b+='<button class="mr-1 mb-1 btn-sm btn btn-secondary">'+String.fromCharCode(i)+"</button>";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,
function confirmSettings(){var a=!0;if(!$("#inputCrossfade").is(":disabled")){var b=parseInt($("#inputCrossfade").val());isNaN(b)?(document.getElementById("inputCrossfade").classList.add("is-invalid"),a=!1):$("#inputCrossfade").val(b)}$("#inputMixrampdb").is(":disabled")||(b=parseFloat($("#inputMixrampdb").val()),isNaN(b)?(document.getElementById("inputMixrampdb").classList.add("is-invalid"),a=!1):$("#inputMixrampdb").val(b));$("#inputMixrampdelay").is(":disabled")||("nan"==$("#inputMixrampdelay").val()&& 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:100<a&&(a=100);domCache.volumeBar.value=a;sendAPI({cmd:"MPD_API_SET_VOLUME",data:{volume:a}})}function beautifyDuration(a){var b=Math.floor(a/86400),c=Math.floor(a/3600)-24*b,e=Math.floor(a/60)-60*c-1440*b;a=a-86400*b-3600*c-60*e;return(0<b?b+"\u2009d ":"")+(0<c?c+"\u2009h "+(10>e?"0":""):"")+e+"\u2009m "+(10>a?"0":"")+a+"\u2009s"}
$("#inputMixrampdelay").val("-1"),b=parseFloat($("#inputMixrampdelay").val()),isNaN(b)?(document.getElementById("inputMixrampdelay").classList.add("is-invalid"),a=!1):$("#inputMixrampdelay").val(b));1==a?(sendAPI({cmd:"MPD_API_SET_SETTINGS",data:{consume:$("#btnconsume").hasClass("active")?1:0,random:$("#btnrandom").hasClass("active")?1:0,single:$("#btnsingle").hasClass("active")?1:0,repeat:$("#btnrepeat").hasClass("active")?1:0,replaygain:$("#selectReplaygain").val(),crossfade:$("#inputCrossfade").val(), function genId(a){return"id"+a.replace(/[^\w]/g,"")}appInit();
mixrampdb:$("#inputMixrampdb").val(),mixrampdelay:$("#inputMixrampdelay").val(),notificationWeb:$("#btnnotifyWeb").hasClass("active")?1:0,notificationPage:$("#btnnotifyPage").hasClass("active")?1:0}},getSettings),$("#settings").modal("hide")):document.getElementById("settingsFrm").classList.add("was-validated")}function toggleoutput(a,b){sendAPI({cmd:"MPD_API_TOGGLE_OUTPUT",data:{output:b,state:$(a).hasClass("active")?0:1}})}
$("#trashmodebtns > button").on("click",function(a){$("#trashmodebtns").children("button").removeClass("active");$(this).addClass("active")});$("#search > input").keypress(function(a){13==a.which&&$("#mainMenu > a").dropdown("toggle")});$("#search").submit(function(){app.goto("Search",void 0,void 0,app.current.page+"/Any Tag/"+$("#search > input").val());return!1});$("#search2").submit(function(){return!1});
function addAllFromSearch(){if(2<=app.current.search.length){sendAPI({cmd:"MPD_API_SEARCH_ADD",data:{filter:app.current.filter,searchstr:+app.current.search}});var a=$("#SearchList >tbody >tr").length;showNotification("Added "+a+" songs from search","","","success")}}$("#searchstr2").keyup(function(a){app.current.page=0;app.current.search=$(this).val();app.goto("Search",void 0,void 0,app.current.page+"/"+app.current.filter+"/"+app.current.search)});
$("#searchtags2 > button").on("click",function(a){$("#searchtags2 > button").removeClass("active");$(this).removeClass("btn-secondary").addClass("active");app.current.filter=$(this).text();app.goto(app.current.app,app.current.tab,app.current.view,app.current.page+"/"+app.current.filter+"/"+app.current.search)});
$("#searchqueuestr").keyup(function(a){app.current.page=0;app.current.search=$(this).val();app.goto(app.current.app,app.current.tab,app.current.view,app.current.page+"/"+app.current.filter+"/"+app.current.search)});
$("#searchqueuetag > button").on("click",function(a){$("#searchqueuetag > button").removeClass("active");$(this).removeClass("btn-secondary").addClass("active");app.current.filter=$(this).text();$("#searchqueuetagdesc").text(app.current.filter);app.goto(app.current.app,app.current.tab,app.current.view,app.current.page+"/"+app.current.filter+"/"+app.current.search)});$("#searchqueue").submit(function(){return!1});$("#searchqueue").submit(function(){return!1});
function scrollToTop(){document.body.scrollTop=0;document.documentElement.scrollTop=0}function gotoPage(a,b,c){switch(a){case "next":app.current.page+=settings.max_elements_per_page;break;case "prev":app.current.page-=settings.max_elements_per_page;0>=app.current.page&&(app.current.page=0);break;default:app.current.page=a}app.goto(app.current.app,app.current.tab,app.current.view,app.current.page+"/"+app.current.filter+"/"+app.current.search);c.preventDefault()}
function addStream(){0<$("#streamurl").val().length&&sendAPI({cmd:"MPD_API_ADD_TRACK",data:{uri:$("#streamurl").val()}});$("#streamurl").val("");$("#addstream").modal("hide")}function saveQueue(){0<$("#playlistname").val().length&&sendAPI({cmd:"MPD_API_SAVE_QUEUE",data:{plist:$("#playlistname").val()}});$("#savequeue").modal("hide")}
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&&$.notify({title:a,message:c},{type:d,offset:{y:60,x:20},template:'<div data-notify="container" class="alert alert-{0}" role="alert"><span data-notify="title">{1}</span> <span data-notify="message">{2}</span></div>'})}function notificationsSupported(){return"Notification"in window}
function songChange(a){if(last_song!=a.data.title+a.data.artist+a.data.album+a.data.uri+a.data.currentsongid){var b="",c="",d="myMPD: ";$("#album-cover").css("backgroundImage",'url("'+a.data.cover+'")');"undefined"!=typeof a.data.artist&&0<a.data.artist.length&&"-"!=a.data.artist?(b+=a.data.artist,c+="<br/>"+a.data.artist,d+=a.data.artist+" - ",$("#artist").text(a.data.artist)):$("#artist").text("");"undefined"!=typeof a.data.album&&0<a.data.album.length&&"-"!=a.data.album?(b+=" - "+a.data.album,
c+="<br/>"+a.data.album,$("#album").text(a.data.album)):$("#album").text("");"undefined"!=typeof a.data.title&&0<a.data.title.length?(d+=a.data.title,$("#currenttrack").text(a.data.title)):$("#currenttrack").text("");document.title=d;showNotification(a.data.title,b,c,"success");last_song=a.data.title+a.data.artist+a.data.album+a.data.uri+a.data.currentsongid}}
$(document).keydown(function(a){if("INPUT"!=a.target.tagName){switch(a.which){case 37:sendAPI({cmd:"MPD_API_SET_PREV"});break;case 39:sendAPI({cmd:"MPD_API_SET_NEXT"});break;case 32:clickPlay();break;default:return}a.preventDefault()}});function setFilterLetter(a){app.goto(app.current.app,app.current.tab,app.current.view,"0/"+a+"/"+app.current.search)}
function doSetFilterLetter(a){$(a+"Letters > button").removeClass("active");"0"==app.current.filter?($(a).text("Filter: #"),$(a+"Letters > button").each(function(){"#"==$(this).text()&&$(this).addClass("active")})):"-"!=app.current.filter?($(a).text("Filter: "+app.current.filter),$(a+"Letters > button").each(function(){$(this).text()==app.current.filter&&$(this).addClass("active")})):$(a).text("Filter")}
function add_filter(a){$(a).append('<button class="mr-1 mb-1 btn btn-sm btn-secondary" onclick="setFilterLetter(\'-\');"><span class="material-icons" style="font-size:14px;">delete</span></button>');$(a).append('<button class="mr-1 mb-1 btn btn-sm btn-secondary" onclick="setFilterLetter(\'0\');">#</button>');for(i=65;90>=i;i++){var b=String.fromCharCode(i);$(a).append('<button class="mr-1 mb-1 btn-sm btn btn-secondary" onclick="setFilterLetter(\''+b+"');\">"+b+"</button>")}}
function chVolume(a){a=volumeBar.slider("getValue")+a;0>a?a=0:100<a&&(a=100);volumeBar.slider("setValue",a);sendAPI({cmd:"MPD_API_SET_VOLUME",data:{volume:a}})}function beautifyDuration(a){var b=Math.floor(a/86400),c=Math.floor(a/3600)-24*b,d=Math.floor(a/60)-60*c-1440*b;a=a-86400*b-3600*c-60*d;return(0<b?b+"\u2009d ":"")+(0<c?c+"\u2009h "+(10>d?"0":""):"")+d+"\u2009m "+(10>a?"0":"")+a+"\u2009s"}function genId(a){return"id"+a.replace(/[^\w]/g,"")};

View File

@ -1,5 +1,5 @@
var mpdstream = decodeURI(location.hash).replace(/^#/,''); var player = document.getElementById('player');
player.src = mpdstream; player.src = decodeURI(location.hash).replace(/^#/,'');
console.log('playing mpd stream: ' + player.src); console.log('playing mpd stream: ' + player.src);
player.load(); player.load();
player.play(); player.play();

View File

@ -1 +1 @@
var mpdstream=decodeURI(location.hash).replace(/^#/,"");player.src=mpdstream;console.log("playing mpd stream: "+player.src);player.load();player.play(); var player=document.getElementById("player");player.src=decodeURI(location.hash).replace(/^#/,"");console.log("playing mpd stream: "+player.src);player.load();player.play();

View File

@ -61,13 +61,17 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg)
float float_buf; float float_buf;
char *p_charbuf1, *p_charbuf2; char *p_charbuf1, *p_charbuf2;
struct mympd_state { int a; int b; } state = { .a = 0, .b = 0 }; struct mympd_state { int a; int b; } state = { .a = 0, .b = 0 };
enum mpd_cmd_ids cmd_id;
#ifdef DEBUG #ifdef DEBUG
fprintf(stdout,"Got request: %s\n",msg.p); fprintf(stdout,"Got request: %s\n",msg.p);
#endif #endif
json_scanf(msg.p, msg.len, "{cmd:%Q}", &cmd); je = json_scanf(msg.p, msg.len, "{cmd:%Q}", &cmd);
enum mpd_cmd_ids cmd_id = get_cmd_id(cmd); if (je == 1)
cmd_id = get_cmd_id(cmd);
else
return;
if(cmd_id == -1) if(cmd_id == -1)
return; return;
@ -116,16 +120,17 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg)
while ((pair = mpd_recv_pair(mpd.conn)) != NULL) { while ((pair = mpd_recv_pair(mpd.conn)) != NULL) {
mpd_return_pair(mpd.conn, pair); mpd_return_pair(mpd.conn, pair);
} }
free(p_charbuf1);
} }
free(p_charbuf1);
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\":\"result\", \"data\": \"ok\"}"); n = snprintf(mpd.buf, MAX_SIZE, "{\"type\":\"result\", \"data\": \"ok\"}");
break; break;
case MPD_API_GET_ARTISTALBUMTITLES: case MPD_API_GET_ARTISTALBUMTITLES:
je = json_scanf(msg.p, msg.len, "{ data: { albumartist:%Q, album:%Q } }", &p_charbuf1, &p_charbuf2); je = json_scanf(msg.p, msg.len, "{ data: { albumartist:%Q, album:%Q } }", &p_charbuf1, &p_charbuf2);
if (je == 2) if (je == 2) {
n = mympd_put_songs_in_album(mpd.buf, p_charbuf1, p_charbuf2); n = mympd_put_songs_in_album(mpd.buf, p_charbuf1, p_charbuf2);
free(p_charbuf1); free(p_charbuf1);
free(p_charbuf2); free(p_charbuf2);
}
break; break;
case MPD_API_WELCOME: case MPD_API_WELCOME:
n = mympd_put_welcome(mpd.buf); n = mympd_put_welcome(mpd.buf);
@ -208,35 +213,56 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg)
break; break;
case MPD_API_GET_ARTISTS: case MPD_API_GET_ARTISTS:
je = json_scanf(msg.p, msg.len, "{ data: { offset:%u, filter:%Q } }", &uint_buf1, &p_charbuf1); je = json_scanf(msg.p, msg.len, "{ data: { offset:%u, filter:%Q } }", &uint_buf1, &p_charbuf1);
if (je == 2) if (je == 2) {
n = mympd_put_db_tag(mpd.buf, uint_buf1, "AlbumArtist","","",p_charbuf1); n = mympd_put_db_tag(mpd.buf, uint_buf1, "AlbumArtist","","",p_charbuf1);
free(p_charbuf1); free(p_charbuf1);
}
break; break;
case MPD_API_GET_ARTISTALBUMS: case MPD_API_GET_ARTISTALBUMS:
je = json_scanf(msg.p, msg.len, "{ data: { offset:%u, filter:%Q, albumartist:%Q } }", &uint_buf1, &p_charbuf1, &p_charbuf2); je = json_scanf(msg.p, msg.len, "{ data: { offset:%u, filter:%Q, albumartist:%Q } }", &uint_buf1, &p_charbuf1, &p_charbuf2);
if (je == 3) 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, "Album", "AlbumArtist", p_charbuf2, p_charbuf1);
free(p_charbuf1); free(p_charbuf1);
free(p_charbuf2); free(p_charbuf2);
}
break; break;
case MPD_API_GET_PLAYLISTS: case MPD_API_GET_PLAYLISTS:
je = json_scanf(msg.p, msg.len, "{ data: { offset:%u, filter:%Q } }", &uint_buf1, &p_charbuf1); je = json_scanf(msg.p, msg.len, "{ data: { offset:%u, filter:%Q } }", &uint_buf1, &p_charbuf1);
if (je == 2) if (je == 2) {
n = mympd_put_playlists(mpd.buf, uint_buf1, p_charbuf1); n = mympd_put_playlists(mpd.buf, uint_buf1, p_charbuf1);
free(p_charbuf1); free(p_charbuf1);
}
break; break;
case MPD_API_GET_FILESYSTEM: case MPD_API_GET_FILESYSTEM:
je = json_scanf(msg.p, msg.len, "{ data: { offset:%u, filter:%Q, path:%Q } }", &uint_buf1, &p_charbuf1, &p_charbuf2); je = json_scanf(msg.p, msg.len, "{ data: { offset:%u, filter:%Q, path:%Q } }", &uint_buf1, &p_charbuf1, &p_charbuf2);
if (je == 3) if (je == 3) {
n = mympd_put_browse(mpd.buf, p_charbuf2, uint_buf1, p_charbuf1); n = mympd_put_browse(mpd.buf, p_charbuf2, uint_buf1, p_charbuf1);
free(p_charbuf1); free(p_charbuf1);
free(p_charbuf2); free(p_charbuf2);
}
break;
case MPD_API_ADD_TRACK_AFTER:
je = json_scanf(msg.p, msg.len, "{ data: { uri:%Q, to:%u } }", &p_charbuf1, &uint_buf1);
if (je == 2) {
mpd_run_add_id_to(mpd.conn, p_charbuf1, uint_buf1);
free(p_charbuf1);
}
break;
case MPD_API_REPLACE_TRACK:
je = json_scanf(msg.p, msg.len, "{ data: { uri:%Q } }", &p_charbuf1);
if (je == 1) {
mpd_run_clear(mpd.conn);
mpd_run_add(mpd.conn, p_charbuf1);
free(p_charbuf1);
mpd_run_play(mpd.conn);
}
break; break;
case MPD_API_ADD_TRACK: case MPD_API_ADD_TRACK:
je = json_scanf(msg.p, msg.len, "{ data: { uri:%Q } }", &p_charbuf1); je = json_scanf(msg.p, msg.len, "{ data: { uri:%Q } }", &p_charbuf1);
if (je == 1) if (je == 1) {
mpd_run_add(mpd.conn, p_charbuf1); mpd_run_add(mpd.conn, p_charbuf1);
free(p_charbuf1); free(p_charbuf1);
}
break; break;
case MPD_API_ADD_PLAY_TRACK: case MPD_API_ADD_PLAY_TRACK:
je = json_scanf(msg.p, msg.len, "{ data: { uri:%Q } }", &p_charbuf1); je = json_scanf(msg.p, msg.len, "{ data: { uri:%Q } }", &p_charbuf1);
@ -244,57 +270,73 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg)
int_buf = mpd_run_add_id(mpd.conn, p_charbuf1); int_buf = mpd_run_add_id(mpd.conn, p_charbuf1);
if(int_buf != -1) if(int_buf != -1)
mpd_run_play_id(mpd.conn, int_buf); mpd_run_play_id(mpd.conn, int_buf);
free(p_charbuf1);
}
break;
case MPD_API_REPLACE_PLAYLIST:
je = json_scanf(msg.p, msg.len, "{ data: { plist:%Q } }", &p_charbuf1);
if (je == 1) {
mpd_run_clear(mpd.conn);
mpd_run_load(mpd.conn, p_charbuf1);
free(p_charbuf1);
mpd_run_play(mpd.conn);
} }
free(p_charbuf1);
break; break;
case MPD_API_ADD_PLAYLIST: case MPD_API_ADD_PLAYLIST:
je = json_scanf(msg.p, msg.len, "{ data: { plist:%Q } }", &p_charbuf1); je = json_scanf(msg.p, msg.len, "{ data: { plist:%Q } }", &p_charbuf1);
if (je == 1) if (je == 1) {
mpd_run_load(mpd.conn, p_charbuf1); mpd_run_load(mpd.conn, p_charbuf1);
free(p_charbuf1); free(p_charbuf1);
}
break; break;
case MPD_API_SAVE_QUEUE: case MPD_API_SAVE_QUEUE:
je = json_scanf(msg.p, msg.len, "{ data: { plist:%Q } }", &p_charbuf1); je = json_scanf(msg.p, msg.len, "{ data: { plist:%Q } }", &p_charbuf1);
if (je == 1) if (je == 1) {
mpd_run_save(mpd.conn, p_charbuf1); mpd_run_save(mpd.conn, p_charbuf1);
free(p_charbuf1); free(p_charbuf1);
}
break; break;
case MPD_API_SEARCH_QUEUE: case MPD_API_SEARCH_QUEUE:
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, mpdtag:%Q, searchstr:%Q } }", &uint_buf1, &p_charbuf1, &p_charbuf2);
if (je == 3) if (je == 3) {
n = mympd_search_queue(mpd.buf, p_charbuf1, uint_buf1, p_charbuf2); n = mympd_search_queue(mpd.buf, p_charbuf1, uint_buf1, p_charbuf2);
free(p_charbuf1); free(p_charbuf1);
free(p_charbuf2); free(p_charbuf2);
}
break; break;
case MPD_API_SEARCH_ADD: case MPD_API_SEARCH_ADD:
je = json_scanf(msg.p, msg.len, "{ data: { mpdtag:%Q, searchstr:%Q } }", &p_charbuf1, &p_charbuf2); je = json_scanf(msg.p, msg.len, "{ data: { filter:%Q, searchstr:%Q } }", &p_charbuf1, &p_charbuf2);
if (je == 2) if (je == 2) {
n = mympd_search_add(mpd.buf, p_charbuf1, p_charbuf2); n = mympd_search_add(mpd.buf, p_charbuf1, p_charbuf2);
free(p_charbuf1); free(p_charbuf1);
free(p_charbuf2); free(p_charbuf2);
}
break; break;
case MPD_API_SEARCH: case MPD_API_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, mpdtag:%Q, searchstr:%Q } }", &uint_buf1, &p_charbuf1, &p_charbuf2);
if (je == 3) if (je == 3) {
n = mympd_search(mpd.buf, p_charbuf1, uint_buf1, p_charbuf2); n = mympd_search(mpd.buf, p_charbuf1, uint_buf1, p_charbuf2);
free(p_charbuf1); free(p_charbuf1);
free(p_charbuf2); free(p_charbuf2);
}
break; break;
case MPD_API_SEND_SHUFFLE: case MPD_API_SEND_SHUFFLE:
mpd_run_shuffle(mpd.conn); mpd_run_shuffle(mpd.conn);
break; break;
case MPD_API_SEND_MESSAGE: case MPD_API_SEND_MESSAGE:
je = json_scanf(msg.p, msg.len, "{ data: { channel:%Q, text:%Q } }", &p_charbuf1, &p_charbuf2); je = json_scanf(msg.p, msg.len, "{ data: { channel:%Q, text:%Q } }", &p_charbuf1, &p_charbuf2);
if (je == 2) if (je == 2) {
mpd_run_send_message(mpd.conn, p_charbuf1, p_charbuf2); mpd_run_send_message(mpd.conn, p_charbuf1, p_charbuf2);
free(p_charbuf1); free(p_charbuf1);
free(p_charbuf2); free(p_charbuf2);
}
break; break;
case MPD_API_RM_PLAYLIST: case MPD_API_RM_PLAYLIST:
je = json_scanf(msg.p, msg.len, "{ data: { plist:%Q } }", &p_charbuf1); je = json_scanf(msg.p, msg.len, "{ data: { plist:%Q } }", &p_charbuf1);
if (je == 1) if (je == 1) {
mpd_run_rm(mpd.conn, p_charbuf1); mpd_run_rm(mpd.conn, p_charbuf1);
free(p_charbuf1); free(p_charbuf1);
}
break; break;
case MPD_API_GET_SETTINGS: case MPD_API_GET_SETTINGS:
n = mympd_put_settings(mpd.buf); n = mympd_put_settings(mpd.buf);
@ -564,13 +606,13 @@ int mympd_put_state(char *buffer, int *current_song_id, int *next_song_id, unsi
mpd_status_get_queue_version(status) mpd_status_get_queue_version(status)
); );
len += json_printf(&out, ",outputs: {"); len += json_printf(&out, ",outputs: [");
mpd_send_outputs(mpd.conn); mpd_send_outputs(mpd.conn);
nr=0; nr=0;
while ((output = mpd_recv_output(mpd.conn)) != NULL) { while ((output = mpd_recv_output(mpd.conn)) != NULL) {
if (nr++) len += json_printf(&out, ","); if (nr++) len += json_printf(&out, ",");
len += json_printf(&out, "\"%d\":%d", len += json_printf(&out, "{id: %d, state: %d}",
mpd_output_get_id(output), mpd_output_get_id(output),
mpd_output_get_enabled(output) mpd_output_get_enabled(output)
); );
@ -581,7 +623,7 @@ int mympd_put_state(char *buffer, int *current_song_id, int *next_song_id, unsi
mpd_connection_clear_error(mpd.conn); mpd_connection_clear_error(mpd.conn);
} }
len += json_printf(&out, "}}}"); len += json_printf(&out, "]}}");
*current_song_id = mpd_status_get_song_id(status); *current_song_id = mpd_status_get_song_id(status);
*next_song_id = mpd_status_get_next_song_id(status); *next_song_id = mpd_status_get_next_song_id(status);
@ -673,13 +715,13 @@ int mympd_put_outputnames(char *buffer)
int nr; int nr;
struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE);
len = json_printf(&out,"{type: outputnames, data:{"); len = json_printf(&out,"{type: outputnames, data: { outputs: [");
mpd_send_outputs(mpd.conn); mpd_send_outputs(mpd.conn);
nr=0; nr=0;
while ((output = mpd_recv_output(mpd.conn)) != NULL) { while ((output = mpd_recv_output(mpd.conn)) != NULL) {
if (nr++) len += json_printf(&out, ","); if (nr++) len += json_printf(&out, ",");
len += json_printf(&out,"\"%d\":%Q", len += json_printf(&out,"{id: %d, name: %Q}",
mpd_output_get_id(output), mpd_output_get_id(output),
mpd_output_get_name(output) mpd_output_get_name(output)
); );
@ -690,7 +732,7 @@ int mympd_put_outputnames(char *buffer)
mpd_connection_clear_error(mpd.conn); mpd_connection_clear_error(mpd.conn);
} }
len += json_printf(&out,"}}"); len += json_printf(&out,"]}}");
if (len > MAX_SIZE) fprintf(stderr,"Buffer truncated\n"); if (len > MAX_SIZE) fprintf(stderr,"Buffer truncated\n");
return len; return len;
@ -828,11 +870,12 @@ int mympd_put_browse(char *buffer, char *path, unsigned int offset, char *filter
( strncmp(filter,"0",1) == 0 && isalpha(*entityName) == 0 ) ( strncmp(filter,"0",1) == 0 && isalpha(*entityName) == 0 )
) { ) {
if (entities_returned ++) len += json_printf(&out,","); if (entities_returned ++) len += json_printf(&out,",");
len += json_printf(&out, "{type:song, uri: %Q, album: %Q, artist: %Q, duration: %d, title: %Q }", len += json_printf(&out, "{type: song, uri: %Q, album: %Q, artist: %Q, duration: %d, title: %Q, name: %Q }",
mpd_song_get_uri(song), mpd_song_get_uri(song),
mympd_get_album(song), mympd_get_album(song),
mympd_get_artist(song), mympd_get_artist(song),
mpd_song_get_duration(song), mpd_song_get_duration(song),
entityName,
entityName entityName
); );
} else { } else {
@ -853,8 +896,9 @@ int mympd_put_browse(char *buffer, char *path, unsigned int offset, char *filter
( strncmp(filter,"0",1) == 0 && isalpha(*dirName) == 0 ) ( strncmp(filter,"0",1) == 0 && isalpha(*dirName) == 0 )
) { ) {
if (entities_returned ++) len += json_printf(&out,","); if (entities_returned ++) len += json_printf(&out,",");
len += json_printf(&out, "{type: directory, dir: %Q }", len += json_printf(&out, "{type: dir, uri: %Q, name: %Q }",
entityName entityName,
dirName
); );
} else { } else {
entity_count --; entity_count --;
@ -874,8 +918,9 @@ int mympd_put_browse(char *buffer, char *path, unsigned int offset, char *filter
( strncmp(filter,"0",1) == 0 && isalpha(*plName) == 0 ) ( strncmp(filter,"0",1) == 0 && isalpha(*plName) == 0 )
) { ) {
if (entities_returned ++) len += json_printf(&out,","); if (entities_returned ++) len += json_printf(&out,",");
len += json_printf(&out, "{ type: playlist, plist: %Q }", len += json_printf(&out, "{ type: plist, uri: %Q, name: %Q }",
entityName entityName,
plName
); );
} else { } else {
entity_count --; entity_count --;
@ -1030,7 +1075,8 @@ int mympd_put_playlists(char *buffer, unsigned int offset, char *filter)
( strncmp(filter,"0",1) == 0 && isalpha(*plpath) == 0 ) ( strncmp(filter,"0",1) == 0 && isalpha(*plpath) == 0 )
) { ) {
if (entities_returned ++) len += json_printf(&out, ", "); if (entities_returned ++) len += json_printf(&out, ", ");
len += json_printf(&out, "{ type: playlist, plist: %Q, last_modified: %d }", len += json_printf(&out, "{ type: plist, uri: %Q, name: %Q, last_modified: %d }",
plpath,
plpath, plpath,
mpd_playlist_get_last_modified(pl) mpd_playlist_get_last_modified(pl)
); );
@ -1084,11 +1130,12 @@ int mympd_search(char *buffer, char *mpdtagtype, unsigned int offset, char *sear
entity_count ++; entity_count ++;
if(entity_count > offset && entity_count <= offset+MAX_ELEMENTS_PER_PAGE) { if(entity_count > offset && entity_count <= offset+MAX_ELEMENTS_PER_PAGE) {
if (entities_returned ++) len += json_printf(&out, ", "); if (entities_returned ++) len += json_printf(&out, ", ");
len += json_printf(&out, "{ type: song, uri: %Q, album: %Q, artist: %Q, duration: %d, title: %Q }", len += json_printf(&out, "{ type: song, uri: %Q, album: %Q, artist: %Q, duration: %d, title: %Q, name: %Q }",
mpd_song_get_uri(song), mpd_song_get_uri(song),
mympd_get_album(song), mympd_get_album(song),
mympd_get_artist(song), mympd_get_artist(song),
mpd_song_get_duration(song), mpd_song_get_duration(song),
mympd_get_title(song),
mympd_get_title(song) mympd_get_title(song)
); );
} }

View File

@ -46,9 +46,12 @@
#define MPD_CMDS(X) \ #define MPD_CMDS(X) \
X(MPD_API_GET_QUEUE) \ X(MPD_API_GET_QUEUE) \
X(MPD_API_GET_FILESYSTEM) \ X(MPD_API_GET_FILESYSTEM) \
X(MPD_API_ADD_TRACK_AFTER) \
X(MPD_API_ADD_TRACK) \ X(MPD_API_ADD_TRACK) \
X(MPD_API_ADD_PLAY_TRACK) \ X(MPD_API_ADD_PLAY_TRACK) \
X(MPD_API_REPLACE_TRACK) \
X(MPD_API_ADD_PLAYLIST) \ X(MPD_API_ADD_PLAYLIST) \
X(MPD_API_REPLACE_PLAYLIST) \
X(MPD_API_PLAY_TRACK) \ X(MPD_API_PLAY_TRACK) \
X(MPD_API_SAVE_QUEUE) \ X(MPD_API_SAVE_QUEUE) \
X(MPD_API_RM_TRACK) \ X(MPD_API_RM_TRACK) \