1 """Expose Radio Browser as a media source."""
3 from __future__
import annotations
8 from radios
import FilterBy, Order, RadioBrowser, Station
20 from .
import RadioBrowserConfigEntry
21 from .const
import DOMAIN
27 "OGG":
"application/ogg",
32 """Set up Radio Browser media source."""
34 entry = hass.config_entries.async_entries(DOMAIN)[0]
40 """Provide Radio stations as media sources."""
42 name =
"Radio Browser"
44 def __init__(self, hass: HomeAssistant, entry: RadioBrowserConfigEntry) ->
None:
45 """Initialize RadioMediaSource."""
52 """Return the radio browser."""
53 return self.
entryentry.runtime_data
56 """Resolve selected Radio station to a streaming URL."""
59 station = await radios.station(uuid=item.identifier)
61 raise Unresolvable(
"Radio station is no longer available")
64 raise Unresolvable(
"Could not determine stream type of radio station")
67 await radios.station_click(uuid=station.uuid)
73 item: MediaSourceItem,
74 ) -> BrowseMediaSource:
81 media_class=MediaClass.CHANNEL,
82 media_content_type=MediaType.MUSIC,
83 title=self.
entryentry.title,
86 children_media_class=MediaClass.DIRECTORY,
98 """Determine mime type of a radio station."""
99 mime_type = CODEC_TO_MIMETYPE.get(station.codec)
101 mime_type, _ = mimetypes.guess_type(station.url)
106 self, radios: RadioBrowser, stations: list[Station]
107 ) -> list[BrowseMediaSource]:
108 """Build list of media sources from radio stations."""
109 items: list[BrowseMediaSource] = []
111 for station
in stations:
112 if station.codec ==
"UNKNOWN" or not (
120 identifier=station.uuid,
121 media_class=MediaClass.MUSIC,
122 media_content_type=mime_type,
126 thumbnail=station.favicon,
133 self, radios: RadioBrowser, item: MediaSourceItem
134 ) -> list[BrowseMediaSource]:
135 """Handle browsing radio stations by country."""
136 category, _, country_code = (item.identifier
or "").partition(
"/")
138 stations = await radios.stations(
139 filter_by=FilterBy.COUNTRY_CODE_EXACT,
140 filter_term=country_code,
148 if not item.identifier
or category ==
"country":
150 await self.
hasshass.async_add_executor_job(
lambda: len(pycountry.countries))
151 countries = await radios.countries(order=Order.NAME)
155 identifier=f
"country/{country.code}",
156 media_class=MediaClass.DIRECTORY,
157 media_content_type=MediaType.MUSIC,
161 thumbnail=country.favicon,
163 for country
in countries
169 self, radios: RadioBrowser, item: MediaSourceItem
170 ) -> list[BrowseMediaSource]:
171 """Handle browsing radio stations by language."""
172 category, _, language = (item.identifier
or "").partition(
"/")
173 if category ==
"language" and language:
174 stations = await radios.stations(
175 filter_by=FilterBy.LANGUAGE_EXACT,
176 filter_term=language,
183 if category ==
"language":
184 languages = await radios.languages(order=Order.NAME, hide_broken=
True)
188 identifier=f
"language/{language.code}",
189 media_class=MediaClass.DIRECTORY,
190 media_content_type=MediaType.MUSIC,
194 thumbnail=language.favicon,
196 for language
in languages
199 if not item.identifier:
203 identifier=
"language",
204 media_class=MediaClass.DIRECTORY,
205 media_content_type=MediaType.MUSIC,
215 self, radios: RadioBrowser, item: MediaSourceItem
216 ) -> list[BrowseMediaSource]:
217 """Handle browsing popular radio stations."""
218 if item.identifier ==
"popular":
219 stations = await radios.stations(
222 order=Order.CLICK_COUNT,
227 if not item.identifier:
231 identifier=
"popular",
232 media_class=MediaClass.DIRECTORY,
233 media_content_type=MediaType.MUSIC,
243 self, radios: RadioBrowser, item: MediaSourceItem
244 ) -> list[BrowseMediaSource]:
245 """Handle browsing radio stations by tags."""
246 category, _, tag = (item.identifier
or "").partition(
"/")
247 if category ==
"tag" and tag:
248 stations = await radios.stations(
249 filter_by=FilterBy.TAG_EXACT,
257 if category ==
"tag":
258 tags = await radios.tags(
261 order=Order.STATION_COUNT,
266 tags.sort(key=
lambda tag: tag.name)
271 identifier=f
"tag/{tag.name}",
272 media_class=MediaClass.DIRECTORY,
273 media_content_type=MediaType.MUSIC,
274 title=tag.name.title(),
281 if not item.identifier:
286 media_class=MediaClass.DIRECTORY,
287 media_content_type=MediaType.MUSIC,