1
0
mirror of https://github.com/SuperBFG7/ympd synced 2024-09-29 14:40:41 +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)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
set(CPACK_PACKAGE_VERSION_MAJOR "3")
set(CPACK_PACKAGE_VERSION_MINOR "0")
set(CPACK_PACKAGE_VERSION_PATCH "2")
set(CPACK_PACKAGE_VERSION_MINOR "1")
set(CPACK_PACKAGE_VERSION_PATCH "0")
if(CMAKE_BUILD_TYPE MATCHES RELEASE)
set(ASSETS_PATH "${CMAKE_INSTALL_PREFIX}/share/${PROJECT_NAME}/htdocs")
@ -12,6 +12,7 @@ if(CMAKE_BUILD_TYPE MATCHES RELEASE)
else()
set(ASSETS_PATH "${PROJECT_SOURCE_DIR}/htdocs")
set(DEBUG "ON")
set(CS_NDEBUG "ON")
endif()
find_package(LibMPDClient REQUIRED)
@ -22,13 +23,9 @@ include_directories(${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR} ${LIBMPDCLIENT_I
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")
if(WITH_IPV6)
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS)
endif()
set(SOURCES
src/mympd.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 htdocs/index.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/bootstrap.bundle.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/bootstrap-native-v4.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-slider.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 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
-------------
- 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
- jQuery: https://jquery.com/
- Bootstrap Native: http://thednp.github.io/bootstrap.native/
Backend
-------

File diff suppressed because one or more lines are too long

View File

@ -17,10 +17,6 @@ body {
background-color:#888;
}
#volumeslider {
width: 104px;
}
button {
overflow: hidden;
}
@ -36,7 +32,6 @@ button {
#counter {
font-size: 22px;
margin-top: -2px;
margin-left: 10px;
min-width: 50px;
}
@ -127,6 +122,10 @@ tbody {
font-feature-settings: 'liga';
}
.material-icons-small {
font-size: 16px;
}
main {
padding-top:20px;
}
@ -150,30 +149,16 @@ main {
overflow-x:hidden;
}
.slider-selection {
background:#28a745 !important;
}
#progressbar .slider-track {
height: 20px !important;
}
#progressbar {
#progressBar {
width:100%;
margin-top:8px;
}
#volumebar {
#volumeBar {
margin-top:2px;
width:160px;
}
.slider-handle {
visibility:hidden !important;
}
[data-notify="title"] {
font-size:120%;
}
.header-logo {
font-size:2rem;
float:left;
@ -184,7 +169,7 @@ main {
#BrowseDatabaseFilterLetters > button,
#BrowsePlaylistsFilterLetters > button
{
min-width:28px;
width:28px;
}
.col-md {
@ -196,11 +181,33 @@ main {
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 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="author" content="mail@jcgames.de">
<title>myMPD</title>
<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="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-status-bar-style" content="black"/>
<link rel="apple-touch-icon" href="assets/appicon.png"/>
@ -26,51 +22,51 @@
</a>
<div class="dropdown-menu bg-dark">
<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>
<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-updatedb" class="dropdown-item text-light bg-dark" href="#" onclick="updateDB(event);">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-settings" class="dropdown-item text-light bg-dark" href="#" data-toggle="modal" data-target="#settings">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-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="#" data-href="{'cmd':'updateDB','options':[]}">Update Database</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="#modalSettings">Settings</a>
<a id="nav-about" class="dropdown-item text-light bg-dark" href="#" data-toggle="modal" data-target="#modalAbout">About</a>
</div>
</div>
<div class="btn-toolbar col-auto pl-0 pr-0" role="toolbar">
<div class="btn-group mr-2" role="group">
<button id="btnPrev" type="button" class="btn btn-secondary pl-2 pr-2" onclick="clickPrev();;">
<span class="material-icons">skip_previous</span>
<div class="btn-group mr-2" role="group" id="playControlBtns">
<button data-href="{'cmd':'clickPrev','options':[]}" id="btnPrev" type="button" class="btn btn-secondary pl-2 pr-2 material-icons">
skip_previous
</button>
<button id="btnStop" type="button" class="btn btn-secondary pl-2 pr-2" onclick="clickStop();">
<span class="material-icons">stop</span>
<button data-href="{'cmd':'clickStop','options':[]}" id="btnStop" type="button" class="btn btn-secondary pl-2 pr-2 material-icons">
stop
</button>
<button id="btnPlay" type="button" class="btn btn-secondary pl-2 pr-2" onclick="clickPlay();">
<span class="material-icons">pause</span>
<button data-href="{'cmd':'clickPlay','options':[]}" id="btnPlay" type="button" class="btn btn-secondary pl-2 pr-2 material-icons">
pause
</button>
<button id="btnNext" type="button" class="btn btn-secondary pl-2 pr-2" onclick="clickNext();">
<span class="material-icons">skip_next</span>
<button data-href="{'cmd':'clickNext','options':[]}" id="btnNext" type="button" class="btn btn-secondary pl-2 pr-2 material-icons">
skip_next
</button>
</div>
<div class="btn-group" role="group">
<button class="btn btn-secondary dropdown-toggle pl-2 pr-2" type="button" data-toggle="dropdown">
<span id="volume-icon" class="material-icons">volume_up</span>
<button id="volumeIcon" class="btn btn-secondary dropdown-toggle pl-2 pr-2 material-icons" type="button" data-toggle="dropdown">
volume_up
</button>
<div class="dropdown-menu dropdown-menu-right bg-dark">
<h2 class="dropdown-header text-light">Volume: <span id="volumePrct"></span></h2>
<form class="px-4 py-0 pb-3" id="volumeControl">
<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">
<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>
<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>
</form>
<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>
</nav>
</header>
<main class="container">
@ -86,7 +82,7 @@
<h4 id="album"></h4>
<div class="row">
<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 class="col-4">
<p id="counter" class="text">&nbsp;&nbsp;</p>
@ -95,40 +91,21 @@
</div>
</div>
<div class="card hide" id="cardQueue">
<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>
</div>
<div class="card-body">
<div class="btn-toolbar collapse show 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 class="btn-toolbar card-toolbar" id="queue-buttons" role="toolbar">
<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>
</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>
</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>
</button>
</div>
@ -151,13 +128,13 @@
</div>
</form>
<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">
<button id="QueuePaginationTopPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="QueuePaginationTopPages">
<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 pages" id="QueuePaginationTopPages">
</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>
@ -183,20 +160,20 @@
</tbody>
</table>
</div>
<div class="btn-toolbar" id="queueButtonsBottom" role="toolbar">
<div class="btn-toolbar" id="QueueButtonsBottom" role="toolbar">
<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>
</button>
</div>
<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">
<button id="QueuePaginationBottomPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="QueuePaginationBottomPages">
<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 pages" id="QueuePaginationBottomPages">
</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>
@ -206,32 +183,32 @@
<div class="card-header" id="panel-heading-browse">
<ul class="nav nav-tabs card-header-tabs">
<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 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 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>
</ul>
</div>
<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">
<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>
</div>
<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">
<button id="BrowsePlaylistsPaginationTopPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="BrowsePlaylistsPaginationTopPages">
<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 pages" id="BrowsePlaylistsPaginationTopPages">
</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>
@ -255,27 +232,27 @@
</div>
<div class="btn-toolbar" id="BrowsePlaylistsButtonsBottom" role="toolbar">
<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>
</button>
</div>
<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">
<button id="BrowsePlaylistsPaginationBottomPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="BrowsePlaylistsPaginationBottomPages">
<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 pages" id="BrowsePlaylistsPaginationBottomPages">
</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 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">
<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 class="btn-group mr-2">
<button id="BrowseDatabaseFilter" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Filter</button>
@ -283,13 +260,13 @@
</div>
</div>
<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">
<button id="BrowseDatabasePaginationTopPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="BrowseDatabasePaginationTopPages">
<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 pages" id="BrowseDatabasePaginationTopPages">
</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>
@ -314,27 +291,27 @@
<div class="btn-toolbar" id="BrowseDatabaseButtonsBottom" role="toolbar">
<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>
</button>
</div>
<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">
<button id="BrowseDatabasePaginationBottomPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="BrowseDatabasePaginationBottomPages">
<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 pages" id="BrowseDatabasePaginationBottomPages">
</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 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">
<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 class="btn-group mr-2">
<button id="BrowseFilesystemFilter" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Filter</button>
@ -342,13 +319,13 @@
</div>
</div>
<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">
<button id="BrowseFilesystemPaginationTopPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="BrowseFilesystemPaginationTopPages">
<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 pages" id="BrowseFilesystemPaginationTopPages">
</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>
@ -379,18 +356,18 @@
</div>
<div class="btn-toolbar" id="BrowseFilesystemButtonsBottom" role="toolbar">
<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>
</button>
</div>
<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">
<button id="BrowseFilesystemPaginationBottomPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="BrowseFilesystemPaginationBottomPages">
<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 pages" id="BrowseFilesystemPaginationBottomPages">
</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>
@ -401,7 +378,7 @@
<span id="panel-heading-search" class="text pull-right"></span>
</div>
<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">
<div class="input-group mr-2">
<input type="text" class="form-control" placeholder="Search" id="searchstr2"/>
@ -421,16 +398,16 @@
</div>
</form>
<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 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">
<button id="SearchPaginationTopPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="SearchPaginationTopPages">
<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 pages" id="SearchPaginationTopPages">
</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 class="table-responsive-md">
@ -457,18 +434,18 @@
</div>
<div class="btn-toolbar" id="SearchButtonsBottom" role="toolbar">
<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>
</button>
</div>
<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">
<button id="SearchPaginationBottomPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Page 1 / 1</button>
<div class="dropdown-menu bg-dark px-2" id="SearchPaginationBottomPages">
<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 pages" id="SearchPaginationBottomPages">
</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>
@ -478,13 +455,14 @@
<footer class="footer">
<nav class="navbar navbar-expand navbar-dark fixed-bottom bg-dark">
<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 class="nav-item flex-fill text-center" id="navQueue"><a 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="navSearch"><a class="nav-link" href="#">Search</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 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 data-href="{'cmd': 'appGoto', 'options': ['Browse']}" class="nav-link" href="#">Browse</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>
</nav>
</footer>
<!-- Modal -->
<div class="modal" id="modalConnectionError" role="dialog">
<div class="modal-dialog" role="document">
@ -500,7 +478,7 @@
</div>
<!-- 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-content">
<div class="modal-header">
@ -512,25 +490,25 @@
<div class="modal-body">
<form class="needs-validation" id="settingsFrm" novalidate>
<div class="row">
<div class="form-group col-md-6" data-toggle="buttons">
<button id="btnrandom" type="button" class="btn btn-secondary btn-block" title="Random">
<div class="form-group col-md-6">
<button data-href="{'cmd':'toggleBtn','options':['btnRandom']}" id="btnRandom" type="button" class="btn btn-secondary btn-block" title="Random">
Random
</button>
</div>
<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
</button>
</div>
</div>
<div class="row">
<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
</button>
</div>
<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
</button>
</div>
@ -573,12 +551,12 @@
<hr/>
<div class="row">
<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
</button>
</div>
<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
</button>
</div>
@ -587,14 +565,14 @@
</div>
<div class="modal-footer">
<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><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.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-content">
<div class="modal-header">
@ -637,7 +615,7 @@
</div><!-- /.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-content">
<div class="modal-header">
@ -647,7 +625,7 @@
</button>
</div>
<div class="modal-body">
<form>
<form id="addstreamFrm">
<div class="row">
<div class="form-group col-md-12">
<label class="control-label" for="streamurl">Stream URL</label>
@ -658,13 +636,13 @@
</div>
<div class="modal-footer">
<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><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</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-content">
<div class="modal-header">
@ -685,15 +663,12 @@
</div>
<div class="modal-footer">
<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><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<script src="js/jquery-3.3.1.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/bootstrap-native-v4.min.js"></script>
<script src="js/mpd.js"></script>
</body>
</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_";
$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.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.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.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");
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},
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"+
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:
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):
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!=
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"==
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>');
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">'+
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()==
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")}};
$(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,
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")});
$("#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)});
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);
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)}}
$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.checkStringArgs=function(a,b,c){if(null==a)throw new TypeError("The 'this' value for String.prototype."+c+" must not be null or undefined");if(b instanceof RegExp)throw new TypeError("First argument to String.prototype."+c+" must not be a regular expression");return a+""};
$jscomp.polyfill=function(a,b,c,e){if(b){c=$jscomp.global;a=a.split(".");for(e=0;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})}};
$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");
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");
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");
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");
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"));
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");
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+
"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}
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.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);
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");
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");
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("/"),
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"==
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 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 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",
"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");
$("#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",
"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)}
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=""}
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>
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="+
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}}
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)}
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+
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>');
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)+
")"));$("#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=
$(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")}})}}
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 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+
(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="'+
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+
(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($("#"+
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()}});
$("#"+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"))}});
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);
app.goto("Browse","Filesystem",void 0,app.current.page+"/"+app.current.filter+"/"+app.current.search)}});doSetFilterLetter("#BrowseFilesystemFilter")}}
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")!=
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>');
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()}});$("#"+
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")}}
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=
'<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==
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),
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",
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")}}
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",
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 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");
$("#"+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",
"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"),
$("#"+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 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 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");
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 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"})}
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 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()}
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()});
$("#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 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()&&
$("#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(),
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,"")};
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*
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"))}
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"),
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");
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=
"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 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}
function parseState(a){if(JSON.stringify(a)!==JSON.stringify(last_state)){1==a.data.state?(domCache.btnPlay.innerText="play_arrow",playstate="stop"):2==a.data.state?(domCache.btnPlay.innerText="pause",playstate="play"):(domCache.btnPlay.innerText="play_arrow",playstate="pause");-1==a.data.nextsongpos?domCache.btnNext.setAttribute("disabled","disabled"):domCache.btnNext.removeAttribute("disabled");0>=a.data.songpos?domCache.btnPrev.setAttribute("disabled","disabled"):domCache.btnPrev.removeAttribute("disabled");
0==a.data.queue_length?domCache.btnPlay.setAttribute("disabled","disabled"):domCache.btnPlay.removeAttribute("disabled");-1==a.data.volume?(domCache.volumePrct.innerText("Volumecontrol disabled"),domCache.volumeControl.classList.add("hide")):(domCache.volumeControl.classList.remove("hide"),domCache.volumePrct.innerText=a.data.volume+" %",domCache.volumeIcon.innerText=0==a.data.volume?"volume_off":50>a.data.volume?"volume_down":"volume_up");domCache.volumeBar.value=a.data.volume;current_song.totalTime=
a.data.totalTime;current_song.currentSongId=a.data.currentsongid;var b=Math.floor(a.data.totalTime/60),c=a.data.totalTime-60*b,e=Math.floor(a.data.elapsedTime/60),d=a.data.elapsedTime-60*e;domCache.progressBar.value=Math.floor(100*a.data.elapsedTime/a.data.totalTime);b=e+":"+(10>d?"0":"")+d+" / "+b+":"+(10>c?"0":"")+c;domCache.counter.innerText=b;last_state&&(c=document.getElementById("queueTrackId"+last_state.data.currentsongid))&&(e=c.getElementsByTagName("td"),e[4].innerText=c.getAttribute("data-duration"),
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<
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)}
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]||
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>';
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&&(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){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",
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>';
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>')}}
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);
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>')}}
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],
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"==
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",
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();
setPagination(a.totalEntities)}}
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+
'" 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 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">'+
(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+
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")}}
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"!=
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 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")}
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 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"),
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,
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")}
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 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 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()}
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"),
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 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&&
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 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}}}
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,
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"}
function genId(a){return"id"+a.replace(/[^\w]/g,"")}appInit();

View File

@ -1,5 +1,5 @@
var mpdstream = decodeURI(location.hash).replace(/^#/,'');
player.src = mpdstream;
var player = document.getElementById('player');
player.src = decodeURI(location.hash).replace(/^#/,'');
console.log('playing mpd stream: ' + player.src);
player.load();
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;
char *p_charbuf1, *p_charbuf2;
struct mympd_state { int a; int b; } state = { .a = 0, .b = 0 };
enum mpd_cmd_ids cmd_id;
#ifdef DEBUG
fprintf(stdout,"Got request: %s\n",msg.p);
#endif
json_scanf(msg.p, msg.len, "{cmd:%Q}", &cmd);
enum mpd_cmd_ids cmd_id = get_cmd_id(cmd);
je = json_scanf(msg.p, msg.len, "{cmd:%Q}", &cmd);
if (je == 1)
cmd_id = get_cmd_id(cmd);
else
return;
if(cmd_id == -1)
return;
@ -115,17 +119,18 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg)
struct mpd_pair *pair;
while ((pair = mpd_recv_pair(mpd.conn)) != NULL) {
mpd_return_pair(mpd.conn, pair);
}
}
free(p_charbuf1);
}
free(p_charbuf1);
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\":\"result\", \"data\": \"ok\"}");
break;
case MPD_API_GET_ARTISTALBUMTITLES:
je = json_scanf(msg.p, msg.len, "{ data: { albumartist:%Q, album:%Q } }", &p_charbuf1, &p_charbuf2);
if (je == 2)
n = mympd_put_songs_in_album(mpd.buf, p_charbuf1, p_charbuf2);
free(p_charbuf1);
free(p_charbuf2);
if (je == 2) {
n = mympd_put_songs_in_album(mpd.buf, p_charbuf1, p_charbuf2);
free(p_charbuf1);
free(p_charbuf2);
}
break;
case MPD_API_WELCOME:
n = mympd_put_welcome(mpd.buf);
@ -208,35 +213,56 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg)
break;
case MPD_API_GET_ARTISTS:
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);
free(p_charbuf1);
free(p_charbuf1);
}
break;
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);
if (je == 3)
if (je == 3) {
n = mympd_put_db_tag(mpd.buf, uint_buf1, "Album", "AlbumArtist", p_charbuf2, p_charbuf1);
free(p_charbuf1);
free(p_charbuf2);
free(p_charbuf1);
free(p_charbuf2);
}
break;
case MPD_API_GET_PLAYLISTS:
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);
free(p_charbuf1);
free(p_charbuf1);
}
break;
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);
if (je == 3)
if (je == 3) {
n = mympd_put_browse(mpd.buf, p_charbuf2, uint_buf1, p_charbuf1);
free(p_charbuf1);
free(p_charbuf2);
free(p_charbuf1);
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;
case MPD_API_ADD_TRACK:
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);
free(p_charbuf1);
free(p_charbuf1);
}
break;
case MPD_API_ADD_PLAY_TRACK:
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);
if(int_buf != -1)
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;
case MPD_API_ADD_PLAYLIST:
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);
free(p_charbuf1);
free(p_charbuf1);
}
break;
case MPD_API_SAVE_QUEUE:
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);
free(p_charbuf1);
free(p_charbuf1);
}
break;
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);
if (je == 3)
if (je == 3) {
n = mympd_search_queue(mpd.buf, p_charbuf1, uint_buf1, p_charbuf2);
free(p_charbuf1);
free(p_charbuf2);
free(p_charbuf1);
free(p_charbuf2);
}
break;
case MPD_API_SEARCH_ADD:
je = json_scanf(msg.p, msg.len, "{ data: { mpdtag:%Q, searchstr:%Q } }", &p_charbuf1, &p_charbuf2);
if (je == 2)
je = json_scanf(msg.p, msg.len, "{ data: { filter:%Q, searchstr:%Q } }", &p_charbuf1, &p_charbuf2);
if (je == 2) {
n = mympd_search_add(mpd.buf, p_charbuf1, p_charbuf2);
free(p_charbuf1);
free(p_charbuf2);
free(p_charbuf1);
free(p_charbuf2);
}
break;
case MPD_API_SEARCH:
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);
free(p_charbuf1);
free(p_charbuf2);
free(p_charbuf1);
free(p_charbuf2);
}
break;
case MPD_API_SEND_SHUFFLE:
mpd_run_shuffle(mpd.conn);
break;
case MPD_API_SEND_MESSAGE:
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);
free(p_charbuf1);
free(p_charbuf2);
free(p_charbuf1);
free(p_charbuf2);
}
break;
case MPD_API_RM_PLAYLIST:
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);
free(p_charbuf1);
free(p_charbuf1);
}
break;
case MPD_API_GET_SETTINGS:
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)
);
len += json_printf(&out, ",outputs: {");
len += json_printf(&out, ",outputs: [");
mpd_send_outputs(mpd.conn);
nr=0;
while ((output = mpd_recv_output(mpd.conn)) != NULL) {
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_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);
}
len += json_printf(&out, "}}}");
len += json_printf(&out, "]}}");
*current_song_id = mpd_status_get_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;
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);
nr=0;
while ((output = mpd_recv_output(mpd.conn)) != NULL) {
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_name(output)
);
@ -690,7 +732,7 @@ int mympd_put_outputnames(char *buffer)
mpd_connection_clear_error(mpd.conn);
}
len += json_printf(&out,"}}");
len += json_printf(&out,"]}}");
if (len > MAX_SIZE) fprintf(stderr,"Buffer truncated\n");
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 )
) {
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),
mympd_get_album(song),
mympd_get_artist(song),
mpd_song_get_duration(song),
entityName,
entityName
);
} 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 )
) {
if (entities_returned ++) len += json_printf(&out,",");
len += json_printf(&out, "{type: directory, dir: %Q }",
entityName
len += json_printf(&out, "{type: dir, uri: %Q, name: %Q }",
entityName,
dirName
);
} else {
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 )
) {
if (entities_returned ++) len += json_printf(&out,",");
len += json_printf(&out, "{ type: playlist, plist: %Q }",
entityName
len += json_printf(&out, "{ type: plist, uri: %Q, name: %Q }",
entityName,
plName
);
} else {
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 )
) {
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,
mpd_playlist_get_last_modified(pl)
);
@ -1084,11 +1130,12 @@ int mympd_search(char *buffer, char *mpdtagtype, unsigned int offset, char *sear
entity_count ++;
if(entity_count > offset && entity_count <= offset+MAX_ELEMENTS_PER_PAGE) {
if (entities_returned ++) len += json_printf(&out, ", ");
len += json_printf(&out, "{ type: song, 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),
mympd_get_album(song),
mympd_get_artist(song),
mpd_song_get_duration(song),
mympd_get_title(song),
mympd_get_title(song)
);
}

View File

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