"""Console entry point.""" from __future__ import annotations import argparse import asyncio from collections.abc import Sequence from . import __version__ from .providers import available_providers, get_provider from .providers.base import make_client from .spectrum import SOURCE_MODES def _build_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( prog="beefy-player", description="Beefy Player — a flashy terminal player for internet " "radio: live spectrum, song history and desktop media integration.", ) parser.add_argument( "--provider", choices=available_providers(), metavar="ID", help="station catalogue to use (default: the one in the config file)", ) parser.add_argument("--station", metavar="ID", help="station id to select") parser.add_argument( "--play", dest="autoplay", action="store_true", default=None, help="start playing immediately", ) parser.add_argument( "--no-autoplay", dest="autoplay", action="store_false", help="never start playing on launch", ) parser.add_argument("--volume", type=int, metavar="0-100", help="initial volume") parser.add_argument( "--no-mpris", "--no-media", dest="no_mpris", action="store_true", help="do not publish to the desktop media session (MPRIS on Linux, " "Now Playing on macOS) and ignore the media keys", ) parser.add_argument( "--offline", action="store_true", help="do not touch the network (cached/bundled stations only)", ) parser.add_argument( "--no-audio", action="store_true", help="UI only; skip mpv/ffmpeg/MPRIS (useful for demos)", ) parser.add_argument( "--spectrum-source", choices=SOURCE_MODES, default="auto", help="spectrum audio source: auto (monitor→stream→sim), monitor " "(parec on Linux, a Core Audio process tap on macOS), " "stream (muted second ffmpeg decode), or sim", ) parser.add_argument( "--diagnose-images", action="store_true", help="print terminal/image-protocol diagnostics and exit", ) parser.add_argument( "--list", action="store_true", help="print known station ids and exit", ) parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}") return parser def _list_stations(offline: bool, provider_id: str | None = None) -> int: provider = get_provider(provider_id) stations = provider.load_cached_stations() if not stations and not offline: async def load(): client = make_client(provider.user_agent) try: return await provider.fetch_stations(client) finally: await client.aclose() try: stations = asyncio.run(load()) except Exception: stations = [] if not stations: stations = provider.fallback_stations() print(f"# {provider.name} ({provider.id}) — {provider.station_source}") for station in sorted(stations, key=lambda item: item.title.casefold()): print(f"{station.id:<20} {station.title}") return 0 def main(argv: Sequence[str] | None = None) -> int: args = _build_parser().parse_args(argv) if args.diagnose_images: from . import artwork for key, value in artwork.diagnostics().items(): print(f"{key}: {value}") return 0 if args.list: return _list_stations(args.offline, args.provider) # Import the app lazily so --list/--version do not probe the terminal for # image protocols. from .app import BeefyPlayerApp app = BeefyPlayerApp( provider=args.provider, autoplay=args.autoplay, station_id=args.station, volume=args.volume, media=not args.no_mpris, offline=args.offline, audio=not args.no_audio, spectrum_source=args.spectrum_source, ) app.run() return 0 if __name__ == "__main__": raise SystemExit(main())