diff --git a/contrib/mympd.conf.dist b/contrib/mympd.conf.dist index c708f37..09e5360 100644 --- a/contrib/mympd.conf.dist +++ b/contrib/mympd.conf.dist @@ -23,8 +23,8 @@ streamport = 8000 #Name for coverimages coverimage = folder.jpg -#myMPD statefile -statefile = /var/lib/mympd/mympd.state +#myMPD state directory +varlibdir = /var/lib/mympd #Enable mixramp settings mixramp = false diff --git a/dist/htdocs/index.html b/dist/htdocs/index.html index f779f5b..b30d4c7 100644 --- a/dist/htdocs/index.html +++ b/dist/htdocs/index.html @@ -1 +1 @@ -myMPD
Playback

Artist

Album

Queue
#TitleArtistAlbumDuration
PlaylistLast modified
Playlist List
#TitleArtistAlbumDuration
Artist

TitleArtistAlbumDuration
Search
TitleArtistAlbumDuration
\ No newline at end of file +myMPD
Playback

Artist

Album

Queue
#TitleArtistAlbumDuration
PlaylistLast modified
Playlist List
#TitleArtistAlbumDuration
Artist

TitleArtistAlbumDuration
Search
TitleArtistAlbumDuration
\ No newline at end of file diff --git a/dist/htdocs/js/mympd.min.js b/dist/htdocs/js/mympd.min.js index cea53af..a562593 100644 --- a/dist/htdocs/js/mympd.min.js +++ b/dist/htdocs/js/mympd.min.js @@ -10,7 +10,8 @@ scrollPos:0},Composer:{state:"0/-/",scrollPos:0},Performer:{state:"0/-/",scrollP domCache.panelHeadingBrowse=document.getElementById("panel-heading-browse").getElementsByTagName("a");domCache.panelHeadingBrowseLen=domCache.panelHeadingBrowse.length;domCache.counter=document.getElementById("counter");domCache.volumePrct=document.getElementById("volumePrct");domCache.volumeControl=document.getElementById("volumeControl");domCache.volumeIcon=document.getElementById("volumeIcon");domCache.btnsPlay=document.getElementsByClassName("btnPlay");domCache.btnsPlayLen=domCache.btnsPlay.length; domCache.btnPrev=document.getElementById("btnPrev");domCache.btnNext=document.getElementById("btnNext");domCache.progressBar=document.getElementById("progressBar");domCache.volumeBar=document.getElementById("volumeBar");domCache.outputs=document.getElementById("outputs");domCache.btnAdd=document.getElementById("nav-add2homescreen");domCache.currentTrack=document.getElementById("currentTrack");domCache.currentArtist=document.getElementById("currentArtist");domCache.currentAlbum=document.getElementById("currentAlbum"); domCache.currentCover=document.getElementById("currentCover");domCache.btnVoteUp=document.getElementById("btnVoteUp");domCache.btnVoteDown=document.getElementById("btnVoteDown"); -var modalConnectionError=new Modal(document.getElementById("modalConnectionError"),{backdrop:"static",keyboard:!1}),modalSettings=new Modal(document.getElementById("modalSettings")),modalSavequeue=new Modal(document.getElementById("modalSaveQueue")),modalSongDetails=new Modal(document.getElementById("modalSongDetails")),modalAddToPlaylist=new Modal(document.getElementById("modalAddToPlaylist")),modalRenamePlaylist=new Modal(document.getElementById("modalRenamePlaylist")),modalUpdateDB=new Modal(document.getElementById("modalUpdateDB")); +var modalConnectionError=new Modal(document.getElementById("modalConnectionError"),{backdrop:"static",keyboard:!1}),modalSettings=new Modal(document.getElementById("modalSettings")),modalSavequeue=new Modal(document.getElementById("modalSaveQueue")),modalSongDetails=new Modal(document.getElementById("modalSongDetails")),modalAddToPlaylist=new Modal(document.getElementById("modalAddToPlaylist")),modalRenamePlaylist=new Modal(document.getElementById("modalRenamePlaylist")),modalUpdateDB=new Modal(document.getElementById("modalUpdateDB")), +modalSaveSmartPlaylist=new Modal(document.getElementById("modalSaveSmartPlaylist")); function appPrepare(a){if(app.current.app!=app.last.app||app.current.tab!=app.last.tab||app.current.view!=app.last.view){for(var b=0;b'+c[a]+"";break}e+=c[a];b+='";e+="/"}a=document.getElementById("BrowseBreadcrumb");a.innerHTML=b;b=a.getElementsByTagName("a");c=b.length;for(a=0;asearchSearching...'),2<=app.current.search.length?sendAPI({cmd:"MPD_API_DATABASE_SEARCH",data:{plist:"",offset:app.current.page,filter:app.current.filter,searchstr:app.current.search}},parseSearch):(document.getElementById("SearchList").getElementsByTagName("tbody")[0].innerHTML="",document.getElementById("searchAddAllSongs").setAttribute("disabled", -"disabled"),document.getElementById("searchAddAllSongsBtn").setAttribute("disabled","disabled"),document.getElementById("panel-heading-search").innerText="",document.getElementById("SearchList").classList.remove("opacity05"),setPagination(0)),selectTag("searchtags","searchtagsdesc",app.current.filter)):appGoto("Playback");app.last.app=app.current.app;app.last.tab=app.current.tab;app.last.view=app.current.view}else appGoto("Playback")} +'";break}e+=c[a];b+='";e+="/"}a=document.getElementById("BrowseBreadcrumb");a.innerHTML=b;b=a.getElementsByTagName("a");c=b.length;for(a=0;asearchSearching...'),2<=app.current.search.length?sendAPI({cmd:"MPD_API_DATABASE_SEARCH",data:{plist:"",offset:app.current.page,filter:app.current.filter,searchstr:app.current.search}},parseSearch):(document.getElementById("SearchList").getElementsByTagName("tbody")[0].innerHTML= +"",document.getElementById("searchAddAllSongs").setAttribute("disabled","disabled"),document.getElementById("searchAddAllSongsBtn").setAttribute("disabled","disabled"),document.getElementById("panel-heading-search").innerText="",document.getElementById("SearchList").classList.remove("opacity05"),setPagination(0)),selectTag("searchtags","searchtagsdesc",app.current.filter)):appGoto("Playback");app.last.app=app.current.app;app.last.tab=app.current.tab;app.last.view=app.current.view}else appGoto("Playback")} function appInit(){getSettings();sendAPI({cmd:"MPD_API_PLAYER_STATE"},parseState);webSocketConnect();domCache.volumeBar.value=0;document.getElementById("btnChVolumeDown").addEventListener("click",function(a){a.stopPropagation()},!1);document.getElementById("btnChVolumeUp").addEventListener("click",function(a){a.stopPropagation()},!1);domCache.volumeBar.addEventListener("click",function(a){a.stopPropagation()},!1);domCache.volumeBar.addEventListener("change",function(a){sendAPI({cmd:"MPD_API_PLAYER_VOLUME", data:{volume:domCache.volumeBar.value}})},!1);domCache.progressBar.value=0;domCache.progressBar.addEventListener("change",function(a){currentSong&&0<=currentSong.currentSongId&&sendAPI({cmd:"MPD_API_PLAYER_SEEK",data:{songid:currentSong.currentSongId,seek:Math.ceil(domCache.progressBar.value/100*currentSong.totalTime)}})},!1);document.getElementById("navDBupdate").addEventListener("click",function(a){a.stopPropagation();a.preventDefault();a=this.getElementsByTagName("span")[0];a.innerText="keyboard_arrow_right"== a.innerText?"keyboard_arrow_down":"keyboard_arrow_right"},!1);document.getElementById("volumeIcon").parentNode.addEventListener("show.bs.dropdown",function(){sendAPI({cmd:"MPD_API_PLAYER_OUTPUT_LIST"},parseOutputs)});document.getElementById("modalAbout").addEventListener("shown.bs.modal",function(){sendAPI({cmd:"MPD_API_DATABASE_STATS"},parseStats)});document.getElementById("modalUpdateDB").addEventListener("hidden.bs.modal",function(){document.getElementById("updateDBprogress").classList.remove("updateDBprogressAnimate")}); @@ -36,28 +37,28 @@ toggleBtn(a.target.id)},!1);document.getElementById("QueueList").addEventListene "/"+decodeURI(a.target.parentNode.getAttribute("data-uri")));break;case "song":appendQueue("song",decodeURI(a.target.parentNode.getAttribute("data-uri")),a.target.parentNode.getAttribute("data-name"));break;case "plist":appendQueue("plist",decodeURI(a.target.parentNode.getAttribute("data-uri")),a.target.parentNode.getAttribute("data-name"))}else"A"==a.target.nodeName&&showMenu(a.target,a)},!1);document.getElementById("BrowsePlaylistsAllList").addEventListener("click",function(a){"TD"==a.target.nodeName? appendQueue("plist",decodeURI(a.target.parentNode.getAttribute("data-uri")),a.target.parentNode.getAttribute("data-name")):"A"==a.target.nodeName&&showMenu(a.target,a)},!1);document.getElementById("BrowsePlaylistsDetailList").addEventListener("click",function(a){"TD"==a.target.nodeName?appendQueue("plist",decodeURI(a.target.parentNode.getAttribute("data-uri")),a.target.parentNode.getAttribute("data-name")):"A"==a.target.nodeName&&showMenu(a.target,a)},!1);document.getElementById("BrowseDatabaseTagList").addEventListener("click", function(a){"TD"==a.target.nodeName&&appGoto("Browse","Database",app.current.view,"0/-/"+a.target.parentNode.getAttribute("data-uri"))},!1);document.getElementById("SearchList").addEventListener("click",function(a){"TD"==a.target.nodeName?appendQueue("song",decodeURI(a.target.parentNode.getAttribute("data-uri")),a.target.parentNode.getAttribute("data-name")):"A"==a.target.nodeName&&showMenu(a.target,a)},!1);document.getElementById("BrowseFilesystemAddAllSongsDropdown").addEventListener("click",function(a){"BUTTON"== -a.target.nodeName&&("Add all to queue"==a.target.innerText?addAllFromBrowse():"Add all to playlist"==a.target.innerText&&showAddToPlaylist(app.current.search))},!1);document.getElementById("searchAddAllSongsDropdown").addEventListener("click",function(a){"BUTTON"==a.target.nodeName&&("Add all to queue"==a.target.innerText?addAllFromSearchPlist("queue"):"Add all to playlist"==a.target.innerText&&showAddToPlaylist("SEARCH"))},!1);document.getElementById("BrowseDatabaseAddAllSongsDropdown").addEventListener("click", -function(a){"BUTTON"==a.target.nodeName&&("Add all to queue"==a.target.innerText?addAllFromBrowseDatabasePlist("queue"):"Add all to playlist"==a.target.innerText&&showAddToPlaylist("DATABASE"))},!1);document.getElementById("searchtags").addEventListener("click",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",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){a=document.getElementsByClassName("popover"); -for(var b=0;b";domCache.outputs.innerHTML=b} function setCounter(a,b,c){currentSong.totalTime=b;currentSong.elapsedTime=c;currentSong.currentSongId=a;var d=Math.floor(b/60),e=b-60*d,f=Math.floor(c/60),g=c-60*f;domCache.progressBar.value=Math.floor(100*c/b);b=f+":"+(10>g?"0":"")+g+" / "+d+":"+(10>e?"0":"")+e;domCache.counter.innerText=b;lastState&&(c=document.getElementById("queueTrackId"+lastState.data.currentSongId))&&(d=c.getElementsByTagName("td"),d[4].innerText=c.getAttribute("data-duration"),d[0].classList.remove("material-icons"),d[0].innerText= c.getAttribute("data-songpos"),c.classList.remove("font-weight-bold"));if(c=document.getElementById("queueTrackId"+a))d=c.getElementsByTagName("td"),d[4].innerText=b,d[0].classList.add("material-icons"),d[0].innerText="play_arrow",c.classList.add("font-weight-bold");progressTimer&&clearTimeout(progressTimer);"play"==playstate&&(progressTimer=setTimeout(function(){currentSong.elapsedTime++;setCounter(currentSong.currentSongId,currentSong.totalTime,currentSong.elapsedTime)},1E3))} @@ -65,21 +66,22 @@ function parseState(a){if(JSON.stringify(a)!==JSON.stringify(lastState)){if(1==a domCache.btnNext.removeAttribute("disabled");0>=a.data.songPos?domCache.btnPrev.setAttribute("disabled","disabled"):domCache.btnPrev.removeAttribute("disabled");if(0==a.data.queueLength)for(b=0;ba.data.volume?"volume_down":"volume_up");domCache.volumeBar.value=a.data.volume;setCounter(a.data.currentSongId,a.data.totalTime,a.data.elapsedTime);sendAPI({cmd:"MPD_API_PLAYER_CURRENT_SONG"},songChange);"-1"==a.data.songPos&&(domCache.currentTrack.innerText="Not playing",domCache.currentAlbum.innerText="",domCache.currentArtist.innerText="",domCache.currentCover.style.backgroundImage= "");lastState=a}}function getQueue(){2<=app.current.search.length?sendAPI({cmd:"MPD_API_QUEUE_SEARCH",data:{filter:app.current.filter,offset:app.current.page,searchstr:app.current.search}},parseQueue):sendAPI({cmd:"MPD_API_QUEUE_LIST",data:{offset:app.current.page}},parseQueue)} -function parseQueue(a){if("Queue"===app.current.app){0g?"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=""+(a.data[e].pos+1)+""+a.data[e].title+""+a.data[e].artist+""+a.data[e].album+""+f+'playlist_add';e=b;e--)d[e].remove();"queuesearch"==a.type&&0==b?c.innerHTML='error_outlineNo results, please refine your search!': +function parseQueue(a){if("Queue"===app.current.app){0g?"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=""+(a.data[e].pos+1)+""+a.data[e].title+""+a.data[e].artist+""+a.data[e].album+""+f+'playlist_add';e=b;e--)d[e].remove();"queuesearch"==a.type&&0==b?c.innerHTML='error_outlineNo results, please refine your search!': "queue"==a.type&&0==b&&(c.innerHTML='error_outlineEmpty queue');setPagination(a.totalEntities);document.getElementById("QueueList").classList.remove("opacity05")}} function parseSearch(a){"Search"===app.current.app&&(document.getElementById("panel-heading-search").innerHTML=a.totalEntities+" Songs found",0playlist_add';break;case "song":f=Math.floor(a.data[e].duration/60);var h=a.data[e].duration-60*f;g.innerHTML='music_note'+a.data[e].title+""+a.data[e].artist+""+a.data[e].album+""+f+":"+(10>h?"0":"")+h+'playlist_add'; -break;case "plist":g.innerHTML='list'+a.data[e].name+'playlist_add'}e=b;e--)d[e].remove();setPagination(a.totalEntities);0==b&&(c.innerHTML='error_outlineNo results');document.getElementById(app.current.app+(void 0==app.current.tab?"": -app.current.tab)+"List").classList.remove("opacity05")}} -function parsePlaylists(a){if("Browse"===app.current.app||"Playlists"===app.current.tab){"All"==app.current.view?(document.getElementById("BrowsePlaylistsAllList").classList.remove("hide"),document.getElementById("BrowsePlaylistsDetailList").classList.add("hide"),document.getElementById("btnBrowsePlaylistsAll").parentNode.classList.add("hide"),document.getElementById("btnPlaylistClear").parentNode.classList.add("hide")):(-1"+g.toUTCString()+'playlist_add';e"+g+""+a.data[e].title+""+a.data[e].artist+""+a.data[e].album+""+f+":"+(10>k?"0":"")+k+'playlist_add'; -e=b;e--)d[e].remove();setPagination(a.totalEntities);0==b&&(c.innerHTML="All"==app.current.view?'error_outlineNo playlists found.':'error_outlineEmpty playlist.');document.getElementById(app.current.app+app.current.tab+app.current.view+"List").classList.remove("opacity05")}} +break;case "smartpls":case "plist":g.innerHTML='list'+a.data[e].name+'playlist_add'}e=b;e--)d[e].remove();setPagination(a.totalEntities);0==b&&(c.innerHTML='error_outlineNo results');document.getElementById(app.current.app+(void 0==app.current.tab? +"":app.current.tab)+"List").classList.remove("opacity05")}} +function parsePlaylists(a){if("Browse"===app.current.app||"Playlists"===app.current.tab){"All"==app.current.view?(document.getElementById("BrowsePlaylistsAllList").classList.remove("hide"),document.getElementById("BrowsePlaylistsDetailList").classList.add("hide"),document.getElementById("btnBrowsePlaylistsAll").parentNode.classList.add("hide"),document.getElementById("btnPlaylistClear").parentNode.classList.add("hide")):(-1list'+a.data[e].name+""+g.toUTCString()+'playlist_add';e"+g+""+ +a.data[e].title+""+a.data[e].artist+""+a.data[e].album+""+f+":"+(10>k?"0":"")+k+'playlist_add';e=b;e--)d[e].remove();setPagination(a.totalEntities);0==b&&(c.innerHTML="All"==app.current.view?'error_outlineNo playlists found.':'error_outlineEmpty playlist.'); +document.getElementById(app.current.app+app.current.tab+app.current.view+"List").classList.remove("opacity05")}} function parseListDBtags(a){if(""!=app.current.search){document.getElementById("BrowseDatabaseAlbumList").classList.remove("hide");document.getElementById("BrowseDatabaseTagList").classList.add("hide");document.getElementById("btnBrowseDatabaseByTag").parentNode.classList.add("hide");document.getElementById("btnBrowseDatabaseTag").parentNode.classList.remove("hide");document.getElementById("BrowseDatabaseAddAllSongs").parentNode.parentNode.classList.remove("hide");document.getElementById("btnBrowseDatabaseTag").innerHTML= "« "+app.current.view;document.getElementById("BrowseDatabaseAlbumListCaption").innerText=a.searchtagtype+": "+a.searchstr;for(var b=a.data.length,c=document.getElementById("BrowseDatabaseAlbumList"),d=c.getElementsByClassName("col-md"),e=0;e

'+a.data[e].value+'

';e=b;e--)d[e].remove();setPagination(a.totalEntities);document.getElementById("BrowseDatabaseAlbumList").classList.remove("opacity05")}else{document.getElementById("BrowseDatabaseAlbumList").classList.add("hide"); @@ -98,28 +100,31 @@ function parseSongDetails(a){var b=document.getElementById("modalSongDetails");b f+""}b.getElementsByTagName("tbody")[0].innerHTML=c}function playlistDetails(a){appGoto("Browse","Playlists","Detail","0/-/"+a)}function removeFromPlaylist(a,b){b--;sendAPI({cmd:"MPD_API_PLAYLIST_RM_TRACK",data:{uri:a,track:b}});document.getElementById("BrowsePlaylistsDetailList").classList.add("opacity05");sendAPI({cmd:"MPD_API_PLAYLIST_CONTENT_LIST",data:{offset:app.current.page,filter:app.current.filter,uri:app.current.search}},parsePlaylists)} 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="":"jukeboxPlaylist"==playlistEl&&(c=""));for(var d=0;d";0==a.offset?document.getElementById(playlistEl).innerHTML=c:document.getElementById(playlistEl).innerHTML+=c;a.totalEntities>a.returnedEntities&& -(a.offset+=settings.maxElementsPerPage,sendAPI({cmd:"MPD_API_PLAYLIST_LIST",data:{offset:a.offset,filter:"-"}},getAllPlaylists))}function updateSmartPlaylists(){sendAPI({cmd:"MPD_API_SMARTPLS_UPDATE"})}function voteSong(a){var b=domCache.currentTrack.getAttribute("data-uri");""!=b&&(2==a&&domCache.btnVoteUp.classList.contains("active-fg-green")?a=1:0==a&&domCache.btnVoteDown.classList.contains("active-fg-red")&&(a=1),sendAPI({cmd:"MPD_API_LIKE",data:{uri:b,like:a}}),setVoteSongBtns(a,b))} +(a.offset+=settings.maxElementsPerPage,sendAPI({cmd:"MPD_API_PLAYLIST_LIST",data:{offset:a.offset,filter:"-"}},getAllPlaylists))}function updateSmartPlaylists(){sendAPI({cmd:"MPD_API_SMARTPLS_UPDATE_ALL"})}function voteSong(a){var b=domCache.currentTrack.getAttribute("data-uri");""!=b&&(2==a&&domCache.btnVoteUp.classList.contains("active-fg-green")?a=1:0==a&&domCache.btnVoteDown.classList.contains("active-fg-red")&&(a=1),sendAPI({cmd:"MPD_API_LIKE",data:{uri:b,like:a}}),setVoteSongBtns(a,b))} function setVoteSongBtns(a,b){""==b||0==b.indexOf("http://")||0==b.indexOf("https://")?(domCache.btnVoteUp.setAttribute("disabled","disabled"),domCache.btnVoteDown.setAttribute("disabled","disabled")):(domCache.btnVoteUp.removeAttribute("disabled"),domCache.btnVoteDown.removeAttribute("disabled"));0==a?(domCache.btnVoteUp.classList.remove("active-fg-green"),domCache.btnVoteDown.classList.add("active-fg-red")):1==a?(domCache.btnVoteUp.classList.remove("active-fg-green"),domCache.btnVoteDown.classList.remove("active-fg-red")): 2==a&&(domCache.btnVoteUp.classList.add("active-fg-green"),domCache.btnVoteDown.classList.remove("active-fg-red"))} function toggleAddToPlaylistFrm(){var a=document.getElementById("toggleAddToPlaylistBtn");toggleBtn("toggleAddToPlaylistBtn");a.classList.contains("active")?(document.getElementById("addToPlaylistFrm").classList.remove("hide"),document.getElementById("addStreamFooter").classList.add("hide"),document.getElementById("addToPlaylistFooter").classList.remove("hide")):(document.getElementById("addToPlaylistFrm").classList.add("hide"),document.getElementById("addStreamFooter").classList.remove("hide"),document.getElementById("addToPlaylistFooter").classList.add("hide"))} +function showSaveSmartPlaylist(){var a=document.getElementById("saveSmartPlaylistName");a.value="";a.classList.remove("is-invalid");document.getElementById("saveSmartPlaylistFrm").classList.remove("was-validated");modalSaveSmartPlaylist.show();a.focus()} +function saveSmartPlaylist(){var a=document.getElementById("saveSmartPlaylistName").value,b=a.replace(/[\w\-]/g,"");""!=a&&""==b?(sendAPI({cmd:"MPD_API_SMARTPLS_SAVE",data:{playlist:a,tag:app.current.filter,searchstr:app.current.search}}),modalSaveSmartPlaylist.hide(),showNotification("Saved smart playlist "+a,"","","success")):(document.getElementById("saveSmartPlaylistName").classList.add("is-invalid"),document.getElementById("saveSmartPlaylistFrm").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"); 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)} -function addToPlaylist(){var a=document.getElementById("addToPlaylistUri").value;if("stream"==a&&(a=document.getElementById("streamUrl").value,""==a||-1==a.indexOf("http"))){document.getElementById("streamUrl").classList.add("is-invalid");document.getElementById("addStreamFrm").classList.add("was-validated");return}var b=document.getElementById("addToPlaylistPlaylist");b=b.options[b.selectedIndex].text;if("New Playlist"==b){b=document.getElementById("addToPlaylistNewPlaylist").value;var c=b.replace(/\w\-/g, +function addToPlaylist(){var a=document.getElementById("addToPlaylistUri").value;if("stream"==a&&(a=document.getElementById("streamUrl").value,""==a||-1==a.indexOf("http"))){document.getElementById("streamUrl").classList.add("is-invalid");document.getElementById("addStreamFrm").classList.add("was-validated");return}var b=document.getElementById("addToPlaylistPlaylist");b=b.options[b.selectedIndex].text;if("New Playlist"==b){b=document.getElementById("addToPlaylistNewPlaylist").value;var c=b.replace(/[\w\-]/g, "");if(""==b||""!=c){document.getElementById("addToPlaylistNewPlaylist").classList.add("is-invalid");document.getElementById("addToPlaylistFrm").classList.add("was-validated");return}}""!=b?("SEARCH"==a?addAllFromSearchPlist(b):"DATABASE"==a?addAllFromBrowseDatabasePlist(b):sendAPI({cmd:"MPD_API_PLAYLIST_ADD_TRACK",data:{uri:a,plist:b}}),modalAddToPlaylist.hide()):(document.getElementById("addToPlaylistPlaylist").classList.add("is-invalid"),document.getElementById("addToPlaylistFrm").classList.add("was-validated"))} function addStream(){var a=document.getElementById("streamUrl").value;""!=a&&0==a.indexOf("http")?(sendAPI({cmd:"MPD_API_QUEUE_ADD_TRACK",data:{uri:a}}),modalAddToPlaylist.hide(),showNotification("Added stream "+a+"to queue","","","success")):(document.getElementById("streamUrl").classList.add("is-invalid"),document.getElementById("addStreamFrm").classList.add("was-validated"))} function showRenamePlaylist(a){document.getElementById("renamePlaylistFrm").classList.remove("was-validated");document.getElementById("renamePlaylistTo").classList.remove("is-invalid");modalRenamePlaylist.show();document.getElementById("renamePlaylistFrom").value=a;document.getElementById("renamePlaylistTo").value=""} -function renamePlaylist(){var a=document.getElementById("renamePlaylistFrom").value,b=document.getElementById("renamePlaylistTo").value,c=b.replace(/\w\-/g,"");""!=b&&b!=a&&""==c?(sendAPI({cmd:"MPD_API_PLAYLIST_RENAME",data:{from:a,to:b}}),modalRenamePlaylist.hide(),sendAPI({cmd:"MPD_API_PLAYLIST_LIST",data:{offset:app.current.page,filter:app.current.filter}},parsePlaylists)):(document.getElementById("renamePlaylistTo").classList.add("is-invalid"),document.getElementById("renamePlaylistFrm").classList.add("was-validated"))} +function renamePlaylist(){var a=document.getElementById("renamePlaylistFrom").value,b=document.getElementById("renamePlaylistTo").value,c=b.replace(/[\w\-]/g,"");""!=b&&b!=a&&""==c?(sendAPI({cmd:"MPD_API_PLAYLIST_RENAME",data:{from:a,to:b}}),modalRenamePlaylist.hide(),sendAPI({cmd:"MPD_API_PLAYLIST_LIST",data:{offset:app.current.page,filter:app.current.filter}},parsePlaylists)):(document.getElementById("renamePlaylistTo").classList.add("is-invalid"),document.getElementById("renamePlaylistFrm").classList.add("was-validated"))} function dirname(a){return a.replace(/\/[^\/]*$/,"")}function b64EncodeUnicode(a){return btoa(encodeURIComponent(a).replace(/%([0-9A-F]{2})/g,function(a,c){return String.fromCharCode("0x"+c)}))}function b64DecodeUnicode(a){return decodeURIComponent(atob(a).split("").map(function(a){return"%"+("00"+a.charCodeAt(0).toString(16)).slice(-2)}).join(""))}function addMenuItem(a,b){return'"+b+""} -function showMenu(a,b){b.preventDefault();b.stopPropagation();b=document.getElementsByClassName("popover");for(var c=0;ckeyboard_arrow_rightAlbum actions
'+addMenuItem({cmd:"appendQueue",options:[b,d,c]},"Append to queue")+addMenuItem({cmd:"appendAfterQueue", -options:[b,d,e,c]},"Add after current playing song")+addMenuItem({cmd:"replaceQueue",options:[b,d,c]},"Replace queue")+addMenuItem({cmd:"showAddToPlaylist",options:[d]},"Add to playlist")+"
")):"Browse"==app.current.app&&"Playlists"==app.current.tab&&"All"==app.current.view?f+=addMenuItem({cmd:"appendQueue",options:[b,d,c]},"Append to queue")+addMenuItem({cmd:"replaceQueue",options:[b,d,c]},"Replace queue")+(0==d.indexOf("myMPDsmart-")?addMenuItem({cmd:"playlistDetails",options:[d]},"View playlist"): -addMenuItem({cmd:"playlistDetails",options:[d]},"Edit playlist"))+addMenuItem({cmd:"showRenamePlaylist",options:[d]},"Rename playlist")+addMenuItem({cmd:"delPlaylist",options:[d]},"Delete playlist"):"Browse"==app.current.app&&"Playlists"==app.current.tab&&"Detail"==app.current.view?(e=document.getElementById("BrowsePlaylistsDetailList"),f+=addMenuItem({cmd:"appendQueue",options:[b,d,c]},"Append to queue")+addMenuItem({cmd:"replaceQueue",options:[b,d,c]},"Replace queue")+("false"==e.getAttribute("data-ro")? -addMenuItem({cmd:"removeFromPlaylist",options:[e.getAttribute("data-uri"),a.parentNode.parentNode.getAttribute("data-songpos")]},"Remove"):"")+("plist"!=b?addMenuItem({cmd:"showAddToPlaylist",options:[d]},"Add to playlist"):"")):"Queue"==app.current.app&&(f+=addMenuItem({cmd:"delQueueSong",options:["single",a.parentNode.parentNode.getAttribute("data-trackid")]},"Remove")+addMenuItem({cmd:"delQueueSong",options:["range",0,a.parentNode.parentNode.getAttribute("data-songpos")]},"Remove all upwards")+ -addMenuItem({cmd:"delQueueSong",options:["range",parseInt(a.parentNode.parentNode.getAttribute("data-songpos"))-1,-1]},"Remove all downwards")+(-1==d.indexOf("http")?addMenuItem({cmd:"songDetails",options:[d]},"Songdetails"):""));new Popover(a,{trigger:"click",delay:0,dismissible:!0,template:'"});var g=a.Popover;a.getAttribute("data-init")||(a.setAttribute("data-init","true"),a.addEventListener("shown.bs.popover", -function(a){document.getElementsByClassName("popover-content")[0].addEventListener("click",function(a){a.preventDefault();a.stopPropagation();if("A"==a.target.nodeName&&(a=a.target.getAttribute("data-href"))){a=JSON.parse(b64DecodeUnicode(a));if("function"===typeof window[a.cmd])switch(a.cmd){case "sendAPI":sendAPI.apply(null,$jscomp.arrayFromIterable(a.options));break;default:window[a.cmd].apply(null,$jscomp.arrayFromIterable(a.options))}g.hide()}},!1);if(a=document.getElementById("advancedMenuLink"))a.addEventListener("click", -function(a){a=this.getElementsByTagName("span")[0];a.innerText="keyboard_arrow_right"==a.innerText?"keyboard_arrow_down":"keyboard_arrow_right"},!1),new Collapse(a)},!1));g.show()} +function hideMenu(){var a=document.querySelector("[data-popover]");a&&(new Popover(a,{}),a.Popover.hide(),a.removeAttribute("data-popover"))} +function showMenu(a,b){b.preventDefault();b.stopPropagation();if(!a.getAttribute("data-init")){hideMenu();b=a.getAttribute("data-type");var c=decodeURI(a.getAttribute("data-uri")),d=a.getAttribute("data-name"),e=0;if(null==b||null==c)b=a.parentNode.parentNode.getAttribute("data-type"),c=decodeURI(a.parentNode.parentNode.getAttribute("data-uri")),d=a.parentNode.parentNode.getAttribute("data-name");lastState&&(e=lastState.data.nextSongPos);var f="";"Browse"==app.current.app&&"Filesystem"==app.current.tab|| +"Search"==app.current.app||"Browse"==app.current.app&&"Database"==app.current.tab?(f+=addMenuItem({cmd:"appendQueue",options:[b,c,d]},"Append to queue")+("song"==b?addMenuItem({cmd:"appendAfterQueue",options:[b,c,e,d]},"Add after current playing song"):"")+addMenuItem({cmd:"replaceQueue",options:[b,c,d]},"Replace queue")+("plist"!=b?addMenuItem({cmd:"showAddToPlaylist",options:[c]},"Add to playlist"):"")+("song"==b?addMenuItem({cmd:"songDetails",options:[c]},"Songdetails"):"")+("plist"==b?addMenuItem({cmd:"playlistDetails", +options:[c]},"Show playlist"):""),"Search"==app.current.app&&(c=dirname(c),f+='keyboard_arrow_rightAlbum actions
'+addMenuItem({cmd:"appendQueue",options:[b,c,d]},"Append to queue")+addMenuItem({cmd:"appendAfterQueue",options:[b,c,e,d]},"Add after current playing song")+ +addMenuItem({cmd:"replaceQueue",options:[b,c,d]},"Replace queue")+addMenuItem({cmd:"showAddToPlaylist",options:[c]},"Add to playlist")+"
")):"Browse"==app.current.app&&"Playlists"==app.current.tab&&"All"==app.current.view?f+=addMenuItem({cmd:"appendQueue",options:[b,c,d]},"Append to queue")+addMenuItem({cmd:"replaceQueue",options:[b,c,d]},"Replace queue")+("smartpls"==b?addMenuItem({cmd:"playlistDetails",options:[c]},"View playlist"):addMenuItem({cmd:"playlistDetails",options:[c]},"Edit playlist"))+ +(0!=c.indexOf("myMPDsmart")?addMenuItem({cmd:"showRenamePlaylist",options:[c]},"Rename playlist")+addMenuItem({cmd:"delPlaylist",options:[c]},"Delete playlist"):""):"Browse"==app.current.app&&"Playlists"==app.current.tab&&"Detail"==app.current.view?(e=document.getElementById("BrowsePlaylistsDetailList"),f+=addMenuItem({cmd:"appendQueue",options:[b,c,d]},"Append to queue")+addMenuItem({cmd:"replaceQueue",options:[b,c,d]},"Replace queue")+("false"==e.getAttribute("data-ro")?addMenuItem({cmd:"removeFromPlaylist", +options:[e.getAttribute("data-uri"),a.parentNode.parentNode.getAttribute("data-songpos")]},"Remove"):"")+addMenuItem({cmd:"showAddToPlaylist",options:[c]},"Add to playlist")):"Queue"==app.current.app&&(f+=addMenuItem({cmd:"delQueueSong",options:["single",a.parentNode.parentNode.getAttribute("data-trackid")]},"Remove")+addMenuItem({cmd:"delQueueSong",options:["range",0,a.parentNode.parentNode.getAttribute("data-songpos")]},"Remove all upwards")+addMenuItem({cmd:"delQueueSong",options:["range",parseInt(a.parentNode.parentNode.getAttribute("data-songpos"))- +1,-1]},"Remove all downwards")+(-1==c.indexOf("http")?addMenuItem({cmd:"songDetails",options:[c]},"Songdetails"):""));new Popover(a,{trigger:"click",delay:0,dismissible:!0,template:'"});b=a.Popover;a.setAttribute("data-init","true");a.addEventListener("shown.bs.popover",function(a){a.target.setAttribute("data-popover","true");document.getElementsByClassName("popover-content")[0].addEventListener("click", +function(a){a.preventDefault();a.stopPropagation();if("A"==a.target.nodeName&&(a=a.target.getAttribute("data-href"))){a=JSON.parse(b64DecodeUnicode(a));if("function"===typeof window[a.cmd])switch(a.cmd){case "sendAPI":sendAPI.apply(null,$jscomp.arrayFromIterable(a.options));break;default:window[a.cmd].apply(null,$jscomp.arrayFromIterable(a.options))}hideMenu()}},!1);if(a=document.getElementById("advancedMenuLink"))a.addEventListener("click",function(a){a=this.getElementsByTagName("span")[0];a.innerText= +"keyboard_arrow_right"==a.innerText?"keyboard_arrow_down":"keyboard_arrow_right"},!1),new Collapse(a)},!1);b.show()}} function sendAPI(a,b){var c=new XMLHttpRequest;c.open("POST","/api",!0);c.setRequestHeader("Content-type","application/json");c.onreadystatechange=function(){if(4==c.readyState)if(""!=c.responseText){var d=JSON.parse(c.responseText);"error"==d.type?(showNotification("Error",d.data,d.data,"danger"),console.log("Error: "+d.data)):"result"==d.type&&"ok"!=d.data?showNotification(d.data,"","","success"):void 0!=b&&"function"==typeof b&&b(d)}else console.log("Empty response for request: "+JSON.stringify(a))}; c.send(JSON.stringify(a))}function openLocalPlayer(){window.open("/player.html#"+settings.mpdstream,"LocalPlayer")}function updateDB(){sendAPI({cmd:"MPD_API_DATABASE_UPDATE"});updateDBstarted(!0)}function rescanDB(){sendAPI({cmd:"MPD_API_DATABASE_RESCAN"});updateDBstarted(!0)} function updateDBstarted(a){1==a?(document.getElementById("updateDBfinished").innerText="",document.getElementById("updateDBfooter").classList.add("hide"),updateDBprogress.style.width="20px",updateDBprogress.style.marginLeft="-20px",modalUpdateDB.show(),document.getElementById("updateDBprogress").classList.add("updateDBprogressAnimate")):showNotification("Database update started","","","success")} @@ -133,7 +138,7 @@ crossfade:document.getElementById("inputCrossfade").value,mixrampdb:1==settings. function addAllFromSearchPlist(a){2<=app.current.search.length&&(sendAPI({cmd:"MPD_API_DATABASE_SEARCH",data:{plist:a,filter:app.current.filter,searchstr:app.current.search,offset:0}}),showNotification("Added "+parseInt(document.getElementById("panel-heading-search").innerText)+" songs from search to "+a,"","","success"))} function addAllFromBrowseDatabasePlist(a){2<=app.current.search.length&&(sendAPI({cmd:"MPD_API_DATABASE_SEARCH",data:{plist:a,filter:app.current.view,searchstr:app.current.search,offset:0}}),showNotification("Added songs from database selection to "+a,"","","success"))}function scrollTo(a){document.body.scrollTop=a;document.documentElement.scrollTop=a} function gotoPage(a){switch(a){case "next":app.current.page+=settings.maxElementsPerPage;break;case "prev":app.current.page-=settings.maxElementsPerPage;0>app.current.page&&(app.current.page=0);break;default:app.current.page=a}appGoto(app.current.app,app.current.tab,app.current.view,app.current.page+"/"+app.current.filter+"/"+app.current.search)} -function saveQueue(){var a=document.getElementById("saveQueueName").value,b=a.replace(/\w\-/g,"");""!=a&&""==b?(sendAPI({cmd:"MPD_API_QUEUE_SAVE",data:{plist:a}}),modalSavequeue.hide()):(document.getElementById("saveQueueName").classList.add("is-invalid"),document.getElementById("saveQueueFrm").classList.add("was-validated"))} +function saveQueue(){var a=document.getElementById("saveQueueName").value,b=a.replace(/[\w\-]/g,"");""!=a&&""==b?(sendAPI({cmd:"MPD_API_QUEUE_SAVE",data:{plist:a}}),modalSavequeue.hide()):(alert(b),document.getElementById("saveQueueName").classList.add("is-invalid"),document.getElementById("saveQueueFrm").classList.add("was-validated"))} function showNotification(a,b,c,d){1==settings.notificationWeb&&(b=new Notification(a,{icon:"assets/favicon.ico",body:b}),setTimeout(function(a){a.close()},3E3,b));1==settings.notificationPage&&(document.getElementById("alertBox")?b=document.getElementById("alertBox"):(b=document.createElement("div"),b.setAttribute("id","alertBox"),b.addEventListener("click",function(){hideNotification()},!1)),b.classList.remove("alert-success","alert-danger"),b.classList.add("alert","alert-"+d),b.innerHTML="
"+ a+"
"+c+"
",document.getElementsByTagName("main")[0].append(b),document.getElementById("alertBox").classList.add("alertBoxActive"),alertTimeout&&clearTimeout(alertTimeout),alertTimeout=setTimeout(function(){hideNotification()},3E3))}function hideNotification(){document.getElementById("alertBox")&&(document.getElementById("alertBox").classList.remove("alertBoxActive"),setTimeout(function(){var a=document.getElementById("alertBox");a&&a.remove()},600))} function notificationsSupported(){return"Notification"in window} diff --git a/htdocs/index.html b/htdocs/index.html index 4210dd9..f608b53 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -467,7 +467,7 @@ @@ -542,8 +542,7 @@ @@ -659,7 +658,7 @@
- +
Invalid filename.
diff --git a/htdocs/js/mympd.js b/htdocs/js/mympd.js index f2a2d47..3b5743b 100644 --- a/htdocs/js/mympd.js +++ b/htdocs/js/mympd.js @@ -540,9 +540,10 @@ function appInit() { }, false); document.getElementsByTagName('body')[0].addEventListener('click', function(event) { - var oldPopover = document.getElementsByClassName('popover'); - for (var i = 0; i < oldPopover.length; i++) - oldPopover[i].remove(); +// var oldPopover = document.getElementsByClassName('popover'); +// for (var i = 0; i < oldPopover.length; i++) +// oldPopover[i].remove(); + hideMenu(); }, false); dragAndDropTable('QueueList'); @@ -861,6 +862,13 @@ function parseSettings(obj) { for (var i = 0; i < stickerElsLen; i++) { stickerEls[i].style.display = displayStickers; } + + var smartplsEls = document.getElementsByClassName('smartpls'); + var smartplsElsLen = smartplsEls.length; + var displaySmartpls = obj.data.smartpls == true ? '' : 'none'; + for (var i = 0; i < smartplsElsLen; i++) { + smartplsEls[i].style.display = displaySmartpls; + } if (obj.data.mixramp == true) { document.getElementsByClassName('mixramp')[0].style.display = ''; @@ -1028,9 +1036,9 @@ function parseQueue(obj) { return; if (typeof(obj.totalTime) != undefined && obj.totalTime > 0 && obj.totalEntities <= settings.maxElementsPerPage ) - document.getElementById('panel-heading-queue').innerText = obj.totalEntities + ' Songs – ' + beautifyDuration(obj.totalTime); + document.getElementById('panel-heading-queue').innerText = obj.totalEntities + ' ' + (obj.totalEntities > 1 ? 'Songs' : 'Song') + ' – ' + beautifyDuration(obj.totalTime); else if (obj.totalEntities > 0) - document.getElementById('panel-heading-queue').innerText = obj.totalEntities + ' Songs'; + document.getElementById('panel-heading-queue').innerText = obj.totalEntities + ' ' + (obj.totalEntities > 1 ? 'Songs' : 'Song'); else document.getElementById('panel-heading-queue').innerText = ''; @@ -1128,6 +1136,7 @@ function parseFilesystem(obj) { '' + minutes + ':' + (seconds < 10 ? '0' : '') + seconds + 'playlist_add'; break; + case 'smartpls': case 'plist': row.innerHTML = 'list' + '' + obj.data[i].name + '' + @@ -1161,7 +1170,7 @@ function parsePlaylists(obj) { document.getElementById('btnBrowsePlaylistsAll').parentNode.classList.add('hide'); document.getElementById('btnPlaylistClear').parentNode.classList.add('hide'); } else { - if (obj.uri.indexOf('.') > -1 || obj.uri.indexOf('myMPDsmart-') == 0) { + if (obj.uri.indexOf('.') > -1 || obj.smartpls == true) { document.getElementById('BrowsePlaylistsDetailList').setAttribute('data-ro', 'true') document.getElementById('btnPlaylistClear').parentNode.classList.add('hide'); } @@ -1170,7 +1179,10 @@ function parsePlaylists(obj) { document.getElementById('btnPlaylistClear').parentNode.classList.remove('hide'); } document.getElementById('BrowsePlaylistsDetailList').setAttribute('data-uri', obj.uri); - document.getElementById('BrowsePlaylistsDetailList').getElementsByTagName('caption')[0].innerText = 'Playlist: ' + obj.uri; + if (obj.smartpls == true) + document.getElementById('BrowsePlaylistsDetailList').getElementsByTagName('caption')[0].innerText = 'Smart playlist: ' + obj.uri; + else + document.getElementById('BrowsePlaylistsDetailList').getElementsByTagName('caption')[0].innerText = 'Playlist: ' + obj.uri; document.getElementById('BrowsePlaylistsDetailList').classList.remove('hide'); document.getElementById('BrowsePlaylistsAllList').classList.add('hide'); document.getElementById('btnBrowsePlaylistsAll').parentNode.classList.remove('hide'); @@ -1188,7 +1200,7 @@ function parsePlaylists(obj) { var d = new Date(obj.data[i].last_modified * 1000); var row = document.createElement('tr'); row.setAttribute('data-uri', uri); - row.setAttribute('data-type', 'plist'); + row.setAttribute('data-type', obj.data[i].type); row.setAttribute('data-name', obj.data[i].name); row.innerHTML = 'list' + '' + obj.data[i].name + '' + @@ -1208,7 +1220,8 @@ function parsePlaylists(obj) { if (tr[i].getAttribute('data-uri') == uri && tr[i].getAttribute('id') == 'playlistTrackId' + songpos) continue; var row = document.createElement('tr'); - row.setAttribute('draggable','true'); + if (obj.smartpls == false) + row.setAttribute('draggable','true'); row.setAttribute('id','playlistTrackId' + songpos); row.setAttribute('data-type', obj.data[i].type); row.setAttribute('data-uri', uri); @@ -1551,7 +1564,7 @@ function getAllPlaylists(obj) { } function updateSmartPlaylists() { - sendAPI({"cmd": "MPD_API_SMARTPLS_UPDATE"}); + sendAPI({"cmd": "MPD_API_SMARTPLS_UPDATE_ALL"}); } function voteSong(vote) { @@ -1605,7 +1618,7 @@ function toggleAddToPlaylistFrm() { function showSaveSmartPlaylist() { var nameEl = document.getElementById('saveSmartPlaylistName'); - nameEl.value = 'myMPDsmart-'; + nameEl.value = ''; nameEl.classList.remove('is-invalid'); document.getElementById('saveSmartPlaylistFrm').classList.remove('was-validated'); modalSaveSmartPlaylist.show(); @@ -1752,13 +1765,23 @@ function addMenuItem(href, text) { return '' + text +''; } +function hideMenu() { + var menuEl = document.querySelector('[data-popover]'); + if (menuEl) { + new Popover(menuEl, { }); + menuEl.Popover.hide(); + menuEl.removeAttribute('data-popover'); + } +} + function showMenu(el, event) { event.preventDefault(); event.stopPropagation(); - var oldPopover = document.getElementsByClassName('popover'); - for (var i = 0; i < oldPopover.length; i++) - oldPopover[i].remove(); + if (el.getAttribute('data-init')) + return; + + hideMenu(); var type = el.getAttribute('data-type'); var uri = decodeURI(el.getAttribute('data-uri')); @@ -1797,9 +1820,10 @@ function showMenu(el, event) { else if (app.current.app == 'Browse' && app.current.tab == 'Playlists' && app.current.view == 'All') { menu += addMenuItem({"cmd": "appendQueue", "options": [type, uri, name]}, 'Append to queue') + addMenuItem({"cmd": "replaceQueue", "options": [type, uri, name]},'Replace queue') + - (uri.indexOf('myMPDsmart-') == 0 ? addMenuItem({"cmd": "playlistDetails", "options": [uri]}, 'View playlist') : addMenuItem({"cmd": "playlistDetails", "options": [uri]}, 'Edit playlist'))+ - addMenuItem({"cmd": "showRenamePlaylist", "options": [uri]}, 'Rename playlist') + - addMenuItem({"cmd": "delPlaylist", "options": [uri]}, 'Delete playlist'); + (type == 'smartpls' ? addMenuItem({"cmd": "playlistDetails", "options": [uri]}, 'View playlist') : addMenuItem({"cmd": "playlistDetails", "options": [uri]}, 'Edit playlist'))+ + (uri.indexOf('myMPDsmart') != 0 ? + addMenuItem({"cmd": "showRenamePlaylist", "options": [uri]}, 'Rename playlist') + + addMenuItem({"cmd": "delPlaylist", "options": [uri]}, 'Delete playlist') : ''); } else if (app.current.app == 'Browse' && app.current.tab == 'Playlists' && app.current.view == 'Detail') { var x = document.getElementById('BrowsePlaylistsDetailList'); @@ -1807,7 +1831,7 @@ function showMenu(el, event) { addMenuItem({"cmd": "replaceQueue", "options": [type, uri, name]}, 'Replace queue') + (x.getAttribute('data-ro') == 'false' ? addMenuItem({"cmd": "removeFromPlaylist", "options": [x.getAttribute('data-uri'), el.parentNode.parentNode.getAttribute('data-songpos')]}, 'Remove') : '') + - (type != 'plist' ? addMenuItem({"cmd": "showAddToPlaylist", "options": [uri]}, 'Add to playlist') : ''); + addMenuItem({"cmd": "showAddToPlaylist", "options": [uri]}, 'Add to playlist'); } else if (app.current.app == 'Queue') { menu += addMenuItem({"cmd": "delQueueSong", "options": ["single", el.parentNode.parentNode.getAttribute('data-trackid')]}, 'Remove') + @@ -1815,20 +1839,15 @@ function showMenu(el, event) { addMenuItem({"cmd": "delQueueSong", "options": ["range", (parseInt(el.parentNode.parentNode.getAttribute('data-songpos'))-1), -1]}, 'Remove all downwards') + (uri.indexOf('http') == -1 ? addMenuItem({"cmd": "songDetails", "options": [uri]}, 'Songdetails') : ''); } - + new Popover(el, { trigger: 'click', delay: 0, dismissible: true, template: ''}); var popoverInit = el.Popover; - - if (el.getAttribute('data-init')) { - popoverInit.show(); - return; - } - el.setAttribute('data-init', 'true'); el.addEventListener('shown.bs.popover', function(event) { + event.target.setAttribute('data-popover', 'true'); document.getElementsByClassName('popover-content')[0].addEventListener('click', function(event) { event.preventDefault(); event.stopPropagation(); @@ -1845,7 +1864,7 @@ function showMenu(el, event) { window[cmd.cmd](... cmd.options); } } - popoverInit.hide(); + hideMenu(); } } }, false); diff --git a/src/mpd_client.c b/src/mpd_client.c index c69077b..cbf5bc9 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -118,14 +118,16 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) { &mympd_state.jukeboxMode, &mympd_state.jukeboxPlaylist); if (je == 4) { - char tmp_file[200]; - snprintf(tmp_file, 200, "%s.tmp", config.statefile); - json_fprintf(tmp_file, "{notificationWeb: %B, notificationPage: %B, jukeboxMode: %B, jukeboxPlaylist: %Q}", + char tmpfile[400]; + char statefile[400]; + snprintf(tmpfile, 400, "%s/tmp/mympd.state", config.varlibdir ); + snprintf(statefile, 400, "%s/mympd.state", config.varlibdir ); + json_fprintf(tmpfile, "{notificationWeb: %B, notificationPage: %B, jukeboxMode: %B, jukeboxPlaylist: %Q}", mympd_state.notificationWeb, mympd_state.notificationPage, mympd_state.jukeboxMode, mympd_state.jukeboxPlaylist); - rename(tmp_file, config.statefile); + rename(tmpfile, statefile); if (mympd_state.jukeboxMode == true) mympd_jukebox(); } @@ -184,7 +186,7 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) { if (uint_rc > 0) n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); break; - case MPD_API_SMARTPLS_UPDATE: + case MPD_API_SMARTPLS_UPDATE_ALL: uint_rc = mympd_smartpls_update_all(); if (uint_rc == 0) n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Smart Playlists updated\"}"); @@ -201,14 +203,6 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) { n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); } break; - case MPD_API_SMARTPLS_RM: - je = json_scanf(msg.p, msg.len, "{data: {playlist: %Q}}", &p_charbuf1); - if (je == 3) { - mympd_smartpls_rm(p_charbuf1); - free(p_charbuf1); - n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); - } - break; case MPD_API_PLAYER_PAUSE: mpd_run_toggle_pause(mpd.conn); n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); @@ -355,8 +349,24 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) { case MPD_API_PLAYLIST_RENAME: je = json_scanf(msg.p, msg.len, "{data: {from: %Q, to: %Q}}", &p_charbuf1, &p_charbuf2); if (je == 2) { - mpd_run_rename(mpd.conn, p_charbuf1, p_charbuf2); - n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Renamed playlist %s to %s\"}", p_charbuf1, p_charbuf2); + //rename smart playlist + char old_pl_file[400]; + char new_pl_file[400]; + snprintf(old_pl_file, 400, "%s/smartpls/%s", config.varlibdir, p_charbuf1); + snprintf(new_pl_file, 400, "%s/smartpls/%s", config.varlibdir, p_charbuf2); + if (access(old_pl_file, F_OK ) != -1) { + if (access(new_pl_file, F_OK ) == -1) { + rename(old_pl_file, new_pl_file); + //rename mpd playlist + mpd_run_rename(mpd.conn, p_charbuf1, p_charbuf2); + n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Renamed playlist %s to %s\"}", p_charbuf1, p_charbuf2); + } else + n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Renamed playlist %s already exists\"}", p_charbuf2); + } + else { + mpd_run_rename(mpd.conn, p_charbuf1, p_charbuf2); + n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Renamed playlist %s to %s\"}", p_charbuf1, p_charbuf2); + } free(p_charbuf1); free(p_charbuf2); } @@ -504,6 +514,12 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) { case MPD_API_PLAYLIST_RM: je = json_scanf(msg.p, msg.len, "{data: {uri:%Q}}", &p_charbuf1); if (je == 1) { + //remove smart playlist + char pl_file[400]; + snprintf(pl_file, 400, "%s/smartpls/%s", config.varlibdir, p_charbuf1); + if (access(pl_file, F_OK ) != -1 ) + unlink(pl_file); + //remove mpd playlist mpd_run_rm(mpd.conn, p_charbuf1); free(p_charbuf1); n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); @@ -1121,7 +1137,7 @@ int mympd_put_settings(char *buffer) { len = json_printf(&out, "{type: settings, data: {" "repeat: %d, single: %d, crossfade: %d, consume: %d, random: %d, " "mixrampdb: %f, mixrampdelay: %f, mpdhost: %Q, mpdport: %d, passwort_set: %B, " - "streamport: %d, coverimage: %Q, stickers: %B, mixramp: %B, maxElementsPerPage: %d, " + "streamport: %d, coverimage: %Q, stickers: %B, mixramp: %B, smartpls: %B, maxElementsPerPage: %d, " "replaygain: %Q, notificationWeb: %B, notificationPage: %B, jukeboxMode: %B, jukeboxPlaylist: %Q, " "tags: { Artist: %B, Album: %B, AlbumArtist: %B, Title: %B, Track: %B, Genre: %B, Date: %B," "Composer: %B, Performer: %B }" @@ -1140,6 +1156,7 @@ int mympd_put_settings(char *buffer) { config.coverimage, config.stickers, config.mixramp, + config.smartpls, MAX_ELEMENTS_PER_PAGE, replaygain, mympd_state.notificationWeb, @@ -1218,7 +1235,7 @@ int mympd_get_cover(const char *uri, char *cover, int cover_len) { replacechar(path, '/', '_'); replacechar(path, '.', '_'); snprintf(cover, cover_len, "%s/pics/%s.png", SRC_PATH, path); - if ( access(cover, F_OK ) == -1 ) { + if (access(cover, F_OK ) == -1 ) { len = snprintf(cover, cover_len, "/assets/coverimage-httpstream.png"); } else { len = snprintf(cover, cover_len, "/pics/%s.png", path); @@ -1230,7 +1247,7 @@ int mympd_get_cover(const char *uri, char *cover, int cover_len) { else { dirname(path); snprintf(cover, cover_len, "%s/library/%s/%s", SRC_PATH, path, config.coverimage); - if ( access(cover, F_OK ) == -1 ) { + if (access(cover, F_OK ) == -1 ) { len = snprintf(cover, cover_len, "/assets/coverimage-notavailable.png"); } else { len = snprintf(cover, cover_len, "/library/%s/%s", path, config.coverimage); @@ -1401,6 +1418,8 @@ int mympd_put_browse(char *buffer, char *path, unsigned int offset, char *filter unsigned int entity_count = 0; unsigned int entities_returned = 0; const char *entityName; + char smartpls_file[400]; + bool smartpls; int len; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); @@ -1477,7 +1496,13 @@ int mympd_put_browse(char *buffer, char *path, unsigned int offset, char *filter ) { if (entities_returned ++) len += json_printf(&out, ","); - len += json_printf(&out, "{type: plist, uri: %Q, name: %Q}", + snprintf(smartpls_file, 400, "%s/smartpls/%s", config.varlibdir, plName); + if (access(smartpls_file, F_OK ) != -1) + smartpls = true; + else + smartpls = false; + len += json_printf(&out, "{type: %Q, uri: %Q, name: %Q}", + (smartpls == true ? "smartpls" : "plist"), entityName, plName ); @@ -1630,6 +1655,8 @@ int mympd_put_playlists(char *buffer, unsigned int offset, char *filter) { unsigned int entities_returned = 0; const char *plpath; int len; + bool smartpls; + char smartpls_file[400]; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); if (!mpd_send_list_playlists(mpd.conn)) @@ -1646,7 +1673,13 @@ int mympd_put_playlists(char *buffer, unsigned int offset, char *filter) { ) { if (entities_returned ++) len += json_printf(&out, ", "); - len += json_printf(&out, "{type: plist, uri: %Q, name: %Q, last_modified: %d}", + snprintf(smartpls_file, 400, "%s/smartpls/%s", config.varlibdir, plpath); + if (access(smartpls_file, F_OK ) != -1) + smartpls = true; + else + smartpls = false; + len += json_printf(&out, "{type: %Q, uri: %Q, name: %Q, last_modified: %d}", + (smartpls == true ? "smartpls" : "plist"), plpath, plpath, mpd_playlist_get_last_modified(pl) @@ -1677,6 +1710,8 @@ int mympd_put_playlist_list(char *buffer, char *uri, unsigned int offset, char * unsigned int entity_count = 0; unsigned int entities_returned = 0; const char *entityName; + char smartpls_file[400]; + bool smartpls; int len; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); @@ -1710,13 +1745,18 @@ int mympd_put_playlist_list(char *buffer, char *uri, unsigned int offset, char * } mpd_entity_free(entity); } - - len += json_printf(&out, "], totalEntities: %d, offset: %d, returnedEntities: %d, filter: %Q, uri: %Q}", + snprintf(smartpls_file, 400, "%s/smartpls/%s", config.varlibdir, uri); + if (access(smartpls_file, F_OK ) != -1) + smartpls = true; + else + smartpls = false; + len += json_printf(&out, "], totalEntities: %d, offset: %d, returnedEntities: %d, filter: %Q, uri: %Q, smartpls: %B}", entity_count, offset, entities_returned, filter, - uri + uri, + smartpls ); if (len > MAX_SIZE) @@ -1903,27 +1943,20 @@ void mympd_disconnect() { int mympd_smartpls_save(char *playlist, char *tag, char *searchstr) { char tmp_file[400]; char pl_file[400]; - snprintf(tmp_file, 400, "/var/lib/mympd/tmp/%s", playlist); - snprintf(pl_file, 400, "/var/lib/mympd/smartpls/%s", playlist); + snprintf(tmp_file, 400, "%s/tmp/%s", config.varlibdir, playlist); + snprintf(pl_file, 400, "%s/smartpls/%s", config.varlibdir, playlist); json_fprintf(tmp_file, "{type: search, tag: %Q, searchstr: %Q}", tag, searchstr); rename(tmp_file, pl_file); mympd_smartpls_update_search(playlist, tag, searchstr); return 0; } -int mympd_smartpls_rm(char *playlist) { - char pl_file[400]; - snprintf(pl_file, 400, "/var/lib/mympd/smartpls/%s", playlist); - unlink(pl_file); - mpd_run_rm(mpd.conn, playlist); - return 0; -} - int mympd_smartpls_update_all() { DIR *dir; struct dirent *ent; char *smartpltype; char filename[400]; + char dirname[400]; int je; char *p_charbuf1, *p_charbuf2; int int_buf1, int_buf2; @@ -1931,11 +1964,12 @@ int mympd_smartpls_update_all() { if (!config.smartpls) return 0; - if ((dir = opendir ("/var/lib/mympd/smartpls")) != NULL) { + snprintf(dirname, 400, "%s/smartpls", config.varlibdir); + if ((dir = opendir (dirname)) != NULL) { while ((ent = readdir(dir)) != NULL) { if (strncmp(ent->d_name, ".", 1) == 0) continue; - snprintf(filename, 400, "/var/lib/mympd/smartpls/%s", ent->d_name); + snprintf(filename, 400, "%s/smartpls/%s", config.varlibdir, ent->d_name); char *content = json_fread(filename); je = json_scanf(content, strlen(content), "{type: %Q }", &smartpltype); if (je != 1) @@ -1971,7 +2005,7 @@ int mympd_smartpls_update_all() { } closedir (dir); } else { - printf("Can't open dir /var/lib/mympd/smartpls\n"); + printf("Can't open dir %s\n", dirname); return 1; } return 0; @@ -2017,6 +2051,7 @@ int mympd_smartpls_update(char *sticker, char *playlist, int maxentries) { char *name; char *p_value; char *crap; + char tmpfile[400]; long value; long value_max = 0; size_t len = 0; @@ -2027,9 +2062,10 @@ int mympd_smartpls_update(char *sticker, char *playlist, int maxentries) { LOG_ERROR_AND_RECOVER("mpd_send_sticker_find"); return 1; } - FILE *fp = fopen("/var/lib/mympd/tmp/playlist.tmp", "w"); + snprintf(tmpfile, 400, "%s/tmp/playlist.tmp", config.varlibdir); + FILE *fp = fopen(tmpfile, "w"); if (fp == NULL) { - printf("Error opening /var/lib/mympd/tmp/playlist.tmp"); + printf("Error opening %s", tmpfile); return 1; } while ((pair = mpd_recv_pair(mpd.conn)) != NULL) { @@ -2054,9 +2090,9 @@ int mympd_smartpls_update(char *sticker, char *playlist, int maxentries) { if (value_max > 2) value_max = value_max / 2; - fp = fopen("/var/lib/mympd/tmp/playlist.tmp", "r"); + fp = fopen(tmpfile, "r"); if (fp == NULL) { - printf("Error opening /var/lib/mympd/tmp/playlist.tmp"); + printf("Error opening %s", tmpfile); return 1; } while ((read = getline(&uri, &len, fp)) != -1) { @@ -2077,7 +2113,7 @@ int mympd_smartpls_update(char *sticker, char *playlist, int maxentries) { } fclose(fp); free(uri); - unlink("/var/lib/mympd/tmp/playlist.tmp"); + unlink(tmpfile); printf("Updated %s with %ld songs, minValue: %ld\n", playlist, i, value_max); return 0; } @@ -2088,6 +2124,7 @@ int mympd_smartpls_update_newest(char *playlist, int timerange, int maxentries) char *p_value; char *name; char *crap; + char tmpfile[400]; time_t value; time_t value_max = 0; size_t len = 0; @@ -2098,9 +2135,10 @@ int mympd_smartpls_update_newest(char *playlist, int timerange, int maxentries) LOG_ERROR_AND_RECOVER("mpd_send_list_all_meta"); return 1; } - FILE *fp = fopen("/var/lib/mympd/tmp/playlist.tmp", "w"); + snprintf(tmpfile, 400, "%s/tmp/playlist.tmp", config.varlibdir); + FILE *fp = fopen(tmpfile, "w"); if (fp == NULL) { - printf("Error opening /var/lib/mympd/tmp/playlist.tmp"); + printf("Error opening %s", tmpfile); return 1; } while ((song = mpd_recv_song(mpd.conn)) != NULL) { @@ -2117,9 +2155,9 @@ int mympd_smartpls_update_newest(char *playlist, int timerange, int maxentries) value_max -= timerange; - fp = fopen("/var/lib/mympd/tmp/playlist.tmp", "r"); + fp = fopen(tmpfile, "r"); if (fp == NULL) { - printf("Error opening /var/lib/mympd/tmp/playlist.tmp"); + printf("Error opening %s", tmpfile); return 1; } while ((read = getline(&uri, &len, fp)) != -1) { @@ -2140,7 +2178,7 @@ int mympd_smartpls_update_newest(char *playlist, int timerange, int maxentries) } fclose(fp); free(uri); - unlink("/var/lib/mympd/tmp/playlist.tmp"); + unlink(tmpfile); printf("Updated %s with %ld songs, minValue: %ld\n", playlist, i, value_max); return 0; } diff --git a/src/mpd_client.h b/src/mpd_client.h index 195cd9f..2028baa 100644 --- a/src/mpd_client.h +++ b/src/mpd_client.h @@ -72,9 +72,8 @@ X(MPD_API_PLAYLIST_RM_TRACK) \ X(MPD_API_PLAYLIST_LIST) \ X(MPD_API_PLAYLIST_CONTENT_LIST) \ - X(MPD_API_SMARTPLS_UPDATE) \ + X(MPD_API_SMARTPLS_UPDATE_ALL) \ X(MPD_API_SMARTPLS_SAVE) \ - X(MPD_API_SMARTPLS_RM) \ X(MPD_API_DATABASE_SEARCH) \ X(MPD_API_DATABASE_UPDATE) \ X(MPD_API_DATABASE_RESCAN) \ @@ -160,11 +159,11 @@ typedef struct { const char* user; long streamport; const char* coverimage; - const char* statefile; bool stickers; bool mixramp; const char* taglist; bool smartpls; + const char* varlibdir; } t_config; t_config config; diff --git a/src/mympd.c b/src/mympd.c index 0a1572c..c9de0ae 100644 --- a/src/mympd.c +++ b/src/mympd.c @@ -155,8 +155,8 @@ static int inihandler(void* user, const char* section, const char* name, const c p_config->streamport = strtol(value, &crap, 10); else if (MATCH("coverimage")) p_config->coverimage = strdup(value); - else if (MATCH("statefile")) - p_config->statefile = strdup(value); + else if (MATCH("varlibdir")) + p_config->varlibdir = strdup(value); else if (MATCH("stickers")) if (strcmp(value, "true") == 0) p_config->stickers = true; @@ -186,6 +186,7 @@ int main(int argc, char **argv) { struct mg_connection *nc_http; struct mg_bind_opts bind_opts; const char *err; + char statefile[400]; //defaults config.mpdhost = "127.0.0.1"; @@ -199,7 +200,7 @@ int main(int argc, char **argv) { config.user = "nobody"; config.streamport = 8000; config.coverimage = "folder.jpg"; - config.statefile = "/var/lib/mympd/mympd.state"; + config.varlibdir = "/var/lib/mympd"; config.stickers = true; config.mixramp = true; config.taglist = "Artist,Album,AlbumArtist,Title,Track,Genre,Date,Composer,Performer"; @@ -240,8 +241,9 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } - if (access( config.statefile, F_OK ) != -1 ) { - char *content = json_fread(config.statefile); + snprintf(statefile, 400, "%s/mympd.state", config.varlibdir); + if (access(statefile, F_OK ) != -1 ) { + char *content = json_fread(statefile); int je = json_scanf(content, strlen(content), "{notificationWeb: %B, notificationPage: %B, jukeboxMode: %B, jukeboxPlaylist: %Q}", &mympd_state.notificationWeb, &mympd_state.notificationPage,