1 -- Authors: <delirium@hackish.org>
3 -- Last Changed: Unknown
5 -- statusd for MPD (Music Player Daemon)
6 -- bugs/requests/comments: delirium@hackish.org
8 -- requires that netcat is available in the path
11 -- 500 or less makes seconds increment relatively smoothly while playing
14 -- mpd server info (localhost:6600 are mpd defaults)
18 -- mpd password (if any)
23 -- can use the following:
24 -- track metadata: %artist, %title, %num, %album, %year, %len
25 -- current track position: %pos
26 -- escape for the percent character: %%
29 template
= "%artist - %num - %title (%pos / %len)"
32 local settings
=table.join(statusd
.get_config("mpd"), defaults
)
37 local function saferead(file
)
38 local data
, err
, errno
40 data
, err
, errno
= file
:read()
41 until errno
~= 4 -- EINTR
42 return data
, err
, errno
45 local function get_mpd_status()
46 local cmd_string
= "status\ncurrentsong\nclose\n"
47 if settings
.password
~= nil then
48 cmd_string
= "password " .. settings
.password
.. "\n" .. cmd_string
50 cmd_string
= string.format('echo -n "%s" | netcat %s %d',
51 cmd_string
, settings
.address
, settings
.port
)
53 last_success
= success
56 local mpd
= io
.popen(cmd_string
, "r")
59 local data
= saferead(mpd
)
60 if data
== nil or string.sub(data
,1,6) ~= "OK MPD" then
62 return "mpd not running"
65 -- 'password' response (if necessary)
66 if settings
.password
~= nil then
69 until data
== nil or string.sub(data
,1,2) == "OK" or string.sub(data
,1,3) == "ACK"
70 if data
== nil or string.sub(data
,1,2) ~= "OK" then
72 return "bad mpd password"
81 if data
== nil then break end
83 local _
,_
,attrib
,val
= string.find(data
, "(.-): (.*)")
84 if attrib
== "time" then
85 _
,_
,info
.pos
,info
.len
= string.find(val
, "(%d+):(%d+)")
86 info
.pos
= string.format("%d:%02d", math
.floor(info
.pos
/ 60), math
.mod(info
.pos
, 60))
87 info
.len
= string.format("%d:%02d", math
.floor(info
.len
/ 60), math
.mod(info
.len
, 60))
88 elseif attrib
== "state" then
91 until string.sub(data
,1,2) == "OK" or string.sub(data
,1,3) == "ACK"
92 if data
== nil or string.sub(data
,1,2) ~= "OK" then
94 return "error querying mpd status"
97 -- 'currentsong' response
100 if data
== nil then break end
102 local _
,_
,attrib
,val
= string.find(data
, "(.-): (.*)")
103 if attrib
== "Artist" then info
.artist
= val
104 elseif attrib
== "Title" then info
.title
= val
105 elseif attrib
== "Album" then info
.album
= val
106 elseif attrib
== "Track" then info
.num
= val
107 elseif attrib
== "Date" then info
.year
= val
109 until string.sub(data
,1,2) == "OK" or string.sub(data
,1,3) == "ACK"
110 if data
== nil or string.sub(data
,1,2) ~= "OK" then
112 return "error querying current song"
119 -- done querying; now build the string
120 if info
.state
== "play" then
121 local mpd_st
= settings
.template
123 mpd_st
= string.gsub(mpd_st
, "%%([%w%_]+)", function (x
) return(info
[x
] or "") end)
124 mpd_st
= string.gsub(mpd_st
, "%%%%", "%%")
126 elseif info
.state
== "pause" then
129 return "No song playing"
136 local function update_mpd()
137 -- update unless there's an error that's not yet twice in a row, to allow
138 -- for transient errors due to load spikes
139 local mpd_st
= get_mpd_status()
140 if success
or not last_success
then
141 statusd
.inform("mpd", mpd_st
)
143 mpd_timer
:set(settings
.update_interval
, update_mpd
)
147 mpd_timer
=statusd
.create_timer()