Include notionflux in the main repo instead of its own submodule
[notion/jeffpc.git] / contrib / statusd / statusd_xmmsip.lua
blob747c08232af598a716b496365c0f3a83000049dd
1 -- Authors: Hendrik Iben <hiben@tzi.de>
2 -- License: GPL, version 2
3 -- Last Changed: 2006-03-23
4 --
5 -- statusd_xmmsip.lua v20060323
6 --
7 -- Interface to the XMMS InfoPipe-Plugin
8 -- Inspired by the high cpu attention statusd_xmms.lua + python demand...
9 -- ( no offense, just observation... :-)
10 -- (using statusd_xmms while writing this... ;-) )
11 --
12 -- Written by Hendrik Iben < hiben at tzi dot de >
14 -- How to use :
15 -- xmmsip provides a lot of statusd-monitors
16 -- You can compose the text displayed in your statusbar using these individual
17 -- monitors or/and you may specify a string with a setup of the values you
18 -- are interested in.
20 -- The monitors :
21 -- xmmsip_pllen : Length of the playlist (number of entries)
22 -- xmmsip_plcur : Current song in playlist (number of entry)
23 -- xmmsip_file : Current file played
24 -- xmmsip_title : Current file's title
25 -- xmmsip_usectime : Length of file in milliseconds (-1 for streams)
26 -- xmmsip_time : Length of file in minutes:seconds or '>>>' for streams
27 -- xmmsip_usecpos : Position in file in milliseconds
28 -- xmmsip_pos : Position in file in minutes:seconds
29 -- xmmsip_usecleft : Time left in milliseconds (0 for streams)
30 -- xmmsip_left : Time left in minutes:seconds or "<<<" for streams
31 -- xmmsip_status : XMMS's status : (Playing, Paused, Stopped, Not running)
32 -- xmmsip_sstatus : same as above but all lowercase
33 -- xmmsip_bitrate : Current bitrate (not average bitrate)
34 -- xmmsip_kbitrate : Current bitrate in kilobit per seconds (using 1000 for k)
35 -- xmmsip_freq : Sampling frequency in Hz
36 -- xmmsip_kfreq : Sampling frequency in kHz
37 -- xmmsip_channels : Current channels (1,2,?)
38 -- xmmsip_xmmsproto : Protocol version of XMMS
39 -- xmmsip_infover : Version of InfoPipe-Plugin
40 --
41 -- xmmsip_user : String resulting from 'user_format'-string
42 -- or 'not_running'-string
44 -- While it is perfectly legal to use these directly in your statusbar I
45 -- recommend you to only use xmmsip_user and configure the format string.
46 -- This way you do not get a '?' for every monitor when XMMS is not running...
48 -- Setting up the 'user_format'-string is done by forming a string where each
49 -- xmmsip_x-monitor is referenced to by '%x%'
50 --
51 -- example :
52 -- "...%xmmsip_status %xmmsip_title ..blub..." in cfg_statusbar template
53 --
54 -- -> "%status% %title%" in xmmsip-config 'user_format'
55 -- and "...%xmmsip_user ..blub..." in cfg_statusbar template
57 -- The mentionend 'not_running'-string is specified in xmmsip-config as
58 -- 'not_running' and will replace %xmmsip_user% whenever the XMMS InfoPipe
59 -- is not running (or found...)
61 -- If you are finally convinced that xmmsip_user is the only monitor you need
62 -- you may disable telling statusd about the other monitors. I have no idea, if
63 -- this has much impact on performance but who knows...
65 -- xmmsip-config -> do_monitors = false
67 -- speaking of configuration you might want a description of what the settings
68 -- do and what the defaults are :
69 --
70 -- interval : delay between checking the pipe (5 seconds)
71 -- user : user name (for xmms-session) (current user)
72 -- xmms_session : the xmms-session to use (0)
73 -- do_monitors : inform statusd of all monitors or just of xmmsip_user (true)
74 -- user_format : template for xmmsip_user (see in code)
75 -- not_running : replacement for xmmsip_user when no pipe is found
76 -- (see in code)
77 --
78 -- Requirements :
79 -- ion3 (tested with 20060305 gentoo ebuild)
80 -- lua (tested with 5.0.2)
81 -- xmms-infopipe v1.3 or compatible
82 -- I have not tested pipes from/for other players...
83 --
84 -- Serving suggestions :
85 -- I use the rotate_statusbar replacement for the standard statusbar as I
86 -- want to display a lot of things but not always...
87 -- XMMS-status information takes quite a bit of space so you might consider
88 -- doing it a bit like me .. but of course in your own special and
89 -- unique way. ;-)
91 -- This is my current setup :
93 -- cfg_statusbar (rotate_statusbar)
95 -- ...
96 -- rotate_statusbar.configurations = {
97 -- ...
98 -- ...
99 -- xmmsip = {
100 -- interval = 1 * 1000,
101 -- user_format = "XMMS (%status%) %title% (%left%/%time%)",
102 -- not_running = "Turn on the Radio!",
103 -- do_monitors = false,
104 -- },
105 -- ...
106 -- ...
108 -- rotate_statusbar.settings = {
109 -- ...
110 -- ...
111 -- all_statusbars = {
112 -- "[ %date || %xmmsip_user ]%filler%systray",
113 -- "[ %fortune ]%filler%systray",
114 -- ...
115 -- ...
117 -- This setup updates the information every second showing the status of
118 -- xmms, the current title, the time that is left and the total time
119 -- of the current song.
120 -- Additionally when xmms is not running a get a reminder to turn it on,
121 -- and as I do not need the other monitors they are disabled.
123 -- Happy listening!
125 -- Feel free to contact me if you discover bugs or want to comment on this.
128 -- You are free to distribute this software under the terms of the GNU
129 -- General Public License Version 2.
131 if not statusd_xmmsip then
132 statusd_xmmsip = {
133 interval=5*1000,
134 user = os.getenv("USER"),
135 xmms_session = 0,
136 do_monitors = true,
137 user_format = "%status%: %title% (%pos%/%time%, %plcur%/%pllen%, %kfreq%kHz@%kbitrate%kbps)",
138 not_running = "Not runnning...",
142 -- merge external settings with defaults
143 local settings = table.join (statusd.get_config("xmmsip"), statusd_xmmsip)
145 -- location of the infopipe
146 local xmmsinfopipe = "/tmp/xmms-info"
148 -- info-pipe is named by user and session
149 if settings.user ~= nil -- should not happen... but default should be okay anyway...
150 then
151 xmmsinfopipe = xmmsinfopipe .. "_" .. settings.user .. "." .. settings.xmms_session
154 -- mapping to InfoPipe-keys
155 local valueassoc = {
156 xmmsip_pllen = "Tunes in playlist",
157 xmmsip_plcur = "Currently playing",
158 xmmsip_file = "File",
159 xmmsip_title = "Title",
160 xmmsip_usectime = "uSecTime",
161 xmmsip_time = "Time",
162 xmmsip_usecpos = "uSecPosition",
163 xmmsip_pos = "Position",
164 xmmsip_left = "left",
165 xmmsip_usecleft = "usecleft",
166 xmmsip_status = "Status",
167 xmmsip_sstatus = "sstatus",
168 xmmsip_bitrate = "Current bitrate",
169 xmmsip_kbitrate = "kbitrate",
170 xmmsip_freq = "Samping Frequency", -- will this ever get fixed ?
171 xmmsip_kfreq = "kfreq",
172 xmmsip_channels = "Channels",
173 xmmsip_xmmsproto = "XMMS protocol version",
174 xmmsip_infover = "InfoPipe Plugin version",
177 -- changes all 'nil's in the infotable to '?' (for statusbar)
178 -- needed when the infopipe is not running or incompatible...
179 local function fixTable(it)
180 for _, v in pairs(valueassoc)
182 if it[v] == nil
183 then
184 it[v] = "?"
187 return it
190 -- some convenience values
191 local function addSpecialValues(it)
192 local bitrate = it[valueassoc["xmmsip_bitrate"]]
193 if bitrate ~= nil
194 then
195 it[valueassoc["xmmsip_kbitrate"]] = math.floor(bitrate / 1000)
197 local status = it[valueassoc["xmmsip_status"]]
198 if status ~= nil
199 then
200 it[valueassoc["xmmsip_sstatus"]] = string.lower(status)
202 local freq = it[valueassoc["xmmsip_freq"]]
203 if freq ~= nil
204 then
205 it[valueassoc["xmmsip_kfreq"]] = math.floor(freq / 1000)
207 local usectime = it[valueassoc["xmmsip_usectime"]]
208 local usecpos = it[valueassoc["xmmsip_usecpos"]]
209 -- streaming leaves time at zero
210 if ( ( usectime ~= nil ) and ( usecpos ~= nil ) )
211 then
212 -- force lua to coerce this to a number...
213 if ((usectime + 0) > 0)
214 then
215 -- not streaming
216 local usecleft = usectime - usecpos
217 local mins = math.floor( usecleft / (60 * 1000) )
218 local secs = math.floor( math.mod( usecleft, 60 * 1000 ) / 1000 )
219 local left = string.format("%i:%02i", mins, secs )
220 it[valueassoc["xmmsip_usecleft"]] = usecleft
221 it[valueassoc["xmmsip_left"]] = left
222 else
223 -- streaming
224 -- I would so like to use unicode for the
225 -- moebius but ion does not like it - yet...
226 it[valueassoc["xmmsip_time"]]=">>>"
227 it[valueassoc["xmmsip_left"]]="<<<"
228 it[valueassoc["xmmsip_usecleft"]]=0
231 return it
234 -- this formats the user_format-string
235 local function makeUserString(s, it)
236 local rval = s
237 for k, v in pairs(valueassoc)
239 -- it would be annoying to type 'xmmsip_' in front
240 -- of everything...
241 _, _, stripped = string.find(k, "xmmsip_(.*)")
242 rval = string.gsub(rval, "%%"..stripped.."%%", it[v])
244 return rval
247 -- our update timer
248 local xmmsip_timer
250 -- retrive information from the pipe - if it exists,
251 -- calculate some additional values and clean the table
252 -- from nilS
253 -- After that update statusd-monitors if the users wishes
254 -- and create the user-string from the template
255 local function fetch_data(partial_data)
256 local infotable = { } -- tabula rasa
257 local pipedata = ""
258 while partial_data
260 pipedata = pipedata .. partial_data
261 partial_data = coroutine.yield()
264 local running = true -- assume the best
266 if pipedata and pipedata ~= ""
267 then
268 for attribute, value in string.gfind(pipedata, "([^:]*):%s*([^\n]*)\n")
270 infotable[attribute] = value
272 else
273 -- obvious...
274 running = false
275 infotable[valueassoc["xmmsip_status"]]="Not running"
278 -- compute things like time left or divide things by 1000...
279 infotable = addSpecialValues(infotable)
280 -- scan for nil-values and fix them with '?'
281 infotable = fixTable(infotable)
283 -- if we are to update the monitors...
284 if settings.do_monitors
285 then
286 for k, v in pairs(valueassoc)
288 -- do so, but coerce to string
289 statusd.inform(k, ""..infotable[v])
293 -- create appropriate user-string
294 if running
295 then
296 statusd.inform("xmmsip_user", makeUserString(settings.user_format, infotable))
297 else
298 statusd.inform("xmmsip_user", settings.not_running)
301 xmmsip_timer:set(settings.interval, update_xmmsip)
304 -- fetch error (and discard...)
305 local function flush_stderr(partial_data)
306 local result = ""
307 while partial_data
309 result = result .. partial_data
310 partial_data = coroutine.yield()
313 -- I don't know what to do with the actual error...
314 -- This would be called a lot when the pipe is not
315 -- running...
318 -- update monitor with bgread
319 function update_xmmsip()
320 statusd.popen_bgread(
321 'cat ' .. xmmsinfopipe
322 , coroutine.wrap(fetch_data)
323 , coroutine.wrap(flush_stderr)
327 -- intialize timer
328 xmmsip_timer = statusd.create_timer()
329 -- start updating
330 update_xmmsip()