LINUX.ORG.RU

Помощь в написании красивого скрипта

 , ,


0

1

В связи с тем, что я плавно переезжаю на wayland и hyprland, встал вопрос о том чтобы сделать маленькие удобства для себя(возможно это пригодится не только мне).

Хочу сделать следующее, в waybar выводить кастомным модулем значок используемого в данный момент выхода(Sink) и его громкость. И если с громкостью проблем никаких нет, то вот распарсить на баше то что выдает wpctl, для меня довольно сложно оказалось.

Audio
 ├─ Devices:
 │      40. HDA NVidia                          [alsa]
 │      41. Webcam C310                         [alsa]
 │      42. Jabra EVOLVE 20 MS                  [alsa]
 │      43. Starship/Matisse HD Audio Controller [alsa]
 │  
 ├─ Sinks:
 │      50. Jabra EVOLVE 20 MS Аналоговый стерео [vol: 0.80]
 │  *   52. Starship/Matisse HD Audio Controller Цифровой стерео (IEC958) [vol: 1.00]
 │  
 ├─ Sink endpoints:
 │  
 ├─ Sources:
 │  *   51. Jabra EVOLVE 20 MS Моно         [vol: 0.76]
 │  
 ├─ Source endpoints:
 │  
 └─ Streams:

Вот из приведенного выше куска, хочу достать во-первых оба синка, хотя бы до первого пробела(Jabra и Starship/Matisse), айдишник каждого(для переключения между ними по клику), ну и пометку какой из них активный в данный момент. Тогда я смогу по синку выводить значок соответствующий(колонка или наушники), а также по клику смогу их переключать между собой.

Подскажите, как это лучше на баше сделать? Я конечно могу сам, но получится лютый говнокод на пару страниц, а я верю, что тут какая-нибудь магия может помочь однострочная.

PS: В принципе можно и на питоне, но текущая версия на баше, поэтому думал так и продолжать.

★★★★★

Последнее исправление: Loki13 (всего исправлений: 2)

не красиво, но что-то похожее отдает

wpctl status | awk '/├─ Sinks:/,/├─ Sink endpoints:/ {if ($0 ~ /[[:space:]]│[[:space:]]+\*[[:space:]]+/) {
 name_start = index($0, ".")+2;
 name_end = index($0, "[vol:");
 print substr($0, name_start, name_end - name_start);
 exit
}}'
cobold ★★★★★
()
Последнее исправление: cobold (всего исправлений: 1)
$ cat audio.txt 
Audio
 ├─ Devices:
 │      40. HDA NVidia                          [alsa]
 │      41. Webcam C310                         [alsa]
 │      42. Jabra EVOLVE 20 MS                  [alsa]
 │      43. Starship/Matisse HD Audio Controller [alsa]
 │  
 ├─ Sinks:
 │      50. Jabra EVOLVE 20 MS Аналоговый стерео [vol: 0.80]
 │  *   52. Starship/Matisse HD Audio Controller Цифровой стерео (IEC958) [vol: 1.00]
 │  
 ├─ Sink endpoints:
 │  
 ├─ Sources:
 │  *   51. Jabra EVOLVE 20 MS Моно         [vol: 0.76]
 │  
 ├─ Source endpoints:
 │  
 └─ Streams:

$ sed -n '/├─ Sinks:/,/├─ Sink/p' audio.txt | awk '/ │  /{if ($2=="*"){gsub(/\./, "", $3);print "Current is: "$3" "$4}else{gsub(/\./, "", $2);print $2" "$3}}'
50 Jabra
Current is: 52 Starship/Matisse
iron ★★★★★
()
parse_sinks=n
for line in "${lines[@]}"; do
  if [[ $parse_sinks == y ]]; then
    # Сделай со мной что-то
    echo "$line"; 
  elif [[ $line == *"Sinks:"* ]]; then 
    parse_sinks=y;
  elif [[ $line == *"Sink endpoints:"* ]] then 
    parse_sinks=n
  fi
done
rtxtxtrx
()

Нативный варик, через wpexec - Lua-интерпретатор WP:

#!/usr/bin/wpexec

Core.require_api("default-nodes", function(dna)
  local defn_id = dna:call("get-default-node", "Audio/Sink")

  obj_mgr = ObjectManager {
    Interest { type = "node",  Constraint {"media.class", "matches", "Audio/Sink"} }
  }

  obj_mgr:connect("installed", function (om)
    for node in om:iterate() do
      local id = node["bound-id"]
      local desc = node["global-properties"]["node.description"]
      local star = defn_id == id and "*" or " "
      print(star.." "..id.." "..desc)
    end
    Core.quit()
  end)

  obj_mgr:activate()
end)
$ chmod +x pw_sinks.lua
$ ./pw_sinks.lua
anonymous
()
Ответ на: комментарий от anonymous

Анон доставляет как всегда. Только на мой вкус лучше не description использовать, а nick_name, т.к. там в случае подключения по hdmi отображается имя подключенного устройства, а не имя порта, к которому оно подключено

cobold ★★★★★
()
Ответ на: комментарий от cobold

Да,мне этот вариант очень понравился. Даже не смотря на то что я lua не знаю. Сегодня буду пробовать его приспособить.

Только на мой вкус лучше не description использовать, а nick_name, т.к. там в случае подключения по hdmi отображается имя подключенного устройства, а не имя порта, к которому оно подключено

Я вообще хочу имена захардкодить и выводить только значок(колонка или наушники), т.к. места в панели не так много чтобы писать прямо названиями. А вот nick_name можно будет в rofi выводить по ПКМ и там уже выбирать более осмысленно.

Loki13 ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Спасибо! Отличный вариант! Нативный конечно всегда лучше, чем парсить портянки текстового выхлопа.

Попробую теперь из этого что-то удобное сделать для себя(с rofi по ПКМ и быстрым переключением по ЛКМ). Получится - выложу сюда. Вдруг кому тоже удобно будет в таком виде.

Loki13 ★★★★★
() автор топика
Ответ на: комментарий от anonymous

А есть где-нибудь документация(может даже доки на API) по вот этому внутреннему нативному скриптингу на Lua? А то в их примерах можно увидеть только то что они показывают именно в этих примерах.

Вот подумал сделать циклическое переключение синков, а где искать хотя бы функцию, которую надо вызвать в их API, чтобы включить другой синк? Как блютус переключить пример увидел, а как синк - нет.

Может если бы знал Lua, то и догадался бы, но так приходится чуть ли не методом тыка.

Loki13 ★★★★★
() автор топика
Ответ на: комментарий от Loki13

Вроде работает :)

#!/usr/bin/wpexec

-- To set new default id run the script with `set-default=id` argument, e.g.
--     ./pw_sinks.lua set-default=50

args = ...
new_default = tonumber(args["set-default"] or args["set_default"])

Core.require_api("default-nodes", "mixer", function(DNA, MXR)
  local default_id = DNA:call("get-default-node", "Audio/Sink")

  obj_mgr = ObjectManager {
    Interest { type = "node",  Constraint {"media.class", "matches", "Audio/Sink"} }
  }

  obj_mgr:connect("installed", function (om)
    if new_default then
      if om:lookup({ Constraint {"bound-id", "=", new_default, type="gobject"} }) then
        default_id = new_default
      else
        -- On error, will print to stdout:
        print("pw-sinks.lua: set-default error: No such audio sink id: " .. new_default)
        goto quit
      end
    end
    for node in om:iterate() do
      local id = node["bound-id"]
      local volt = MXR:call("get-volume", id)
      local vol = math.floor(math.pow(volt.volume, 1/3) * 100 + 0.5)
      local mut = volt.mute and " (muted)" or ""
      local props = node["global-properties"] 
      local name = props["node.name"]
      local nick = props["node.nick"]
      local desc = props["node.description"]
      local is_default = default_id == id
      local star = is_default and "*" or " "
      print(string.format("%s %d : %d%%%s : %s (%s) ", star, id, vol, mut, nick, desc))

      if new_default and is_default then
        DNA:call("set-default-configured-node-name", "Audio/Sink", name)
      end
    end
    ::quit::
    Core.quit()
  end)

  obj_mgr:activate()
end)
./pw_sinks.lua                 # выведет все синки
./pw_sinks.lua set-default=50  # установит синк с id=50 в качестве дефолтного
anonymous
()