From 87d3fb525e841b5648e360a926d90c11d9a0a56b Mon Sep 17 00:00:00 2001 From: Samir Benmendil Date: Sun, 20 Sep 2020 15:36:06 +0100 Subject: [PATCH] awesome/mpc: react to subsystem changes to idle --- awesome/widgets/mpc.lua | 80 +++++++++++----------- awesome/widgets/mpd_widget.lua | 121 ++++++++++++++++++--------------- 2 files changed, 108 insertions(+), 93 deletions(-) diff --git a/awesome/widgets/mpc.lua b/awesome/widgets/mpc.lua index a3c5b87..932a4a5 100644 --- a/awesome/widgets/mpc.lua +++ b/awesome/widgets/mpc.lua @@ -4,6 +4,8 @@ local lgi = require "lgi" local GLib = lgi.GLib local Gio = lgi.Gio +local trace_mpc = false + local mpc = {} local function parse_password(host) @@ -28,12 +30,19 @@ function mpc.new(host, port, password, error_handler, ...) _error_handler = error_handler or function() end, _connected = false, _try_reconnect = false, - _idle_commands = { ... } + _idle_subsystems = { ... } }, { __index = mpc }) self:_connect() return self end +function mpc:_write(command) + if trace_mpc then + print("write: " .. command) + end + self._output:write(command .. "\n") +end + function mpc:_error(err) self._connected = false self._error_handler(err) @@ -108,10 +117,15 @@ function mpc:_connect() table.remove(self._reply_handlers, 1) self._pending_reply = {} handler(success, arg) + + if next(self._reply_handlers) == nil then + self:_start_idle() + end else local _, _, key, value = string.find(line, "([^:]+):%s(.+)") if key then - if key == "binary" then + local k = string.lower(key) + if k == "binary" then value = tonumber(value) local data = {} while value > 0 do @@ -120,9 +134,15 @@ function mpc:_connect() value = value - #b end local w = obj:read_bytes(1) -- read newline at end of binary - self._pending_reply[string.lower(key)] = table.concat(data) + self._pending_reply[k] = table.concat(data) + elseif k == "changed" then + if not self._pending_reply[k] then + self._pending_reply[k] = {} + end + + self._pending_reply[k][value] = true else - self._pending_reply[string.lower(key)] = value + self._pending_reply[k] = value end end end @@ -132,42 +152,28 @@ function mpc:_connect() end do_read() - -- To synchronize the state on startup, send the idle commands now. As a - -- side effect, this will enable idle state. - self:_send_idle_commands(true) - - return self -end - -function mpc:_send_idle_commands(skip_stop_idle) - -- We use a ping to unset this to make sure we never get into a busy - -- loop sending idle / unidle commands. Next call to - -- _send_idle_commands() might be ignored! - if self._idle_commands_pending then - return - end - if not skip_stop_idle then - self:_stop_idle() + -- To synchronize the state on startup, send the idle commands now. + for i = 1, #self._idle_subsystems, 2 do + self._idle_subsystems[i+1](self) end - self._idle_commands_pending = true - for i = 1, #self._idle_commands, 2 do - self:_send(self._idle_commands[i], self._idle_commands[i+1]) - end - self:_send("ping", function() - self._idle_commands_pending = false - end) - self:_start_idle() + return self end function mpc:_start_idle() if self._idle then - error("Still idle?!") + error("start_idle but already idle") end self:_send("idle", function(success, reply) + self._idle = false if reply.changed then -- idle mode was disabled by mpd - self:_send_idle_commands() + for i = 1, #self._idle_subsystems, 2 do + local subsys = self._idle_subsystems[i] + if reply.changed[subsys] then + self._idle_subsystems[i+1](self) + end + end end end) self._idle = true @@ -175,9 +181,9 @@ end function mpc:_stop_idle() if not self._idle then - error("Not idle?!") + error("stop_idle but not idle") end - self._output:write("noidle\n") + self:_write("noidle") self._idle = false end @@ -185,7 +191,7 @@ function mpc:_send(command, callback) if self._idle then error("Still idle in send()?!") end - self._output:write(command .. "\n") + self:_write(command) table.insert(self._reply_handlers, callback or function() end) end @@ -194,15 +200,13 @@ function mpc:send(...) if not self._connected then return end - local args = { ... } - if not self._idle then - error("Something is messed up, we should be idle here...") + if self._idle then + self:_stop_idle() end - self:_stop_idle() + local args = { ... } for i = 1, #args, 2 do self:_send(args[i], args[i+1]) end - self:_start_idle() end function mpc:toggle_play() diff --git a/awesome/widgets/mpd_widget.lua b/awesome/widgets/mpd_widget.lua index e71e087..9da5152 100644 --- a/awesome/widgets/mpd_widget.lua +++ b/awesome/widgets/mpd_widget.lua @@ -43,50 +43,50 @@ local function song_duration(elapsed, duration) return sec_to_min(elapsed) .. "/" .. sec_to_min(duration) end -function widget:get_info(callback) - local status = nil - self._connection:send("status", function(_, s) status = s end) - - local song = nil - - self._connection:send("currentsong", function(_, s) - song = s - self._connection:albumart(song.file, function(_, art) - local info = {} - if art and art.binary then - info.icon = '/tmp/test.jpg' - local f = io.open(info.icon, 'w') - f:write(art.binary) - f:close() - end - - info.title = status.state .. " " .. status.song .. "/" .. status.playlistlength .. " " .. song_duration(status.elapsed, status.duration) - if not song.artist then - info.text = string.format("%s", song.title or song.file) - else - info.text = string.format("%s - %s", song.artist, song.title) - end - if song.album then - info.text = info.text .. "\n" .. tostring(song.album or "") - end - callback(info) - end) - end) +local dbg = require("gears.debug") +function widget:get_albumart() + local art = self._albumart + -- dbg.dump(art) + -- dbg.dump(self._albumart.binary) + if art and art.binary then + local path = '/tmp/test.jpg' + local f = io.open(path, 'w') + f:write(art.binary) + f:close() + return path + else + return beautiful.mpd_default_album + end +end + +function widget:get_info() + local info = {} + local status, song = self._status, self._currentsong + info.title = status.state .. " " .. status.song .. "/" .. status.playlistlength .. " " .. song_duration(status.elapsed, status.duration) + if not song.artist then + info.text = string.format("%s", song.title or song.file) + else + info.text = string.format("%s - %s", song.artist, song.title) + end + if song.album then + info.text = info.text .. "\n" .. tostring(song.album or "") + end + + return info end function widget:popup_show() - self:get_info(function(table) - if self._notification then return end - self._notification = naughty.notify( - { title = table.title - , icon = table.icon or beautiful.mpd_default_album - , icon_size = 64 - , text = table.text - , timeout = 0 - , destroy = function() self._timer:stop(); self._notification = nil end - }) - self._timer:start() - end) + if self._notification then return end + local table = self:get_info() + self._timer:start() + self._notification = naughty.notify( + { title = table.title + , icon = self:get_albumart() + , icon_size = 64 + , text = table.text + , timeout = 0 + , destroy = function() self._timer:stop(); self._notification = nil end + }) end function widget:popup_hide(delay) @@ -116,7 +116,10 @@ function widget:popup_hide(delay) end function widget:popup_update() - self:get_info(function(table) + if not self._notification then return end + self._connection:send("status", function(_, status) + self._status = status + local table = self:get_info() if not self._notification then return end naughty.replace_text(self._notification, table.title, table.text) end) @@ -140,20 +143,28 @@ function widget:error_handler(err) end function widget:run() + self._status = {} + self._status.songid = nil + self._connection = mpc.new(nil, nil, nil, function(err) self:error_handler(err) end, - "status", function(_, result) - if not self._status or result.state ~= self._status.state then - self._status = result - self:update_widget() - self:popup_oneshot(5) - end - end, - "currentsong", function(_, result) - if not self._currentsong or result.id ~= self._currentsong.id then - self._currentsong = result - self:update_widget() - self:popup_oneshot(5) - end + "player", function(conn) + conn:send("status", function(err, status) + local songchanged = self._status.songid ~= status.songid + self._status = status + if not songchanged then + self:update_widget() + return + end + + conn:send("currentsong", function(_, song) + self._currentsong = song + conn:albumart(song.file, function(_, art) + self._albumart = art + self:update_widget() + self:popup_oneshot(5) + end) + end) + end) end ) -- 2.48.1