77 lines
1.6 KiB
Python
77 lines
1.6 KiB
Python
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)]
|
|
)
|
|
|