aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--awesompd.lua497
1 files changed, 497 insertions, 0 deletions
diff --git a/awesompd.lua b/awesompd.lua
new file mode 100644
index 0000000..f3721c0
--- /dev/null
+++ b/awesompd.lua
@@ -0,0 +1,497 @@
+local naughty = naughty
+local awful = awful
+
+awesompd = {}
+
+-- Constants
+awesompd.MOUSE_LEFT = 1
+awesompd.MOUSE_MIDDLE = 2
+awesompd.MOUSE_RIGHT = 3
+awesompd.MOUSE_SCROLL_UP = 4
+awesompd.MOUSE_SCROLL_DOWN = 5
+awesompd.NOTIFY_VOLUME = 1
+awesompd.NOTIFY_REPEAT = 2
+awesompd.NOTIFY_RANDOM = 3
+awesompd.NOTIFY_SINGLE = 4
+awesompd.NOTIFY_CONSUME = 5
+awesompd.PLAY_ICON = "/home/unlogic/.config/awesome/play_icon.png"
+awesompd.PAUSE_ICON = "/home/unlogic/.config/awesome/pause_icon.png"
+awesompd.PLAY_PAUSE_ICON = "/home/unlogic/.config/awesome/play_pause_icon.png"
+awesompd.STOP_ICON = "/home/unlogic/.config/awesome/stop_icon.png"
+awesompd.NEXT_ICON = "/home/unlogic/.config/awesome/next_icon.png"
+awesompd.PREV_ICON = "/home/unlogic/.config/awesome/prev_icon.png"
+awesompd.CHECK_ICON = "/home/unlogic/.config/awesome/check_icon.png"
+awesompd.RADIO_ICON = "/home/unlogic/.config/awesome/radio_icon.png"
+
+function awesompd:create()
+-- Initialization
+ instance = {}
+ setmetatable(instance,self)
+ self.__index = self
+ instance.current_server = 1
+ instance.widget = widget({ type = "textbox" })
+ instance.notification = nil
+ instance.scroll_pos = 1
+ instance.text = ""
+ instance.status = "Stopped"
+ instance.status_text = "Stopped"
+ instance.to_notify = false
+ instance.connected = true
+ instance.promptbox = {}
+ for s = 1, screen.count() do
+ instance.promptbox[s] = awful.widget.prompt({ layout = awful.widget.layout.horizontal.leftright })
+ end
+ instance.recreate_playback = true
+ instance.recreate_list = true
+ instance.recreate_servers = true
+ instance.recreate_options = true
+ instance.current_number = 0
+ instance.menu_shown = false
+
+-- Default user options
+ instance.servers = { { server = "localhost", port = 6600 } }
+ instance.font = "Monospace"
+ instance.scrolling = true
+ instance.output_size = 30
+ instance.update_interval = 10
+
+-- Widget configuration
+ instance.widget:add_signal("mouse::enter", function(c)
+ instance:notify_track()
+ end)
+ instance.widget:add_signal("mouse::leave", function(c)
+ instance:remove_hint()
+ end)
+
+ return instance
+end
+
+function awesompd:run()
+ self:update_track()
+ self:update_state()
+ awful.hooks.timer.register(1, function () self:update_widget() end)
+ awful.hooks.timer.register(self.update_interval, function () self:update_track() end)
+end
+
+-- Function that registers buttons on the widget.
+function awesompd:register_buttons(buttons)
+ widget_buttons = {}
+ for b=1,table.getn(buttons) do
+ mods = self.split(buttons[b][1],"+")
+ table.insert(widget_buttons, button(mods, buttons[b][2], buttons[b][3]))
+ end
+ self.widget:buttons(widget_buttons)
+end
+
+-- /// Group of mpc command functions ///
+
+function awesompd:command(com,hook)
+ io.popen(self:mpcquery() .. com):read("*all")
+ t = hook and hook(self)
+end
+
+function awesompd:command_toggle()
+ return function()
+ self:command("toggle",self.update_track)
+ end
+end
+
+function awesompd:command_next_track()
+ return function()
+ self:command("next",self.update_track)
+ end
+end
+
+function awesompd:command_prev_track()
+ return function()
+ self:command("seek 0")
+ self:command("prev",self.update_track)
+ end
+end
+
+function awesompd:command_play_specific(n)
+ return function()
+ self:command("play " .. n,self.update_track)
+ end
+end
+
+function awesompd:command_stop()
+ return function()
+ self:command("stop",self.update_track)
+ end
+end
+
+function awesompd:command_volume_up()
+ return function()
+ self:command("volume +5",self.update_state)
+ self:notify_state(self.NOTIFY_VOLUME)
+ end
+end
+
+function awesompd:command_volume_down()
+ return function()
+ self:command("volume -5",self.update_state)
+ self:notify_state(self.NOTIFY_VOLUME)
+ end
+end
+
+function awesompd:command_random_toggle()
+ return function()
+ self:command("random",self.update_state)
+ self:notify_state(self.NOTIFY_RANDOM)
+ end
+end
+
+function awesompd:command_repeat_toggle()
+ return function()
+ self:command("repeat",self.update_state)
+ self:notify_state(self.NOTIFY_REPEAT)
+ end
+end
+
+function awesompd:command_single_toggle()
+ return function()
+ self:command("single",self.update_state)
+ self:notify_state(self.NOTIFY_SINGLE)
+ end
+end
+
+function awesompd:command_consume_toggle()
+ return function()
+ self:command("consume",self.update_state)
+ self:notify_state(self.NOTIFY_CONSUME)
+ end
+end
+
+function awesompd:command_echo_prompt()
+ return function()
+ self:run_prompt("Sample text: ",function(s)
+ self:add_hint("Prompt",s)
+ end)
+ end
+end
+
+-- /// End of mpc command functions ///
+
+-- /// Menu generation functions ///
+
+function awesompd:command_show_menu()
+ return function()
+ self:remove_hint()
+ self:check_list()
+ self:check_playlists()
+ if self.recreate_playback or
+ self.recreate_options or
+ self.recreate_list then
+ -- self.recreate_playlists then
+ if self.main_menu ~= nil then
+ self.main_menu:hide()
+ end
+ local new_menu = {}
+ if self.connected then
+ table.insert(new_menu, { "Playback", self:get_playback_menu() })
+-- table.insert(new_menu, { "Options", self:get_options_menu() })
+ table.insert(new_menu, { "List", self:get_list_menu() })
+ end
+ table.insert(new_menu, { "Servers", self:get_servers_menu() })
+-- new_menu[3] = { "Playlists", self:get_playlists_menu() }
+ self.main_menu = awful.menu({ items = new_menu,
+ width = 300
+ })
+ end
+ self.main_menu:toggle()
+ end
+end
+
+function awesompd:get_playback_menu()
+ if self.recreate_playback then
+ local new_menu = {}
+ table.insert(new_menu, { "Play\\Pause", self:command_toggle(), self.PLAY_PAUSE_ICON })
+ if self.connected and self.status ~= "Stopped" then
+ if self.current_number ~= 1 then
+ table.insert(new_menu, { "Prev: " .. self.list_array[self.current_number - 1],
+ self:command_prev_track(), self.PREV_ICON })
+ end
+ if self.current_number ~= table.getn(self.list_array) then
+ table.insert(new_menu, { "Next: " .. self.list_array[self.current_number + 1],
+ self:command_next_track(), self.NEXT_ICON })
+ end
+ table.insert(new_menu, { "Stop", self:command_stop(), self.STOP_ICON })
+ end
+ self.recreate_playback = false
+ playback_menu = new_menu
+ end
+ return playback_menu
+end
+
+function awesompd:get_list_menu()
+ if self.recreate_list then
+ local new_menu = {}
+ for i = 1, table.getn(self.list_array) do
+ new_menu[i] = {self.list_array[i],
+ self:command_play_specific(i),
+ self.current_number == i and
+ (self.status == "Playing" and self.PLAY_ICON or self.PAUSE_ICON)
+ or nil}
+ end
+ self.recreate_list = false
+ self.list_menu = new_menu
+ end
+ return self.list_menu
+end
+
+function awesompd:get_servers_menu()
+ if self.recreate_servers then
+ local new_menu = {}
+ for i = 1, table.getn(self.servers) do
+ table.insert(new_menu, {"Server: " .. self.servers[i].server ..
+ ", port: " .. self.servers[i].port,
+ function() self:change_server(i) end,
+ i == self.current_server and self.RADIO_ICON or nil})
+ end
+ self.servers_menu = new_menu
+ end
+ return self.servers_menu
+end
+
+function awesompd:get_options_menu()
+ if self.recreate_options then
+ local new_menu = {}
+ update_state()
+ table.insert(new_menu, { "Repeat", self:command_repeat_toggle(),
+ self.state_repeat == "on" and self.CHECK_ICON or nil})
+ table.insert(new_menu, { "Random", self:command_random_toggle(),
+ self.state_random == "on" and self.CHECK_ICON or nil})
+ table.insert(new_menu, { "Single", self:command_single_toggle(),
+ self.state_single == "on" and self.CHECK_ICON or nil})
+ table.insert(new_menu, { "Consume", self:command_consume_toggle(),
+ self.state_consume == "on" and self.CHECK_ICON or nil})
+ self.options_menu = new_menu
+ self.recreate_options = false
+ return self.options_menu
+ end
+end
+
+function awesompd:check_list()
+ local bus = io.popen(self:mpcquery() .. "playlist")
+ local info = bus:read("*all")
+ bus:close()
+ if info ~= self.list_line then
+ self.list_line = info
+ self.list_array = self.split(info,"\n")
+ self.recreate_list = true
+ end
+end
+
+function awesompd:check_playlists()
+ local bus = io.popen(self:mpcquery() .. "lsplaylists")
+ local info = bus:read("*all")
+ bus:close()
+ if info ~= self.playlists_line then
+ self.playlists_line = info
+ self.recreate_playlists = true
+ end
+end
+
+function awesompd:change_server(server_number)
+ self.current_server = server_number
+ self:remove_hint()
+ self.recreate_playback = true
+ self.recreate_list = true
+ self.recreate_playlists = true
+ self.recreate_servers = true
+ self:update_track()
+ self:update_state()
+end
+
+-- /// End of menu generation functions ///
+
+function awesompd:add_hint(hint_title, hint_text)
+ self:remove_hint()
+ self.notification = naughty.notify({ title = hint_title
+ , text = hint_text
+ , timeout = 5
+ , position = "top_right"
+ })
+end
+
+function awesompd:remove_hint()
+ if self.notification ~= nil then
+ naughty.destroy(self.notification)
+ self.notification = nil
+ end
+end
+
+function awesompd:notify_track()
+ if self.status ~= "Stopped" then
+ self:add_hint(self.status_text, self.text)
+ end
+end
+
+function awesompd:notify_state(state_changed)
+ state_array = { "Volume: " .. self.state_volume ,
+ "Repeat: " .. self.state_repeat ,
+ "Random: " .. self.state_random ,
+ "Single: " .. self.state_single ,
+ "Consume: " .. self.state_consume }
+ state_header = state_array[state_changed]
+ table.remove(state_array,state_changed)
+ full_state = state_array[1]
+ for i = 2, table.getn(state_array) do
+ full_state = full_state .. "\n" .. state_array[i]
+ end
+ self:add_hint(state_header, full_state)
+end
+
+function awesompd:wrap_output(text)
+ return '<span font="' .. self.font .. '">| ' .. text .. ' |</span>'
+end
+
+function awesompd.split (s,t)
+ local l = {n=0}
+ local f = function (s)
+ l.n = l.n + 1
+ l[l.n] = s
+ end
+ local p = "%s*(.-)%s*"..t.."%s*"
+ s = string.gsub(s,"^%s+","")
+ s = string.gsub(s,"%s+$","")
+ s = string.gsub(s,p,f)
+ l.n = l.n + 1
+ l[l.n] = string.gsub(s,"(%s%s*)$","")
+ return l
+end
+
+function awesompd:mpcquery()
+ return "mpc -h " .. self.servers[self.current_server].server ..
+ " -p " .. self.servers[self.current_server].port .. " "
+end
+
+function awesompd:set_text(text)
+ self.widget.text = self:wrap_output(text)
+end
+
+function awesompd.find_pattern(text, pattern, start)
+ return string.sub(text, string.find(text, pattern, start))
+end
+
+function awesompd:scroll_text(text)
+ if self.output_size > string.len(text) then
+ result = text
+ elseif self.scroll_pos + self.output_size - 1 > string.len(text) then
+ text = text .. " "
+ result = string.sub(text, self.scroll_pos)
+ result = result .. string.sub(text, 1, self.scroll_pos + self.output_size - 1 - string.len(text))
+ self.scroll_pos = self.scroll_pos + 1
+ if self.scroll_pos > string.len(text) then
+ self.scroll_pos = 1
+ end
+ else
+ text = text .. " "
+ result = string.sub(text, self.scroll_pos, self.scroll_pos + self.output_size - 1)
+ self.scroll_pos = self.scroll_pos + 1
+ end
+ return result
+end
+
+function awesompd:update_widget()
+ self:set_text(self:scroll_text(self.text))
+ self:check_notify()
+end
+
+function awesompd:check_notify()
+ if self.to_notify then
+ self:notify_track()
+ self.to_notify = false
+ end
+end
+
+function awesompd:notify_disconnect()
+ self:add_hint("Disconnected", "Cannot connect to " .. self.servers[self.current_server].server ..
+ " on port " .. self.servers[self.current_server].port)
+end
+
+function awesompd:update_track()
+ local bus = io.popen(self:mpcquery())
+ local info = bus:read("*all")
+ bus:close()
+ local info_ar = self.split(info,"\n")
+ if string.len(info) == 0 then
+ self.text = "Disconnected"
+ if self.connected then
+ self:notify_disconnect()
+ self.connected = false
+ self.recreate_list = true
+ end
+ elseif string.find(info_ar[1],"volume:") then
+ self.connected = true
+ self.text = "MPD stopped"
+ if self.status ~= "Stopped" then
+ self.status = "Stopped"
+ self.current_number = 0
+ self.recreate_playback = true
+ self.recreate_list = true
+ end
+ else
+ self.connected = true
+ local new_track = info_ar[1]
+ if new_track ~= self.text then
+ self.text = new_track
+ self.to_notify = true
+ self.recreate_playback = true
+ self.recreate_list = true
+ self.current_number = tonumber(self.find_pattern(info_ar[2],"%d+"))
+ end
+ local tmp_pst = string.find(info_ar[2],"%d+%:%d+%/")
+ local progress = self.find_pattern(info_ar[2],"%#%d+/%d+") .. " " .. string.sub(info_ar[2],tmp_pst)
+ newstatus = "Playing"
+ if string.find(info_ar[2],"paused") then
+ newstatus = "Paused"
+ end
+ if newstatus ~= self.status then
+ self.to_notify = true
+ self.recreate_list = true
+ end
+ self.status = newstatus
+ self.status_text = self.status .. " " .. progress
+ end
+end
+
+function awesompd:update_state()
+ local bus = io.popen(self:mpcquery())
+ local info = bus:read("*all")
+ bus:close()
+ local info_ar = self.split(info,"\n")
+ state_string = info_ar[3]
+ if string.find(info_ar[1],"volume:") then
+ state_string = info_ar[1]
+ end
+ self.state_volume = self.find_pattern(state_string,"%d+%% ")
+ if string.find(state_string,"repeat: on") then
+ self.state_repeat = "on"
+ else
+ self.state_repeat = "off"
+ end
+ if string.find(state_string,"random: on") then
+ self.state_random = "on"
+ else
+ self.state_random = "off"
+ end
+ if string.find(state_string,"single: on") then
+ self.state_single = "on"
+ else
+ self.state_single = "off"
+ end
+ if string.find(state_string,"consume: on") then
+ self.state_consume = "on"
+ else
+ self.state_consume = "off"
+ end
+ self.recreate_options = true
+end
+
+function awesompd:run_prompt(welcome,hook)
+ awful.prompt.run({ prompt = welcome },
+ self.promptbox[mouse.screen].widget,
+ hook)
+end