61 lines
1.9 KiB
Python
61 lines
1.9 KiB
Python
"""SomaFM: the station catalogue Beefy Player was born with.
|
|
|
|
Everything SomaFM-specific lives in this package — the ``channels.json``
|
|
schema, the ``songs/<station>.json`` history, the ``.pls`` layout and the
|
|
guessed icecast mirrors. The rest of the app only sees
|
|
:class:`SomaFMProvider`, which implements
|
|
:class:`beefy_player.providers.base.RadioProvider`.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import httpx
|
|
|
|
from ... import config
|
|
from ...models import Song, Station
|
|
from ..base import RadioProvider
|
|
from . import api, fallback
|
|
from . import hero as hero_art
|
|
|
|
__all__ = ["SomaFMProvider"]
|
|
|
|
|
|
class SomaFMProvider(RadioProvider):
|
|
id = "somafm"
|
|
name = "SomaFM"
|
|
homepage = "somafm.com"
|
|
brand = "SOMA FM"
|
|
tagline = "listener-supported radio · san francisco"
|
|
station_source = "somafm.com/channels.json"
|
|
history_source = "songs/<station>.json"
|
|
|
|
hero = hero_art.LOGO
|
|
hero_gradient = True
|
|
hero_lines = hero_art.TAGLINES
|
|
|
|
@property
|
|
def user_agent(self) -> str:
|
|
# SomaFM asks clients to identify themselves, so say who we are and
|
|
# where we come from.
|
|
return f"{config.USER_AGENT}; +https://somafm.com"
|
|
|
|
async def fetch_stations(self, client: httpx.AsyncClient) -> list[Station]:
|
|
return await api.fetch_channels(client)
|
|
|
|
def load_cached_stations(self) -> list[Station]:
|
|
return api.load_cached_channels()
|
|
|
|
def fallback_stations(self) -> list[Station]:
|
|
return api.parse_channels({"channels": fallback.fallback_channels()})
|
|
|
|
async def fetch_history(
|
|
self, client: httpx.AsyncClient, station_id: str
|
|
) -> list[Song]:
|
|
return await api.fetch_history(client, station_id)
|
|
|
|
def load_cached_history(self, station_id: str) -> list[Song]:
|
|
return api.load_cached_songs(station_id)
|
|
|
|
def fallback_urls(self, station: Station) -> list[str]:
|
|
return api.synthetic_mirrors(station.id)
|