awesome-wm-widgets/mpris-widget/init.lua
Romanos Skiadas 4bc22fbb70 mpris-widget: delete on mouse::enter code
this code is janky, because the notification is set asynchronously, it
can end up not being cleaned by the mouse exit and then you can end up
with multiple ones. Also, the image field of the table needs to be icon,
but if the icon is an http url like some players print or even a local
file like firefox does, setting the icon causes an error as it can't be
read.
2021-10-16 09:59:03 +03:00

187 lines
6.2 KiB
Lua

-------------------------------------------------
-- mpris based Arc Widget for Awesome Window Manager
-- Modelled after Pavel Makhov's work
-- @author Mohammed Gaber
-- requires - playerctl
-- @copyright 2020
-------------------------------------------------
local awful = require("awful")
local beautiful = require("beautiful")
local watch = require("awful.widget.watch")
local wibox = require("wibox")
local gears = require("gears")
local GET_MPD_CMD = "playerctl -p %s -f '{{status}};{{xesam:artist}};{{xesam:title}}' metadata"
local TOGGLE_MPD_CMD = "playerctl play-pause"
local NEXT_MPD_CMD = "playerctl next"
local PREV_MPD_CMD = "playerctl previous"
local LIST_PLAYERS_CMD = "playerctl -l"
local PATH_TO_ICONS = "/usr/share/icons/Arc"
local PAUSE_ICON_NAME = PATH_TO_ICONS .. "/actions/24/player_pause.png"
local PLAY_ICON_NAME = PATH_TO_ICONS .. "/actions/24/player_play.png"
local STOP_ICON_NAME = PATH_TO_ICONS .. "/actions/24/player_stop.png"
local LIBRARY_ICON_NAME = PATH_TO_ICONS .. "/actions/24/music-library.png"
local default_player = ''
local icon = wibox.widget {
id = "icon",
widget = wibox.widget.imagebox,
image = PLAY_ICON_NAME
}
local mpris_widget = wibox.widget{
{
id = 'artist',
widget = wibox.widget.textbox
},
{
icon,
max_value = 1,
value = 0,
thickness = 2,
start_angle = 4.71238898, -- 2pi*3/4
forced_height = 24,
forced_width = 24,
rounded_edge = true,
bg = "#ffffff11",
paddings = 0,
widget = wibox.container.arcchart
},
{
id = 'title',
widget = wibox.widget.textbox
},
layout = wibox.layout.fixed.horizontal,
set_text = function(self, artist, title)
self:get_children_by_id('artist')[1]:set_text(artist)
self:get_children_by_id('title')[1]:set_text(title)
end
}
local rows = { layout = wibox.layout.fixed.vertical }
local popup = awful.popup{
bg = beautiful.bg_normal,
ontop = true,
visible = false,
shape = gears.shape.rounded_rect,
border_width = 1,
border_color = beautiful.bg_focus,
maximum_width = 400,
offset = { y = 5 },
widget = {}
}
local function rebuild_popup()
awful.spawn.easy_async(LIST_PLAYERS_CMD, function(stdout, _, _, _)
for i = 0, #rows do rows[i]=nil end
for player_name in stdout:gmatch("[^\r\n]+") do
if player_name ~='' and player_name ~=nil then
local checkbox = wibox.widget{
{
checked = player_name == default_player,
color = beautiful.bg_normal,
paddings = 2,
shape = gears.shape.circle,
forced_width = 20,
forced_height = 20,
check_color = beautiful.fg_urgent,
widget = wibox.widget.checkbox
},
valign = 'center',
layout = wibox.container.place,
}
checkbox:connect_signal("button::press", function()
default_player = player_name
rebuild_popup()
end)
table.insert(rows, wibox.widget {
{
{
checkbox,
{
{
text = player_name,
align = 'left',
widget = wibox.widget.textbox
},
left = 10,
layout = wibox.container.margin
},
spacing = 8,
layout = wibox.layout.align.horizontal
},
margins = 4,
layout = wibox.container.margin
},
bg = beautiful.bg_normal,
widget = wibox.container.background
})
end
end
end)
popup:setup(rows)
end
local function worker()
-- retrieve song info
local current_song, artist, player_status
local update_graphic = function(widget, stdout, _, _, _)
local words = gears.string.split(stdout, ';')
player_status = words[1]
artist = words[2]
current_song = words[3]
if current_song ~= nil then
if string.len(current_song) > 18 then
current_song = string.sub(current_song, 0, 9) .. ".."
end
end
if player_status == "Playing" then
icon.image = PLAY_ICON_NAME
widget.colors = {beautiful.widget_main_color}
widget:set_text(artist, current_song)
elseif player_status == "Paused" then
icon.image = PAUSE_ICON_NAME
widget.colors = {beautiful.widget_main_color}
widget:set_text(artist, current_song)
elseif player_status == "Stopped" then
icon.image = STOP_ICON_NAME
else -- no player is running
icon.image = LIBRARY_ICON_NAME
widget.colors = {beautiful.widget_red}
end
end
mpris_widget:buttons(
awful.util.table.join(
awful.button({}, 3, function()
if popup.visible then
popup.visible = not popup.visible
else
rebuild_popup()
popup:move_next_to(mouse.current_widget_geometry)
end
end),
awful.button({}, 4, function() awful.spawn(NEXT_MPD_CMD, false) end),
awful.button({}, 5, function() awful.spawn(PREV_MPD_CMD, false) end),
awful.button({}, 1, function() awful.spawn(TOGGLE_MPD_CMD, false) end)
)
)
watch(string.format(GET_MPD_CMD, "'" .. default_player .. "'"), 1, update_graphic, mpris_widget)
return mpris_widget
end
return setmetatable(mpris_widget, {__call = function(_, ...) return worker(...) end})