--- /dev/null
+urlbase="mpd.lua?"
+minScrollHeight=200
+
+currentState=""
+
+function GetFilename(url)
+{
+ if (url)
+ return url.split('/').pop().split('#')[0].split('?')[0];
+}
+
+function EscapeStr(str) {
+ res = str.replace(/'/g,"\\'");
+ return res;
+}
+
+function SetSize() {
+ var w = window,
+ d = document,
+ e = d.documentElement,
+ g = d.getElementsByTagName('body')[0],
+ body_h = g.clientHeight,
+ window_h = w.innerHeight|| e.clientHeight|| g.clientHeight,
+ items = d.getElementById('items'),
+ current_h = items.clientHeight,
+ new_h=(window_h-body_h)+current_h;
+ if (new_h>minScrollHeight) {
+ items.style.height=new_h+"px";
+ }
+}
+
+function toHHMMSS(seconds) {
+ var hours = Math.floor(seconds / 3600);
+ seconds -= hours*3600;
+ var minutes = Math.floor(seconds / 60);
+ seconds -= minutes*60;
+
+ if (hours < 10) {hours = "0"+hours;}
+ if (minutes < 10) {minutes = "0"+minutes;}
+ if (seconds < 10) {seconds = "0"+seconds;}
+ if (hours == 0) {
+ return minutes+':'+seconds;
+ } else {
+ return hours+':'+minutes+':'+seconds;
+ }
+}
+
+function RefreshTime() {
+ if (currentSeconds) {
+ currentTime = toHHMMSS(currentSeconds)
+ trackTime = toHHMMSS(trackSeconds)
+ nowPlayingTime = currentTime+"/"+trackTime
+ } else {
+ nowPlayingTime = "-:--/-:--"
+ }
+ document.getElementById('nowplaying_tracklen').innerHTML=nowPlayingTime;
+}
+
+function PeriodicRefreshTime() {
+ if (currentState == "play") {
+ nowTime = Date.now()
+ delta = (nowTime - updateTime)/1000
+ currentSeconds = updateSeconds + Math.round(delta)
+ if (currentSeconds > trackSeconds) {
+ currentSeconds = trackSeconds
+ }
+ RefreshTime()
+ }
+}
+
+function RefreshPageStatus() {
+
+ var req = new XMLHttpRequest();
+
+ req.onreadystatechange = function () {
+ if (this.readyState != 4 || this.status != 200) return;
+ var returnedData = JSON.parse(this.responseText);
+ trackName = GetFilename(returnedData['current_playing']);
+ trackNo = returnedData['song'];
+ currentState = returnedData['state'];
+ document.title='MPD Player: '+trackName;
+ if (trackNo) {
+ var nowPlayingTrackNo=String(1+Number(trackNo))
+ } else {
+ var nowPlayingTrackNo="-"
+ }
+ nowPlayingTrack = nowPlayingTrackNo + '/' + returnedData['playlistlength'];
+ nowPlayingName = trackName;
+ playingTime = returnedData['time']
+ if (playingTime) {
+ var splits = playingTime.split(":")
+ updateTime = Date.now()
+ currentSeconds = Number(splits[0])
+ updateSeconds = currentSeconds
+ trackSeconds = Number(splits[1])
+ } else {
+ currentSeconds = null
+ }
+ if (currentState=='stop') {
+ nowPlayingName = '<font color="gray">' + nowPlayingName+ '</font>'
+ }
+ document.getElementById('nowplaying_trackno').innerHTML=nowPlayingTrack;
+ document.getElementById('nowplaying_trackname').innerHTML=nowPlayingName;
+ RefreshTime()
+ if (currentState=="play") {
+ document.getElementById('playpausebutton').innerHTML="<span onclick=\"Command('pause')\"><img class=\"button\" title=\"Pause\" src=\"images/pause.svg\"></span>";
+ } else {
+ document.getElementById('playpausebutton').innerHTML="<span onclick=\"Command('play')\"><img class=\"button\" title=\"Play\" src=\"images/play-button.svg\"></span>";
+ }
+ if (currentState=="stop") {
+ document.getElementById('stopbutton').innerHTML="<span><img class=\"button\" src=\"images/stopoff.svg\"></span>";
+ } else {
+ document.getElementById('stopbutton').innerHTML="<span onclick=\"Command('stop')\"><img class=\"button\" title=\"Stop\" src=\"images/stop.svg\"></span>";
+ }
+ if (returnedData["repeat"]=="1") {
+ document.getElementById('repeatstate').innerHTML="<img class=\"button\" title=\"Replay is on\" src=\"images/replay.svg\"></a>";
+ } else {
+ document.getElementById('repeatstate').innerHTML="<img class=\"button\" title=\"Replay is off\" src=\"images/replayoff.svg\"></a>";
+ }
+ document.getElementById('volume_total').innerHTML="<div id=\"volume_actual\" style=\"width:"+returnedData["volume"]+"%\">";
+
+ var items = document.getElementById('items');
+ var table = items.getElementsByClassName('track');
+ var current_track="track_"+trackNo;
+ for (var i = 0; i < table.length; i++) {
+ if (table[i].id==current_track) {
+ table[i].classList.add("itemActive");
+ } else {
+ table[i].classList.remove("itemActive")
+ }
+ }
+
+ };
+
+ req.open("GET", urlbase+"status", true);
+ req.send();
+
+}
+
+function RefreshPlaylist() {
+
+var req = new XMLHttpRequest();
+
+req.onreadystatechange = function () {
+ if (this.readyState != 4 || this.status != 200) return;
+ var returnedData = JSON.parse(this.responseText);
+
+ var playlistMenuText = "<table>\
+ <tr>\
+ <td><span onclick=\"EditPlayList()\"><img class=\"medium-button\" title=\"Files\" src=\"images/folder.svg\"></span><td>\
+ <td><span onclick=\"LoadPlayList()\"><img class=\"medium-button\" title=\"Lists\" src=\"images/list.svg\"></span><td>\
+ <td><span onclick=\"SavePlayList()\"><img class=\"medium-button\" title=\"Save current list\" src=\"images/download.svg\"></span><td>\
+ <td><span onclick=\"return confirm('Clear current playlist, are you sure?') ? PlaylistCommand('clear') : false;\" ><img class=\"medium-button\" title=\"Clear current list\" src=\"images/cancel.svg\"></span><td>\
+ </tr>\
+ </table>";
+
+ var itemsText="<table>\
+ <tr id=\"items_heading\">\
+ <td></td class=\"track_number\"><td class=\"file\">Title</td><td class=\"medium-button\" colspan=\"3\">Controls</td>\
+ </tr>";
+
+ var even = 0;
+ for (var key in returnedData) {
+ var rec=returnedData[key];
+ var name=GetFilename(rec["name"]);
+ var id=rec["id"];
+
+ if (even) {
+ evText="itemEven";
+ } else {
+ evText="itemOdd";
+ };
+
+ even = ! even;
+
+ itemsText = itemsText + "<tr id=\"track_"+id+"\" class=\"track "+evText+"\">\
+ <td class=\"track_number\">\
+ <a name=\""+id+"\">"+(Number(id)+1)+"</a></td>\
+ </td>\
+ <td class=\"file\">\
+ <span class=\"link\" onclick=\"PlaylistCommand('playitem',"+id+")\">"+name+"</span>\
+ </td>\
+ <td class=\"move\">\
+ <span onclick=\"PlaylistCommand('moveup',"+id+")\"><img class=\"small-button\" title=\"Move up\" src=\"images/up-arrow.svg\"></span>\
+ </td>\
+ <td class=\"move\">\
+ <span onclick=\"PlaylistCommand('movedown',"+id+")\"><img class=\"small-button\" title=\"Move down\" src=\"images/down-arrow.svg\"></span>\
+ </td>\
+ <td class=\"remove\">\
+ <span onclick=\"PlaylistCommand('remove',"+id+")\"><img class=\"small-button\" title=\"Remove\" src=\"images/cancel.svg\"></span>\
+ </td>\
+ </tr>";
+ }
+
+ itemsText = itemsText + "</table>";
+
+ document.getElementById('items').innerHTML=itemsText;
+ document.getElementById('playlist_menu_top').innerHTML=playlistMenuText;
+ document.getElementById('playlist_menu_bottom').innerHTML=playlistMenuText;
+};
+
+req.open("GET", urlbase+"playlist", true);
+req.send();
+
+}
+
+function EditPlayList(dir) {
+
+var req = new XMLHttpRequest();
+
+req.onreadystatechange = function () {
+ if (this.readyState != 4 || this.status != 200) return;
+ var returnedData = JSON.parse(this.responseText);
+
+ var playlistMenuText = "<table>\
+ <tr>\
+ <td><span onclick=\"RefreshPlaylist()\"><img class=\"medium-button\" title=\"Home\" src=\"images/list.svg\"></span><td>\
+ <td><span onclick=\"return confirm('Add all to the list, are you sure?') ? PlaylistEditCommand('add','"+EscapeStr(dir)+"') : false;\" ><img class=\"medium-button\" title=\"Add all\" src=\"images/plus.svg\"></span><td>\
+ </tr>\
+ </table>";
+
+ var itemsText= "<table>\
+ <tr id=\"items_heading\">\
+ <td></td class=\"track_number\"><td class=\"file\">Title</td><td colspan=\"2\">Controls</td>\
+ </tr>";
+
+ var even = 0;
+ if (dir) {
+ var lastSlash=dir.lastIndexOf("/");
+ if (lastSlash>0) {
+ var upperLevel=dir.slice(0,lastSlash);
+ } else {
+ var upperLevel="";
+ }
+ even = ! even;
+ var itemsText = itemsText + "<tr class=\"itemOdd\">\
+ <td class=\"track_number\"></td>\
+ <td class=\"file\"><span class=\"link\" onclick=\"EditPlayList('"+upperLevel+"')\">..</span></td>\
+ <td></td><td></td>";
+ }
+
+ var i = 0;
+ for (var key in returnedData) {
+ var rec=returnedData[key];
+ var type=rec["type"];
+ var name=rec["name"];
+ var lastSlash=name.lastIndexOf("/");
+ if (lastSlash>0) {
+ var tailName=name.slice(lastSlash+1);
+ } else {
+ var tailName=name
+ };
+
+ if (type == "directory" || type == "file") {
+ if (even) {
+ evText="itemEven";
+ } else {
+ evText="itemOdd";
+ };
+
+ i = i + 1;
+ even = ! even;
+
+ itemsText = itemsText + "<tr class=\""+evText+"\">\
+ <td class=\"track_number\">\
+ <a name=\""+i+"\"></a></td>\
+ </td>";
+
+ if (type == "directory") {
+ itemsText = itemsText + "<td class=\"file\">\
+ <span class=\"link\" onclick=\"EditPlayList('"+EscapeStr(name)+"')\">"+tailName+"</span></td><td>\
+ <span onclick=\"PlaylistEditCommand('add','"+EscapeStr(name)+"')\"><img class=\"small-button\" title=\"Add\" src=\"images/plus.svg\"></span></td>";
+ };
+
+ if (type == "file") {
+ itemsText = itemsText + "<td class=\"file\">\
+ <span class=\"link\" onclick=\"PlaylistEditCommand('add','"+EscapeStr(name)+"')\">"+tailName+"</span></td><td>\
+ <span onclick=\"PlaylistEditCommand('add','"+EscapeStr(name)+"')\"><img class=\"small-button\" title=\"Add\" src=\"images/plus.svg\"></span></td>";
+ };
+
+ itemsText = itemsText + "</tr>";
+
+ }
+
+ }
+
+ var itemsText = itemsText+"</table>";
+ document.getElementById('items').innerHTML=itemsText;
+ document.getElementById('playlist_menu_top').innerHTML=playlistMenuText;
+ document.getElementById('playlist_menu_bottom').innerHTML=playlistMenuText;
+};
+
+if (!dir) { dir = ''; };
+
+req.open("GET", urlbase+"lists|edit|"+dir, true);
+req.send();
+
+}
+
+function LoadPlayList() {
+
+var req = new XMLHttpRequest();
+
+req.onreadystatechange = function () {
+ if (this.readyState != 4 || this.status != 200) return;
+ var returnedData = JSON.parse(this.responseText);
+ playlistMenuText="<table>\
+ <tr>\
+ <td><span onclick=\"RefreshPlaylist()\"><img class=\"medium-button\" title=\"Home\" src=\"images/list.svg\"></span><td>\
+ <td><span onclick=\"confirm('Clear current playlist, are you sure?') ? PlaylistCommandRefStatus('clear') : false;\" ><img class=\"medium-button\" title=\"Clear all\" src=\"images/cancel.svg\"></span><td>\
+ </tr>\
+ </table>";
+ itemsText="<table>\
+ <tr id=\"items_heading\">\
+ <td class=\"track_number\"></td><td class=\"file\">Name</td><td>Controls</td>\
+ </tr>";
+
+ var even = 0;
+ for (var key in returnedData) {
+ var name=returnedData[key];
+
+ if (even) {
+ evText="itemEven";
+ } else {
+ evText="itemOdd";
+ };
+
+ even = ! even;
+
+ itemsText = itemsText + "<tr class=\""+evText+"\">\
+ <td class=\"track_number\"><a name=\"0\"></a></td>\
+ <td class=\"file\"><span class=\"link\" onclick=\"PlaylistEditCommandRefFull('load','"+EscapeStr(name)+"')\">"+name+"</td>\
+ <td class=\"controls\"><span onclick=\"confirm('Delete playlist "+name+", are you sure?') ? DelPlayList('"+EscapeStr(name)+"') : false;\"><img class=\"small-button\" title=\"Delete\" src=\"images/minus.svg\"></span></td>\
+ </tr>";
+ }
+
+ itemsText=itemsText+"</table>";
+ document.getElementById('items').innerHTML=itemsText;
+ document.getElementById('playlist_menu_top').innerHTML=playlistMenuText;
+ document.getElementById('playlist_menu_bottom').innerHTML=playlistMenuText;
+};
+
+req.open("GET", urlbase+"lists|load", true);
+req.send();
+
+}
+
+function SavePlayList() {
+
+var name=window.prompt('List name','');
+
+var req = new XMLHttpRequest();
+
+req.onreadystatechange = function () {
+ if (this.readyState != 4 || this.status != 200) return;
+ if (this.responseText != 'OK') {
+ window.alert(this.responseText);
+ }
+};
+
+req.open("GET", urlbase+"lists|save|"+name, true);
+req.send();
+
+}
+
+function DelPlayList(item) {
+
+var req = new XMLHttpRequest();
+
+req.onreadystatechange = function () {
+ if (this.readyState != 4 || this.status != 200) return;
+ LoadPlayList();
+ RefreshPageStatus();
+};
+
+req.open("GET", urlbase+"lists|delete|"+item, true);
+req.send();
+
+}
+
+function RefreshPageContent() {
+ RefreshPlaylist();
+ RefreshPageStatus();
+}
+
+function Command(cmd) {
+
+var req = new XMLHttpRequest();
+
+req.onreadystatechange = function () {
+ if (this.readyState != 4 || this.status != 200) return;
+ RefreshPageStatus();
+};
+
+req.open("GET", urlbase+cmd, true);
+req.send();
+
+}
+
+function PlaylistCommand(cmd,item) {
+
+var req = new XMLHttpRequest();
+
+req.onreadystatechange = function () {
+ if (this.readyState != 4 || this.status != 200) return;
+ RefreshPageContent();
+};
+
+req.open("GET", urlbase+"cpl|"+cmd+"|"+item, true);
+req.send();
+
+}
+
+function PlaylistCommandRefStatus(cmd,item) {
+
+var req = new XMLHttpRequest();
+
+req.onreadystatechange = function () {
+ if (this.readyState != 4 || this.status != 200) return;
+ RefreshPageStatus();
+};
+
+req.open("GET", urlbase+"cpl|"+cmd+"|"+item, true);
+req.send();
+
+}
+
+function PlaylistEditCommand(cmd,item) {
+
+var req = new XMLHttpRequest();
+
+req.onreadystatechange = function () {
+ if (this.readyState != 4 || this.status != 200) return;
+ RefreshPageStatus();
+};
+
+req.open("GET", urlbase+"lists|"+cmd+"|"+item, true);
+req.send();
+
+}
+
+function PlaylistEditCommandRefFull(cmd,item) {
+
+var req = new XMLHttpRequest();
+
+req.onreadystatechange = function () {
+ if (this.readyState != 4 || this.status != 200) return;
+ RefreshPageContent();
+};
+
+req.open("GET", urlbase+"lists|"+cmd+"|"+item, true);
+req.send();
+
+}
+
+function subscribe_status() {
+ var xhr = new XMLHttpRequest();
+
+ xhr.onreadystatechange = function() {
+ if (this.readyState != 4) return;
+ if (this.status == 200) {
+ RefreshPageStatus()
+ setTimeout(subscribe_status,1000)
+ } else {
+ setTimeout(subscribe_status,15000)
+ }
+ }
+ xhr.open("GET", urlbase+"idle", true);
+ xhr.send();
+}
+
+setTimeout(subscribe_status,5000)
+setInterval(PeriodicRefreshTime, 1000);
--- /dev/null
+#!/usr/bin/lua
+
+local hasuci,uci = pcall(require,"uci")
+
+require("socket")
+json=require("json")
+
+function url_decode(str)
+ if not str then return nil end
+ str = string.gsub (str, "+", " ")
+ str = string.gsub (str, "%%(%x%x)", function(h) return
+ string.char(tonumber(h,16)) end)
+ str = string.gsub (str, "\r\n", "\n")
+ return str
+end
+
+function split(s, delimiter)
+ local result = {};
+ for match in (s..delimiter):gmatch("(.-)"..delimiter) do
+ result[#result+1] = match;
+ end
+ return result;
+end
+
+function string.starts(String,Start)
+ return string.sub(String,1,string.len(Start))==Start
+end
+
+function process_playlist(playlist)
+ local res={}
+ for _,record in pairs(playlist) do
+ local splitted = split(record,": ")
+ local name = splitted[2]
+ local splitted = split(splitted[1],":")
+ local id = splitted[1]
+ local rectype = splitted[2]
+ local rec = {}
+ if not (id == "OK") then
+ rec["id"] = id
+ rec["type"] = rectype
+ rec["name"] = name
+ res[id] = rec
+ end
+ end
+ return res
+end
+
+function process_playlists(playlists)
+ local res={}
+ for _,record in pairs(playlists) do
+ local splitted = split(record,": ")
+ if splitted[1]=="playlist" then
+ res[#res+1] = splitted[2]
+ end
+ end
+ return res
+end
+
+function process_directory(directory)
+ local res={}
+ for _,record in pairs(directory) do
+ local splitted = split(record,": ")
+ if splitted[1]=="directory" or splitted[1]=="file" then
+ local rec={}
+ rec["type"] = splitted[1]
+ rec["name"] = splitted[2]
+ res[#res+1] = rec
+ end
+ end
+ return res
+end
+
+function mpd_new(settings)
+ local client = {}
+ if settings == nil then settings = {} end
+
+ client.hostname = settings.hostname or "localhost"
+ client.port = settings.port or 6600
+ client.desc = settings.desc or client.hostname
+ client.password = settings.password
+ client.timeout = settings.timeout or 1
+ client.retry = settings.retry or 60
+
+ return client
+end
+
+function mpd_send(mpd,action,raw)
+
+ local command = string.format("%s\n", action)
+ local values = {}
+
+ -- connect to MPD server if not already done.
+ if not mpd.connected then
+ local now = os.time();
+ if not mpd.last_try or (now - mpd.last_try) > mpd.retry then
+ mpd.socket = socket.tcp()
+ mpd.socket:settimeout(mpd.timeout, 't')
+ mpd.last_try = os.time()
+ mpd.connected = mpd.socket:connect(mpd.hostname, mpd.port)
+ if not mpd.connected then
+ return { errormsg = "could not connect" }
+ end
+ mpd.last_error = nil
+
+ -- Read the server's hello message
+ local line = mpd.socket:receive("*l")
+ if not line:match("^OK MPD") then -- Invalid hello message?
+ mpd.connected = false
+ return { errormsg = string.format("invalid hello message: %s", line) }
+ else
+ _, _, mpd.version = string.find(line, "^OK MPD ([0-9.]+)")
+ end
+
+ -- send the password if needed
+ if mpd.password then
+ local rsp = mpd_send(mpd,string.format("password %s", mpd.password))
+ if rsp.errormsg then
+ return rsp
+ end
+ end
+ else
+ local retry_sec = mpd.retry - (now - mpd.last_try)
+ return { errormsg = string.format("%s (retrying in %d sec)", mpd.last_error, retry_sec) }
+ end
+ end
+
+ mpd.socket:send(command)
+
+ local line = ""; err=0
+ while not line:match("^OK$") do
+ line, err = mpd.socket:receive("*l")
+ if not line then -- closed,timeout (mpd killed?)
+ mpd.last_error = err
+ mpd.connected = false
+ mpd.socket:close()
+ return mpd_send(mpd,action)
+ end
+
+ if line:match("^ACK") then
+ return { errormsg = line }
+ end
+
+ if not raw then
+
+ local pattern = string.format("(%s)", ": ")
+ local i = string.find (line, pattern, 0)
+
+ if i ~= nil then
+ local key=string.sub(line,1,i-1)
+ local value=string.sub(line,i+2,-1)
+ values[string.lower(key)] = value
+ end
+
+ else
+
+ values[#values+1]=line
+
+ end
+ end
+
+ return values
+end
+
+if hasuci then
+
+ x = uci.cursor()
+
+ settings = {}
+ settings['host'] = x.get("mpd","server","host") or "localhost"
+ settings['port'] = x.get("mpd","server","port") or 6600
+ settings['timeout'] = x.get("mpd","server","timeout") or 1
+
+ volstep = x.get("mpd","control","volume_step") or 3
+
+ password = x.get("mpd","server","password")
+
+else
+
+ config = arg[1]
+ if not config then
+ config="/etc/mpd-lua.json"
+ end
+
+ settings={}
+ local open = io.open
+ local file = open(config, "r")
+ if file then
+ local content = file:read "*a"
+ file:close()
+ settings=json.decode(content)
+ end
+
+ settings['host'] = settings['host'] or "localhost"
+ settings['port'] = settings["port"] or 6600
+ settings['timeout'] = settings["timeout"] or 1
+
+ volstep = settings["volstep"] or 3
+
+end
+
+
+if password then
+ settings["password"] = password
+end
+
+m = mpd_new(settings)
+
+command = url_decode(os.getenv('QUERY_STRING'))
+
+if not command or command=="" then
+ command="idle"
+end
+
+if command=="play" or command=="pause" or command=="stop" then
+
+ res=mpd_send(m,command)
+
+elseif command=="previous" or command=="next" then
+
+ res=mpd_send(m,"play")
+ res=mpd_send(m,command)
+
+elseif command=="idle" then
+
+ m.timeout=30
+ res=mpd_send(m,command)
+
+elseif command=="vold" then
+
+ status=mpd_send(m,"status")
+ volume=tonumber(status["volume"])
+ res=mpd_send(m,"setvol "..(volume-volstep))
+
+elseif command=="volu" then
+
+ status=mpd_send(m,"status")
+ volume=tonumber(status["volume"])
+ res=mpd_send(m,"setvol "..(volume+volstep))
+
+elseif string.starts(command,"fastfwd") then
+
+ cmd=split(command,"|")
+ skip=tonumber(cmd[2])
+ if not skip then
+ skip=15
+ end
+
+ status=mpd_send(m,"status")
+ rec_time=status["time"]
+ song=status["song"]
+
+ if song then
+
+ if rec_time then
+ rec_time=split(rec_time,":")
+ cur_time=tonumber(rec_time[1])
+
+ track_time=tonumber(rec_time[2])
+ cur_time=cur_time+skip
+ if cur_time>track_time then
+ cur_time=track_time
+ end
+
+ mpd_send(m,"seek "..song.." "..cur_time)
+
+ else
+
+ mpd_send(m,"play")
+
+ end
+
+ end
+
+ res={}
+
+elseif string.starts(command,"rewind") then
+
+ cmd=split(command,"|")
+ skip=tonumber(cmd[2])
+ if not skip then
+ skip=15
+ end
+
+ status=mpd_send(m,"status")
+ rec_time=status["time"]
+ song=status["song"]
+
+ if song then
+
+ if rec_time then
+ rec_time=split(rec_time,":")
+ cur_time=tonumber(rec_time[1])
+
+ track_time=tonumber(rec_time[2])
+ cur_time=cur_time-skip
+ if cur_time<0 then
+ cur_time=0
+ end
+
+ mpd_send(m,"seek "..song.." "..cur_time)
+
+ else
+
+ mpd_send(m,"play")
+ mpd_send(m,"previous")
+
+ end
+
+ end
+
+ res={}
+
+elseif command=="status" then
+
+ res=mpd_send(m,"status")
+ song=res["song"]
+ playlist=mpd_send(m,"playlist",1)
+ pl=process_playlist(playlist)
+
+ if song then
+ res['current_playing']=pl[song]['name']
+ else
+ res['song']="--"
+ res['current_playing']="---"
+ end
+
+elseif command=="playlist" then
+
+ playlist=mpd_send(m,"playlist",1)
+ res=process_playlist(playlist)
+
+elseif command=="repeat" then
+
+ status=mpd_send(m,"status")
+ rep=1-status["repeat"]
+ res=mpd_send(m,"repeat "..rep)
+
+elseif string.starts(command,"cpl") then
+
+ cmd=split(command,"|")
+ id=cmd[3]
+ command=cmd[2]
+
+ if command=="playitem" then
+ command="play "..id
+ res=mpd_send(m,command)
+ end
+
+ if command=="clear" then
+ res=mpd_send(m,"clear")
+ end
+
+ if command=="remove" then
+ command="delete "..id
+ res=mpd_send(m,command)
+ end
+
+ if command=="moveup" then
+ command="swap "..id.." "..(id-1)
+ res=mpd_send(m,command)
+ end
+
+ if command=="movedown" then
+ command="swap "..id.." "..(id+1)
+ res=mpd_send(m,command)
+ end
+
+elseif string.starts(command,"lists") then
+
+ cmd=split(command,"|")
+ command=cmd[2]
+
+ if command=="load" then
+ if not cmd[3] then
+ lists=mpd_send(m,"listplaylists",1)
+ res=process_playlists(lists)
+ else
+ res=mpd_send(m,"load "..cmd[3],1)
+ end
+ end
+
+ if command=="save" and cmd[3] then
+ res=mpd_send(m,"save "..cmd[3],1)
+ end
+
+ if command=="delete" and cmd[3] then
+ res=mpd_send(m,"rm "..cmd[3],1)
+ end
+
+ if command=="edit" then
+ if cmd[3] then
+ dir=mpd_send(m,"lsinfo \""..cmd[3].."\"",1)
+ else
+ dir=mpd_send(m,"lsinfo",1)
+ end
+ res=process_directory(dir)
+ end
+
+ if command=="add" then
+ res={}
+ if cmd[3] then
+ res=mpd_send(m,"add \""..cmd[3].."\"")
+ end
+ end
+
+end
+
+if not res then
+ print("Content-Type: text/plain\r\n")
+ print("MPD server - unknown command "..command)
+elseif (res['error_msg']) then
+ print("Content-Type: text/plain\r\n")
+ print("MPD server connection error: "..res['error_msg'])
+else
+ print "Content-Type: text/plain\r\n"
+ print(json.encode(res))
+end