1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
-------------------------------------------------
-- Spotify Widget for Awesome Window Manager
-- Shows currently playing song on Spotify for Linux client
-- More details could be found here:
-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/spotify-widget
-- @author Pavel Makhov
-- @copyright 2020 Pavel Makhov
-------------------------------------------------
local awful = require("awful")
local wibox = require("wibox")
local watch = require("awful.widget.watch")
local function ellipsize(text, length)
-- utf8 only available in Lua 5.3+
if utf8 == nil then
return text:sub(0, length)
end
return (utf8.len(text) > length and length > 0)
and text:sub(0, utf8.offset(text, length - 2) - 1) .. '...'
or text
end
local spotify_widget = {}
local function worker(user_args)
local args = user_args or {}
local play_icon = args.play_icon or '/usr/share/icons/Arc/actions/24/player_play.png'
local pause_icon = args.pause_icon or '/usr/share/icons/Arc/actions/24/player_pause.png'
local font = args.font or 'Play 9'
local dim_when_paused = args.dim_when_paused == nil and false or args.dim_when_paused
local dim_opacity = args.dim_opacity or 0.2
local max_length = args.max_length or 15
local show_tooltip = args.show_tooltip == nil and true or args.show_tooltip
local timeout = args.timeout or 1
local sp_bin = args.sp_bin or 'sp'
local GET_SPOTIFY_STATUS_CMD = sp_bin .. ' status'
local GET_CURRENT_SONG_CMD = sp_bin .. ' current'
local PLAY_PAUSE_CMD = sp_bin .. ' play'
local NEXT_SONG_CMD = sp_bin .. ' next'
local PREVIOUS_SONG_CMD = sp_bin .. ' prev'
local cur_artist = ''
local cur_title = ''
local cur_album = ''
spotify_widget = wibox.widget {
{
id = 'artistw',
font = font,
widget = wibox.widget.textbox,
},
{
layout = wibox.layout.stack,
{
id = "icon",
widget = wibox.widget.imagebox,
},
{
widget = wibox.widget.textbox,
font = font,
text = ' ',
forced_height = 1
}
},
{
layout = wibox.container.scroll.horizontal,
max_size = 100,
step_function = wibox.container.scroll.step_functions.waiting_nonlinear_back_and_forth,
speed = 40,
{
id = 'titlew',
font = font,
widget = wibox.widget.textbox
}
},
layout = wibox.layout.align.horizontal,
set_status = function(self, is_playing)
self:get_children_by_id('icon')[1]:set_image(is_playing and play_icon or pause_icon)
if dim_when_paused then
self:get_children_by_id('icon')[1]:set_opacity(is_playing and 1 or dim_opacity)
self:get_children_by_id('titlew')[1]:set_opacity(is_playing and 1 or dim_opacity)
self:get_children_by_id('titlew')[1]:emit_signal('widget::redraw_needed')
self:get_children_by_id('artistw')[1]:set_opacity(is_playing and 1 or dim_opacity)
self:get_children_by_id('artistw')[1]:emit_signal('widget::redraw_needed')
end
end,
set_text = function(self, artist, song)
local artist_to_display = ellipsize(artist, max_length)
if self:get_children_by_id('artistw')[1]:get_markup() ~= artist_to_display then
self:get_children_by_id('artistw')[1]:set_markup(artist_to_display)
end
local title_to_display = ellipsize(song, max_length)
if self:get_children_by_id('titlew')[1]:get_markup() ~= title_to_display then
self:get_children_by_id('titlew')[1]:set_markup(title_to_display)
end
end
}
local update_widget_icon = function(widget, stdout, _, _, _)
stdout = string.gsub(stdout, "\n", "")
widget:set_status(stdout == 'Playing' and true or false)
end
local update_widget_text = function(widget, stdout, _, _, _)
if string.find(stdout, 'Error: Spotify is not running.') ~= nil then
widget:set_text('','')
widget:set_visible(false)
return
end
local escaped = string.gsub(stdout, "&", '&')
local album, _, artist, title =
string.match(escaped, 'Album%s*(.*)\nAlbumArtist%s*(.*)\nArtist%s*(.*)\nTitle%s*(.*)\n')
if album ~= nil and title ~=nil and artist ~= nil then
cur_artist = artist
cur_title = title
cur_album = album
widget:set_text(artist, title)
widget:set_visible(true)
end
end
watch(GET_SPOTIFY_STATUS_CMD, timeout, update_widget_icon, spotify_widget)
watch(GET_CURRENT_SONG_CMD, timeout, update_widget_text, spotify_widget)
--- Adds mouse controls to the widget:
-- - left click - play/pause
-- - scroll up - play next song
-- - scroll down - play previous song
spotify_widget:connect_signal("button::press", function(_, _, _, button)
if (button == 1) then
awful.spawn(PLAY_PAUSE_CMD, false) -- left click
elseif (button == 4) then
awful.spawn(NEXT_SONG_CMD, false) -- scroll up
elseif (button == 5) then
awful.spawn(PREVIOUS_SONG_CMD, false) -- scroll down
end
awful.spawn.easy_async(GET_SPOTIFY_STATUS_CMD, function(stdout, stderr, exitreason, exitcode)
update_widget_icon(spotify_widget, stdout, stderr, exitreason, exitcode)
end)
end)
if show_tooltip then
local spotify_tooltip = awful.tooltip {
mode = 'outside',
preferred_positions = {'bottom'},
}
spotify_tooltip:add_to_object(spotify_widget)
spotify_widget:connect_signal('mouse::enter', function()
spotify_tooltip.markup = '<b>Album</b>: ' .. cur_album
.. '\n<b>Artist</b>: ' .. cur_artist
.. '\n<b>Song</b>: ' .. cur_title
end)
end
return spotify_widget
end
return setmetatable(spotify_widget, { __call = function(_, ...)
return worker(...)
end })
|