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)] )