Released version 3-2014010502
[notion.git] / contrib / statusd / statusd_mocmon.lua
blobd6ed9dc4505a43d23aa0ee4f5650e86d96c34535
1 -- Authors: Hendrik Iben <hiben@tzi.de>
2 -- License: GPL, version 2
3 -- Last Changed: 2006-03-23
4 --
5 -- statusd_mocmon.lua v20060323
6 --
7 -- Just another monitor for moc.
8 -- Believe it or not, while I was working on fixing the crash-bug in
9 -- statusd_xmmsip.lua I stumbled over statusd_mocp.lua for popen_bgread.
10 -- This was the moment I realized a) I finally found an audio player I really
11 -- and fully like (I had my journey on console players the day before) and
12 -- b) I should not have written xmmsip as I am going to moc up my life... :-)
14 -- But when I took a closer look at the moc scripts I really did not like what
15 -- they offer and adapting the mocmon stuff for them is quite easy...
16 --
17 -- Written by Hendrik Iben < hiben at tzi dot de >
19 -- How to use :
20 -- mocmon provides a lot of statusd-monitors
21 -- You can compose the text displayed in your statusbar using these individual
22 -- monitors or/and you may specify a string with a setup of the values you
23 -- are interested in.
25 -- The monitors :
26 -- mocmon_file : Current file played
27 -- mocmon_title : Current file's title
28 -- mocmon_songtitle : Current song's title
29 -- mocmon_artist : Artist performing current song
30 -- mocmon_album : Album of current song
31 -- mocmon_sectime : Length of file in seconds (0 for streams)
32 -- mocmon_time : Length of file in minutes:seconds or '>>>' for streams
33 -- mocmon_secpos : Position in file in seconds
34 -- mocmon_pos : Position in file in minutes:seconds
35 -- mocmon_secleft : Time left in seconds (-1 for streams)
36 -- mocmon_left : Time left in minutes:seconds or "<<<" for streams
37 -- mocmon_state : moc's status : (PLAY, PAUSE, STOP, NOT RUNNING)
38 -- mocmon_sstate : same as above but all lowercase
39 -- mocmon_bitrate : Current bitrate
40 -- mocmon_rate : Sampling frequency
41 --
42 -- mocmon_user : String resulting from 'user_format'-string
43 -- or 'stopped'-string
45 -- While it is perfectly legal to use these directly in your statusbar I
46 -- recommend you to only use mocmon_user and configure the format string.
47 -- This way you do not get a '?' for every monitor when moc is not running...
49 -- Setting up the 'user_format'-string is done by forming a string where each
50 -- mocmon_x-monitor is referenced to by '%x%'
51 --
52 -- example :
53 -- "...%mocmon_state %mocmon_title ..blub..." in cfg_statusbar template
54 --
55 -- -> "%state% %title%" in mocmon-config 'user_format'
56 -- and "...%mocmon_user ..blub..." in cfg_statusbar template
58 -- The mentionend 'stopped'-string is specified in mocmon-config as
59 -- 'stopped' and will replace %mocmon_user% whenever moc is stopped or
60 -- mocp is not found.
62 -- If you are finally convinced that mocmon_user is the only monitor you need
63 -- you may disable telling statusd about the other monitors. I have no idea, if
64 -- this has much impact on performance but who knows...
66 -- mocmon-config -> do_monitors = false
68 -- speaking of configuration you might want a description of what the settings
69 -- do and what the defaults are :
70 --
71 -- mocinfo : command to query moc (mocp -i)
72 -- interval : delay between checking moc (5 seconds)
73 -- do_monitors : inform statusd of all monitors or just of mocmon_user (true)
74 -- user_format : template for mocmon_user (see in code)
75 -- stoppped : replacement for mocmon_user when mocp is not found or moc
76 -- is stoppped (see in code)
77 --
78 -- Requirements :
79 -- ion3 (tested with 20060305 gentoo ebuild)
80 -- lua (tested with 5.0.2)
81 -- moc (tested with 2.4.0)
82 --
83 -- Serving suggestions :
84 -- I use the rotate_statusbar replacement for the standard statusbar as I
85 -- want to display a lot of things but not always...
86 -- moc-status information takes quite a bit of space so you might consider
87 -- doing it a bit like me .. but of course in your own special and
88 -- unique way. ;-)
90 -- This is my current setup :
92 -- cfg_statusbar (rotate_statusbar)
94 -- ...
95 -- rotate_statusbar.configurations = {
96 -- ...
97 -- ...
98 -- mocmon = {
99 -- interval = 1 * 1000,
100 -- user_format = "(%sstate%) %artist% - %songtitle% (%pos%/%left%/%time%)",
101 -- stoppped = "MOC up your life!",
102 -- do_monitors = false,
103 -- },
104 -- ...
105 -- ...
107 -- rotate_statusbar.settings = {
108 -- ...
109 -- ...
110 -- all_statusbars = {
111 -- "[ %date || MOC %mocmon_user ]%filler%systray",
112 -- "[ %fortune ]%filler%systray",
113 -- ...
114 -- ...
116 -- This setup updates the information every second showing the status of
117 -- moc, the current title, the time that is left and the total time
118 -- of the current song.
119 -- Additionally when moc is not running a get a reminder to turn it on,
120 -- and as I do not need the other monitors they are disabled.
122 -- Happy listening!
124 -- Feel free to contact me if you discover bugs or want to comment on this.
127 -- You are free to distribute this software under the terms of the GNU
128 -- General Public License Version 2.
130 if not statusd_mocmon then
131 statusd_mocmon = {
132 interval=5*1000,
133 do_monitors = true,
134 user_format = "(%sstate%) %artist% - %songtitle% (%pos%/%left%/%time%)",
135 stopped = "moc is stopped...",
136 mocinfo = "mocp -i",
140 -- merge external settings with defaults
141 local settings = table.join (statusd.get_config("mocmon"), statusd_mocmon)
143 -- mapping to moc-Info
144 local valueassoc = {
145 mocmon_file = "File",
146 mocmon_title = "Title",
147 mocmon_songtitle = "SongTitle",
148 mocmon_artist = "Artist",
149 mocmon_album = "Album",
150 mocmon_sectime = "TotalSec",
151 mocmon_time = "TotalTime",
152 mocmon_secpos = "CurrentSec",
153 mocmon_pos = "CurrentTime",
154 mocmon_left = "TimeLeft",
155 mocmon_secleft = "secleft",
156 mocmon_state = "State",
157 mocmon_sstate = "sstate",
158 mocmon_bitrate = "Bitrate",
159 mocmon_rate = "Rate",
162 -- changes all 'nil's in the infotable to '?' (for statusbar)
163 -- needed when the infopipe is not running or incompatible...
164 local function fixTable(it)
165 for _, v in pairs(valueassoc)
167 if it[v] == nil
168 then
169 it[v] = "?"
172 return it
175 -- some convenience values
176 local function addSpecialValues(it)
177 local state = it[valueassoc["mocmon_state"]]
178 if state ~= nil
179 then
180 it[valueassoc["mocmon_sstate"]] = string.lower(state)
183 local sectime = it[valueassoc["mocmon_sectime"]]
184 local left = it[valueassoc["mocmon_left"]]
186 if (not sectime) or (sectime == "")
187 then
188 it[valueassoc["mocmon_sectime"]]=0
189 it[valueassoc["mocmon_time"]]=">>>"
192 if (not left) or (left == "")
193 then
194 it[valueassoc["mocmon_left"]]="<<<"
195 it[valueassoc["mocmon_secleft"]]=-1
196 else
197 local _, _, min, sec = string.find(left, "([0-9]+):([0-9]+)")
198 if min and sec
199 then
200 it[valueassoc["mocmon_secleft"]]=min*60+sec
201 else
202 it[valueassoc["monmon_secleft"]]=0
206 return it
209 -- this formats the user_format-string
210 local function makeUserString(s, it)
211 local rval = s
212 for k, v in pairs(valueassoc)
214 -- it would be annoying to type 'mocmon_' in front
215 -- of everything...
216 _, _, stripped = string.find(k, "mocmon_(.*)")
217 rval = string.gsub(rval, "%%"..stripped.."%%", it[v])
219 return rval
222 -- our update timer
223 local mocmon_timer
225 -- retrive information from moc - if found.
226 -- calculate some additional values and clean the table
227 -- from nilS
228 -- After that update statusd-monitors if the users wishes
229 -- and create the user-string from the template
230 local function fetch_data(partial_data)
231 local infotable = { } -- tabula rasa
232 local mocdata = ""
233 while partial_data
235 mocdata = mocdata .. partial_data
236 partial_data = coroutine.yield()
239 local running = true -- assume the best
241 if mocdata and mocdata ~= ""
242 then
243 for attribute, value in string.gfind(mocdata, "([^:]*):([^\n]*)\n")
245 infotable[attribute] = string.gsub(value, "^%s*(.*)", "%1")
247 else
248 -- obvious...
249 running = false
250 infotable[valueassoc["mocmon_state"]]="NOT RUNNING"
253 -- compute things like time left or divide things by 1000...
254 infotable = addSpecialValues(infotable)
255 -- scan for nil-values and fix them with '?'
256 infotable = fixTable(infotable)
258 local stopped = false
259 if infotable[valueassoc["mocmon_state"]] == "STOP"
260 then
261 stopped = true
264 -- if we are to update the monitors...
265 if settings.do_monitors
266 then
267 for k, v in pairs(valueassoc)
269 -- do so, but coerce to string
270 statusd.inform(k, ""..infotable[v])
274 -- create appropriate user-string
275 if running and (not stopped)
276 then
277 statusd.inform("mocmon_user", makeUserString(settings.user_format, infotable))
278 else
279 statusd.inform("mocmon_user", settings.not_running)
282 mocmon_timer:set(settings.interval, update_mocmon)
285 -- fetch error (and discard...)
286 local function flush_stderr(partial_data)
287 local result = ""
288 while partial_data
290 result = result .. partial_data
291 partial_data = coroutine.yield()
294 -- I don't know what to do with the actual error...
295 -- This would be called a lot when mocp is not
296 -- found...
299 -- update monitor with bgread
300 function update_mocmon()
301 statusd.popen_bgread(
302 settings.mocinfo
303 , coroutine.wrap(fetch_data)
304 , coroutine.wrap(flush_stderr)
308 -- intialize timer
309 mocmon_timer = statusd.create_timer()
310 -- start updating
311 update_mocmon()