Files
browser-cli/browser_cli/models.py
T
2026-04-14 13:21:21 +02:00

140 lines
4.4 KiB
Python

"""
Typed dataclasses returned by the BrowserCLI Python API.
Each object is bound to a BrowserCLI instance so you can call actions
directly on it:
tabs = b.tabs_list()
tabs[0].close()
tabs[0].move(forward=True)
groups = b.group_list()
groups[0].tabs()
groups[0].add_tab("https://example.com")
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from browser_cli import BrowserCLI
# ── Tab ───────────────────────────────────────────────────────────────────────
@dataclass
class Tab:
"""A browser tab."""
id: int
window_id: int
active: bool
muted: bool = False
title: str = ""
url: str = ""
group_id: int | None = None
browser: str | None = None
_browser: BrowserCLI | None = field(default=None, repr=False, compare=False, init=False)
def _b(self) -> BrowserCLI:
if self._browser is None:
raise RuntimeError("Tab is not bound to a BrowserCLI instance")
return self._browser
def close(self) -> None:
"""Close this tab."""
self._b()._cmd("tabs.close", {"tabId": self.id})
def activate(self) -> None:
"""Switch browser focus to this tab."""
self._b()._cmd("tabs.active", {"tabId": self.id})
def mute(self) -> None:
"""Mute this tab."""
self._b()._cmd("tabs.mute", {"tabId": self.id})
def unmute(self) -> None:
"""Unmute this tab."""
self._b()._cmd("tabs.unmute", {"tabId": self.id})
def reload(self) -> None:
"""Reload this tab."""
self._b()._cmd("navigate.reload", {"tabId": self.id})
def hard_reload(self) -> None:
"""Hard-reload this tab (bypass cache)."""
self._b()._cmd("navigate.hard_reload", {"tabId": self.id})
def move(
self, *,
forward: bool = False,
backward: bool = False,
group_id: int | None = None,
window_id: int | None = None,
index: int | None = None,
) -> None:
"""Move this tab.
Args:
forward: Move one position to the right within the window.
backward: Move one position to the left within the window.
group_id: Move into the tab group with this ID.
window_id: Move to the window with this ID.
index: Absolute position index in the target window.
"""
self._b()._cmd("tabs.move", {
"tabId": self.id,
"forward": forward,
"backward": backward,
"groupId": group_id,
"windowId": window_id,
"index": index,
})
def html(self) -> str:
"""Return the full HTML source of this tab."""
return self._b()._cmd("tabs.html", {"tabId": self.id})
def open(self, url: str, *, background: bool = False) -> None:
"""Navigate this tab to *url* in place."""
self._b().navigate_tab(self.id, url)
# ── Group ─────────────────────────────────────────────────────────────────────
@dataclass
class Group:
"""A browser tab group."""
id: int
title: str
color: str
collapsed: bool
tab_count: int
browser: str | None = None
_browser: BrowserCLI | None = field(default=None, repr=False, compare=False, init=False)
def _b(self) -> BrowserCLI:
if self._browser is None:
raise RuntimeError("Group is not bound to a BrowserCLI instance")
return self._browser
def close(self) -> None:
"""Ungroup (and close) this tab group."""
self._b()._cmd("group.close", {"groupId": self.id})
def tabs(self) -> list[Tab]:
"""Return all tabs inside this group."""
return self._b().group_tabs(self.id)
def move(self, *, forward: bool = False, backward: bool = False) -> None:
"""Move this group forward or backward among groups."""
self._b()._cmd("group.move", {
"group": str(self.id),
"forward": forward,
"backward": backward,
})
def add_tab(self, url: str | None = None) -> int | None:
"""Open a new tab inside this group. Returns the new tab ID."""
return self._b().group_add_tab(self.id, url)