-- Requires libsocket
-- TODO:
-- do pubsub tunes+notify instead of status hacking
require 'socket'
local settings = {
hostname = "localhost",
password = nil,
port = 6600,
}
mpd = {}
-- 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 mpd.receive_message ( tcp, separator )
local ret = {}
local line = tcp:receive ( '*l' )
while line and not ( line:find ( '^OK' ) or line:find ( '^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 }
-- 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 mpd.call_command ( opts )
local tcp = socket.tcp ()
if not tcp then
print ( 'mpd: cannot get master tcp object' )
return nil
elseif not tcp:connect ( settings.hostname, settings.port ) then
tcp:close ()
print ( 'mpd: cannot connect to server' )
return nil
end
local ret = {}
if not opts.noret then
ret = mpd.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
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
if not opts.noret then
ret[num] = mpd.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
end
tcp:close ()
if #ret > 1 then
return ret
else
return ret[1]
end
end
-- MCABBER PART --
mpd_enabled = false
function mpd_getstatus ()
if not mpd_enabled then
return ''
end
local stats = mpd.call_command { 'status', 'currentsong' }
if stats[1].state ~= 'play' and stats[1].state ~= 'pause' then
return ''
end
local title = stats[2].title
if not title then
if stats[2].file then
title = stats[2].file
else
title = ''
end
elseif not stats[2].artist then
title = string.format ( "%s (%s)", title, stats[2].file )
else
title = string.format ( "%s - %s", stats[2].artist, title )
end
if stats[1].state == 'pause' then
return string.format ( "[mpd: <зупинено> %s]", title )
else
return string.format ( "[mpd: %s]", title )
end
end
function parse_status ()
local stletter, stmessage = main.status ()
local cmd = char2status[stletter]
local message, mpd_string = stmessage:match ( "^(.-)%s+(%[mpd:%s+.+%s*%])" )
if message then
return cmd, message, mpd_string
else
return cmd, stmessage, ''
end
end
function mpd_callback ()
local new_mpd_string = mpd_getstatus ()
local status, message, mpd_string = parse_status ()
if new_mpd_string ~= mpd_string then
main.run ( string.format ( 'status %s %s %s', status, message, new_mpd_string ) )
end
if mpd_enabled then
return true
else
return false
end
end
-- do not call it too fast, or you end up with many daemons at once
function enable_mpd ( yn )
if yn == nil then
yn = true
end
if yn then
if not mpd_enabled then
main.timer ( 15, mpd_callback )
mpd_enabled = true
-- update status
end
else
if mpd_enabled then
mpd_enabled = false
-- update status
end
end
end
main.add_command ( 'mpd',
function ( args )
local enable = yesno ( args )
if enable == nil then
if mpd_enabled then
print ( "MPD status string is enabled" )
else
print ( "MPD status string is disabled" )
end
else
enable_mpd ( enable )
end
end )
commands_help['mpd'] = "[enable|disable|on|off|yes|no|true|false]\n\nSets state of mpd string in your status.\nIf state is omitted, prints current state."
-- vim: se ts=4: --