X-Git-Url: https://git.rmz.io/dotfiles.git/blobdiff_plain/3beaf9036986d749752eb658a7c83a1c69d04dd4..f737a40a8269639bb3364df31c4d9888e9f12d98:/awesome/widgets/awesompd/awesompd.lua diff --git a/awesome/widgets/awesompd/awesompd.lua b/awesome/widgets/awesompd/awesompd.lua deleted file mode 100644 index 8494003..0000000 --- a/awesome/widgets/awesompd/awesompd.lua +++ /dev/null @@ -1,1219 +0,0 @@ ---------------------------------------------------------------------------- --- @author Alexander Yakushev --- @copyright 2010-2013 Alexander Yakushev --- @release v1.2.4 ---------------------------------------------------------------------------- - -local wibox = require("wibox") -local awful = require('awful') -local beautiful = require('beautiful') -local naughty = require('naughty') -local format = string.format - -local module_path = (...):match ("(.+/)[^/]+$") or "" - -local awesompd = {} - --- Function for checking icons and modules. Checks if a file exists, --- and if it does, returns the path to file, nil otherwise. -function awesompd.try_load(file) - if awful.util.file_readable(file) then - return file - end -end - --- Function for loading modules. -function awesompd.try_require(module) - if awesompd.try_load(awful.util.getdir("config") .. '/'.. - module_path .. module .. ".lua") then - return require(module_path .. module) - else - return require(module) - end -end - -local utf8 = awesompd.try_require("utf8") -asyncshell = awesompd.try_require("asyncshell") -local jamendo = awesompd.try_require("jamendo") - --- Constants -awesompd.PLAYING = "Playing" -awesompd.PAUSED = "Paused" -awesompd.STOPPED = "MPD stopped" -awesompd.DISCONNECTED = "Disconnected" - -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.FORMAT_MP3 = jamendo.FORMAT_MP3 -awesompd.FORMAT_OGG = jamendo.FORMAT_OGG -awesompd.ESCAPE_SYMBOL_MAPPING = {} -awesompd.ESCAPE_SYMBOL_MAPPING["&"] = "&" --- Menus do not handle symbol escaping correctly, so they need their --- own mapping. -awesompd.ESCAPE_MENU_SYMBOL_MAPPING = {} -awesompd.ESCAPE_MENU_SYMBOL_MAPPING["&"] = "'n'" - --- /// Current track variables and functions /// - --- Returns a string for the given track to be displayed in the widget --- and notification. -function awesompd.get_display_name(track) - if track.display_name then - return track.display_name - elseif track.artist_name and track.track_name then - return track.artist_name .. " - " .. track.name - end -end - --- Returns a track display name, album name (if exists) and album --- release year (if exists). -function awesompd.get_extended_info(track) - local result = awesompd.get_display_name(track) - if track.album_name then - result = result .. "\n" .. track.album_name - end - if track.year then - result = result .. "\n" .. track.year - end - return result -end - --- Returns true if the current status is either PLAYING or PAUSED -function awesompd:playing_or_paused() - return self.status == awesompd.PLAYING - or self.status == awesompd.PAUSED -end - --- /// Helper functions /// - --- Just like awful.util.pread, but takes an argument how to read like --- "*line" or "*all". -function awesompd.pread(com, mode) - local f = io.popen(com, 'r') - local result = nil - if f then - result = f:read(mode) - f:close() - end - return result -end - --- Slightly modified function awful.util.table.join. -function awesompd.ajoin(buttons) - local result = {} - for i = 1, #buttons do - if buttons[i] then - for k, v in pairs(buttons[i]) do - if type(k) == "number" then - table.insert(result, v) - else - result[k] = v - end - end - end - end - return result - end - --- Splits a given string with linebreaks into an array. -function awesompd.split(s) - local l = { n = 0 } - if s == "" then - return l - end - s = s .. "\n" - local f = function (s) - l.n = l.n + 1 - l[l.n] = s - end - local p = "%s*(.-)%s*\n%s*" - s = string.gsub(s,p,f) - return l -end - --- Returns the given string if it is not nil or non-empty, otherwise --- returns nil. -local function non_empty(s) - if s and s ~= "" then - return s - end -end - --- Icons - -function awesompd.load_icons(path) - awesompd.ICONS = {} - awesompd.ICONS.PLAY = awesompd.try_load(path .. "/play_icon.png") - awesompd.ICONS.PAUSE = awesompd.try_load(path .. "/pause_icon.png") - awesompd.ICONS.PLAY_PAUSE = awesompd.try_load(path .. "/play_pause_icon.png") - awesompd.ICONS.STOP = awesompd.try_load(path .. "/stop_icon.png") - awesompd.ICONS.NEXT = awesompd.try_load(path .. "/next_icon.png") - awesompd.ICONS.PREV = awesompd.try_load(path .. "/prev_icon.png") - awesompd.ICONS.CHECK = awesompd.try_load(path .. "/check_icon.png") - awesompd.ICONS.RADIO = awesompd.try_load(path .. "/radio_icon.png") - awesompd.ICONS.DEFAULT_ALBUM_COVER = - awesompd.try_load(path .. "/default_album_cover.png") -end - --- Function that returns a new awesompd object. -function awesompd:create() --- Initialization - local instance = {} - setmetatable(instance,self) - self.__index = self - instance.current_server = 1 - instance.widget = wibox.layout.fixed.horizontal() - instance.notification = nil - instance.scroll_pos = 1 - instance.text = "" - instance.to_notify = false - instance.album_cover = nil - instance.current_track = { } - instance.recreate_menu = true - instance.recreate_playback = true - instance.recreate_list = true - instance.recreate_servers = true - instance.recreate_options = true - instance.recreate_jamendo_formats = true - instance.recreate_jamendo_order = true - instance.recreate_jamendo_browse = true - instance.current_number = 0 - instance.menu_shown = false - instance.state_volume = "NaN" - instance.state_repeat = "NaN" - instance.state_random = "NaN" - instance.state_single = "NaN" - instance.state_consume = "NaN" - --- Default user options - instance.servers = { { server = "localhost", port = 6600 } } - instance.font = "Monospace" - instance.font_color = beautiful.fg_normal - instance.background = beautiful.bg_normal - instance.scrolling = true - instance.output_size = 30 - instance.update_interval = 10 - instance.path_to_icons = "" - instance.ldecorator = " " - instance.rdecorator = " " - instance.jamendo_format = awesompd.FORMAT_MP3 - instance.show_album_cover = true - instance.album_cover_size = 50 - instance.browser = "firefox" - --- Widget configuration - instance.widget:connect_signal("mouse::enter", function(c) - instance:notify_track() - end) - instance.widget:connect_signal("mouse::leave", function(c) - instance:hide_notification() - end) - return instance -end - --- Registers timers for the widget -function awesompd:run() - self.load_icons(self.path_to_icons) - jamendo.set_current_format(self.jamendo_format) - if self.album_cover_size > 100 then - self.album_cover_size = 100 - end - - self.text_widget = wibox.widget.textbox() - if self.widget_icon then - self.icon_widget = wibox.widget.imagebox() - self.icon_widget:set_image(self.widget_icon) - self.widget:add(self.icon_widget) - end - self.widget:add(self.text_widget) - - self:update_track() - self:check_playlists() - - if scheduler then - scheduler.register_recurring("awesompd_scroll", 1, - function() self:update_widget() end) - scheduler.register_recurring("awesompd_update", self.update_interval, - function() self:update_track() end) - else - self.update_widget_timer = timer({ timeout = 1 }) - self.update_widget_timer:connect_signal("timeout", function() - self:update_widget() - end) - self.update_widget_timer:start() - self.update_track_timer = timer({ timeout = self.update_interval }) - self.update_track_timer:connect_signal("timeout", function() - self:update_track() - end) - self.update_track_timer:start() - end -end - --- Function that registers buttons on the widget. -function awesompd:register_buttons(buttons) - widget_buttons = {} - self.global_bindings = {} - for b=1, #buttons do - if type(buttons[b][1]) == "string" then - mods = { buttons[b][1] } - else - mods = buttons[b][1] - end - if type(buttons[b][2]) == "number" then - -- This is a mousebinding, bind it to the widget - table.insert(widget_buttons, - awful.button(mods, buttons[b][2], buttons[b][3])) - else - -- This is a global keybinding, remember it for later usage in append_global_keys - table.insert(self.global_bindings, awful.key(mods, buttons[b][2], buttons[b][3])) - end - end - self.widget:buttons(self.ajoin(widget_buttons)) -end - --- Takes the current table with keybindings and adds widget's own --- global keybindings that were specified in register_buttons. --- If keytable is not specified, then adds bindings to default --- globalkeys table. If specified, then adds bindings to keytable and --- returns it. -function awesompd:append_global_keys(keytable) - if keytable then - for i = 1, #self.global_bindings do - keytable = awful.util.table.join(keytable, self.global_bindings[i]) - end - return keytable - else - for i = 1, #self.global_bindings do - globalkeys = awful.util.table.join(globalkeys, self.global_bindings[i]) - end - end -end - --- /// Group of mpc command functions /// - --- Returns a mpc command with all necessary parameters. Boolean --- human_readable argument configures if the command special --- formatting of the output (to be later used in parsing) should not --- be used. -function awesompd:mpcquery(human_readable) - local result = - "mpc -h " .. self.servers[self.current_server].server .. - " -p " .. self.servers[self.current_server].port .. " " - if human_readable then - return result - else - return result ..' -f "%file%-<>-%name%-<>-%title%-<>-%artist%-<>-%album%" ' - end -end - --- Takes a command to mpc and a hook that is provided with awesompd --- instance and the result of command execution. -function awesompd:command(com,hook) - local file = io.popen(self:mpcquery() .. com) - if hook then - hook(self,file) - end - file:close() -end - --- Takes a command to mpc and read mode and returns the result. -function awesompd:command_read(com, mode) - mode = mode or "*line" - self:command(com, function(_, f) - result = f:read(mode) - end) - return result -end - -function awesompd:command_playpause() - 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_stop() - return function() - self:command("stop",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_volume_up() - return function() - self:command("volume +5") - self:update_track() -- Nasty! I should replace it with proper callback later. - self:notify_state(self.NOTIFY_VOLUME) - end -end - -function awesompd:command_volume_down() - return function() - self:command("volume -5") - self:update_track() - self:notify_state(self.NOTIFY_VOLUME) - end -end - -function awesompd:command_load_playlist(name) - return function() - self:command("load \"" .. name .. "\"", function() - self.recreate_menu = true - end) - end -end - -function awesompd:command_replace_playlist(name) - return function() - self:command("clear") - self:command("load \"" .. name .. "\"") - self:command("play 1", self.update_track) - end -end - -function awesompd:command_clear_playlist() - return function() - self:command("clear", self.update_track) - self.recreate_list = true - self.recreate_menu = true - end -end - -function awesompd:command_open_in_browser(link) - return function() - if self.browser then - awful.util.spawn(self.browser .. " '" .. link .. "'") - end - end -end - ---- Change to the previous server. -function awesompd:command_previous_server() - return function() - servers = table.getn(self.servers) - if servers == 1 or servers == nil then - return - else - if self.current_server > 1 then - self:change_server(self.current_server - 1) - else - self:change_server(servers) - end - end - end -end - ---- Change to the previous server. -function awesompd:command_next_server() - return function() - servers = table.getn(self.servers) - if servers == 1 or servers == nil then - return - else - if self.current_server < servers then - self:change_server(self.current_server + 1) - else - self:change_server(1) - end - end - end -end - --- /// End of mpc command functions /// - --- /// Menu generation functions /// - -function awesompd:command_show_menu() - return - function() - self:hide_notification() - if self.recreate_menu then - local new_menu = {} - if self.main_menu ~= nil then - self.main_menu:hide() - end - if self.status ~= awesompd.DISCONNECTED - then - self:check_list() - self:check_playlists() - local jamendo_menu = { { "Search by", - { { "Nothing (Top 100)", self:menu_jamendo_top() }, - { "Artist", self:menu_jamendo_search_by(jamendo.SEARCH_ARTIST) }, - { "Album", self:menu_jamendo_search_by(jamendo.SEARCH_ALBUM) }, - { "Tag", self:menu_jamendo_search_by(jamendo.SEARCH_TAG) }}} } - local browse_menu = self:menu_jamendo_browse() - if browse_menu then - table.insert(jamendo_menu, browse_menu) - end - table.insert(jamendo_menu, self:menu_jamendo_format()) - table.insert(jamendo_menu, self:menu_jamendo_order()) - - new_menu = { { "Playback", self:menu_playback() }, - { "Options", self:menu_options() }, - { "List", self:menu_list() }, - { "Playlists", self:menu_playlists() }, - { "Jamendo", jamendo_menu } } - end - table.insert(new_menu, { "Servers", self:menu_servers() }) - self.main_menu = awful.menu({ items = new_menu, theme = { width = 300 } }) - self.recreate_menu = false - end - self.main_menu:toggle() - end -end - --- Returns an icon for a checkbox menu item if it is checked, nil --- otherwise. -function awesompd:menu_item_toggle(checked) - return checked and self.ICONS.CHECK or nil -end - --- Returns an icon for a radiobox menu item if it is selected, nil --- otherwise. -function awesompd:menu_item_radio(selected) - return selected and self.ICONS.RADIO or nil -end - --- Returns the playback menu. Menu contains of: --- Play\Pause - always --- Previous - if the current track is not the first --- in the list and playback is not stopped --- Next - if the current track is not the last --- in the list and playback is not stopped --- Stop - if the playback is not stopped --- Clear playlist - always -function awesompd:menu_playback() - if self.recreate_playback then - local new_menu = {} - table.insert(new_menu, { "Play\\Pause", - self:command_toggle(), - self.ICONS.PLAY_PAUSE }) - if self:playing_or_paused() then - if self.list_array and self.list_array[self.current_number-1] then - table.insert(new_menu, - { "Prev: " .. - awesompd.protect_string(jamendo.replace_link( - self.list_array[self.current_number - 1]), - true), - self:command_prev_track(), self.ICONS.PREV }) - end - if self.list_array and self.current_number ~= #self.list_array then - table.insert(new_menu, - { "Next: " .. - awesompd.protect_string(jamendo.replace_link( - self.list_array[self.current_number + 1]), - true), - self:command_next_track(), self.ICONS.NEXT }) - end - table.insert(new_menu, { "Stop", self:command_stop(), self.ICONS.STOP }) - table.insert(new_menu, { "", nil }) - end - table.insert(new_menu, { "Clear playlist", self:command_clear_playlist() }) - self.recreate_playback = false - playback_menu = new_menu - end - return playback_menu -end - --- Returns the current playlist menu. Menu consists of all elements in the playlist. -function awesompd:menu_list() - if self.recreate_list then - local new_menu = {} - if self.list_array then - local total_count = #self.list_array - local start_num = (self.current_number - 15 > 0) and self.current_number - 15 or 1 - local end_num = (self.current_number + 15 < total_count ) and self.current_number + 15 or total_count - for i = start_num, end_num do - table.insert(new_menu, { jamendo.replace_link(self.list_array[i]), - self:command_play_specific(i), - self.current_number == i and - (self.status == self.PLAYING and self.ICONS.PLAY or self.ICONS.PAUSE) - or nil} ) - end - end - self.recreate_list = false - self.list_menu = new_menu - end - return self.list_menu -end - --- Returns the playlists menu. Menu consists of all files in the playlist folder. -function awesompd:menu_playlists() - if self.recreate_playlists then - local new_menu = {} - if #self.playlists_array > 0 then - for i = 1, #self.playlists_array do - local submenu = {} - submenu[1] = { "Add to current", self:command_load_playlist(self.playlists_array[i]) } - submenu[2] = { "Replace current", self:command_replace_playlist(self.playlists_array[i]) } - new_menu[i] = { self.playlists_array[i], submenu } - end - table.insert(new_menu, {"", ""}) -- This is a separator - end - table.insert(new_menu, { "Refresh", function() self:check_playlists() end }) - self.recreate_playlists = false - self.playlists_menu = new_menu - end - return self.playlists_menu -end - --- Returns the server menu. Menu consists of all servers specified by user during initialization. -function awesompd:menu_servers() - if self.recreate_servers then - local new_menu = {} - for i = 1, #self.servers do - table.insert(new_menu, {"Server: " .. self.servers[i].server .. - ", port: " .. self.servers[i].port, - function() self:change_server(i) end, - self:menu_item_radio(i == self.current_server)}) - end - self.servers_menu = new_menu - end - return self.servers_menu -end - --- Returns the options menu. Menu works like checkboxes for it's elements. -function awesompd:menu_options() - if self.recreate_options then - local new_menu = { { "Repeat", self:menu_toggle_repeat(), - self:menu_item_toggle(self.state_repeat == "on")}, - { "Random", self:menu_toggle_random(), - self:menu_item_toggle(self.state_random == "on")}, - { "Single", self:menu_toggle_single(), - self:menu_item_toggle(self.state_single == "on")}, - { "Consume", self:menu_toggle_consume(), - self:menu_item_toggle(self.state_consume == "on")} } - self.options_menu = new_menu - self.recreate_options = false - end - return self.options_menu -end - -function awesompd:menu_toggle_random() - return function() - self:command("random",self.update_track) - self:notify_state(self.NOTIFY_RANDOM) - end -end - -function awesompd:menu_toggle_repeat() - return function() - self:command("repeat",self.update_track) - self:notify_state(self.NOTIFY_REPEAT) - end -end - -function awesompd:menu_toggle_single() - return function() - self:command("single",self.update_track) - self:notify_state(self.NOTIFY_SINGLE) - end -end - -function awesompd:menu_toggle_consume() - return function() - self:command("consume",self.update_track) - self:notify_state(self.NOTIFY_CONSUME) - end -end - -function awesompd:menu_jamendo_top() - return - function () - local track_table = jamendo.return_track_table() - if not track_table then - self:show_notification("Can't connect to Jamendo server", "Please check your network connection") - else - self:add_jamendo_tracks(track_table) - self:show_notification("Jamendo Top 100 by " .. - jamendo.current_request_table.params.order.short_display, - format("Added %s tracks to the playlist", - #track_table)) - end - end -end - -function awesompd:menu_jamendo_format() - if self.recreate_jamendo_formats then - local setformat = - function(format) - return function() - jamendo.set_current_format(format) - self.recreate_menu = true - self.recreate_jamendo_formats = true - end - end - - local iscurr = - function(f) - return jamendo.current_request_table.params.streamencoding.value - == f.value - end - - local new_menu = {} - for _, format in pairs(jamendo.ALL_FORMATS) do - table.insert(new_menu, { format.display, setformat(format), - self:menu_item_radio(iscurr(format))}) - end - self.recreate_jamendo_formats = false - self.jamendo_formats_menu = { - "Format: " .. - jamendo.current_request_table.params.streamencoding.short_display, - new_menu } - end - return self.jamendo_formats_menu -end - -function awesompd:menu_jamendo_browse() - if self.recreate_jamendo_browse and self.browser - and self.current_track.unique_name then - local track = jamendo.get_track_by_link(self.current_track.unique_name) - local new_menu - if track then - local artist_link = - "http://www.jamendo.com/artist/" .. track.artist_link_name - local album_link = - "http://www.jamendo.com/album/" .. track.album_id - new_menu = { { "Artist's page" , - self:command_open_in_browser(artist_link) }, - { "Album's page" , - self:command_open_in_browser(album_link) } } - self.jamendo_browse_menu = { "Browse on Jamendo", new_menu } - else - self.jamendo_browse_menu = nil - end - end - return self.jamendo_browse_menu -end - -function awesompd:menu_jamendo_order() - if self.recreate_jamendo_order then - local setorder = - function(order) - return function() - jamendo.set_current_order(order) - self.recreate_menu = true - self.recreate_jamendo_order = true - end - end - - local iscurr = - function(o) - return jamendo.current_request_table.params.order.value - == o.value - end - - local new_menu = {} - for _, order in pairs(jamendo.ALL_ORDERS) do - table.insert(new_menu, { order.display, setorder(order), - self:menu_item_radio(iscurr(order))}) - end - self.recreate_jamendo_order = false - self.jamendo_order_menu = { - "Order: " .. - jamendo.current_request_table.params.order.short_display, - new_menu } - end - return self.jamendo_order_menu -end - -function awesompd:menu_jamendo_search_by(what) - return function() - local callback = - function(s) - local result = jamendo.search_by(what, s) - if result then - local track_count = #result.tracks - self:add_jamendo_tracks(result.tracks) - self:show_notification(format("%s \"%s\" was found", - what.display, - result.search_res.name), - format("Added %s tracks to the playlist", - track_count)) - else - self:show_notification("Search failed", - format("%s \"%s\" was not found", - what.display, s)) - end - end - self:display_inputbox("Search music on Jamendo", - what.display, callback) - end -end - --- Checks if the current playlist has changed after the last check. -function awesompd:check_list() - local bus = io.popen(self:mpcquery(true) .. "playlist") - local info = bus:read("*all") - bus:close() - if info ~= self.list_line then - self.list_line = info - if string.len(info) > 0 then - self.list_array = self.split(string.sub(info,1,string.len(info))) - else - self.list_array = {} - end - self.recreate_menu = true - self.recreate_list = true - end -end - --- Checks if the collection of playlists changed after the last check. -function awesompd:check_playlists() - local bus = io.popen(self:mpcquery(true) .. "lsplaylists") - local info = bus:read("*all") - bus:close() - if info ~= self.playlists_line then - self.playlists_line = info - if string.len(info) > 0 then - self.playlists_array = self.split(info) - else - self.playlists_array = {} - end - self.recreate_menu = true - self.recreate_playlists = true - end -end - --- Changes the current server to the specified one. -function awesompd:change_server(server_number) - self.current_server = server_number - self:hide_notification() - self.recreate_menu = true - self.recreate_playback = true - self.recreate_list = true - self.recreate_playlists = true - self.recreate_servers = true - self:update_track() -end - -function awesompd:add_jamendo_tracks(track_table) - for i = 1, #track_table do - self:command("add '" .. string.gsub(track_table[i].stream, '\\/', '/') .. "'") - end - self.recreate_menu = true - self.recreate_list = true -end - --- /// End of menu generation functions /// - -function awesompd:show_notification(hint_title, hint_text, hint_image) - self:hide_notification() - self.notification = naughty.notify({ title = hint_title - , text = awesompd.protect_string(hint_text) - , timeout = 5 - , position = "top_right" - , icon = hint_image - , icon_size = self.album_cover_size - }) -end - -function awesompd:hide_notification() - if self.notification ~= nil then - naughty.destroy(self.notification) - self.notification = nil - end -end - -function awesompd:notify_track() - if self:playing_or_paused() then - local caption = self.status_text - local nf_text = self.get_display_name(self.current_track) - local al_cover = nil - if self.show_album_cover then - nf_text = self.get_extended_info(self.current_track) - al_cover = self.current_track.album_cover - end - self:show_notification(caption, nf_text, al_cover) - 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, #state_array do - full_state = full_state .. "\n" .. state_array[i] - end - self:show_notification(state_header, full_state) -end - -function awesompd:wrap_output(text) - return format('%s%s%s', - self.font, self.font_color, self.background, - (text == "" and "" or self.ldecorator), awesompd.protect_string(text), - (text == "" and "" or self.rdecorator)) -end - --- This function actually sets the text on the widget. -function awesompd:set_text(text) - self.text_widget:set_markup(self:wrap_output(text)) -end - -function awesompd.find_pattern(text, pattern, start) - return utf8.sub(text, string.find(text, pattern, start)) -end - --- Scroll the given text by the current number of symbols. -function awesompd:scroll_text(text) - local result = text - if self.scrolling then - if self.output_size < utf8.len(text) then - text = text .. " - " - if self.scroll_pos + self.output_size - 1 > utf8.len(text) then - result = utf8.sub(text, self.scroll_pos) - result = result .. utf8.sub(text, 1, self.scroll_pos + self.output_size - 1 - utf8.len(text)) - self.scroll_pos = self.scroll_pos + 1 - if self.scroll_pos > utf8.len(text) then - self.scroll_pos = 1 - end - else - result = utf8.sub(text, self.scroll_pos, self.scroll_pos + self.output_size - 1) - self.scroll_pos = self.scroll_pos + 1 - end - end - end - return result -end - --- This function is called every second. -function awesompd:update_widget() - self:set_text(self:scroll_text(self.text)) - self:check_notify() -end - --- This function is called by update_track each time content of --- the widget must be changed. -function awesompd:update_widget_text() - if self:playing_or_paused() then - self.text = self.get_display_name(self.current_track) - else - self.text = self.status - end -end - --- Checks if notification should be shown and shows if positive. -function awesompd:check_notify() - if self.to_notify then - self:notify_track() - self.to_notify = false - end -end - -function awesompd:notify_connect() - self:show_notification("Connected", "Connection established to " .. self.servers[self.current_server].server .. - " on port " .. self.servers[self.current_server].port) -end - -function awesompd:notify_disconnect() - self:show_notification("Disconnected", "Cannot connect to " .. self.servers[self.current_server].server .. - " on port " .. self.servers[self.current_server].port) -end - -function awesompd:update_track(file) - local file_exists = (file ~= nil) - if not file_exists then - file = io.popen(self:mpcquery()) - end - local track_line = file:read("*line") - local status_line = file:read("*line") - local options_line = file:read("*line") - if not file_exists then - file:close() - end - - if not track_line or string.len(track_line) == 0 then - if self.status ~= awesompd.DISCONNECTED then - self:notify_disconnect() - self.recreate_menu = true - self.status = awesompd.DISCONNECTED - self.current_track = { } - self:update_widget_text() - end - else - if self.status == awesompd.DISCONNECTED then - self:notify_connect() - self.recreate_menu = true - self:update_widget_text() - end - if string.find(track_line,"volume:") or string.find(track_line,"Updating DB") then - if self.status ~= awesompd.STOPPED then - self.status = awesompd.STOPPED - self.current_number = 0 - self.recreate_menu = true - self.recreate_playback = true - self.recreate_list = true - self.album_cover = nil - self.current_track = { } - self:update_widget_text() - end - self:update_state(track_line) - else - self:update_state(options_line) - local _, _, new_file, station, title, artist, album = - string.find(track_line, "(.*)%-<>%-(.*)%-<>%-(.*)%-<>%-(.*)%-<>%-(.*)") - local display_name, force_update = artist .. " - " .. title, false - -- The following code checks if the current track is an - -- Internet link. Internet radios change tracks, but the - -- current file stays the same, so we should manually compare - -- its title. - if string.match(new_file, "http://") and - -- The following line is awful. This needs to be replaced ASAP. - not string.match(new_file, "http://storage%-new%.newjamendo%.com") then - album = non_empty(station) or "" - display_name = non_empty(title) or new_file - if display_name ~= self.current_track.display_name then - force_update = true - end - end - if new_file ~= self.current_track.unique_name or force_update then - self.current_track = jamendo.get_track_by_link(new_file) - if not self.current_track then - self.current_track = { display_name = display_name, - album_name = album } - end - self.current_track.unique_name = new_file - if self.show_album_cover then - self.current_track.album_cover = self:get_cover(new_file) - end - self.to_notify = true - self.recreate_menu = true - self.recreate_playback = true - self.recreate_list = true - self.current_number = tonumber(self.find_pattern(status_line,"%d+")) - self:update_widget_text() - - -- If the track is not the last, asynchronously download - -- the cover for the next track. - if self.list_array and self.current_number ~= #self.list_array then - -- Get the link (in case it is Jamendo stream) to the next track - local next_track = - self:command_read('playlist -f "%file%" | head -' .. - self.current_number + 1 .. ' | tail -1', "*line") - jamendo.try_get_cover_async(next_track) - end - end - local tmp_pst = string.find(status_line,"%d+%:%d+%/") - local progress = self.find_pattern(status_line,"%#%d+/%d+") .. " " .. string.sub(status_line,tmp_pst) - local new_status = awesompd.PLAYING - if string.find(status_line,"paused") then - new_status = awesompd.PAUSED - end - if new_status ~= self.status then - self.to_notify = true - self.recreate_list = true - self.status = new_status - self:update_widget_text() - end - self.status_text = self.status .. " " .. progress - end - end -end - -function awesompd:update_state(state_string) - self.state_volume = self.find_pattern(state_string,"%d+%% ") - if string.find(state_string,"repeat: on") then - self.state_repeat = self:check_set_state(self.state_repeat, "on") - else - self.state_repeat = self:check_set_state(self.state_repeat, "off") - end - if string.find(state_string,"random: on") then - self.state_random = self:check_set_state(self.state_random, "on") - else - self.state_random = self:check_set_state(self.state_random, "off") - end - if string.find(state_string,"single: on") then - self.state_single = self:check_set_state(self.state_single, "on") - else - self.state_single = self:check_set_state(self.state_single, "off") - end - if string.find(state_string,"consume: on") then - self.state_consume = self:check_set_state(self.state_consume, "on") - else - self.state_consume = self:check_set_state(self.state_consume, "off") - end -end - -function awesompd:check_set_state(statevar, val) - if statevar ~= val then - self.recreate_menu = true - self.recreate_options = true - end - return val -end - -function awesompd:run_prompt(welcome,hook) - awful.prompt.run({ prompt = welcome }, - self.promptbox[mouse.screen].widget, - hook) -end - --- Replaces control characters with escaped ones. --- for_menu - defines if the special escable table for menus should be --- used. -function awesompd.protect_string(str, for_menu) - if for_menu then - return utf8.replace(str, awesompd.ESCAPE_MENU_SYMBOL_MAPPING) - else - return utf8.replace(str, awesompd.ESCAPE_SYMBOL_MAPPING) - end -end - --- Initialize the inputbox. -function awesompd:init_inputbox() - local width = 200 - local height = 30 - local border_color = beautiful.bg_focus or '#535d6c' - local margin = 4 - local wbox = wibox({ name = "awmpd_ibox", height = height , width = width, - border_color = border_color, border_width = 1 }) - local ws = screen[mouse.screen].workarea - - wbox.screen = mouse.screen - wbox.ontop = true - - local wprompt = awful.widget.prompt() - local wtbox = wibox.widget.textbox() - local wtmarginbox = wibox.layout.margin(wtbox, margin) - local tw, th = wtbox:fit(-1, -1) - wbox:geometry({ x = ws.width - width - 5, y = 25, - width = 200, height = th * 2 + margin}) - local layout = wibox.layout.flex.vertical() - layout:add(wtmarginbox) - layout:add(wprompt) - wbox:set_widget(layout) - self.inputbox = { wibox = wbox, - title = wtbox, - prompt = wprompt } -end - --- Displays an inputbox on the screen (looks like naughty with prompt). --- title_text - bold text on the first line --- prompt_text - preceding text on the second line --- hook - function that will be called with input data --- Use it like this: --- self:display_inputbox("Search music on Jamendo", "Artist", print) -function awesompd:display_inputbox(title_text, prompt_text, hook) - if not self.inputbox then - self:init_inputbox() - end - if self.inputbox.wibox.visible then -- Inputbox already exists, replace it - keygrabber.stop() - end - - local exe_callback = function(s) - hook(s) - self.inputbox.wibox.visible = false - end - local done_callback = function() - self.inputbox.wibox.visible = false - end - self.inputbox.title:set_markup("" .. title_text .. "") - awful.prompt.run( { prompt = " " .. prompt_text .. ": ", bg_cursor = "#222222" }, - self.inputbox.prompt.widget, - exe_callback, nil, nil, nil, done_callback, nil, nil) - self.inputbox.wibox.visible = true -end - --- Gets the cover for the given track. First looks in the Jamendo --- cache. If the track is not a Jamendo stream, looks in local --- folders. If there is no cover art either returns the default album --- cover. -function awesompd:get_cover(track) - return jamendo.try_get_cover(track) or - self:try_get_local_cover(track) or self.ICONS.DEFAULT_ALBUM_COVER -end - --- Tries to find an album cover for the track that is currently --- playing. -function awesompd:try_get_local_cover(current_file) - if self.mpd_config then - local result - -- First find the music directory in MPD configuration file - local _, _, music_folder = string.find( - self.pread('cat ' .. self.mpd_config .. ' | grep -v "#" | grep music_directory', "*line"), - 'music_directory%s+"(.+)"') - music_folder = music_folder .. "/" - - -- If the music_folder is specified with ~ at the beginning, - -- replace it with user home directory - if string.sub(music_folder, 1, 1) == "~" then - local user_folder = self.pread("echo ~", "*line") - music_folder = user_folder .. string.sub(music_folder, 2) - end - - -- Get the path to the file currently playing. - local _, _, current_file_folder = string.find(current_file, '(.+%/).*') - - -- Check if the current file is not some kind of http stream or - -- Spotify track (like spotify:track:5r65GeuIoebfJB5sLcuPoC) - if not current_file_folder or string.match(current_file, "%w+://") then - return -- Let the default image to be the cover - end - - local folder = music_folder .. current_file_folder - - -- Get all images in the folder. Also escape occasional single - -- quotes in folder name. - local request = format("ls '%s' | grep -P '\\.jpg|\\.png|\\.gif|\\.jpeg'", - string.gsub(folder, "'", "'\\''")) - - local covers = self.pread(request, "*all") - local covers_table = self.split(covers) - - if covers_table.n > 0 then - result = folder .. covers_table[1] - if covers_table.n > 1 then - -- Searching for front cover with grep because Lua regular - -- expressions suck:[ - local front_cover = - self.pread('echo "' .. covers .. - '" | grep -P -i "cover|front|folder|albumart" | head -n 1', "*line") - if front_cover then - result = folder .. front_cover - end - end - end - return result - end -end - --- /// Deprecated, left for some backward compatibility in --- configuration /// - -function awesompd:command_toggle() - return self:command_playpause() -end - -return awesompd