Фикс для совместимости с lua 5.1 на debian
[mpd-lua.git] / mpd.lua
diff --git a/mpd.lua b/mpd.lua
index 31275b69277cf1ae3210969c6537ddfcec155622..c8ea77858bebca8ab7189dca8477cea5944e6c1b 100755 (executable)
--- a/mpd.lua
+++ b/mpd.lua
@@ -1,7 +1,8 @@
 #!/usr/bin/lua
 
-require "uci"
-require("socket")
+local hasuci,uci = pcall(require,"uci")
+
+socket=require("socket")
 json=require("json")
 
 function url_decode(str)
@@ -13,6 +14,23 @@ function url_decode(str)
   return str
 end
 
+function url_encode(str)
+
+  --Ensure all newlines are in CRLF form
+  str = string.gsub (str, "\r?\n", "\r\n")
+
+  --Percent-encode all non-unreserved characters
+  --as per RFC 3986, Section 2.3
+  --(except for space, which gets plus-encoded)
+  str = string.gsub (str, "([^%w%-%.%_%~:/])",
+    function (c) return string.format ("%%%02X", string.byte(c)) end)
+
+  --Convert spaces to plus signs
+  str = string.gsub (str, " ", "+")
+
+  return str
+end
+
 function split(s, delimiter)
     local result = {};
     for match in (s..delimiter):gmatch("(.-)"..delimiter) do
@@ -25,25 +43,53 @@ function string.starts(String,Start)
    return string.sub(String,1,string.len(Start))==Start
 end
 
+function filename(path)
+  local path_elems=split(path,'/')
+  return path_elems[#path_elems]
+end
+
 function process_playlist(playlist)
   local res={}
+  local rec={}
   for _,record in pairs(playlist) do
+    if record=="OK" then 
+      break
+    end  
     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
+    local fieldname = string.lower(splitted[1])
+    local fieldvalue = splitted[2]
+    rec[fieldname] = fieldvalue
+    if fieldname=="id" then
+      local title = rec['title']
+      if title then
+        local filtered_title=string.gsub(string.lower(title),'track','')
+        local filtered_title=string.gsub(filtered_title,'[ _.-]','')
+      else
+        filtered_title=""
+      end  
+      if not filtered_title or string.len(filtered_title)<4 then
+        if title then
+          rec['title']=title..' - '..filename(rec['file'])
+        else
+          rec['title']=filename(rec['file'])
+        end  
+      end
+      res[#res+1] = rec
+      rec={}
     end
   end
   return res
 end
 
+function find_by_id(playlist,id)
+  for key,record in pairs(playlist) do
+    if record['id']==id then
+      return key
+    end
+  end
+  return nil
+end
+
 function process_playlists(playlists)
   local res={}
   for _,record in pairs(playlists) do
@@ -71,6 +117,7 @@ end
 
 function mpd_new(settings)
     local client = {}
+
     if settings == nil then settings = {} end
 
     client.hostname = settings.hostname or "localhost"
@@ -160,16 +207,40 @@ function mpd_send(mpd,action,raw)
     return values
 end
 
-x = uci.cursor()
+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
+  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
+  volstep = x.get("mpd","control","volume_step") or 3
+
+  password = x.get("mpd","server","password")
+
+else
 
-password = x.get("mpd","server","password")
+  config="/etc/mpd-lua.json"
+
+  settings={}
+  local open = io.open
+  file = open(config, "r")
+  if file then
+    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
@@ -182,8 +253,13 @@ if not command or command=="" then
   command="idle"
 end
 
-if command=="play" or command=="pause" or command=="stop" or command=="previous" or command=="next" then
+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
@@ -203,22 +279,95 @@ elseif command=="volu" then
   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["songid"]
+  
+  if song then
+
+    if rec_time then
+      rec_time=split(rec_time,":")
+      cur_time=tonumber(rec_time[1])
+
+      track_time=tonumber(rec_time[2])
+      if track_time then
+        cur_time=cur_time+skip
+        if cur_time>track_time then
+          cur_time=track_time
+        end
+      end  
+      mpd_send(m,"seekid "..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["songid"]
+  
+  if song then
+
+    if rec_time then
+      rec_time=split(rec_time,":")
+      cur_time=tonumber(rec_time[1])
+      cur_time=cur_time-skip
+      if cur_time<0 then
+        cur_time=0
+      end
+
+      print(song)
+      print(cur_time)
+      mpd_send(m,"seekid "..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)
-
+  song=tonumber(res["songid"])
   if song then 
-    res['current_playing']=pl[song]['name']
-  else
-    res['current_playing']="No songs selected"
+    playlist=mpd_send(m,"playlistid "..song,1)
+    pl=process_playlist(playlist)
+    res['current_playing']=pl[1]['title']
+  else  
+    res['current_playing']="---"
   end
 
 elseif command=="playlist" then
 
-  playlist=mpd_send(m,"playlist",1)
+  playlist=mpd_send(m,"playlistinfo",1)
   res=process_playlist(playlist)
 
 elseif command=="repeat" then
@@ -234,7 +383,7 @@ elseif string.starts(command,"cpl") then
   command=cmd[2]
 
   if command=="playitem" then
-    command="play "..id
+    command="playid "..id
     res=mpd_send(m,command)
   end
 
@@ -243,17 +392,27 @@ elseif string.starts(command,"cpl") then
   end
 
   if command=="remove" then
-    command="delete "..id
+    command="deleteid "..id
     res=mpd_send(m,command)
   end
 
   if command=="moveup" then
-    command="swap "..id.." "..(id-1)
+    playlist=mpd_send(m,"playlistinfo ",1)
+    pl=process_playlist(playlist)
+    idx=find_by_id(pl,id)
+    if idx>1 then
+      command="swap "..(idx-1).." "..(idx-2)
+    end  
     res=mpd_send(m,command)
   end
 
   if command=="movedown" then
-    command="swap "..id.." "..(id+1)
+    playlist=mpd_send(m,"playlistinfo ",1)
+    pl=process_playlist(playlist)
+    idx=find_by_id(pl,id)
+    if idx<#pl then
+      command="swap "..(idx-1).." "..(idx)
+    end  
     res=mpd_send(m,command)
   end
 
@@ -267,16 +426,16 @@ elseif string.starts(command,"lists") then
       lists=mpd_send(m,"listplaylists",1)
       res=process_playlists(lists)
     else
-      res=mpd_send(m,"load "..cmd[3],1)
+      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)
+    res=mpd_send(m,"save \""..cmd[3].."\"",1)
   end
 
   if command=="delete" and cmd[3] then
-    res=mpd_send(m,"rm "..cmd[3],1)
+    res=mpd_send(m,"rm \""..cmd[3].."\"",1)
   end
 
   if command=="edit" then
@@ -292,6 +451,10 @@ elseif string.starts(command,"lists") then
     res={}
     if cmd[3] then
       res=mpd_send(m,"add \""..cmd[3].."\"")
+      if (res['errormsg']) then
+        path=url_encode(cmd[3])
+        res=mpd_send(m,"add \""..path.."\"")
+      end
     end
   end
 
@@ -300,9 +463,9 @@ end
 if not res then
   print("Content-Type: text/plain\r\n")
   print("MPD server - unknown command "..command)
-elseif (res['error_msg']) then
+elseif (res['errormsg']) then
   print("Content-Type: text/plain\r\n")
-  print("MPD server connection error: "..res['error_msg'])
+  print("MPD server connection error: "..res['errormsg'])
 else
   print "Content-Type: text/plain\r\n"
   print(json.encode(res))