1 -- Authors: Hendrik Iben <hiben@tzi.de>
2 -- License: GPL, version 2
3 -- Last Changed: 2006-03-23
5 -- statusd_mocmon.lua v20060323
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...
17 -- Written by Hendrik Iben < hiben at tzi dot de >
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
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
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%'
53 -- "...%mocmon_state %mocmon_title ..blub..." in cfg_statusbar template
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
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 :
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)
79 -- ion3 (tested with 20060305 gentoo ebuild)
80 -- lua (tested with 5.0.2)
81 -- moc (tested with 2.4.0)
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
90 -- This is my current setup :
92 -- cfg_statusbar (rotate_statusbar)
95 -- rotate_statusbar.configurations = {
99 -- interval = 1 * 1000,
100 -- user_format = "(%sstate%) %artist% - %songtitle% (%pos%/%left%/%time%)",
101 -- stoppped = "MOC up your life!",
102 -- do_monitors = false,
107 -- rotate_statusbar.settings = {
110 -- all_statusbars = {
111 -- "[ %date || MOC %mocmon_user ]%filler%systray",
112 -- "[ %fortune ]%filler%systray",
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.
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
134 user_format
= "(%sstate%) %artist% - %songtitle% (%pos%/%left%/%time%)",
135 stopped
= "moc is stopped...",
140 -- merge external settings with defaults
141 local settings
= table.join (statusd
.get_config("mocmon"), statusd_mocmon
)
143 -- mapping to moc-Info
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
)
175 -- some convenience values
176 local function addSpecialValues(it
)
177 local state
= it
[valueassoc
["mocmon_state"]]
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
== "")
188 it
[valueassoc
["mocmon_sectime"]]
=0
189 it
[valueassoc
["mocmon_time"]]
=">>>"
192 if (not left
) or (left
== "")
194 it
[valueassoc
["mocmon_left"]]
="<<<"
195 it
[valueassoc
["mocmon_secleft"]]
=-1
197 local _
, _
, min, sec
= string.find(left
, "([0-9]+):([0-9]+)")
200 it
[valueassoc
["mocmon_secleft"]]
=min*60+sec
202 it
[valueassoc
["monmon_secleft"]]
=0
209 -- this formats the user_format-string
210 local function makeUserString(s
, it
)
212 for k
, v
in pairs(valueassoc
)
214 -- it would be annoying to type 'mocmon_' in front
216 _
, _
, stripped
= string.find(k
, "mocmon_(.*)")
217 rval
= string.gsub(rval
, "%%"..stripped
.."%%", it
[v
])
225 -- retrive information from moc - if found.
226 -- calculate some additional values and clean the table
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
235 mocdata
= mocdata
.. partial_data
236 partial_data
= coroutine
.yield()
239 local running
= true -- assume the best
241 if mocdata
and mocdata
~= ""
243 for attribute
, value
in string.gfind(mocdata
, "([^:]*):([^\n]*)\n")
245 infotable
[attribute
] = string.gsub(value
, "^%s*(.*)", "%1")
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"
264 -- if we are to update the monitors...
265 if settings
.do_monitors
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
)
277 statusd
.inform("mocmon_user", makeUserString(settings
.user_format
, infotable
))
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
)
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
299 -- update monitor with bgread
300 function update_mocmon()
301 statusd
.popen_bgread(
303 , coroutine
.wrap(fetch_data
)
304 , coroutine
.wrap(flush_stderr
)
309 mocmon_timer
= statusd
.create_timer()