mirror of
https://github.com/SuperBFG7/ympd
synced 2025-01-29 10:24:53 +00:00
Merge pull request #39 from jcorporation/devel
Merge devel v4.0.0 into master
This commit is contained in:
commit
4b5181181e
@ -2,8 +2,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 "5")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR "4")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "0")
|
||||
set(CPACK_PACKAGE_VERSION_PATCH "0")
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES RELEASE)
|
||||
@ -48,9 +48,8 @@ install(FILES dist/htdocs/player.html DESTINATION share/${PROJECT_NAME}/htdocs/)
|
||||
install(FILES dist/htdocs/sw.min.js DESTINATION share/${PROJECT_NAME}/htdocs/)
|
||||
install(FILES dist/htdocs/js/player.min.js DESTINATION share/${PROJECT_NAME}/htdocs/js/)
|
||||
install(FILES dist/htdocs/js/bootstrap-native-v4.min.js DESTINATION share/${PROJECT_NAME}/htdocs/js/)
|
||||
install(FILES dist/htdocs/js/mpd.min.js DESTINATION share/${PROJECT_NAME}/htdocs/js/)
|
||||
install(FILES dist/htdocs/js/mympd.min.js DESTINATION share/${PROJECT_NAME}/htdocs/js/)
|
||||
install(FILES dist/htdocs/css/bootstrap.min.css DESTINATION share/${PROJECT_NAME}/htdocs/css/)
|
||||
install(FILES dist/htdocs/css/mpd.min.css DESTINATION share/${PROJECT_NAME}/htdocs/css/)
|
||||
install(FILES dist/htdocs/css/mympd.min.css DESTINATION share/${PROJECT_NAME}/htdocs/css/)
|
||||
install(DIRECTORY htdocs/assets DESTINATION share/${PROJECT_NAME}/htdocs)
|
||||
install(DIRECTORY DESTINATION /var/lib/${PROJECT_NAME}/)
|
||||
install(FILES contrib/mympd.conf DESTINATION /etc/${PROJECT_NAME}/)
|
||||
|
@ -25,6 +25,8 @@ This fork provides a reworked ui based on Bootstrap 4, a modernized backend and
|
||||
- Local coverart support
|
||||
- HTTP stream support
|
||||
- Local playback of mpd http stream (html5 audio api)
|
||||
- Play statistics and song voting (uses mpd stickers)
|
||||
- Embedded Webserver (mongoose)
|
||||
|
||||
myMPD is work in progress. Bugreportes and feature requests are very welcome.
|
||||
- Issues and feature requests: https://github.com/jcorporation/myMPD/issues
|
||||
@ -61,7 +63,7 @@ Build Dependencies
|
||||
Unix Build Instructions
|
||||
-----------------------
|
||||
|
||||
1. Install dependencies: cmake, libmpdclient (dev) and OpenSSL (dev), java are available from all major distributions.
|
||||
1. Install dependencies: cmake, libmpdclient (dev), OpenSSL (dev) and java are available from all major distributions.
|
||||
2. Build and install: ```cd /path/to/src; ./mkrelease.sh```.
|
||||
3. Link your mpd music directory to ```/usr/share/mympd/htdocs/library``` and put ```folder.jpg``` files in your album directories (mkrelease.sh tries to do this for you).
|
||||
4. Configure your mpd with http stream output to use the local player.
|
||||
|
@ -1,6 +1,6 @@
|
||||
.\" Manpage for myMPD.
|
||||
.\" Contact mail@jcgames.de to correct errors or typos.
|
||||
.TH man 1 "06 Aug 2018" "3.5.0" "myMPD man page"
|
||||
.TH man 1 "22 Aug 2018" "4.0.0" "myMPD man page"
|
||||
.SH NAME
|
||||
myMPD \- Standalone MPD Web GUI written in C, utilizing Websockets and Bootstrap/JS
|
||||
.SH SYNOPSIS
|
||||
|
@ -25,3 +25,9 @@ coverimage = folder.jpg
|
||||
|
||||
#myMPD statefile
|
||||
statefile = /var/lib/mympd/mympd.state
|
||||
|
||||
#Enable mixramp settings
|
||||
mixramp = false
|
||||
|
||||
#Enable usage of mpd stickers for play statistics and voting
|
||||
stickers = true
|
||||
|
1
dist/htdocs/css/mpd.min.css
vendored
1
dist/htdocs/css/mpd.min.css
vendored
@ -1 +0,0 @@
|
||||
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}.card{min-height:350px}@media only screen and (max-width:576px){.header-logo{display:none!important}}.clickable{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}.title-icon{float:left;margin-right:5px;font-size:1.8rem}.header-logo{font-size:2rem;float:left;margin-right:5px}.letters>button{width:28px;height:28px}.col-md{max-width:250px;min-width:250px}a.card-img-top{overflow:hidden;display:block}button.active{color:#fff;background-color:#28a745!important;border-color:#28a745!important}div#alertBox{position:fixed;top:50px;right:10px;width:80%;max-width:400px;z-index:1000;opacity:0;visibility:visible;transition:opacity .5s ease-in}div.alertBoxActive{opacity:1!important;visibility:visible!important;transition:opacity .5s ease-in}.popover-content{padding-top:4px;padding-bottom:4px}.opacity05{opacity:.5}caption{caption-side:top;font-size:120%;font-weight:bold;color:black}.dragover>td{border-top:25px solid transparent}[draggable]{-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;user-select:none;-khtml-user-drag:element;-webkit-user-drag:element}
|
1
dist/htdocs/css/mympd.min.css
vendored
Normal file
1
dist/htdocs/css/mympd.min.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
html{position:relative;min-height:100%}body{margin-bottom:60px;padding-top:50px;padding-bottom:50px;background-color:#888}main{padding-top:20px}footer{position:absolute;bottom:0}button{overflow:hidden}#BrowseBreadrumb{overflow:auto;white-space:nowrap}#BrowseBreadcrumb>li>a{cursor:pointer}.card{min-height:350px}@media only screen and (max-width:576px){.header-logo{display:none!important}}.clickable{cursor:pointer}.tblnum,.tblaction{width:30px}small{color:#aaa}.card-footer-playback{padding:0}.album-cover{background-size:cover;border:1px solid black;border-radius:5px;overflow:hidden;width:240px;height:240px;background-color:#eee;float:left;margin-right:20px;margin-bottom:20px}.album-desc{min-width:240px;float:left}.hide{display:none!important}.pull-right{float:right!important}.card-toolbar{margin-bottom:10px}.card-toolbar>div,.card-toolbar>form{margin-bottom:5px}@font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(/assets/MaterialIcons-Regular.eot);src:local('Material Icons'),local('MaterialIcons-Regular');src:url(/assets/MaterialIcons-Regular.woff2) format('woff2'),url(/assets/MaterialIcons-Regular.woff) format('woff'),url(/assets/MaterialIcons-Regular.ttf) format('truetype')}.material-icons{font-family:'Material Icons';font-weight:normal;font-style:normal;font-size:18px;display:inline-block;line-height:1;text-transform:none;letter-spacing:normal;word-wrap:normal;white-space:nowrap;direction:ltr;vertical-align:top;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;font-feature-settings:'liga'}.material-icons-small{font-size:16px}.color-darkgrey,.color-darkgrey:hover{color:#6c757d!important}#btn-outputs-block>button{margin-bottom:10px}#btn-outputs-block>button:last-child{margin-bottom:0}.card-body{overflow-x:hidden}.progressBarPlay{font-size:22px}#counter{cursor:text}#volumeBar{margin-top:2px;width:160px}.title-icon{float:left;margin-right:5px;font-size:1.8rem}.header-logo{font-size:2rem;float:left;margin-right:5px}.letters>button{width:28px;height:28px}.col-md{max-width:250px;min-width:250px}a.card-img-top{overflow:hidden;display:block}button.active{color:#fff;background-color:#28a745!important;border-color:#28a745!important}button.active-fg-green{color:#28a745!important}button.active-fg-red{color:#bd2130!important}div#alertBox{position:fixed;top:50px;right:10px;width:80%;max-width:400px;z-index:1000;opacity:0;visibility:visible;transition:opacity .5s ease-in}div.alertBoxActive{opacity:1!important;visibility:visible!important;transition:opacity .5s ease-in}.popover-content{padding-top:4px;padding-bottom:4px}.opacity05{opacity:.5}caption{caption-side:top;font-size:120%;font-weight:bold;color:black}.dragover>td{border-top:25px solid transparent}[draggable]{-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;user-select:none;-khtml-user-drag:element;-webkit-user-drag:element}@keyframes changewidth{0%{width:0%}to{width:100%}}.updateDBprogressAnimate{animation-duration:2s;animation-name:changewidth;animation-iteration-count:infinite}
|
2
dist/htdocs/index.html
vendored
2
dist/htdocs/index.html
vendored
File diff suppressed because one or more lines are too long
@ -5,11 +5,11 @@ $jscomp.iteratorPrototype=function(a){$jscomp.initSymbolIterator();a={next:a};a[
|
||||
$jscomp.checkStringArgs=function(a,b,c){if(null==a)throw new TypeError("The 'this' value for String.prototype."+c+" must not be null or undefined");if(b instanceof RegExp)throw new TypeError("First argument to String.prototype."+c+" must not be a regular expression");return a+""};
|
||||
$jscomp.polyfill=function(a,b,c,e){if(b){c=$jscomp.global;a=a.split(".");for(e=0;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={},alertTimeout,deferredPrompt,dragEl,app={apps:{Playback:{state:"0/-/",scrollPos:0},Queue:{state:"0/Any Tag/",scrollPos:0},Browse:{active:"Database",tabs:{Filesystem:{state:"0/-/",scrollPos:0},Playlists:{active:"All",views:{All:{state:"0/-/",scrollPos:0},Detail:{state:"0/-/",scrollPos:0}}},Database:{active:"Artist",views:{Artist:{state:"0/-/",scrollPos:0},Album:{state:"0/-/",scrollPos:0}}}}},Search:{state:"0/Any Tag/",scrollPos:0}},
|
||||
current:{app:"Playback",tab:void 0,view:void 0,page:0,filter:"",search:"",scrollPos:0},last:{app:void 0,tab:void 0,view:void 0,filter:"",search:"",scrollPos:0}},domCache={};domCache.navbarBottomBtns=document.getElementById("navbar-bottom").getElementsByTagName("div");domCache.navbarBottomBtnsLen=domCache.navbarBottomBtns.length;domCache.panelHeadingBrowse=document.getElementById("panel-heading-browse").getElementsByTagName("a");domCache.panelHeadingBrowseLen=domCache.panelHeadingBrowse.length;
|
||||
domCache.counter=document.getElementById("counter");domCache.volumePrct=document.getElementById("volumePrct");domCache.volumeControl=document.getElementById("volumeControl");domCache.volumeIcon=document.getElementById("volumeIcon");domCache.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");domCache.btnAdd=document.getElementById("nav-add2homescreen");domCache.currentTrack=document.getElementById("currentTrack");
|
||||
var modalConnectionError=new Modal(document.getElementById("modalConnectionError")),modalSettings=new Modal(document.getElementById("modalSettings")),modalSavequeue=new Modal(document.getElementById("modalSaveQueue")),modalSongDetails=new Modal(document.getElementById("modalSongDetails")),modalAddToPlaylist=new Modal(document.getElementById("modalAddToPlaylist")),modalRenamePlaylist=new Modal(document.getElementById("modalRenamePlaylist"));
|
||||
var socket,lastSong="",lastState,currentSong={},playstate="",settings={},alertTimeout,progressTimer,deferredPrompt,dragEl,app={apps:{Playback:{state:"0/-/",scrollPos:0},Queue:{state:"0/Any Tag/",scrollPos:0},Browse:{active:"Database",tabs:{Filesystem:{state:"0/-/",scrollPos:0},Playlists:{active:"All",views:{All:{state:"0/-/",scrollPos:0},Detail:{state:"0/-/",scrollPos:0}}},Database:{active:"Artist",views:{Artist:{state:"0/-/",scrollPos:0},Album:{state:"0/-/",scrollPos:0}}}}},Search:{state:"0/Any Tag/",
|
||||
scrollPos:0}},current:{app:"Playback",tab:void 0,view:void 0,page:0,filter:"",search:"",scrollPos:0},last:{app:void 0,tab:void 0,view:void 0,filter:"",search:"",scrollPos:0}},domCache={};domCache.navbarBottomBtns=document.getElementById("navbar-bottom").getElementsByTagName("div");domCache.navbarBottomBtnsLen=domCache.navbarBottomBtns.length;domCache.panelHeadingBrowse=document.getElementById("panel-heading-browse").getElementsByTagName("a");domCache.panelHeadingBrowseLen=domCache.panelHeadingBrowse.length;
|
||||
domCache.counter=document.getElementById("counter");domCache.volumePrct=document.getElementById("volumePrct");domCache.volumeControl=document.getElementById("volumeControl");domCache.volumeIcon=document.getElementById("volumeIcon");domCache.btnsPlay=document.getElementsByClassName("btnPlay");domCache.btnsPlayLen=domCache.btnsPlay.length;domCache.btnPrev=document.getElementById("btnPrev");domCache.btnNext=document.getElementById("btnNext");domCache.progressBar=document.getElementById("progressBar");
|
||||
domCache.volumeBar=document.getElementById("volumeBar");domCache.outputs=document.getElementById("outputs");domCache.btnAdd=document.getElementById("nav-add2homescreen");domCache.currentTrack=document.getElementById("currentTrack");domCache.currentArtist=document.getElementById("currentArtist");domCache.currentAlbum=document.getElementById("currentAlbum");domCache.currentCover=document.getElementById("currentCover");domCache.btnVoteUp=document.getElementById("btnVoteUp");domCache.btnVoteDown=document.getElementById("btnVoteDown");
|
||||
var modalConnectionError=new Modal(document.getElementById("modalConnectionError")),modalSettings=new Modal(document.getElementById("modalSettings")),modalSavequeue=new Modal(document.getElementById("modalSaveQueue")),modalSongDetails=new Modal(document.getElementById("modalSongDetails")),modalAddToPlaylist=new Modal(document.getElementById("modalAddToPlaylist")),modalRenamePlaylist=new Modal(document.getElementById("modalRenamePlaylist")),modalUpdateDB=new Modal(document.getElementById("modalUpdateDB"));
|
||||
function appPrepare(a){if(app.current.app!=app.last.app||app.current.tab!=app.last.tab||app.current.view!=app.last.view){for(var b=0;b<domCache.navbarBottomBtnsLen;b++)domCache.navbarBottomBtns[b].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(b=0;b<domCache.panelHeadingBrowseLen;b++)domCache.panelHeadingBrowse[b].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"));scrollTo(a)}(a=document.getElementById(app.current.app+(void 0==app.current.tab?"":app.current.tab)+(void 0==app.current.view?"":app.current.view)+"List"))&&a.classList.add("opacity05")}
|
||||
@ -17,53 +17,55 @@ function appGoto(a,b,c,e){var d=document.body.scrollTop?document.body.scrollTop:
|
||||
(void 0==b&&(b=app.apps[a].active),app.apps[a].tabs[b].views?(void 0==c&&(c=app.apps[a].tabs[b].active),a="/"+a+"/"+b+"/"+c+"!"+(void 0==e?app.apps[a].tabs[b].views[c].state:e)):a="/"+a+"/"+b+"!"+(void 0==e?app.apps[a].tabs[b].state:e)):a="/"+a+"!"+(void 0==e?app.apps[a].state:e);location.hash=a}
|
||||
function appRoute(){var a;if(a=decodeURI(location.hash).match(/^#\/(\w+)\/?(\w+)?\/?(\w+)?!((\d+)\/([^\/]+)\/(.*))$/)){app.current.app=a[1];app.current.tab=a[2];app.current.view=a[3];app.apps[app.current.app].state?(app.apps[app.current.app].state=a[4],app.current.scrollPos=app.apps[app.current.app].scrollPos):app.apps[app.current.app].tabs[app.current.tab].state?(app.apps[app.current.app].tabs[app.current.tab].state=a[4],app.apps[app.current.app].active=app.current.tab,app.current.scrollPos=app.apps[app.current.app].tabs[app.current.tab].scrollPos):
|
||||
app.apps[app.current.app].tabs[app.current.tab].views[app.current.view].state&&(app.apps[app.current.app].tabs[app.current.tab].views[app.current.view].state=a[4],app.apps[app.current.app].active=app.current.tab,app.apps[app.current.app].tabs[app.current.tab].active=app.current.view,app.current.scrollPos=app.apps[app.current.app].tabs[app.current.tab].views[app.current.view].scrollPos);app.current.page=parseInt(a[5]);app.current.filter=a[6];app.current.search=a[7];appPrepare(app.current.scrollPos);
|
||||
if("Playback"==app.current.app)sendAPI({cmd:"MPD_API_GET_CURRENT_SONG"},songChange);else if("Queue"==app.current.app){var b=document.getElementById("searchqueuetag").getElementsByTagName("button");for(a=0;a<b.length;a++)b[a].classList.remove("active"),b[a].innerText==app.current.filter&&(b[a].classList.add("active"),document.getElementById("searchqueuetagdesc").innerText=b[a].innerText);getQueue()}else if("Browse"==app.current.app&&"Playlists"==app.current.tab&&"All"==app.current.view)sendAPI({cmd:"MPD_API_GET_PLAYLISTS",
|
||||
if("Playback"==app.current.app)sendAPI({cmd:"MPD_API_GET_CURRENT_SONG"},songChange);else if("Queue"==app.current.app){var b=document.getElementById("searchqueuetag").getElementsByTagName("button"),c=b.length;for(a=0;a<c;a++)b[a].classList.remove("active"),b[a].innerText==app.current.filter&&(b[a].classList.add("active"),document.getElementById("searchqueuetagdesc").innerText=b[a].innerText);getQueue()}else if("Browse"==app.current.app&&"Playlists"==app.current.tab&&"All"==app.current.view)sendAPI({cmd:"MPD_API_GET_PLAYLISTS",
|
||||
data:{offset:app.current.page,filter:app.current.filter}},parsePlaylists),doSetFilterLetter("BrowsePlaylistsFilter");else if("Browse"==app.current.app&&"Playlists"==app.current.tab&&"Detail"==app.current.view)sendAPI({cmd:"MPD_API_GET_PLAYLIST_LIST",data:{offset:app.current.page,filter:app.current.filter,uri:app.current.search}},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("BrowseFilesystemAddAllSongsBtn").removeAttribute("disabled")):(document.getElementById("BrowseFilesystemAddAllSongs").setAttribute("disabled","disabled"),document.getElementById("BrowseFilesystemAddAllSongsBtn").setAttribute("disabled","disabled"));b='<li class="breadcrumb-item"><a data-uri="">root</a></li>';
|
||||
var c=app.current.search.split("/"),e=c.length,d="";for(a=0;a<e;a++){if(e-1==a){b+='<li class="breadcrumb-item active">'+c[a]+"</li>";break}d+=c[a];b+='<li class="breadcrumb-item"><a data-uri="'+d+'">'+c[a]+"</a></li>";d+="/"}a=document.getElementById("BrowseBreadcrumb");a.innerHTML=b;b=a.getElementsByTagName("a");c=b.length;for(a=0;a<c;a++)b[a].addEventListener("click",function(){appGoto("Browse","Filesystem",void 0,"0/"+app.current.filter+"/"+this.getAttribute("data-uri"))},!1);doSetFilterLetter("BrowseFilesystemFilter")}else if("Search"==
|
||||
c=app.current.search.split("/");var e=c.length,d="";for(a=0;a<e;a++){if(e-1==a){b+='<li class="breadcrumb-item active">'+c[a]+"</li>";break}d+=c[a];b+='<li class="breadcrumb-item"><a data-uri="'+d+'">'+c[a]+"</a></li>";d+="/"}a=document.getElementById("BrowseBreadcrumb");a.innerHTML=b;b=a.getElementsByTagName("a");c=b.length;for(a=0;a<c;a++)b[a].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(document.getElementById("searchstr").focus(),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>'),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("searchAddAllSongsBtn").setAttribute("disabled","disabled"),document.getElementById("panel-heading-search").innerText="",document.getElementById("SearchList").classList.remove("opacity05"),setPagination(0)),b=document.getElementById("searchtags").getElementsByTagName("button"),c=b.length,a=0;a<c;a++)b[a].classList.remove("active"),b[a].innerText==app.current.filter&&(b[a].classList.add("active"),
|
||||
document.getElementById("searchtagsdesc").innerText=b[a].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();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("volumeIcon").parentNode.addEventListener("show.bs.dropdown",
|
||||
function(){sendAPI({cmd:"MPD_API_GET_OUTPUTS"},parseOutputnames)});document.getElementById("modalAbout").addEventListener("shown.bs.modal",function(){sendAPI({cmd:"MPD_API_GET_STATS"},parseStats)});document.getElementById("modalSaveQueue").addEventListener("shown.bs.modal",function(){var a=document.getElementById("saveQueueName");a.focus();a.value="";a.classList.remove("is-invalid");document.getElementById("saveQueueFrm").classList.remove("was-validated")});document.getElementById("modalSettings").addEventListener("shown.bs.modal",
|
||||
function(){getSettings();document.getElementById("settingsFrm").classList.remove("was-validated");document.getElementById("inputCrossfade").classList.remove("is-invalid");document.getElementById("inputMixrampdb").classList.remove("is-invalid");document.getElementById("inputMixrampdelay").classList.remove("is-invalid")});document.getElementById("addToPlaylistPlaylist").addEventListener("change",function(a){"New Playlist"==this.options[this.selectedIndex].text?(document.getElementById("addToPlaylistNewPlaylistDiv").classList.remove("hide"),
|
||||
document.getElementById("addToPlaylistNewPlaylist").focus()):document.getElementById("addToPlaylistNewPlaylistDiv").classList.add("hide")},!1);addFilterLetter("BrowseFilesystemFilterLetters");addFilterLetter("BrowseDatabaseFilterLetters");addFilterLetter("BrowsePlaylistsFilterLetters");for(var a=document.querySelectorAll("[data-href]"),b=a.length,c=0;c<b;c++)a[c].classList.add("clickable"),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}});toggleBtn(a.target.id)},!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(a.target.parentNode.getAttribute("data-uri")),a.target.parentNode.getAttribute("data-name"));break;case "plist":appendQueue("plist",decodeURI(a.target.parentNode.getAttribute("data-uri")),a.target.parentNode.getAttribute("data-name"))}else"A"==
|
||||
a.target.nodeName&&(a.preventDefault(),showMenu(a.target))},!1);document.getElementById("BrowsePlaylistsAllList").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("BrowsePlaylistsDetailList").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("BrowseFilesystemAddAllSongsDropdown").addEventListener("click",function(a){"BUTTON"==a.target.nodeName&&("Add all to queue"==a.target.innerText?addAllFromBrowse():"Add all to playlist"==a.target.innerText&&showAddToPlaylist(app.current.search))},!1);document.getElementById("searchAddAllSongsDropdown").addEventListener("click",function(a){"BUTTON"==a.target.nodeName&&
|
||||
("Add all to queue"==a.target.innerText?addAllFromSearch():"Add all to playlist"==a.target.innerText&&showAddToPlaylist("SEARCH"))},!1);document.getElementById("searchtags").addEventListener("click",function(a){"BUTTON"==a.target.nodeName&&appGoto(app.current.app,app.current.tab,app.current.view,"0/"+a.target.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("search").addEventListener("submit",function(){return!1},!1);document.getElementById("searchqueue").addEventListener("submit",function(){return!1},!1);document.getElementById("searchstr").addEventListener("keyup",function(a){appGoto("Search",
|
||||
void 0,void 0,"0/"+app.current.filter+"/"+this.value)},!1);dragAndDropTable("QueueList");dragAndDropTable("BrowsePlaylistsDetailList");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);"serviceWorker"in navigator&&"https"==document.URL.substring(0,5)&&window.addEventListener("load",function(){navigator.serviceWorker.register("/sw.min.js",
|
||||
{scope:"/"}).then(function(a){console.log("ServiceWorker registration successful with scope: ",a.scope);a.update()},function(a){console.log("ServiceWorker registration failed: ",a)})});window.addEventListener("beforeinstallprompt",function(a){a.preventDefault();deferredPrompt=a});window.addEventListener("beforeinstallprompt",function(a){a.preventDefault();deferredPrompt=a;domCache.btnAdd.classList.remove("hide")});domCache.btnAdd.addEventListener("click",function(a){domCache.btnAdd.classList.add("hide");
|
||||
deferredPrompt.prompt();deferredPrompt.userChoice.then(function(a){"accepted"===a.outcome?console.log("User accepted the A2HS prompt"):console.log("User dismissed the A2HS prompt");deferredPrompt=null})});window.addEventListener("appinstalled",function(a){console.log("myMPD installed as app")})}
|
||||
function appInit(){getSettings();sendAPI({cmd:"MPD_API_GET_STATE"},parseState);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){currentSong&&0<=currentSong.currentSongId&&sendAPI({cmd:"MPD_API_SET_SEEK",data:{songid:currentSong.currentSongId,seek:Math.ceil(domCache.progressBar.value/
|
||||
100*currentSong.totalTime)}})},!1);document.getElementById("volumeIcon").parentNode.addEventListener("show.bs.dropdown",function(){sendAPI({cmd:"MPD_API_GET_OUTPUTS"},parseOutputs)});document.getElementById("modalAbout").addEventListener("shown.bs.modal",function(){sendAPI({cmd:"MPD_API_GET_STATS"},parseStats)});document.getElementById("modalUpdateDB").addEventListener("hidden.bs.modal",function(){document.getElementById("updateDBprogress").classList.remove("updateDBprogressAnimate")});document.getElementById("modalSaveQueue").addEventListener("shown.bs.modal",
|
||||
function(){var a=document.getElementById("saveQueueName");a.focus();a.value="";a.classList.remove("is-invalid");document.getElementById("saveQueueFrm").classList.remove("was-validated")});document.getElementById("modalSettings").addEventListener("shown.bs.modal",function(){getSettings();document.getElementById("settingsFrm").classList.remove("was-validated");document.getElementById("inputCrossfade").classList.remove("is-invalid");document.getElementById("inputMixrampdb").classList.remove("is-invalid");
|
||||
document.getElementById("inputMixrampdelay").classList.remove("is-invalid")});document.getElementById("addToPlaylistPlaylist").addEventListener("change",function(a){"New Playlist"==this.options[this.selectedIndex].text?(document.getElementById("addToPlaylistNewPlaylistDiv").classList.remove("hide"),document.getElementById("addToPlaylistNewPlaylist").focus()):document.getElementById("addToPlaylistNewPlaylistDiv").classList.add("hide")},!1);addFilterLetter("BrowseFilesystemFilterLetters");addFilterLetter("BrowseDatabaseFilterLetters");
|
||||
addFilterLetter("BrowsePlaylistsFilterLetters");for(var a=document.querySelectorAll("[data-href]"),b=a.length,c=0;c<b;c++)a[c].classList.add("clickable"),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.getElementsByClassName("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}});toggleBtn(a.target.id)},!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(a.target.parentNode.getAttribute("data-uri")),a.target.parentNode.getAttribute("data-name"));break;case "plist":appendQueue("plist",decodeURI(a.target.parentNode.getAttribute("data-uri")),a.target.parentNode.getAttribute("data-name"))}else"A"==a.target.nodeName&&(a.preventDefault(),showMenu(a.target))},!1);document.getElementById("BrowsePlaylistsAllList").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("BrowsePlaylistsDetailList").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("BrowseFilesystemAddAllSongsDropdown").addEventListener("click",function(a){"BUTTON"==
|
||||
a.target.nodeName&&("Add all to queue"==a.target.innerText?addAllFromBrowse():"Add all to playlist"==a.target.innerText&&showAddToPlaylist(app.current.search))},!1);document.getElementById("searchAddAllSongsDropdown").addEventListener("click",function(a){"BUTTON"==a.target.nodeName&&("Add all to queue"==a.target.innerText?addAllFromSearch():"Add all to playlist"==a.target.innerText&&showAddToPlaylist("SEARCH"))},!1);document.getElementById("searchtags").addEventListener("click",function(a){"BUTTON"==
|
||||
a.target.nodeName&&appGoto(app.current.app,app.current.tab,app.current.view,"0/"+a.target.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("search").addEventListener("submit",function(){return!1},!1);document.getElementById("searchqueue").addEventListener("submit",function(){return!1},!1);document.getElementById("searchstr").addEventListener("keyup",function(a){appGoto("Search",void 0,void 0,"0/"+app.current.filter+"/"+this.value)},!1);dragAndDropTable("QueueList");dragAndDropTable("BrowsePlaylistsDetailList");window.addEventListener("hashchange",appRoute,!1);window.addEventListener("focus",
|
||||
function(){sendAPI({cmd:"MPD_API_GET_STATE"},parseState)},!1);document.addEventListener("keydown",function(a){if("INPUT"!=a.target.tagName){switch(a.which){case 37:clickPrev();break;case 39:clickNext();break;case 32:clickPlay();break;default:return}a.preventDefault()}},!1);"serviceWorker"in navigator&&"https"==document.URL.substring(0,5)&&window.addEventListener("load",function(){navigator.serviceWorker.register("/sw.min.js",{scope:"/"}).then(function(a){console.log("ServiceWorker registration successful with scope: ",
|
||||
a.scope);a.update()},function(a){console.log("ServiceWorker registration failed: ",a)})});window.addEventListener("beforeinstallprompt",function(a){a.preventDefault();deferredPrompt=a});window.addEventListener("beforeinstallprompt",function(a){a.preventDefault();deferredPrompt=a;domCache.btnAdd.classList.remove("hide")});domCache.btnAdd.addEventListener("click",function(a){domCache.btnAdd.classList.add("hide");deferredPrompt.prompt();deferredPrompt.userChoice.then(function(a){"accepted"===a.outcome?
|
||||
console.log("User accepted the A2HS prompt"):console.log("User dismissed the A2HS prompt");deferredPrompt=null})});window.addEventListener("appinstalled",function(a){console.log("myMPD installed as app")})}
|
||||
function dragAndDropTable(a){var b=document.getElementById(a).getElementsByTagName("tbody")[0];b.addEventListener("dragstart",function(a){"TR"==a.target.nodeName&&(a.target.classList.add("opacity05"),a.dataTransfer.setDragImage(a.target,0,0),a.dataTransfer.effectAllowed="move",a.dataTransfer.setData("Text",a.target.getAttribute("id")),dragEl=a.target.cloneNode(!0))},!1);b.addEventListener("dragleave",function(a){a.preventDefault();var b=a.target;"TD"==a.target.nodeName&&(b=a.target.parentNode);"TR"==
|
||||
b.nodeName&&b.classList.remove("dragover")},!1);b.addEventListener("dragover",function(a){a.preventDefault();for(var c=b.querySelectorAll(".dragover"),d=c.length,f=0;f<d;f++)c[f].classList.remove("dragover");c=a.target;"TD"==a.target.nodeName&&(c=a.target.parentNode);"TR"==c.nodeName&&c.classList.add("dragover");a.dataTransfer.dropEffect="move"},!1);b.addEventListener("dragend",function(a){for(var c=b.querySelectorAll(".dragover"),d=c.length,f=0;f<d;f++)c[f].classList.remove("dragover");document.getElementById(a.dataTransfer.getData("Text"))&&
|
||||
document.getElementById(a.dataTransfer.getData("Text")).classList.remove("opacity05")},!1);b.addEventListener("drop",function(c){c.stopPropagation();c.preventDefault();var e=c.target;"TD"==c.target.nodeName&&(e=c.target.parentNode);var d=document.getElementById(c.dataTransfer.getData("Text")).getAttribute("data-songpos"),f=e.getAttribute("data-songpos");document.getElementById(c.dataTransfer.getData("Text")).remove();dragEl.classList.remove("opacity05");b.insertBefore(dragEl,e);c=b.querySelectorAll(".dragover");
|
||||
e=c.length;for(var g=0;g<e;g++)c[g].classList.remove("dragover");document.getElementById(a).classList.add("opacity05");"Queue"==app.current.app?sendAPI({cmd:"MPD_API_MOVE_TRACK",data:{from:d,to:f}}):"Browse"==app.current.app&&"Playlists"==app.current.tab&&"Detail"==app.current.view&&playlistMoveTrack(d,f)},!1)}
|
||||
b.nodeName&&b.classList.remove("dragover")},!1);b.addEventListener("dragover",function(a){a.preventDefault();for(var c=b.getElementsByClassName("dragover"),d=c.length,f=0;f<d;f++)c[f].classList.remove("dragover");c=a.target;"TD"==a.target.nodeName&&(c=a.target.parentNode);"TR"==c.nodeName&&c.classList.add("dragover");a.dataTransfer.dropEffect="move"},!1);b.addEventListener("dragend",function(a){for(var c=b.getElementsByClassName("dragover"),d=c.length,f=0;f<d;f++)c[f].classList.remove("dragover");
|
||||
document.getElementById(a.dataTransfer.getData("Text"))&&document.getElementById(a.dataTransfer.getData("Text")).classList.remove("opacity05")},!1);b.addEventListener("drop",function(c){c.stopPropagation();c.preventDefault();var e=c.target;"TD"==c.target.nodeName&&(e=c.target.parentNode);var d=document.getElementById(c.dataTransfer.getData("Text")).getAttribute("data-songpos"),f=e.getAttribute("data-songpos");document.getElementById(c.dataTransfer.getData("Text")).remove();dragEl.classList.remove("opacity05");
|
||||
b.insertBefore(dragEl,e);c=b.getElementsByClassName("dragover");e=c.length;for(var g=0;g<e;g++)c[g].classList.remove("dragover");document.getElementById(a).classList.add("opacity05");"Queue"==app.current.app?sendAPI({cmd:"MPD_API_MOVE_TRACK",data:{from:d,to:f}}):"Browse"==app.current.app&&"Playlists"==app.current.tab&&"Detail"==app.current.view&&playlistMoveTrack(d,f)},!1)}
|
||||
function playlistMoveTrack(a,b){sendAPI({cmd:"MPD_API_PLAYLIST_MOVE_TRACK",data:{plist:app.current.search,from:a,to:b}});sendAPI({cmd:"MPD_API_GET_PLAYLIST_LIST",data:{offset:app.current.page,filter:app.current.filter,uri:app.current.search}},parsePlaylists)}
|
||||
function webSocketConnect(){socket=new WebSocket(getWsUrl());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 getWsUrl(){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){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){if(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 webSocketConnect(){socket=new WebSocket(getWsUrl());try{socket.onopen=function(){console.log("connected");showNotification("Connected to myMPD","","","success");modalConnectionError.hide();appRoute();sendAPI({cmd:"MPD_API_GET_STATE"},parseState)},socket.onmessage=function(a){if(a.data!==lastState&&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 "update_state":parseState(b);break;case "disconnected":showNotification("myMPD lost connection to MPD",
|
||||
"","","danger");break;case "update_queue":"Queue"===app.current.app&&getQueue();sendAPI({cmd:"MPD_API_GET_STATE"},parseState);break;case "update_options":getSettings();break;case "update_outputs":sendAPI({cmd:"MPD_API_GET_OUTPUTS"},parseOutputs);break;case "update_started":updateDBstarted();break;case "update_database":case "update_finished":updateDBfinished(b.type);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 getWsUrl(){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){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.mympdVersion;document.getElementById("mpdVersion").innerText=a.data.mpdVersion}function toggleBtn(a,b){if(a=document.getElementById(a))void 0==b&&(b=a.classList.contains("active")?0:1),1==b?a.classList.add("active"):a.classList.remove("active")}
|
||||
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 data-output-id="'+a.data.outputs[e].id+'" class="btn btn-secondary btn-block',1==a.data.outputs[e].state&&(b+=" active"),b+='"><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);"-1"==a.data.songpos&&(domCache.currentTrack.innerText=
|
||||
"Not playing",document.getElementById("currentAlbum").innerText="",document.getElementById("currentArtist").innerText="",document.getElementById("currentCover").style.backgroundImage="");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="";var b=a.data.length,c=document.getElementById(app.current.app+"List");c.setAttribute("data-version",a.queue_version);c=c.getElementsByTagName("tbody")[0];
|
||||
for(var e=c.getElementsByTagName("tr"),d=0;d<b;d++)if(!e[d]||e[d].getAttribute("data-trackid")!=a.data[d].id||e[d].getAttribute("data-songpos")!=a.data[d].pos+1){var f=Math.floor(a.data[d].duration/60),g=a.data[d].duration-60*f;f=f+":"+(10>g?"0":"")+g;g=document.createElement("tr");g.setAttribute("draggable","true");g.setAttribute("data-trackid",a.data[d].id);g.setAttribute("id","queueTrackId"+a.data[d].id);g.setAttribute("data-songpos",a.data[d].pos+1);g.setAttribute("data-duration",f);g.setAttribute("data-uri",
|
||||
a.data[d].uri);g.innerHTML="<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>"+f+'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';d<e.length?e[d].replaceWith(g):c.append(g)}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);document.getElementById("QueueList").classList.remove("opacity05")}}
|
||||
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);b=document.getElementsByClassName("stickers");for(var c=
|
||||
b.length,e=1==a.data.stickers?"":"none",d=0;d<c;d++)b[d].style.display=e;1==a.data.mixramp?document.getElementsByClassName("mixramp")[0].style.display="":document.getElementsByClassName("mixramp")[0].style.display="none";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 parseOutputs(a){for(var b="",c=a.data.outputs.length,e=0;e<c;e++)b+='<button data-output-id="'+a.data.outputs[e].id+'" class="btn btn-secondary btn-block',1==a.data.outputs[e].state&&(b+=" active"),b+='"><span class="material-icons float-left">volume_up</span> '+a.data.outputs[e].name+"</button>";domCache.outputs.innerHTML=b}
|
||||
function setCounter(a,b,c){currentSong.totalTime=b;currentSong.elapsedTime=c;currentSong.currentSongId=a;var e=Math.floor(b/60),d=b-60*e,f=Math.floor(c/60),g=c-60*f;domCache.progressBar.value=Math.floor(100*c/b);b=f+":"+(10>g?"0":"")+g+" / "+e+":"+(10>d?"0":"")+d;domCache.counter.innerText=b;lastState&&(c=document.getElementById("queueTrackId"+lastState.data.currentSongId))&&(e=c.getElementsByTagName("td"),e[4].innerText=c.getAttribute("data-duration"),e[0].classList.remove("material-icons"),e[0].innerText=
|
||||
c.getAttribute("data-songpos"),c.classList.remove("font-weight-bold"));if(c=document.getElementById("queueTrackId"+a))e=c.getElementsByTagName("td"),e[4].innerText=b,e[0].classList.add("material-icons"),e[0].innerText="play_arrow",c.classList.add("font-weight-bold");progressTimer&&clearTimeout(progressTimer);"play"==playstate&&(progressTimer=setTimeout(function(){currentSong.elapsedTime++;setCounter(currentSong.currentSongId,currentSong.totalTime,currentSong.elapsedTime)},1E3))}
|
||||
function parseState(a){if(JSON.stringify(a)!==JSON.stringify(lastState)){if(1==a.data.state){for(var b=0;b<domCache.btnsPlayLen;b++)domCache.btnsPlay[b].innerText="play_arrow";playstate="stop"}else if(2==a.data.state){for(b=0;b<domCache.btnsPlayLen;b++)domCache.btnsPlay[b].innerText="pause";playstate="play"}else{for(b=0;b<domCache.btnsPlayLen;b++)domCache.btnsPlay[b].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");if(0==a.data.queueLength)for(b=0;b<domCache.btnsPlayLen;b++)domCache.btnsPlay[b].setAttribute("disabled","disabled");else for(b=0;b<domCache.btnsPlayLen;b++)domCache.btnsPlay[b].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;setCounter(a.data.currentSongId,a.data.totalTime,a.data.elapsedTime);sendAPI({cmd:"MPD_API_GET_CURRENT_SONG"},songChange);"-1"==a.data.songPos&&(domCache.currentTrack.innerText="Not playing",domCache.currentAlbum.innerText="",domCache.currentArtist.innerText="",domCache.currentCover.style.backgroundImage="");lastState=a}}
|
||||
function getQueue(){2<=app.current.search.length?sendAPI({cmd:"MPD_API_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&&a.totalEntities<=settings.maxElementsPerPage?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="";var b=a.data.length,c=document.getElementById(app.current.app+"List");c.setAttribute("data-version",a.queueVersion);
|
||||
c=c.getElementsByTagName("tbody")[0];for(var e=c.getElementsByTagName("tr"),d=0;d<b;d++)if(!e[d]||e[d].getAttribute("data-trackid")!=a.data[d].id||e[d].getAttribute("data-songpos")!=a.data[d].pos+1){var f=Math.floor(a.data[d].duration/60),g=a.data[d].duration-60*f;f=f+":"+(10>g?"0":"")+g;g=document.createElement("tr");g.setAttribute("draggable","true");g.setAttribute("data-trackid",a.data[d].id);g.setAttribute("id","queueTrackId"+a.data[d].id);g.setAttribute("data-songpos",a.data[d].pos+1);g.setAttribute("data-duration",
|
||||
f);g.setAttribute("data-uri",a.data[d].uri);g.innerHTML="<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>"+f+'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';d<e.length?e[d].replaceWith(g):c.append(g)}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);document.getElementById("QueueList").classList.remove("opacity05")}}
|
||||
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("searchAddAllSongsBtn").removeAttribute("disabled")):(document.getElementById("searchAddAllSongs").setAttribute("disabled","disabled"),document.getElementById("searchAddAllSongsBtn").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 f=encodeURI(a.data[d].uri);if(!e[d]||e[d].getAttribute("data-uri")!=f){var g=document.createElement("tr");g.setAttribute("data-type",a.data[d].type);g.setAttribute("data-uri",f);g.setAttribute("data-name",
|
||||
a.data[d].name);switch(a.data[d].type){case "dir":g.innerHTML='<td><span class="material-icons">folder_open</span></td><td colspan="4">'+a.data[d].name+'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';break;case "song":f=Math.floor(a.data[d].duration/60);var h=a.data[d].duration-60*f;g.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>"+f+":"+(10>h?"0":"")+h+'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';
|
||||
@ -76,24 +78,28 @@ h.setAttribute("data-uri",f);h.setAttribute("data-type","plist");h.setAttribute(
|
||||
"playlistTrackId"+g){h=document.createElement("tr");h.setAttribute("draggable","true");h.setAttribute("id","playlistTrackId"+g);h.setAttribute("data-type",a.data[d].type);h.setAttribute("data-uri",f);h.setAttribute("data-name",a.data[d].name);h.setAttribute("data-songpos",g);f=Math.floor(a.data[d].duration/60);var k=a.data[d].duration-60*f;h.innerHTML="<td>"+g+"</td><td>"+a.data[d].title+"</td><td>"+a.data[d].artist+"</td><td>"+a.data[d].album+"</td><td>"+f+":"+(10>k?"0":"")+k+'</td><td><a href="#" class="material-icons color-darkgrey">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="All"==app.current.view?'<tr><td><span class="material-icons">error_outline</span></td><td colspan="5">No playlists found.</td></tr>':'<tr><td><span class="material-icons">error_outline</span></td><td colspan="5">Empty playlist.</td></tr>');document.getElementById(app.current.app+app.current.tab+app.current.view+"List").classList.remove("opacity05")}}
|
||||
function parseListDBtags(a){if("Browse"===app.current.app||"Database"===app.current.tab||"Artist"===app.current.view)if("AlbumArtist"==a.tagtype){document.getElementById("BrowseDatabaseAlbumList").classList.add("hide");document.getElementById("BrowseDatabaseArtistList").classList.remove("hide");document.getElementById("btnBrowseDatabaseArtist").parentNode.classList.add("hide");for(var b=a.data.length,c=document.getElementById(app.current.app+app.current.tab+app.current.view+"List").getElementsByTagName("tbody")[0],
|
||||
e=c.getElementsByTagName("tr"),d=0;d<b;d++){var f=encodeURI(a.data[d].value);if(!e[d]||e[d].getAttribute("data-uri")!=f){var g=document.createElement("tr");g.setAttribute("data-uri",f);g.innerHTML='<td><span class="material-icons">album</span></td><td>'+a.data[d].value+"</td>";d<e.length?e[d].replaceWith(g):c.append(g)}}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>');
|
||||
document.getElementById("BrowseDatabaseArtistList").classList.remove("opacity05")}else if("Album"==a.tagtype){document.getElementById("BrowseDatabaseAlbumList").classList.remove("hide");document.getElementById("BrowseDatabaseArtistList").classList.add("hide");document.getElementById("btnBrowseDatabaseArtist").parentNode.classList.remove("hide");b=a.data.length;c=document.getElementById("BrowseDatabaseAlbumList");e=c.querySelectorAll(".col-md");for(d=0;d<b;d++)f=genId(a.data[d].value),e[d]&&e[d].getAttribute("id")==
|
||||
e=c.getElementsByTagName("tr"),d=0;d<b;d++){var f=encodeURI(a.data[d].value);if(!e[d]||e[d].getAttribute("data-uri")!=f){var g=document.createElement("tr");g.setAttribute("data-uri",f);g.innerHTML='<td><span class="material-icons">album</span></td><td>'+a.data[d].value+"</td>";d<e.length?e[d].replaceWith(g):c.append(g)}}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>No entries found.</td></tr>');
|
||||
document.getElementById("BrowseDatabaseArtistList").classList.remove("opacity05")}else if("Album"==a.tagtype){document.getElementById("BrowseDatabaseAlbumList").classList.remove("hide");document.getElementById("BrowseDatabaseArtistList").classList.add("hide");document.getElementById("btnBrowseDatabaseArtist").parentNode.classList.remove("hide");b=a.data.length;c=document.getElementById("BrowseDatabaseAlbumList");e=c.getElementsByClassName("col-md");for(d=0;d<b;d++)f=genId(a.data[d].value),e[d]&&e[d].getAttribute("id")==
|
||||
f||(g=document.createElement("div"),g.classList.add("col-md"),g.classList.add("mr-0"),g.setAttribute("id",f),g.innerHTML='<div class="card mb-4" id="card'+f+'"> <a href="#" class="card-img-top"><img class="card-img-top" src="" ></a> <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'+f+'"><tbody></tbody></table </div></div>',d<e.length?e[d].replaceWith(g):c.append(g),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);document.getElementById("BrowseDatabaseAlbumList").classList.remove("opacity05")}}
|
||||
function parseListTitles(a){if("Browse"===app.current.app||"Database"===app.current.tab||"Album"===app.current.view){var b=genId(a.album),c=document.getElementById("card"+b);b=c.getElementsByTagName("tbody")[0];var e=c.getElementsByTagName("img")[0];c=e.parentNode;e.setAttribute("src",a.cover);c.setAttribute("data-uri",encodeURI(a.data[0].uri.replace(/\/[^\/]+$/,"")));c.setAttribute("data-name",a.album);c.setAttribute("data-type","dir");e="";for(var d=a.data.length,f=0;f<d;f++)e+='<tr data-type="song" data-name="'+
|
||||
a.data[f].title+'" data-uri="'+encodeURI(a.data[f].uri)+'"><td>'+a.data[f].track+"</td><td>"+a.data[f].title+'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td></tr>';b.innerHTML=e;c.addEventListener("click",function(a){a.preventDefault();showMenu(this)},!1);b.parentNode.addEventListener("click",function(a){"TD"==a.target.nodeName?appendQueue("song",decodeURI(a.target.parentNode.getAttribute("data-uri")),a.target.parentNode.getAttribute("data-name")):"A"==a.target.nodeName&&
|
||||
(a.preventDefault(),showMenu(a.target))},!1)}}
|
||||
function setPagination(a){var b=Math.ceil(a/settings.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 f="",g=0;g<b;g++)f+='<button data-page="'+g*settings.max_elements_per_page+'" type="button" class="mr-1 mb-1 btn-sm btn btn-secondary">'+
|
||||
(g+1)+"</button>";document.getElementById(c+e[d]+"Pages").innerHTML=f}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+e[d]).classList.remove("hide"),document.getElementById(c+"ButtonsBottom").classList.remove("hide")):(document.getElementById(c+e[d]+"Next").setAttribute("disabled","disabled"),document.getElementById(c+e[d]).classList.add("hide"),
|
||||
function setPagination(a){var b=Math.ceil(a/settings.maxElementsPerPage),c=app.current.app+(void 0==app.current.tab?"":app.current.tab);0==b&&(b=1);for(var e=["PaginationTop","PaginationBottom"],d=0;2>d;d++){document.getElementById(c+e[d]+"Page").innerText=app.current.page/settings.maxElementsPerPage+1+" / "+b;if(1<b){document.getElementById(c+e[d]+"Page").removeAttribute("disabled");for(var f="",g=0;g<b;g++)f+='<button data-page="'+g*settings.maxElementsPerPage+'" type="button" class="mr-1 mb-1 btn-sm btn btn-secondary">'+
|
||||
(g+1)+"</button>";document.getElementById(c+e[d]+"Pages").innerHTML=f}else document.getElementById(c+e[d]+"Page").setAttribute("disabled","disabled");a>app.current.page+settings.maxElementsPerPage?(document.getElementById(c+e[d]+"Next").removeAttribute("disabled"),document.getElementById(c+e[d]).classList.remove("hide"),document.getElementById(c+"ButtonsBottom").classList.remove("hide")):(document.getElementById(c+e[d]+"Next").setAttribute("disabled","disabled"),document.getElementById(c+e[d]).classList.add("hide"),
|
||||
document.getElementById(c+"ButtonsBottom").classList.add("hide"));0<app.current.page?(document.getElementById(c+e[d]+"Prev").removeAttribute("disabled"),document.getElementById(c+e[d]).classList.remove("hide"),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 "dir":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 appendAfterQueue(a,b,c,e){switch(a){case "song":sendAPI({cmd:"MPD_API_ADD_TRACK_AFTER",data:{uri:b,to:c}}),showNotification('"'+e+'" added to pos '+c,"","","success")}}
|
||||
function replaceQueue(a,b,c){switch(a){case "song":sendAPI({cmd:"MPD_API_REPLACE_TRACK",data:{uri:b}});showNotification('"'+c+'" replaced',"","","success");break;case "dir":sendAPI({cmd:"MPD_API_REPLACE_TRACK",data:{uri:b}});showNotification('"'+c+'" replaced',"","","success");break;case "plist":sendAPI({cmd:"MPD_API_REPLACE_PLAYLIST",data:{plist:b}}),showNotification('"'+c+'" replaced',"","","success")}}function songClick(){songDetails(domCache.currentTrack.getAttribute("data-uri"))}
|
||||
function artistClick(){appGoto("Browse","Database","Album","0/-/"+document.getElementById("currentArtist").innerText)}function songDetails(a){sendAPI({cmd:"MPD_API_GET_SONGDETAILS",data:{uri:a}},parseSongDetails);modalSongDetails.show()}
|
||||
function parseSongDetails(a){var b=document.getElementById("modalSongDetails");b.querySelector(".album-cover").style.backgroundImage='url("'+a.data.cover+'")';b.getElementsByTagName("h1")[0].innerText=a.data.title;b=b.getElementsByTagName("tr");for(var c=b.length,e=0;e<c;e++){var d=b[e].getAttribute("data-name"),f=a.data[d];"duration"==d?(d=Math.floor(f/60),f-=60*d,f=d+":"+(10>f?"0":"")+f):"uri"==d&&(f='<a class="text-success" href="/library/'+f+'">'+f+"</a>");b[e].getElementsByTagName("td")[1].innerHTML=
|
||||
f}}function playlistDetails(a){appGoto("Browse","Playlists","Detail","0/-/"+a)}function removeFromPlaylist(a,b){b--;sendAPI({cmd:"MPD_API_RM_PLAYLIST_TRACK",data:{uri:a,track:b}});document.getElementById("BrowsePlaylistsDetailList").classList.add("opacity05");sendAPI({cmd:"MPD_API_GET_PLAYLIST_LIST",data:{offset:app.current.page,filter:app.current.filter,uri:app.current.search}},parsePlaylists)}
|
||||
function replaceQueue(a,b,c){switch(a){case "song":sendAPI({cmd:"MPD_API_REPLACE_TRACK",data:{uri:b}});showNotification('"'+c+'" replaced',"","","success");break;case "dir":sendAPI({cmd:"MPD_API_REPLACE_TRACK",data:{uri:b}});showNotification('"'+c+'" replaced',"","","success");break;case "plist":sendAPI({cmd:"MPD_API_REPLACE_PLAYLIST",data:{plist:b}}),showNotification('"'+c+'" replaced',"","","success")}}
|
||||
function songClick(){var a=domCache.currentTrack.getAttribute("data-uri");""!=a&&songDetails(a)}function artistClick(){var a=domCache.currentArtist.getAttribute("data-albumartist");""!=a&&appGoto("Browse","Database","Album","0/-/"+a)}function songDetails(a){sendAPI({cmd:"MPD_API_GET_SONGDETAILS",data:{uri:a}},parseSongDetails);modalSongDetails.show()}
|
||||
function parseSongDetails(a){var b=document.getElementById("modalSongDetails");b.getElementsByClassName("album-cover")[0].style.backgroundImage='url("'+a.data.cover+'")';b.getElementsByTagName("h1")[0].innerText=a.data.title;b=b.getElementsByTagName("tr");for(var c=b.length,e=0;e<c;e++){var d=b[e].getAttribute("data-name");if(d){var f=a.data[d];"duration"==d?(d=Math.floor(f/60),f-=60*d,f=d+":"+(10>f?"0":"")+f):"lastPlayed"==d?f=0==f?"never":(new Date(1E3*f)).toUTCString():"like"==d?f=0==f?'<span class="material-icons">thumb_down_alt</span>':
|
||||
2==f?'<span class="material-icons">thumb_up_alt</span>':"not voted":"uri"==d&&(f='<a class="text-success" href="/library/'+f+'">'+f+"</a>");b[e].getElementsByTagName("td")[0].innerHTML=f}}}function playlistDetails(a){appGoto("Browse","Playlists","Detail","0/-/"+a)}
|
||||
function removeFromPlaylist(a,b){b--;sendAPI({cmd:"MPD_API_RM_PLAYLIST_TRACK",data:{uri:a,track:b}});document.getElementById("BrowsePlaylistsDetailList").classList.add("opacity05");sendAPI({cmd:"MPD_API_GET_PLAYLIST_LIST",data:{offset:app.current.page,filter:app.current.filter,uri:app.current.search}},parsePlaylists)}
|
||||
function playlistClear(){var a=document.getElementById("BrowsePlaylistsDetailList").getAttribute("data-uri");sendAPI({cmd:"MPD_API_PLAYLIST_CLEAR",data:{uri:a}});document.getElementById("BrowsePlaylistsDetailList").classList.add("opacity05");sendAPI({cmd:"MPD_API_GET_PLAYLIST_LIST",data:{offset:app.current.page,filter:app.current.filter,uri:app.current.search}},parsePlaylists)}
|
||||
function getAllPlaylists(a){for(var b=a.data.length,c="<option></option><option>New Playlist</option>",e=0;e<b;e++)c+="<option>"+a.data[e].uri+"</option>";document.getElementById("addToPlaylistPlaylist").innerHTML+=c;a.totalEntities>a.returnedEntities&&(a.offset+=settings.max_elements_per_page,sendAPI({cmd:"MPD_API_GET_PLAYLISTS",data:{offset:a.offset,filter:"-"}},getAllPlaylists))}
|
||||
function getAllPlaylists(a){for(var b=a.data.length,c="<option></option><option>New Playlist</option>",e=0;e<b;e++)c+="<option>"+a.data[e].uri+"</option>";document.getElementById("addToPlaylistPlaylist").innerHTML+=c;a.totalEntities>a.returnedEntities&&(a.offset+=settings.maxElementsPerPage,sendAPI({cmd:"MPD_API_GET_PLAYLISTS",data:{offset:a.offset,filter:"-"}},getAllPlaylists))}
|
||||
function voteSong(a){var b=domCache.currentTrack.getAttribute("data-uri");""!=b&&(2==a&&domCache.btnVoteUp.classList.contains("active-fg-green")?a=1:0==a&&domCache.btnVoteDown.classList.contains("active-fg-red")&&(a=1),sendAPI({cmd:"MPD_API_LIKE",data:{uri:b,like:a}}),setVoteSongBtns(a,b))}
|
||||
function setVoteSongBtns(a,b){""==b||0==b.indexOf("http://")||0==b.indexOf("https://")?(domCache.btnVoteUp.setAttribute("disabled","disabled"),domCache.btnVoteDown.setAttribute("disabled","disabled")):(domCache.btnVoteUp.removeAttribute("disabled"),domCache.btnVoteDown.removeAttribute("disabled"));0==a?(domCache.btnVoteUp.classList.remove("active-fg-green"),domCache.btnVoteDown.classList.add("active-fg-red")):1==a?(domCache.btnVoteUp.classList.remove("active-fg-green"),domCache.btnVoteDown.classList.remove("active-fg-red")):
|
||||
2==a&&(domCache.btnVoteUp.classList.add("active-fg-green"),domCache.btnVoteDown.classList.remove("active-fg-red"))}
|
||||
function toggleAddToPlaylistFrm(){var a=document.getElementById("toggleAddToPlaylistBtn");toggleBtn("toggleAddToPlaylistBtn");a.classList.contains("active")?(document.getElementById("addToPlaylistFrm").classList.remove("hide"),document.getElementById("addStreamFooter").classList.add("hide"),document.getElementById("addToPlaylistFooter").classList.remove("hide")):(document.getElementById("addToPlaylistFrm").classList.add("hide"),document.getElementById("addStreamFooter").classList.remove("hide"),document.getElementById("addToPlaylistFooter").classList.add("hide"))}
|
||||
function showAddToPlaylist(a){document.getElementById("addToPlaylistUri").value=a;document.getElementById("addToPlaylistPlaylist").innerHTML="";document.getElementById("addToPlaylistNewPlaylistDiv").classList.add("hide");document.getElementById("addToPlaylistFrm").classList.remove("was-validated");document.getElementById("addToPlaylistNewPlaylist").classList.remove("is-invalid");toggleBtn("toggleAddToPlaylistBtn",0);var b=document.getElementById("streamUrl");b.focus();b.value="";b.classList.remove("is-invalid");
|
||||
document.getElementById("addStreamFrm").classList.remove("was-validated");"stream"!=a?(document.getElementById("addStreamFooter").classList.add("hide"),document.getElementById("addStreamFrm").classList.add("hide"),document.getElementById("addToPlaylistFooter").classList.remove("hide"),document.getElementById("addToPlaylistFrm").classList.remove("hide"),document.getElementById("addToPlaylistLabel").innerText="Add to playlist"):(document.getElementById("addStreamFooter").classList.remove("hide"),document.getElementById("addStreamFrm").classList.remove("hide"),
|
||||
@ -103,32 +109,34 @@ function addToPlaylist(){var a=document.getElementById("addToPlaylistUri").value
|
||||
function addStream(){var a=document.getElementById("streamUrl").value;""!=a&&0==a.indexOf("http")?(sendAPI({cmd:"MPD_API_ADD_TRACK",data:{uri:a}}),modalAddToPlaylist.hide(),showNotification("Added stream "+a+"to queue","","","success")):(document.getElementById("streamUrl").classList.add("is-invalid"),document.getElementById("addStreamFrm").classList.add("was-validated"))}
|
||||
function showRenamePlaylist(a){document.getElementById("renamePlaylistFrm").classList.remove("was-validated");document.getElementById("renamePlaylistTo").classList.remove("is-invalid");modalRenamePlaylist.show();document.getElementById("renamePlaylistFrom").value=a;document.getElementById("renamePlaylistTo").value=""}
|
||||
function renamePlaylist(){var a=document.getElementById("renamePlaylistFrom").value,b=document.getElementById("renamePlaylistTo").value,c=b.replace(/\w/g,"");""!=b&&b!=a&&""==c?(sendAPI({cmd:"MPD_API_PLAYLIST_RENAME",data:{from:a,to:b}}),modalRenamePlaylist.hide(),sendAPI({cmd:"MPD_API_GET_PLAYLISTS",data:{offset:app.current.page,filter:app.current.filter}},parsePlaylists)):(document.getElementById("renamePlaylistTo").classList.add("is-invalid"),document.getElementById("renamePlaylistFrm").classList.add("was-validated"))}
|
||||
function showMenu(a){var b=a.getAttribute("data-type"),c=decodeURI(a.getAttribute("data-uri")),e=a.getAttribute("data-name"),d=0;if(null==b||null==c)b=a.parentNode.parentNode.getAttribute("data-type"),c=decodeURI(a.parentNode.parentNode.getAttribute("data-uri")),e=a.parentNode.parentNode.getAttribute("data-name");last_state&&(d=last_state.data.nextsongpos);var f="";"Browse"==app.current.app&&"Filesystem"==app.current.tab||"Search"==app.current.app||"Browse"==app.current.app&&"Database"==app.current.tab&&
|
||||
function showMenu(a){var b=a.getAttribute("data-type"),c=decodeURI(a.getAttribute("data-uri")),e=a.getAttribute("data-name"),d=0;if(null==b||null==c)b=a.parentNode.parentNode.getAttribute("data-type"),c=decodeURI(a.parentNode.parentNode.getAttribute("data-uri")),e=a.parentNode.parentNode.getAttribute("data-name");lastState&&(d=lastState.data.nextsongpos);var f="";"Browse"==app.current.app&&"Filesystem"==app.current.tab||"Search"==app.current.app||"Browse"==app.current.app&&"Database"==app.current.tab&&
|
||||
"Album"==app.current.view?f+="<a class=\"dropdown-item\" href=\"#\" data-href=\"{'cmd': 'appendQueue', 'options': ['"+b+"','"+c+"','"+e+"']}\">Append to queue</a>"+("song"==b?"<a class=\"dropdown-item\" href=\"#\" data-href=\"{'cmd': 'appendAfterQueue', 'options': ['"+b+"','"+c+"',"+d+",'"+e+"']}\">Add after current playing song</a>":"")+"<a class=\"dropdown-item\" href=\"#\" data-href=\"{'cmd': 'replaceQueue', 'options': ['"+b+"','"+c+"','"+e+"']}\">Replace queue</a>"+("plist"!=b?"<div class=\"dropdown-divider\"></div><a class=\"dropdown-item\" href=\"#\" data-href=\"{'cmd': 'showAddToPlaylist', 'options': ['"+
|
||||
c+"']}\">Add to playlist</a>":"")+("dir"!=b?'<div class="dropdown-divider"></div>':"")+("song"==b?"<a class=\"dropdown-item\" data-href=\"{'cmd': 'songDetails', 'options': ['"+c+'\']}" href="#">Songdetails</a>':"")+("plist"==b?"<a class=\"dropdown-item\" href=\"#\" data-href=\"{'cmd': 'playlistDetails', 'options': ['"+c+"']}\">Show playlist</a>":""):"Browse"==app.current.app&&"Playlists"==app.current.tab&&"All"==app.current.view?f+="<a class=\"dropdown-item\" href=\"#\" data-href=\"{'cmd': 'appendQueue', 'options': ['"+
|
||||
b+"','"+c+"','"+e+"']}\">Append to queue</a><a class=\"dropdown-item\" href=\"#\" data-href=\"{'cmd': 'replaceQueue', 'options': ['"+b+"','"+c+"','"+e+"']}\">Replace queue</a><div class=\"dropdown-divider\"></div><a class=\"dropdown-item\" href=\"#\" data-href=\"{'cmd': 'playlistDetails', 'options': ['"+c+"']}\">Edit playlist</a><a class=\"dropdown-item\" href=\"#\" data-href=\"{'cmd': 'showRenamePlaylist', 'options': ['"+c+"']}\">Rename playlist</a><a class=\"dropdown-item\" href=\"#\" data-href=\"{'cmd': 'delPlaylist', 'options': ['"+
|
||||
c+"']}\">Delete playlist</a>":"Browse"==app.current.app&&"Playlists"==app.current.tab&&"Detail"==app.current.view?f+="<a class=\"dropdown-item\" href=\"#\" data-href=\"{'cmd': 'appendQueue', 'options': ['"+b+"','"+c+"','"+e+"']}\">Append to queue</a><a class=\"dropdown-item\" href=\"#\" data-href=\"{'cmd': 'replaceQueue', 'options': ['"+b+"','"+c+"','"+e+"']}\">Replace queue</a>"+("false"==document.getElementById("BrowsePlaylistsDetailList").getAttribute("data-ro")?"<div class=\"dropdown-divider\"></div><a class=\"dropdown-item\" href=\"#\" data-href=\"{'cmd': 'removeFromPlaylist', 'options': ['"+
|
||||
document.getElementById("BrowsePlaylistsDetailList").getAttribute("data-uri")+"', '"+a.parentNode.parentNode.getAttribute("data-songpos")+"']}\">Remove</a>":"")+("plist"!=b?"<div class=\"dropdown-divider\"></div><a class=\"dropdown-item\" href=\"#\" data-href=\"{'cmd': 'showAddToPlaylist', 'options': ['"+c+"']}\">Add to playlist</a>":""):"Queue"==app.current.app&&(f+="<a class=\"dropdown-item\" href=\"#\" data-href=\"{'cmd': 'delQueueSong', 'options': ['single',"+a.parentNode.parentNode.getAttribute("data-trackid")+
|
||||
"]}\">Remove</a><a class=\"dropdown-item\" href=\"#\" data-href=\"{'cmd': 'delQueueSong', 'options': ['range',0,"+a.parentNode.parentNode.getAttribute("data-songpos")+"]}\">Remove all upwards</a><a class=\"dropdown-item\" href=\"#\" data-href=\"{'cmd': 'delQueueSong', 'options': ['range',"+(parseInt(a.parentNode.parentNode.getAttribute("data-songpos"))-1)+',-1]}">Remove all downwards</a><div class="dropdown-divider"></div>'+(-1==c.indexOf("http")?"<a class=\"dropdown-item\" data-href=\"{'cmd': 'songDetails', 'options': ['"+
|
||||
c+'\']}" href="#">Songdetails</a>':""));void 0==a.Popover&&(new Popover(a,{trigger:"click",template:'<div class="popover" role="tooltip"><div class="arrow"></div><div class="popover-content">'+f+"</div></div>"}),b=a.Popover,a.addEventListener("shown.bs.popover",function(a){document.querySelector(".popover-content").addEventListener("click",function(a){a.preventDefault();a.stopPropagation();a=JSON.parse(a.target.getAttribute("data-href").replace(/'/g,'"'));if("function"===typeof window[a.cmd])switch(a.cmd){case "sendAPI":sendAPI.apply(null,
|
||||
c+'\']}" href="#">Songdetails</a>':""));void 0==a.Popover&&(new Popover(a,{trigger:"click",template:'<div class="popover" role="tooltip"><div class="arrow"></div><div class="popover-content">'+f+"</div></div>"}),b=a.Popover,a.addEventListener("shown.bs.popover",function(a){document.getElementsByClassName("popover-content")[0].addEventListener("click",function(a){a.preventDefault();a.stopPropagation();a=JSON.parse(a.target.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)},!1),b.show())}
|
||||
function sendAPI(a,b){var c=new XMLHttpRequest;c.open("POST","/api",!0);c.setRequestHeader("Content-type","application/json");c.onreadystatechange=function(){if(4==c.readyState)if(""!=c.responseText){var e=JSON.parse(c.responseText);"error"==e.type?(showNotification("Error",e.data,e.data,"danger"),console.log("Error: "+e.data)):"result"==e.type&&"ok"!=e.data?showNotification(e.data,"","","success"):void 0!=b&&"function"==typeof b&&b(e)}else console.log("Empty response for request: "+JSON.stringify(a))};
|
||||
c.send(JSON.stringify(a))}function openLocalPlayer(){window.open("/player.html#"+settings.mpdstream,"LocalPlayer")}function updateDB(){sendAPI({cmd:"MPD_API_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,c){"range"==a?sendAPI({cmd:"MPD_API_RM_RANGE",data:{start:b,end:c}}):"single"==a&&sendAPI({cmd:"MPD_API_RM_TRACK",data:{track:b}})}function delPlaylist(a){sendAPI({cmd:"MPD_API_RM_PLAYLIST",data:{uri:a}});sendAPI({cmd:"MPD_API_GET_PLAYLISTS",data:{offset:app.current.page,filter:app.current.filter}},parsePlaylists)}
|
||||
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")}
|
||||
c.send(JSON.stringify(a))}function openLocalPlayer(){window.open("/player.html#"+settings.mpdstream,"LocalPlayer")}function updateDB(){sendAPI({cmd:"MPD_API_UPDATE_DB"});updateDBstarted()}function updateDBstarted(){document.getElementById("updateDBfinished").innerText="";document.getElementById("updateDBfooter").classList.add("hide");modalUpdateDB.show();document.getElementById("updateDBprogress").classList.add("updateDBprogressAnimate")}
|
||||
function updateDBfinished(a){"update_database"==a?document.getElementById("updateDBfinished").innerText="Database successfully updated":"update_finished"==a&&(document.getElementById("updateDBfinished").innerText="Database update finished.");a=document.getElementById("updateDBprogress");a.classList.remove("updateDBprogressAnimate");a.style.width="100%";document.getElementById("updateDBfooter").classList.remove("hide")}
|
||||
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,c){"range"==a?sendAPI({cmd:"MPD_API_RM_RANGE",data:{start:b,end:c}}):"single"==a&&sendAPI({cmd:"MPD_API_RM_TRACK",data:{track:b}})}
|
||||
function delPlaylist(a){sendAPI({cmd:"MPD_API_RM_PLAYLIST",data:{uri:a}});sendAPI({cmd:"MPD_API_GET_PLAYLISTS",data:{offset:app.current.page,filter:app.current.filter}},parsePlaylists)}
|
||||
function confirmSettings(){var a=!0,b=document.getElementById("inputCrossfade");if(!b.getAttribute("disabled")){var c=parseInt(b.value);isNaN(c)?(b.classList.add("is-invalid"),a=!1):b.value=c}settings.mixramp&&(b=document.getElementById("inputMixrampdb"),b.getAttribute("disabled")||(c=parseFloat(b.value),isNaN(c)?(b.classList.add("is-invalid"),a=!1):b.value=c),b=document.getElementById("inputMixrampdelay"),b.getAttribute("disabled")||("nan"==b.value&&(b.value="-1"),c=parseFloat(b.value),isNaN(c)?
|
||||
(b.classList.add("is-invalid"),a=!1):b.value=c));1==a?(a=document.getElementById("selectReplaygain"),sendAPI({cmd:"MPD_API_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:1==settings.mixramp?document.getElementById("inputMixrampdb").value:settings.mixrampdb,mixrampdelay:1==settings.mixramp?document.getElementById("inputMixrampdelay").value:settings.mixrampdelay,notificationWeb:document.getElementById("btnnotifyWeb").classList.contains("active")?1:0,notificationPage:document.getElementById("btnnotifyPage").classList.contains("active")?1:0}},getSettings),modalSettings.hide()):document.getElementById("settingsFrm").classList.add("was-validated")}
|
||||
function addAllFromBrowse(){sendAPI({cmd:"MPD_API_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 addAllFromSearchPlist(a){if(2<=app.current.search.length){var b=app.current.filter;"Any Tag"==b&&(b="any");sendAPI({cmd:"MPD_API_SEARCH_ADD_PLIST",data:{plist:a,filter:b,searchstr:app.current.search}});showNotification("Added "+parseInt(document.getElementById("panel-heading-search").innerText)+" songs from search to "+a,"","","success")}}function scrollTo(a){document.body.scrollTop=a;document.documentElement.scrollTop=a}
|
||||
function 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 gotoPage(a){switch(a){case "next":app.current.page+=settings.maxElementsPerPage;break;case "prev":app.current.page-=settings.maxElementsPerPage;0>app.current.page&&(app.current.page=0);break;default:app.current.page=a}appGoto(app.current.app,app.current.tab,app.current.view,app.current.page+"/"+app.current.filter+"/"+app.current.search)}
|
||||
function saveQueue(){var a=document.getElementById("saveQueueName").value,b=a.replace(/\w/g,"");""!=a&&""==b?(sendAPI({cmd:"MPD_API_SAVE_QUEUE",data:{plist:a}}),modalSavequeue.hide()):(document.getElementById("saveQueueName").classList.add("is-invalid"),document.getElementById("saveQueueFrm").classList.add("was-validated"))}
|
||||
function showNotification(a,b,c,e){1==settings.notificationWeb&&(b=new Notification(a,{icon:"assets/favicon.ico",body:b}),setTimeout(function(a){a.close()},3E3,b));1==settings.notificationPage&&(document.getElementById("alertBox")?b=document.getElementById("alertBox"):(b=document.createElement("div"),b.setAttribute("id","alertBox"),b.addEventListener("click",function(){hideNotification()},!1)),b.classList.remove("alert-success","alert-danger"),b.classList.add("alert","alert-"+e),b.innerHTML="<div><strong>"+
|
||||
a+"</strong><br/>"+c+"</div>",document.getElementsByTagName("main")[0].append(b),document.getElementById("alertBox").classList.add("alertBoxActive"),alertTimeout&&clearTimeout(alertTimeout),alertTimeout=setTimeout(function(){hideNotification()},3E3))}function hideNotification(){document.getElementById("alertBox")&&(document.getElementById("alertBox").classList.remove("alertBoxActive"),setTimeout(function(){document.getElementById("alertBox").remove()},600))}
|
||||
a+"</strong><br/>"+c+"</div>",document.getElementsByTagName("main")[0].append(b),document.getElementById("alertBox").classList.add("alertBoxActive"),alertTimeout&&clearTimeout(alertTimeout),alertTimeout=setTimeout(function(){hideNotification()},3E3))}function hideNotification(){document.getElementById("alertBox")&&(document.getElementById("alertBox").classList.remove("alertBoxActive"),setTimeout(function(){var a=document.getElementById("alertBox");a&&a.remove()},600))}
|
||||
function notificationsSupported(){return"Notification"in window}
|
||||
function songChange(a){if("error"!=a.type&&"result"!=a.type){var b=a.data.title+a.data.artist+a.data.album+a.data.uri+a.data.currentsongid;if(last_song!=b){var c="",e="",d="myMPD: ";document.getElementById("currentCover").style.backgroundImage='url("'+a.data.cover+'")';"undefined"!=typeof a.data.artist&&0<a.data.artist.length&&"-"!=a.data.artist?(c+=a.data.artist,e+=a.data.artist,d+=a.data.artist+" - ",document.getElementById("currentArtist").innerText=a.data.artist):document.getElementById("currentArtist").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("currentAlbum").innerText=a.data.album):document.getElementById("currentAlbum").innerText="";"undefined"!=typeof a.data.title&&0<a.data.title.length?(d+=a.data.title,domCache.currentTrack.innerText=a.data.title,domCache.currentTrack.setAttribute("data-uri",a.data.uri)):(domCache.currentTrack.innerText="",domCache.currentTrack.setAttribute("data-uri",
|
||||
""));document.title=d;if(d=document.getElementById("queueTrackId"+a.data.currentsongid))d.getElementsByTagName("td")[1].innerText=a.data.title;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 songChange(a){if("error"!=a.type&&"result"!=a.type){var b=a.data.title+a.data.artist+a.data.album+a.data.uri+a.data.currentSongId;if(lastSong!=b){var c="",e="",d="myMPD: ";domCache.currentCover.style.backgroundImage='url("'+a.data.cover+'")';"undefined"!=typeof a.data.artist&&0<a.data.artist.length&&"-"!=a.data.artist?(c+=a.data.artist,e+=a.data.artist,d+=a.data.artist+" - ",domCache.currentArtist.innerText=a.data.artist,domCache.currentArtist.setAttribute("data-albumartist",a.data.albumartist)):
|
||||
domCache.currentArtist.innerText="";"undefined"!=typeof a.data.album&&0<a.data.album.length&&"-"!=a.data.album?(c+=" - "+a.data.album,e+="<br/>"+a.data.album,domCache.currentAlbum.innerText=a.data.album):domCache.currentAlbum.innerText="";"undefined"!=typeof a.data.title&&0<a.data.title.length?(d+=a.data.title,domCache.currentTrack.innerText=a.data.title,domCache.currentTrack.setAttribute("data-uri",a.data.uri)):(domCache.currentTrack.innerText="",domCache.currentTrack.setAttribute("data-uri",""));
|
||||
document.title=d;1==settings.stickers&&setVoteSongBtns(a.data.like,a.data.uri);if(d=document.getElementById("queueTrackId"+a.data.currentSongId))d.getElementsByTagName("td")[1].innerText=a.data.title;showNotification(a.data.title,c,e,"success");lastSong=b}}}
|
||||
function doSetFilterLetter(a){var b=document.getElementById(a+"Letters").getElementsByClassName("active")[0];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){for(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>',c=65;90>=c;c++)b+='<button class="mr-1 mb-1 btn-sm btn btn-secondary">'+String.fromCharCode(c)+"</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();
|
2
dist/htdocs/player.html
vendored
2
dist/htdocs/player.html
vendored
@ -1 +1 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="description" content="myMPD - fast and lightweight MPD webclient"><meta name="author" content="mail@jcgames.de"><title>myMPD: Local Player</title><link href="css/bootstrap.min.css" rel="stylesheet"><link href="css/mpd.min.css" rel="stylesheet"><link href="assets/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon"><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"/></head><body><header><nav class="navbar navbar-expand navbar-dark fixed-top bg-dark"><a class="navbar-brand" data-toggle="dropdown" href="#"><span class="material-icons header-logo">play_circle_outline</span>myMPD</a></nav></header><main role="main" class="container"><div class="card"><div class="card-header">Local Player</div><div class="card-body"><audio id="player" preload="none" controls=""></audio></div></div></main><script type="text/javascript" src="js/player.min.js"></script></body></html>
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="description" content="myMPD - fast and lightweight MPD webclient"><meta name="author" content="mail@jcgames.de"><title>myMPD: Local Player</title><link href="css/bootstrap.min.css" rel="stylesheet"><link href="css/mympd.min.css" rel="stylesheet"><link href="assets/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon"><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"/></head><body><header><nav class="navbar navbar-expand navbar-dark fixed-top bg-dark"><a class="navbar-brand" data-toggle="dropdown" href="#"><span class="material-icons header-logo">play_circle_outline</span>myMPD</a></nav></header><main role="main" class="container"><div class="card"><div class="card-header">Local Player</div><div class="card-body"><audio id="player" preload="none" controls=""></audio></div></div></main><script type="text/javascript" src="js/player.min.js"></script></body></html>
|
2
dist/htdocs/sw.min.js
vendored
2
dist/htdocs/sw.min.js
vendored
@ -10,5 +10,5 @@ function(){function a(a){return function(d){c||(c=!0,a.call(b,d))}}var b=this,c=
|
||||
void 0;try{d=a.then}catch(h){this.reject_(h);return}"function"==typeof d?this.settleSameAsThenable_(d,a):this.fulfill_(a)};c.prototype.reject_=function(a){this.settle_(2,a)};c.prototype.fulfill_=function(a){this.settle_(1,a)};c.prototype.settle_=function(a,b){if(0!=this.state_)throw Error("Cannot settle("+a+", "+b+"): Promise already settled in state"+this.state_);this.state_=a;this.result_=b;this.executeOnSettledCallbacks_()};c.prototype.executeOnSettledCallbacks_=function(){if(null!=this.onSettledCallbacks_){for(var a=
|
||||
0;a<this.onSettledCallbacks_.length;++a)l.asyncExecute(this.onSettledCallbacks_[a]);this.onSettledCallbacks_=null}};var l=new b;c.prototype.settleSameAsPromise_=function(a){var b=this.createResolveAndReject_();a.callWhenSettled_(b.resolve,b.reject)};c.prototype.settleSameAsThenable_=function(a,b){var c=this.createResolveAndReject_();try{a.call(b,c.resolve,c.reject)}catch(k){c.reject(k)}};c.prototype.then=function(a,b){function d(a,b){return"function"==typeof a?function(b){try{f(a(b))}catch(m){e(m)}}:
|
||||
b}var f,e,g=new c(function(a,b){f=a;e=b});this.callWhenSettled_(d(a,f),d(b,e));return g};c.prototype.catch=function(a){return this.then(void 0,a)};c.prototype.callWhenSettled_=function(a,b){function c(){switch(d.state_){case 1:a(d.result_);break;case 2:b(d.result_);break;default:throw Error("Unexpected state: "+d.state_);}}var d=this;null==this.onSettledCallbacks_?l.asyncExecute(c):this.onSettledCallbacks_.push(c)};c.resolve=f;c.reject=function(a){return new c(function(b,c){c(a)})};c.race=function(a){return new c(function(b,
|
||||
c){for(var d=$jscomp.makeIterator(a),e=d.next();!e.done;e=d.next())f(e.value).callWhenSettled_(b,c)})};c.all=function(a){var b=$jscomp.makeIterator(a),d=b.next();return d.done?f([]):new c(function(a,c){function e(b){return function(c){g[b]=c;h--;0==h&&a(g)}}var g=[],h=0;do g.push(void 0),h++,f(d.value).callWhenSettled_(e(g.length-1),c),d=b.next();while(!d.done)})};return c},"es6","es3");var CACHE="myMPD-cache-v3.5.0",urlsToCache="/ /player.html /css/bootstrap.min.css /css/mpd.min.css /js/bootstrap-native-v4.min.js /js/mpd.min.js /js/player.min.js /assets/appicon-167.png /assets/appicon-192.png /assets/appicon-512.png /assets/coverimage-httpstream.png /assets/coverimage-notavailable.png /assets/favicon.ico /assets/MaterialIcons-Regular.eot /assets/MaterialIcons-Regular.ttf /assets/MaterialIcons-Regular.woff /assets/MaterialIcons-Regular.woff2".split(" ");
|
||||
c){for(var d=$jscomp.makeIterator(a),e=d.next();!e.done;e=d.next())f(e.value).callWhenSettled_(b,c)})};c.all=function(a){var b=$jscomp.makeIterator(a),d=b.next();return d.done?f([]):new c(function(a,c){function e(b){return function(c){g[b]=c;h--;0==h&&a(g)}}var g=[],h=0;do g.push(void 0),h++,f(d.value).callWhenSettled_(e(g.length-1),c),d=b.next();while(!d.done)})};return c},"es6","es3");var CACHE="myMPD-cache-v4.0.0",urlsToCache="/ /player.html /css/bootstrap.min.css /css/mympd.min.css /js/bootstrap-native-v4.min.js /js/mympd.min.js /js/player.min.js /assets/appicon-167.png /assets/appicon-192.png /assets/appicon-512.png /assets/coverimage-httpstream.png /assets/coverimage-notavailable.png /assets/favicon.ico /assets/MaterialIcons-Regular.eot /assets/MaterialIcons-Regular.ttf /assets/MaterialIcons-Regular.woff /assets/MaterialIcons-Regular.woff2".split(" ");
|
||||
self.addEventListener("install",function(a){a.waitUntil(caches.open(CACHE).then(function(a){return a.addAll(urlsToCache)}))});self.addEventListener("fetch",function(a){a.respondWith(caches.match(a.request).then(function(b){return b?b:fetch(a.request)}))});self.addEventListener("activate",function(a){a.waitUntil(caches.keys().then(function(a){return Promise.all(a.map(function(a){if(a!=CACHE)return caches.delete(a)}))}))});
|
||||
|
@ -2,8 +2,16 @@ html {
|
||||
position: relative;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin-bottom: 60px;
|
||||
padding-top: 50px;
|
||||
padding-bottom: 50px;
|
||||
background-color: #888;
|
||||
}
|
||||
|
||||
main {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
footer {
|
||||
@ -11,12 +19,6 @@ footer {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
padding-top: 50px;
|
||||
padding-bottom: 50px;
|
||||
background-color:#888;
|
||||
}
|
||||
|
||||
button {
|
||||
overflow: hidden;
|
||||
}
|
||||
@ -30,14 +32,9 @@ button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#counter {
|
||||
font-size: 22px;
|
||||
margin-left: 10px;
|
||||
min-width: 50px;
|
||||
}
|
||||
|
||||
.card {
|
||||
min-height:350px;
|
||||
min-height: 350px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 576px) {
|
||||
@ -54,15 +51,30 @@ button {
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
small {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.card-footer-playback {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.album-cover {
|
||||
background-size:cover;
|
||||
border:1px solid black;
|
||||
border-radius:5px;
|
||||
overflow:hidden;
|
||||
margin-bottom:20px;
|
||||
width:240px;
|
||||
height:240px;
|
||||
background-color:#eee;
|
||||
background-size: cover;
|
||||
border: 1px solid black;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
width: 240px;
|
||||
height: 240px;
|
||||
background-color: #eee;
|
||||
float: left;
|
||||
margin-right: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.album-desc {
|
||||
min-width: 240px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.hide {
|
||||
@ -74,11 +86,11 @@ button {
|
||||
}
|
||||
|
||||
.card-toolbar {
|
||||
margin-bottom:10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.card-toolbar > div, .card-toolbar > form {
|
||||
margin-bottom:5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@ -117,111 +129,115 @@ button {
|
||||
}
|
||||
|
||||
.material-icons-small {
|
||||
font-size: 16px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
main {
|
||||
padding-top:20px;
|
||||
}
|
||||
|
||||
.color-darkgrey {
|
||||
color:#6c757d;
|
||||
}
|
||||
|
||||
.color-darkgrey:hover {
|
||||
color:#6c757d !important;
|
||||
.color-darkgrey, .color-darkgrey:hover {
|
||||
color:#6c757d !important;
|
||||
}
|
||||
|
||||
#btn-outputs-block > button {
|
||||
margin-bottom:10px;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
#btn-outputs-block > button:last-child {
|
||||
margin-bottom:0px;
|
||||
margin-bottom:0px;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
overflow-x:hidden;
|
||||
overflow-x:hidden;
|
||||
}
|
||||
|
||||
#progressBar {
|
||||
width:100%;
|
||||
margin-top:8px;
|
||||
.progressBarPlay {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
#counter {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
#volumeBar {
|
||||
margin-top:2px;
|
||||
width:160px;
|
||||
margin-top:2px;
|
||||
width:160px;
|
||||
}
|
||||
|
||||
.title-icon {
|
||||
float:left;
|
||||
margin-right:5px;
|
||||
font-size:1.8rem;
|
||||
float:left;
|
||||
margin-right:5px;
|
||||
font-size:1.8rem;
|
||||
}
|
||||
|
||||
.header-logo {
|
||||
font-size:2rem;
|
||||
float:left;
|
||||
margin-right:5px;
|
||||
font-size:2rem;
|
||||
float:left;
|
||||
margin-right:5px;
|
||||
}
|
||||
|
||||
.letters > button {
|
||||
width:28px;
|
||||
height:28px;
|
||||
width:28px;
|
||||
height:28px;
|
||||
}
|
||||
|
||||
.col-md {
|
||||
max-width:250px;
|
||||
min-width:250px;
|
||||
max-width:250px;
|
||||
min-width:250px;
|
||||
}
|
||||
|
||||
a.card-img-top {
|
||||
overflow:hidden;
|
||||
display:block;
|
||||
overflow:hidden;
|
||||
display:block;
|
||||
}
|
||||
|
||||
button.active {
|
||||
color: #fff;
|
||||
background-color: #28a745 !important;
|
||||
border-color: #28a745 !important;
|
||||
color: #fff;
|
||||
background-color: #28a745 !important;
|
||||
border-color: #28a745 !important;
|
||||
}
|
||||
|
||||
button.active-fg-green {
|
||||
color: #28a745 !important;
|
||||
}
|
||||
|
||||
button.active-fg-red {
|
||||
color: #bd2130 !important;
|
||||
}
|
||||
|
||||
div#alertBox {
|
||||
position:fixed;
|
||||
top: 50px;
|
||||
right:10px;
|
||||
width:80%;
|
||||
max-width:400px;
|
||||
z-index:1000;
|
||||
opacity:0;
|
||||
visibility:visible;
|
||||
transition:opacity 0.5s ease-in;
|
||||
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;
|
||||
opacity:1 !important;
|
||||
visibility:visible !important;
|
||||
transition:opacity 0.5s ease-in;
|
||||
}
|
||||
|
||||
.popover-content {
|
||||
padding-top:4px;
|
||||
padding-bottom:4px;
|
||||
padding-top:4px;
|
||||
padding-bottom:4px;
|
||||
}
|
||||
|
||||
.opacity05 {
|
||||
opacity:0.5;
|
||||
opacity:0.5;
|
||||
}
|
||||
|
||||
caption {
|
||||
caption-side: top;
|
||||
font-size: 120%;
|
||||
font-weight: bold;
|
||||
color: black;
|
||||
caption-side: top;
|
||||
font-size: 120%;
|
||||
font-weight: bold;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.dragover > td {
|
||||
border-top:25px solid transparent;
|
||||
border-top:25px solid transparent;
|
||||
}
|
||||
|
||||
[draggable] {
|
||||
@ -233,3 +249,17 @@ caption {
|
||||
-khtml-user-drag: element;
|
||||
-webkit-user-drag: element;
|
||||
}
|
||||
|
||||
@keyframes changewidth {
|
||||
from { margin-left: -20px; }
|
||||
to { margin-left: 100%; }
|
||||
}
|
||||
|
||||
#updateDBprogress {
|
||||
width:20px;
|
||||
}
|
||||
.updateDBprogressAnimate {
|
||||
animation-duration: 2s;
|
||||
animation-name: changewidth;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
@ -9,11 +9,11 @@
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="theme-color" content="#343a40">
|
||||
<link href="css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="css/mpd.css" rel="stylesheet">
|
||||
<link href="assets/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon">
|
||||
<link rel="manifest" href="mympd.webmanifest">
|
||||
<link rel="apple-touch-icon" href="assets/appicon-167.png">
|
||||
<link href="/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="/css/mympd.css" rel="stylesheet">
|
||||
<link href="/assets/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon">
|
||||
<link rel="manifest" href="/mympd.webmanifest">
|
||||
<link rel="apple-touch-icon" href="/assets/appicon-167.png">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
@ -23,37 +23,37 @@
|
||||
<span class="material-icons header-logo">play_circle_outline</span>myMPD
|
||||
</a>
|
||||
<div class="dropdown-menu bg-dark">
|
||||
<a id="nav-addstream" class="dropdown-item text-light bg-dark" href="#" data-href="{'cmd':'showAddToPlaylist','options':['stream']}">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>
|
||||
<a class="dropdown-item text-light bg-dark" href="#" data-href="{'cmd':'showAddToPlaylist','options':['stream']}">Add Stream</a>
|
||||
<a class="dropdown-item text-light bg-dark" href="#" data-href="{'cmd':'updateDB','options':[]}">Update Database</a>
|
||||
<a class="dropdown-item text-light bg-dark" href="#" data-href="{'cmd':'openLocalPlayer','options':[]}">Local Player</a>
|
||||
<a class="dropdown-item text-light bg-dark" href="#" data-toggle="modal" data-target="#modalSettings">Settings</a>
|
||||
<a class="dropdown-item text-light bg-dark" href="#" data-toggle="modal" data-target="#modalAbout">About</a>
|
||||
<a id="nav-add2homescreen" class="dropdown-item text-light bg-dark hide" href="#">Add2HomeScreen</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-toolbar col-auto pl-0 pr-0" role="toolbar">
|
||||
<div class="btn-group mr-2" role="group" id="playControlBtns">
|
||||
<div class="btn-toolbar col-auto pl-0 pr-0">
|
||||
<div class="btn-group mr-2" 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 data-href="{'cmd':'clickStop','options':[]}" id="btnStop" type="button" class="btn btn-secondary pl-2 pr-2 material-icons">
|
||||
stop
|
||||
</button>
|
||||
<button data-href="{'cmd':'clickPlay','options':[]}" id="btnPlay" type="button" class="btn btn-secondary pl-2 pr-2 material-icons">
|
||||
<button data-href="{'cmd':'clickPlay','options':[]}" id="btnPlay" type="button" class="btnPlay btn btn-secondary pl-2 pr-2 material-icons">
|
||||
pause
|
||||
</button>
|
||||
<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">
|
||||
<div class="btn-group">
|
||||
<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">
|
||||
<div class="btn-group">
|
||||
<button data-href="{'cmd':'chVolume','options':[-5]}" class="btn btn-secondary">−</button>
|
||||
<div class="btn btn-secondary">
|
||||
<input type="range" min="0" max="100" step="1" class="form-control-range" id="volumeBar">
|
||||
@ -70,41 +70,49 @@
|
||||
</header>
|
||||
<main class="container">
|
||||
<noscript>
|
||||
<div class="alert alert-danger" role="alert">JavaScript is disabled!</div>
|
||||
<div class="alert alert-danger">JavaScript is disabled!</div>
|
||||
</noscript>
|
||||
|
||||
<div class="card" id="cardPlayback">
|
||||
<div class="card-header">Playback</div>
|
||||
<div class="card-header">Playback
|
||||
<div class="btn-group btn-group-sm stickers pull-right">
|
||||
<button title="Dislike song" id="btnVoteDown" data-href="{'cmd': 'voteSong', 'options': ['0']}" class="btn btn-sm btn-light material-icons">thumb_down</button>
|
||||
<button title="Like song" id="btnVoteUp" data-href="{'cmd': 'voteSong', 'options': ['2']}" class="btn btn-sm btn-light material-icons">thumb_up</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="album-cover" id="currentCover"></div>
|
||||
<h1 id="currentTrack" data-href="{'cmd': 'songClick', 'options': []}"></h1>
|
||||
<h3 id="currentArtist" data-href="{'cmd': 'artistClick', 'options': []}"></h3>
|
||||
<h4 id="currentAlbum"></h4>
|
||||
<div class="row">
|
||||
<div class="col-8">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
<div class="album-desc">
|
||||
<h2 id="currentTrack" data-href="{'cmd': 'songClick', 'options': []}"></h2>
|
||||
<small>Artist</small>
|
||||
<h4 id="currentArtist" data-href="{'cmd': 'artistClick', 'options': []}"></h4>
|
||||
<small>Album</small>
|
||||
<h4 id="currentAlbum"></h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer card-footer-playback">
|
||||
<div class="d-flex align-items-center">
|
||||
<button data-href="{'cmd':'clickPlay','options':[]}" class="mr-1 ml-1 btn btn-light material-icons btnPlay progressBarPlay">pause</button>
|
||||
<input type="range" min="0" max="100" step="1" class="mr-1 ml-1 form-control-range flex-grow-1" id="progressBar">
|
||||
<div class="btn ml-1 mr-1" id="counter"> </div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card hide" id="cardQueue">
|
||||
<div class="card-header">
|
||||
<a href="#" data-target="#queue-buttons" class="text-dark">Queue</a>
|
||||
<span id="panel-heading-queue" class="text pull-right"></span>
|
||||
Queue<span id="panel-heading-queue" class="text pull-right"></span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="btn-toolbar card-toolbar" id="queue-buttons" role="toolbar">
|
||||
<div class="btn-toolbar card-toolbar" id="queue-buttons">
|
||||
<div class="btn-group mr-2">
|
||||
<button type="button" class="btn btn-secondary" data-toggle="modal" data-target="#modalSaveQueue" title="Save queue">
|
||||
<span class="material-icons">save</span>
|
||||
<button type="button" class="btn btn-secondary material-icons" data-toggle="modal" data-target="#modalSaveQueue" title="Save queue">
|
||||
save
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group mr-2">
|
||||
<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 type="button" class="btn btn-secondary material-icons" data-href="{'cmd': 'sendAPI', 'options': [{'cmd':'MPD_API_QUEUE_SHUFFLE'}]}" title="Shuffle queue">
|
||||
shuffle
|
||||
</button>
|
||||
</div>
|
||||
<div class="input-group mr-2">
|
||||
@ -117,7 +125,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form id="searchqueue" role="search">
|
||||
<form id="searchqueue">
|
||||
<div class="input-group mr-2">
|
||||
<input type="text" class="form-control" placeholder="Search Queue" id="searchqueuestr"/>
|
||||
<div class="input-group-append">
|
||||
@ -168,10 +176,10 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="btn-toolbar hide" id="QueueButtonsBottom" role="toolbar">
|
||||
<div class="btn-toolbar hide" id="QueueButtonsBottom">
|
||||
<div class="btn-group mr-2">
|
||||
<button type="button" class="btn btn-secondary" data-href="{'cmd':'scrollTo','options':[0]}" title="To top">
|
||||
<span class="material-icons">keyboard_arrow_up</span>
|
||||
<button type="button" class="btn btn-secondary material-icons" data-href="{'cmd':'scrollTo','options':[0]}" title="To top">
|
||||
keyboard_arrow_up
|
||||
</button>
|
||||
</div>
|
||||
<div id="QueuePaginationBottom" class="btn-group mr-2 dropup">
|
||||
@ -203,13 +211,13 @@
|
||||
</div>
|
||||
|
||||
<div class="card-body hide" id="cardBrowsePlaylists">
|
||||
<div class="btn-toolbar card-toolbar" id="BrowsePlaylistsButtons" role="toolbar">
|
||||
<div class="btn-toolbar card-toolbar" id="BrowsePlaylistsButtons">
|
||||
<div class="btn-group mr-2 hide">
|
||||
<button data-href="{'cmd': 'appGoto', 'options': ['Browse','Playlists','All']}" id="btnBrowsePlaylistsAll" type="button" class="btn btn-secondary">« Playlists</button>
|
||||
</div>
|
||||
<div class="btn-group mr-2 hide">
|
||||
<button id="btnPlaylistClear" type="button" class="btn btn-secondary" data-href="{'cmd': 'playlistClear', 'options': []}" title="Clear playlist">
|
||||
<span class="material-icons">clear_all</span>
|
||||
<button id="btnPlaylistClear" type="button" class="btn btn-secondary material-icons" data-href="{'cmd': 'playlistClear', 'options': []}" title="Clear playlist">
|
||||
clear_all
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group mr-2">
|
||||
@ -266,10 +274,10 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="btn-toolbar hide" id="BrowsePlaylistsButtonsBottom" role="toolbar">
|
||||
<div class="btn-toolbar hide" id="BrowsePlaylistsButtonsBottom">
|
||||
<div class="btn-group mr-2">
|
||||
<button type="button" class="btn btn-secondary" data-href="{'cmd': 'scrollTo', 'options': [0]}" title="To top">
|
||||
<span class="material-icons">keyboard_arrow_up</span>
|
||||
<button type="button" class="btn btn-secondary material-icons" data-href="{'cmd': 'scrollTo', 'options': [0]}" title="To top">
|
||||
keyboard_arrow_up
|
||||
</button>
|
||||
</div>
|
||||
<div id="BrowsePlaylistsPaginationBottom" class="btn-group mr-2 dropup">
|
||||
@ -285,7 +293,7 @@
|
||||
</div>
|
||||
|
||||
<div class="card-body hide" id="cardBrowseDatabase">
|
||||
<div class="btn-toolbar card-toolbar" id="BrowseDatabaseButtons" role="toolbar">
|
||||
<div class="btn-toolbar card-toolbar" id="BrowseDatabaseButtons">
|
||||
<div class="btn-group mr-2 hide">
|
||||
<button data-href="{'cmd': 'appGoto', 'options': ['Browse','Database','Artist']}" id="btnBrowseDatabaseArtist" type="button" class="btn btn-secondary">« Artists</button>
|
||||
</div>
|
||||
@ -309,12 +317,10 @@
|
||||
<table id="BrowseDatabaseArtistList" class="table table-hover table-sm">
|
||||
<col class="tblnum"/>
|
||||
<col class="tbltitle"/>
|
||||
<col class="tblaction"/>
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Artist</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="clickable">
|
||||
@ -324,10 +330,10 @@
|
||||
|
||||
<div id="BrowseDatabaseAlbumList" class="row hide"></div>
|
||||
|
||||
<div class="btn-toolbar hide" id="BrowseDatabaseButtonsBottom" role="toolbar">
|
||||
<div class="btn-toolbar hide" id="BrowseDatabaseButtonsBottom">
|
||||
<div class="btn-group mr-2">
|
||||
<button type="button" class="btn btn-secondary" data-href="{'cmd': 'scrollTo', 'options': [0]}" title="To top">
|
||||
<span class="material-icons">keyboard_arrow_up</span>
|
||||
<button type="button" class="btn btn-secondary material-icons" data-href="{'cmd': 'scrollTo', 'options': [0]}" title="To top">
|
||||
keyboard_arrow_up
|
||||
</button>
|
||||
</div>
|
||||
<div id="BrowseDatabasePaginationBottom" class="btn-group mr-2 dropup">
|
||||
@ -344,7 +350,7 @@
|
||||
</div>
|
||||
|
||||
<div class="card-body hide" id="cardBrowseFilesystem">
|
||||
<div class="btn-toolbar card-toolbar" id="BrowseFilesystemButtons" role="toolbar">
|
||||
<div class="btn-toolbar card-toolbar" id="BrowseFilesystemButtons">
|
||||
<div class="btn-group mr-2">
|
||||
<button id="BrowseFilesystemFilter" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Filter</button>
|
||||
<div class="dropdown-menu bg-dark px-2 letters" id="BrowseFilesystemFilterLetters">
|
||||
@ -396,10 +402,10 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="btn-toolbar hide" id="BrowseFilesystemButtonsBottom" role="toolbar">
|
||||
<div class="btn-toolbar hide" id="BrowseFilesystemButtonsBottom">
|
||||
<div class="btn-group mr-2">
|
||||
<button type="button" class="btn btn-secondary" data-href="{'cmd': 'scrollTo', 'options': [0]}" title="To top">
|
||||
<span class="material-icons">keyboard_arrow_up</span>
|
||||
<button type="button" class="btn btn-secondary material-icons" data-href="{'cmd': 'scrollTo', 'options': [0]}" title="To top">
|
||||
keyboard_arrow_up
|
||||
</button>
|
||||
</div>
|
||||
<div id="BrowseFilesystemPaginationBottom" class="btn-group mr-2 dropup">
|
||||
@ -416,12 +422,13 @@
|
||||
</div>
|
||||
|
||||
<div class="card hide" id="cardSearch">
|
||||
<div class="card-header">Search
|
||||
<div class="card-header">
|
||||
Search
|
||||
<span id="panel-heading-search" class="text pull-right"></span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="btn-toolbar card-toolbar" id="SearchButtons" role="toolbar">
|
||||
<form id="search" role="search">
|
||||
<div class="btn-toolbar card-toolbar" id="SearchButtons">
|
||||
<form id="search">
|
||||
<div class="input-group mr-2">
|
||||
<input type="text" class="form-control" placeholder="Search" id="searchstr"/>
|
||||
<div class="input-group-append">
|
||||
@ -481,10 +488,10 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="btn-toolbar hide" id="SearchButtonsBottom" role="toolbar">
|
||||
<div class="btn-toolbar hide" id="SearchButtonsBottom">
|
||||
<div class="btn-group mr-2">
|
||||
<button type="button" class="btn btn-secondary" data-href="{'cmd': 'scrollTo', 'options': [0]}" title="To top">
|
||||
<span class="material-icons">keyboard_arrow_up</span>
|
||||
<button type="button" class="btn btn-secondary material-icons" data-href="{'cmd': 'scrollTo', 'options': [0]}" title="To top">
|
||||
keyboard_arrow_up
|
||||
</button>
|
||||
</div>
|
||||
<div id="SearchPaginationBottom" class="btn-group mr-2 dropup">
|
||||
@ -513,8 +520,8 @@
|
||||
</footer>
|
||||
|
||||
<!-- Modals -->
|
||||
<div class="modal fade" id="modalConnectionError" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal fade" id="modalConnectionError" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-danger text-light">
|
||||
<h5 class="modal-title"><span class="material-icons title-icon">error</span> Connection Error</h5>
|
||||
@ -526,14 +533,34 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="modalAddToPlaylist" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal fade" id="modalUpdateDB" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><span class="material-icons title-icon">update</span> Updating MPD database</h5>
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Dependent on the size of your music collection this can take a while.</p>
|
||||
<div class="progress">
|
||||
<div id="updateDBprogress" class="progress-bar bg-success" role="progressbar"></div>
|
||||
</div>
|
||||
<br/>
|
||||
<p id="updateDBfinished"></p>
|
||||
</div>
|
||||
<div class="modal-footer hide" id="updateDBfooter">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="modalAddToPlaylist" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><span class="material-icons title-icon">playlist_add</span> <span id="addToPlaylistLabel">Add to playlist</span></h5>
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="addStreamFrm" class="needs-validation hide" novalidate>
|
||||
@ -572,19 +599,17 @@
|
||||
<div class="modal-footer hide" id="addStreamFooter">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-success" data-href="{'cmd': 'addStream', 'options': []}">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="modalRenamePlaylist" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal fade" id="modalRenamePlaylist" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><span class="material-icons title-icon">playlist_add</span>Rename playlist</h5>
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="needs-validation" id="renamePlaylistFrm" novalidate>
|
||||
@ -607,14 +632,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="modalSettings" tabindex="-1" role="dialog">
|
||||
<div class="modal fade" id="modalSettings" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="settingsLabel"><span class="material-icons title-icon">settings</span> Settings</h5>
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="needs-validation" id="settingsFrm" novalidate>
|
||||
@ -661,7 +684,7 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="row mixramp">
|
||||
<div class="form-group input-group col-md-6 border-secondary">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text bg-secondary text-light border-secondary">Mixramp DB</div>
|
||||
@ -700,14 +723,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="modalAbout" tabindex="-1" role="dialog">
|
||||
<div class="modal fade" id="modalAbout" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="aboutLabel"><span class="material-icons title-icon">play_circle_outline</span> About</h5>
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<h4><a class="text-success" rel="noreferrer" href="https://github.com/jcorporation/ympd">myMPD</a> – <small>MPD Web GUI - written in C, utilizing Websockets and Bootstrap/JS</small></h4>
|
||||
@ -723,8 +744,8 @@
|
||||
<tr><th>Artists</th><td id="mpdstats_artists"></td></tr>
|
||||
<tr><th>Albums</th><td id="mpdstats_albums"></td></tr>
|
||||
<tr><th>Songs</th><td id="mpdstats_songs"></td></tr>
|
||||
<tr><th>DB Play Time</th><td id="mpdstats_dbplaytime"></td></tr>
|
||||
<tr><th>DB Updated</th><td id="mpdstats_dbupdated"></td></tr>
|
||||
<tr><th>DB Play Time</th><td id="mpdstats_dbPlaytime"></td></tr>
|
||||
<tr><th>DB Updated</th><td id="mpdstats_dbUpdated"></td></tr>
|
||||
<tr><td colspan="2" class="pt-3"><h5>Play Statistics</h5></td></tr>
|
||||
<tr><th>Uptime</th><td id="mpdstats_uptime"></td></tr>
|
||||
<tr><th>Play Time</th><td id="mpdstats_playtime"></td></tr>
|
||||
@ -737,14 +758,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="modalSaveQueue" tabindex="-1" role="dialog">
|
||||
<div class="modal fade" id="modalSaveQueue" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><span class="material-icons title-icon">save</span> Save Queue</h5>
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="needs-validation" id="saveQueueFrm" novalidate>
|
||||
@ -765,27 +784,30 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="modalSongDetails" tabindex="-1" role="dialog">
|
||||
<div class="modal fade" id="modalSongDetails" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><span class="material-icons title-icon">music_note</span> Song Details</h5>
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="album-cover"></div>
|
||||
<h1></h1>
|
||||
<table class="table">
|
||||
<table class="table table-sm">
|
||||
<tbody>
|
||||
<tr data-name="artist"><td>Artist</td><td></td></tr>
|
||||
<tr data-name="album"><td>Album</td><td></td></tr>
|
||||
<tr data-name="track"><td>Track</td><td></td></tr>
|
||||
<tr data-name="albumartist"><td>Albumartist</td><td></td></tr>
|
||||
<tr data-name="genre"><td>Genre</td><td></td></tr>
|
||||
<tr data-name="date"><td>Date</td><td></td></tr>
|
||||
<tr data-name="uri"><td>Uri</td><td></td></tr>
|
||||
<tr data-name="artist"><th>Artist</th><td></td></tr>
|
||||
<tr data-name="album"><th>Album</th><td></td></tr>
|
||||
<tr data-name="track"><th>Track</th><td></td></tr>
|
||||
<tr data-name="albumartist"><th>Albumartist</th><td></td></tr>
|
||||
<tr data-name="genre"><th>Genre</th><td></td></tr>
|
||||
<tr data-name="date"><th>Date</th><td></td></tr>
|
||||
<tr data-name="uri"><th>Uri</th><td></td></tr>
|
||||
<tr class="stickers"><th colspan="2">Statistics</th></tr>
|
||||
<tr class="stickers" data-name="playCount"><th>Play count</th><td></td></tr>
|
||||
<tr class="stickers" data-name="skipCount"><th>Skip count</th><td></td></tr>
|
||||
<tr class="stickers" data-name="lastPlayed"><th>Last played</th><td></td></tr>
|
||||
<tr class="stickers" data-name="like"><th>Like</th><td></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@ -796,7 +818,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="js/bootstrap-native-v4.min.js"></script>
|
||||
<script src="js/mpd.js"></script>
|
||||
<script src="/js/bootstrap-native-v4.min.js"></script>
|
||||
<script src="/js/mympd.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@
|
||||
<meta name="author" content="mail@jcgames.de">
|
||||
<title>myMPD: Local Player</title>
|
||||
<link href="css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="css/mpd.css" rel="stylesheet">
|
||||
<link href="css/mympd.css" rel="stylesheet">
|
||||
<link href="assets/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
|
||||
|
@ -1,11 +1,11 @@
|
||||
var CACHE = 'myMPD-cache-v3.5.0';
|
||||
var CACHE = 'myMPD-cache-v4.0.0';
|
||||
var urlsToCache = [
|
||||
'/',
|
||||
'/player.html',
|
||||
'/css/bootstrap.min.css',
|
||||
'/css/mpd.css',
|
||||
'/css/mympd.css',
|
||||
'/js/bootstrap-native-v4.min.js',
|
||||
'/js/mpd.js',
|
||||
'/js/mympd.js',
|
||||
'/js/player.js',
|
||||
'/assets/appicon-167.png',
|
||||
'/assets/appicon-192.png',
|
||||
|
52
mkrelease.sh
52
mkrelease.sh
@ -7,16 +7,16 @@ then
|
||||
echo "Minifying javascript"
|
||||
[ htdocs/js/player.js -nt dist/htdocs/js/player.min.js ] && \
|
||||
java -jar dist/buildtools/closure-compiler.jar htdocs/js/player.js > dist/htdocs/js/player.min.js
|
||||
[ htdocs/js/mpd.js -nt dist/htdocs/js/mpd.min.js ] && \
|
||||
java -jar dist/buildtools/closure-compiler.jar htdocs/js/mpd.js > dist/htdocs/js/mpd.min.js
|
||||
[ htdocs/js/mympd.js -nt dist/htdocs/js/mympd.min.js ] && \
|
||||
java -jar dist/buildtools/closure-compiler.jar htdocs/js/mympd.js > dist/htdocs/js/mympd.min.js
|
||||
[ htdocs/sw.js -nt dist/htdocs/sw.min.js ] && \
|
||||
java -jar dist/buildtools/closure-compiler.jar htdocs/sw.js > dist/htdocs/sw.min.js
|
||||
else
|
||||
echo "dist/buildtools/closure-compiler.jar not found, using non-minified files"
|
||||
[ htdocs/js/player.js -nt dist/htdocs/js/player.min.js ] && \
|
||||
cp htdocs/js/player.js dist/htdocs/js/player.min.js
|
||||
[ htdocs/js/mpd.js -nt dist/htdocs/js/mpd.min.js ] && \
|
||||
cp htdocs/js/mpd.js dist/htdocs/js/mpd.min.js
|
||||
[ htdocs/js/mympd.js -nt dist/htdocs/js/mympd.min.js ] && \
|
||||
cp htdocs/js/mympd.js dist/htdocs/js/mympd.min.js
|
||||
[ htdocs/sw.js -nt dist/htdocs/sw.min.js ] && \
|
||||
cp htdocs/sw.js dist/htdocs/sw.min.js
|
||||
fi
|
||||
@ -24,19 +24,19 @@ fi
|
||||
if [ -f dist/buildtools/closure-stylesheets.jar ] && [ "$java" != "" ]
|
||||
then
|
||||
echo "Minifying stylesheets"
|
||||
[ htdocs/css/mpd.css -nt dist/htdocs/css/mpd.min.css ] && \
|
||||
java -jar dist/buildtools/closure-stylesheets.jar --allow-unrecognized-properties htdocs/css/mpd.css > dist/htdocs/css/mpd.min.css
|
||||
[ htdocs/css/mympd.css -nt dist/htdocs/css/mympd.min.css ] && \
|
||||
java -jar dist/buildtools/closure-stylesheets.jar --allow-unrecognized-properties htdocs/css/mympd.css > dist/htdocs/css/mympd.min.css
|
||||
else
|
||||
echo "dist/buildtools/closure-stylesheets.jar not found, using non-minified files"
|
||||
[ htdocs/css/mpd.css -nt dist/htdocs/css/mpd.min.css ] && \
|
||||
cp htdocs/css/mpd.css dist/htdocs/css/mpd.min.css
|
||||
[ htdocs/css/mympd.css -nt dist/htdocs/css/mympd.min.css ] && \
|
||||
cp htdocs/css/mympd.css dist/htdocs/css/mympd.min.css
|
||||
fi
|
||||
|
||||
echo "Replacing javascript and stylesheets with minified files"
|
||||
sed -e 's/mpd\.css/mpd\.min\.css/' -e 's/mpd\.js/mpd\.min\.js/' htdocs/index.html > dist/htdocs/index.html
|
||||
sed -e 's/mpd\.css/mpd\.min\.css/' -e 's/player\.js/player\.min\.js/' htdocs/player.html > dist/htdocs/player.html
|
||||
sed -i -e 's/mpd\.css/mpd\.min\.css/' -e 's/mpd\.js/mpd\.min\.js/' -e 's/player\.js/player\.min\.js/' dist/htdocs/sw.min.js
|
||||
sed -i -e 's/\/sw\.js/\/sw\.min\.js/' dist/htdocs/js/mpd.min.js
|
||||
sed -e 's/mympd\.css/mympd\.min\.css/' -e 's/mympd\.js/mympd\.min\.js/' htdocs/index.html > dist/htdocs/index.html
|
||||
sed -e 's/mympd\.css/mympd\.min\.css/' -e 's/player\.js/player\.min\.js/' htdocs/player.html > dist/htdocs/player.html
|
||||
sed -i -e 's/mympd\.css/mympd\.min\.css/' -e 's/mympd\.js/mympd\.min\.js/' -e 's/player\.js/player\.min\.js/' dist/htdocs/sw.min.js
|
||||
sed -i -e 's/\/sw\.js/\/sw\.min\.js/' dist/htdocs/js/mympd.min.js
|
||||
echo "Minifying html"
|
||||
perl -i -pe 's/^\s*//gm; s/\s*$//gm' dist/htdocs/index.html
|
||||
perl -i -pe 's/^\s*//gm; s/\s*$//gm' dist/htdocs/player.html
|
||||
@ -55,21 +55,33 @@ sudo chown nobody /var/lib/mympd
|
||||
echo "Trying to link musicdir to library"
|
||||
if [ -f /etc/mpd.conf ]
|
||||
then
|
||||
LIBRARY=$(grep music /etc/mpd.conf | awk {'print $2'} | sed -e 's/"//g')
|
||||
[ "$LIBRARY" != "" ] && [ ! -e /usr/share/mympd/htdocs/library ] && ln -s "$LIBRARY" /usr/share/mympd/htdocs/library
|
||||
LIBRARY=$(grep ^music_directory /etc/mpd.conf | awk {'print $2'} | sed -e 's/"//g')
|
||||
[ "$LIBRARY" != "" ] && [ ! -e /usr/share/mympd/htdocs/library ] && sudo ln -s "$LIBRARY" /usr/share/mympd/htdocs/library
|
||||
else
|
||||
echo "/etc/mpd.conf not found, you must link your musicdir manually to /usr/share/mympd/htdocs/library"
|
||||
echo "/etc/mpd.conf not found, you must link your music_directory manually to /usr/share/mympd/htdocs/library"
|
||||
fi
|
||||
|
||||
echo "Creating dir for cover pictures"
|
||||
[ -d /usr/share/mympd/htdocs/pics ] || mkdir /usr/share/mympd/htdocs/pics
|
||||
|
||||
echo "Installing systemd service"
|
||||
if [ -d /etc/systemd/system ]
|
||||
then
|
||||
if [ contrib/mympd.service -nt /etc/systemd/system/mympd.service ]
|
||||
then
|
||||
sudo cp -v contrib/mympd.service /etc/systemd/system/
|
||||
systemctl daemon-reload
|
||||
sudo cp contrib/mympd.service /etc/systemd/system/
|
||||
sudo systemctl daemon-reload
|
||||
fi
|
||||
systemctl enable mympd
|
||||
sudo systemctl enable mympd
|
||||
fi
|
||||
|
||||
if [ -f /etc/mympd/mympd.conf ]
|
||||
then
|
||||
echo "/etc/mympd/mympd.conf already exists"
|
||||
cp contrib/mympd.conf /etc/mympd/mympd.conf.dist
|
||||
else
|
||||
[ -d /etc/mympd ] || mkdir /etc/mympd
|
||||
cp contrib/mympd.conf /etc/mympd/mympd.conf
|
||||
fi
|
||||
|
||||
if [ -d /etc/mympd/ssl ]
|
||||
@ -79,6 +91,6 @@ else
|
||||
echo "Creating certificates"
|
||||
contrib/crcert.sh
|
||||
fi
|
||||
|
||||
|
||||
echo "myMPD installed"
|
||||
echo "Edit /etc/mympd/mympd.conf before starting mympd"
|
||||
echo "Edit /etc/mympd/mympd.conf before starting myMPD"
|
||||
|
931
src/mpd_client.c
931
src/mpd_client.c
File diff suppressed because it is too large
Load Diff
162
src/mpd_client.h
162
src/mpd_client.h
@ -37,6 +37,11 @@
|
||||
return len; \
|
||||
} while (0)
|
||||
|
||||
#define LOG_ERROR_AND_RECOVER(X) do { \
|
||||
fprintf(stderr, "MPD X: %s\n", mpd_connection_get_error_message(mpd.conn)); \
|
||||
if (!mpd_connection_clear_error(mpd.conn)) \
|
||||
mpd.conn_state = MPD_FAILURE; \
|
||||
} while (0)
|
||||
|
||||
#define MAX_SIZE 1024 * 100
|
||||
#define MAX_ELEMENTS_PER_PAGE 100
|
||||
@ -44,54 +49,56 @@
|
||||
#define GEN_ENUM(X) X,
|
||||
#define GEN_STR(X) #X,
|
||||
#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_RM_PLAYLIST_TRACK) \
|
||||
X(MPD_API_QUEUE_CLEAR) \
|
||||
X(MPD_API_QUEUE_CROP) \
|
||||
X(MPD_API_QUEUE_SAVE) \
|
||||
X(MPD_API_QUEUE_LIST) \
|
||||
X(MPD_API_QUEUE_SEARCH) \
|
||||
X(MPD_API_QUEUE_RM_TRACK) \
|
||||
X(MPD_API_QUEUE_RM_RANGE) \
|
||||
X(MPD_API_QUEUE_MOVE_TRACK) \
|
||||
X(MPD_API_QUEUE_ADD_TRACK_AFTER) \
|
||||
X(MPD_API_QUEUE_ADD_TRACK) \
|
||||
X(MPD_API_QUEUE_ADD_PLAY_TRACK) \
|
||||
X(MPD_API_QUEUE_REPLACE_TRACK) \
|
||||
X(MPD_API_QUEUE_ADD_PLAYLIST) \
|
||||
X(MPD_API_QUEUE_REPLACE_PLAYLIST) \
|
||||
X(MPD_API_QUEUE_SHUFFLE) \
|
||||
X(MPD_API_PLAYLIST_RM) \
|
||||
X(MPD_API_PLAYLIST_CLEAR) \
|
||||
X(MPD_API_PLAYLIST_RENAME) \
|
||||
X(MPD_API_PLAYLIST_MOVE_TRACK) \
|
||||
X(MPD_API_ADD_TO_PLAYLIST) \
|
||||
X(MPD_API_PLAY_TRACK) \
|
||||
X(MPD_API_SAVE_QUEUE) \
|
||||
X(MPD_API_RM_TRACK) \
|
||||
X(MPD_API_RM_RANGE) \
|
||||
X(MPD_API_QUEUE_CLEAR) \
|
||||
X(MPD_API_QUEUE_CROP) \
|
||||
X(MPD_API_MOVE_TRACK) \
|
||||
X(MPD_API_SEARCH_QUEUE) \
|
||||
X(MPD_API_SEARCH_ADD_PLIST) \
|
||||
X(MPD_API_SEARCH_ADD) \
|
||||
X(MPD_API_SEARCH) \
|
||||
X(MPD_API_SEND_MESSAGE) \
|
||||
X(MPD_API_SET_VOLUME) \
|
||||
X(MPD_API_SET_PAUSE) \
|
||||
X(MPD_API_SET_PLAY) \
|
||||
X(MPD_API_SET_STOP) \
|
||||
X(MPD_API_SET_SEEK) \
|
||||
X(MPD_API_SET_NEXT) \
|
||||
X(MPD_API_SET_PREV) \
|
||||
X(MPD_API_UPDATE_DB) \
|
||||
X(MPD_API_GET_OUTPUTS) \
|
||||
X(MPD_API_TOGGLE_OUTPUT) \
|
||||
X(MPD_API_SEND_SHUFFLE) \
|
||||
X(MPD_API_GET_STATS) \
|
||||
X(MPD_API_GET_PLAYLISTS) \
|
||||
X(MPD_API_GET_PLAYLIST_LIST) \
|
||||
X(MPD_API_RM_PLAYLIST) \
|
||||
X(MPD_API_GET_ARTISTALBUMS) \
|
||||
X(MPD_API_GET_ARTISTALBUMTITLES) \
|
||||
X(MPD_API_GET_ARTISTS) \
|
||||
X(MPD_API_GET_CURRENT_SONG) \
|
||||
X(MPD_API_GET_SONGDETAILS) \
|
||||
X(MPD_API_PLAYLIST_ADD_TRACK) \
|
||||
X(MPD_API_PLAYLIST_RM_TRACK) \
|
||||
X(MPD_API_PLAYLIST_LIST) \
|
||||
X(MPD_API_PLAYLIST_CONTENT_LIST) \
|
||||
X(MPD_API_DATABASE_SEARCH_ADD_PLAYLIST) \
|
||||
X(MPD_API_DATABASE_SEARCH_ADD_QUEUE) \
|
||||
X(MPD_API_DATABASE_SEARCH) \
|
||||
X(MPD_API_DATABASE_UPDATE) \
|
||||
X(MPD_API_DATABASE_FILESYSTEM_LIST) \
|
||||
X(MPD_API_DATABASE_ARTISTALBUM_LIST) \
|
||||
X(MPD_API_DATABASE_ARTISTALBUMTITLE_LIST) \
|
||||
X(MPD_API_DATABASE_ARTIST_LIST) \
|
||||
X(MPD_API_DATABASE_STATS) \
|
||||
X(MPD_API_DATABASE_SONGDETAILS) \
|
||||
X(MPD_API_PLAYER_PLAY_TRACK) \
|
||||
X(MPD_API_PLAYER_VOLUME) \
|
||||
X(MPD_API_PLAYER_PAUSE) \
|
||||
X(MPD_API_PLAYER_PLAY) \
|
||||
X(MPD_API_PLAYER_STOP) \
|
||||
X(MPD_API_PLAYER_SEEK) \
|
||||
X(MPD_API_PLAYER_NEXT) \
|
||||
X(MPD_API_PLAYER_PREV) \
|
||||
X(MPD_API_PLAYER_OUTPUT_LIST) \
|
||||
X(MPD_API_PLAYER_TOGGLE_OUTPUT) \
|
||||
X(MPD_API_PLAYER_CURRENT_SONG) \
|
||||
X(MPD_API_PLAYER_STATE) \
|
||||
X(MPD_API_SETTINGS_GET) \
|
||||
X(MPD_API_SETTINGS_SET) \
|
||||
X(MPD_API_MESSAGE_SEND) \
|
||||
X(MPD_API_WELCOME) \
|
||||
X(MPD_API_GET_SETTINGS) \
|
||||
X(MPD_API_SET_SETTINGS) \
|
||||
X(MPD_API_LIKE) \
|
||||
X(MPD_API_UNKNOWN)
|
||||
|
||||
enum mpd_cmd_ids {
|
||||
@ -116,43 +123,59 @@ struct t_mpd {
|
||||
|
||||
int song_id;
|
||||
int next_song_id;
|
||||
int last_song_id;
|
||||
unsigned queue_version;
|
||||
unsigned queue_length;
|
||||
int timeout;
|
||||
|
||||
int last_update_sticker_song_id;
|
||||
} mpd;
|
||||
|
||||
typedef struct {
|
||||
int mpdport;
|
||||
const char* mpdhost;
|
||||
const char* mpdpass;
|
||||
const char* webport;
|
||||
bool ssl;
|
||||
const char* sslport;
|
||||
const char* sslcert;
|
||||
const char* sslkey;
|
||||
const char* user;
|
||||
int streamport;
|
||||
const char* coverimage;
|
||||
const char* statefile;
|
||||
} configuration;
|
||||
long mpdport;
|
||||
const char* mpdhost;
|
||||
const char* mpdpass;
|
||||
const char* webport;
|
||||
bool ssl;
|
||||
const char* sslport;
|
||||
const char* sslcert;
|
||||
const char* sslkey;
|
||||
const char* user;
|
||||
long streamport;
|
||||
const char* coverimage;
|
||||
const char* statefile;
|
||||
bool stickers;
|
||||
bool mixramp;
|
||||
} t_config;
|
||||
|
||||
configuration config;
|
||||
t_config config;
|
||||
|
||||
typedef struct {
|
||||
long playCount;
|
||||
long skipCount;
|
||||
long lastPlayed;
|
||||
long like;
|
||||
} t_sticker;
|
||||
|
||||
static int is_websocket(const struct mg_connection *nc) {
|
||||
return nc->flags & MG_F_IS_WEBSOCKET;
|
||||
return nc->flags & MG_F_IS_WEBSOCKET;
|
||||
}
|
||||
|
||||
struct t_mpd_client_session {
|
||||
int song_id;
|
||||
int next_song_id;
|
||||
unsigned queue_version;
|
||||
};
|
||||
|
||||
void mympd_poll(struct mg_mgr *s);
|
||||
void mympd_idle(struct mg_mgr *sm, int timeout);
|
||||
void mympd_parse_idle(struct mg_mgr *s, int idle_bitmask);
|
||||
void callback_mympd(struct mg_connection *nc, const struct mg_str msg);
|
||||
int mympd_close_handler(struct mg_connection *c);
|
||||
int mympd_put_state(char *buffer, int *current_song_id, int *next_song_id, unsigned *queue_version);
|
||||
void mympd_notify(struct mg_mgr *s);
|
||||
void mympd_count_song_id(int song_id, char *name, int value);
|
||||
void mympd_count_song_uri(const char *uri, char *name, int value);
|
||||
void mympd_like_song_uri(const char *uri, int value);
|
||||
void mympd_last_played_song_uri(const char *uri);
|
||||
void mympd_last_played_song_id(int song_id);
|
||||
void mympd_get_sticker(const char *uri, t_sticker *sticker);
|
||||
int mympd_get_updatedb_state(char *buffer);
|
||||
int mympd_put_state(char *buffer, int *current_song_id, int *next_song_id, int *last_song_id, unsigned *queue_version, unsigned *queue_length);
|
||||
int mympd_put_outputs(char *buffer);
|
||||
int mympd_put_current_song(char *buffer);
|
||||
int mympd_put_queue(char *buffer, unsigned int offset);
|
||||
int mympd_put_queue(char *buffer, unsigned int offset, unsigned *queue_version, unsigned *queue_length);
|
||||
int mympd_put_browse(char *buffer, char *path, unsigned int offset, char *filter);
|
||||
int mympd_search(char *buffer, char *mpdtagtype, unsigned int offset, char *searchstr);
|
||||
int mympd_search_add(char *buffer, char *mpdtagtype, char *searchstr);
|
||||
@ -169,4 +192,3 @@ int mympd_put_songdetails(char *buffer, char *uri);
|
||||
int mympd_queue_crop(char *buffer);
|
||||
void mympd_disconnect();
|
||||
#endif
|
||||
|
||||
|
116
src/mympd.c
116
src/mympd.c
@ -36,7 +36,7 @@
|
||||
|
||||
static sig_atomic_t s_signal_received = 0;
|
||||
static struct mg_serve_http_opts s_http_server_opts;
|
||||
char s_redirect[250];
|
||||
|
||||
|
||||
static void signal_handler(int sig_num) {
|
||||
signal(sig_num, signal_handler); // Reinstantiate signal handler
|
||||
@ -48,8 +48,9 @@ static void handle_api(struct mg_connection *nc, struct http_message *hm) {
|
||||
mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\nContent-Type: application/json\r\n\r\n");
|
||||
|
||||
char buf[1000] = {0};
|
||||
memcpy(buf, hm->body.p,sizeof(buf) - 1 < hm->body.len ? sizeof(buf) - 1 : hm->body.len);
|
||||
struct mg_str d = {buf, strlen(buf)};
|
||||
int len = sizeof(buf) - 1 < hm->body.len ? sizeof(buf) - 1 : hm->body.len;
|
||||
memcpy(buf, hm->body.p, len);
|
||||
struct mg_str d = {buf, len};
|
||||
callback_mympd(nc, d);
|
||||
|
||||
if (!is_websocket(nc))
|
||||
@ -60,35 +61,32 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
||||
switch(ev) {
|
||||
case MG_EV_WEBSOCKET_HANDSHAKE_DONE: {
|
||||
#ifdef DEBUG
|
||||
fprintf(stdout,"New Websocket connection\n");
|
||||
fprintf(stderr, "New Websocket connection\n");
|
||||
#endif
|
||||
struct mg_str d = {(char *) "{\"cmd\": \"MPD_API_WELCOME\"}", 25 };
|
||||
struct mg_str d = mg_mk_str("{\"cmd\": \"MPD_API_WELCOME\"}");
|
||||
callback_mympd(nc, d);
|
||||
break;
|
||||
}
|
||||
case MG_EV_HTTP_REQUEST: {
|
||||
struct http_message *hm = (struct http_message *) ev_data;
|
||||
#ifdef DEBUG
|
||||
printf("HTTP request: %.*s\n", hm->uri.len, hm->uri.p);
|
||||
fprintf(stderr, "HTTP request: %.*s\n", hm->uri.len, hm->uri.p);
|
||||
#endif
|
||||
if (mg_vcmp(&hm->uri, "/api") == 0) {
|
||||
handle_api(nc, hm);
|
||||
}
|
||||
else {
|
||||
mg_serve_http(nc, hm, s_http_server_opts);
|
||||
}
|
||||
if (mg_vcmp(&hm->uri, "/api") == 0)
|
||||
handle_api(nc, hm);
|
||||
else
|
||||
mg_serve_http(nc, hm, s_http_server_opts);
|
||||
break;
|
||||
}
|
||||
case MG_EV_CLOSE: {
|
||||
if (is_websocket(nc)) {
|
||||
#ifdef DEBUG
|
||||
printf("Websocket connection closed\n");
|
||||
fprintf(stderr, "Websocket connection closed\n");
|
||||
#endif
|
||||
mympd_close_handler(nc);
|
||||
}
|
||||
else {
|
||||
#ifdef DEBUG
|
||||
fprintf(stdout,"HTTP Close\n");
|
||||
fprintf(stderr,"HTTP connection closed\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
@ -99,6 +97,10 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
|
||||
static void ev_handler_http(struct mg_connection *nc_http, int ev, void *ev_data) {
|
||||
switch(ev) {
|
||||
case MG_EV_HTTP_REQUEST: {
|
||||
struct http_message *hm = (struct http_message *) ev_data;
|
||||
struct mg_str *host_hdr = mg_get_http_header(hm, "Host");
|
||||
char s_redirect[250];
|
||||
snprintf(s_redirect, 250, "https://%.*s:%s/", host_hdr->len, host_hdr->p, config.sslport);
|
||||
printf("Redirecting to %s\n", s_redirect);
|
||||
mg_http_send_redirect(nc_http, 301, mg_mk_str(s_redirect), mg_mk_str(NULL));
|
||||
break;
|
||||
@ -107,15 +109,17 @@ static void ev_handler_http(struct mg_connection *nc_http, int ev, void *ev_data
|
||||
}
|
||||
|
||||
static int inihandler(void* user, const char* section, const char* name, const char* value) {
|
||||
configuration* p_config = (configuration*)user;
|
||||
t_config* p_config = (t_config*)user;
|
||||
char *crap;
|
||||
|
||||
#define MATCH(n) strcmp(name, n) == 0
|
||||
|
||||
if (MATCH("mpdhost"))
|
||||
p_config->mpdhost = strdup(value);
|
||||
else if (MATCH("mpdhost"))
|
||||
p_config->mpdhost = strdup(value);
|
||||
else if (MATCH("mpdport"))
|
||||
p_config->mpdport = atoi(value);
|
||||
p_config->mpdport = strtol(value, &crap, 10);
|
||||
else if (MATCH("mpdhost"))
|
||||
p_config->mpdhost = strdup(value);
|
||||
else if (MATCH("mpdpass"))
|
||||
@ -134,11 +138,21 @@ static int inihandler(void* user, const char* section, const char* name, const c
|
||||
else if (MATCH("user"))
|
||||
p_config->user = strdup(value);
|
||||
else if (MATCH("streamport"))
|
||||
p_config->streamport = atoi(value);
|
||||
p_config->streamport = strtol(value, &crap, 10);
|
||||
else if (MATCH("coverimage"))
|
||||
p_config->coverimage = strdup(value);
|
||||
else if (MATCH("statefile"))
|
||||
p_config->statefile = strdup(value);
|
||||
else if (MATCH("stickers"))
|
||||
if (strcmp(value, "true") == 0)
|
||||
p_config->stickers = true;
|
||||
else
|
||||
p_config->stickers = false;
|
||||
else if (MATCH("mixramp"))
|
||||
if (strcmp(value, "true") == 0)
|
||||
p_config->mixramp = true;
|
||||
else
|
||||
p_config->mixramp = false;
|
||||
else
|
||||
return 0; /* unknown section/name, error */
|
||||
|
||||
@ -149,14 +163,9 @@ int main(int argc, char **argv) {
|
||||
struct mg_mgr mgr;
|
||||
struct mg_connection *nc;
|
||||
struct mg_connection *nc_http;
|
||||
unsigned int current_timer = 0, last_timer = 0;
|
||||
struct mg_bind_opts bind_opts;
|
||||
const char *err;
|
||||
|
||||
char hostname[1024];
|
||||
hostname[1023] = '\0';
|
||||
gethostname(hostname, 1023);
|
||||
|
||||
//defaults
|
||||
config.mpdhost = "127.0.0.1";
|
||||
config.mpdport = 6600;
|
||||
@ -170,23 +179,34 @@ int main(int argc, char **argv) {
|
||||
config.streamport = 8000;
|
||||
config.coverimage = "folder.jpg";
|
||||
config.statefile = "/var/lib/mympd/mympd.state";
|
||||
config.stickers = true;
|
||||
config.mixramp = true;
|
||||
|
||||
mpd.timeout = 3000;
|
||||
mpd.last_update_sticker_song_id = -1;
|
||||
mpd.last_song_id = -1;
|
||||
|
||||
if (argc == 2) {
|
||||
printf("Parsing config file: %s\n", argv[1]);
|
||||
if (ini_parse(argv[1], inihandler, &config) < 0) {
|
||||
printf("Can't load '%s'\n", argv[1]);
|
||||
printf("Can't load config file \"%s\"\n", argv[1]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stdout, "myMPD %s\n"
|
||||
"Copyright (C) 2018 Juergen Mang <mail@jcgames.de>\n"
|
||||
"https://github.com/jcorporation/myMPD\n"
|
||||
"Built " __DATE__ " "__TIME__"\n\n",
|
||||
MYMPD_VERSION);
|
||||
printf("Usage: %s /path/to/mympd.conf\n", argv[0]);
|
||||
printf("myMPD %s\n"
|
||||
"Copyright (C) 2018 Juergen Mang <mail@jcgames.de>\n"
|
||||
"https://github.com/jcorporation/myMPD\n"
|
||||
"Built " __DATE__ " "__TIME__"\n\n"
|
||||
"Usage: %s /path/to/mympd.conf\n",
|
||||
MYMPD_VERSION,
|
||||
argv[0]
|
||||
);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("Starting myMPD %s\n", MYMPD_VERSION);
|
||||
|
||||
signal(SIGTERM, signal_handler);
|
||||
signal(SIGINT, signal_handler);
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
@ -195,32 +215,32 @@ int main(int argc, char **argv) {
|
||||
mg_mgr_init(&mgr, NULL);
|
||||
|
||||
if (config.ssl == true) {
|
||||
snprintf(s_redirect, 200, "https://%s:%s/", hostname, config.sslport);
|
||||
nc_http = mg_bind(&mgr, config.webport, ev_handler_http);
|
||||
if (nc_http == NULL) {
|
||||
fprintf(stderr, "Error starting server on port %s\n", config.webport );
|
||||
return EXIT_FAILURE;
|
||||
printf("Error listening on port %s\n", config.webport);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
memset(&bind_opts, 0, sizeof(bind_opts));
|
||||
bind_opts.ssl_cert = config.sslcert;
|
||||
bind_opts.ssl_key = config.sslkey;
|
||||
bind_opts.error_string = &err;
|
||||
|
||||
nc = mg_bind_opt(&mgr, config.sslport, ev_handler, bind_opts);
|
||||
if (nc == NULL) {
|
||||
fprintf(stderr, "Error starting server on port %s: %s\n", config.sslport, err);
|
||||
printf("Error listening on port %s: %s\n", config.sslport, err);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
nc = mg_bind(&mgr, config.webport, ev_handler);
|
||||
if (nc == NULL) {
|
||||
fprintf(stderr, "Error starting server on port %s\n", config.webport );
|
||||
return EXIT_FAILURE;
|
||||
printf("Error listening on port %s\n", config.webport);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (config.user != NULL) {
|
||||
printf("Droping privileges\n");
|
||||
printf("Droping privileges to %s\n", config.user);
|
||||
struct passwd *pw;
|
||||
if ((pw = getpwnam(config.user)) == NULL) {
|
||||
printf("Unknown user\n");
|
||||
@ -238,29 +258,25 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
if (getuid() == 0) {
|
||||
printf("myMPD should not be run with root privileges\n");
|
||||
mg_mgr_free(&mgr);
|
||||
return EXIT_FAILURE;
|
||||
printf("myMPD should not be run with root privileges\n");
|
||||
mg_mgr_free(&mgr);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (config.ssl == true)
|
||||
mg_set_protocol_http_websocket(nc_http);
|
||||
|
||||
|
||||
mg_set_protocol_http_websocket(nc);
|
||||
s_http_server_opts.document_root = SRC_PATH;
|
||||
s_http_server_opts.enable_directory_listing = "no";
|
||||
|
||||
printf("myMPD started on http port %s\n", config.webport);
|
||||
printf("Listening on http port %s\n", config.webport);
|
||||
if (config.ssl == true)
|
||||
printf("myMPD started on ssl port %s\n", config.sslport);
|
||||
|
||||
printf("Listening on ssl port %s\n", config.sslport);
|
||||
|
||||
while (s_signal_received == 0) {
|
||||
mg_mgr_poll(&mgr, 200);
|
||||
current_timer = time(NULL);
|
||||
if (current_timer - last_timer) {
|
||||
last_timer = current_timer;
|
||||
mympd_poll(&mgr);
|
||||
}
|
||||
mg_mgr_poll(&mgr, 100);
|
||||
mympd_idle(&mgr, 0);
|
||||
}
|
||||
mg_mgr_free(&mgr);
|
||||
mympd_disconnect();
|
||||
|
Loading…
Reference in New Issue
Block a user