diff options
| -rw-r--r-- | hosts/mercury/hjem.nix | 1 | ||||
| -rw-r--r-- | modules/desktop/hjem/wm/default.nix | 148 | ||||
| -rw-r--r-- | modules/desktop/hjem/wm/sway.nix | 14 | ||||
| -rw-r--r-- | pkgs/util/default.nix | 44 | ||||
| -rw-r--r-- | pkgs/util/util.lua | 35 | ||||
| -rw-r--r-- | pkgs/util/util/brightness.lua | 40 | ||||
| -rw-r--r-- | pkgs/util/util/music.lua | 124 | ||||
| -rw-r--r-- | pkgs/util/util/volume.lua | 47 |
8 files changed, 301 insertions, 152 deletions
diff --git a/hosts/mercury/hjem.nix b/hosts/mercury/hjem.nix index cc6034d..a9d6d08 100644 --- a/hosts/mercury/hjem.nix +++ b/hosts/mercury/hjem.nix @@ -24,6 +24,7 @@ inputs.glide-browser.packages."x86_64-linux".default (pkgs.callPackage ../../pkgs/yoshi.nix {inherit inputs;}) + (pkgs.callPackage ../../pkgs/yo.nix {inherit inputs;}) ]; files.".config/captive-browser.toml".text = '' diff --git a/modules/desktop/hjem/wm/default.nix b/modules/desktop/hjem/wm/default.nix index a5575ad..6b8aeed 100644 --- a/modules/desktop/hjem/wm/default.nix +++ b/modules/desktop/hjem/wm/default.nix @@ -1,147 +1,5 @@ {pkgs, ...}: { - files.".config/util.lua" = { - text = let - lua = pkgs.lua.withPackages (p: [p.lua-subprocess]); - in - # lua - '' - #!${lua}/bin/lua - local subprocess = require("subprocess") - - local function get_volume() - local proc, err = subprocess.popen({ - "wpctl", "get-volume", "@DEFAULT_AUDIO_SINK@", - stdout = subprocess.PIPE, - stderr = subprocess.PIPE - }) - if not proc then - error("Failed to run wpctl get-volume: " .. tostring(err)) - end - - local out = proc.stdout:read("*a") or "" - local _, _, code = proc:wait() - if (code or 0) ~= 0 then - local errout = proc.stderr and proc.stderr:read("*a") or "" - error(("wpctl get-volume failed (code %d): %s"):format(code, errout)) - end - - local num = out:match("^Volume:%s*([%d%.]+)") - if not num then - error("Unexpected wpctl output: " .. out) - end - - return tonumber(num) * 100 - end - - local function notify_volume() - local ok, reason, code = subprocess.call({ - "dunstify", "-t", "300", - "-h", "string:x-canonical-private-synchronous:audio", - "Volume:", "-h", "int:value:"..get_volume() - }) - if not ok then - io.stderr:write(("dunstify failed (%s, code %s)\n"):format(reason or "?", code or "?")) - end - end - - local function set_volume(vol) - local ok, reason, code = subprocess.call({ - "wpctl", "set-volume", "@DEFAULT_AUDIO_SINK@", vol - }) - if not ok then - io.stderr:write(("wpctl set-volume failed (%s, code %s)\n"):format(reason or "?", code or "?")) - end - end - - local function get_brightness() - local proc = subprocess.popen({ - "${pkgs.brightnessctl}/bin/brightnessctl", "-e", "get", - stdout = subprocess.PIPE - }) - if not proc then error("Failed to run brightnessctl get") end - local cur = tonumber(proc.stdout:read("*a")) - proc:wait() - if not cur then error("Failed to parse brightnessctl get output") end - - local proc2 = subprocess.popen({ - "${pkgs.brightnessctl}/bin/brightnessctl", "-e", "max", - stdout = subprocess.PIPE - }) - if not proc2 then error("Failed to run brightnessctl max") end - local max = tonumber(proc2.stdout:read("*a")) - proc2:wait() - if not max or max == 0 then error("Failed to parse brightnessctl max output") end - - return (cur / max) * 100 - end - - local function notify_brightness() - local ok, reason, code = subprocess.call({ - "dunstify", "-t", "300", - "-h", "string:x-canonical-private-synchronous:brightness", - "Brightness", "-h", "int:value:"..get_brightness() - }) - if not ok then - io.stderr:write(("dunstify failed (%s, code %s)\n"):format(reason or "?", code or "?")) - end - end - - local function set_brightness(brightness) - local ok, reason, code = subprocess.call({ - "${pkgs.brightnessctl}/bin/brightnessctl", "-e", "set", brightness - }) - if not ok then - io.stderr:write(("brightnessctl set failed (%s, code %s)\n"):format(reason or "?", code or "?")) - end - end - - local function list_music_players() - local proc = subprocess.popen({ - "${pkgs.playerctl}/bin/playerctl", "-l", - stdout = subprocess.PIPE - }) - if not proc then error("Failed to run playerctl -l") end - - local cur = proc.stdout:lines() - - local out = {} - for i in cur do - table.insert(out, i) - end - - return out - end - - local function toggle_music() - local ok, reason, code = subprocess.call({ - "${pkgs.playerctl}/bin/playerctl", "play-pause", - }) - if not ok then - io.stderr:write(("playerctl play-pause failed (%s, code %s)\n"):format(reason or "?", code or "?")) - end - end - - -- main logic - if arg[2] and arg[2]:match("^(%d+)%%([%+%-])$") then - if arg[1] == "vol" then - set_volume(arg[2]) - notify_volume() - elseif arg[1] == "brightness" then - set_brightness(arg[2]) - notify_brightness() - else - error(("arg[2] '%s' incorrect format. Should look like 5%%+ or 10%%-"):format(tostring(arg[2]))) - end - elseif arg[1] and arg[1] == "music" then - if arg[2] == "play" then - toggle_music() - else - error(("Invalid arg[2]: '%s'. should be `play`"):format(arg[3])) - end - else - error("Unknown command: " .. tostring(arg[1])) - end - ''; - executable = true; - }; + packages = [ + (pkgs.callPackage ../../../../pkgs/util {}) # util.lua + ]; } diff --git a/modules/desktop/hjem/wm/sway.nix b/modules/desktop/hjem/wm/sway.nix index f3a544f..4cecdea 100644 --- a/modules/desktop/hjem/wm/sway.nix +++ b/modules/desktop/hjem/wm/sway.nix @@ -82,15 +82,15 @@ bindsym Mod4+Shift+s exec '${pkgs.grim}/bin/grim -g "$(${pkgs.slurp}/bin/slurp)" ~/Pictures/$(date +"%s_grim.png")' bindsym Mod4+Alt+s exec '${pkgs.hyprpicker}/bin/hyprpicker' - bindsym XF86AudioRaiseVolume exec 'wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+; dunstify -t 300 -h string:x-canonical-private-synchronous:audio "Volume: " -h "int:value:$(dec=$(wpctl get-volume @DEFAULT_AUDIO_SINK@ | cut -d\" \" -f2);echo "$dec * 100" | ${pkgs.bc}/bin/bc)"' - bindsym XF86AudioLowerVolume exec 'wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-; dunstify -t 300 -h string:x-canonical-private-synchronous:audio "Volume: " -h "int:value:$(dec=$(wpctl get-volume @DEFAULT_AUDIO_SINK@ | cut -d\" \" -f2);echo "$dec * 100" | ${pkgs.bc}/bin/bc)"' + bindsym XF86AudioRaiseVolume exec 'util.lua volume up' + bindsym XF86AudioLowerVolume exec 'util.lua volume down' - bindsym XF86MonBrightnessUp exec 'brightnessctl set 5%+; dunstify -t 300 -h string:x-canonical-private-synchronous:brightness "Brightness: " -h "int:value:$(g=$(brightnessctl get);m=$(brightnessctl max);echo $((g * 100 / m)))"' - bindsym XF86MonBrightnessDown exec 'brightnessctl set 5%-; dunstify -t 300 -h string:x-canonical-private-synchronous:brightness "Brightness: " -h "int:value:$(g=$(brightnessctl get);m=$(brightnessctl max);echo $((g * 100 / m)))"' + bindsym XF86MonBrightnessUp exec 'util.lua brightness up' + bindsym XF86MonBrightnessDown exec 'util.lua brightness down' - bindsym Home exec 'playerctl previous' - bindsym End exec 'playerctl play-pause' - bindsym Insert exec 'playerctl next' + bindsym Home exec 'util.lua music prev' + bindsym End exec 'util.lua music toggle' + bindsym Insert exec 'util.lua music next' default_border pixel 2 smart_borders on diff --git a/pkgs/util/default.nix b/pkgs/util/default.nix new file mode 100644 index 0000000..9dbe067 --- /dev/null +++ b/pkgs/util/default.nix @@ -0,0 +1,44 @@ +{pkgs ? import <nixpkgs> {system = "x86_64-linux";}, ...}: let + lsdbus-src = pkgs.fetchFromGitHub { + owner = "kmarkus"; + repo = "lsdbus"; + rev = "6f80930248110927d1f898966544eec202ea3550"; + hash = "sha256-N/VCjrI7RolHV0ya1U+YTLGAWv8+WNz2nobaGxdR1wQ="; + }; + + lsdbus = pkgs.stdenv.mkDerivation { + pname = "lsdbus"; + version = "scm-3"; + src = lsdbus-src; + nativeBuildInputs = with pkgs; [cmake gnumake pkg-config systemdLibs minixml lua5_4]; + cmakeFlags = ["-DCONFIG_LUA_VER=5.4"]; + }; + + lua = + pkgs.runCommand "lua-env" { + buildInputs = with pkgs; [lua5_4]; + nativeBuildInputs = [pkgs.makeWrapper]; + } '' + mkdir -p $out/bin + install -D -m 755 ${pkgs.lua5_4}/bin/lua $out/bin/lua + wrapProgram $out/bin/lua \ + --prefix LUA_PATH \; '?.lua;?/init.lua' \ + --prefix LUA_PATH \; '${lsdbus}/share/lua/5.4/?.lua' \ + --prefix LUA_PATH \; '${lsdbus}/share/lua/5.4/?/init.lua' \ + --prefix LUA_CPATH \; '${lsdbus}/lib/lua/5.4/?.so' + ''; +in + pkgs.stdenv.mkDerivation { + pname = "util.lua"; + version = "1.0.0"; + src = ./.; + buildInputs = [pkgs.brightnessctl]; + nativeBuildInputs = [pkgs.makeWrapper]; + + buildPhase = '' + mkdir -p $out/{bin,lib} + substitute $src/util.lua $out/bin/util.lua --replace-fail @lua@ ${lua} --replace-fail @out@ $out + cp -r $src/util $out/lib/util + chmod +x $out/bin/util.lua + ''; + } diff --git a/pkgs/util/util.lua b/pkgs/util/util.lua new file mode 100644 index 0000000..ade7019 --- /dev/null +++ b/pkgs/util/util.lua @@ -0,0 +1,35 @@ +#!@lua@/bin/lua +local lsdbus = require("lsdbus") + +local music = dofile"@out@/lib/util/music.lua" +local brightness = dofile"@out@/lib/util/brightness.lua" +local volume = dofile"@out@/lib/util/volume.lua" + +local b = lsdbus.open() +local s = lsdbus.open("system") + +if arg[1] == "music" then + if arg[2] == "toggle" then + music.toggle_play(b) + elseif arg[2] == "next" then + music.next_song(b) + elseif arg[2] == "prev" then + music.prev_song(b) + end +elseif arg[1] == "brightness" then + if arg[2] == "up" then + brightness.brightness_up(s) + elseif arg[2] == "down" then + brightness.brightness_down(s) + else + error(("arg[2] '%s' incorrect format. Should be `up` or `down`"):format(tostring(arg[2]))) + end +elseif arg[1] == "volume" then + if arg[2] == "up" then + volume.volume_up() + elseif arg[2] == "down" then + volume.volume_down() + else + error(("arg[2] '%s' incorrect format. Should be `up` or `down`"):format(tostring(arg[2]))) + end +end diff --git a/pkgs/util/util/brightness.lua b/pkgs/util/util/brightness.lua new file mode 100644 index 0000000..13a7974 --- /dev/null +++ b/pkgs/util/util/brightness.lua @@ -0,0 +1,40 @@ +local lsdbus = require("lsdbus") + +local function get_brightness() + local proc = io.open("/sys/class/backlight/intel_backlight/brightness") + local cur_brightness = tonumber(proc:read("*l")) + return cur_brightness +end + +local function get_max_brightness() + local proc = io.open("/sys/class/backlight/intel_backlight/max_brightness") + local max_brightness = tonumber(proc:read("*l")) + return max_brightness +end + +local function notify_brightness() + local brightness_percent = math.floor((get_brightness() / get_max_brightness()) * 100) + os.execute(string.format( + "dunstify -t 2000 -h string:x-canonical-private-synchronous:brightness 'Brightness' -h int:value:%d", + brightness_percent + )) +end + +local M = {} + +function set_brightness(s, brightness) + local brightness_proxy = lsdbus.proxy.new(s, 'org.freedesktop.login1', '/org/freedesktop/login1/session/1', "org.freedesktop.login1.Session") + brightness_proxy("SetBrightness", "backlight", "intel_backlight", brightness) +end + +function M.brightness_down(s, brightness) + set_brightness(s, get_brightness() - 5*(get_max_brightness() / 100)) + notify_brightness() +end + +function M.brightness_up(s, brightness) + set_brightness(s, get_brightness() + 5*(get_max_brightness() / 100)) + notify_brightness() +end + +return M diff --git a/pkgs/util/util/music.lua b/pkgs/util/util/music.lua new file mode 100644 index 0000000..c9dd726 --- /dev/null +++ b/pkgs/util/util/music.lua @@ -0,0 +1,124 @@ +local lsdbus = require("lsdbus") + +function list_players(b) + local dbus = lsdbus.proxy.new(b, + 'org.freedesktop.DBus', + '/org/freedesktop/DBus', + 'org.freedesktop.DBus' + ) + local all_services = dbus("ListNames") + + local players = {} + for _, name in ipairs(all_services) do + if name:match("^org.mpris.MediaPlayer2") then + table.insert(players, name) + end + end + return players +end + +local function get_player_proxy(b, player) + local ok, res = pcall(function() return lsdbus.proxy.new(b, + player, + '/org/mpris/MediaPlayer2', + 'org.mpris.MediaPlayer2.Player' + ) end) + if ok then + return res + end +end + +local function list_playing_players(b) + local playing = {} + for _, player in ipairs(list_players(b)) do + local proxy = get_player_proxy(b, player) + if proxy and proxy.PlaybackStatus == "Playing" then + -- print(player) + table.insert(playing, player) + end + end + return playing +end + +local function solo_player(b, player) + for _, i in list_playing_players(b) do + if i ~= player then + get_player_proxy(b, player)"Pause" + end + end +end + +local STATE_FILE = os.getenv("HOME") .. "/.local/state/music_player_paused" +local function write_state(state_file, player) + local f, _ = io.open(state_file, "w") + f:write(player.."\n") + f:close() +end + +local function read_state(state_file) + local f, _ = io.open(state_file, "r") + local read = f:read("*l") + f:close() + return read +end + +local M = {} + +local function notify_music(b, player) + local player_proxy = lsdbus.proxy.new(b, player, '/org/mpris/MediaPlayer2', 'org.mpris.MediaPlayer2.Player') + local meta = player_proxy.Metadata + + os.execute(string.format( + "dunstify -t 2000 -h string:x-canonical-private-synchronous:music -i '%s' '%s' '%s' -h int:value:%d", + meta["mpris:artUrl"] or "", + player_proxy.PlaybackStatus .. " " .. meta["xesam:title"] or "", + "by " .. meta["xesam:artist"][1], + math.floor(player_proxy.Position / meta["mpris:length"]) + )) +end + +function M.toggle_play(b) + local current_playing = list_playing_players(b) + local state = read_state(STATE_FILE) + + if #current_playing == 0 and state ~= "" then + local p = get_player_proxy(b, state) + if p then + p("Play") + notify_music(b, state) + end + return + end + + if #current_playing == 1 then + local c = current_playing[1] + write_state(STATE_FILE, c) + get_player_proxy(b, c)("Pause") + notify_music(b, c) + return + end + + if #current_playing > 1 then + for _, player in ipairs(current_playing) do + get_player_proxy(b, player)"Pause" + end + end +end + +function M.next_song(b) + local currently_playing = list_playing_players(b) + if #currently_playing ~= 0 then + local player_proxy = lsdbus.proxy.new(b, currently_playing[1], '/org/mpris/MediaPlayer2', 'org.mpris.MediaPlayer2.Player') + player_proxy("Next") + end +end + +function M.prev_song(b) + local currently_playing = list_playing_players(b) + if #currently_playing ~= 0 then + local player_proxy = lsdbus.proxy.new(b, currently_playing[1], '/org/mpris/MediaPlayer2', 'org.mpris.MediaPlayer2.Player') + player_proxy("Previous") + end +end + +return M diff --git a/pkgs/util/util/volume.lua b/pkgs/util/util/volume.lua new file mode 100644 index 0000000..750f67c --- /dev/null +++ b/pkgs/util/util/volume.lua @@ -0,0 +1,47 @@ +local function get_volume() + local handle = io.popen("wpctl get-volume @DEFAULT_AUDIO_SINK@") + local out = handle:read("*a") + handle:close() + + local num = out:match("^Volume:%s*([%d%.]+)") + if not num then + error("Unexpected wpctl output: " .. out) + end + + return tonumber(num) * 100 +end + +local function notify_volume() + os.execute(string.format( + "dunstify -t 2000 -h string:x-canonical-private-synchronous:audio 'Volume' -h int:value:%d", + math.floor(get_volume()) + )) +end + +local M = {} + +function M.set_volume(vol) + os.execute(string.format("wpctl set-volume @DEFAULT_AUDIO_SINK@ %.2f", vol / 100)) + notify_volume() +end + +function M.volume_up(step) + step = step or 5 + local current = get_volume() + local new_volume = math.min(150, current + step) + M.set_volume(new_volume) +end + +function M.volume_down(step) + step = step or 5 + local current = get_volume() + local new_volume = math.max(0, current - step) + M.set_volume(new_volume) +end + +function M.toggle_mute() + os.execute("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle") + notify_volume() +end + +return M |
