Released version 3-2015061300
[notion.git] / contrib / statusd / statusd_mpd.lua
bloba3be5119b8336777eacd37458da592bf4893bcf1
1 -- Authors: <delirium@hackish.org>
2 -- License: Unknown
3 -- Last Changed: Unknown
4 --
5 -- statusd for MPD (Music Player Daemon)
6 -- bugs/requests/comments: delirium@hackish.org
8 -- requires that netcat is available in the path
10 local defaults={
11 -- 500 or less makes seconds increment relatively smoothly while playing
12 update_interval=500,
14 -- mpd server info (localhost:6600 are mpd defaults)
15 address="localhost",
16 port=6600,
18 -- mpd password (if any)
19 password=nil,
21 -- display template
22 -- ---
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: %%
28 -- a default template
29 template = "%artist - %num - %title (%pos / %len)"
32 local settings=table.join(statusd.get_config("mpd"), defaults)
34 local success
35 local last_success
37 local function saferead(file)
38 local data, err, errno
39 repeat
40 data, err, errno = file:read()
41 until errno ~= 4 -- EINTR
42 return data, err, errno
43 end
45 local function get_mpd_status()
47 -- The first version of cmd_string is the original, however, some versions
48 -- of MPD close the socket too quickly if close is included. If you see the
49 -- message: error querying mpd status
50 -- then try the second version.
51 local cmd_string = "status\ncurrentsong\nclose\n"
52 -- local cmd_string = "status\ncurrentsong\n"
54 if settings.password ~= nil then
55 cmd_string = "password " .. settings.password .. "\n" .. cmd_string
56 end
57 cmd_string = string.format('echo -n "%s" | netcat %s %d',
58 cmd_string, settings.address, settings.port)
60 last_success = success
61 success = false
63 local mpd = io.popen(cmd_string, "r")
65 -- welcome msg
66 local data = saferead(mpd)
67 if data == nil or string.sub(data,1,6) ~= "OK MPD" then
68 mpd:close()
69 return "mpd not running"
70 end
72 -- 'password' response (if necessary)
73 if settings.password ~= nil then
74 repeat
75 data = saferead(mpd)
76 until data == nil or string.sub(data,1,2) == "OK" or string.sub(data,1,3) == "ACK"
77 if data == nil or string.sub(data,1,2) ~= "OK" then
78 mpd:close()
79 return "bad mpd password"
80 end
81 end
83 local info = {}
85 -- 'status' response
86 repeat
87 data = saferead(mpd)
88 if data == nil then break end
90 local _,_,attrib,val = string.find(data, "(.-): (.*)")
91 if attrib == "time" then
92 _,_,info.pos,info.len = string.find(val, "(%d+):(%d+)")
94 -- Around Lua 5.1, math.mod() was renamed math.fmod().
95 if type(math.mod) == "function" then
96 info.pos = string.format("%d:%02d", math.floor(info.pos / 60), math.mod(info.pos, 60))
97 info.len = string.format("%d:%02d", math.floor(info.len / 60), math.mod(info.len, 60))
98 else
99 info.pos = string.format("%d:%02d", math.floor(info.pos / 60), math.fmod(info.pos, 60))
100 info.len = string.format("%d:%02d", math.floor(info.len / 60), math.fmod(info.len, 60))
102 elseif attrib == "state" then
103 info.state = val
105 until string.sub(data,1,2) == "OK" or string.sub(data,1,3) == "ACK"
106 if data == nil or string.sub(data,1,2) ~= "OK" then
107 mpd:close()
108 return "error querying mpd status"
111 -- 'currentsong' response
112 repeat
113 data = saferead(mpd)
114 if data == nil then break end
116 local _,_,attrib,val = string.find(data, "(.-): (.*)")
117 if attrib == "Artist" then info.artist = val
118 elseif attrib == "Title" then info.title = val
119 elseif attrib == "Album" then info.album = val
120 elseif attrib == "Track" then info.num = val
121 elseif attrib == "Date" then info.year = val
123 until string.sub(data,1,2) == "OK" or string.sub(data,1,3) == "ACK"
124 if data == nil or string.sub(data,1,2) ~= "OK" then
125 mpd:close()
126 return "error querying current song"
129 mpd:close()
131 success = true
133 -- done querying; now build the string
134 if info.state == "play" then
135 local mpd_st = settings.template
136 -- fill in %values
137 mpd_st = string.gsub(mpd_st, "%%([%w%_]+)", function (x) return(info[x] or "") end)
138 mpd_st = string.gsub(mpd_st, "%%%%", "%%")
139 return mpd_st
140 elseif info.state == "pause" then
141 return "Paused"
142 else
143 return "No song playing"
148 local mpd_timer
150 local function update_mpd()
151 -- update unless there's an error that's not yet twice in a row, to allow
152 -- for transient errors due to load spikes
153 local mpd_st = get_mpd_status()
154 if success or not last_success then
155 statusd.inform("mpd", mpd_st)
157 mpd_timer:set(settings.update_interval, update_mpd)
160 -- Init
161 mpd_timer=statusd.create_timer()
162 update_mpd()