"""Console entry point.""" from __future__ import annotations import argparse import asyncio from collections.abc import Sequence from . import __version__, api from .fallback import fallback_channels from .spectrum import SOURCE_MODES def _build_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( prog="somafm-tui", description="A flashy terminal radio for somafm.com — live spectrum, " "song history and desktop media integration.", ) 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", action="store_true", help="do not announce playback over MPRIS", ) 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, " "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) -> int: stations = api.load_cached_channels() if not stations and not offline: async def load(): client = api.make_client() try: return await api.fetch_channels(client) finally: await client.aclose() try: stations = asyncio.run(load()) except Exception: stations = [] if not stations: stations = api.parse_channels({"channels": fallback_channels()}) 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) # Import the app lazily so --list/--version do not probe the terminal for # image protocols. from .app import SomaFMApp app = SomaFMApp( autoplay=args.autoplay, station_id=args.station, volume=args.volume, mpris=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())