Jarian Cottingham 5c283eceef chore: remove test artifacts, fix hardcoded paths, ruff clean, license
- Remove committed .coverage and test-results/ (196K screenshots); gitignore them
- Fix hardcoded  /home/userpath + venv/bin/python in test_endpoints.py
  (relative backend dir + sys.executable)
- Fix concatenated 'import json' in settings.py; bare excepts -> Exception;
  SQLAlchemy-safe is_active.is_(True); __all__ on models/schemas barrels
- ruff clean (93 fixes), MIT LICENSE, PLAN.md -> docs/, README Tests section
- 300 tests pass, 93.7% coverage
2026-08-20 21:34:15 +00:00

62 lines
2.0 KiB
Python

from fastapi import APIRouter, Query
from fastapi.responses import StreamingResponse
from typing import List, Optional
import httpx
from ..schemas.radio import RadioStationResponse, RadioCurrentResponse
from ..services.radio_browser import fetch_stations, fetch_nearby_stations
router = APIRouter(prefix="/api/radio", tags=["radio"])
@router.get("/stations", response_model=List[RadioStationResponse])
async def list_stations(
country: Optional[str] = None,
genre: Optional[str] = None,
limit: int = Query(50, ge=1, le=200),
):
stations = fetch_stations(country=country, genre=genre, limit=limit)
return stations
@router.get("/nearby", response_model=List[RadioStationResponse])
async def nearby_stations(
lat: float = Query(...),
lon: float = Query(...),
radius: int = Query(100, ge=1, le=1000),
):
stations = fetch_nearby_stations(lat=lat, lon=lon, radius=radius)
return stations
@router.get("/current")
async def current_playing():
return RadioCurrentResponse(
station=None,
song_name=None,
artist_name=None,
is_playing=False,
)
@router.get("/stream/{station_id}")
async def stream_radio(station_id: str): # pragma: no cover
stations = fetch_stations(limit=200)
station = next((s for s in stations if s["id"] == station_id), None)
if not station or not station.get("stream_url"):
return {"error": "Station not found or no stream URL"}
async with httpx.AsyncClient(timeout=30.0) as client:
async with client.stream("GET", station["stream_url"]) as response:
async def stream():
async for chunk in response.aiter_bytes(chunk_size=1024 * 1024):
yield chunk
return StreamingResponse(
stream(),
media_type="audio/mpeg",
headers={
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "*",
},
)