1
0
mirror of https://github.com/SuperBFG7/ympd synced 2025-10-31 05:43:01 +00:00

Merge pull request #66 from jcorporation/devel

Merge devel into master for 4.3.1 release
This commit is contained in:
Jürgen Mang
2018-10-10 22:05:09 +02:00
committed by GitHub
21 changed files with 527 additions and 398 deletions

View File

@@ -4,7 +4,7 @@ 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 "3") set(CPACK_PACKAGE_VERSION_MINOR "3")
set(CPACK_PACKAGE_VERSION_PATCH "0") set(CPACK_PACKAGE_VERSION_PATCH "1")
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")
@@ -31,6 +31,7 @@ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS NS_ENABLE_SSL)
set(SOURCES set(SOURCES
src/mympd.c src/mympd.c
src/mpd_client.c src/mpd_client.c
src/list.c
dist/src/mongoose/mongoose.c dist/src/mongoose/mongoose.c
dist/src/frozen/frozen.c dist/src/frozen/frozen.c
dist/src/inih/ini.c dist/src/inih/ini.c

View File

@@ -4,9 +4,9 @@
pkgname=mympd pkgname=mympd
_pkgname=myMPD _pkgname=myMPD
pkgver=4.3.0 pkgver=4.3.1
pkgrel=1 pkgrel=1
pkgdesc="A standalone MPD Web GUI based on YMPD - Default port set to 80" pkgdesc="myMPD is a standalone and mobile friendly web mpdclient."
arch=('x86_64' 'armv7h' 'aarch64') arch=('x86_64' 'armv7h' 'aarch64')
url="http://github.org/jcorporation/myMPD" url="http://github.org/jcorporation/myMPD"
license=('GPL') license=('GPL')

View File

@@ -10,10 +10,6 @@ post_upgrade() {
getent passwd mympd > /dev/null getent passwd mympd > /dev/null
[ "$?" = "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
echo "INFO: Fixing ownership of /var/lib/mympd"
chown -R mympd.mympd /var/lib/mympd
# 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"
if [ -f /etc/mpd.conf ] if [ -f /etc/mpd.conf ]
@@ -64,6 +60,17 @@ post_upgrade() {
fi fi
done done
#default state files
[ -f /var/lib/mympd/state/jukeboxMode ] || echo -n "0" > /var/lib/mympd/state/jukeboxMode
[ -f /var/lib/mympd/state/jukeboxPlaylist ] || echo -n "Database" > /var/lib/mympd/state/jukeboxPlaylist
[ -f /var/lib/mympd/state/jukeboxQueueLength ] || echo -n "1" > /var/lib/mympd/state/jukeboxQueueLength
[ -f /var/lib/mympd/state/notificationPage ] || echo -n "true" > /var/lib/mympd/state/notificationPage
[ -f /var/lib/mympd/state/notificationWeb ] || echo -n "false" > /var/lib/mympd/state/notificationWeb
# fix ownership of /var/lib/mympd
echo "INFO: Fixing ownership of /var/lib/mympd"
chown -R mympd.mympd /var/lib/mympd
# 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.3.0 Version: 4.3.1
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.3.0.zip Source: https://github.com/jcorporation/myMPD/archive/v%{version}.zip
BuildRequires: gcc BuildRequires: gcc
BuildRequires: cmake BuildRequires: cmake
BuildRequires: unzip BuildRequires: unzip
@@ -44,9 +44,6 @@ 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
echo "Fixing ownership of /var/lib/mympd"
chown -R mympd.mympd /var/lib/mympd
if [ -d /etc/systemd ] if [ -d /etc/systemd ]
then then
[ -d /usr/lib/systemd/system ] || mkdir -p /usr/lib/systemd/system [ -d /usr/lib/systemd/system ] || mkdir -p /usr/lib/systemd/system
@@ -78,6 +75,16 @@ do
fi fi
done done
#default state files
[ -f /var/lib/mympd/state/jukeboxMode ] || echo -n "0" > /var/lib/mympd/state/jukeboxMode
[ -f /var/lib/mympd/state/jukeboxPlaylist ] || echo -n "Database" > /var/lib/mympd/state/jukeboxPlaylist
[ -f /var/lib/mympd/state/jukeboxQueueLength ] || echo -n "1" > /var/lib/mympd/state/jukeboxQueueLength
[ -f /var/lib/mympd/state/notificationPage ] || echo -n "true" > /var/lib/mympd/state/notificationPage
[ -f /var/lib/mympd/state/notificationWeb ] || echo -n "false" > /var/lib/mympd/state/notificationWeb
echo "Fixing ownership of /var/lib/mympd"
chown -R mympd.mympd /var/lib/mympd
# 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

@@ -1,18 +1,18 @@
.\" Manpage for myMPD. .\" Manpage for myMPD.
.\" Contact mail@jcgames.de to correct errors or typos. .\" Contact mail@jcgames.de to correct errors or typos.
.TH man 1 "22 Aug 2018" "4.0.0" "myMPD man page" .TH man 1 "02 Oct 2018" "4.3.1" "myMPD man page"
.SH NAME .SH NAME
myMPD \- Standalone MPD Web GUI written in C, utilizing Websockets and Bootstrap/JS myMPD \- myMPD is a standalone and mobile friendly web mpdclient
.SH SYNOPSIS .SH SYNOPSIS
mympd /path/to/mympd.conf mympd /path/to/mympd.conf
.SH DESCRIPTION .SH DESCRIPTION
myMPD is a lightweight MPD web client that runs without a dedicated webserver or interpreter. myMPD is a lightweight MPD web client that runs without a dedicated webserver or interpreter. It's tuned for minimal resource usage and requires only very litte dependencies.
It's tuned for minimal resource usage and requires only very litte dependencies. myMPD is a fork of ympd (https://github.com/notandy/ympd).
myMPD is a fork of ympd. This fork provides a reworked ui based on Bootstrap 4, a modernized backend and many new features while having the same small footprint as ympd.
.SH BUGS .SH BUGS
No known bugs. No known bugs.
.SH AUTHOR .SH AUTHOR
Juergen Mang (mail@jcgames.de) Juergen Mang (mail@jcgames.de)
https://github.com/jcorporation/mympd https://github.com/jcorporation/mympd

View File

@@ -33,7 +33,6 @@ mixramp = false
stickers = true 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
taglist = Artist,Album,AlbumArtist,Title,Track,Genre,Date,Composer,Performer taglist = Artist,Album,AlbumArtist,Title,Track,Genre,Date,Composer,Performer
#Enable smart playlists #Enable smart playlists

4
debian/changelog vendored
View File

@@ -1,5 +1,5 @@
mympd (4.3.0-1) stable; urgency=medium mympd (4.3.1-1) stable; urgency=medium
* Release from master * Release from master
-- Juergen Mang <mail@jcgames.de> Tue, 25 Sep 2018 00:35:00 +0200 -- Juergen Mang <mail@jcgames.de> Mon, 02 Oct 2018 00:04:00 +0200

14
debian/postinst vendored
View File

@@ -6,8 +6,7 @@ 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
echo "Fixing ownership of /var/lib/mympd"
chown -R mympd.mympd /var/lib/mympd
echo "Trying to link musicdir to library" echo "Trying to link musicdir to library"
if [ -f /etc/mpd.conf ] if [ -f /etc/mpd.conf ]
@@ -48,7 +47,6 @@ do
fi fi
done 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
@@ -57,6 +55,16 @@ else
echo "mympd.conf installed as mympd.conf.dist" echo "mympd.conf installed as mympd.conf.dist"
fi fi
#default state files
[ -f /var/lib/mympd/state/jukeboxMode ] || echo -n "0" > /var/lib/mympd/state/jukeboxMode
[ -f /var/lib/mympd/state/jukeboxPlaylist ] || echo -n "Database" > /var/lib/mympd/state/jukeboxPlaylist
[ -f /var/lib/mympd/state/jukeboxQueueLength ] || echo -n "1" > /var/lib/mympd/state/jukeboxQueueLength
[ -f /var/lib/mympd/state/notificationPage ] || echo -n "true" > /var/lib/mympd/state/notificationPage
[ -f /var/lib/mympd/state/notificationWeb ] || echo -n "false" > /var/lib/mympd/state/notificationWeb
echo "Fixing ownership of /var/lib/mympd"
chown -R mympd.mympd /var/lib/mympd
if [ -d /etc/mympd/ssl ] if [ -d /etc/mympd/ssl ]
then then
echo "Certificates already created" echo "Certificates already created"

File diff suppressed because one or more lines are too long

View File

@@ -42,9 +42,10 @@ showAddToPlaylist(app.current.search))},!1);document.getElementById("searchAddAl
("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, ("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,
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", 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",
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"); 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");
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", 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&&"SELECT"!=a.target.tagName){if(a.shiftKey)switch(a.which){case 83:sendAPI({cmd:"MPD_API_QUEUE_SHUFFLE"});break;case 67:sendAPI({cmd:"MPD_API_QUEUE_CROP"});break;default:return}else switch(a.which){case 37:clickPrev();break;case 39:clickNext();break;case 32:clickPlay();break;case 83:clickStop();
{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"); break;case 173:chVolume(-5);break;case 171:chVolume(5);break;case 67:sendAPI({cmd:"MPD_API_QUEUE_CLEAR"});break;default:return}a.preventDefault()}},!1);"serviceWorker"in navigator&&"https"==document.URL.substring(0,5)&&window.addEventListener("load",function(){navigator.serviceWorker.register("/sw.min.js",{scope:"/"}).then(function(a){console.log("ServiceWorker registration successful with scope: ",a.scope);a.update()},function(a){console.log("ServiceWorker registration failed: ",a)})});window.addEventListener("beforeinstallprompt",
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(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");
@@ -66,8 +67,8 @@ function setCounter(a,b,c){currentSong.totalTime=b;currentSong.elapsedTime=c;cur
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))}
function parseState(a){if(JSON.stringify(a)!==JSON.stringify(lastState)){if(1==a.data.state){for(var b=0;b<domCache.btnsPlayLen;b++)domCache.btnsPlay[b].innerText="play_arrow";playstate="stop"}else if(2==a.data.state){for(b=0;b<domCache.btnsPlayLen;b++)domCache.btnsPlay[b].innerText="pause";playstate="play"}else{for(b=0;b<domCache.btnsPlayLen;b++)domCache.btnsPlay[b].innerText="play_arrow";playstate="pause"}-1==a.data.nextSongPos&&0==settings.jukeboxMode?domCache.btnNext.setAttribute("disabled","disabled"): function parseState(a){if(JSON.stringify(a)!==JSON.stringify(lastState)){if(1==a.data.state){for(var b=0;b<domCache.btnsPlayLen;b++)domCache.btnsPlay[b].innerText="play_arrow";playstate="stop"}else if(2==a.data.state){for(b=0;b<domCache.btnsPlayLen;b++)domCache.btnsPlay[b].innerText="pause";playstate="play"}else{for(b=0;b<domCache.btnsPlayLen;b++)domCache.btnsPlay[b].innerText="play_arrow";playstate="pause"}-1==a.data.nextSongPos&&0==settings.jukeboxMode?domCache.btnNext.setAttribute("disabled","disabled"):
domCache.btnNext.removeAttribute("disabled");0>=a.data.songPos?domCache.btnPrev.setAttribute("disabled","disabled"):domCache.btnPrev.removeAttribute("disabled");if(0==a.data.queueLength)for(b=0;b<domCache.btnsPlayLen;b++)domCache.btnsPlay[b].setAttribute("disabled","disabled");else for(b=0;b<domCache.btnsPlayLen;b++)domCache.btnsPlay[b].removeAttribute("disabled");-1==a.data.volume?(domCache.volumePrct.innerText="Volumecontrol disabled",domCache.volumeControl.classList.add("hide")):(domCache.volumeControl.classList.remove("hide"), domCache.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);lastState&&lastState.data.currentSongId!=a.data.currentSongId&&sendAPI({cmd:"MPD_API_PLAYER_CURRENT_SONG"},songChange);"-1"==a.data.songPos&&(domCache.currentTrack.innerText="Not playing",domCache.currentAlbum.innerText="",domCache.currentArtist.innerText=
"");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)} "",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)}
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+ 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+
"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); "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);
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>': 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>':
@@ -97,9 +98,9 @@ document.getElementById(c+"ButtonsBottom").classList.add("hide"));0<app.current.
function appendQueue(a,b,c){switch(a){case "song":case "dir":sendAPI({cmd:"MPD_API_QUEUE_ADD_TRACK",data:{uri:b}});showNotification('"'+c+'" added',"","","success");break;case "plist":sendAPI({cmd:"MPD_API_QUEUE_ADD_PLAYLIST",data:{plist:b}}),showNotification('"'+c+'" added',"","","success")}}function appendAfterQueue(a,b,c,d){switch(a){case "song":sendAPI({cmd:"MPD_API_QUEUE_ADD_TRACK_AFTER",data:{uri:b,to:c}}),showNotification('"'+d+'" added to pos '+c,"","","success")}} function appendQueue(a,b,c){switch(a){case "song":case "dir":sendAPI({cmd:"MPD_API_QUEUE_ADD_TRACK",data:{uri:b}});showNotification('"'+c+'" added',"","","success");break;case "plist":sendAPI({cmd:"MPD_API_QUEUE_ADD_PLAYLIST",data:{plist:b}}),showNotification('"'+c+'" added',"","","success")}}function appendAfterQueue(a,b,c,d){switch(a){case "song":sendAPI({cmd:"MPD_API_QUEUE_ADD_TRACK_AFTER",data:{uri:b,to:c}}),showNotification('"'+d+'" added to pos '+c,"","","success")}}
function replaceQueue(a,b,c){switch(a){case "song":case "dir":sendAPI({cmd:"MPD_API_QUEUE_REPLACE_TRACK",data:{uri:b}});showNotification('"'+c+'" replaced',"","","success");break;case "plist":sendAPI({cmd:"MPD_API_QUEUE_REPLACE_PLAYLIST",data:{plist:b}}),showNotification('"'+c+'" replaced',"","","success")}}function songClick(){var a=domCache.currentTrack.getAttribute("data-uri");""!=a&&songDetails(a)} function replaceQueue(a,b,c){switch(a){case "song":case "dir":sendAPI({cmd:"MPD_API_QUEUE_REPLACE_TRACK",data:{uri:b}});showNotification('"'+c+'" replaced',"","","success");break;case "plist":sendAPI({cmd:"MPD_API_QUEUE_REPLACE_PLAYLIST",data:{plist:b}}),showNotification('"'+c+'" replaced',"","","success")}}function songClick(){var a=domCache.currentTrack.getAttribute("data-uri");""!=a&&songDetails(a)}
function artistClick(){var a=domCache.currentArtist.getAttribute("data-albumartist");""!=a&&appGoto("Browse","Database","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;for(var c="",d=0;d<settings.tags.length;d++){var e=a.data[settings.tags[d].toLowerCase()];if("duration"==settings.tags[d]){var f=Math.floor(e/60);e-=60*f;e=f+":"+(10>e?"0":"")+e}c+="<tr><th>"+settings.tags[d]+"</th><td>"+e+"</td></tr>"}c+='<tr><th>Uri</th><td><a class="text-success" href="/library/'+
'">'+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.data.uri+"</a></td></tr>";1==settings.stickers&&(d="not voted",0==a.data.like?d='<span class="material-icons">thumb_down_alt</span>':2==a.data.like&&(d='<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){document.getElementById("BrowsePlaylistsAllList").classList.add("opacity05");appGoto("Browse","Playlists","Detail","0/-/"+a)} d+"</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 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>":"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> 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>
@@ -110,12 +111,12 @@ function setVoteSongBtns(a,b){""==b||0==b.indexOf("http://")||0==b.indexOf("http
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 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"); 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"), for(var c='<option value="any">Any Tag</option>',d=0;d<settings.tags.length;d++)"Track"!=settings.tags[d]&&(c+='<option value="'+settings.tags[d]+'">'+settings.tags[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"==
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()} 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"),a=a.data.timerange/24/60/60,document.getElementById("inputSaveSmartPlaylistNewestTimerange").value=a);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 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"== 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, b){c=document.getElementById("selectSaveSmartPlaylistSticker");c=c.options[c.selectedIndex].value;var e=document.getElementById("inputSaveSmartPlaylistStickerMaxentries");if(!chkInt(e,d))return;sendAPI({cmd:"MPD_API_SMARTPLS_SAVE",data:{type:b,playlist:a,sticker:c,maxentries:e.value}})}else if("newest"==b){c=document.getElementById("inputSaveSmartPlaylistNewestTimerange");if(!chkInt(c,d))return;d=86400*parseInt(c.value);sendAPI({cmd:"MPD_API_SMARTPLS_SAVE",data:{type:b,playlist:a,timerange:d}})}else{document.getElementById("saveSmartPlaylistType").classList.add("is-invalid");
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")} 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)}
@@ -158,5 +159,6 @@ domCache.currentArtist.innerText="";"undefined"!=typeof a.data.album&&0<a.data.a
function doSetFilterLetter(a){var b=document.getElementById(a+"Letters").getElementsByClassName("active")[0];b&&b.classList.remove("active");b=app.current.filter;"0"==b&&(b="#");document.getElementById(a).innerText="Filter"+("-"!=b?": "+b:"");if("-"!=b){a=document.getElementById(a+"Letters").getElementsByTagName("button");for(var c=a.length,d=0;d<c;d++)if(a[d].innerText==b){a[d].classList.add("active");break}}} function doSetFilterLetter(a){var b=document.getElementById(a+"Letters").getElementsByClassName("active")[0];b&&b.classList.remove("active");b=app.current.filter;"0"==b&&(b="#");document.getElementById(a).innerText="Filter"+("-"!=b?": "+b:"");if("-"!=b){a=document.getElementById(a+"Letters").getElementsByTagName("button");for(var c=a.length,d=0;d<c;d++)if(a[d].innerText==b){a[d].classList.add("active");break}}}
function addFilterLetter(a){for(var b='<button class="mr-1 mb-1 btn btn-sm btn-secondary material-icons material-icons-small">delete</button><button class="mr-1 mb-1 btn btn-sm btn-secondary">#</button>',c=65;90>=c;c++)b+='<button class="mr-1 mb-1 btn-sm btn btn-secondary">'+String.fromCharCode(c)+"</button>";a=document.getElementById(a);a.innerHTML=b;a.addEventListener("click",function(a){switch(a.target.innerText){case "delete":b="-";break;case "#":b="0";break;default:b=a.target.innerText}appGoto(app.current.app, function addFilterLetter(a){for(var b='<button class="mr-1 mb-1 btn btn-sm btn-secondary material-icons material-icons-small">delete</button><button class="mr-1 mb-1 btn btn-sm btn-secondary">#</button>',c=65;90>=c;c++)b+='<button class="mr-1 mb-1 btn-sm btn btn-secondary">'+String.fromCharCode(c)+"</button>";a=document.getElementById(a);a.innerHTML=b;a.addEventListener("click",function(a){switch(a.target.innerText){case "delete":b="-";break;case "#":b="0";break;default:b=a.target.innerText}appGoto(app.current.app,
app.current.tab,app.current.view,"0/"+b+"/"+app.current.search)},!1)}function selectTag(a,b,c){a=document.getElementById(a);var d=a.querySelector(".active");d&&d.classList.remove("active");if(d=a.querySelector("[data-tag="+c+"]"))d.classList.add("active"),document.getElementById(b).innerText=d.innerText} app.current.tab,app.current.view,"0/"+b+"/"+app.current.search)},!1)}function selectTag(a,b,c){a=document.getElementById(a);var d=a.querySelector(".active");d&&d.classList.remove("active");if(d=a.querySelector("[data-tag="+c+"]"))d.classList.add("active"),document.getElementById(b).innerText=d.innerText}
function addTagList(a,b){var c="";1==b&&(c+='<button type="button" class="btn btn-secondary btn-sm btn-block" data-tag="any">Any Tag</button>');for(var d in settings.tags)1==settings.tags[d]&&"Track"!=d&&(c+='<button type="button" class="btn btn-secondary btn-sm btn-block" data-tag="'+d+'">'+d+"</button>");document.getElementById(a).innerHTML=c}function gotoTagList(){appGoto(app.current.app,app.current.tab,app.current.view,"0/-/")} function addTagList(a,b){var c="",d="Title MUSICBRAINZ_TRACKID Count Disc Comment Name".split(" ");1==b&&(c+='<button type="button" class="btn btn-secondary btn-sm btn-block" data-tag="any">Any Tag</button>');for(var e=0;e<settings.tags.length;e++)"Track"!=settings.tags[e]&&(0==b&&-1<d.indexOf(settings.tags[e])||(c+='<button type="button" class="btn btn-secondary btn-sm btn-block" data-tag="'+settings.tags[e]+'">'+settings.tags[e]+"</button>"));document.getElementById(a).innerHTML=c}
function chVolume(a){a=parseInt(domCache.volumeBar.value)+a;0>a?a=0:100<a&&(a=100);domCache.volumeBar.value=a;sendAPI({cmd:"MPD_API_PLAYER_VOLUME",data:{volume:a}})}function beautifyDuration(a){var b=Math.floor(a/86400),c=Math.floor(a/3600)-24*b,d=Math.floor(a/60)-60*c-1440*b;a=a-86400*b-3600*c-60*d;return(0<b?b+"\u2009d ":"")+(0<c?c+"\u2009h "+(10>d?"0":""):"")+d+"\u2009m "+(10>a?"0":"")+a+"\u2009s"}function genId(a){return"id"+a.replace(/[^\w\-]/g,"")}appInit(); function gotoTagList(){appGoto(app.current.app,app.current.tab,app.current.view,"0/-/")}function chVolume(a){a=parseInt(domCache.volumeBar.value)+a;0>a?a=0:100<a&&(a=100);domCache.volumeBar.value=a;sendAPI({cmd:"MPD_API_PLAYER_VOLUME",data:{volume:a}})}function beautifyDuration(a){var b=Math.floor(a/86400),c=Math.floor(a/3600)-24*b,d=Math.floor(a/60)-60*c-1440*b;a=a-86400*b-3600*c-60*d;return(0<b?b+"\u2009d ":"")+(0<c?c+"\u2009h "+(10>d?"0":""):"")+d+"\u2009m "+(10>a?"0":"")+a+"\u2009s"}
function genId(a){return"id"+a.replace(/[^\w\-]/g,"")}appInit();

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.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(" "); 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.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(" ");
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

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

View File

@@ -699,11 +699,6 @@
<input type="text" class="form-control" id="inputSaveSmartPlaylistNewestTimerange"/> <input type="text" class="form-control" id="inputSaveSmartPlaylistNewestTimerange"/>
<div class="invalid-feedback">Must be a number.</div> <div class="invalid-feedback">Must be a number.</div>
</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> </div>
</form> </form>
</div> </div>

View File

@@ -567,20 +567,46 @@ function appInit() {
}, false); }, false);
document.addEventListener('keydown', function(event) { document.addEventListener('keydown', function(event) {
if (event.target.tagName == 'INPUT') if (event.target.tagName == 'INPUT' || event.target.tagName == 'SELECT')
return; return;
switch (event.which) { if (event.shiftKey) {
case 37: //left switch (event.which) {
clickPrev(); case 83: //S
break; sendAPI({"cmd": "MPD_API_QUEUE_SHUFFLE"});
case 39: //right break;
clickNext(); case 67: //C
break; sendAPI({"cmd": "MPD_API_QUEUE_CROP"});
case 32: //space break;
clickPlay(); default:
break; return;
default: }
return; }
else {
switch (event.which) {
case 37: //left
clickPrev();
break;
case 39: //right
clickNext();
break;
case 32: //space
clickPlay();
break;
case 83: //s
clickStop();
break;
case 173: //-
chVolume(-5);
break;
case 171: //+
chVolume(5);
break;
case 67: //c
sendAPI({"cmd": "MPD_API_QUEUE_CLEAR"});
break;
default:
return;
}
} }
event.preventDefault(); event.preventDefault();
}, false); }, false);
@@ -1029,7 +1055,8 @@ function parseState(obj) {
setCounter(obj.data.currentSongId, obj.data.totalTime, obj.data.elapsedTime); setCounter(obj.data.currentSongId, obj.data.totalTime, obj.data.elapsedTime);
//Get current song //Get current song
sendAPI({"cmd": "MPD_API_PLAYER_CURRENT_SONG"}, songChange); if (lastState && lastState.data.currentSongId != obj.data.currentSongId)
sendAPI({"cmd": "MPD_API_PLAYER_CURRENT_SONG"}, songChange);
//clear playback card if not playing //clear playback card if not playing
if (obj.data.songPos == '-1') { if (obj.data.songPos == '-1') {
domCache.currentTrack.innerText = 'Not playing'; domCache.currentTrack.innerText = 'Not playing';
@@ -1508,16 +1535,14 @@ function parseSongDetails(obj) {
modal.getElementsByTagName('h1')[0].innerText = obj.data.title; modal.getElementsByTagName('h1')[0].innerText = obj.data.title;
var songDetails = ''; var songDetails = '';
for (var key in settings.tags) { for (var i = 0; i < settings.tags.length; i++) {
if (settings.tags[key] == true) { var value = obj.data[settings.tags[i].toLowerCase()];
var value = obj.data[key.toLowerCase()]; if (settings.tags[i] == 'duration') {
if (key == 'duration') { var minutes = Math.floor(value / 60);
var minutes = Math.floor(value / 60); var seconds = value - minutes * 60;
var seconds = value - minutes * 60; value = minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
value = minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
}
songDetails += '<tr><th>' + key + '</th><td>' + value + '</td></tr>';
} }
songDetails += '<tr><th>' + settings.tags[i] + '</th><td>' + value + '</td></tr>';
} }
songDetails += '<tr><th>Uri</th><td><a class="text-success" href="/library/' + obj.data.uri + '">' + obj.data.uri + '</a></td></tr>'; songDetails += '<tr><th>Uri</th><td><a class="text-success" href="/library/' + obj.data.uri + '">' + obj.data.uri + '</a></td></tr>';
@@ -1649,9 +1674,9 @@ function parseSmartPlaylist(obj) {
document.getElementById('saveSmartPlaylistSticker').classList.add('hide'); document.getElementById('saveSmartPlaylistSticker').classList.add('hide');
document.getElementById('saveSmartPlaylistNewest').classList.add('hide'); document.getElementById('saveSmartPlaylistNewest').classList.add('hide');
var tagList = '<option value="any">Any Tag</option>'; var tagList = '<option value="any">Any Tag</option>';
for (var key in settings.tags) { for (var i = 0; i < settings.tags.length; i++) {
if (settings.tags[key] == true && key != 'Track') { if (settings.tags[i] != 'Track') {
tagList += '<option value="' + key + '">' + key + '</option>'; tagList += '<option value="' + settings.tags[i] + '">' + settings.tags[i] + '</option>';
} }
} }
document.getElementById('selectSaveSmartPlaylistTag').innerHTML = tagList; document.getElementById('selectSaveSmartPlaylistTag').innerHTML = tagList;
@@ -1669,7 +1694,6 @@ function parseSmartPlaylist(obj) {
document.getElementById('saveSmartPlaylistNewest').classList.remove('hide'); document.getElementById('saveSmartPlaylistNewest').classList.remove('hide');
var timerange = obj.data.timerange / 24 / 60 / 60; var timerange = obj.data.timerange / 24 / 60 / 60;
document.getElementById('inputSaveSmartPlaylistNewestTimerange').value = timerange; document.getElementById('inputSaveSmartPlaylistNewestTimerange').value = timerange;
document.getElementById('inputSaveSmartPlaylistNewestMaxentries').value = obj.data.maxentries;
} }
modalSaveSmartPlaylist.show(); modalSaveSmartPlaylist.show();
nameEl.focus(); nameEl.focus();
@@ -1711,11 +1735,7 @@ function saveSmartPlaylist() {
if (!chkInt(timerangeEl, frm)) if (!chkInt(timerangeEl, frm))
return; return;
var timerange = parseInt(timerangeEl.value) * 60 * 60 * 24; var timerange = parseInt(timerangeEl.value) * 60 * 60 * 24;
var maxentriesEl = document.getElementById('inputSaveSmartPlaylistNewestMaxentries'); sendAPI({"cmd": "MPD_API_SMARTPLS_SAVE", "data": {"type": type, "playlist": name, "timerange": timerange}});
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 { else {
document.getElementById('saveSmartPlaylistType').classList.add('is-invalid'); document.getElementById('saveSmartPlaylistType').classList.add('is-invalid');
@@ -2374,12 +2394,15 @@ function selectTag(btnsEl, desc, setTo) {
function addTagList(x, any) { function addTagList(x, any) {
var tagList = ''; var tagList = '';
var tagBlacklist = ["Title", "MUSICBRAINZ_TRACKID", "Count", "Disc", "Comment", "Name"];
if (any == true) if (any == true)
tagList += '<button type="button" class="btn btn-secondary btn-sm btn-block" data-tag="any">Any Tag</button>'; tagList += '<button type="button" class="btn btn-secondary btn-sm btn-block" data-tag="any">Any Tag</button>';
for (var key in settings.tags) { for (var i = 0; i < settings.tags.length; i++) {
if (settings.tags[key] == true && key != 'Track') { if (settings.tags[i] == 'Track')
tagList += '<button type="button" class="btn btn-secondary btn-sm btn-block" data-tag="' + key + '">' + key + '</button>'; continue;
} if (any == false && tagBlacklist.indexOf(settings.tags[i]) > -1)
continue;
tagList += '<button type="button" class="btn btn-secondary btn-sm btn-block" data-tag="' + settings.tags[i] + '">' + settings.tags[i] + '</button>';
} }
var tagListEl = document.getElementById(x); var tagListEl = document.getElementById(x);
tagListEl.innerHTML = tagList; tagListEl.innerHTML = tagList;

View File

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

View File

@@ -1,4 +1,15 @@
#!/bin/bash #!/bin/bash
VERSION=$(grep VERSION_ CMakeLists.txt | cut -d\" -f2 | tr '\n' '.')
cat > debian/changelog << EOL
mympd (${VERSION}-1) stable; urgency=medium
* Release from master
-- Juergen Mang <mail@jcgames.de> $(date +"%a, %d %b %Y %H:%m:%S %z")
EOL
./mkclean.sh ./mkclean.sh
tar -czvf ../mympd_4.3.0.orig.tar.gz * tar -czvf ../mympd_${VERSION}.orig.tar.gz *
dpkg-buildpackage -rfakeroot dpkg-buildpackage -rfakeroot

124
src/list.c Normal file
View File

@@ -0,0 +1,124 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#include "list.h"
int list_init(struct list *l) {
l->length = 0;
l->list = NULL;
return 0;
}
int list_get_value(const struct list *l, char *data) {
int value = 0;
struct node *current = l->list;
while (current != NULL) {
if (strcmp(current->data, data) == 0) {
value = current->value;
break;
}
current = current->next;
}
return value;
}
struct node *list_node_at(const struct list *l, unsigned index) {
/* if there's no data in the list, fail */
if (l->list == NULL) { return NULL; }
struct node * current = l->list;
for (; index > 0; index--) {
if (current->next == NULL) { return NULL; }
current = current->next;
}
return current;
}
int list_swap_item(struct node *n1, struct node *n2) {
if (n1 == n2)
return 1;
if (n1 == NULL || n2 == NULL)
return 1;
int value = n2->value;
char *data = strdup(n2->data);
n2->value = n1->value;
n2->data = realloc(n2->data, strlen(n1->data) + 1);
if (n2->data)
strcpy(n2->data, n1->data);
n1->value = value;
n1->data = realloc(n1->data, strlen(data) + 1);
if (n1->data)
strcpy(n1->data, data);
free(data);
return 0;
}
int list_shuffle(struct list *l) {
int pos;
int n = 0;
if (l->length < 2)
return 1;
srand((unsigned int)time(NULL));
struct node *current = l->list;
while (current != NULL) {
pos = rand() / (RAND_MAX / (l->length - n + 1) + 1);
list_swap_item(current, list_node_at(l, pos));
n++;
current = current->next;
}
return 0;
}
int list_replace(struct list *l, int pos, char *data, int value) {
int i = 0;
struct node *current = l->list;
while (current->next != NULL) {
if (i == pos)
break;
current = current->next;
i++;
}
current->value = value;
current->data = realloc(current->data, strlen(data) + 1);
if (current->data)
strcpy(current->data, data);
return 0;
}
int list_push(struct list *l, char *data, int value) {
struct node *n = malloc(sizeof(struct node));
n->value = value;
n->data = strdup(data);
n->next = NULL;
struct node **next = &l->list;
while (*next != NULL) {
next = &(*next)->next;
}
*next = n;
l->length++;
return 0;
}
int list_free(struct list *l) {
struct node *current = l->list, *tmp = NULL;
while (current != NULL) {
free(current->data);
tmp = current;
current = current->next;
free(tmp);
}
list_init(l);
return 0;
}

21
src/list.h Normal file
View File

@@ -0,0 +1,21 @@
struct node {
char *data;
int value;
struct node *next;
};
struct list {
unsigned length;
struct node *list;
};
int list_init(struct list *l);
int list_push(struct list *l, char *data, int value);
int list_replace(struct list *l, int pos, char *data, int value);
int list_free(struct list *l);
int list_get_value(const struct list *l, char *data);
int list_shuffle(struct list *l);
int list_swap_item(struct node *n1, struct node *n2);
struct node *list_node_at(const struct list * l, unsigned index);

View File

@@ -54,7 +54,7 @@ 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_buf1, int_buf2, int_rc; int je, int_buf1, int_rc;
float float_buf; float float_buf;
char *p_charbuf1, *p_charbuf2, *p_charbuf3, *p_charbuf4; char *p_charbuf1, *p_charbuf2, *p_charbuf3, *p_charbuf4;
char p_char[4]; char p_char[4];
@@ -210,8 +210,8 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) {
free(p_charbuf3); free(p_charbuf3);
} }
else if (strcmp(p_charbuf1, "newest") == 0) { 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); je = json_scanf(msg.p, msg.len, "{data: {playlist: %Q, timerange: %d}}", &p_charbuf2, &int_buf1);
n = mympd_smartpls_save(p_charbuf1, p_charbuf2, NULL, NULL, int_buf2, int_buf1); n = mympd_smartpls_save(p_charbuf1, p_charbuf2, NULL, NULL, 0, int_buf1);
free(p_charbuf2); free(p_charbuf2);
} }
else if (strcmp(p_charbuf1, "search") == 0) { else if (strcmp(p_charbuf1, "search") == 0) {
@@ -680,15 +680,6 @@ void mympd_mpd_features() {
// Defaults // Defaults
mpd.feat_sticker = false; mpd.feat_sticker = false;
mpd.tag_artist = false;
mpd.tag_album = false;
mpd.tag_album_artist = false;
mpd.tag_title = false;
mpd.tag_track = false;
mpd.tag_genre = false;
mpd.tag_date = false;
mpd.tag_composer = false;
mpd.tag_performer = false;
mpd_send_allowed_commands(mpd.conn); mpd_send_allowed_commands(mpd.conn);
while ((pair = mpd_recv_command_pair(mpd.conn)) != NULL) { while ((pair = mpd_recv_command_pair(mpd.conn)) != NULL) {
@@ -708,69 +699,22 @@ void mympd_mpd_features() {
} }
printf("MPD supported tags: "); printf("MPD supported tags: ");
list_free(&mpd_tags);
mpd_send_list_tag_types(mpd.conn); mpd_send_list_tag_types(mpd.conn);
while ((pair = mpd_recv_tag_type_pair(mpd.conn)) != NULL) { while ((pair = mpd_recv_tag_type_pair(mpd.conn)) != NULL) {
printf("%s ", pair->value); printf("%s ", pair->value);
if (strcmp(pair->value, "Artist") == 0) list_push(&mpd_tags, pair->value, 1);
mpd.tag_artist = true;
else if (strcmp(pair->value, "Album") == 0)
mpd.tag_album = true;
else if (strcmp(pair->value, "AlbumArtist") == 0)
mpd.tag_album_artist = true;
else if (strcmp(pair->value, "Title") == 0)
mpd.tag_title = true;
else if (strcmp(pair->value, "Track") == 0)
mpd.tag_track = true;
else if (strcmp(pair->value, "Genre") == 0)
mpd.tag_genre = true;
else if (strcmp(pair->value, "Date") == 0)
mpd.tag_date = true;
else if (strcmp(pair->value, "Composer") == 0)
mpd.tag_composer = true;
else if (strcmp(pair->value, "Performer") == 0)
mpd.tag_performer = true;
mpd_return_pair(mpd.conn, pair); mpd_return_pair(mpd.conn, pair);
} }
mpd_response_finish(mpd.conn); mpd_response_finish(mpd.conn);
printf("\nmyMPD enabled tags: "); printf("\nmyMPD enabled tags: ");
list_free(&mympd_tags);
token = strtok(str, s); token = strtok(str, s);
while (token != NULL) { while (token != NULL) {
if (strcmp(token, "Artist") == 0) { if (list_get_value(&mpd_tags, token) == 1) {
if (mpd.tag_artist == true) printf("%s ", token); list_push(&mympd_tags, token, 1);
else mpd.tag_artist = false; printf("%s ", token);
}
else if (strcmp(token, "Album") == 0) {
if (mpd.tag_album == true) printf("%s ", token);
else mpd.tag_album = false;
}
else if (strcmp(token, "AlbumArtist") == 0) {
if (mpd.tag_album_artist == true) printf("%s ", token);
else mpd.tag_album_artist = false;
}
else if (strcmp(token, "Title") == 0) {
if (mpd.tag_title == true) printf("%s ", token);
else mpd.tag_title = false;
}
else if (strcmp(token, "Track") == 0) {
if (mpd.tag_track == true) printf("%s ", token);
else mpd.tag_track = false;
}
else if (strcmp(token, "Genre") == 0) {
if (mpd.tag_genre == true) printf("%s ", token);
else mpd.tag_genre = false;
}
else if (strcmp(token, "Date") == 0) {
if (mpd.tag_date == true) printf("%s ", token);
else mpd.tag_date = false;
}
else if (strcmp(token, "Composer") == 0) {
if (mpd.tag_composer == true) printf("%s ", token);
else mpd.tag_composer = false;
}
else if (strcmp(token, "Performer") == 0) {
if (mpd.tag_performer == true) printf("%s ", token);
else mpd.tag_performer = false;
} }
token = strtok(NULL, s); token = strtok(NULL, s);
} }
@@ -1008,11 +952,12 @@ 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, j, addSongs; int queue_length, addSongs, i;
struct mpd_entity *entity; struct mpd_entity *entity;
const struct mpd_song *song; const struct mpd_song *song;
struct mpd_pair *pair; struct mpd_pair *pair;
char *album; int lineno = 1;
int nkeep = 0;
if (!status) { if (!status) {
LOG_ERROR_AND_RECOVER("mpd_run_status"); LOG_ERROR_AND_RECOVER("mpd_run_status");
@@ -1022,116 +967,128 @@ void mympd_jukebox() {
mpd_status_free(status); mpd_status_free(status);
if (queue_length > mympd_state.jukeboxQueueLength) if (queue_length > mympd_state.jukeboxQueueLength)
return; return;
srand((unsigned int)time(NULL));
num_songs = 0;
if (mympd_state.jukeboxMode == 1 && strcmp(mympd_state.jukeboxPlaylist, "Database") == 0) {
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);
mpd_stats_free(stats);
}
else if (mympd_state.jukeboxMode == 1) {
if (!mpd_send_list_playlist(mpd.conn, mympd_state.jukeboxPlaylist)) {
LOG_ERROR_AND_RECOVER("mpd_send_list_playlist");
return;
}
while ((entity = mpd_recv_entity(mpd.conn)) != NULL) {
num_songs++;
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;
}
if (!mpd_search_commit(mpd.conn)) {
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) if (mympd_state.jukeboxMode == 1)
addSongs = mympd_state.jukeboxQueueLength - queue_length; addSongs = mympd_state.jukeboxQueueLength - queue_length;
else else
addSongs = 1; addSongs = 1;
if (num_songs > 0) {
for (j = 0; j < addSongs; j++) { if (addSongs < 1)
rand_song = rand() % num_songs; return;
if (mympd_state.jukeboxMode == 1) {
//add songs srand((unsigned int)time(NULL));
if (strcmp(mympd_state.jukeboxPlaylist, "Database") == 0) {
if (!mpd_send_list_all(mpd.conn, "/")) { struct list add_list;
LOG_ERROR_AND_RECOVER("mpd_send_list_playlist"); list_init(&add_list);
return;
} if (mympd_state.jukeboxMode == 1) {
} //add songs
else { if (strcmp(mympd_state.jukeboxPlaylist, "Database") == 0) {
if (!mpd_send_list_playlist(mpd.conn, mympd_state.jukeboxPlaylist)) { if (!mpd_send_list_all(mpd.conn, "/")) {
LOG_ERROR_AND_RECOVER("mpd_send_list_playlist"); LOG_ERROR_AND_RECOVER("mpd_send_list_playlist");
return; list_free(&add_list);
} 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);
}
else if (mympd_state.jukeboxMode == 2) {
//add album
if (!mpd_search_db_tags(mpd.conn, MPD_TAG_ALBUM)) {
LOG_ERROR_AND_RECOVER("mpd_send_list_playlist");
return;
}
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_run_play(mpd.conn); else {
if (!mpd_send_list_playlist(mpd.conn, mympd_state.jukeboxPlaylist)) {
LOG_ERROR_AND_RECOVER("mpd_send_list_playlist");
list_free(&add_list);
return;
}
}
while ((entity = mpd_recv_entity(mpd.conn)) != NULL) {
if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) {
if (randrange(lineno) < addSongs) {
if (nkeep < addSongs) {
song = mpd_entity_get_song(entity);
list_push(&add_list, mpd_song_get_uri(song), lineno);
nkeep++;
}
else {
i = 0;
if (addSongs > 1)
i = randrange(addSongs);
if (addSongs == 1) {
song = mpd_entity_get_song(entity);
list_replace(&add_list, 0, mpd_song_get_uri(song), lineno);
}
else {
song = mpd_entity_get_song(entity);
list_replace(&add_list, i, mpd_song_get_uri(song), lineno);
}
}
}
lineno++;
}
mpd_entity_free(entity);
}
} }
else if (mympd_state.jukeboxMode == 2) {
//add album
if (!mpd_search_db_tags(mpd.conn, MPD_TAG_ALBUM)) {
LOG_ERROR_AND_RECOVER("mpd_send_list_playlist");
list_free(&add_list);
return;
}
if (!mpd_search_commit(mpd.conn)) {
LOG_ERROR_AND_RECOVER("mpd_send_list_playlist");
list_free(&add_list);
return;
}
while ((pair = mpd_recv_pair_tag(mpd.conn, MPD_TAG_ALBUM )) != NULL) {
if (randrange(lineno) < addSongs) {
if (nkeep < addSongs) {
list_push(&add_list, strdup(pair->value), lineno);
nkeep++;
}
else {
i = 0;
if (addSongs > 1)
i = randrange(addSongs);
if (addSongs == 1) {
list_replace(&add_list, 0, strdup(pair->value), lineno);
}
else {
list_replace(&add_list, i, strdup(pair->value), lineno);
}
}
}
lineno++;
mpd_return_pair(mpd.conn, pair);
}
}
if (nkeep < addSongs) {
fprintf(stderr, "Warning: input didn't contain %d entries\n", addSongs);
}
list_shuffle(&add_list);
struct node *current = add_list.list;
while (current != NULL) {
if (mympd_state.jukeboxMode == 1) {
printf("Jukebox adding song: %s\n", current->data);
if (!mpd_run_add(mpd.conn, current->data)) {
LOG_ERROR_AND_RECOVER("mpd_run_add");
}
}
else {
printf("Jukebox adding album: %s\n", current->data);
if (!mpd_send_command(mpd.conn, "searchadd", "Album", current->data, NULL)) {
LOG_ERROR_AND_RECOVER("mpd_send_command");
return;
}
mpd_response_finish(mpd.conn);
}
current = current->next;
}
list_free(&add_list);
mpd_run_play(mpd.conn);
}
int randrange(int n) {
return rand() / (RAND_MAX / (n + 1) + 1);
} }
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) {
@@ -1207,7 +1164,7 @@ bool mympd_state_get(char *name, char *value) {
snprintf(cfgfile, 400, "%s/state/%s", config.varlibdir, name); snprintf(cfgfile, 400, "%s/state/%s", config.varlibdir, name);
FILE *fp = fopen(cfgfile, "r"); FILE *fp = fopen(cfgfile, "r");
if (fp == NULL) { if (fp == NULL) {
printf("Error opening %s", cfgfile); printf("Error opening %s\n", cfgfile);
return false; return false;
} }
read = getline(&line, &n, fp); read = getline(&line, &n, fp);
@@ -1230,7 +1187,7 @@ bool mympd_state_set(char *name, char *value) {
FILE *fp = fopen(tmpfile, "w"); FILE *fp = fopen(tmpfile, "w");
if (fp == NULL) { if (fp == NULL) {
printf("Error opening %s", tmpfile); printf("Error opening %s\n", tmpfile);
return false; return false;
} }
fprintf(fp, value); fprintf(fp, value);
@@ -1243,6 +1200,7 @@ int mympd_put_settings(char *buffer) {
struct mpd_status *status; struct mpd_status *status;
char *replaygain = strdup(""); char *replaygain = strdup("");
int len; int len;
int nr = 0;
struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE);
status = mpd_run_status(mpd.conn); status = mpd_run_status(mpd.conn);
@@ -1265,9 +1223,7 @@ int mympd_put_settings(char *buffer) {
"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, smartpls: %B, maxElementsPerPage: %d, " "streamport: %d, coverimage: %Q, stickers: %B, mixramp: %B, smartpls: %B, maxElementsPerPage: %d, "
"replaygain: %Q, notificationWeb: %B, notificationPage: %B, jukeboxMode: %d, jukeboxPlaylist: %Q, jukeboxQueueLength: %d, " "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: [",
"Composer: %B, Performer: %B }"
"}}",
mpd_status_get_repeat(status), mpd_status_get_repeat(status),
mpd_status_get_single(status), mpd_status_get_single(status),
mpd_status_get_crossfade(status), mpd_status_get_crossfade(status),
@@ -1289,19 +1245,20 @@ int mympd_put_settings(char *buffer) {
mympd_state.notificationPage, mympd_state.notificationPage,
mympd_state.jukeboxMode, mympd_state.jukeboxMode,
mympd_state.jukeboxPlaylist, mympd_state.jukeboxPlaylist,
mympd_state.jukeboxQueueLength, mympd_state.jukeboxQueueLength
mpd.tag_artist,
mpd.tag_album,
mpd.tag_album_artist,
mpd.tag_title,
mpd.tag_track,
mpd.tag_genre,
mpd.tag_date,
mpd.tag_composer,
mpd.tag_performer
); );
mpd_status_free(status); mpd_status_free(status);
free(replaygain); free(replaygain);
struct node *current = mympd_tags.list;
while (current != NULL) {
if (nr ++)
len += json_printf(&out, ",");
len += json_printf(&out, "%Q", current->data);
current = current->next;
}
len += json_printf(&out, "]}}");
if (len > MAX_SIZE) if (len > MAX_SIZE)
printf("Buffer truncated\n"); printf("Buffer truncated\n");
@@ -2071,7 +2028,7 @@ int mympd_smartpls_put(char *buffer, char *playlist) {
char pl_file[400]; char pl_file[400];
char *smartpltype; char *smartpltype;
char *p_charbuf1, *p_charbuf2; char *p_charbuf1, *p_charbuf2;
int je, int_buf1, int_buf2; int je, int_buf1;
int len = 0; int len = 0;
struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE);
@@ -2091,13 +2048,12 @@ int mympd_smartpls_put(char *buffer, char *playlist) {
} }
} }
else if (strcmp(smartpltype, "newest") == 0) { else if (strcmp(smartpltype, "newest") == 0) {
je = json_scanf(content, strlen(content), "{timerange: %d, maxentries: %d}", &int_buf1, &int_buf2); je = json_scanf(content, strlen(content), "{timerange: %d}", &int_buf1);
if (je == 2) { if (je == 1) {
len = json_printf(&out, "{type: smartpls, data: {playlist: %Q, type: %Q, timerange: %d, maxentries: %d}}", len = json_printf(&out, "{type: smartpls, data: {playlist: %Q, type: %Q, timerange: %d}}",
playlist, playlist,
smartpltype, smartpltype,
int_buf1, int_buf1);
int_buf2);
} }
} }
else if (strcmp(smartpltype, "search") == 0) { else if (strcmp(smartpltype, "search") == 0) {
@@ -2128,9 +2084,9 @@ int mympd_smartpls_save(char *smartpltype, char *playlist, char *tag, char *sear
mympd_smartpls_update(playlist, tag, maxentries); mympd_smartpls_update(playlist, tag, maxentries);
} }
else if (strcmp(smartpltype, "newest") == 0) { else if (strcmp(smartpltype, "newest") == 0) {
json_fprintf(tmp_file, "{type: %Q, timerange: %d, maxentries: %d}", smartpltype, timerange, maxentries); json_fprintf(tmp_file, "{type: %Q, timerange: %d}", smartpltype, timerange);
rename(tmp_file, pl_file); rename(tmp_file, pl_file);
mympd_smartpls_update_newest(playlist, timerange, maxentries); mympd_smartpls_update_newest(playlist, timerange);
} }
else if (strcmp(smartpltype, "search") == 0) { else if (strcmp(smartpltype, "search") == 0) {
json_fprintf(tmp_file, "{type: %Q, tag: %Q, searchstr: %Q}", smartpltype, tag, searchstr); json_fprintf(tmp_file, "{type: %Q, tag: %Q, searchstr: %Q}", smartpltype, tag, searchstr);
@@ -2148,7 +2104,7 @@ int mympd_smartpls_update_all() {
char dirname[400]; char dirname[400];
int je; int je;
char *p_charbuf1, *p_charbuf2; char *p_charbuf1, *p_charbuf2;
int int_buf1, int_buf2; int int_buf1;
if (!config.smartpls) if (!config.smartpls)
return 0; return 0;
@@ -2173,9 +2129,9 @@ int mympd_smartpls_update_all() {
printf("Can't parse file %s\n", filename); printf("Can't parse file %s\n", filename);
} }
else if (strcmp(smartpltype, "newest") == 0) { else if (strcmp(smartpltype, "newest") == 0) {
je = json_scanf(content, strlen(content), "{timerange: %d, maxentries: %d}", &int_buf1, &int_buf2); je = json_scanf(content, strlen(content), "{timerange: %d}", &int_buf1);
if (je == 2) { if (je == 1) {
mympd_smartpls_update_newest(ent->d_name, int_buf1, int_buf2); mympd_smartpls_update_newest(ent->d_name, int_buf1);
} }
else else
printf("Can't parse file %s\n", filename); printf("Can't parse file %s\n", filename);
@@ -2240,23 +2196,18 @@ int mympd_smartpls_update(char *playlist, char *sticker, int maxentries) {
char *name; char *name;
char *p_value; char *p_value;
char *crap; char *crap;
char tmpfile[400];
long value; long value;
long value_max = 0; long value_max = 0;
size_t len = 0;
ssize_t read;
long i = 0; long i = 0;
if (!mpd_send_sticker_find(mpd.conn, "song", "", sticker)) { if (!mpd_send_sticker_find(mpd.conn, "song", "", sticker)) {
LOG_ERROR_AND_RECOVER("mpd_send_sticker_find"); LOG_ERROR_AND_RECOVER("mpd_send_sticker_find");
return 1; return 1;
} }
snprintf(tmpfile, 400, "%s/tmp/playlist.tmp", config.varlibdir);
FILE *fp = fopen(tmpfile, "w"); struct list add_list;
if (fp == NULL) { list_init(&add_list);
printf("Error opening %s", tmpfile);
return 1;
}
while ((pair = mpd_recv_pair(mpd.conn)) != NULL) { while ((pair = mpd_recv_pair(mpd.conn)) != NULL) {
if (strcmp(pair->name, "file") == 0) { if (strcmp(pair->name, "file") == 0) {
uri = strdup(pair->value); uri = strdup(pair->value);
@@ -2265,111 +2216,60 @@ int mympd_smartpls_update(char *playlist, char *sticker, int maxentries) {
name = strtok(strdup(pair->value), "="); name = strtok(strdup(pair->value), "=");
p_value = strtok(NULL, "="); p_value = strtok(NULL, "=");
value = strtol(p_value, &crap, 10); value = strtol(p_value, &crap, 10);
if (value > 1) if (value > 1)
fprintf(fp, "%s::%ld\n", uri, value); list_push(&add_list, uri, value);
if (value > value_max) if (value > value_max)
value_max = value; value_max = value;
} }
mpd_return_pair(mpd.conn, pair); mpd_return_pair(mpd.conn, pair);
} }
mpd_response_finish(mpd.conn); mpd_response_finish(mpd.conn);
fclose(fp); free(uri);
mympd_smartpls_clear(playlist); mympd_smartpls_clear(playlist);
if (value_max > 2) if (value_max > 2)
value_max = value_max / 2; value_max = value_max / 2;
fp = fopen(tmpfile, "r");
if (fp == NULL) { struct node *current = add_list.list;
printf("Error opening %s", tmpfile); while (current != NULL) {
return 1; if (current->value >= value_max) {
} if (!mpd_run_playlist_add(mpd.conn, playlist, current->data)) {
while ((read = getline(&uri, &len, fp)) != -1) { LOG_ERROR_AND_RECOVER("mpd_run_playlist_add");
name = strtok(uri, "::"); list_free(&add_list);
p_value = strtok(NULL, "::"); return 1;
value = strtol(p_value, &crap, 10); }
if (value < value_max) i++;
continue; if (i >= maxentries)
if (!mpd_run_playlist_add(mpd.conn, playlist, name)) { break;
LOG_ERROR_AND_RECOVER("mpd_run_playlist_add");
fclose(fp);
free(uri);
unlink(tmpfile);
return 1;
} }
i++; current = current->next;
if (i >= maxentries)
break;
} }
fclose(fp); list_free(&add_list);
free(uri);
unlink(tmpfile);
printf("Updated %s with %ld songs, minValue: %ld\n", playlist, i, value_max); printf("Updated %s with %ld songs, minValue: %ld\n", playlist, i, value_max);
return 0; return 0;
} }
int mympd_smartpls_update_newest(char *playlist, int timerange, int maxentries) { int mympd_smartpls_update_newest(char *playlist, int timerange) {
struct mpd_song *song; unsigned long value_max = 0;
char *uri; char searchstr[20];
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, "/")) { struct mpd_stats *stats = mpd_run_stats(mpd.conn);
LOG_ERROR_AND_RECOVER("mpd_send_list_all_meta"); if (stats != NULL) {
return 1; value_max = mpd_stats_get_db_update_time(stats);
mpd_stats_free(stats);
} }
snprintf(tmpfile, 400, "%s/tmp/playlist.tmp", config.varlibdir); else {
FILE *fp = fopen(tmpfile, "w"); LOG_ERROR_AND_RECOVER("mpd_run_stats");
if (fp == NULL) {
printf("Error opening %s", tmpfile);
return 1; 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); mympd_smartpls_clear(playlist);
value_max -= timerange; value_max -= timerange;
if (value_max > 0) {
fp = fopen(tmpfile, "r"); snprintf(searchstr, 20, "%lu", value_max);
if (fp == NULL) { mympd_search(mpd.buf, searchstr, "modified-since", playlist, 0);
printf("Error opening %s", tmpfile); printf("Updated %s\n", playlist);
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; return 0;
} }

View File

@@ -26,6 +26,7 @@
#define __MPD_CLIENT_H__ #define __MPD_CLIENT_H__
#include "../dist/src/mongoose/mongoose.h" #include "../dist/src/mongoose/mongoose.h"
#include "list.h"
#define RETURN_ERROR_AND_RECOVER(X) do { \ #define RETURN_ERROR_AND_RECOVER(X) do { \
printf("MPD X: %s\n", mpd_connection_get_error_message(mpd.conn)); \ printf("MPD X: %s\n", mpd_connection_get_error_message(mpd.conn)); \
@@ -137,17 +138,11 @@ struct t_mpd {
const unsigned* protocol; const unsigned* protocol;
// Supported tags // Supported tags
bool feat_sticker; bool feat_sticker;
bool tag_artist;
bool tag_album;
bool tag_album_artist;
bool tag_title;
bool tag_track;
bool tag_genre;
bool tag_date;
bool tag_composer;
bool tag_performer;
} mpd; } mpd;
struct list mpd_tags;
struct list mympd_tags;
typedef struct { typedef struct {
long mpdport; long mpdport;
const char* mpdhost; const char* mpdhost;
@@ -190,6 +185,7 @@ static int is_websocket(const struct mg_connection *nc) {
return nc->flags & MG_F_IS_WEBSOCKET; return nc->flags & MG_F_IS_WEBSOCKET;
} }
int randrange(int n);
void mympd_idle(struct mg_mgr *sm, int timeout); void mympd_idle(struct mg_mgr *sm, int timeout);
void mympd_parse_idle(struct mg_mgr *s, int idle_bitmask); void mympd_parse_idle(struct mg_mgr *s, int idle_bitmask);
void callback_mympd(struct mg_connection *nc, const struct mg_str msg); void callback_mympd(struct mg_connection *nc, const struct mg_str msg);
@@ -208,7 +204,7 @@ int mympd_smartpls_put(char *buffer, char *playlist);
int mympd_smartpls_update_all(); int mympd_smartpls_update_all();
int mympd_smartpls_clear(char *playlist); int mympd_smartpls_clear(char *playlist);
int mympd_smartpls_update(char *sticker, char *playlist, int maxentries); 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_newest(char *playlist, int timerange);
int mympd_smartpls_update_search(char *playlist, char *tag, char *searchstr); 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);

View File

@@ -183,14 +183,18 @@ static int inihandler(void* user, const char* section, const char* name, const c
void read_statefiles() { void read_statefiles() {
char *crap; char *crap;
char value[400]; char value[400];
printf("Reading states\n");
if (mympd_state_get("notificationWeb", value)) { if (mympd_state_get("notificationWeb", value)) {
if (strcmp(value, "true") == 0) if (strcmp(value, "true") == 0)
mympd_state.notificationWeb = true; mympd_state.notificationWeb = true;
else else
mympd_state.notificationWeb = false; mympd_state.notificationWeb = false;
} }
else else {
mympd_state.notificationWeb = false; mympd_state.notificationWeb = false;
mympd_state_set("notificationWeb", "false");
}
if (mympd_state_get("notificationPage", value)) { if (mympd_state_get("notificationPage", value)) {
if (strcmp(value, "true") == 0) if (strcmp(value, "true") == 0)
@@ -198,24 +202,44 @@ void read_statefiles() {
else else
mympd_state.notificationPage = false; mympd_state.notificationPage = false;
} }
else else {
mympd_state.notificationPage = true; mympd_state.notificationPage = true;
mympd_state_set("notificationPage", "true");
}
if (mympd_state_get("jukeboxMode", value)) if (mympd_state_get("jukeboxMode", value))
mympd_state.jukeboxMode = strtol(value, &crap, 10); mympd_state.jukeboxMode = strtol(value, &crap, 10);
else else {
mympd_state.jukeboxMode = 0; mympd_state.jukeboxMode = 0;
mympd_state_set("jukeboxMode", "0");
}
if (mympd_state_get("jukeboxPlaylist", value)) if (mympd_state_get("jukeboxPlaylist", value))
mympd_state.jukeboxPlaylist = strdup(value); mympd_state.jukeboxPlaylist = strdup(value);
else else {
mympd_state.jukeboxPlaylist = "Database"; mympd_state.jukeboxPlaylist = "Database";
mympd_state_set("jukeboxPlaylist", "Database");
}
if (mympd_state_get("jukeboxQueueLength", value)) if (mympd_state_get("jukeboxQueueLength", value))
mympd_state.jukeboxQueueLength = strtol(value, &crap, 10); mympd_state.jukeboxQueueLength = strtol(value, &crap, 10);
else else {
mympd_state.jukeboxQueueLength = 1; mympd_state.jukeboxQueueLength = 1;
mympd_state_set("jukeboxQueueLength", "1");
}
}
bool testdir(char *name, char *dirname) {
DIR* dir = opendir(dirname);
if (dir) {
closedir(dir);
printf("%s: \"%s\"\n", name, dirname);
return true;
}
else {
printf("%s: \"%s\" don't exists\n", name, dirname);
return false;
}
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
@@ -224,6 +248,7 @@ int main(int argc, char **argv) {
struct mg_connection *nc_http; struct mg_connection *nc_http;
struct mg_bind_opts bind_opts; struct mg_bind_opts bind_opts;
const char *err; const char *err;
char testdirname[400];
//defaults //defaults
config.mpdhost = "127.0.0.1"; config.mpdhost = "127.0.0.1";
@@ -268,18 +293,6 @@ int main(int argc, char **argv) {
printf("Starting myMPD %s\n", MYMPD_VERSION); printf("Starting myMPD %s\n", MYMPD_VERSION);
DIR* dir = opendir(SRC_PATH);
if (dir) {
printf("Document root: %s\n", SRC_PATH);
closedir(dir);
}
else {
printf("Document root \"%s\" don't exists\n", SRC_PATH);
return EXIT_FAILURE;
}
read_statefiles();
signal(SIGTERM, signal_handler); signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler); signal(SIGINT, signal_handler);
setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(stdout, NULL, _IOLBF, 0);
@@ -341,6 +354,26 @@ int main(int argc, char **argv) {
mg_mgr_free(&mgr); mg_mgr_free(&mgr);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (!testdir("Document root", SRC_PATH))
return EXIT_FAILURE;
snprintf(testdirname, 400, "%s/tmp", config.varlibdir);
if (!testdir("Temp dir", testdirname))
return EXIT_FAILURE;
snprintf(testdirname, 400, "%s/smartpls", config.varlibdir);
if (!testdir("Smartpls dir", testdirname))
return EXIT_FAILURE;
snprintf(testdirname, 400, "%s/state", config.varlibdir);
if (!testdir("State dir", testdirname))
return EXIT_FAILURE;
read_statefiles();
list_init(&mpd_tags);
list_init(&mympd_tags);
if (config.ssl == true) if (config.ssl == true)
mg_set_protocol_http_websocket(nc_http); mg_set_protocol_http_websocket(nc_http);
@@ -358,6 +391,8 @@ int main(int argc, char **argv) {
mympd_idle(&mgr, 0); mympd_idle(&mgr, 0);
} }
mg_mgr_free(&mgr); mg_mgr_free(&mgr);
list_free(&mpd_tags);
list_free(&mympd_tags);
mympd_disconnect(); mympd_disconnect();
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }