diff --git a/.gitignore b/.gitignore index 6a2e583..91cbc69 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,9 @@ # TOML Bombadil templating directory .dots/ -# Python cache files +# Python files **/__pycache__/ +**/venv/ # Program-specific cache files nvim/lazy-lock.json diff --git a/rofi/audio.py b/rofi/audio.py new file mode 100755 index 0000000..dd847f4 --- /dev/null +++ b/rofi/audio.py @@ -0,0 +1,10 @@ +#!/home/mbradley/.config/rofi/venv/bin/python -OO +from sys import argv + +from rofi_menu import run + +from lib.pactl import create_menu, NodeType + + +if __name__ == "__main__": + run(create_menu(NodeType[argv[1]])) diff --git a/rofi/config.rasi b/rofi/config.rasi index f744126..18247cf 100644 --- a/rofi/config.rasi +++ b/rofi/config.rasi @@ -1,6 +1,6 @@ @theme "arthuredit" configuration { - modi: "drun,calc,emoji:/usr/bin/rofimoji -a copy -f emojis math"; + modi: "drun,calc,emoji:/usr/bin/rofimoji -a copy -f emojis math,sinks:/home/mbradley/.config/rofi/venv/bin/python -OO /home/mbradley/.config/rofi/audio.py SINK,sources:/home/mbradley/.config/rofi/venv/bin/python -OO /home/mbradley/.config/rofi/audio.py SOURCE"; icon-theme: "Papirus"; show-icons: true; run-command: "uwsm-app -- {cmd}"; diff --git a/rofi/lib/__init__.py b/rofi/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rofi/lib/pactl.py b/rofi/lib/pactl.py new file mode 100644 index 0000000..7a90b88 --- /dev/null +++ b/rofi/lib/pactl.py @@ -0,0 +1,77 @@ +from enum import auto, StrEnum +from json import loads +from subprocess import run +from typing import TypedDict, cast + +from rofi_menu import FLAG_STYLE_URGENT, Menu, ShellItem + + +class NodeType(StrEnum): + SINK = auto() + SOURCE = auto() + + +def _pactl(*args: str) -> str: + return run(["pactl", "--format=json", *args], capture_output=True).stdout.decode() + + +class Volume(TypedDict): + value: int + value_percent: str + db: str +class Latency(TypedDict): + actual: float + configured: float +class Port(TypedDict): + name: str + description: str + type: str + priority: int + availability_group: str + availability: str +class Node(TypedDict): + index: int + state: str + name: str + description: str + driver: str + sample_specification: str + channel_map: str + owner_module: int + mute: bool + volume: dict[str, Volume] + balance: float + base_volume: Volume + monitor_source: str + latency: Latency + flags: list[str] + properties: dict[str, str] + ports: list[Port] + active_port: str + formats: list[str] + + +def list_nodes(node_type: NodeType) -> list[Node]: + return cast(list[Node], loads(_pactl("list", f"{node_type}s"))) + + +def get_default(node_type: NodeType) -> str: + return _pactl(f"get-default-{node_type}").strip() + + +def create_item(node_type: NodeType, node: Node, default: str) -> ShellItem: + return ShellItem( + node["description"], + f"pactl set-default-{node_type} {node["name"]}", + flags=FLAG_STYLE_URGENT if node["name"] == default else None, + show_output=True + ) + + +def create_menu(node_type: NodeType) -> Menu: + default = get_default(node_type) + return Menu( + prompt=f"Select {node_type}", + items=[create_item(node_type, node, default) for node in list_nodes(node_type)] + ) + diff --git a/rofi/requirements.txt b/rofi/requirements.txt new file mode 100644 index 0000000..0e312ba --- /dev/null +++ b/rofi/requirements.txt @@ -0,0 +1 @@ +rofi-menu==0.6