-- MPD INTERATION
-- library
local socket = require 'socket'
--
local O = {
hostname = "localhost",
password = nil,
port = 6600,
}
local F = { }
-- separator allows split output into records, that are started by any of present in separator keys
-- returns table of field (lowercase) - value records
-- command status is returned in STATUS field
-- on unexpected errors returns just false, dropping any available data
function F.receive_message ( tcp, separator )
local ret = {}
local line = tcp:receive ( '*l' )
while line and not ( line:match ( '^OK' ) or line:match ( '^ACK' ) ) do
local key, val = line:match ( '^(.-):%s*(.*)$' )
if key then
if separator then
key = key:lower ()
if separator[key] then
table.insert ( ret, {} )
end
ret[#ret][key] = val
else
ret[key:lower()] = val
end
end
line = tcp:receive ( '*l' )
end
if not line then
return false -- an error occured, ret, most likely, does not contains exact and complete info...
else
ret.STATUS = line:match ( '^%S+' )
return ret
end
end
-- use: mpd.call_command { 'status' }
-- mpd.call_command { 'lsinfo misc', list = { file = true, directory = true } }
-- mpd.call_command { 'next', noret = true } -- removed, early termination with password :/
-- mpd.call_command { 'status', 'currentsong' }
-- on one command returns just results of that command, on multi - array of results
-- on errors returns nil
-- noret can terminate socket too early, thus, do not use it with lists of commands
function F.call_command ( opts )
local tcp = socket.tcp ()
if not tcp then
print ( 'mpd: cannot get master tcp object' )
return nil
end
if not O.hostname then
local server = os.getenv ( 'MPD_HOST' )
if server then
local password, host = server:match ( '(.+)@(.-)' )
if password then
F.server ( host, os.getenv ( 'MPD_PORT' ) or 6600, password )
else
F.server ( server, os.getenv ( 'MPD_PORT' ) or 6600, nil )
end
else
F.server ( "localhost", 6600, nil )
end
end
if not tcp:connect ( O.hostname, O.port ) then
tcp:close ()
print ( 'mpd: cannot connect to server' )
return nil
end
local ret = {}
ret = F.receive_message ( tcp )
if not ret then
tcp:close ()
print ( 'mpd: error getting greeting from server' )
return nil
elseif ret.STATUS ~= 'OK' then
print ( 'mpd: server ack\'s in greeting' )
end
if O.password then
if not tcp:send ( "password " .. O.password .. "\n" ) then
tcp:close ()
print ( 'mpd: error sending password' )
return nil
end
ret = mpd.receive_message ( tcp )
if not ret then
tcp:close ()
print ( 'mpd: error getting response for password' )
return nil
elseif ret.STATUS ~= 'OK' then
print ( 'mpd: server refuses password' )
end
end
for num, command in ipairs ( opts ) do
if not tcp:send ( command .. "\n" ) then
tcp:close ()
print ( 'mpd: error sending command ' .. command )
return nil
end
ret[num] = F.receive_message ( tcp, opts.list )
if not ret[num] then
print ( 'mpd: error getting result' )
end
if ret[num]['STATUS'] ~= 'OK' then
print ( 'mpd: server acks our command ' .. command )
end
end
tcp:close ()
if #ret > 1 then
return ret
else
return ret[1]
end
end
function F.server ( host, port, password )
O.hostname = host
O.port = port
O.password = password
end
return F
-- vim: se ts=4: --