mirror of
				https://github.com/SuperBFG7/ympd
				synced 2025-10-31 13:53:00 +00:00 
			
		
		
		
	| @@ -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}/) | ||||
|   | ||||
| @@ -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 | ||||
| ------- | ||||
|   | ||||
							
								
								
									
										41
									
								
								htdocs/css/bootstrap-slider.min.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										41
									
								
								htdocs/css/bootstrap-slider.min.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -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; | ||||
| } | ||||
							
								
								
									
										2
									
								
								htdocs/css/mpd.min.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								htdocs/css/mpd.min.css
									
									
									
									
										vendored
									
									
								
							| @@ -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} | ||||
| @@ -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="−" onclick="chVolume(-5)"/> | ||||
|                   <button data-href="{'cmd':'chVolume','options':[-5]}" class="btn btn-secondary">−</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">  </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">«</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="QueuePaginationTopPrev" title="Previous Page" type="button" class="btn btn-secondary">«</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">»</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="QueuePaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">»</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">«</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="QueuePaginationBottomPrev" title="Previous Page" type="button" class="btn btn-secondary">«</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">»</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="QueuePaginationBottomNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">»</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">«</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="BrowsePlaylistsPaginationTopPrev" title="Previous Page" type="button" class="btn btn-secondary">«</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">»</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="BrowsePlaylistsPaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">»</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">«</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="BrowsePlaylistsPaginationBottomPrev" title="Previous Page" type="button" class="btn btn-secondary">«</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">»</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="BrowsePlaylistsPaginationBottomNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">»</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">« Artists</button> | ||||
|             <button data-href="{'cmd': 'appGoto', 'options': ['Browse','Database','Artist']}" id="btnBrowseDatabaseArtist" type="button" class="btn btn-secondary hide">« 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">«</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="BrowseDatabasePaginationTopPrev" title="Previous Page" type="button" class="btn btn-secondary">«</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">»</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="BrowseDatabasePaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">»</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">«</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="BrowseDatabasePaginationBottomPrev" title="Previous Page" type="button" class="btn btn-secondary">«</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">»</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="BrowseDatabasePaginationBottomNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">»</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">«</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="BrowseFilesystemPaginationTopPrev" title="Previous Page" type="button" class="btn btn-secondary">«</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">»</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="BrowseFilesystemPaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">»</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">«</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="BrowseFilesystemPaginationBottomPrev" title="Previous Page" type="button" class="btn btn-secondary">«</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">»</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="BrowseFilesystemPaginationBottomNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">»</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">«</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="SearchPaginationTopPrev" title="Previous Page" type="button" class="btn btn-secondary">«</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">»</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="SearchPaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">»</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">«</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['prev']}" id="SearchPaginationBottomPrev" title="Previous Page" type="button" class="btn btn-secondary">«</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">»</button> | ||||
|             <button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="SearchPaginationBottomNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">»</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
									
								
							
							
						
						
									
										2
									
								
								htdocs/js/bootstrap-native-v4.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								htdocs/js/bootstrap-notify.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								htdocs/js/bootstrap-notify.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										5
									
								
								htdocs/js/bootstrap-slider.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								htdocs/js/bootstrap-slider.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										6
									
								
								htdocs/js/bootstrap.bundle.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								htdocs/js/bootstrap.bundle.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								htdocs/js/jquery-3.3.1.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								htdocs/js/jquery-3.3.1.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										4
									
								
								htdocs/js/modernizr-custom.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								htdocs/js/modernizr-custom.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2127
									
								
								htdocs/js/mpd.js
									
									
									
									
									
								
							
							
						
						
									
										2127
									
								
								htdocs/js/mpd.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										165
									
								
								htdocs/js/mpd.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										165
									
								
								htdocs/js/mpd.min.js
									
									
									
									
										vendored
									
									
								
							| @@ -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(); | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
							
								
								
									
										2
									
								
								htdocs/js/player.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								htdocs/js/player.min.js
									
									
									
									
										vendored
									
									
								
							| @@ -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(); | ||||
|   | ||||
							
								
								
									
										153
									
								
								src/mpd_client.c
									
									
									
									
									
								
							
							
						
						
									
										153
									
								
								src/mpd_client.c
									
									
									
									
									
								
							| @@ -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) | ||||
|                 ); | ||||
|             } | ||||
|   | ||||
| @@ -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) \ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jürgen Mang
					Jürgen Mang