import click from browser_cli.commands import client_from_ctx, handle_errors from rich.console import Console console = Console() ENGINES = { "google": "https://www.google.com/search?q={query}", "brave": "https://search.brave.com/search?q={query}", "duckduckgo": "https://duckduckgo.com/?q={query}", "ddg": "https://duckduckgo.com/?q={query}", "youtube": "https://www.youtube.com/results?search_query={query}", "yt": "https://www.youtube.com/results?search_query={query}", "spotify": "https://open.spotify.com/search/{query}", "amazon": "https://www.amazon.com/s?k={query}", "ecosia": "https://www.ecosia.org/search?q={query}", "furaffinity": "https://www.furaffinity.net/search/?q={query}", "fa": "https://www.furaffinity.net/search/?q={query}", "bing": "https://www.bing.com/search?q={query}", "github": "https://github.com/search?q={query}", "wikipedia": "https://en.wikipedia.org/wiki/Special:Search?search={query}", "wiki": "https://en.wikipedia.org/wiki/Special:Search?search={query}", "reddit": "https://www.reddit.com/search/?q={query}", "stackoverflow": "https://stackoverflow.com/search?q={query}", "so": "https://stackoverflow.com/search?q={query}", } _DISPLAY_NAMES = { "google": "Google", "brave": "Brave Search", "duckduckgo": "DuckDuckGo", "ddg": "DuckDuckGo", "youtube": "YouTube", "yt": "YouTube", "spotify": "Spotify", "amazon": "Amazon", "ecosia": "Ecosia", "furaffinity": "FurAffinity", "fa": "FurAffinity", "bing": "Bing", "github": "GitHub", "wikipedia": "Wikipedia", "wiki": "Wikipedia", "reddit": "Reddit", "stackoverflow": "Stack Overflow", "so": "Stack Overflow", } _SUBCOMMANDS = [ ("google", "Search with Google."), ("brave", "Search with Brave Search."), ("duckduckgo", "Search with DuckDuckGo."), ("ddg", "Search with DuckDuckGo (alias for duckduckgo)."), ("youtube", "Search YouTube videos."), ("yt", "Search YouTube (alias for youtube)."), ("spotify", "Search Spotify."), ("amazon", "Search Amazon."), ("ecosia", "Search with Ecosia."), ("furaffinity", "Search FurAffinity."), ("fa", "Search FurAffinity (alias for furaffinity)."), ("bing", "Search with Bing."), ("github", "Search GitHub."), ("wikipedia", "Search Wikipedia."), ("wiki", "Search Wikipedia (alias for wikipedia)."), ("reddit", "Search Reddit."), ("stackoverflow", "Search Stack Overflow."), ("so", "Search Stack Overflow (alias for stackoverflow)."), ] @click.group("search") def search_group(): """Search the web — open a query in a search engine.""" def _build_command(engine_key: str, help_text: str) -> click.Command: @click.command(engine_key, help=help_text) @click.argument("query", nargs=-1, required=True) @click.option("--bg", is_flag=True, help="Open in background (no focus)") @click.option("--window", "window", default=None, help="Open in named window") @click.option("--group", "group", default=None, help="Open in tab group (name or ID)") @handle_errors def _cmd(query, bg, window, group): terms = " ".join(query) client_from_ctx().nav.search(engine_key, terms, background=bg, window=window, group=group) suffix = f" in group '{group}'" if group else (f" in window '{window}'" if window else "") display = _DISPLAY_NAMES.get(engine_key, engine_key.capitalize()) console.print(f"[green]Searching[/green] [cyan]{display}[/cyan]: {terms}{suffix}") return _cmd for _name, _help in _SUBCOMMANDS: search_group.add_command(_build_command(_name, _help))