1
0
mirror of https://github.com/SuperBFG7/ympd synced 2024-12-26 02:50:26 +00:00

Merge pull request #63 from jcorporation/devel

Merge devel into master for 4.3.0 release
This commit is contained in:
Jürgen Mang 2018-10-01 22:24:30 +02:00 committed by GitHub
commit 044eaa2ad4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 1164 additions and 334 deletions

View File

@ -3,8 +3,8 @@ cmake_minimum_required(VERSION 2.6)
project (mympd C) project (mympd C)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
set(CPACK_PACKAGE_VERSION_MAJOR "4") set(CPACK_PACKAGE_VERSION_MAJOR "4")
set(CPACK_PACKAGE_VERSION_MINOR "2") set(CPACK_PACKAGE_VERSION_MINOR "3")
set(CPACK_PACKAGE_VERSION_PATCH "1") set(CPACK_PACKAGE_VERSION_PATCH "0")
if(CMAKE_BUILD_TYPE MATCHES RELEASE) if(CMAKE_BUILD_TYPE MATCHES RELEASE)
set(ASSETS_PATH "/usr/share/${PROJECT_NAME}/htdocs") set(ASSETS_PATH "/usr/share/${PROJECT_NAME}/htdocs")
@ -55,3 +55,6 @@ install(FILES dist/htdocs/css/bootstrap.min.css DESTINATION share/${PROJECT_NAME
install(FILES dist/htdocs/css/mympd.min.css DESTINATION share/${PROJECT_NAME}/htdocs/css/) install(FILES dist/htdocs/css/mympd.min.css DESTINATION share/${PROJECT_NAME}/htdocs/css/)
install(DIRECTORY htdocs/assets DESTINATION share/${PROJECT_NAME}/htdocs) install(DIRECTORY htdocs/assets DESTINATION share/${PROJECT_NAME}/htdocs)
install(DIRECTORY DESTINATION ../var/lib/${PROJECT_NAME}/pics) install(DIRECTORY DESTINATION ../var/lib/${PROJECT_NAME}/pics)
install(DIRECTORY DESTINATION ../var/lib/${PROJECT_NAME}/tmp)
install(DIRECTORY DESTINATION ../var/lib/${PROJECT_NAME}/state)
install(DIRECTORY dist/smartpls DESTINATION ../var/lib/${PROJECT_NAME})

View File

@ -4,7 +4,7 @@
pkgname=mympd pkgname=mympd
_pkgname=myMPD _pkgname=myMPD
pkgver=4.2.1 pkgver=4.3.0
pkgrel=1 pkgrel=1
pkgdesc="A standalone MPD Web GUI based on YMPD - Default port set to 80" pkgdesc="A standalone MPD Web GUI based on YMPD - Default port set to 80"
arch=('x86_64' 'armv7h' 'aarch64') arch=('x86_64' 'armv7h' 'aarch64')

View File

@ -21,13 +21,14 @@ This fork provides a reworked ui based on Bootstrap 4, a modernized backend and
- Queue management - Queue management
- Playlist management - Playlist management
- Advanced search - Advanced search
- Progressiv Web App enabled - Jukebox mode (add's random songs / albums from database or playlists to queue)
- Smart playlists and saved searches
- Play statistics and song voting (uses mpd stickers)
- Local coverart support (Albums and Streams) - Local coverart support (Albums and Streams)
- HTTP stream support - HTTP stream support
- Local playback of mpd http stream (html5 audio api) - Local playback of mpd http stream (html5 audio api)
- Play statistics and song voting (uses mpd stickers) - Progressiv Web App enabled
- Embedded Webserver (mongoose) - Embedded Webserver (mongoose)
- Jukebox mode (add's random songs from database or playlists to queue)
myMPD is work in progress. Bugreportes and feature requests are very welcome. myMPD is work in progress. Bugreportes and feature requests are very welcome.
- https://github.com/jcorporation/myMPD/issues - https://github.com/jcorporation/myMPD/issues

View File

@ -11,11 +11,8 @@ post_upgrade() {
[ "$?" = "2" ] && useradd --system -d /var/lib/mympd -s /usr/sbin/nologin -g mympd mympd [ "$?" = "2" ] && useradd --system -d /var/lib/mympd -s /usr/sbin/nologin -g mympd mympd
# fix ownership of /var/lib/mympd # fix ownership of /var/lib/mympd
if ! [ $(stat -c '%U:%G' /var/lib/mympd/) = 'mympd:mympd' ] echo "INFO: Fixing ownership of /var/lib/mympd"
then chown -R mympd.mympd /var/lib/mympd
echo "INFO: Fixing ownership of /var/lib/mympd"
chown -R mympd.mympd /var/lib/mympd
fi
# link music directory to mympd if not already exising # link music directory to mympd if not already exising
echo "INFO: Trying to link musicdir to library" echo "INFO: Trying to link musicdir to library"
@ -52,6 +49,18 @@ post_upgrade() {
/usr/share/mympd/crcert.sh /usr/share/mympd/crcert.sh
fi fi
# move smartpls into place unless already existing
for PLDIST in /var/lib/mympd/smartpls/*.dist
do
PLS=$(basename $PLDIST .dist)
if [ -f /var/lib/mympd/smartpls/$PLS ]
then
rm $PLDIST
else
mv $PLDIST /var/lib/mympd/smartpls/$PLS
fi
done
# move config into place unless already existing # move config into place unless already existing
if [ ! -f /etc/mympd/mympd.conf ] if [ ! -f /etc/mympd/mympd.conf ]
then then

View File

@ -4,13 +4,13 @@
# (c) 2018 Juergen Mang <mail@jcgames.de> # (c) 2018 Juergen Mang <mail@jcgames.de>
Name: myMPD Name: myMPD
Version: 4.2.1 Version: 4.3.0
Release: 0 Release: 0
License: GPL-2.0 License: GPL-2.0
Group: Productivity/Multimedia/Sound/Players Group: Productivity/Multimedia/Sound/Players
Summary: Standalone webclient for mpd Summary: Standalone webclient for mpd
Url: https://github.com/jcorporation/myMPD Url: https://github.com/jcorporation/myMPD
Source: https://github.com/jcorporation/myMPD/archive/v4.2.1.zip Source: https://github.com/jcorporation/myMPD/archive/v4.3.0.zip
BuildRequires: gcc BuildRequires: gcc
BuildRequires: cmake BuildRequires: cmake
BuildRequires: unzip BuildRequires: unzip
@ -44,15 +44,12 @@ getent group mympd > /dev/null
getent passwd mympd > /dev/null getent passwd mympd > /dev/null
[ "$?" = "2" ] && useradd -r mympd -g mympd -d /var/lib/mympd -s /usr/sbin/nologin [ "$?" = "2" ] && useradd -r mympd -g mympd -d /var/lib/mympd -s /usr/sbin/nologin
if ! [ $(stat -c '%U:%G' /var/lib/mympd/) = 'mympd:mympd' ] echo "Fixing ownership of /var/lib/mympd"
then chown -R mympd.mympd /var/lib/mympd
echo "Fixing ownership of /var/lib/mympd"
chown -R mympd.mympd /var/lib/mympd
fi
if [ -d /etc/systemd ] if [ -d /etc/systemd ]
then then
[ -d /usr/lib/systemd/system ] || sudo mkdir -p /usr/lib/systemd/system [ -d /usr/lib/systemd/system ] || mkdir -p /usr/lib/systemd/system
cp /usr/share/mympd/mympd.service /usr/lib/systemd/system/ cp /usr/share/mympd/mympd.service /usr/lib/systemd/system/
systemctl daemon-reload systemctl daemon-reload
systemctl enable mympd systemctl enable mympd
@ -66,6 +63,19 @@ fi
[ -e /usr/share/mympd/htdocs/pics ] || ln -s /var/lib/mympd/pics /usr/share/mympd/htdocs/ [ -e /usr/share/mympd/htdocs/pics ] || ln -s /var/lib/mympd/pics /usr/share/mympd/htdocs/
# move smartpls into place unless already existing
for PLDIST in /var/lib/mympd/smartpls/*.dist
do
PLS=$(basename $PLDIST .dist)
if [ -f /var/lib/mympd/smartpls/$PLS ]
then
rm $PLDIST
else
mv $PLDIST /var/lib/mympd/smartpls/$PLS
fi
done
# move config into place unless already existing
if [ ! -f /etc/mympd/mympd.conf ] if [ ! -f /etc/mympd/mympd.conf ]
then then
mv /etc/mympd/mympd.conf.dist /etc/mympd/mympd.conf mv /etc/mympd/mympd.conf.dist /etc/mympd/mympd.conf

View File

@ -23,8 +23,8 @@ streamport = 8000
#Name for coverimages #Name for coverimages
coverimage = folder.jpg coverimage = folder.jpg
#myMPD statefile #myMPD state directory
statefile = /var/lib/mympd/mympd.state varlibdir = /var/lib/mympd
#Enable mixramp settings #Enable mixramp settings
mixramp = false mixramp = false
@ -35,3 +35,6 @@ stickers = true
#List of tags in myMPD gui #List of tags in myMPD gui
#Supported tags: Artist,Album,AlbumArtist,Title,Track,Genre,Date,Composer,Performer #Supported tags: Artist,Album,AlbumArtist,Title,Track,Genre,Date,Composer,Performer
taglist = Artist,Album,AlbumArtist,Title,Track,Genre,Date,Composer,Performer taglist = Artist,Album,AlbumArtist,Title,Track,Genre,Date,Composer,Performer
#Enable smart playlists
smartpls = true

4
debian/changelog vendored
View File

@ -1,5 +1,5 @@
mympd (4.2.1-1) stable; urgency=medium mympd (4.3.0-1) stable; urgency=medium
* Release from master * Release from master
-- Juergen Mang <mail@jcgames.de> Thu, 20 Sep 2018 19:32:00 +0200 -- Juergen Mang <mail@jcgames.de> Tue, 25 Sep 2018 00:35:00 +0200

21
debian/postinst vendored
View File

@ -6,11 +6,8 @@ getent group mympd > /dev/null
getent passwd mympd > /dev/null getent passwd mympd > /dev/null
[ "$?" = "2" ] && useradd -r mympd -g mympd -d /var/lib/mympd -s /usr/sbin/nologin [ "$?" = "2" ] && useradd -r mympd -g mympd -d /var/lib/mympd -s /usr/sbin/nologin
if ! [ $(stat -c '%U:%G' /var/lib/mympd/) = 'mympd:mympd' ] echo "Fixing ownership of /var/lib/mympd"
then chown -R mympd.mympd /var/lib/mympd
echo "Fixing ownership of /var/lib/mympd"
chown -R mympd.mympd /var/lib/mympd
fi
echo "Trying to link musicdir to library" echo "Trying to link musicdir to library"
if [ -f /etc/mpd.conf ] if [ -f /etc/mpd.conf ]
@ -36,6 +33,18 @@ then
systemctl enable mympd systemctl enable mympd
fi fi
# move smartpls into place unless already existing
for PLDIST in /var/lib/mympd/smartpls/*.dist
do
PLS=$(basename $PLDIST .dist)
if [ -f /var/lib/mympd/smartpls/$PLS ]
then
rm $PLDIST
else
mv $PLDIST /var/lib/mympd/smartpls/$PLS
fi
done
# move config into place unless already existing # move config into place unless already existing
if [ ! -f /etc/mympd/mympd.conf ] if [ ! -f /etc/mympd/mympd.conf ]
then then
@ -49,7 +58,7 @@ then
echo "Certificates already created" echo "Certificates already created"
else else
echo "Creating certificates" echo "Creating certificates"
sudo /usr/share/mympd/crcert.sh /usr/share/mympd/crcert.sh
fi fi
echo "myMPD installed" echo "myMPD installed"

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
// Native Javascript for Bootstrap 4 v2.0.23 | © dnp_theme | MIT-License // Native Javascript for Bootstrap 4 v2.0.24 | © dnp_theme | MIT-License
(function (root, factory) { (function (root, factory) {
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
// AMD support: // AMD support:
@ -315,7 +315,7 @@
arrowLeft && (arrow[style][left] = arrowLeft + 'px'); arrowLeft && (arrow[style][left] = arrowLeft + 'px');
}; };
BSN.version = '2.0.23'; BSN.version = '2.0.24';
/* Native Javascript for Bootstrap 4 | Alert /* Native Javascript for Bootstrap 4 | Alert
-------------------------------------------*/ -------------------------------------------*/
@ -501,7 +501,8 @@
this[interval] = typeof intervalOption === 'number' ? intervalOption this[interval] = typeof intervalOption === 'number' ? intervalOption
: intervalOption === false || intervalData === 0 || intervalData === false ? 0 : intervalOption === false || intervalData === 0 || intervalData === false ? 0
: 5000; // bootstrap carousel default interval : isNaN(intervalData) ? 5000 // bootstrap carousel default interval
: intervalData;
// bind, event targets // bind, event targets
var self = this, index = element.index = 0, timer = element.timer = 0, var self = this, index = element.index = 0, timer = element.timer = 0,
@ -592,8 +593,11 @@
var activeItem = this.getActiveIndex(), // the current active var activeItem = this.getActiveIndex(), // the current active
orientation; orientation;
// determine slideDirection first // first return if we're on the same item #227
if ( (activeItem < next ) || (activeItem === 0 && next === total -1 ) ) { if ( activeItem === next ) {
return;
// or determine slideDirection
} else if ( (activeItem < next ) || (activeItem === 0 && next === total -1 ) ) {
slideDirection = self[direction] = left; // next slideDirection = self[direction] = left; // next
} else if ( (activeItem > next) || (activeItem === total - 1 && next === 0 ) ) { } else if ( (activeItem > next) || (activeItem === total - 1 && next === 0 ) ) {
slideDirection = self[direction] = right; // prev slideDirection = self[direction] = right; // prev

File diff suppressed because one or more lines are too long

View File

@ -10,7 +10,8 @@ scrollPos:0},Composer:{state:"0/-/",scrollPos:0},Performer:{state:"0/-/",scrollP
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.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.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"); domCache.currentCover=document.getElementById("currentCover");domCache.btnVoteUp=document.getElementById("btnVoteUp");domCache.btnVoteDown=document.getElementById("btnVoteDown");
var modalConnectionError=new Modal(document.getElementById("modalConnectionError"),{backdrop:"static",keyboard:!1}),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")); var modalConnectionError=new Modal(document.getElementById("modalConnectionError"),{backdrop:"static",keyboard:!1}),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")),
modalSaveSmartPlaylist=new Modal(document.getElementById("modalSaveSmartPlaylist"));
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"); 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+ 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")} "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")}
@ -22,42 +23,44 @@ if("Playback"==app.current.app)sendAPI({cmd:"MPD_API_PLAYER_CURRENT_SONG"},songC
"Detail"==app.current.view)sendAPI({cmd:"MPD_API_PLAYLIST_CONTENT_LIST",data:{offset:app.current.page,filter:app.current.filter,uri:app.current.search}},parsePlaylists),doSetFilterLetter("BrowsePlaylistsFilter");else if("Browse"==app.current.app&&"Database"==app.current.tab)""!=app.current.search?(sendAPI({cmd:"MPD_API_DATABASE_TAG_ALBUM_LIST",data:{offset:app.current.page,filter:app.current.filter,search:app.current.search,tag:app.current.view}},parseListDBtags),doSetFilterLetter("BrowseDatabaseFilter")): "Detail"==app.current.view)sendAPI({cmd:"MPD_API_PLAYLIST_CONTENT_LIST",data:{offset:app.current.page,filter:app.current.filter,uri:app.current.search}},parsePlaylists),doSetFilterLetter("BrowsePlaylistsFilter");else if("Browse"==app.current.app&&"Database"==app.current.tab)""!=app.current.search?(sendAPI({cmd:"MPD_API_DATABASE_TAG_ALBUM_LIST",data:{offset:app.current.page,filter:app.current.filter,search:app.current.search,tag:app.current.view}},parseListDBtags),doSetFilterLetter("BrowseDatabaseFilter")):
(sendAPI({cmd:"MPD_API_DATABASE_TAG_LIST",data:{offset:app.current.page,filter:app.current.filter,tag:app.current.view}},parseListDBtags),doSetFilterLetter("BrowseDatabaseFilter"),selectTag("BrowseDatabaseByTagDropdown","btnBrowseDatabaseByTag",app.current.view));else if("Browse"==app.current.app&&"Filesystem"==app.current.tab){sendAPI({cmd:"MPD_API_DATABASE_FILESYSTEM_LIST",data:{offset:app.current.page,path:app.current.search?app.current.search:"/",filter:app.current.filter}},parseFilesystem);app.current.search? (sendAPI({cmd:"MPD_API_DATABASE_TAG_LIST",data:{offset:app.current.page,filter:app.current.filter,tag:app.current.view}},parseListDBtags),doSetFilterLetter("BrowseDatabaseFilter"),selectTag("BrowseDatabaseByTagDropdown","btnBrowseDatabaseByTag",app.current.view));else if("Browse"==app.current.app&&"Filesystem"==app.current.tab){sendAPI({cmd:"MPD_API_DATABASE_FILESYSTEM_LIST",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"));var b='<li class="breadcrumb-item"><a data-uri="">root</a></li>',c=app.current.search.split("/"),d=c.length,e="";for(a=0;a<d;a++){if(d-1==a){b+= (document.getElementById("BrowseFilesystemAddAllSongs").removeAttribute("disabled"),document.getElementById("BrowseFilesystemAddAllSongsBtn").removeAttribute("disabled")):(document.getElementById("BrowseFilesystemAddAllSongs").setAttribute("disabled","disabled"),document.getElementById("BrowseFilesystemAddAllSongsBtn").setAttribute("disabled","disabled"));var b='<li class="breadcrumb-item"><a data-uri="">root</a></li>',c=app.current.search.split("/"),d=c.length,e="";for(a=0;a<d;a++){if(d-1==a){b+=
'<li class="breadcrumb-item active">'+c[a]+"</li>";break}e+=c[a];b+='<li class="breadcrumb-item"><a data-uri="'+e+'">'+c[a]+"</a></li>";e+="/"}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"Search"==app.current.app?(document.getElementById("searchstr").focus(), '<li class="breadcrumb-item active">'+c[a]+"</li>";break}e+=c[a];b+='<li class="breadcrumb-item"><a data-uri="'+e+'">'+c[a]+"</a></li>";e+="/"}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"Search"==app.current.app?(a=document.getElementById("searchstr"),
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_DATABASE_SEARCH",data:{plist:"",offset:app.current.page,filter:app.current.filter,searchstr:app.current.search}},parseSearch):(document.getElementById("SearchList").getElementsByTagName("tbody")[0].innerHTML="",document.getElementById("searchAddAllSongs").setAttribute("disabled", a.focus(),""==a.value&&""!=app.current.search&&(a.value=app.current.search),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_DATABASE_SEARCH",data:{plist:"",offset:app.current.page,filter:app.current.filter,searchstr:app.current.search}},parseSearch):(document.getElementById("SearchList").getElementsByTagName("tbody")[0].innerHTML=
"disabled"),document.getElementById("searchAddAllSongsBtn").setAttribute("disabled","disabled"),document.getElementById("panel-heading-search").innerText="",document.getElementById("SearchList").classList.remove("opacity05"),setPagination(0)),selectTag("searchtags","searchtagsdesc",app.current.filter)):appGoto("Playback");app.last.app=app.current.app;app.last.tab=app.current.tab;app.last.view=app.current.view}else appGoto("Playback")} "",document.getElementById("searchAddAllSongs").setAttribute("disabled","disabled"),document.getElementById("searchAddAllSongsBtn").setAttribute("disabled","disabled"),document.getElementById("panel-heading-search").innerText="",document.getElementById("SearchList").classList.remove("opacity05"),setPagination(0)),selectTag("searchtags","searchtagsdesc",app.current.filter)):appGoto("Playback");app.last.app=app.current.app;app.last.tab=app.current.tab;app.last.view=app.current.view}else appGoto("Playback")}
function appInit(){getSettings();sendAPI({cmd:"MPD_API_PLAYER_STATE"},parseState);webSocketConnect();domCache.volumeBar.value=0;domCache.volumeBar.addEventListener("click",function(a){a.stopPropagation()},!1);domCache.volumeBar.addEventListener("change",function(a){sendAPI({cmd:"MPD_API_PLAYER_VOLUME",data:{volume:domCache.volumeBar.value}})},!1);domCache.progressBar.value=0;domCache.progressBar.addEventListener("change",function(a){currentSong&&0<=currentSong.currentSongId&&sendAPI({cmd:"MPD_API_PLAYER_SEEK", function appInit(){getSettings();sendAPI({cmd:"MPD_API_PLAYER_STATE"},parseState);webSocketConnect();domCache.volumeBar.value=0;document.getElementById("btnChVolumeDown").addEventListener("click",function(a){a.stopPropagation()},!1);document.getElementById("btnChVolumeUp").addEventListener("click",function(a){a.stopPropagation()},!1);domCache.volumeBar.addEventListener("click",function(a){a.stopPropagation()},!1);domCache.volumeBar.addEventListener("change",function(a){sendAPI({cmd:"MPD_API_PLAYER_VOLUME",
data:{songid:currentSong.currentSongId,seek:Math.ceil(domCache.progressBar.value/100*currentSong.totalTime)}})},!1);document.getElementById("navDBupdate").addEventListener("click",function(a){a.stopPropagation();a.preventDefault();a=this.getElementsByTagName("span")[0];a.innerText="keyboard_arrow_right"==a.innerText?"keyboard_arrow_down":"keyboard_arrow_right"},!1);document.getElementById("volumeIcon").parentNode.addEventListener("show.bs.dropdown",function(){sendAPI({cmd:"MPD_API_PLAYER_OUTPUT_LIST"}, data:{volume:domCache.volumeBar.value}})},!1);domCache.progressBar.value=0;domCache.progressBar.addEventListener("change",function(a){currentSong&&0<=currentSong.currentSongId&&sendAPI({cmd:"MPD_API_PLAYER_SEEK",data:{songid:currentSong.currentSongId,seek:Math.ceil(domCache.progressBar.value/100*currentSong.totalTime)}})},!1);document.getElementById("navDBupdate").addEventListener("click",function(a){a.stopPropagation();a.preventDefault();a=this.getElementsByTagName("span")[0];a.innerText="keyboard_arrow_right"==
parseOutputs)});document.getElementById("modalAbout").addEventListener("shown.bs.modal",function(){sendAPI({cmd:"MPD_API_DATABASE_STATS"},parseStats)});document.getElementById("modalUpdateDB").addEventListener("hidden.bs.modal",function(){document.getElementById("updateDBprogress").classList.remove("updateDBprogressAnimate")});document.getElementById("modalSaveQueue").addEventListener("shown.bs.modal",function(){var a=document.getElementById("saveQueueName");a.focus();a.value="";a.classList.remove("is-invalid"); a.innerText?"keyboard_arrow_down":"keyboard_arrow_right"},!1);document.getElementById("volumeIcon").parentNode.addEventListener("show.bs.dropdown",function(){sendAPI({cmd:"MPD_API_PLAYER_OUTPUT_LIST"},parseOutputs)});document.getElementById("modalAbout").addEventListener("shown.bs.modal",function(){sendAPI({cmd:"MPD_API_DATABASE_STATS"},parseStats)});document.getElementById("modalUpdateDB").addEventListener("hidden.bs.modal",function(){document.getElementById("updateDBprogress").classList.remove("updateDBprogressAnimate")});
document.getElementById("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", 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");
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< document.getElementById("inputMixrampdb").classList.remove("is-invalid");document.getElementById("inputMixrampdelay").classList.remove("is-invalid")});document.getElementById("selectJukeboxMode").addEventListener("change",function(){var a=this.options[this.selectedIndex].value;0==a||2==a?(document.getElementById("inputJukeboxQueueLength").setAttribute("disabled","disabled"),document.getElementById("selectJukeboxPlaylist").setAttribute("disabled","disabled")):1==a&&(document.getElementById("inputJukeboxQueueLength").removeAttribute("disabled"),
b;c++)a[c].classList.add("clickable"),a[c].addEventListener("click",function(a){a.preventDefault();a=JSON.parse(this.getAttribute("data-href"));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"))}, document.getElementById("selectJukeboxPlaylist").removeAttribute("disabled"))});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");
!1);document.getElementById("outputs").addEventListener("click",function(a){"BUTTON"==a.target.nodeName&&a.stopPropagation();sendAPI({cmd:"MPD_API_PLAYER_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_PLAYER_PLAY_TRACK",data:{track:a.target.parentNode.getAttribute("data-trackid")}}): 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=JSON.parse(this.getAttribute("data-href"));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");
"A"==a.target.nodeName&&showMenu(a.target,a)},!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", 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_PLAYER_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",
decodeURI(a.target.parentNode.getAttribute("data-uri")),a.target.parentNode.getAttribute("data-name"))}else"A"==a.target.nodeName&&showMenu(a.target,a)},!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&&showMenu(a.target,a)},!1);document.getElementById("BrowsePlaylistsDetailList").addEventListener("click", function(a){"TD"==a.target.nodeName?sendAPI({cmd:"MPD_API_PLAYER_PLAY_TRACK",data:{track:a.target.parentNode.getAttribute("data-trackid")}}):"A"==a.target.nodeName&&showMenu(a.target,a)},!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",
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&&showMenu(a.target,a)},!1);document.getElementById("BrowseDatabaseTagList").addEventListener("click",function(a){"TD"==a.target.nodeName&&appGoto("Browse","Database",app.current.view,"0/-/"+a.target.parentNode.getAttribute("data-uri"))},!1);document.getElementById("SearchList").addEventListener("click",function(a){"TD"== 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&&showMenu(a.target,a)},!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.target.nodeName?appendQueue("song",decodeURI(a.target.parentNode.getAttribute("data-uri")),a.target.parentNode.getAttribute("data-name")):"A"==a.target.nodeName&&showMenu(a.target,a)},!1);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", "A"==a.target.nodeName&&showMenu(a.target,a)},!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&&showMenu(a.target,a)},!1);document.getElementById("BrowseDatabaseTagList").addEventListener("click",function(a){"TD"==a.target.nodeName&&appGoto("Browse","Database",app.current.view,"0/-/"+a.target.parentNode.getAttribute("data-uri"))},
function(a){"BUTTON"==a.target.nodeName&&("Add all to queue"==a.target.innerText?addAllFromSearchPlist("queue"):"Add all to playlist"==a.target.innerText&&showAddToPlaylist("SEARCH"))},!1);document.getElementById("BrowseDatabaseAddAllSongsDropdown").addEventListener("click",function(a){"BUTTON"==a.target.nodeName&&("Add all to queue"==a.target.innerText?addAllFromBrowseDatabasePlist("queue"):"Add all to playlist"==a.target.innerText&&showAddToPlaylist("DATABASE"))},!1);document.getElementById("searchtags").addEventListener("click", !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&&showMenu(a.target,a)},!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&&
function(a){"BUTTON"==a.target.nodeName&&appGoto(app.current.app,app.current.tab,app.current.view,"0/"+a.target.getAttribute("data-tag")+"/"+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, showAddToPlaylist(app.current.search))},!1);document.getElementById("searchAddAllSongsDropdown").addEventListener("click",function(a){"BUTTON"==a.target.nodeName&&("Add all to queue"==a.target.innerText?addAllFromSearchPlist("queue"):"Add all to playlist"==a.target.innerText?showAddToPlaylist("SEARCH"):"Save as smart playlist"==a.target.innerText&&saveSearchAsSmartPlaylist())},!1);document.getElementById("BrowseDatabaseAddAllSongsDropdown").addEventListener("click",function(a){"BUTTON"==a.target.nodeName&&
app.current.page+"/"+a.target.getAttribute("data-tag")+"/"+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);document.getElementById("BrowseDatabaseByTagDropdown").addEventListener("click",function(a){"BUTTON"== ("Add all to queue"==a.target.innerText?addAllFromBrowseDatabasePlist("queue"):"Add all to playlist"==a.target.innerText&&showAddToPlaylist("DATABASE"))},!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.getAttribute("data-tag")+"/"+app.current.search)},!1);document.getElementById("searchqueuestr").addEventListener("keyup",function(a){appGoto(app.current.app,app.current.tab,
a.target.nodeName&&appGoto(app.current.app,app.current.tab,a.target.getAttribute("data-tag"),"0/"+app.current.filter+"/"+app.current.search)},!1);document.getElementsByTagName("body")[0].addEventListener("click",function(a){a=document.getElementsByClassName("popover");for(var b=0;b<a.length;b++)a[b].remove()},!1);dragAndDropTable("QueueList");dragAndDropTable("BrowsePlaylistsDetailList");window.addEventListener("hashchange",appRoute,!1);window.addEventListener("focus",function(){sendAPI({cmd:"MPD_API_PLAYER_STATE"}, 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.getAttribute("data-tag")+"/"+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",
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: ", function(a){appGoto("Search",void 0,void 0,"0/"+app.current.filter+"/"+this.value)},!1);document.getElementById("BrowseDatabaseByTagDropdown").addEventListener("click",function(a){"BUTTON"==a.target.nodeName&&appGoto(app.current.app,app.current.tab,a.target.getAttribute("data-tag"),"0/"+app.current.filter+"/"+app.current.search)},!1);document.getElementsByTagName("body")[0].addEventListener("click",function(a){hideMenu()},!1);dragAndDropTable("QueueList");dragAndDropTable("BrowsePlaylistsDetailList");
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"); window.addEventListener("hashchange",appRoute,!1);window.addEventListener("focus",function(){sendAPI({cmd:"MPD_API_PLAYER_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",
deferredPrompt=null})});window.addEventListener("appinstalled",function(a){console.log("myMPD installed as app")})} {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"== 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.getElementsByClassName("dragover"),e=c.length,f=0;f<e;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"),e=c.length,f=0;f<e;f++)c[f].classList.remove("dragover"); b.nodeName&&b.classList.remove("dragover")},!1);b.addEventListener("dragover",function(a){a.preventDefault();for(var c=b.getElementsByClassName("dragover"),e=c.length,f=0;f<e;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"),e=c.length,f=0;f<e;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 d=c.target;"TD"==c.target.nodeName&&(d=c.target.parentNode);var e=document.getElementById(c.dataTransfer.getData("Text")).getAttribute("data-songpos"),f=d.getAttribute("data-songpos");document.getElementById(c.dataTransfer.getData("Text")).remove();dragEl.classList.remove("opacity05"); 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 d=c.target;"TD"==c.target.nodeName&&(d=c.target.parentNode);var e=document.getElementById(c.dataTransfer.getData("Text")).getAttribute("data-songpos"),f=d.getAttribute("data-songpos");document.getElementById(c.dataTransfer.getData("Text")).remove();dragEl.classList.remove("opacity05");
b.insertBefore(dragEl,d);c=b.getElementsByClassName("dragover");d=c.length;for(var g=0;g<d;g++)c[g].classList.remove("dragover");document.getElementById(a).classList.add("opacity05");"Queue"==app.current.app?sendAPI({cmd:"MPD_API_QUEUE_MOVE_TRACK",data:{from:e,to:f}}):"Browse"==app.current.app&&"Playlists"==app.current.tab&&"Detail"==app.current.view&&playlistMoveTrack(e,f)},!1)} b.insertBefore(dragEl,d);c=b.getElementsByClassName("dragover");d=c.length;for(var g=0;g<d;g++)c[g].classList.remove("dragover");document.getElementById(a).classList.add("opacity05");"Queue"==app.current.app?sendAPI({cmd:"MPD_API_QUEUE_MOVE_TRACK",data:{from:e,to:f}}):"Browse"==app.current.app&&"Playlists"==app.current.tab&&"Detail"==app.current.view&&playlistMoveTrack(e,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_PLAYLIST_CONTENT_LIST",data:{offset:app.current.page,filter:app.current.filter,uri:app.current.search}},parsePlaylists)} function playlistMoveTrack(a,b){sendAPI({cmd:"MPD_API_PLAYLIST_MOVE_TRACK",data:{plist:app.current.search,from:a,to:b}});sendAPI({cmd:"MPD_API_PLAYLIST_CONTENT_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();sendAPI({cmd:"MPD_API_PLAYER_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", function webSocketConnect(){var a=getWsUrl();socket=new WebSocket(a);try{socket.onopen=function(){console.log("connected");showNotification("Connected to myMPD: "+a,"","","success");modalConnectionError.hide();appRoute();sendAPI({cmd:"MPD_API_PLAYER_STATE"},parseState)},socket.onmessage=function(b){if(b.data!==lastState&&0!=b.data.length){try{var c=JSON.parse(b.data)}catch(d){console.log("Invalid JSON data received: "+b.data)}switch(c.type){case "update_state":parseState(c);break;case "disconnected":showNotification("Lost connection to myMPD: "+
"","","danger");break;case "update_queue":"Queue"===app.current.app&&getQueue();sendAPI({cmd:"MPD_API_PLAYER_STATE"},parseState);break;case "update_options":getSettings();break;case "update_outputs":sendAPI({cmd:"MPD_API_PLAYER_OUTPUT_LIST"},parseOutputs);break;case "update_started":updateDBstarted(!1);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(); a,"","","danger");break;case "update_queue":"Queue"===app.current.app&&getQueue();sendAPI({cmd:"MPD_API_PLAYER_STATE"},parseState);break;case "update_options":getSettings();break;case "update_outputs":sendAPI({cmd:"MPD_API_PLAYER_OUTPUT_LIST"},parseOutputs);break;case "update_started":updateDBstarted(!1);break;case "update_database":case "update_finished":updateDBfinished(c.type);break;case "error":showNotification(c.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"} setTimeout(function(){console.log("reconnect");webSocketConnect()},3E3)}}catch(b){alert("Error: "+b)}}function getWsUrl(){var a=window.location.hostname,b=window.location.protocol,c=window.location.port;a=("https:"==b?"wss://":"ws://")+a+(""!=c?":"+c:"")+"/ws";return document.getElementById("wsUrl").innerText=a}
function parseStats(a){document.getElementById("mpdstats_artists").innerText=a.data.artists;document.getElementById("mpdstats_albums").innerText=a.data.albums;document.getElementById("mpdstats_songs").innerText=a.data.songs;document.getElementById("mpdstats_dbPlaytime").innerText=beautifyDuration(a.data.dbPlaytime);document.getElementById("mpdstats_playtime").innerText=beautifyDuration(a.data.playtime);document.getElementById("mpdstats_uptime").innerText=beautifyDuration(a.data.uptime);var b=new Date(1E3* function 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||1==b?a.classList.add("active"):a.classList.remove("active")} 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||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);toggleBtn("btnJukebox",a.data.jukeboxMode);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"), 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"); 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);b=document.getElementsByClassName("stickers");for(var c= 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);var c=document.getElementsByClassName("stickers"),d=c.length,
b.length,d=1==a.data.stickers?"":"none",e=0;e<c;e++)b[e].style.display=d;1==a.data.mixramp?document.getElementsByClassName("mixramp")[0].style.display="":document.getElementsByClassName("mixramp")[0].style.display="none";settings=a.data;playlistEl="jukeboxPlaylist";sendAPI({cmd:"MPD_API_PLAYLIST_LIST",data:{offset:0,filter:"-"}},getAllPlaylists);settings.mpdstream="http://";settings.mpdstream="127.0.0.1"==settings.mpdhost||"localhost"==settings.mpdhost?settings.mpdstream+window.location.hostname: e=1==a.data.stickers?"":"none";for(b=0;b<d;b++)c[b].style.display=e;c=document.getElementsByClassName("smartpls");d=c.length;e=1==a.data.smartpls?"":"none";for(b=0;b<d;b++)c[b].style.display=e;1==a.data.mixramp?document.getElementsByClassName("mixramp")[0].style.display="":document.getElementsByClassName("mixramp")[0].style.display="none";document.getElementById("selectJukeboxMode").value=a.data.jukeboxMode;document.getElementById("inputJukeboxQueueLength").value=a.data.jukeboxQueueLength;0==a.data.jukeboxMode||
settings.mpdstream+settings.mpdhost;settings.mpdstream+=":"+settings.streamport+"/";addTagList("BrowseDatabaseByTagDropdown",!1);addTagList("searchqueuetag",!0);addTagList("searchtags",!0)}function getSettings(){sendAPI({cmd:"MPD_API_SETTINGS_GET"},parseSettings)} 2==a.data.jukeboxMode?(document.getElementById("inputJukeboxQueueLength").setAttribute("disabled","disabled"),document.getElementById("selectJukeboxPlaylist").setAttribute("disabled","disabled")):1==a.data.jukeboxMode&&(document.getElementById("inputJukeboxQueueLength").removeAttribute("disabled"),document.getElementById("selectJukeboxPlaylist").removeAttribute("disabled"));settings=a.data;playlistEl="selectJukeboxPlaylist";sendAPI({cmd:"MPD_API_PLAYLIST_LIST",data:{offset:0,filter:"-"}},getAllPlaylists);
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+"/";addTagList("BrowseDatabaseByTagDropdown",!1);addTagList("searchqueuetag",!0);addTagList("searchtags",!0)}function getSettings(){sendAPI({cmd:"MPD_API_SETTINGS_GET"},parseSettings)}
function parseOutputs(a){for(var b="",c=a.data.outputs.length,d=0;d<c;d++)b+='<button id="btnOutput'+a.data.outputs[d].id+'" data-output-id="'+a.data.outputs[d].id+'" class="btn btn-secondary btn-block',1==a.data.outputs[d].state&&(b+=" active"),b+='"><span class="material-icons float-left">volume_up</span> '+a.data.outputs[d].name+"</button>";domCache.outputs.innerHTML=b} function parseOutputs(a){for(var b="",c=a.data.outputs.length,d=0;d<c;d++)b+='<button id="btnOutput'+a.data.outputs[d].id+'" data-output-id="'+a.data.outputs[d].id+'" class="btn btn-secondary btn-block',1==a.data.outputs[d].state&&(b+=" active"),b+='"><span class="material-icons float-left">volume_up</span> '+a.data.outputs[d].name+"</button>";domCache.outputs.innerHTML=b}
function setCounter(a,b,c){currentSong.totalTime=b;currentSong.elapsedTime=c;currentSong.currentSongId=a;var d=Math.floor(b/60),e=b-60*d,f=Math.floor(c/60),g=c-60*f;domCache.progressBar.value=Math.floor(100*c/b);b=f+":"+(10>g?"0":"")+g+" / "+d+":"+(10>e?"0":"")+e;domCache.counter.innerText=b;lastState&&(c=document.getElementById("queueTrackId"+lastState.data.currentSongId))&&(d=c.getElementsByTagName("td"),d[4].innerText=c.getAttribute("data-duration"),d[0].classList.remove("material-icons"),d[0].innerText= function setCounter(a,b,c){currentSong.totalTime=b;currentSong.elapsedTime=c;currentSong.currentSongId=a;var d=Math.floor(b/60),e=b-60*d,f=Math.floor(c/60),g=c-60*f;domCache.progressBar.value=Math.floor(100*c/b);b=f+":"+(10>g?"0":"")+g+" / "+d+":"+(10>e?"0":"")+e;domCache.counter.innerText=b;lastState&&(c=document.getElementById("queueTrackId"+lastState.data.currentSongId))&&(d=c.getElementsByTagName("td"),d[4].innerText=c.getAttribute("data-duration"),d[0].classList.remove("material-icons"),d[0].innerText=
c.getAttribute("data-songpos"),c.classList.remove("font-weight-bold"));if(c=document.getElementById("queueTrackId"+a))d=c.getElementsByTagName("td"),d[4].innerText=b,d[0].classList.add("material-icons"),d[0].innerText="play_arrow",c.classList.add("font-weight-bold");progressTimer&&clearTimeout(progressTimer);"play"==playstate&&(progressTimer=setTimeout(function(){currentSong.elapsedTime++;setCounter(currentSong.currentSongId,currentSong.totalTime,currentSong.elapsedTime)},1E3))} c.getAttribute("data-songpos"),c.classList.remove("font-weight-bold"));if(c=document.getElementById("queueTrackId"+a))d=c.getElementsByTagName("td"),d[4].innerText=b,d[0].classList.add("material-icons"),d[0].innerText="play_arrow",c.classList.add("font-weight-bold");progressTimer&&clearTimeout(progressTimer);"play"==playstate&&(progressTimer=setTimeout(function(){currentSong.elapsedTime++;setCounter(currentSong.currentSongId,currentSong.totalTime,currentSong.elapsedTime)},1E3))}
@ -65,21 +68,22 @@ function parseState(a){if(JSON.stringify(a)!==JSON.stringify(lastState)){if(1==a
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.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_PLAYER_CURRENT_SONG"},songChange);"-1"==a.data.songPos&&(domCache.currentTrack.innerText="Not playing",domCache.currentAlbum.innerText="",domCache.currentArtist.innerText="",domCache.currentCover.style.backgroundImage= 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_PLAYER_CURRENT_SONG"},songChange);"-1"==a.data.songPos&&(domCache.currentTrack.innerText="Not playing",domCache.currentAlbum.innerText="",domCache.currentArtist.innerText="",domCache.currentCover.style.backgroundImage=
"");lastState=a}}function getQueue(){2<=app.current.search.length?sendAPI({cmd:"MPD_API_QUEUE_SEARCH",data:{filter:app.current.filter,offset:app.current.page,searchstr:app.current.search}},parseQueue):sendAPI({cmd:"MPD_API_QUEUE_LIST",data:{offset:app.current.page}},parseQueue)} "");lastState=a}}function getQueue(){2<=app.current.search.length?sendAPI({cmd:"MPD_API_QUEUE_SEARCH",data:{filter:app.current.filter,offset:app.current.page,searchstr:app.current.search}},parseQueue):sendAPI({cmd:"MPD_API_QUEUE_LIST",data:{offset:app.current.page}},parseQueue)}
function parseQueue(a){if("Queue"===app.current.app){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); function parseQueue(a){if("Queue"===app.current.app){0<a.totalTime&&a.totalEntities<=settings.maxElementsPerPage?document.getElementById("panel-heading-queue").innerText=a.totalEntities+" "+(1<a.totalEntities?"Songs":"Song")+" \u2013 "+beautifyDuration(a.totalTime):0<a.totalEntities?document.getElementById("panel-heading-queue").innerText=a.totalEntities+" "+(1<a.totalEntities?"Songs":"Song"):document.getElementById("panel-heading-queue").innerText="";var b=a.data.length,c=document.getElementById(app.current.app+
c=c.getElementsByTagName("tbody")[0];for(var d=c.getElementsByTagName("tr"),e=0;e<b;e++)if(!d[e]||d[e].getAttribute("data-trackid")!=a.data[e].id||d[e].getAttribute("data-songpos")!=a.data[e].pos+1){var f=Math.floor(a.data[e].duration/60),g=a.data[e].duration-60*f;f=f+":"+(10>g?"0":"")+g;g=document.createElement("tr");g.setAttribute("draggable","true");g.setAttribute("data-trackid",a.data[e].id);g.setAttribute("id","queueTrackId"+a.data[e].id);g.setAttribute("data-songpos",a.data[e].pos+1);g.setAttribute("data-duration", "List");c.setAttribute("data-version",a.queueVersion);c=c.getElementsByTagName("tbody")[0];for(var d=c.getElementsByTagName("tr"),e=0;e<b;e++)if(!d[e]||d[e].getAttribute("data-trackid")!=a.data[e].id||d[e].getAttribute("data-songpos")!=a.data[e].pos+1){var f=Math.floor(a.data[e].duration/60),g=a.data[e].duration-60*f;f=f+":"+(10>g?"0":"")+g;g=document.createElement("tr");g.setAttribute("draggable","true");g.setAttribute("data-trackid",a.data[e].id);g.setAttribute("id","queueTrackId"+a.data[e].id);
f);g.setAttribute("data-uri",a.data[e].uri);g.innerHTML="<td>"+(a.data[e].pos+1)+"</td><td>"+a.data[e].title+"</td><td>"+a.data[e].artist+"</td><td>"+a.data[e].album+"</td><td>"+f+'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';e<d.length?d[e].replaceWith(g):c.append(g)}for(e=d.length-1;e>=b;e--)d[e].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>': g.setAttribute("data-songpos",a.data[e].pos+1);g.setAttribute("data-duration",f);g.setAttribute("data-uri",a.data[e].uri);g.innerHTML="<td>"+(a.data[e].pos+1)+"</td><td>"+a.data[e].title+"</td><td>"+a.data[e].artist+"</td><td>"+a.data[e].album+"</td><td>"+f+'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';e<d.length?d[e].replaceWith(g):c.append(g)}for(e=d.length-1;e>=b;e--)d[e].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")}} "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 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],d=c.getElementsByTagName("tr"),e=0;e<b;e++){var f=encodeURI(a.data[e].uri);if(!d[e]||d[e].getAttribute("data-uri")!=f){var g=document.createElement("tr");g.setAttribute("data-type",a.data[e].type);g.setAttribute("data-uri",f);g.setAttribute("data-name", function parseFilesystem(a){if("Browse"===app.current.app||"Filesystem"===app.current.tab||"Search"===app.current.app){for(var b=a.data.length,c=document.getElementById(app.current.app+(void 0==app.current.tab?"":app.current.tab)+"List").getElementsByTagName("tbody")[0],d=c.getElementsByTagName("tr"),e=0;e<b;e++){var f=encodeURI(a.data[e].uri);if(!d[e]||d[e].getAttribute("data-uri")!=f){var g=document.createElement("tr");g.setAttribute("data-type",a.data[e].type);g.setAttribute("data-uri",f);g.setAttribute("data-name",
a.data[e].name);switch(a.data[e].type){case "dir":g.innerHTML='<td><span class="material-icons">folder_open</span></td><td colspan="4">'+a.data[e].name+'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';break;case "song":f=Math.floor(a.data[e].duration/60);var h=a.data[e].duration-60*f;g.innerHTML='<td><span class="material-icons">music_note</span></td><td>'+a.data[e].title+"</td><td>"+a.data[e].artist+"</td><td>"+a.data[e].album+"</td><td>"+f+":"+(10>h?"0":"")+h+'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>'; a.data[e].name);switch(a.data[e].type){case "dir":g.innerHTML='<td><span class="material-icons">folder_open</span></td><td colspan="4">'+a.data[e].name+'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';break;case "song":f=Math.floor(a.data[e].duration/60);var h=a.data[e].duration-60*f;g.innerHTML='<td><span class="material-icons">music_note</span></td><td>'+a.data[e].title+"</td><td>"+a.data[e].artist+"</td><td>"+a.data[e].album+"</td><td>"+f+":"+(10>h?"0":"")+h+'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';
break;case "plist":g.innerHTML='<td><span class="material-icons">list</span></td><td colspan="4">'+a.data[e].name+'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>'}e<d.length?d[e].replaceWith(g):c.append(g)}}for(e=d.length-1;e>=b;e--)d[e].remove();setPagination(a.totalEntities);0==b&&(c.innerHTML='<tr><td><span class="material-icons">error_outline</span></td><td colspan="5">No results</td></tr>');document.getElementById(app.current.app+(void 0==app.current.tab?"": break;case "smartpls":case "plist":g.innerHTML='<td><span class="material-icons">list</span></td><td colspan="4">'+a.data[e].name+'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>'}e<d.length?d[e].replaceWith(g):c.append(g)}}for(e=d.length-1;e>=b;e--)d[e].remove();setPagination(a.totalEntities);0==b&&(c.innerHTML='<tr><td><span class="material-icons">error_outline</span></td><td colspan="5">No results</td></tr>');document.getElementById(app.current.app+(void 0==app.current.tab?
app.current.tab)+"List").classList.remove("opacity05")}} "":app.current.tab)+"List").classList.remove("opacity05")}}
function parsePlaylists(a){if("Browse"===app.current.app||"Playlists"===app.current.tab){"All"==app.current.view?(document.getElementById("BrowsePlaylistsAllList").classList.remove("hide"),document.getElementById("BrowsePlaylistsDetailList").classList.add("hide"),document.getElementById("btnBrowsePlaylistsAll").parentNode.classList.add("hide"),document.getElementById("btnPlaylistClear").parentNode.classList.add("hide")):(-1<a.uri.indexOf(".")?(document.getElementById("BrowsePlaylistsDetailList").setAttribute("data-ro", function parsePlaylists(a){if("Browse"===app.current.app||"Playlists"===app.current.tab){"All"==app.current.view?(document.getElementById("BrowsePlaylistsAllList").classList.remove("hide"),document.getElementById("BrowsePlaylistsDetailList").classList.add("hide"),document.getElementById("btnBrowsePlaylistsAll").parentNode.classList.add("hide"),document.getElementById("btnPlaylistClear").parentNode.classList.add("hide")):(-1<a.uri.indexOf(".")||1==a.smartpls?(document.getElementById("BrowsePlaylistsDetailList").setAttribute("data-ro",
"true"),document.getElementById("btnPlaylistClear").parentNode.classList.add("hide")):(document.getElementById("BrowsePlaylistsDetailList").setAttribute("data-ro","false"),document.getElementById("btnPlaylistClear").parentNode.classList.remove("hide")),document.getElementById("BrowsePlaylistsDetailList").setAttribute("data-uri",a.uri),document.getElementById("BrowsePlaylistsDetailList").getElementsByTagName("caption")[0].innerText="Playlist: "+a.uri,document.getElementById("BrowsePlaylistsDetailList").classList.remove("hide"), "true"),document.getElementById("btnPlaylistClear").parentNode.classList.add("hide")):(document.getElementById("BrowsePlaylistsDetailList").setAttribute("data-ro","false"),document.getElementById("btnPlaylistClear").parentNode.classList.remove("hide")),document.getElementById("BrowsePlaylistsDetailList").setAttribute("data-uri",a.uri),1==a.smartpls?document.getElementById("BrowsePlaylistsDetailList").getElementsByTagName("caption")[0].innerText="Smart playlist: "+a.uri:document.getElementById("BrowsePlaylistsDetailList").getElementsByTagName("caption")[0].innerText=
document.getElementById("BrowsePlaylistsAllList").classList.add("hide"),document.getElementById("btnBrowsePlaylistsAll").parentNode.classList.remove("hide"));var b=a.data.length,c=document.getElementById(app.current.app+app.current.tab+app.current.view+"List").getElementsByTagName("tbody")[0],d=c.getElementsByTagName("tr");if("All"==app.current.view)for(var e=0;e<b;e++){var f=encodeURI(a.data[e].uri);if(!d[e]||d[e].getAttribute("data-uri")!=f){var g=new Date(1E3*a.data[e].last_modified),h=document.createElement("tr"); "Playlist: "+a.uri,document.getElementById("BrowsePlaylistsDetailList").classList.remove("hide"),document.getElementById("BrowsePlaylistsAllList").classList.add("hide"),document.getElementById("btnBrowsePlaylistsAll").parentNode.classList.remove("hide"));var b=a.data.length,c=document.getElementById(app.current.app+app.current.tab+app.current.view+"List").getElementsByTagName("tbody")[0],d=c.getElementsByTagName("tr");if("All"==app.current.view)for(var e=0;e<b;e++){var f=encodeURI(a.data[e].uri);
h.setAttribute("data-uri",f);h.setAttribute("data-type","plist");h.setAttribute("data-name",a.data[e].name);h.innerHTML='<td><span class="material-icons">list</span></td><td>'+a.data[e].name+"</td><td>"+g.toUTCString()+'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';e<d.length?d[e].replaceWith(h):c.append(h)}}else if("Detail"==app.current.view)for(e=0;e<b;e++)if(f=encodeURI(a.data[e].uri),g=a.offset+e+1,!d[e]||d[e].getAttribute("data-uri")!=f||d[e].getAttribute("id")!= if(!d[e]||d[e].getAttribute("data-uri")!=f){var g=new Date(1E3*a.data[e].last_modified),h=document.createElement("tr");h.setAttribute("data-uri",f);h.setAttribute("data-type",a.data[e].type);h.setAttribute("data-name",a.data[e].name);h.innerHTML='<td><span class="material-icons">list</span></td><td>'+a.data[e].name+"</td><td>"+g.toUTCString()+'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';e<d.length?d[e].replaceWith(h):c.append(h)}}else if("Detail"==app.current.view)for(e=
"playlistTrackId"+g){h=document.createElement("tr");h.setAttribute("draggable","true");h.setAttribute("id","playlistTrackId"+g);h.setAttribute("data-type",a.data[e].type);h.setAttribute("data-uri",f);h.setAttribute("data-name",a.data[e].name);h.setAttribute("data-songpos",g);f=Math.floor(a.data[e].duration/60);var k=a.data[e].duration-60*f;h.innerHTML="<td>"+g+"</td><td>"+a.data[e].title+"</td><td>"+a.data[e].artist+"</td><td>"+a.data[e].album+"</td><td>"+f+":"+(10>k?"0":"")+k+'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>'; 0;e<b;e++)if(f=encodeURI(a.data[e].uri),g=a.offset+e+1,!d[e]||d[e].getAttribute("data-uri")!=f||d[e].getAttribute("id")!="playlistTrackId"+g){h=document.createElement("tr");0==a.smartpls&&h.setAttribute("draggable","true");h.setAttribute("id","playlistTrackId"+g);h.setAttribute("data-type",a.data[e].type);h.setAttribute("data-uri",f);h.setAttribute("data-name",a.data[e].name);h.setAttribute("data-songpos",g);f=Math.floor(a.data[e].duration/60);var k=a.data[e].duration-60*f;h.innerHTML="<td>"+g+"</td><td>"+
e<d.length?d[e].replaceWith(h):c.append(h)}for(e=d.length-1;e>=b;e--)d[e].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")}} a.data[e].title+"</td><td>"+a.data[e].artist+"</td><td>"+a.data[e].album+"</td><td>"+f+":"+(10>k?"0":"")+k+'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';e<d.length?d[e].replaceWith(h):c.append(h)}for(e=d.length-1;e>=b;e--)d[e].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(""!=app.current.search){document.getElementById("BrowseDatabaseAlbumList").classList.remove("hide");document.getElementById("BrowseDatabaseTagList").classList.add("hide");document.getElementById("btnBrowseDatabaseByTag").parentNode.classList.add("hide");document.getElementById("btnBrowseDatabaseTag").parentNode.classList.remove("hide");document.getElementById("BrowseDatabaseAddAllSongs").parentNode.parentNode.classList.remove("hide");document.getElementById("btnBrowseDatabaseTag").innerHTML= function parseListDBtags(a){if(""!=app.current.search){document.getElementById("BrowseDatabaseAlbumList").classList.remove("hide");document.getElementById("BrowseDatabaseTagList").classList.add("hide");document.getElementById("btnBrowseDatabaseByTag").parentNode.classList.add("hide");document.getElementById("btnBrowseDatabaseTag").parentNode.classList.remove("hide");document.getElementById("BrowseDatabaseAddAllSongs").parentNode.parentNode.classList.remove("hide");document.getElementById("btnBrowseDatabaseTag").innerHTML=
"&laquo; "+app.current.view;document.getElementById("BrowseDatabaseAlbumListCaption").innerText=a.searchtagtype+": "+a.searchstr;for(var b=a.data.length,c=document.getElementById("BrowseDatabaseAlbumList"),d=c.getElementsByClassName("col-md"),e=0;e<b;e++){var f=genId(a.data[e].value);if(!d[e]||d[e].getAttribute("id")!=f){var 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" id="albumartist'+ "&laquo; "+app.current.view;document.getElementById("BrowseDatabaseAlbumListCaption").innerText=a.searchtagtype+": "+a.searchstr;for(var b=a.data.length,c=document.getElementById("BrowseDatabaseAlbumList"),d=c.getElementsByClassName("col-md"),e=0;e<b;e++){var f=genId(a.data[e].value);if(!d[e]||d[e].getAttribute("id")!=f){var 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" id="albumartist'+
f+'"></h5> <h4 class="card-title">'+a.data[e].value+'</h4> <table class="table table-sm table-hover" id="tbl'+f+'"><tbody></tbody></table </div></div>';e<d.length?d[e].replaceWith(g):c.append(g);sendAPI({cmd:"MPD_API_DATABASE_TAG_ALBUM_TITLE_LIST",data:{album:a.data[e].value,search:app.current.search,tag:app.current.view}},parseListTitles)}}for(e=d.length-1;e>=b;e--)d[e].remove();setPagination(a.totalEntities);document.getElementById("BrowseDatabaseAlbumList").classList.remove("opacity05")}else{document.getElementById("BrowseDatabaseAlbumList").classList.add("hide"); f+'"></h5> <h4 class="card-title">'+a.data[e].value+'</h4> <table class="table table-sm table-hover" id="tbl'+f+'"><tbody></tbody></table </div></div>';e<d.length?d[e].replaceWith(g):c.append(g);sendAPI({cmd:"MPD_API_DATABASE_TAG_ALBUM_TITLE_LIST",data:{album:a.data[e].value,search:app.current.search,tag:app.current.view}},parseListTitles)}}for(e=d.length-1;e>=b;e--)d[e].remove();setPagination(a.totalEntities);document.getElementById("BrowseDatabaseAlbumList").classList.remove("opacity05")}else{document.getElementById("BrowseDatabaseAlbumList").classList.add("hide");
@ -95,45 +99,56 @@ function replaceQueue(a,b,c){switch(a){case "song":case "dir":sendAPI({cmd:"MPD_
function artistClick(){var a=domCache.currentArtist.getAttribute("data-albumartist");""!=a&&appGoto("Browse","Database","AlbumArtist","0/-/"+a)}function albumClick(){var a=domCache.currentAlbum.getAttribute("data-album");""!=a&&appGoto("Browse","Database","Album","0/-/"+a)}function songDetails(a){sendAPI({cmd:"MPD_API_DATABASE_SONGDETAILS",data:{uri:a}},parseSongDetails);modalSongDetails.show()} function artistClick(){var a=domCache.currentArtist.getAttribute("data-albumartist");""!=a&&appGoto("Browse","Database","AlbumArtist","0/-/"+a)}function albumClick(){var a=domCache.currentAlbum.getAttribute("data-album");""!=a&&appGoto("Browse","Database","Album","0/-/"+a)}function songDetails(a){sendAPI({cmd:"MPD_API_DATABASE_SONGDETAILS",data:{uri:a}},parseSongDetails);modalSongDetails.show()}
function parseSongDetails(a){var b=document.getElementById("modalSongDetails");b.getElementsByClassName("album-cover")[0].style.backgroundImage='url("'+a.data.cover+'")';b.getElementsByTagName("h1")[0].innerText=a.data.title;var c="";for(f in settings.tags)if(1==settings.tags[f]){var d=a.data[f.toLowerCase()];if("duration"==f){var e=Math.floor(d/60);d-=60*e;d=e+":"+(10>d?"0":"")+d}c+="<tr><th>"+f+"</th><td>"+d+"</td></tr>"}c+='<tr><th>Uri</th><td><a class="text-success" href="/library/'+a.data.uri+ function parseSongDetails(a){var b=document.getElementById("modalSongDetails");b.getElementsByClassName("album-cover")[0].style.backgroundImage='url("'+a.data.cover+'")';b.getElementsByTagName("h1")[0].innerText=a.data.title;var c="";for(f in settings.tags)if(1==settings.tags[f]){var d=a.data[f.toLowerCase()];if("duration"==f){var e=Math.floor(d/60);d-=60*e;d=e+":"+(10>d?"0":"")+d}c+="<tr><th>"+f+"</th><td>"+d+"</td></tr>"}c+='<tr><th>Uri</th><td><a class="text-success" href="/library/'+a.data.uri+
'">'+a.data.uri+"</a></td></tr>";if(1==settings.stickers){var f="not voted";0==a.data.like?f='<span class="material-icons">thumb_down_alt</span>':2==a.data.like&&(f='<span class="material-icons">thumb_up_alt</span>');c+='<tr><th colspan="2">Statistics</th></tr><tr><th>Play count</th><td>'+a.data.playCount+"</td></tr><tr><th>Skip count</th><td>"+a.data.skipCount+"</td></tr><tr><th>Last played</th><td>"+(0==a.data.lastPlayed?"never":(new Date(1E3*a.data.lastPlayed)).toUTCString())+"</td></tr><tr><th>Like</th><td>"+ '">'+a.data.uri+"</a></td></tr>";if(1==settings.stickers){var f="not voted";0==a.data.like?f='<span class="material-icons">thumb_down_alt</span>':2==a.data.like&&(f='<span class="material-icons">thumb_up_alt</span>');c+='<tr><th colspan="2">Statistics</th></tr><tr><th>Play count</th><td>'+a.data.playCount+"</td></tr><tr><th>Skip count</th><td>"+a.data.skipCount+"</td></tr><tr><th>Last played</th><td>"+(0==a.data.lastPlayed?"never":(new Date(1E3*a.data.lastPlayed)).toUTCString())+"</td></tr><tr><th>Like</th><td>"+
f+"</td></tr>"}b.getElementsByTagName("tbody")[0].innerHTML=c}function playlistDetails(a){appGoto("Browse","Playlists","Detail","0/-/"+a)}function removeFromPlaylist(a,b){b--;sendAPI({cmd:"MPD_API_PLAYLIST_RM_TRACK",data:{uri:a,track:b}});document.getElementById("BrowsePlaylistsDetailList").classList.add("opacity05");sendAPI({cmd:"MPD_API_PLAYLIST_CONTENT_LIST",data:{offset:app.current.page,filter:app.current.filter,uri:app.current.search}},parsePlaylists)} f+"</td></tr>"}b.getElementsByTagName("tbody")[0].innerHTML=c}function playlistDetails(a){document.getElementById("BrowsePlaylistsAllList").classList.add("opacity05");appGoto("Browse","Playlists","Detail","0/-/"+a)}
function removeFromPlaylist(a,b){b--;sendAPI({cmd:"MPD_API_PLAYLIST_RM_TRACK",data:{uri:a,track:b}});document.getElementById("BrowsePlaylistsDetailList").classList.add("opacity05");sendAPI({cmd:"MPD_API_PLAYLIST_CONTENT_LIST",data:{offset:app.current.page,filter:app.current.filter,uri:app.current.search}},parsePlaylists)}
function playlistClear(){var a=document.getElementById("BrowsePlaylistsDetailList").getAttribute("data-uri");sendAPI({cmd:"MPD_API_PLAYLIST_CLEAR",data:{uri:a}});document.getElementById("BrowsePlaylistsDetailList").classList.add("opacity05");sendAPI({cmd:"MPD_API_PLAYLIST_CONTENT_LIST",data:{offset:app.current.page,filter:app.current.filter,uri:app.current.search}},parsePlaylists)} function playlistClear(){var a=document.getElementById("BrowsePlaylistsDetailList").getAttribute("data-uri");sendAPI({cmd:"MPD_API_PLAYLIST_CLEAR",data:{uri:a}});document.getElementById("BrowsePlaylistsDetailList").classList.add("opacity05");sendAPI({cmd:"MPD_API_PLAYLIST_CONTENT_LIST",data:{offset:app.current.page,filter:app.current.filter,uri:app.current.search}},parsePlaylists)}
function getAllPlaylists(a){var b=a.data.length,c="";0==a.offset&&("addToPlaylistPlaylist"==playlistEl?c="<option></option><option>New Playlist</option>":"jukeboxPlaylist"==playlistEl&&(c="<option>Database</option>"));for(var d=0;d<b;d++)c+="<option","jukeboxPlaylist"==playlistEl&&a.data[d].uri==settings.jukeboxPlaylist&&(c+=" selected"),c+=">"+a.data[d].uri+"</option>";0==a.offset?document.getElementById(playlistEl).innerHTML=c:document.getElementById(playlistEl).innerHTML+=c;a.totalEntities>a.returnedEntities&& function getAllPlaylists(a){var b=a.data.length,c="";0==a.offset&&("addToPlaylistPlaylist"==playlistEl?c="<option></option><option>New Playlist</option>":"selectJukeboxPlaylist"==playlistEl&&(c="<option>Database</option>"));for(var d=0;d<b;d++)c+="<option","selectJukeboxPlaylist"==playlistEl&&a.data[d].uri==settings.jukeboxPlaylist&&(c+=" selected"),c+=">"+a.data[d].uri+"</option>";0==a.offset?document.getElementById(playlistEl).innerHTML=c:document.getElementById(playlistEl).innerHTML+=c;a.totalEntities>
(a.offset+=settings.maxElementsPerPage,sendAPI({cmd:"MPD_API_PLAYLIST_LIST",data:{offset:a.offset,filter:"-"}},getAllPlaylists))}function voteSong(a){var b=domCache.currentTrack.getAttribute("data-uri");""!=b&&(2==a&&domCache.btnVoteUp.classList.contains("active-fg-green")?a=1:0==a&&domCache.btnVoteDown.classList.contains("active-fg-red")&&(a=1),sendAPI({cmd:"MPD_API_LIKE",data:{uri:b,like:a}}),setVoteSongBtns(a,b))} a.returnedEntities&&(a.offset+=settings.maxElementsPerPage,sendAPI({cmd:"MPD_API_PLAYLIST_LIST",data:{offset:a.offset,filter:"-"}},getAllPlaylists))}function updateSmartPlaylists(){sendAPI({cmd:"MPD_API_SMARTPLS_UPDATE_ALL"})}
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")): 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"))} 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 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 saveSearchAsSmartPlaylist(){parseSmartPlaylist({type:"smartpls",data:{playlist:"",type:"search",tag:app.current.filter,searchstr:app.current.search}})}
function parseSmartPlaylist(a){var b=document.getElementById("saveSmartPlaylistName");b.value=a.data.playlist;b.classList.remove("is-invalid");document.getElementById("saveSmartPlaylistType").value=a.data.type;document.getElementById("saveSmartPlaylistFrm").classList.remove("was-validated");document.getElementById("saveSmartPlaylistSearch").classList.add("hide");document.getElementById("saveSmartPlaylistSticker").classList.add("hide");document.getElementById("saveSmartPlaylistNewest").classList.add("hide");
var c='<option value="any">Any Tag</option>',d;for(d in settings.tags)1==settings.tags[d]&&"Track"!=d&&(c+='<option value="'+d+'">'+d+"</option>");document.getElementById("selectSaveSmartPlaylistTag").innerHTML=c;"search"==a.data.type?(document.getElementById("saveSmartPlaylistSearch").classList.remove("hide"),document.getElementById("selectSaveSmartPlaylistTag").value=a.data.tag,document.getElementById("inputSaveSmartPlaylistSearchstr").value=a.data.searchstr):"sticker"==a.data.type?(document.getElementById("saveSmartPlaylistSticker").classList.remove("hide"),
document.getElementById("selectSaveSmartPlaylistSticker").value=a.data.sticker,document.getElementById("inputSaveSmartPlaylistStickerMaxentries").value=a.data.maxentries):"newest"==a.data.type&&(document.getElementById("saveSmartPlaylistNewest").classList.remove("hide"),c=a.data.timerange/24/60/60,document.getElementById("inputSaveSmartPlaylistNewestTimerange").value=c,document.getElementById("inputSaveSmartPlaylistNewestMaxentries").value=a.data.maxentries);modalSaveSmartPlaylist.show();b.focus()}
function chkInt(a,b){if(""!=a.value.replace(/\d/g,""))return a.classList.add("is-invalid"),b.classList.add("was-validated"),!1;a.classList.remove("is-invalid");return!0}
function saveSmartPlaylist(){var a=document.getElementById("saveSmartPlaylistName").value,b=document.getElementById("saveSmartPlaylistType").value,c=a.replace(/[\w\-]/g,""),d=document.getElementById("saveSmartPlaylistFrm");if(""!=a&&""==c){if("search"==b)d=document.getElementById("selectSaveSmartPlaylistTag"),d=d.options[d.selectedIndex].value,c=document.getElementById("inputSaveSmartPlaylistSearchstr").value,sendAPI({cmd:"MPD_API_SMARTPLS_SAVE",data:{type:b,playlist:a,tag:d,searchstr:c}});else if("sticker"==
b){c=document.getElementById("selectSaveSmartPlaylistSticker");c=c.options[c.selectedIndex].value;var e=document.getElementById("inputSaveSmartPlaylistStickerMaxentries");if(!chkInt(e,d))return;d=e.value;sendAPI({cmd:"MPD_API_SMARTPLS_SAVE",data:{type:b,playlist:a,sticker:c,maxentries:d}})}else if("newest"==b){c=document.getElementById("inputSaveSmartPlaylistNewestTimerange");if(!chkInt(c,d))return;c=86400*parseInt(c.value);e=document.getElementById("inputSaveSmartPlaylistNewestMaxentries");if(!chkInt(e,
d))return;d=e.value;sendAPI({cmd:"MPD_API_SMARTPLS_SAVE",data:{type:b,playlist:a,timerange:c,maxentries:d}})}else{document.getElementById("saveSmartPlaylistType").classList.add("is-invalid");return}modalSaveSmartPlaylist.hide();showNotification("Saved smart playlist "+a,"","","success")}else document.getElementById("saveSmartPlaylistName").classList.add("is-invalid"),d.classList.add("was-validated")}
function showAddToPlaylist(a){document.getElementById("addToPlaylistUri").value=a;document.getElementById("addToPlaylistPlaylist").innerHTML="";document.getElementById("addToPlaylistNewPlaylist").value="";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"); function showAddToPlaylist(a){document.getElementById("addToPlaylistUri").value=a;document.getElementById("addToPlaylistPlaylist").innerHTML="";document.getElementById("addToPlaylistNewPlaylist").value="";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"), b.focus();b.value="";b.classList.remove("is-invalid");document.getElementById("addStreamFrm").classList.remove("was-validated");"stream"!=a?(document.getElementById("addStreamFooter").classList.add("hide"),document.getElementById("addStreamFrm").classList.add("hide"),document.getElementById("addToPlaylistFooter").classList.remove("hide"),document.getElementById("addToPlaylistFrm").classList.remove("hide"),document.getElementById("addToPlaylistLabel").innerText="Add to playlist"):(document.getElementById("addStreamFooter").classList.remove("hide"),
document.getElementById("addStreamFrm").classList.remove("hide"),document.getElementById("addToPlaylistFooter").classList.add("hide"),document.getElementById("addToPlaylistFrm").classList.add("hide"),document.getElementById("addToPlaylistLabel").innerText="Add Stream");modalAddToPlaylist.show();playlistEl="addToPlaylistPlaylist";sendAPI({cmd:"MPD_API_PLAYLIST_LIST",data:{offset:0,filter:"-"}},getAllPlaylists)} document.getElementById("addStreamFrm").classList.remove("hide"),document.getElementById("addToPlaylistFooter").classList.add("hide"),document.getElementById("addToPlaylistFrm").classList.add("hide"),document.getElementById("addToPlaylistLabel").innerText="Add Stream");modalAddToPlaylist.show();playlistEl="addToPlaylistPlaylist";sendAPI({cmd:"MPD_API_PLAYLIST_LIST",data:{offset:0,filter:"-"}},getAllPlaylists)}
function addToPlaylist(){var a=document.getElementById("addToPlaylistUri").value;if("stream"==a&&(a=document.getElementById("streamUrl").value,""==a||-1==a.indexOf("http"))){document.getElementById("streamUrl").classList.add("is-invalid");document.getElementById("addStreamFrm").classList.add("was-validated");return}var b=document.getElementById("addToPlaylistPlaylist");b=b.options[b.selectedIndex].text;if("New Playlist"==b){b=document.getElementById("addToPlaylistNewPlaylist").value;var c=b.replace(/\w\-/g, function addToPlaylist(){var a=document.getElementById("addToPlaylistUri").value;if("stream"==a&&(a=document.getElementById("streamUrl").value,""==a||-1==a.indexOf("http"))){document.getElementById("streamUrl").classList.add("is-invalid");document.getElementById("addStreamFrm").classList.add("was-validated");return}var b=document.getElementById("addToPlaylistPlaylist");b=b.options[b.selectedIndex].text;if("New Playlist"==b){b=document.getElementById("addToPlaylistNewPlaylist").value;var c=b.replace(/[\w\-]/g,
"");if(""==b||""!=c){document.getElementById("addToPlaylistNewPlaylist").classList.add("is-invalid");document.getElementById("addToPlaylistFrm").classList.add("was-validated");return}}""!=b?("SEARCH"==a?addAllFromSearchPlist(b):"DATABASE"==a?addAllFromBrowseDatabasePlist(b):sendAPI({cmd:"MPD_API_PLAYLIST_ADD_TRACK",data:{uri:a,plist:b}}),modalAddToPlaylist.hide()):(document.getElementById("addToPlaylistPlaylist").classList.add("is-invalid"),document.getElementById("addToPlaylistFrm").classList.add("was-validated"))} "");if(""==b||""!=c){document.getElementById("addToPlaylistNewPlaylist").classList.add("is-invalid");document.getElementById("addToPlaylistFrm").classList.add("was-validated");return}}""!=b?("SEARCH"==a?addAllFromSearchPlist(b):"DATABASE"==a?addAllFromBrowseDatabasePlist(b):sendAPI({cmd:"MPD_API_PLAYLIST_ADD_TRACK",data:{uri:a,plist:b}}),modalAddToPlaylist.hide()):(document.getElementById("addToPlaylistPlaylist").classList.add("is-invalid"),document.getElementById("addToPlaylistFrm").classList.add("was-validated"))}
function addStream(){var a=document.getElementById("streamUrl").value;""!=a&&0==a.indexOf("http")?(sendAPI({cmd:"MPD_API_QUEUE_ADD_TRACK",data:{uri:a}}),modalAddToPlaylist.hide(),showNotification("Added stream "+a+"to queue","","","success")):(document.getElementById("streamUrl").classList.add("is-invalid"),document.getElementById("addStreamFrm").classList.add("was-validated"))} function addStream(){var a=document.getElementById("streamUrl").value;""!=a&&0==a.indexOf("http")?(sendAPI({cmd:"MPD_API_QUEUE_ADD_TRACK",data:{uri:a}}),modalAddToPlaylist.hide(),showNotification("Added stream "+a+"to queue","","","success")):(document.getElementById("streamUrl").classList.add("is-invalid"),document.getElementById("addStreamFrm").classList.add("was-validated"))}
function showRenamePlaylist(a){document.getElementById("renamePlaylistFrm").classList.remove("was-validated");document.getElementById("renamePlaylistTo").classList.remove("is-invalid");modalRenamePlaylist.show();document.getElementById("renamePlaylistFrom").value=a;document.getElementById("renamePlaylistTo").value=""} function showRenamePlaylist(a){document.getElementById("renamePlaylistFrm").classList.remove("was-validated");document.getElementById("renamePlaylistTo").classList.remove("is-invalid");modalRenamePlaylist.show();document.getElementById("renamePlaylistFrom").value=a;document.getElementById("renamePlaylistTo").value=""}
function renamePlaylist(){var a=document.getElementById("renamePlaylistFrom").value,b=document.getElementById("renamePlaylistTo").value,c=b.replace(/\w\-/g,"");""!=b&&b!=a&&""==c?(sendAPI({cmd:"MPD_API_PLAYLIST_RENAME",data:{from:a,to:b}}),modalRenamePlaylist.hide(),sendAPI({cmd:"MPD_API_PLAYLIST_LIST",data:{offset:app.current.page,filter:app.current.filter}},parsePlaylists)):(document.getElementById("renamePlaylistTo").classList.add("is-invalid"),document.getElementById("renamePlaylistFrm").classList.add("was-validated"))} function renamePlaylist(){var a=document.getElementById("renamePlaylistFrom").value,b=document.getElementById("renamePlaylistTo").value,c=b.replace(/[\w\-]/g,"");""!=b&&b!=a&&""==c?(sendAPI({cmd:"MPD_API_PLAYLIST_RENAME",data:{from:a,to:b}}),modalRenamePlaylist.hide(),sendAPI({cmd:"MPD_API_PLAYLIST_LIST",data:{offset:app.current.page,filter:app.current.filter}},parsePlaylists)):(document.getElementById("renamePlaylistTo").classList.add("is-invalid"),document.getElementById("renamePlaylistFrm").classList.add("was-validated"))}
function dirname(a){return a.replace(/\/[^\/]*$/,"")}function addMenuItem(a,b){return'<a class="dropdown-item" href="#" data-href=\''+btoa(JSON.stringify(a))+"'>"+b+"</a>"} function showSmartPlaylist(a){sendAPI({cmd:"MPD_API_SMARTPLS_GET",data:{playlist:a}},parseSmartPlaylist)}function dirname(a){return a.replace(/\/[^\/]*$/,"")}function b64EncodeUnicode(a){return btoa(encodeURIComponent(a).replace(/%([0-9A-F]{2})/g,function(a,c){return String.fromCharCode("0x"+c)}))}function b64DecodeUnicode(a){return decodeURIComponent(atob(a).split("").map(function(a){return"%"+("00"+a.charCodeAt(0).toString(16)).slice(-2)}).join(""))}
function showMenu(a,b){b.preventDefault();b.stopPropagation();b=document.getElementsByClassName("popover");for(var c=0;c<b.length;c++)b[c].remove();b=a.getAttribute("data-type");var d=decodeURI(a.getAttribute("data-uri"));c=a.getAttribute("data-name");var e=0;if(null==b||null==d)b=a.parentNode.parentNode.getAttribute("data-type"),d=decodeURI(a.parentNode.parentNode.getAttribute("data-uri")),c=a.parentNode.parentNode.getAttribute("data-name");lastState&&(e=lastState.data.nextSongPos);var f="";"Browse"== function addMenuItem(a,b){return'<a class="dropdown-item" href="#" data-href=\''+b64EncodeUnicode(JSON.stringify(a))+"'>"+b+"</a>"}function hideMenu(){var a=document.querySelector("[data-popover]");a&&(new Popover(a,{}),a.Popover.hide(),a.removeAttribute("data-popover"))}
app.current.app&&"Filesystem"==app.current.tab||"Search"==app.current.app||"Browse"==app.current.app&&"Database"==app.current.tab?(f+=addMenuItem({cmd:"appendQueue",options:[b,d,c]},"Append to queue")+("song"==b?addMenuItem({cmd:"appendAfterQueue",options:[b,d,e,c]},"Add after current playing song"):"")+addMenuItem({cmd:"replaceQueue",options:[b,d,c]},"Replace queue")+("plist"!=b?addMenuItem({cmd:"showAddToPlaylist",options:[d]},"Add to playlist"):"")+("song"==b?addMenuItem({cmd:"songDetails",options:[d]}, function showMenu(a,b){b.preventDefault();b.stopPropagation();if(!a.getAttribute("data-init")){hideMenu();b=a.getAttribute("data-type");var c=decodeURI(a.getAttribute("data-uri")),d=a.getAttribute("data-name"),e=0;if(null==b||null==c)b=a.parentNode.parentNode.getAttribute("data-type"),c=decodeURI(a.parentNode.parentNode.getAttribute("data-uri")),d=a.parentNode.parentNode.getAttribute("data-name");lastState&&(e=lastState.data.nextSongPos);var f="";"Browse"==app.current.app&&"Filesystem"==app.current.tab||
"Songdetails"):"")+("plist"==b?addMenuItem({cmd:"playlistDetails",options:[d]},"Show playlist"):""),"Search"==app.current.app&&(d=dirname(d),f+='<div class="dropdown-divider"></div><a class="dropdown-item" id="advancedMenuLink" data-toggle="collapse" href="#advancedMenu"><span class="material-icons material-icons-small-left">keyboard_arrow_right</span>Album actions</a><div class="collapse" id="advancedMenu">'+addMenuItem({cmd:"appendQueue",options:[b,d,c]},"Append to queue")+addMenuItem({cmd:"appendAfterQueue", "Search"==app.current.app||"Browse"==app.current.app&&"Database"==app.current.tab?(f+=addMenuItem({cmd:"appendQueue",options:[b,c,d]},"Append to queue")+("song"==b?addMenuItem({cmd:"appendAfterQueue",options:[b,c,e,d]},"Add after current playing song"):"")+addMenuItem({cmd:"replaceQueue",options:[b,c,d]},"Replace queue")+("plist"!=b&&"smartpls"!=b?addMenuItem({cmd:"showAddToPlaylist",options:[c]},"Add to playlist"):"")+("song"==b?addMenuItem({cmd:"songDetails",options:[c]},"Songdetails"):"")+("plist"==
options:[b,d,e,c]},"Add after current playing song")+addMenuItem({cmd:"replaceQueue",options:[b,d,c]},"Replace queue")+addMenuItem({cmd:"showAddToPlaylist",options:[d]},"Add to playlist")+"</div>")):"Browse"==app.current.app&&"Playlists"==app.current.tab&&"All"==app.current.view?f+=addMenuItem({cmd:"appendQueue",options:[b,d,c]},"Append to queue")+addMenuItem({cmd:"replaceQueue",options:[b,d,c]},"Replace queue")+addMenuItem({cmd:"playlistDetails",options:[d]},"Edit playlist")+addMenuItem({cmd:"showRenamePlaylist", b||"smartpls"==b?addMenuItem({cmd:"playlistDetails",options:[c]},"View playlist"):""),"Search"==app.current.app&&(c=dirname(c),f+='<div class="dropdown-divider"></div><a class="dropdown-item" id="advancedMenuLink" data-toggle="collapse" href="#advancedMenu"><span class="material-icons material-icons-small-left">keyboard_arrow_right</span>Album actions</a><div class="collapse" id="advancedMenu">'+addMenuItem({cmd:"appendQueue",options:[b,c,d]},"Append to queue")+addMenuItem({cmd:"appendAfterQueue",
options:[d]},"Rename playlist")+addMenuItem({cmd:"delPlaylist",options:[d]},"Delete playlist"):"Browse"==app.current.app&&"Playlists"==app.current.tab&&"Detail"==app.current.view?(e=document.getElementById("BrowsePlaylistsDetailList"),f+=addMenuItem({cmd:"appendQueue",options:[b,d,c]},"Append to queue")+addMenuItem({cmd:"replaceQueue",options:[b,d,c]},"Replace queue")+("false"==e.getAttribute("data-ro")?addMenuItem({cmd:"removeFromPlaylist",options:[e.getAttribute("data-uri"),a.parentNode.parentNode.getAttribute("data-songpos")]}, options:[b,c,e,d]},"Add after current playing song")+addMenuItem({cmd:"replaceQueue",options:[b,c,d]},"Replace queue")+addMenuItem({cmd:"showAddToPlaylist",options:[c]},"Add to playlist")+"</div>")):"Browse"==app.current.app&&"Playlists"==app.current.tab&&"All"==app.current.view?f+=addMenuItem({cmd:"appendQueue",options:[b,c,d]},"Append to queue")+addMenuItem({cmd:"replaceQueue",options:[b,c,d]},"Replace queue")+("smartpls"==b?addMenuItem({cmd:"playlistDetails",options:[c]},"View playlist"):addMenuItem({cmd:"playlistDetails",
"Remove"):"")+("plist"!=b?addMenuItem({cmd:"showAddToPlaylist",options:[d]},"Add to playlist"):"")):"Queue"==app.current.app&&(f+=addMenuItem({cmd:"delQueueSong",options:["single",a.parentNode.parentNode.getAttribute("data-trackid")]},"Remove")+addMenuItem({cmd:"delQueueSong",options:["range",0,a.parentNode.parentNode.getAttribute("data-songpos")]},"Remove all upwards")+addMenuItem({cmd:"delQueueSong",options:["range",parseInt(a.parentNode.parentNode.getAttribute("data-songpos"))-1,-1]},"Remove all downwards")+ options:[c]},"Edit playlist"))+("smartpls"==b?addMenuItem({cmd:"showSmartPlaylist",options:[c]},"Edit smart playlist"):"")+(0!=c.indexOf("myMPDsmart")?addMenuItem({cmd:"showRenamePlaylist",options:[c]},"Rename playlist")+addMenuItem({cmd:"delPlaylist",options:[c]},"Delete playlist"):""):"Browse"==app.current.app&&"Playlists"==app.current.tab&&"Detail"==app.current.view?(e=document.getElementById("BrowsePlaylistsDetailList"),f+=addMenuItem({cmd:"appendQueue",options:[b,c,d]},"Append to queue")+addMenuItem({cmd:"replaceQueue",
(-1==d.indexOf("http")?addMenuItem({cmd:"songDetails",options:[d]},"Songdetails"):""));new Popover(a,{trigger:"click",delay:0,dismissible:!0,template:'<div class="popover" role="tooltip"><div class="arrow"></div><div class="popover-content">'+f+"</div></div>"});var g=a.Popover;a.getAttribute("data-init")||(a.setAttribute("data-init","true"),a.addEventListener("shown.bs.popover",function(a){document.getElementsByClassName("popover-content")[0].addEventListener("click",function(a){a.preventDefault(); options:[b,c,d]},"Replace queue")+("false"==e.getAttribute("data-ro")?addMenuItem({cmd:"removeFromPlaylist",options:[e.getAttribute("data-uri"),a.parentNode.parentNode.getAttribute("data-songpos")]},"Remove"):"")+addMenuItem({cmd:"showAddToPlaylist",options:[c]},"Add to playlist")+(-1==c.indexOf("http")?addMenuItem({cmd:"songDetails",options:[c]},"Songdetails"):"")):"Queue"==app.current.app&&(f+=addMenuItem({cmd:"delQueueSong",options:["single",a.parentNode.parentNode.getAttribute("data-trackid")]},
a.stopPropagation();if("A"==a.target.nodeName&&(a=a.target.getAttribute("data-href"))){a=JSON.parse(atob(a));if("function"===typeof window[a.cmd])switch(a.cmd){case "sendAPI":sendAPI.apply(null,$jscomp.arrayFromIterable(a.options));break;default:window[a.cmd].apply(null,$jscomp.arrayFromIterable(a.options))}g.hide()}},!1);if(a=document.getElementById("advancedMenuLink"))a.addEventListener("click",function(a){a=this.getElementsByTagName("span")[0];a.innerText="keyboard_arrow_right"==a.innerText?"keyboard_arrow_down": "Remove")+addMenuItem({cmd:"delQueueSong",options:["range",0,a.parentNode.parentNode.getAttribute("data-songpos")]},"Remove all upwards")+addMenuItem({cmd:"delQueueSong",options:["range",parseInt(a.parentNode.parentNode.getAttribute("data-songpos"))-1,-1]},"Remove all downwards")+(-1==c.indexOf("http")?addMenuItem({cmd:"songDetails",options:[c]},"Songdetails"):""));new Popover(a,{trigger:"click",delay:0,dismissible:!0,template:'<div class="popover" role="tooltip"><div class="arrow"></div><div class="popover-content">'+
"keyboard_arrow_right"},!1),new Collapse(a)},!1));g.show()} f+"</div></div>"});b=a.Popover;a.setAttribute("data-init","true");a.addEventListener("shown.bs.popover",function(a){a.target.setAttribute("data-popover","true");document.getElementsByClassName("popover-content")[0].addEventListener("click",function(a){a.preventDefault();a.stopPropagation();if("A"==a.target.nodeName&&(a=a.target.getAttribute("data-href"))){a=JSON.parse(b64DecodeUnicode(a));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))}hideMenu()}},!1);if(a=document.getElementById("advancedMenuLink"))a.addEventListener("click",function(a){a=this.getElementsByTagName("span")[0];a.innerText="keyboard_arrow_right"==a.innerText?"keyboard_arrow_down":"keyboard_arrow_right"},!1),new Collapse(a)},!1);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 d=JSON.parse(c.responseText);"error"==d.type?(showNotification("Error",d.data,d.data,"danger"),console.log("Error: "+d.data)):"result"==d.type&&"ok"!=d.data?showNotification(d.data,"","","success"):void 0!=b&&"function"==typeof b&&b(d)}else console.log("Empty response for request: "+JSON.stringify(a))}; function sendAPI(a,b){var c=new XMLHttpRequest;c.open("POST","/api",!0);c.setRequestHeader("Content-type","application/json");c.onreadystatechange=function(){if(4==c.readyState)if(""!=c.responseText){var d=JSON.parse(c.responseText);"error"==d.type?(showNotification("Error",d.data,d.data,"danger"),console.log("Error: "+d.data)):"result"==d.type&&"ok"!=d.data?showNotification(d.data,"","","success"):void 0!=b&&"function"==typeof b&&b(d)}else console.log("Empty response for request: "+JSON.stringify(a))};
c.send(JSON.stringify(a))}function openLocalPlayer(){window.open("/player.html#"+settings.mpdstream,"LocalPlayer")}function updateDB(){sendAPI({cmd:"MPD_API_DATABASE_UPDATE"});updateDBstarted(!0)}function rescanDB(){sendAPI({cmd:"MPD_API_DATABASE_RESCAN"});updateDBstarted(!0)} c.send(JSON.stringify(a))}function openLocalPlayer(){window.open("/player.html#"+settings.mpdstream,"LocalPlayer")}function updateDB(){sendAPI({cmd:"MPD_API_DATABASE_UPDATE"});updateDBstarted(!0)}function rescanDB(){sendAPI({cmd:"MPD_API_DATABASE_RESCAN"});updateDBstarted(!0)}
function updateDBstarted(a){1==a?(document.getElementById("updateDBfinished").innerText="",document.getElementById("updateDBfooter").classList.add("hide"),updateDBprogress.style.width="20px",updateDBprogress.style.marginLeft="-20px",modalUpdateDB.show(),document.getElementById("updateDBprogress").classList.add("updateDBprogressAnimate")):showNotification("Database update started","","","success")} function updateDBstarted(a){1==a?(document.getElementById("updateDBfinished").innerText="",document.getElementById("updateDBfooter").classList.add("hide"),updateDBprogress.style.width="20px",updateDBprogress.style.marginLeft="-20px",modalUpdateDB.show(),document.getElementById("updateDBprogress").classList.add("updateDBprogressAnimate")):showNotification("Database update started","","","success")}
function updateDBfinished(a){document.getElementById("modalUpdateDB").classList.contains("show")?("update_database"==a?document.getElementById("updateDBfinished").innerText="Database successfully updated.":"update_finished"==a&&(document.getElementById("updateDBfinished").innerText="Database update finished."),a=document.getElementById("updateDBprogress"),a.classList.remove("updateDBprogressAnimate"),a.style.width="100%",a.style.marginLeft="0px",document.getElementById("updateDBfooter").classList.remove("hide")): function updateDBfinished(a){document.getElementById("modalUpdateDB").classList.contains("show")?("update_database"==a?document.getElementById("updateDBfinished").innerText="Database successfully updated.":"update_finished"==a&&(document.getElementById("updateDBfinished").innerText="Database update finished."),a=document.getElementById("updateDBprogress"),a.classList.remove("updateDBprogressAnimate"),a.style.width="100%",a.style.marginLeft="0px",document.getElementById("updateDBfooter").classList.remove("hide")):
"update_database"==a?showNotification("Database successfully updated.","","","success"):"update_finished"==a&&showNotification("Database update finished.","","","success")}function clickPlay(){"play"!=playstate?sendAPI({cmd:"MPD_API_PLAYER_PLAY"}):sendAPI({cmd:"MPD_API_PLAYER_PAUSE"})}function clickStop(){sendAPI({cmd:"MPD_API_PLAYER_STOP"})}function clickPrev(){sendAPI({cmd:"MPD_API_PLAYER_PREV"})}function clickNext(){sendAPI({cmd:"MPD_API_PLAYER_NEXT"})} "update_database"==a?showNotification("Database successfully updated.","","","success"):"update_finished"==a&&showNotification("Database update finished.","","","success")}function clickPlay(){"play"!=playstate?sendAPI({cmd:"MPD_API_PLAYER_PLAY"}):sendAPI({cmd:"MPD_API_PLAYER_PAUSE"})}function clickStop(){sendAPI({cmd:"MPD_API_PLAYER_STOP"})}function clickPrev(){sendAPI({cmd:"MPD_API_PLAYER_PREV"})}function clickNext(){sendAPI({cmd:"MPD_API_PLAYER_NEXT"})}
function delQueueSong(a,b,c){"range"==a?sendAPI({cmd:"MPD_API_QUEUE_RM_RANGE",data:{start:b,end:c}}):"single"==a&&sendAPI({cmd:"MPD_API_QUEUE_RM_TRACK",data:{track:b}})}function delPlaylist(a){sendAPI({cmd:"MPD_API_PLAYLIST_RM",data:{uri:a}});sendAPI({cmd:"MPD_API_PLAYLIST_LIST",data:{offset:app.current.page,filter:app.current.filter}},parsePlaylists)} function delQueueSong(a,b,c){"range"==a?sendAPI({cmd:"MPD_API_QUEUE_RM_RANGE",data:{start:b,end:c}}):"single"==a&&sendAPI({cmd:"MPD_API_QUEUE_RM_TRACK",data:{track:b}})}function delPlaylist(a){sendAPI({cmd:"MPD_API_PLAYLIST_RM",data:{uri:a}});sendAPI({cmd:"MPD_API_PLAYLIST_LIST",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)? 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("inputJukeboxQueueLength");c=parseInt(b.value);isNaN(c)?(b.classList.add("is-invalid"),a=!1):0<c?b.value=c:(b.classList.add("is-invalid"),a=!1);settings.mixramp&&(b=document.getElementById("inputMixrampdb"),b.getAttribute("disabled")||(c=parseFloat(b.value),isNaN(c)?(b.classList.add("is-invalid"),
(b.classList.add("is-invalid"),a=!1):b.value=c));1==a?(a=document.getElementById("selectReplaygain"),c=document.getElementById("jukeboxPlaylist"),sendAPI({cmd:"MPD_API_SETTINGS_SET",data:{consume:document.getElementById("btnConsume").classList.contains("active")?1:0,random:document.getElementById("btnRandom").classList.contains("active")?1:0,single:document.getElementById("btnSingle").classList.contains("active")?1:0,repeat:document.getElementById("btnRepeat").classList.contains("active")?1:0,replaygain:a.options[a.selectedIndex].value, 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"),c=document.getElementById("selectJukeboxPlaylist"),b=document.getElementById("selectJukeboxMode"),sendAPI({cmd:"MPD_API_SETTINGS_SET",data:{consume:document.getElementById("btnConsume").classList.contains("active")?1:0,random:document.getElementById("btnRandom").classList.contains("active")?
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")?!0:!1,notificationPage:document.getElementById("btnnotifyPage").classList.contains("active")?!0:!1,jukeboxMode:document.getElementById("btnJukebox").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")?
!0:!1,jukeboxPlaylist:c.options[c.selectedIndex].value}},getSettings),modalSettings.hide()):document.getElementById("settingsFrm").classList.add("was-validated")}function addAllFromBrowseFilesystem(){sendAPI({cmd:"MPD_API_QUEUE_ADD_TRACK",data:{uri:app.current.search}});showNotification("Added all songs","","","success")} !0:!1,notificationPage:document.getElementById("btnnotifyPage").classList.contains("active")?!0:!1,jukeboxMode:b.options[b.selectedIndex].value,jukeboxPlaylist:c.options[c.selectedIndex].value,jukeboxQueueLength:document.getElementById("inputJukeboxQueueLength").value}},getSettings),modalSettings.hide()):document.getElementById("settingsFrm").classList.add("was-validated")}
function addAllFromSearchPlist(a){2<=app.current.search.length&&(sendAPI({cmd:"MPD_API_DATABASE_SEARCH",data:{plist:a,filter:app.current.filter,searchstr:app.current.search,offset:0}}),showNotification("Added "+parseInt(document.getElementById("panel-heading-search").innerText)+" songs from search to "+a,"","","success"))} function addAllFromBrowseFilesystem(){sendAPI({cmd:"MPD_API_QUEUE_ADD_TRACK",data:{uri:app.current.search}});showNotification("Added all songs","","","success")}function addAllFromSearchPlist(a){2<=app.current.search.length&&(sendAPI({cmd:"MPD_API_DATABASE_SEARCH",data:{plist:a,filter:app.current.filter,searchstr:app.current.search,offset:0}}),showNotification("Added "+parseInt(document.getElementById("panel-heading-search").innerText)+" songs from search to "+a,"","","success"))}
function addAllFromBrowseDatabasePlist(a){2<=app.current.search.length&&(sendAPI({cmd:"MPD_API_DATABASE_SEARCH",data:{plist:a,filter:app.current.view,searchstr:app.current.search,offset:0}}),showNotification("Added songs from database selection to "+a,"","","success"))}function scrollTo(a){document.body.scrollTop=a;document.documentElement.scrollTop=a} function addAllFromBrowseDatabasePlist(a){2<=app.current.search.length&&(sendAPI({cmd:"MPD_API_DATABASE_SEARCH",data:{plist:a,filter:app.current.view,searchstr:app.current.search,offset:0}}),showNotification("Added songs from database selection to "+a,"","","success"))}function scrollTo(a){document.body.scrollTop=a;document.documentElement.scrollTop=a}
function gotoPage(a){switch(a){case "next":app.current.page+=settings.maxElementsPerPage;break;case "prev":app.current.page-=settings.maxElementsPerPage;0>app.current.page&&(app.current.page=0);break;default:app.current.page=a}appGoto(app.current.app,app.current.tab,app.current.view,app.current.page+"/"+app.current.filter+"/"+app.current.search)} function gotoPage(a){switch(a){case "next":app.current.page+=settings.maxElementsPerPage;break;case "prev":app.current.page-=settings.maxElementsPerPage;0>app.current.page&&(app.current.page=0);break;default:app.current.page=a}appGoto(app.current.app,app.current.tab,app.current.view,app.current.page+"/"+app.current.filter+"/"+app.current.search)}
function saveQueue(){var a=document.getElementById("saveQueueName").value,b=a.replace(/\w\-/g,"");""!=a&&""==b?(sendAPI({cmd:"MPD_API_QUEUE_SAVE",data:{plist:a}}),modalSavequeue.hide()):(document.getElementById("saveQueueName").classList.add("is-invalid"),document.getElementById("saveQueueFrm").classList.add("was-validated"))} function saveQueue(){var a=document.getElementById("saveQueueName").value,b=a.replace(/[\w\-]/g,"");""!=a&&""==b?(sendAPI({cmd:"MPD_API_QUEUE_SAVE",data:{plist:a}}),modalSavequeue.hide()):(alert(b),document.getElementById("saveQueueName").classList.add("is-invalid"),document.getElementById("saveQueueFrm").classList.add("was-validated"))}
function showNotification(a,b,c,d){1==settings.notificationWeb&&(b=new Notification(a,{icon:"assets/favicon.ico",body:b}),setTimeout(function(a){a.close()},3E3,b));1==settings.notificationPage&&(document.getElementById("alertBox")?b=document.getElementById("alertBox"):(b=document.createElement("div"),b.setAttribute("id","alertBox"),b.addEventListener("click",function(){hideNotification()},!1)),b.classList.remove("alert-success","alert-danger"),b.classList.add("alert","alert-"+d),b.innerHTML="<div><strong>"+ function showNotification(a,b,c,d){1==settings.notificationWeb&&(b=new Notification(a,{icon:"assets/favicon.ico",body:b}),setTimeout(function(a){a.close()},3E3,b));1==settings.notificationPage&&(document.getElementById("alertBox")?b=document.getElementById("alertBox"):(b=document.createElement("div"),b.setAttribute("id","alertBox"),b.addEventListener("click",function(){hideNotification()},!1)),b.classList.remove("alert-success","alert-danger"),b.classList.add("alert","alert-"+d),b.innerHTML="<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(){var a=document.getElementById("alertBox");a&&a.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 notificationsSupported(){return"Notification"in window}

View File

@ -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= 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)}}: 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, 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-v4.2.1",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(" "); 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.3.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){if(a.request.url.match("^http://"))return!1;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)}))}))}); self.addEventListener("install",function(a){a.waitUntil(caches.open(CACHE).then(function(a){return a.addAll(urlsToCache)}))});self.addEventListener("fetch",function(a){if(a.request.url.match("^http://"))return!1;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)}))}))});

View File

@ -0,0 +1 @@
{"type": "sticker", "sticker": "like", "maxentries": 200}

View File

@ -0,0 +1 @@
{"type": "sticker", "sticker": "playCount", "maxentries": 200}

View File

@ -0,0 +1 @@
{"type": "newest", "timerange": 604800 , "maxentries": 200}

View File

@ -24,10 +24,11 @@
</a> </a>
<div class="dropdown-menu bg-dark"> <div class="dropdown-menu bg-dark">
<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": "showAddToPlaylist", "options": ["stream"]}'>Add Stream</a>
<a id="navDBupdate" class="dropdown-item text-light bg-dark" data-toggle="collapse" href="#menu-dbupdate"><span class="material-icons material-icons-left">keyboard_arrow_right</span>Database</a> <a id="navDBupdate" class="dropdown-item text-light bg-dark" data-toggle="collapse" href="#menu-dbupdate"><span class="material-icons material-icons-left">keyboard_arrow_right</span>Update</a>
<div class="collapse" id="menu-dbupdate"> <div class="collapse" id="menu-dbupdate">
<a class="dropdown-item text-light bg-dark" href="#" data-href='{"cmd": "updateDB", "options": []}'>Update</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": "rescanDB", "options": []}'>Rescan</a> <a class="dropdown-item text-light bg-dark" href="#" data-href='{"cmd": "rescanDB", "options": []}'>Rescan Database</a>
<a class="dropdown-item text-light bg-dark" href="#" data-href='{"cmd": "updateSmartPlaylists", "options": []}'>Update Smart Playlists</a>
</div> </div>
<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-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="#modalSettings">Settings</a>
@ -58,11 +59,11 @@
<h2 class="dropdown-header text-light">Volume: <span id="volumePrct"></span></h2> <h2 class="dropdown-header text-light">Volume: <span id="volumePrct"></span></h2>
<form class="px-4 py-0 pb-3" id="volumeControl"> <form class="px-4 py-0 pb-3" id="volumeControl">
<div class="btn-group"> <div class="btn-group">
<button data-href='{"cmd": "chVolume", "options": [-5]}' class="btn btn-secondary">&minus;</button> <button id="btnChVolumeDown" data-href='{"cmd": "chVolume", "options": [-5]}' class="btn btn-secondary">&minus;</button>
<div class="btn btn-secondary"> <div class="btn btn-secondary">
<input type="range" min="0" max="100" step="1" class="form-control-range" id="volumeBar"> <input type="range" min="0" max="100" step="1" class="form-control-range" id="volumeBar">
</div> </div>
<button data-href='{"cmd": "chVolume", "options": [5]}' class="btn btn-secondary">+</button> <button id="btnChVolumeUp" data-href='{"cmd": "chVolume", "options": [5]}' class="btn btn-secondary">+</button>
</div> </div>
</form> </form>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
@ -466,6 +467,7 @@
<div class="dropdown-menu bg-dark dropdown-menu-right px-2" id="searchAddAllSongsDropdown"> <div class="dropdown-menu bg-dark dropdown-menu-right px-2" id="searchAddAllSongsDropdown">
<button type="button" class="btn btn-secondary btn-sm btn-block">Add all to queue</button> <button type="button" class="btn btn-secondary btn-sm btn-block">Add all to queue</button>
<button type="button" class="btn btn-secondary btn-sm btn-block">Add all to playlist</button> <button type="button" class="btn btn-secondary btn-sm btn-block">Add all to playlist</button>
<button type="button" class="btn btn-secondary btn-sm btn-block smartpls">Save as smart playlist</button>
</div> </div>
</div> </div>
</div> </div>
@ -540,7 +542,7 @@
<h5 class="modal-title"><span class="material-icons title-icon">error</span> Connection Error</h5> <h5 class="modal-title"><span class="material-icons title-icon">error</span> Connection Error</h5>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<p>Connection to myMPD failed. Trying to reconnect.</p> <p>Connection to myMPD failed. Trying to reconnect to <span id="wsUrl"></span></p>
</div> </div>
</div> </div>
</div> </div>
@ -644,6 +646,74 @@
</div> </div>
</div> </div>
</div> </div>
<div class="modal fade" id="modalSaveSmartPlaylist" 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>Save smart playlist</h5>
<button type="button" class="close" data-dismiss="modal">&times;</button>
</div>
<div class="modal-body">
<form class="needs-validation" id="saveSmartPlaylistFrm" novalidate>
<div class="row">
<div class="form-group col-md-6">
<label for="saveSmartPlaylistName">Name</label>
<input type="text" class="form-control" id="saveSmartPlaylistName"/>
<div class="invalid-feedback">Invalid filename.</div>
</div>
<div class="form-group col-md-6">
<label for="saveSmartPlaylistType">Type</label>
<input type="text" class="form-control" id="saveSmartPlaylistType" readonly/>
<div class="invalid-feedback">Invalid type.</div>
</div>
</div>
<hr/>
<div class="row" id="saveSmartPlaylistSearch" class="hide">
<div class="form-group col-md-6">
<label for="selectSaveSmartPlaylistTag">Tag</label>
<select id="selectSaveSmartPlaylistTag" class="form-control custom-select"></select>
</div>
<div class="form-group col-md-6">
<label for="inputSaveSmartPlaylistSearchstr">Search</label>
<input type="text" class="form-control" id="inputSaveSmartPlaylistSearchstr"/>
</div>
</div>
<div class="row" id="saveSmartPlaylistSticker" class="hide">
<div class="form-group col-md-6">
<label for="selectSaveSmartPlaylistSticker">Sticker</label>
<select id="selectSaveSmartPlaylistSticker" class="form-control custom-select">
<option value="like">Like</option>
<option value="playCount">playCount</option>
</select>
</div>
<div class="form-group col-md-6">
<label for="inputSaveSmartPlaylistStickerMaxentries">Max. entries</label>
<input type="text" class="form-control" id="inputSaveSmartPlaylistStickerMaxentries"/>
<div class="invalid-feedback">Must be a number.</div>
</div>
</div>
<div class="row" id="saveSmartPlaylistNewest" class="hide">
<div class="form-group col-md-6">
<label for="inputSaveSmartPlaylistNewestTimerange">Timerange (days)</label>
<input type="text" class="form-control" id="inputSaveSmartPlaylistNewestTimerange"/>
<div class="invalid-feedback">Must be a number.</div>
</div>
<div class="form-group col-md-6">
<label for="inputSaveSmartPlaylistNewestMaxentries">Max. entries</label>
<input type="text" class="form-control" id="inputSaveSmartPlaylistNewestMaxentries"/>
<div class="invalid-feedback">Must be a number.</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-success" data-href='{"cmd": "saveSmartPlaylist", "options": []}'>Save</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="modalSettings" tabindex="-1"> <div class="modal fade" id="modalSettings" tabindex="-1">
<div class="modal-dialog"> <div class="modal-dialog">
@ -717,16 +787,30 @@
<hr/> <hr/>
<h4>Jukebox</h4> <h4>Jukebox</h4>
<div class="row"> <div class="row">
<div class="form-group col-md-6" data-toggle="buttons"> <div class="form-group input-group col-md-6 border-secondary">
<button data-href='{"cmd": "toggleBtn", "options": ["btnJukebox"]}' id="btnJukebox" type="button" class="btn btn-secondary btn-block" title="Jukebox"> <div class="input-group-prepend">
Jukebox <div class="input-group-text bg-secondary text-light border-secondary">Mode</div>
</button> </div>
<select id="selectJukeboxMode" class="form-control custom-select border-secondary">
<option value="0">Off</option>
<option value="1">Track</option>
<option value="2">Album</option>
</select>
</div> </div>
<div class="form-group input-group col-md-6 border-secondary"> <div class="form-group input-group col-md-6 border-secondary">
<select id="jukeboxPlaylist" class="form-control custom-select border-secondary"> <select id="selectJukeboxPlaylist" class="form-control custom-select border-secondary">
</select> </select>
</div> </div>
</div> </div>
<div class="row">
<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">Min. queue length</div>
</div>
<input id="inputJukeboxQueueLength" type="text" class="form-control border-secondary" value="1">
<div class="invalid-feedback">Must be a number and &gt; 0</div>
</div>
</div>
<hr/> <hr/>
<h4>Notifications</h4> <h4>Notifications</h4>
<div class="row"> <div class="row">

View File

@ -97,6 +97,7 @@ var modalSongDetails = new Modal(document.getElementById('modalSongDetails'));
var modalAddToPlaylist = new Modal(document.getElementById('modalAddToPlaylist')); var modalAddToPlaylist = new Modal(document.getElementById('modalAddToPlaylist'));
var modalRenamePlaylist = new Modal(document.getElementById('modalRenamePlaylist')); var modalRenamePlaylist = new Modal(document.getElementById('modalRenamePlaylist'));
var modalUpdateDB = new Modal(document.getElementById('modalUpdateDB')); var modalUpdateDB = new Modal(document.getElementById('modalUpdateDB'));
var modalSaveSmartPlaylist = new Modal(document.getElementById('modalSaveSmartPlaylist'));
//var mainMenu = new Dropdown(document.getElementById('mainMenu')); //var mainMenu = new Dropdown(document.getElementById('mainMenu'));
//var volumeMenu = new Dropdown(document.getElementById('volumeIcon')); //var volumeMenu = new Dropdown(document.getElementById('volumeIcon'));
@ -259,7 +260,10 @@ function appRoute() {
doSetFilterLetter('BrowseFilesystemFilter'); doSetFilterLetter('BrowseFilesystemFilter');
} }
else if (app.current.app == 'Search') { else if (app.current.app == 'Search') {
document.getElementById('searchstr').focus(); var searchstrEl = document.getElementById('searchstr');
searchstrEl.focus();
if (searchstrEl.value == '' && app.current.search != '')
searchstrEl.value = app.current.search;
if (app.last.app != app.current.app) { if (app.last.app != app.current.app) {
if (app.current.search != '') if (app.current.search != '')
document.getElementById('SearchList').getElementsByTagName('tbody')[0].innerHTML= document.getElementById('SearchList').getElementsByTagName('tbody')[0].innerHTML=
@ -295,6 +299,14 @@ function appInit() {
webSocketConnect(); webSocketConnect();
domCache.volumeBar.value = 0; domCache.volumeBar.value = 0;
document.getElementById('btnChVolumeDown').addEventListener('click', function(event) {
event.stopPropagation();
}, false);
document.getElementById('btnChVolumeUp').addEventListener('click', function(event) {
event.stopPropagation();
}, false);
domCache.volumeBar.addEventListener('click', function(event) { domCache.volumeBar.addEventListener('click', function(event) {
event.stopPropagation(); event.stopPropagation();
}, false); }, false);
@ -348,8 +360,19 @@ function appInit() {
document.getElementById('inputMixrampdelay').classList.remove('is-invalid'); document.getElementById('inputMixrampdelay').classList.remove('is-invalid');
}); });
document.getElementById('selectJukeboxMode').addEventListener('change', function () {
var value = this.options[this.selectedIndex].value;
if (value == 0 || value == 2) {
document.getElementById('inputJukeboxQueueLength').setAttribute('disabled', 'disabled');
document.getElementById('selectJukeboxPlaylist').setAttribute('disabled', 'disabled');
}
else if (value == 1) {
document.getElementById('inputJukeboxQueueLength').removeAttribute('disabled');
document.getElementById('selectJukeboxPlaylist').removeAttribute('disabled');
}
});
document.getElementById('addToPlaylistPlaylist').addEventListener('change',function(event) { document.getElementById('addToPlaylistPlaylist').addEventListener('change', function (event) {
if (this.options[this.selectedIndex].text == 'New Playlist') { if (this.options[this.selectedIndex].text == 'New Playlist') {
document.getElementById('addToPlaylistNewPlaylistDiv').classList.remove('hide'); document.getElementById('addToPlaylistNewPlaylistDiv').classList.remove('hide');
document.getElementById('addToPlaylistNewPlaylist').focus(); document.getElementById('addToPlaylistNewPlaylist').focus();
@ -479,6 +502,9 @@ function appInit() {
else if (event.target.innerText == 'Add all to playlist') { else if (event.target.innerText == 'Add all to playlist') {
showAddToPlaylist('SEARCH'); showAddToPlaylist('SEARCH');
} }
else if (event.target.innerText == 'Save as smart playlist') {
saveSearchAsSmartPlaylist();
}
} }
}, false); }, false);
@ -525,9 +551,10 @@ function appInit() {
}, false); }, false);
document.getElementsByTagName('body')[0].addEventListener('click', function(event) { document.getElementsByTagName('body')[0].addEventListener('click', function(event) {
var oldPopover = document.getElementsByClassName('popover'); // var oldPopover = document.getElementsByClassName('popover');
for (var i = 0; i < oldPopover.length; i++) // for (var i = 0; i < oldPopover.length; i++)
oldPopover[i].remove(); // oldPopover[i].remove();
hideMenu();
}, false); }, false);
dragAndDropTable('QueueList'); dragAndDropTable('QueueList');
@ -677,12 +704,13 @@ function playlistMoveTrack(from, to) {
} }
function webSocketConnect() { function webSocketConnect() {
socket = new WebSocket(getWsUrl()); var wsUrl = getWsUrl();
socket = new WebSocket(wsUrl);
try { try {
socket.onopen = function() { socket.onopen = function() {
console.log('connected'); console.log('connected');
showNotification('Connected to myMPD', '', '', 'success'); showNotification('Connected to myMPD: ' + wsUrl, '', '', 'success');
modalConnectionError.hide(); modalConnectionError.hide();
appRoute(); appRoute();
sendAPI({"cmd": "MPD_API_PLAYER_STATE"}, parseState); sendAPI({"cmd": "MPD_API_PLAYER_STATE"}, parseState);
@ -703,7 +731,7 @@ function webSocketConnect() {
parseState(obj); parseState(obj);
break; break;
case 'disconnected': case 'disconnected':
showNotification('myMPD lost connection to MPD', '', '', 'danger'); showNotification('Lost connection to myMPD: ' + wsUrl, '', '', 'danger');
break; break;
case 'update_queue': case 'update_queue':
if (app.current.app === 'Queue') if (app.current.app === 'Queue')
@ -746,26 +774,18 @@ function webSocketConnect() {
} }
function getWsUrl() { function getWsUrl() {
var pcol; var hostname = window.location.hostname;
var u = document.URL; var protocol = window.location.protocol;
var separator; var port = window.location.port;
if (u.substring(0, 5) == 'https') { if (protocol == 'https:')
pcol = 'wss://'; protocol = 'wss://';
u = u.substr(8);
} else {
pcol = 'ws://';
if (u.substring(0, 4) == 'http')
u = u.substr(7);
}
u = u.split('#');
if (/\/$/.test(u[0]))
separator = '';
else else
separator = '/'; protocol = 'ws://';
return pcol + u[0] + separator + 'ws'; var wsUrl = protocol + hostname + (port != '' ? ':' + port : '') + '/ws';
document.getElementById('wsUrl').innerText = wsUrl;
return wsUrl;
} }
function parseStats(obj) { function parseStats(obj) {
@ -799,7 +819,6 @@ function parseSettings(obj) {
toggleBtn('btnConsume', obj.data.consume); toggleBtn('btnConsume', obj.data.consume);
toggleBtn('btnSingle', obj.data.single); toggleBtn('btnSingle', obj.data.single);
toggleBtn('btnRepeat', obj.data.repeat); toggleBtn('btnRepeat', obj.data.repeat);
toggleBtn('btnJukebox', obj.data.jukeboxMode);
if (obj.data.crossfade != undefined) { if (obj.data.crossfade != undefined) {
document.getElementById('inputCrossfade').removeAttribute('disabled'); document.getElementById('inputCrossfade').removeAttribute('disabled');
@ -850,19 +869,34 @@ function parseSettings(obj) {
var stickerEls = document.getElementsByClassName('stickers'); var stickerEls = document.getElementsByClassName('stickers');
var stickerElsLen = stickerEls.length; var stickerElsLen = stickerEls.length;
var displayStickers = obj.data.stickers == true ? '' : 'none'; var displayStickers = obj.data.stickers == true ? '' : 'none';
for (var i = 0; i < stickerElsLen; i++) { for (var i = 0; i < stickerElsLen; i++)
stickerEls[i].style.display = displayStickers; stickerEls[i].style.display = displayStickers;
}
var smartplsEls = document.getElementsByClassName('smartpls');
var smartplsElsLen = smartplsEls.length;
var displaySmartpls = obj.data.smartpls == true ? '' : 'none';
for (var i = 0; i < smartplsElsLen; i++)
smartplsEls[i].style.display = displaySmartpls;
if (obj.data.mixramp == true) { if (obj.data.mixramp == true)
document.getElementsByClassName('mixramp')[0].style.display = ''; document.getElementsByClassName('mixramp')[0].style.display = '';
} else { else
document.getElementsByClassName('mixramp')[0].style.display = 'none'; document.getElementsByClassName('mixramp')[0].style.display = 'none';
document.getElementById('selectJukeboxMode').value = obj.data.jukeboxMode;
document.getElementById('inputJukeboxQueueLength').value = obj.data.jukeboxQueueLength;
if (obj.data.jukeboxMode == 0 || obj.data.jukeboxMode == 2) {
document.getElementById('inputJukeboxQueueLength').setAttribute('disabled', 'disabled');
document.getElementById('selectJukeboxPlaylist').setAttribute('disabled', 'disabled');
}
else if (obj.data.jukeboxMode == 1) {
document.getElementById('inputJukeboxQueueLength').removeAttribute('disabled');
document.getElementById('selectJukeboxPlaylist').removeAttribute('disabled');
} }
settings = obj.data; settings = obj.data;
playlistEl = 'jukeboxPlaylist'; playlistEl = 'selectJukeboxPlaylist';
sendAPI({"cmd": "MPD_API_PLAYLIST_LIST", "data": {"offset": 0, "filter": "-"}}, getAllPlaylists); sendAPI({"cmd": "MPD_API_PLAYLIST_LIST", "data": {"offset": 0, "filter": "-"}}, getAllPlaylists);
settings.mpdstream = 'http://'; settings.mpdstream = 'http://';
@ -1020,9 +1054,9 @@ function parseQueue(obj) {
return; return;
if (typeof(obj.totalTime) != undefined && obj.totalTime > 0 && obj.totalEntities <= settings.maxElementsPerPage ) if (typeof(obj.totalTime) != undefined && obj.totalTime > 0 && obj.totalEntities <= settings.maxElementsPerPage )
document.getElementById('panel-heading-queue').innerText = obj.totalEntities + ' Songs ' + beautifyDuration(obj.totalTime); document.getElementById('panel-heading-queue').innerText = obj.totalEntities + ' ' + (obj.totalEntities > 1 ? 'Songs' : 'Song') + ' ' + beautifyDuration(obj.totalTime);
else if (obj.totalEntities > 0) else if (obj.totalEntities > 0)
document.getElementById('panel-heading-queue').innerText = obj.totalEntities + ' Songs'; document.getElementById('panel-heading-queue').innerText = obj.totalEntities + ' ' + (obj.totalEntities > 1 ? 'Songs' : 'Song');
else else
document.getElementById('panel-heading-queue').innerText = ''; document.getElementById('panel-heading-queue').innerText = '';
@ -1120,6 +1154,7 @@ function parseFilesystem(obj) {
'<td>' + minutes + ':' + (seconds < 10 ? '0' : '') + seconds + '<td>' + minutes + ':' + (seconds < 10 ? '0' : '') + seconds +
'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>'; '</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';
break; break;
case 'smartpls':
case 'plist': case 'plist':
row.innerHTML = '<td><span class="material-icons">list</span></td>' + row.innerHTML = '<td><span class="material-icons">list</span></td>' +
'<td colspan="4">' + obj.data[i].name + '</td>' + '<td colspan="4">' + obj.data[i].name + '</td>' +
@ -1153,7 +1188,7 @@ function parsePlaylists(obj) {
document.getElementById('btnBrowsePlaylistsAll').parentNode.classList.add('hide'); document.getElementById('btnBrowsePlaylistsAll').parentNode.classList.add('hide');
document.getElementById('btnPlaylistClear').parentNode.classList.add('hide'); document.getElementById('btnPlaylistClear').parentNode.classList.add('hide');
} else { } else {
if (obj.uri.indexOf('.') > -1) { if (obj.uri.indexOf('.') > -1 || obj.smartpls == true) {
document.getElementById('BrowsePlaylistsDetailList').setAttribute('data-ro', 'true') document.getElementById('BrowsePlaylistsDetailList').setAttribute('data-ro', 'true')
document.getElementById('btnPlaylistClear').parentNode.classList.add('hide'); document.getElementById('btnPlaylistClear').parentNode.classList.add('hide');
} }
@ -1162,7 +1197,10 @@ function parsePlaylists(obj) {
document.getElementById('btnPlaylistClear').parentNode.classList.remove('hide'); document.getElementById('btnPlaylistClear').parentNode.classList.remove('hide');
} }
document.getElementById('BrowsePlaylistsDetailList').setAttribute('data-uri', obj.uri); document.getElementById('BrowsePlaylistsDetailList').setAttribute('data-uri', obj.uri);
document.getElementById('BrowsePlaylistsDetailList').getElementsByTagName('caption')[0].innerText = 'Playlist: ' + obj.uri; if (obj.smartpls == true)
document.getElementById('BrowsePlaylistsDetailList').getElementsByTagName('caption')[0].innerText = 'Smart playlist: ' + obj.uri;
else
document.getElementById('BrowsePlaylistsDetailList').getElementsByTagName('caption')[0].innerText = 'Playlist: ' + obj.uri;
document.getElementById('BrowsePlaylistsDetailList').classList.remove('hide'); document.getElementById('BrowsePlaylistsDetailList').classList.remove('hide');
document.getElementById('BrowsePlaylistsAllList').classList.add('hide'); document.getElementById('BrowsePlaylistsAllList').classList.add('hide');
document.getElementById('btnBrowsePlaylistsAll').parentNode.classList.remove('hide'); document.getElementById('btnBrowsePlaylistsAll').parentNode.classList.remove('hide');
@ -1180,7 +1218,7 @@ function parsePlaylists(obj) {
var d = new Date(obj.data[i].last_modified * 1000); var d = new Date(obj.data[i].last_modified * 1000);
var row = document.createElement('tr'); var row = document.createElement('tr');
row.setAttribute('data-uri', uri); row.setAttribute('data-uri', uri);
row.setAttribute('data-type', 'plist'); row.setAttribute('data-type', obj.data[i].type);
row.setAttribute('data-name', obj.data[i].name); row.setAttribute('data-name', obj.data[i].name);
row.innerHTML = '<td><span class="material-icons">list</span></td>' + row.innerHTML = '<td><span class="material-icons">list</span></td>' +
'<td>' + obj.data[i].name + '</td>' + '<td>' + obj.data[i].name + '</td>' +
@ -1200,7 +1238,8 @@ function parsePlaylists(obj) {
if (tr[i].getAttribute('data-uri') == uri && tr[i].getAttribute('id') == 'playlistTrackId' + songpos) if (tr[i].getAttribute('data-uri') == uri && tr[i].getAttribute('id') == 'playlistTrackId' + songpos)
continue; continue;
var row = document.createElement('tr'); var row = document.createElement('tr');
row.setAttribute('draggable','true'); if (obj.smartpls == false)
row.setAttribute('draggable','true');
row.setAttribute('id','playlistTrackId' + songpos); row.setAttribute('id','playlistTrackId' + songpos);
row.setAttribute('data-type', obj.data[i].type); row.setAttribute('data-type', obj.data[i].type);
row.setAttribute('data-uri', uri); row.setAttribute('data-uri', uri);
@ -1500,6 +1539,7 @@ function parseSongDetails(obj) {
} }
function playlistDetails(uri) { function playlistDetails(uri) {
document.getElementById('BrowsePlaylistsAllList').classList.add('opacity05');
appGoto('Browse', 'Playlists', 'Detail', '0/-/' + uri); appGoto('Browse', 'Playlists', 'Detail', '0/-/' + uri);
} }
@ -1523,12 +1563,12 @@ function getAllPlaylists(obj) {
if (obj.offset == 0) { if (obj.offset == 0) {
if (playlistEl == 'addToPlaylistPlaylist') if (playlistEl == 'addToPlaylistPlaylist')
playlists = '<option></option><option>New Playlist</option>'; playlists = '<option></option><option>New Playlist</option>';
else if (playlistEl == 'jukeboxPlaylist') else if (playlistEl == 'selectJukeboxPlaylist')
playlists = '<option>Database</option>'; playlists = '<option>Database</option>';
} }
for (var i = 0; i < nrItems; i++) { for (var i = 0; i < nrItems; i++) {
playlists += '<option'; playlists += '<option';
if (playlistEl == 'jukeboxPlaylist' && obj.data[i].uri == settings.jukeboxPlaylist) if (playlistEl == 'selectJukeboxPlaylist' && obj.data[i].uri == settings.jukeboxPlaylist)
playlists += ' selected'; playlists += ' selected';
playlists += '>' + obj.data[i].uri + '</option>'; playlists += '>' + obj.data[i].uri + '</option>';
} }
@ -1542,6 +1582,10 @@ function getAllPlaylists(obj) {
} }
} }
function updateSmartPlaylists() {
sendAPI({"cmd": "MPD_API_SMARTPLS_UPDATE_ALL"});
}
function voteSong(vote) { function voteSong(vote) {
var uri = domCache.currentTrack.getAttribute('data-uri'); var uri = domCache.currentTrack.getAttribute('data-uri');
if (uri == '') if (uri == '')
@ -1591,6 +1635,101 @@ function toggleAddToPlaylistFrm() {
} }
} }
function saveSearchAsSmartPlaylist() {
parseSmartPlaylist({"type": "smartpls", "data": {"playlist": "", "type": "search", "tag": app.current.filter, "searchstr": app.current.search}});
}
function parseSmartPlaylist(obj) {
var nameEl = document.getElementById('saveSmartPlaylistName');
nameEl.value = obj.data.playlist;
nameEl.classList.remove('is-invalid');
document.getElementById('saveSmartPlaylistType').value = obj.data.type;
document.getElementById('saveSmartPlaylistFrm').classList.remove('was-validated');
document.getElementById('saveSmartPlaylistSearch').classList.add('hide');
document.getElementById('saveSmartPlaylistSticker').classList.add('hide');
document.getElementById('saveSmartPlaylistNewest').classList.add('hide');
var tagList = '<option value="any">Any Tag</option>';
for (var key in settings.tags) {
if (settings.tags[key] == true && key != 'Track') {
tagList += '<option value="' + key + '">' + key + '</option>';
}
}
document.getElementById('selectSaveSmartPlaylistTag').innerHTML = tagList;
if (obj.data.type == 'search') {
document.getElementById('saveSmartPlaylistSearch').classList.remove('hide');
document.getElementById('selectSaveSmartPlaylistTag').value = obj.data.tag;
document.getElementById('inputSaveSmartPlaylistSearchstr').value = obj.data.searchstr;
}
else if (obj.data.type == 'sticker') {
document.getElementById('saveSmartPlaylistSticker').classList.remove('hide');
document.getElementById('selectSaveSmartPlaylistSticker').value = obj.data.sticker;
document.getElementById('inputSaveSmartPlaylistStickerMaxentries').value = obj.data.maxentries;
}
else if (obj.data.type == 'newest') {
document.getElementById('saveSmartPlaylistNewest').classList.remove('hide');
var timerange = obj.data.timerange / 24 / 60 / 60;
document.getElementById('inputSaveSmartPlaylistNewestTimerange').value = timerange;
document.getElementById('inputSaveSmartPlaylistNewestMaxentries').value = obj.data.maxentries;
}
modalSaveSmartPlaylist.show();
nameEl.focus();
}
function chkInt(el, frm) {
var value = el.value.replace(/\d/g,'');
if (value != '') {
el.classList.add('is-invalid');
frm.classList.add('was-validated');
return false;
} else {
el.classList.remove('is-invalid');
return true;
}
}
function saveSmartPlaylist() {
var name = document.getElementById('saveSmartPlaylistName').value;
var type = document.getElementById('saveSmartPlaylistType').value;
var valid = name.replace(/[\w\-]/g, '');
var frm = document.getElementById('saveSmartPlaylistFrm');
if (name != '' && valid == '') {
if (type == 'search') {
var tagEl = document.getElementById('selectSaveSmartPlaylistTag');
var tag = tagEl.options[tagEl.selectedIndex].value;
var searchstr = document.getElementById('inputSaveSmartPlaylistSearchstr').value;
sendAPI({"cmd": "MPD_API_SMARTPLS_SAVE", "data": {"type": type, "playlist": name, "tag": tag, "searchstr": searchstr}});
} else if (type == 'sticker') {
var stickerEl = document.getElementById('selectSaveSmartPlaylistSticker');
var sticker = stickerEl.options[stickerEl.selectedIndex].value;
var maxentriesEl = document.getElementById('inputSaveSmartPlaylistStickerMaxentries');
if (!chkInt(maxentriesEl, frm))
return;
var maxentries = maxentriesEl.value;
sendAPI({"cmd": "MPD_API_SMARTPLS_SAVE", "data": {"type": type, "playlist": name, "sticker": sticker, "maxentries": maxentries}});
} else if (type == 'newest') {
var timerangeEl = document.getElementById('inputSaveSmartPlaylistNewestTimerange');
if (!chkInt(timerangeEl, frm))
return;
var timerange = parseInt(timerangeEl.value) * 60 * 60 * 24;
var maxentriesEl = document.getElementById('inputSaveSmartPlaylistNewestMaxentries');
if (!chkInt(maxentriesEl, frm))
return;
var maxentries = maxentriesEl.value;
sendAPI({"cmd": "MPD_API_SMARTPLS_SAVE", "data": {"type": type, "playlist": name, "timerange": timerange, "maxentries": maxentries}});
}
else {
document.getElementById('saveSmartPlaylistType').classList.add('is-invalid');
return;
}
modalSaveSmartPlaylist.hide();
showNotification('Saved smart playlist ' + name, '', '', 'success');
}
else {
document.getElementById('saveSmartPlaylistName').classList.add('is-invalid');
frm.classList.add('was-validated');
}
}
function showAddToPlaylist(uri) { function showAddToPlaylist(uri) {
document.getElementById('addToPlaylistUri').value = uri; document.getElementById('addToPlaylistUri').value = uri;
document.getElementById('addToPlaylistPlaylist').innerHTML = ''; document.getElementById('addToPlaylistPlaylist').innerHTML = '';
@ -1636,7 +1775,7 @@ function addToPlaylist() {
var plist = plistEl.options[plistEl.selectedIndex].text; var plist = plistEl.options[plistEl.selectedIndex].text;
if (plist == 'New Playlist') { if (plist == 'New Playlist') {
var newPl = document.getElementById('addToPlaylistNewPlaylist').value; var newPl = document.getElementById('addToPlaylistNewPlaylist').value;
var valid = newPl.replace(/\w\-/g, ''); var valid = newPl.replace(/[\w\-]/g, '');
if (newPl != '' && valid == '') { if (newPl != '' && valid == '') {
plist = newPl; plist = newPl;
} else { } else {
@ -1684,7 +1823,7 @@ function showRenamePlaylist(from) {
function renamePlaylist() { function renamePlaylist() {
var from = document.getElementById('renamePlaylistFrom').value; var from = document.getElementById('renamePlaylistFrom').value;
var to = document.getElementById('renamePlaylistTo').value; var to = document.getElementById('renamePlaylistTo').value;
var valid = to.replace(/\w\-/g, ''); var valid = to.replace(/[\w\-]/g, '');
if (to != '' && to != from && valid == '') { if (to != '' && to != from && valid == '') {
sendAPI({"cmd": "MPD_API_PLAYLIST_RENAME", "data": {"from": from, "to": to}}); sendAPI({"cmd": "MPD_API_PLAYLIST_RENAME", "data": {"from": from, "to": to}});
modalRenamePlaylist.hide(); modalRenamePlaylist.hide();
@ -1696,21 +1835,48 @@ function renamePlaylist() {
} }
} }
function showSmartPlaylist(playlist) {
sendAPI({"cmd": "MPD_API_SMARTPLS_GET", "data": {"playlist": playlist}}, parseSmartPlaylist);
}
function dirname(uri) { function dirname(uri) {
return uri.replace(/\/[^\/]*$/, ''); return uri.replace(/\/[^\/]*$/, '');
} }
function b64EncodeUnicode(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,
function toSolidBytes(match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
function b64DecodeUnicode(str) {
return decodeURIComponent(atob(str).split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}
function addMenuItem(href, text) { function addMenuItem(href, text) {
return '<a class="dropdown-item" href="#" data-href=\'' + btoa(JSON.stringify(href)) + '\'>' + text +'</a>'; return '<a class="dropdown-item" href="#" data-href=\'' + b64EncodeUnicode(JSON.stringify(href)) + '\'>' + text +'</a>';
}
function hideMenu() {
var menuEl = document.querySelector('[data-popover]');
if (menuEl) {
new Popover(menuEl, {});
menuEl.Popover.hide();
menuEl.removeAttribute('data-popover');
}
} }
function showMenu(el, event) { function showMenu(el, event) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
var oldPopover = document.getElementsByClassName('popover'); if (el.getAttribute('data-init'))
for (var i = 0; i < oldPopover.length; i++) return;
oldPopover[i].remove();
hideMenu();
var type = el.getAttribute('data-type'); var type = el.getAttribute('data-type');
var uri = decodeURI(el.getAttribute('data-uri')); var uri = decodeURI(el.getAttribute('data-uri'));
@ -1731,9 +1897,9 @@ function showMenu(el, event) {
menu += addMenuItem({"cmd": "appendQueue", "options": [type, uri, name]}, 'Append to queue') + menu += addMenuItem({"cmd": "appendQueue", "options": [type, uri, name]}, 'Append to queue') +
(type == 'song' ? addMenuItem({"cmd": "appendAfterQueue", "options": [type, uri, nextsongpos, name]}, 'Add after current playing song') : '') + (type == 'song' ? addMenuItem({"cmd": "appendAfterQueue", "options": [type, uri, nextsongpos, name]}, 'Add after current playing song') : '') +
addMenuItem({"cmd": "replaceQueue", "options": [type, uri, name]}, 'Replace queue') + addMenuItem({"cmd": "replaceQueue", "options": [type, uri, name]}, 'Replace queue') +
(type != 'plist' ? addMenuItem({"cmd": "showAddToPlaylist", "options": [uri]}, 'Add to playlist') : '') + (type != 'plist' && type != 'smartpls' ? addMenuItem({"cmd": "showAddToPlaylist", "options": [uri]}, 'Add to playlist') : '') +
(type == 'song' ? addMenuItem({"cmd": "songDetails", "options": [uri]}, 'Songdetails') : '') + (type == 'song' ? addMenuItem({"cmd": "songDetails", "options": [uri]}, 'Songdetails') : '') +
(type == 'plist' ? addMenuItem({"cmd": "playlistDetails", "options": [uri]}, 'Show playlist') : ''); (type == 'plist' || type == 'smartpls' ? addMenuItem({"cmd": "playlistDetails", "options": [uri]}, 'View playlist') : '');
if (app.current.app == 'Search') { if (app.current.app == 'Search') {
var baseuri = dirname(uri); var baseuri = dirname(uri);
menu += '<div class="dropdown-divider"></div>' + menu += '<div class="dropdown-divider"></div>' +
@ -1749,9 +1915,11 @@ function showMenu(el, event) {
else if (app.current.app == 'Browse' && app.current.tab == 'Playlists' && app.current.view == 'All') { else if (app.current.app == 'Browse' && app.current.tab == 'Playlists' && app.current.view == 'All') {
menu += addMenuItem({"cmd": "appendQueue", "options": [type, uri, name]}, 'Append to queue') + menu += addMenuItem({"cmd": "appendQueue", "options": [type, uri, name]}, 'Append to queue') +
addMenuItem({"cmd": "replaceQueue", "options": [type, uri, name]},'Replace queue') + addMenuItem({"cmd": "replaceQueue", "options": [type, uri, name]},'Replace queue') +
addMenuItem({"cmd": "playlistDetails", "options": [uri]}, 'Edit playlist') + (type == 'smartpls' ? addMenuItem({"cmd": "playlistDetails", "options": [uri]}, 'View playlist') : addMenuItem({"cmd": "playlistDetails", "options": [uri]}, 'Edit playlist'))+
addMenuItem({"cmd": "showRenamePlaylist", "options": [uri]}, 'Rename playlist') + (type == 'smartpls' ? addMenuItem({"cmd": "showSmartPlaylist", "options": [uri]}, 'Edit smart playlist') : '') +
addMenuItem({"cmd": "delPlaylist", "options": [uri]}, 'Delete playlist'); (uri.indexOf('myMPDsmart') != 0 ?
addMenuItem({"cmd": "showRenamePlaylist", "options": [uri]}, 'Rename playlist') +
addMenuItem({"cmd": "delPlaylist", "options": [uri]}, 'Delete playlist') : '');
} }
else if (app.current.app == 'Browse' && app.current.tab == 'Playlists' && app.current.view == 'Detail') { else if (app.current.app == 'Browse' && app.current.tab == 'Playlists' && app.current.view == 'Detail') {
var x = document.getElementById('BrowsePlaylistsDetailList'); var x = document.getElementById('BrowsePlaylistsDetailList');
@ -1759,7 +1927,8 @@ function showMenu(el, event) {
addMenuItem({"cmd": "replaceQueue", "options": [type, uri, name]}, 'Replace queue') + addMenuItem({"cmd": "replaceQueue", "options": [type, uri, name]}, 'Replace queue') +
(x.getAttribute('data-ro') == 'false' ? addMenuItem({"cmd": "removeFromPlaylist", "options": [x.getAttribute('data-uri'), (x.getAttribute('data-ro') == 'false' ? addMenuItem({"cmd": "removeFromPlaylist", "options": [x.getAttribute('data-uri'),
el.parentNode.parentNode.getAttribute('data-songpos')]}, 'Remove') : '') + el.parentNode.parentNode.getAttribute('data-songpos')]}, 'Remove') : '') +
(type != 'plist' ? addMenuItem({"cmd": "showAddToPlaylist", "options": [uri]}, 'Add to playlist') : ''); addMenuItem({"cmd": "showAddToPlaylist", "options": [uri]}, 'Add to playlist') +
(uri.indexOf('http') == -1 ? addMenuItem({"cmd": "songDetails", "options": [uri]}, 'Songdetails') : '');
} }
else if (app.current.app == 'Queue') { else if (app.current.app == 'Queue') {
menu += addMenuItem({"cmd": "delQueueSong", "options": ["single", el.parentNode.parentNode.getAttribute('data-trackid')]}, 'Remove') + menu += addMenuItem({"cmd": "delQueueSong", "options": ["single", el.parentNode.parentNode.getAttribute('data-trackid')]}, 'Remove') +
@ -1767,27 +1936,22 @@ function showMenu(el, event) {
addMenuItem({"cmd": "delQueueSong", "options": ["range", (parseInt(el.parentNode.parentNode.getAttribute('data-songpos'))-1), -1]}, 'Remove all downwards') + addMenuItem({"cmd": "delQueueSong", "options": ["range", (parseInt(el.parentNode.parentNode.getAttribute('data-songpos'))-1), -1]}, 'Remove all downwards') +
(uri.indexOf('http') == -1 ? addMenuItem({"cmd": "songDetails", "options": [uri]}, 'Songdetails') : ''); (uri.indexOf('http') == -1 ? addMenuItem({"cmd": "songDetails", "options": [uri]}, 'Songdetails') : '');
} }
new Popover(el, { trigger: 'click', delay: 0, dismissible: true, template: '<div class="popover" role="tooltip">' + new Popover(el, { trigger: 'click', delay: 0, dismissible: true, template: '<div class="popover" role="tooltip">' +
'<div class="arrow"></div>' + '<div class="arrow"></div>' +
'<div class="popover-content">' + menu + '</div>' + '<div class="popover-content">' + menu + '</div>' +
'</div>'}); '</div>'});
var popoverInit = el.Popover; var popoverInit = el.Popover;
if (el.getAttribute('data-init')) {
popoverInit.show();
return;
}
el.setAttribute('data-init', 'true'); el.setAttribute('data-init', 'true');
el.addEventListener('shown.bs.popover', function(event) { el.addEventListener('shown.bs.popover', function(event) {
event.target.setAttribute('data-popover', 'true');
document.getElementsByClassName('popover-content')[0].addEventListener('click', function(event) { document.getElementsByClassName('popover-content')[0].addEventListener('click', function(event) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
if (event.target.nodeName == 'A') { if (event.target.nodeName == 'A') {
var dh = event.target.getAttribute('data-href'); var dh = event.target.getAttribute('data-href');
if (dh) { if (dh) {
var cmd = JSON.parse(atob(dh)); var cmd = JSON.parse(b64DecodeUnicode(dh));
if (typeof window[cmd.cmd] === 'function') { if (typeof window[cmd.cmd] === 'function') {
switch(cmd.cmd) { switch(cmd.cmd) {
case 'sendAPI': case 'sendAPI':
@ -1797,7 +1961,7 @@ function showMenu(el, event) {
window[cmd.cmd](... cmd.options); window[cmd.cmd](... cmd.options);
} }
} }
popoverInit.hide(); hideMenu();
} }
} }
}, false); }, false);
@ -1932,6 +2096,20 @@ function confirmSettings() {
formOK = false; formOK = false;
} }
} }
var inputJukeboxQueueLength = document.getElementById('inputJukeboxQueueLength');
var value = parseInt(inputJukeboxQueueLength.value);
if (!isNaN(value)) {
if (value > 0) {
inputJukeboxQueueLength.value = value;
} else {
inputJukeboxQueueLength.classList.add('is-invalid');
formOK = false;
}
}
else {
inputJukeboxQueueLength.classList.add('is-invalid');
formOK = false;
}
if (settings.mixramp) { if (settings.mixramp) {
var inputMixrampdb = document.getElementById('inputMixrampdb'); var inputMixrampdb = document.getElementById('inputMixrampdb');
if (!inputMixrampdb.getAttribute('disabled')) { if (!inputMixrampdb.getAttribute('disabled')) {
@ -1959,7 +2137,8 @@ function confirmSettings() {
if (formOK == true) { if (formOK == true) {
var selectReplaygain = document.getElementById('selectReplaygain'); var selectReplaygain = document.getElementById('selectReplaygain');
var selectJukeboxPlaylist = document.getElementById('jukeboxPlaylist'); var selectJukeboxPlaylist = document.getElementById('selectJukeboxPlaylist');
var selectJukeboxMode = document.getElementById('selectJukeboxMode');
sendAPI({"cmd": "MPD_API_SETTINGS_SET", "data": { sendAPI({"cmd": "MPD_API_SETTINGS_SET", "data": {
"consume": (document.getElementById('btnConsume').classList.contains('active') ? 1 : 0), "consume": (document.getElementById('btnConsume').classList.contains('active') ? 1 : 0),
"random": (document.getElementById('btnRandom').classList.contains('active') ? 1 : 0), "random": (document.getElementById('btnRandom').classList.contains('active') ? 1 : 0),
@ -1971,8 +2150,9 @@ function confirmSettings() {
"mixrampdelay": (settings.mixramp == true ? document.getElementById('inputMixrampdelay').value : settings.mixrampdelay), "mixrampdelay": (settings.mixramp == true ? document.getElementById('inputMixrampdelay').value : settings.mixrampdelay),
"notificationWeb": (document.getElementById('btnnotifyWeb').classList.contains('active') ? true : false), "notificationWeb": (document.getElementById('btnnotifyWeb').classList.contains('active') ? true : false),
"notificationPage": (document.getElementById('btnnotifyPage').classList.contains('active') ? true : false), "notificationPage": (document.getElementById('btnnotifyPage').classList.contains('active') ? true : false),
"jukeboxMode": (document.getElementById('btnJukebox').classList.contains('active') ? true : false), "jukeboxMode": selectJukeboxMode.options[selectJukeboxMode.selectedIndex].value,
"jukeboxPlaylist": selectJukeboxPlaylist.options[selectJukeboxPlaylist.selectedIndex].value "jukeboxPlaylist": selectJukeboxPlaylist.options[selectJukeboxPlaylist.selectedIndex].value,
"jukeboxQueueLength": document.getElementById('inputJukeboxQueueLength').value
}}, getSettings); }}, getSettings);
modalSettings.hide(); modalSettings.hide();
} else } else
@ -2021,12 +2201,13 @@ function gotoPage(x) {
function saveQueue() { function saveQueue() {
var plName = document.getElementById('saveQueueName').value; var plName = document.getElementById('saveQueueName').value;
var valid = plName.replace(/\w\-/g, ''); var valid = plName.replace(/[\w\-]/g, '');
if (plName != '' && valid == '') { if (plName != '' && valid == '') {
sendAPI({"cmd": "MPD_API_QUEUE_SAVE", "data": {"plist": plName}}); sendAPI({"cmd": "MPD_API_QUEUE_SAVE", "data": {"plist": plName}});
modalSavequeue.hide(); modalSavequeue.hide();
} }
else { else {
alert(valid);
document.getElementById('saveQueueName').classList.add('is-invalid'); document.getElementById('saveQueueName').classList.add('is-invalid');
document.getElementById('saveQueueFrm').classList.add('was-validated'); document.getElementById('saveQueueFrm').classList.add('was-validated');
} }

View File

@ -1,4 +1,4 @@
var CACHE = 'myMPD-cache-v4.2.1'; var CACHE = 'myMPD-cache-v4.3.0';
var urlsToCache = [ var urlsToCache = [
'/', '/',
'/player.html', '/player.html',

View File

@ -1,4 +1,4 @@
#!/bin/bash #!/bin/bash
./mkclean.sh ./mkclean.sh
tar -czvf ../mympd_4.2.1.orig.tar.gz * tar -czvf ../mympd_4.3.0.orig.tar.gz *
dpkg-buildpackage -rfakeroot dpkg-buildpackage -rfakeroot

View File

@ -46,7 +46,10 @@ make
sudo make install sudo make install
cd .. cd ..
debian/postinst sudo debian/postinst
echo "Running cppcheck" if [ -x /usr/bin/cppcheck ]
[ -x /usr/bin/cppcheck ] && cppcheck --enable=warning --inconclusive --force --inline-suppr src/*.c src/*.h then
echo "Running cppcheck"
cppcheck --enable=warning --inconclusive --force --inline-suppr src/*.c src/*.h
fi

View File

@ -54,9 +54,10 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) {
size_t n = 0; size_t n = 0;
char *cmd; char *cmd;
unsigned int uint_buf1, uint_buf2, uint_rc; unsigned int uint_buf1, uint_buf2, uint_rc;
int je, int_buf, int_rc; int je, int_buf1, int_buf2, int_rc;
float float_buf; float float_buf;
char *p_charbuf1, *p_charbuf2, *p_charbuf3; char *p_charbuf1, *p_charbuf2, *p_charbuf3, *p_charbuf4;
char p_char[4];
enum mpd_cmd_ids cmd_id; enum mpd_cmd_ids cmd_id;
struct pollfd fds[1]; struct pollfd fds[1];
int pollrc; int pollrc;
@ -112,24 +113,30 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) {
n = mympd_put_state(mpd.buf, &mpd.song_id, &mpd.next_song_id, &mpd.last_song_id, &mpd.queue_version, &mpd.queue_length); n = mympd_put_state(mpd.buf, &mpd.song_id, &mpd.next_song_id, &mpd.last_song_id, &mpd.queue_version, &mpd.queue_length);
break; break;
case MPD_API_SETTINGS_SET: case MPD_API_SETTINGS_SET:
je = json_scanf(msg.p, msg.len, "{data: {notificationWeb: %B, notificationPage: %B, jukeboxMode: %B, jukeboxPlaylist: %Q}}", je = json_scanf(msg.p, msg.len, "{data: {notificationWeb: %B}}", &mympd_state.notificationWeb);
&mympd_state.notificationWeb, if (je == 1)
&mympd_state.notificationPage, mympd_state_set("notificationWeb", (mympd_state.notificationWeb == true ? "true" : "false"));
&mympd_state.jukeboxMode,
&mympd_state.jukeboxPlaylist);
if (je == 4) {
char tmp_file[200];
snprintf(tmp_file, 200, "%s.tmp", config.statefile);
json_fprintf(tmp_file, "{notificationWeb: %B, notificationPage: %B, jukeboxMode: %B, jukeboxPlaylist: %Q}",
mympd_state.notificationWeb,
mympd_state.notificationPage,
mympd_state.jukeboxMode,
mympd_state.jukeboxPlaylist);
rename(tmp_file, config.statefile);
if (mympd_state.jukeboxMode == true)
mympd_jukebox();
}
je = json_scanf(msg.p, msg.len, "{data: {notificationPage: %B}}", &mympd_state.notificationPage);
if (je == 1)
mympd_state_set("notificationPage", (mympd_state.notificationPage == true ? "true" : "false"));
je = json_scanf(msg.p, msg.len, "{data: {jukeboxMode: %d}}", &mympd_state.jukeboxMode);
if (je == 1) {
snprintf(p_char, 4, "%d", mympd_state.jukeboxMode);
mympd_state_set("jukeboxMode", p_char);
}
je = json_scanf(msg.p, msg.len, "{data: {jukeboxPlaylist: %Q}}", &mympd_state.jukeboxPlaylist);
if (je == 1)
mympd_state_set("jukeboxPlaylist", mympd_state.jukeboxPlaylist);
je = json_scanf(msg.p, msg.len, "{data: {jukeboxQueueLength: %d}}", &mympd_state.jukeboxQueueLength);
if (je == 1) {
snprintf(p_char, 4, "%d", mympd_state.jukeboxQueueLength);
mympd_state_set("jukeboxQueueLength", p_char);
}
je = json_scanf(msg.p, msg.len, "{data: {random: %u}}", &uint_buf1); je = json_scanf(msg.p, msg.len, "{data: {random: %u}}", &uint_buf1);
if (je == 1) if (je == 1)
mpd_run_random(mpd.conn, uint_buf1); mpd_run_random(mpd.conn, uint_buf1);
@ -160,7 +167,7 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) {
mpd_run_mixrampdelay(mpd.conn, float_buf); mpd_run_mixrampdelay(mpd.conn, float_buf);
} }
je = json_scanf(msg.p, msg.len, "{data: {replaygain:%Q}}", &p_charbuf1); je = json_scanf(msg.p, msg.len, "{data: {replaygain: %Q}}", &p_charbuf1);
if (je == 1) { if (je == 1) {
mpd_send_command(mpd.conn, "replay_gain_mode", p_charbuf1, NULL); mpd_send_command(mpd.conn, "replay_gain_mode", p_charbuf1, NULL);
struct mpd_pair *pair; struct mpd_pair *pair;
@ -169,6 +176,8 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) {
} }
free(p_charbuf1); free(p_charbuf1);
} }
if (mympd_state.jukeboxMode > 0)
mympd_jukebox();
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}");
break; break;
case MPD_API_WELCOME: case MPD_API_WELCOME:
@ -183,7 +192,49 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) {
uint_rc = mpd_run_rescan(mpd.conn, NULL); uint_rc = mpd_run_rescan(mpd.conn, NULL);
if (uint_rc > 0) if (uint_rc > 0)
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}");
break; break;
case MPD_API_SMARTPLS_UPDATE_ALL:
uint_rc = mympd_smartpls_update_all();
if (uint_rc == 0)
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Smart Playlists updated\"}");
else
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Smart Playlists update failed\"}");
break;
case MPD_API_SMARTPLS_SAVE:
je = json_scanf(msg.p, msg.len, "{data: {type: %Q}}", &p_charbuf1);
if (je == 1) {
if (strcmp(p_charbuf1, "sticker") == 0) {
je = json_scanf(msg.p, msg.len, "{data: {playlist: %Q, sticker: %Q, maxentries: %d}}", &p_charbuf2, &p_charbuf3, &int_buf1);
n = mympd_smartpls_save(p_charbuf1, p_charbuf2, p_charbuf3, NULL, int_buf1, 0);
free(p_charbuf2);
free(p_charbuf3);
}
else if (strcmp(p_charbuf1, "newest") == 0) {
je = json_scanf(msg.p, msg.len, "{data: {playlist: %Q, timerange: %d, maxentries: %d}}", &p_charbuf2, &int_buf1, &int_buf2);
n = mympd_smartpls_save(p_charbuf1, p_charbuf2, NULL, NULL, int_buf2, int_buf1);
free(p_charbuf2);
}
else if (strcmp(p_charbuf1, "search") == 0) {
je = json_scanf(msg.p, msg.len, "{data: {playlist: %Q, tag: %Q, searchstr: %Q}}", &p_charbuf2, &p_charbuf3, &p_charbuf4);
n = mympd_smartpls_save(p_charbuf1, p_charbuf2, p_charbuf3, p_charbuf4, 0, 0);
free(p_charbuf2);
free(p_charbuf3);
free(p_charbuf4);
}
free(p_charbuf1);
}
if (n == 0)
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}");
else
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Error saving playlist\"}");
break;
case MPD_API_SMARTPLS_GET:
je = json_scanf(msg.p, msg.len, "{data: {playlist: %Q}}", &p_charbuf1);
if (je == 1) {
n = mympd_smartpls_put(mpd.buf, p_charbuf1);
free(p_charbuf1);
}
break;
case MPD_API_PLAYER_PAUSE: case MPD_API_PLAYER_PAUSE:
mpd_run_toggle_pause(mpd.conn); mpd_run_toggle_pause(mpd.conn);
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}");
@ -330,8 +381,24 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) {
case MPD_API_PLAYLIST_RENAME: case MPD_API_PLAYLIST_RENAME:
je = json_scanf(msg.p, msg.len, "{data: {from: %Q, to: %Q}}", &p_charbuf1, &p_charbuf2); je = json_scanf(msg.p, msg.len, "{data: {from: %Q, to: %Q}}", &p_charbuf1, &p_charbuf2);
if (je == 2) { if (je == 2) {
mpd_run_rename(mpd.conn, p_charbuf1, p_charbuf2); //rename smart playlist
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Renamed playlist %s to %s\"}", p_charbuf1, p_charbuf2); char old_pl_file[400];
char new_pl_file[400];
snprintf(old_pl_file, 400, "%s/smartpls/%s", config.varlibdir, p_charbuf1);
snprintf(new_pl_file, 400, "%s/smartpls/%s", config.varlibdir, p_charbuf2);
if (access(old_pl_file, F_OK ) != -1) {
if (access(new_pl_file, F_OK ) == -1) {
rename(old_pl_file, new_pl_file);
//rename mpd playlist
mpd_run_rename(mpd.conn, p_charbuf1, p_charbuf2);
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Renamed playlist %s to %s\"}", p_charbuf1, p_charbuf2);
} else
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Renamed playlist %s already exists\"}", p_charbuf2);
}
else {
mpd_run_rename(mpd.conn, p_charbuf1, p_charbuf2);
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Renamed playlist %s to %s\"}", p_charbuf1, p_charbuf2);
}
free(p_charbuf1); free(p_charbuf1);
free(p_charbuf2); free(p_charbuf2);
} }
@ -385,9 +452,9 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) {
} }
break; break;
case MPD_API_QUEUE_ADD_TRACK_AFTER: case MPD_API_QUEUE_ADD_TRACK_AFTER:
je = json_scanf(msg.p, msg.len, "{data: {uri:%Q, to:%d}}", &p_charbuf1, &int_buf); je = json_scanf(msg.p, msg.len, "{data: {uri:%Q, to:%d}}", &p_charbuf1, &int_buf1);
if (je == 2) { if (je == 2) {
int_rc = mpd_run_add_id_to(mpd.conn, p_charbuf1, int_buf); int_rc = mpd_run_add_id_to(mpd.conn, p_charbuf1, int_buf1);
if (int_rc > -1 ) if (int_rc > -1 )
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}");
free(p_charbuf1); free(p_charbuf1);
@ -414,9 +481,9 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) {
case MPD_API_QUEUE_ADD_PLAY_TRACK: case MPD_API_QUEUE_ADD_PLAY_TRACK:
je = json_scanf(msg.p, msg.len, "{data: {uri:%Q}}", &p_charbuf1); je = json_scanf(msg.p, msg.len, "{data: {uri:%Q}}", &p_charbuf1);
if (je == 1) { if (je == 1) {
int_buf = mpd_run_add_id(mpd.conn, p_charbuf1); int_buf1 = mpd_run_add_id(mpd.conn, p_charbuf1);
if (int_buf != -1) if (int_buf1 != -1)
mpd_run_play_id(mpd.conn, int_buf); mpd_run_play_id(mpd.conn, int_buf1);
free(p_charbuf1); free(p_charbuf1);
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}");
} }
@ -479,6 +546,12 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) {
case MPD_API_PLAYLIST_RM: case MPD_API_PLAYLIST_RM:
je = json_scanf(msg.p, msg.len, "{data: {uri:%Q}}", &p_charbuf1); je = json_scanf(msg.p, msg.len, "{data: {uri:%Q}}", &p_charbuf1);
if (je == 1) { if (je == 1) {
//remove smart playlist
char pl_file[400];
snprintf(pl_file, 400, "%s/smartpls/%s", config.varlibdir, p_charbuf1);
if (access(pl_file, F_OK ) != -1 )
unlink(pl_file);
//remove mpd playlist
mpd_run_rm(mpd.conn, p_charbuf1); mpd_run_rm(mpd.conn, p_charbuf1);
free(p_charbuf1); free(p_charbuf1);
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}");
@ -549,13 +622,14 @@ void mympd_parse_idle(struct mg_mgr *s, int idle_bitmask) {
switch(idle_event) { switch(idle_event) {
case MPD_IDLE_DATABASE: case MPD_IDLE_DATABASE:
len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_database\"}"); len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_database\"}");
mympd_smartpls_update_all();
break; break;
case MPD_IDLE_STORED_PLAYLIST: case MPD_IDLE_STORED_PLAYLIST:
len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_stored_playlist\"}"); len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_stored_playlist\"}");
break; break;
case MPD_IDLE_QUEUE: case MPD_IDLE_QUEUE:
len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_queue\"}"); len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_queue\"}");
if (mympd_state.jukeboxMode == true) if (mympd_state.jukeboxMode > 0)
mympd_jukebox(); mympd_jukebox();
break; break;
case MPD_IDLE_PLAYER: case MPD_IDLE_PLAYER:
@ -628,6 +702,10 @@ void mympd_mpd_features() {
printf("MPD don't support stickers, disabling myMPD feature\n"); printf("MPD don't support stickers, disabling myMPD feature\n");
config.stickers = false; config.stickers = false;
} }
if (config.stickers == false && config.smartpls == true) {
printf("Stickers are disabled, disabling smartplaylists\n");
config.smartpls = false;
}
printf("MPD supported tags: "); printf("MPD supported tags: ");
mpd_send_list_tag_types(mpd.conn); mpd_send_list_tag_types(mpd.conn);
@ -736,8 +814,9 @@ void mympd_idle(struct mg_mgr *s, int timeout) {
mpd_connection_set_timeout(mpd.conn, mpd.timeout); mpd_connection_set_timeout(mpd.conn, mpd.timeout);
mpd.conn_state = MPD_CONNECTED; mpd.conn_state = MPD_CONNECTED;
mympd_mpd_features(); mympd_mpd_features();
if (mympd_state.jukeboxMode == true) mympd_smartpls_update_all();
mympd_jukebox(); if (mympd_state.jukeboxMode > 0)
mympd_jukebox();
mpd_send_idle(mpd.conn); mpd_send_idle(mpd.conn);
break; break;
@ -929,76 +1008,129 @@ char* mympd_get_tag(struct mpd_song const *song, enum mpd_tag_type tag) {
void mympd_jukebox() { void mympd_jukebox() {
struct mpd_status *status; struct mpd_status *status;
status = mpd_run_status(mpd.conn); status = mpd_run_status(mpd.conn);
int queue_length, num_songs, rand_song, i; int queue_length, num_songs, rand_song, i, j, addSongs;
struct mpd_entity *entity; struct mpd_entity *entity;
const struct mpd_song *song; const struct mpd_song *song;
struct mpd_pair *pair;
char *album;
if (!status) { if (!status) {
printf("MPD mpd_run_status: %s\n", mpd_connection_get_error_message(mpd.conn)); LOG_ERROR_AND_RECOVER("mpd_run_status");
mpd.conn_state = MPD_FAILURE;
return; return;
} }
queue_length = mpd_status_get_queue_length(status); queue_length = mpd_status_get_queue_length(status);
mpd_status_free(status); mpd_status_free(status);
if (queue_length > 0) if (queue_length > mympd_state.jukeboxQueueLength)
return; return;
srand((unsigned int)time(NULL)); srand((unsigned int)time(NULL));
num_songs = 0;
if (strcmp(mympd_state.jukeboxPlaylist, "Database") == 0) {
if (mympd_state.jukeboxMode == 1 && strcmp(mympd_state.jukeboxPlaylist, "Database") == 0) {
struct mpd_stats *stats = mpd_run_stats(mpd.conn); struct mpd_stats *stats = mpd_run_stats(mpd.conn);
if (stats == NULL) {
LOG_ERROR_AND_RECOVER("mpd_run_stats");
return;
}
num_songs = mpd_stats_get_number_of_songs(stats); num_songs = mpd_stats_get_number_of_songs(stats);
mpd_stats_free(stats); mpd_stats_free(stats);
num_songs--;
if (num_songs > 0) {
rand_song = rand() % num_songs;
mpd_send_list_all(mpd.conn, "/");
i = 0;
while ((entity = mpd_recv_entity(mpd.conn)) != NULL) {
if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) {
if (i == rand_song)
break;
i++;
}
mpd_entity_free(entity);
}
mpd_response_finish(mpd.conn);
song = mpd_entity_get_song(entity);
if (song != NULL) {
printf("Jukebox enabled, playing random song from database: %d/%d\n", rand_song, num_songs);
mpd_run_add(mpd.conn, mpd_song_get_uri(song));
mpd_run_play(mpd.conn);
}
mpd_entity_free(entity);
}
} }
else { else if (mympd_state.jukeboxMode == 1) {
mpd_send_list_playlist(mpd.conn, mympd_state.jukeboxPlaylist); if (!mpd_send_list_playlist(mpd.conn, mympd_state.jukeboxPlaylist)) {
num_songs = 0; LOG_ERROR_AND_RECOVER("mpd_send_list_playlist");
return;
}
while ((entity = mpd_recv_entity(mpd.conn)) != NULL) { while ((entity = mpd_recv_entity(mpd.conn)) != NULL) {
num_songs++; num_songs++;
mpd_entity_free(entity); mpd_entity_free(entity);
}
}
else if (mympd_state.jukeboxMode == 2) {
if (!mpd_search_db_tags(mpd.conn, MPD_TAG_ALBUM)) {
LOG_ERROR_AND_RECOVER("mpd_send_list_playlist");
return;
} }
num_songs--; if (!mpd_search_commit(mpd.conn)) {
if (num_songs > 0) { LOG_ERROR_AND_RECOVER("mpd_send_list_playlist");
return;
}
while ((pair = mpd_recv_pair_tag(mpd.conn, MPD_TAG_ALBUM)) != NULL) {
num_songs++;
mpd_return_pair(mpd.conn, pair);
}
mpd_response_finish(mpd.conn);
}
num_songs--;
if (mympd_state.jukeboxMode == 1)
addSongs = mympd_state.jukeboxQueueLength - queue_length;
else
addSongs = 1;
if (num_songs > 0) {
for (j = 0; j < addSongs; j++) {
rand_song = rand() % num_songs; rand_song = rand() % num_songs;
mpd_send_list_playlist(mpd.conn, mympd_state.jukeboxPlaylist); if (mympd_state.jukeboxMode == 1) {
i = 0; //add songs
while ((entity = mpd_recv_entity(mpd.conn)) != NULL) { if (strcmp(mympd_state.jukeboxPlaylist, "Database") == 0) {
if (i == rand_song) if (!mpd_send_list_all(mpd.conn, "/")) {
break; LOG_ERROR_AND_RECOVER("mpd_send_list_playlist");
i++; return;
}
}
else {
if (!mpd_send_list_playlist(mpd.conn, mympd_state.jukeboxPlaylist)) {
LOG_ERROR_AND_RECOVER("mpd_send_list_playlist");
return;
}
}
i = 0;
while ((entity = mpd_recv_entity(mpd.conn)) != NULL) {
if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) {
if (i == rand_song)
break;
i++;
}
mpd_entity_free(entity);
}
mpd_response_finish(mpd.conn);
song = mpd_entity_get_song(entity);
if (song != NULL) {
printf("Jukebox enabled, adding random song: %d/%d\n", rand_song, num_songs);
if (!mpd_run_add(mpd.conn, mpd_song_get_uri(song))) {
LOG_ERROR_AND_RECOVER("mpd_send_list_playlist");
}
}
mpd_entity_free(entity); mpd_entity_free(entity);
} }
mpd_response_finish(mpd.conn); else if (mympd_state.jukeboxMode == 2) {
song = mpd_entity_get_song(entity); //add album
if (song != NULL) { if (!mpd_search_db_tags(mpd.conn, MPD_TAG_ALBUM)) {
printf("Jukebox enabled, playing random song from %s: %d/%d\n", mympd_state.jukeboxPlaylist, rand_song, num_songs); LOG_ERROR_AND_RECOVER("mpd_send_list_playlist");
mpd_run_add(mpd.conn, mpd_song_get_uri(song)); return;
mpd_run_play(mpd.conn); }
if (!mpd_search_commit(mpd.conn)) {
LOG_ERROR_AND_RECOVER("mpd_send_list_playlist");
return;
}
i = 0;
while ((pair = mpd_recv_pair_tag(mpd.conn, MPD_TAG_ALBUM )) != NULL) {
if (i == rand_song) {
album = strdup(pair->value);
break;
}
i++;
mpd_return_pair(mpd.conn, pair);
}
mpd_return_pair(mpd.conn, pair);
mpd_response_finish(mpd.conn);
printf("Jukebox enabled, adding random album %s: %d/%d\n", album, rand_song, num_songs);
if (!mpd_send_command(mpd.conn, "searchadd", "Album", album, NULL)) {
LOG_ERROR_AND_RECOVER("mpd_send_list_playlist");
return;
}
mpd_response_finish(mpd.conn);
} }
mpd_entity_free(entity);
} }
mpd_run_play(mpd.conn);
} }
} }
@ -1066,6 +1198,47 @@ int mympd_put_welcome(char *buffer) {
return len; return len;
} }
bool mympd_state_get(char *name, char *value) {
char cfgfile[400];
char *line;
size_t n = 0;
ssize_t read;
snprintf(cfgfile, 400, "%s/state/%s", config.varlibdir, name);
FILE *fp = fopen(cfgfile, "r");
if (fp == NULL) {
printf("Error opening %s", cfgfile);
return false;
}
read = getline(&line, &n, fp);
snprintf(value, 400, "%s", line);
#ifdef DEBUG
printf("State %s: %s\n", name, value);
#endif
fclose(fp);
if (read > 0)
return true;
else
return false;
}
bool mympd_state_set(char *name, char *value) {
char tmpfile[400];
char cfgfile[400];
snprintf(cfgfile, 400, "%s/state/%s", config.varlibdir, name);
snprintf(tmpfile, 400, "%s/tmp/%s", config.varlibdir, name);
FILE *fp = fopen(tmpfile, "w");
if (fp == NULL) {
printf("Error opening %s", tmpfile);
return false;
}
fprintf(fp, value);
fclose(fp);
rename(tmpfile, cfgfile);
return true;
}
int mympd_put_settings(char *buffer) { int mympd_put_settings(char *buffer) {
struct mpd_status *status; struct mpd_status *status;
char *replaygain = strdup(""); char *replaygain = strdup("");
@ -1090,8 +1263,8 @@ int mympd_put_settings(char *buffer) {
len = json_printf(&out, "{type: settings, data: {" len = json_printf(&out, "{type: settings, data: {"
"repeat: %d, single: %d, crossfade: %d, consume: %d, random: %d, " "repeat: %d, single: %d, crossfade: %d, consume: %d, random: %d, "
"mixrampdb: %f, mixrampdelay: %f, mpdhost: %Q, mpdport: %d, passwort_set: %B, " "mixrampdb: %f, mixrampdelay: %f, mpdhost: %Q, mpdport: %d, passwort_set: %B, "
"streamport: %d, coverimage: %Q, stickers: %B, mixramp: %B, maxElementsPerPage: %d, " "streamport: %d, coverimage: %Q, stickers: %B, mixramp: %B, smartpls: %B, maxElementsPerPage: %d, "
"replaygain: %Q, notificationWeb: %B, notificationPage: %B, jukeboxMode: %B, jukeboxPlaylist: %Q, " "replaygain: %Q, notificationWeb: %B, notificationPage: %B, jukeboxMode: %d, jukeboxPlaylist: %Q, jukeboxQueueLength: %d, "
"tags: { Artist: %B, Album: %B, AlbumArtist: %B, Title: %B, Track: %B, Genre: %B, Date: %B," "tags: { Artist: %B, Album: %B, AlbumArtist: %B, Title: %B, Track: %B, Genre: %B, Date: %B,"
"Composer: %B, Performer: %B }" "Composer: %B, Performer: %B }"
"}}", "}}",
@ -1109,12 +1282,14 @@ int mympd_put_settings(char *buffer) {
config.coverimage, config.coverimage,
config.stickers, config.stickers,
config.mixramp, config.mixramp,
config.smartpls,
MAX_ELEMENTS_PER_PAGE, MAX_ELEMENTS_PER_PAGE,
replaygain, replaygain,
mympd_state.notificationWeb, mympd_state.notificationWeb,
mympd_state.notificationPage, mympd_state.notificationPage,
mympd_state.jukeboxMode, mympd_state.jukeboxMode,
mympd_state.jukeboxPlaylist, mympd_state.jukeboxPlaylist,
mympd_state.jukeboxQueueLength,
mpd.tag_artist, mpd.tag_artist,
mpd.tag_album, mpd.tag_album,
mpd.tag_album_artist, mpd.tag_album_artist,
@ -1187,7 +1362,7 @@ int mympd_get_cover(const char *uri, char *cover, int cover_len) {
replacechar(path, '/', '_'); replacechar(path, '/', '_');
replacechar(path, '.', '_'); replacechar(path, '.', '_');
snprintf(cover, cover_len, "%s/pics/%s.png", SRC_PATH, path); snprintf(cover, cover_len, "%s/pics/%s.png", SRC_PATH, path);
if ( access(cover, F_OK ) == -1 ) { if (access(cover, F_OK ) == -1 ) {
len = snprintf(cover, cover_len, "/assets/coverimage-httpstream.png"); len = snprintf(cover, cover_len, "/assets/coverimage-httpstream.png");
} else { } else {
len = snprintf(cover, cover_len, "/pics/%s.png", path); len = snprintf(cover, cover_len, "/pics/%s.png", path);
@ -1199,7 +1374,7 @@ int mympd_get_cover(const char *uri, char *cover, int cover_len) {
else { else {
dirname(path); dirname(path);
snprintf(cover, cover_len, "%s/library/%s/%s", SRC_PATH, path, config.coverimage); snprintf(cover, cover_len, "%s/library/%s/%s", SRC_PATH, path, config.coverimage);
if ( access(cover, F_OK ) == -1 ) { if (access(cover, F_OK ) == -1 ) {
len = snprintf(cover, cover_len, "/assets/coverimage-notavailable.png"); len = snprintf(cover, cover_len, "/assets/coverimage-notavailable.png");
} else { } else {
len = snprintf(cover, cover_len, "/library/%s/%s", path, config.coverimage); len = snprintf(cover, cover_len, "/library/%s/%s", path, config.coverimage);
@ -1370,6 +1545,8 @@ int mympd_put_browse(char *buffer, char *path, unsigned int offset, char *filter
unsigned int entity_count = 0; unsigned int entity_count = 0;
unsigned int entities_returned = 0; unsigned int entities_returned = 0;
const char *entityName; const char *entityName;
char smartpls_file[400];
bool smartpls;
int len; int len;
struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE);
@ -1446,7 +1623,13 @@ int mympd_put_browse(char *buffer, char *path, unsigned int offset, char *filter
) { ) {
if (entities_returned ++) if (entities_returned ++)
len += json_printf(&out, ","); len += json_printf(&out, ",");
len += json_printf(&out, "{type: plist, uri: %Q, name: %Q}", snprintf(smartpls_file, 400, "%s/smartpls/%s", config.varlibdir, plName);
if (access(smartpls_file, F_OK ) != -1)
smartpls = true;
else
smartpls = false;
len += json_printf(&out, "{type: %Q, uri: %Q, name: %Q}",
(smartpls == true ? "smartpls" : "plist"),
entityName, entityName,
plName plName
); );
@ -1599,6 +1782,8 @@ int mympd_put_playlists(char *buffer, unsigned int offset, char *filter) {
unsigned int entities_returned = 0; unsigned int entities_returned = 0;
const char *plpath; const char *plpath;
int len; int len;
bool smartpls;
char smartpls_file[400];
struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE);
if (!mpd_send_list_playlists(mpd.conn)) if (!mpd_send_list_playlists(mpd.conn))
@ -1615,7 +1800,13 @@ int mympd_put_playlists(char *buffer, unsigned int offset, char *filter) {
) { ) {
if (entities_returned ++) if (entities_returned ++)
len += json_printf(&out, ", "); len += json_printf(&out, ", ");
len += json_printf(&out, "{type: plist, uri: %Q, name: %Q, last_modified: %d}", snprintf(smartpls_file, 400, "%s/smartpls/%s", config.varlibdir, plpath);
if (access(smartpls_file, F_OK ) != -1)
smartpls = true;
else
smartpls = false;
len += json_printf(&out, "{type: %Q, uri: %Q, name: %Q, last_modified: %d}",
(smartpls == true ? "smartpls" : "plist"),
plpath, plpath,
plpath, plpath,
mpd_playlist_get_last_modified(pl) mpd_playlist_get_last_modified(pl)
@ -1646,6 +1837,8 @@ int mympd_put_playlist_list(char *buffer, char *uri, unsigned int offset, char *
unsigned int entity_count = 0; unsigned int entity_count = 0;
unsigned int entities_returned = 0; unsigned int entities_returned = 0;
const char *entityName; const char *entityName;
char smartpls_file[400];
bool smartpls;
int len; int len;
struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE);
@ -1679,13 +1872,18 @@ int mympd_put_playlist_list(char *buffer, char *uri, unsigned int offset, char *
} }
mpd_entity_free(entity); mpd_entity_free(entity);
} }
snprintf(smartpls_file, 400, "%s/smartpls/%s", config.varlibdir, uri);
len += json_printf(&out, "], totalEntities: %d, offset: %d, returnedEntities: %d, filter: %Q, uri: %Q}", if (access(smartpls_file, F_OK ) != -1)
smartpls = true;
else
smartpls = false;
len += json_printf(&out, "], totalEntities: %d, offset: %d, returnedEntities: %d, filter: %Q, uri: %Q, smartpls: %B}",
entity_count, entity_count,
offset, offset,
entities_returned, entities_returned,
filter, filter,
uri uri,
smartpls
); );
if (len > MAX_SIZE) if (len > MAX_SIZE)
@ -1805,7 +2003,7 @@ int mympd_search_queue(char *buffer, char *mpdtagtype, unsigned int offset, char
else { else {
len = json_printf(&out, "{type: queuesearch, data: ["); len = json_printf(&out, "{type: queuesearch, data: [");
while((song = mpd_recv_song(mpd.conn)) != NULL) { while ((song = mpd_recv_song(mpd.conn)) != NULL) {
entity_count ++; entity_count ++;
if (entity_count > offset && entity_count <= offset + MAX_ELEMENTS_PER_PAGE) { if (entity_count > offset && entity_count <= offset + MAX_ELEMENTS_PER_PAGE) {
if (entities_returned ++) if (entities_returned ++)
@ -1868,3 +2066,310 @@ void mympd_disconnect() {
mpd.conn_state = MPD_DISCONNECT; mpd.conn_state = MPD_DISCONNECT;
mympd_idle(NULL, 0); mympd_idle(NULL, 0);
} }
int mympd_smartpls_put(char *buffer, char *playlist) {
char pl_file[400];
char *smartpltype;
char *p_charbuf1, *p_charbuf2;
int je, int_buf1, int_buf2;
int len = 0;
struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE);
snprintf(pl_file, 400, "%s/smartpls/%s", config.varlibdir, playlist);
char *content = json_fread(pl_file);
je = json_scanf(content, strlen(content), "{type: %Q }", &smartpltype);
if (je == 1) {
if (strcmp(smartpltype, "sticker") == 0) {
je = json_scanf(content, strlen(content), "{sticker: %Q, maxentries: %d}", &p_charbuf1, &int_buf1);
if (je == 2) {
len = json_printf(&out, "{type: smartpls, data: {playlist: %Q, type: %Q, sticker: %Q, maxentries: %d}}",
playlist,
smartpltype,
p_charbuf1,
int_buf1);
free(p_charbuf1);
}
}
else if (strcmp(smartpltype, "newest") == 0) {
je = json_scanf(content, strlen(content), "{timerange: %d, maxentries: %d}", &int_buf1, &int_buf2);
if (je == 2) {
len = json_printf(&out, "{type: smartpls, data: {playlist: %Q, type: %Q, timerange: %d, maxentries: %d}}",
playlist,
smartpltype,
int_buf1,
int_buf2);
}
}
else if (strcmp(smartpltype, "search") == 0) {
je = json_scanf(content, strlen(content), "{tag: %Q, searchstr: %Q}", &p_charbuf1, &p_charbuf2);
if (je == 2) {
len = json_printf(&out, "{type: smartpls, data: {playlist: %Q, type: %Q, tag: %Q, searchstr: %Q}}",
playlist,
smartpltype,
p_charbuf1,
p_charbuf2);
free(p_charbuf1);
free(p_charbuf2);
}
}
free(smartpltype);
}
return len;
}
int mympd_smartpls_save(char *smartpltype, char *playlist, char *tag, char *searchstr, int maxentries, int timerange) {
char tmp_file[400];
char pl_file[400];
snprintf(tmp_file, 400, "%s/tmp/%s", config.varlibdir, playlist);
snprintf(pl_file, 400, "%s/smartpls/%s", config.varlibdir, playlist);
if (strcmp(smartpltype, "sticker") == 0) {
json_fprintf(tmp_file, "{type: %Q, sticker: %Q, maxentries: %d}", smartpltype, tag, maxentries);
rename(tmp_file, pl_file);
mympd_smartpls_update(playlist, tag, maxentries);
}
else if (strcmp(smartpltype, "newest") == 0) {
json_fprintf(tmp_file, "{type: %Q, timerange: %d, maxentries: %d}", smartpltype, timerange, maxentries);
rename(tmp_file, pl_file);
mympd_smartpls_update_newest(playlist, timerange, maxentries);
}
else if (strcmp(smartpltype, "search") == 0) {
json_fprintf(tmp_file, "{type: %Q, tag: %Q, searchstr: %Q}", smartpltype, tag, searchstr);
rename(tmp_file, pl_file);
mympd_smartpls_update_search(playlist, tag, searchstr);
}
return 0;
}
int mympd_smartpls_update_all() {
DIR *dir;
struct dirent *ent;
char *smartpltype;
char filename[400];
char dirname[400];
int je;
char *p_charbuf1, *p_charbuf2;
int int_buf1, int_buf2;
if (!config.smartpls)
return 0;
snprintf(dirname, 400, "%s/smartpls", config.varlibdir);
if ((dir = opendir (dirname)) != NULL) {
while ((ent = readdir(dir)) != NULL) {
if (strncmp(ent->d_name, ".", 1) == 0)
continue;
snprintf(filename, 400, "%s/smartpls/%s", config.varlibdir, ent->d_name);
char *content = json_fread(filename);
je = json_scanf(content, strlen(content), "{type: %Q }", &smartpltype);
if (je != 1)
continue;
if (strcmp(smartpltype, "sticker") == 0) {
je = json_scanf(content, strlen(content), "{sticker: %Q, maxentries: %d}", &p_charbuf1, &int_buf1);
if (je == 2) {
mympd_smartpls_update(ent->d_name, p_charbuf1, int_buf1);
free(p_charbuf1);
}
else
printf("Can't parse file %s\n", filename);
}
else if (strcmp(smartpltype, "newest") == 0) {
je = json_scanf(content, strlen(content), "{timerange: %d, maxentries: %d}", &int_buf1, &int_buf2);
if (je == 2) {
mympd_smartpls_update_newest(ent->d_name, int_buf1, int_buf2);
}
else
printf("Can't parse file %s\n", filename);
}
else if (strcmp(smartpltype, "search") == 0) {
je = json_scanf(content, strlen(content), "{tag: %Q, searchstr: %Q}", &p_charbuf1, &p_charbuf2);
if (je == 2) {
mympd_smartpls_update_search(ent->d_name, p_charbuf1, p_charbuf2);
free(p_charbuf1);
free(p_charbuf2);
}
else
printf("Can't parse file %s\n", filename);
}
free(smartpltype);
}
closedir (dir);
} else {
printf("Can't open dir %s\n", dirname);
return 1;
}
return 0;
}
int mympd_smartpls_clear(char *playlist) {
struct mpd_playlist *pl;
const char *plpath;
bool exists = false;
if (!mpd_send_list_playlists(mpd.conn)) {
LOG_ERROR_AND_RECOVER("mpd_send_list_playlists");
return 1;
}
while((pl = mpd_recv_playlist(mpd.conn)) != NULL) {
plpath = mpd_playlist_get_path(pl);
if (strcmp(playlist, plpath) == 0)
exists = true;
mpd_playlist_free(pl);
if (exists)
break;
}
mpd_response_finish(mpd.conn);
if (exists) {
if (!mpd_run_rm(mpd.conn, playlist)) {
LOG_ERROR_AND_RECOVER("mpd_run_rm");
return 1;
}
}
return 0;
}
int mympd_smartpls_update_search(char *playlist, char *tag, char *searchstr) {
mympd_smartpls_clear(playlist);
mympd_search(mpd.buf, searchstr, tag, playlist, 0);
printf("Updated %s\n", playlist);
return 0;
}
int mympd_smartpls_update(char *playlist, char *sticker, int maxentries) {
struct mpd_pair *pair;
char *uri = NULL;
char *name;
char *p_value;
char *crap;
char tmpfile[400];
long value;
long value_max = 0;
size_t len = 0;
ssize_t read;
long i = 0;
if (!mpd_send_sticker_find(mpd.conn, "song", "", sticker)) {
LOG_ERROR_AND_RECOVER("mpd_send_sticker_find");
return 1;
}
snprintf(tmpfile, 400, "%s/tmp/playlist.tmp", config.varlibdir);
FILE *fp = fopen(tmpfile, "w");
if (fp == NULL) {
printf("Error opening %s", tmpfile);
return 1;
}
while ((pair = mpd_recv_pair(mpd.conn)) != NULL) {
if (strcmp(pair->name, "file") == 0) {
uri = strdup(pair->value);
}
else if (strcmp(pair->name, "sticker") == 0) {
name = strtok(strdup(pair->value), "=");
p_value = strtok(NULL, "=");
value = strtol(p_value, &crap, 10);
if (value > 1)
fprintf(fp, "%s::%ld\n", uri, value);
if (value > value_max)
value_max = value;
}
mpd_return_pair(mpd.conn, pair);
}
mpd_response_finish(mpd.conn);
fclose(fp);
mympd_smartpls_clear(playlist);
if (value_max > 2)
value_max = value_max / 2;
fp = fopen(tmpfile, "r");
if (fp == NULL) {
printf("Error opening %s", tmpfile);
return 1;
}
while ((read = getline(&uri, &len, fp)) != -1) {
name = strtok(uri, "::");
p_value = strtok(NULL, "::");
value = strtol(p_value, &crap, 10);
if (value < value_max)
continue;
if (!mpd_run_playlist_add(mpd.conn, playlist, name)) {
LOG_ERROR_AND_RECOVER("mpd_run_playlist_add");
fclose(fp);
free(uri);
unlink(tmpfile);
return 1;
}
i++;
if (i >= maxentries)
break;
}
fclose(fp);
free(uri);
unlink(tmpfile);
printf("Updated %s with %ld songs, minValue: %ld\n", playlist, i, value_max);
return 0;
}
int mympd_smartpls_update_newest(char *playlist, int timerange, int maxentries) {
struct mpd_song *song;
char *uri;
char *p_value;
char *name;
char *crap;
char tmpfile[400];
time_t value;
time_t value_max = 0;
size_t len = 0;
ssize_t read;
long i = 0;
if (!mpd_send_list_all_meta(mpd.conn, "/")) {
LOG_ERROR_AND_RECOVER("mpd_send_list_all_meta");
return 1;
}
snprintf(tmpfile, 400, "%s/tmp/playlist.tmp", config.varlibdir);
FILE *fp = fopen(tmpfile, "w");
if (fp == NULL) {
printf("Error opening %s", tmpfile);
return 1;
}
while ((song = mpd_recv_song(mpd.conn)) != NULL) {
value = mpd_song_get_last_modified(song);
if (value > value_max)
value_max = value;
fprintf(fp, "%s::%ld\n", mpd_song_get_uri(song), value);
mpd_song_free(song);
}
mpd_response_finish(mpd.conn);
fclose(fp);
mympd_smartpls_clear(playlist);
value_max -= timerange;
fp = fopen(tmpfile, "r");
if (fp == NULL) {
printf("Error opening %s", tmpfile);
return 1;
}
while ((read = getline(&uri, &len, fp)) != -1) {
name = strtok(uri, "::");
p_value = strtok(NULL, "::");
value = strtol(p_value, &crap, 10);
if (value >= value_max)
continue;
if (!mpd_run_playlist_add(mpd.conn, playlist, name)) {
LOG_ERROR_AND_RECOVER("mpd_run_playlist_add");
fclose(fp);
unlink(tmpfile);
free(uri);
return 1;
}
i++;
if (i >= maxentries)
break;
}
fclose(fp);
free(uri);
unlink(tmpfile);
printf("Updated %s with %ld songs, minValue: %ld\n", playlist, i, value_max);
return 0;
}

View File

@ -28,7 +28,7 @@
#include "../dist/src/mongoose/mongoose.h" #include "../dist/src/mongoose/mongoose.h"
#define RETURN_ERROR_AND_RECOVER(X) do { \ #define RETURN_ERROR_AND_RECOVER(X) do { \
fprintf(stderr, "MPD X: %s\n", mpd_connection_get_error_message(mpd.conn)); \ printf("MPD X: %s\n", mpd_connection_get_error_message(mpd.conn)); \
len = json_printf(&out, "{ type:error, data : %Q }", \ len = json_printf(&out, "{ type:error, data : %Q }", \
mpd_connection_get_error_message(mpd.conn) \ mpd_connection_get_error_message(mpd.conn) \
); \ ); \
@ -38,7 +38,7 @@
} while (0) } while (0)
#define LOG_ERROR_AND_RECOVER(X) do { \ #define LOG_ERROR_AND_RECOVER(X) do { \
fprintf(stderr, "MPD X: %s\n", mpd_connection_get_error_message(mpd.conn)); \ printf("MPD X: %s\n", mpd_connection_get_error_message(mpd.conn)); \
if (!mpd_connection_clear_error(mpd.conn)) \ if (!mpd_connection_clear_error(mpd.conn)) \
mpd.conn_state = MPD_FAILURE; \ mpd.conn_state = MPD_FAILURE; \
} while (0) } while (0)
@ -72,6 +72,9 @@
X(MPD_API_PLAYLIST_RM_TRACK) \ X(MPD_API_PLAYLIST_RM_TRACK) \
X(MPD_API_PLAYLIST_LIST) \ X(MPD_API_PLAYLIST_LIST) \
X(MPD_API_PLAYLIST_CONTENT_LIST) \ X(MPD_API_PLAYLIST_CONTENT_LIST) \
X(MPD_API_SMARTPLS_UPDATE_ALL) \
X(MPD_API_SMARTPLS_SAVE) \
X(MPD_API_SMARTPLS_GET) \
X(MPD_API_DATABASE_SEARCH) \ X(MPD_API_DATABASE_SEARCH) \
X(MPD_API_DATABASE_UPDATE) \ X(MPD_API_DATABASE_UPDATE) \
X(MPD_API_DATABASE_RESCAN) \ X(MPD_API_DATABASE_RESCAN) \
@ -157,10 +160,11 @@ typedef struct {
const char* user; const char* user;
long streamport; long streamport;
const char* coverimage; const char* coverimage;
const char* statefile;
bool stickers; bool stickers;
bool mixramp; bool mixramp;
const char* taglist; const char* taglist;
bool smartpls;
const char* varlibdir;
} t_config; } t_config;
t_config config; t_config config;
@ -175,8 +179,9 @@ typedef struct {
typedef struct { typedef struct {
bool notificationWeb; bool notificationWeb;
bool notificationPage; bool notificationPage;
bool jukeboxMode; int jukeboxMode;
const char* jukeboxPlaylist; const char* jukeboxPlaylist;
int jukeboxQueueLength;
} t_mympd_state; } t_mympd_state;
t_mympd_state mympd_state; t_mympd_state mympd_state;
@ -196,6 +201,15 @@ void mympd_last_played_song_uri(const char *uri);
void mympd_last_played_song_id(int song_id); void mympd_last_played_song_id(int song_id);
void mympd_get_sticker(const char *uri, t_sticker *sticker); void mympd_get_sticker(const char *uri, t_sticker *sticker);
void mympd_jukebox(); void mympd_jukebox();
bool mympd_state_get(char *name, char *value);
bool mympd_state_set(char *name, char *value);
int mympd_smartpls_save(char *smartpltype, char *playlist, char *tag, char *searchstr, int maxentries, int timerange);
int mympd_smartpls_put(char *buffer, char *playlist);
int mympd_smartpls_update_all();
int mympd_smartpls_clear(char *playlist);
int mympd_smartpls_update(char *sticker, char *playlist, int maxentries);
int mympd_smartpls_update_newest(char *playlist, int timerange, int maxentries);
int mympd_smartpls_update_search(char *playlist, char *tag, char *searchstr);
int mympd_get_updatedb_state(char *buffer); 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_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_outputs(char *buffer);

View File

@ -155,13 +155,18 @@ static int inihandler(void* user, const char* section, const char* name, const c
p_config->streamport = strtol(value, &crap, 10); p_config->streamport = strtol(value, &crap, 10);
else if (MATCH("coverimage")) else if (MATCH("coverimage"))
p_config->coverimage = strdup(value); p_config->coverimage = strdup(value);
else if (MATCH("statefile")) else if (MATCH("varlibdir"))
p_config->statefile = strdup(value); p_config->varlibdir = strdup(value);
else if (MATCH("stickers")) else if (MATCH("stickers"))
if (strcmp(value, "true") == 0) if (strcmp(value, "true") == 0)
p_config->stickers = true; p_config->stickers = true;
else else
p_config->stickers = false; p_config->stickers = false;
else if (MATCH("smartpls"))
if (strcmp(value, "true") == 0)
p_config->smartpls = true;
else
p_config->smartpls = false;
else if (MATCH("mixramp")) else if (MATCH("mixramp"))
if (strcmp(value, "true") == 0) if (strcmp(value, "true") == 0)
p_config->mixramp = true; p_config->mixramp = true;
@ -175,6 +180,44 @@ static int inihandler(void* user, const char* section, const char* name, const c
return 1; return 1;
} }
void read_statefiles() {
char *crap;
char value[400];
if (mympd_state_get("notificationWeb", value)) {
if (strcmp(value, "true") == 0)
mympd_state.notificationWeb = true;
else
mympd_state.notificationWeb = false;
}
else
mympd_state.notificationWeb = false;
if (mympd_state_get("notificationPage", value)) {
if (strcmp(value, "true") == 0)
mympd_state.notificationPage = true;
else
mympd_state.notificationPage = false;
}
else
mympd_state.notificationPage = true;
if (mympd_state_get("jukeboxMode", value))
mympd_state.jukeboxMode = strtol(value, &crap, 10);
else
mympd_state.jukeboxMode = 0;
if (mympd_state_get("jukeboxPlaylist", value))
mympd_state.jukeboxPlaylist = strdup(value);
else
mympd_state.jukeboxPlaylist = "Database";
if (mympd_state_get("jukeboxQueueLength", value))
mympd_state.jukeboxQueueLength = strtol(value, &crap, 10);
else
mympd_state.jukeboxQueueLength = 1;
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
struct mg_mgr mgr; struct mg_mgr mgr;
struct mg_connection *nc; struct mg_connection *nc;
@ -194,10 +237,11 @@ int main(int argc, char **argv) {
config.user = "nobody"; config.user = "nobody";
config.streamport = 8000; config.streamport = 8000;
config.coverimage = "folder.jpg"; config.coverimage = "folder.jpg";
config.statefile = "/var/lib/mympd/mympd.state"; config.varlibdir = "/var/lib/mympd";
config.stickers = true; config.stickers = true;
config.mixramp = true; config.mixramp = true;
config.taglist = "Artist,Album,AlbumArtist,Title,Track,Genre,Date,Composer,Performer"; config.taglist = "Artist,Album,AlbumArtist,Title,Track,Genre,Date,Composer,Performer";
config.smartpls = true;
mpd.timeout = 3000; mpd.timeout = 3000;
mpd.last_update_sticker_song_id = -1; mpd.last_update_sticker_song_id = -1;
@ -234,25 +278,7 @@ int main(int argc, char **argv) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (access( config.statefile, F_OK ) != -1 ) { read_statefiles();
char *content = json_fread(config.statefile);
int je = json_scanf(content, strlen(content), "{notificationWeb: %B, notificationPage: %B, jukeboxMode: %B, jukeboxPlaylist: %Q}",
&mympd_state.notificationWeb,
&mympd_state.notificationPage,
&mympd_state.jukeboxMode,
&mympd_state.jukeboxPlaylist);
if (je != 4) {
mympd_state.notificationWeb = false;
mympd_state.notificationPage = true;
mympd_state.jukeboxMode = false;
mympd_state.jukeboxPlaylist = "Database";
}
} else {
mympd_state.notificationWeb = false;
mympd_state.notificationPage = true;
mympd_state.jukeboxMode = false;
mympd_state.jukeboxPlaylist = "Database";
}
signal(SIGTERM, signal_handler); signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler); signal(SIGINT, signal_handler);