From 1a066108298b845adc6cb5f870add2df7912e2a0 Mon Sep 17 00:00:00 2001 From: DButter Date: Mon, 19 Jan 2026 16:27:30 +0100 Subject: [PATCH] orf radiothek provider (#2968) * orf radiothek: Initial Commit * orf radiothek: fixed duplicate super call * orf radiothek: moved some config value to advanced category * orf radiothek: renamed classes to helper, removed catchup day conf entry set it to 30 days flat * orf radiothek: set stage to beta and corrected version * orf radiothek: some more cleanup * orf radiothek: fixed some code smells * orf radiothek: move stream quality type to advanced * Update music_assistant/providers/orf_radiothek/__init__.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: DButter Co-authored-by: Marvin Schenkel Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../providers/orf_radiothek/__init__.py | 1063 +++++++++++++++++ .../providers/orf_radiothek/helpers.py | 380 ++++++ .../providers/orf_radiothek/icon.svg | 3 + .../orf_radiothek/icon_monochrome.svg | 3 + .../providers/orf_radiothek/manifest.json | 14 + .../providers/orf_radiothek/media/bgl.png | Bin 0 -> 1333 bytes .../providers/orf_radiothek/media/fm4.png | Bin 0 -> 28544 bytes .../providers/orf_radiothek/media/ktn.png | Bin 0 -> 1510 bytes .../providers/orf_radiothek/media/noe.png | Bin 0 -> 3647 bytes .../providers/orf_radiothek/media/oe1.png | Bin 0 -> 11771 bytes .../providers/orf_radiothek/media/oe3.png | Bin 0 -> 36964 bytes .../providers/orf_radiothek/media/ooe.png | Bin 0 -> 2619 bytes .../providers/orf_radiothek/media/sbg.png | Bin 0 -> 1925 bytes .../providers/orf_radiothek/media/stm.png | Bin 0 -> 2276 bytes .../providers/orf_radiothek/media/tir.png | Bin 0 -> 399 bytes .../providers/orf_radiothek/media/vbg.png | Bin 0 -> 1649 bytes .../providers/orf_radiothek/media/wie.png | Bin 0 -> 2579 bytes 17 files changed, 1463 insertions(+) create mode 100644 music_assistant/providers/orf_radiothek/__init__.py create mode 100644 music_assistant/providers/orf_radiothek/helpers.py create mode 100644 music_assistant/providers/orf_radiothek/icon.svg create mode 100644 music_assistant/providers/orf_radiothek/icon_monochrome.svg create mode 100644 music_assistant/providers/orf_radiothek/manifest.json create mode 100644 music_assistant/providers/orf_radiothek/media/bgl.png create mode 100644 music_assistant/providers/orf_radiothek/media/fm4.png create mode 100644 music_assistant/providers/orf_radiothek/media/ktn.png create mode 100644 music_assistant/providers/orf_radiothek/media/noe.png create mode 100644 music_assistant/providers/orf_radiothek/media/oe1.png create mode 100644 music_assistant/providers/orf_radiothek/media/oe3.png create mode 100644 music_assistant/providers/orf_radiothek/media/ooe.png create mode 100644 music_assistant/providers/orf_radiothek/media/sbg.png create mode 100644 music_assistant/providers/orf_radiothek/media/stm.png create mode 100644 music_assistant/providers/orf_radiothek/media/tir.png create mode 100644 music_assistant/providers/orf_radiothek/media/vbg.png create mode 100644 music_assistant/providers/orf_radiothek/media/wie.png diff --git a/music_assistant/providers/orf_radiothek/__init__.py b/music_assistant/providers/orf_radiothek/__init__.py new file mode 100644 index 00000000..b4a37bb2 --- /dev/null +++ b/music_assistant/providers/orf_radiothek/__init__.py @@ -0,0 +1,1063 @@ +"""ORF Radiothek / ORF Sound provider for Music Assistant. + +Features: +- Live radios (ORF stations + privates) from ORF bundle.json +- ORF station logos from local provider media/.png (served via resolve_image) +- Catch-up broadcasts exposed as Podcasts + PodcastEpisodes (last N days), auto-removed by sync +- ORF Sound “actual podcasts” (api 2.0) exposed as Podcasts + PodcastEpisodes (full feed) + +Endpoints: +- bundle.json: + https://orf.at/app-infos/sound/web/1.0/bundle.json?_o=sound.orf.at +- broadcasts by day: + https://audioapi.orf.at//api/json/5.0/broadcasts/ +- broadcast detail: + https://audioapi.orf.at//api/json/5.0/broadcast/ +- podcasts index: + https://audioapi.orf.at/radiothek/api/public/2.0/podcasts +- podcast detail (+episodes): + https://audioapi.orf.at/radiothek/api/public/2.0/podcast/?episodes=episodes +""" + +from __future__ import annotations + +import re +from collections.abc import AsyncGenerator +from datetime import UTC, datetime, timedelta +from pathlib import Path +from typing import TYPE_CHECKING, Any + +from aiohttp import ClientError, ClientTimeout +from music_assistant_models.config_entries import ConfigEntry +from music_assistant_models.enums import ( + ConfigEntryType, + ContentType, + ImageType, + MediaType, + ProviderFeature, + StreamType, +) +from music_assistant_models.errors import MediaNotFoundError, UnplayableMediaError +from music_assistant_models.media_items import ( + AudioFormat, + ItemMapping, + MediaItemImage, + Podcast, + PodcastEpisode, + ProviderMapping, + Radio, + SearchResults, +) +from music_assistant_models.streamdetails import StreamDetails + +from music_assistant.controllers.cache import use_cache +from music_assistant.models.music_provider import MusicProvider + +from .helpers import ( + OrfPodcast, + OrfPodcastEpisode, + OrfStation, + PrivateStation, + parse_orf_podcast_episodes, + parse_orf_podcasts_index, + parse_orf_stations, + parse_private_stations, +) + +if TYPE_CHECKING: + from music_assistant_models.config_entries import ConfigValueType, ProviderConfig + from music_assistant_models.provider import ProviderManifest + + from music_assistant.mass import MusicAssistant + from music_assistant.models import ProviderInstanceType + + +# ORF Sound bundle (stations + privates) +API_BUNDLE = "https://orf.at/app-infos/sound/web/1.0/bundle.json?_o=sound.orf.at" + +# ORF broadcasts (catch-up “Sendungen” per station/day) +BROADCASTS_URL = "https://audioapi.orf.at/{station}/api/json/5.0/broadcasts/{yyyymmdd}" +BROADCAST_URL = "https://audioapi.orf.at/{station}/api/json/5.0/broadcast/{bid}" + +# ORF actual podcasts (API 2.0) +PODCASTS_INDEX_URL = "https://audioapi.orf.at/radiothek/api/public/2.0/podcasts" +PODCAST_DETAIL_URL = ( + "https://audioapi.orf.at/radiothek/api/public/2.0/podcast/{pid}?episodes=episodes" +) + +# Provider config +CONF_STREAM_PROTO = "stream_proto" # hls | shoutcast (ORF stations only) +CONF_STREAM_QUALITY = "stream_quality" # hls: q1a/q2a/q3a/q4a/qxa ; shoutcast: q1a/q2a +CONF_INCLUDE_HIDDEN = "include_hidden" + +CONF_CATCHUP_PROTO = "catchup_proto" # progressive | hls +CONF_CATCHUP_STATIONS = "catchup_stations" # optional comma-separated station ids + +# local-image pseudo scheme (provider-owned) +LOCAL_IMG_PREFIX = "radiothek://station/" +CATCHUP_DAYS = 30 + +SUPPORTED_FEATURES = { + ProviderFeature.SEARCH, + ProviderFeature.LIBRARY_RADIOS, + ProviderFeature.LIBRARY_PODCASTS, +} + + +async def setup( + mass: MusicAssistant, manifest: ProviderManifest, config: ProviderConfig +) -> ProviderInstanceType: + """Set up the ORF Radiothek provider.""" + return RadiothekProvider(mass, manifest, config, SUPPORTED_FEATURES) + + +async def get_config_entries( + mass: MusicAssistant, + instance_id: str | None = None, + action: str | None = None, + values: dict[str, ConfigValueType] | None = None, +) -> tuple[ConfigEntry, ...]: + """Return provider configuration entries.""" + values = values or {} # ruff: noqa: ARG001 + + return ( + ConfigEntry( + key=CONF_STREAM_PROTO, + type=ConfigEntryType.STRING, + label="Preferred ORF protocol", + required=False, + default_value="hls", + description=( + "Used for ORF stations (template-based). " + "Privates use explicit URLs from bundle.json." + ), + value=values.get(CONF_STREAM_PROTO), + category="advanced", + ), + ConfigEntry( + key=CONF_STREAM_QUALITY, + type=ConfigEntryType.STRING, + label="ORF quality", + required=False, + default_value="qxa", + description="For ORF HLS: q1a/q2a/q3a/q4a/qxa. For shoutcast: q1a/q2a.", + value=values.get(CONF_STREAM_QUALITY), + category="advanced", + ), + ConfigEntry( + key=CONF_INCLUDE_HIDDEN, + type=ConfigEntryType.BOOLEAN, + label="Include hidden stations", + required=False, + default_value=False, + description="Include stations with hideFromStations=true.", + value=values.get(CONF_INCLUDE_HIDDEN), + category="advanced", + ), + ConfigEntry( + key=CONF_CATCHUP_PROTO, + type=ConfigEntryType.STRING, + label="Catch-up stream type", + required=False, + default_value="progressive", + description="Use 'progressive' (mp3) or 'hls' (m3u8) URLs from the broadcast detail.", + value=values.get(CONF_CATCHUP_PROTO), + ), + ConfigEntry( + key=CONF_CATCHUP_STATIONS, + type=ConfigEntryType.STRING, + label="Catch-up stations (optional)", + required=False, + default_value="", + description=( + "Comma-separated station ids (e.g. 'stm,wie,oe1'). " + "Empty = all ORF stations from bundle." + ), + value=values.get(CONF_CATCHUP_STATIONS), + ), + ) + + +class RadiothekProvider(MusicProvider): + """ORF Radiothek provider.""" + + def __init__(self, *args: Any, **kwargs: Any) -> None: + """Initialize provider state.""" + super().__init__(*args, **kwargs) + self._bundle: dict[str, Any] | None = None + self._media_dir = Path(__file__).parent / "media" + + self.stream_proto = "hls" + self.stream_quality = "qxa" + self.include_hidden = False + + self.catchup_proto = "progressive" + self.catchup_stations = "" + + @property + def is_streaming_provider(self) -> bool: + """Return True for streaming providers.""" + return True + + async def handle_async_init(self) -> None: + """Load config and prime caches.""" + self.stream_proto = str(self.config.get_value(CONF_STREAM_PROTO) or "hls").lower() + self.stream_quality = str(self.config.get_value(CONF_STREAM_QUALITY) or "qxa").lower() + self.include_hidden = bool(self.config.get_value(CONF_INCLUDE_HIDDEN) or False) + + self.catchup_proto = str(self.config.get_value(CONF_CATCHUP_PROTO) or "progressive").lower() + self.catchup_stations = str(self.config.get_value(CONF_CATCHUP_STATIONS) or "").strip() + + if self.stream_proto not in ("hls", "shoutcast"): + self.stream_proto = "hls" + + if self.stream_proto == "shoutcast": + if self.stream_quality not in ("q1a", "q2a"): + self.stream_quality = "q2a" + elif self.stream_quality not in ("q1a", "q2a", "q3a", "q4a", "qxa"): + self.stream_quality = "qxa" + + if self.catchup_proto not in ("progressive", "hls"): + self.catchup_proto = "progressive" + + await self._get_bundle(force=True) + + # ---------------------------- + # HTTP / caching helpers + # ---------------------------- + + async def _http_get_json(self, url: str) -> dict[str, Any]: + async with self.mass.http_session.get( + url, + headers={"User-Agent": "Music Assistant"}, + timeout=ClientTimeout(total=20), + ) as resp: + resp.raise_for_status() + data = await resp.json() + if not isinstance(data, dict): + raise TypeError("Expected JSON object") + return data + + async def _get_bundle(self, force: bool = False) -> dict[str, Any]: + if self._bundle is not None and not force: + return self._bundle + try: + self._bundle = await self._http_get_json(API_BUNDLE) + return self._bundle + except (ClientError, TimeoutError, ValueError) as err: + self.logger.warning("Failed to fetch bundle.json: %s", err) + if self._bundle is not None: + return self._bundle + raise + + @use_cache(3600 * 24) + async def _get_broadcasts_for_day(self, station: str, yyyymmdd: str) -> list[dict[str, Any]]: + data = await self._http_get_json(BROADCASTS_URL.format(station=station, yyyymmdd=yyyymmdd)) + payload = data.get("payload") + if not isinstance(payload, list): + return [] + return [x for x in payload if isinstance(x, dict)] + + @use_cache(3600 * 24) + async def _get_broadcast_detail(self, station: str, bid: int) -> dict[str, Any]: + data = await self._http_get_json(BROADCAST_URL.format(station=station, bid=bid)) + payload = data.get("payload") + return payload if isinstance(payload, dict) else {} + + @use_cache(3600 * 24) + async def _get_orf_podcasts_index_payload(self) -> dict[str, Any]: + data = await self._http_get_json(PODCASTS_INDEX_URL) + payload = data.get("payload") + return payload if isinstance(payload, dict) else {} + + async def _get_orf_podcasts_index(self) -> list[OrfPodcast]: + payload = await self._get_orf_podcasts_index_payload() + return parse_orf_podcasts_index(payload) + + @use_cache(3600 * 24) + async def _get_orf_podcast_detail(self, pid: int) -> dict[str, Any]: + data = await self._http_get_json(PODCAST_DETAIL_URL.format(pid=pid)) + payload = data.get("payload") + return payload if isinstance(payload, dict) else {} + + # ---------------------------- + # Bundle parsing + # ---------------------------- + + def _iter_orf_stations(self, bundle: dict[str, Any]) -> list[OrfStation]: + return parse_orf_stations(bundle, include_hidden=self.include_hidden) + + def _iter_privates(self, bundle: dict[str, Any]) -> list[PrivateStation]: + return parse_private_stations(bundle) + + def _privates_by_id(self, bundle: dict[str, Any]) -> dict[str, PrivateStation]: + return {p.id: p for p in self._iter_privates(bundle)} + + def _catchup_station_ids(self, bundle: dict[str, Any]) -> list[str]: + stations = [s.id for s in self._iter_orf_stations(bundle)] + if self.catchup_stations: + allowed = {s.strip() for s in self.catchup_stations.split(",") if s.strip()} + stations = [s for s in stations if s in allowed] + return stations + + # ---------------------------- + # Images + # ---------------------------- + + def _orf_local_icon_image(self, station_id: str) -> MediaItemImage | None: + if (self._media_dir / f"{station_id}.png").is_file(): + return MediaItemImage( + type=ImageType.THUMB, + path=f"{LOCAL_IMG_PREFIX}{station_id}.png", + provider=self.domain, + remotely_accessible=False, + ) + return None + + async def resolve_image(self, path: str) -> str | bytes: + """Resolve provider-local image paths to a file path.""" + if not path.startswith(LOCAL_IMG_PREFIX): + return path + + filename = path.removeprefix(LOCAL_IMG_PREFIX) + if "/" in filename or "\\" in filename or ".." in filename: + raise MediaNotFoundError("Image not found.") + + fpath = self._media_dir / filename + if not fpath.is_file(): + raise MediaNotFoundError("Image not found.") + + return str(fpath) + + # ---------------------------- + # Stream URL helpers (radio) + # ---------------------------- + + def _build_orf_url(self, station: OrfStation) -> str | None: + tmpl = station.live_stream_url_template + if not isinstance(tmpl, str) or "{quality}" not in tmpl: + return None + if self.stream_proto == "shoutcast": + return f"https://orf-live.ors-shoutcast.at/{station.id}-{self.stream_quality}" + return tmpl.replace("{quality}", self.stream_quality) + + def _build_private_url(self, pstation: PrivateStation) -> tuple[str | None, str | None]: + if not pstation.streams: + return None, None + s0 = pstation.streams[0] + return s0.url, s0.format + + def _content_type_from_url_or_format(self, url: str, fmt: str | None) -> ContentType: + if fmt: + f = fmt.lower() + if f == "mp3": + return ContentType.try_parse("mp3") + if f in ("aac", "aacp"): + return ContentType.try_parse("aac") + if ".m3u8" in url.lower(): + return ContentType.try_parse("aac") + return ContentType.try_parse("unknown") + + # ---------------------------- + # ID schemes (avoid collisions) + # ---------------------------- + + # catch-up podcasts/episodes from broadcasts API + def _catchup_podcast_id(self, station_id: str) -> str: + return f"br:{station_id}" + + def _catchup_episode_id(self, station_id: str, bid: int) -> str: + return f"br:{station_id}:{bid}" + + def _parse_catchup_episode_id(self, prov_episode_id: str) -> tuple[str, int]: + # br:: + _, station, bid_s = prov_episode_id.split(":", 2) + return station, int(bid_s) + + # actual podcasts API 2.0 + def _podcast_id(self, pid: int) -> str: + return f"pod:{pid}" + + def _pod_episode_id(self, pid: int, guid: str) -> str: + return f"pod:{pid}:{guid}" + + def _parse_pod_episode_id(self, prov_episode_id: str) -> tuple[int, str]: + # pod:: + _, pid_s, guid = prov_episode_id.split(":", 2) + return int(pid_s), guid + + # ---------------------------- + # Text helpers + # ---------------------------- + def _strip_html(self, s: str | None) -> str | None: + if not s: + return None + return re.sub(r"<[^>]+>", "", s).strip() + + def _sanitize_template_url(self, url: str) -> str: + # ORF template URLs contain "{&offset}" / "{&duration}" etc. + return re.sub(r"\{[^}]+\}", "", url) + + # ---------------------------- + # Media item constructors + # ---------------------------- + + def _radio_item(self, item_id: str, name: str) -> Radio: + return Radio( + name=name, + item_id=item_id, + provider=self.instance_id, + provider_mappings={ + ProviderMapping( + item_id=item_id, + provider_domain=self.domain, + provider_instance=self.instance_id, + ) + }, + ) + + def _podcast_from_station(self, station: OrfStation) -> Podcast: + name = station.name or station.id + pid = self._catchup_podcast_id(station.id) + p = Podcast( + name=name, + item_id=pid, + provider=self.instance_id, + provider_mappings={ + ProviderMapping( + item_id=pid, + provider_domain=self.domain, + provider_instance=self.instance_id, + ) + }, + ) + p.metadata.description = f"Catch-up broadcasts for {name}" + img = self._orf_local_icon_image(station.id) + if img: + # img is probably already a MediaItemImage + p.metadata.add_image(img) + return p + + def _episode_from_broadcast_obj( + self, + b: dict[str, Any], + station_id: str, + podcast_title: str, + podcast_id: str, + ) -> PodcastEpisode | None: + bid = b.get("id") + title = b.get("title") + if not isinstance(bid, int) or not isinstance(title, str) or not title: + return None + + prefix = self.iso_prefix(b.get("niceTime")) + name = f"{prefix} - {title}" if prefix else title + + duration_sec: int | None = None + dur_ms = b.get("duration") + if isinstance(dur_ms, int) and dur_ms > 0: + duration_sec = int(dur_ms / 1000) + + eid = self._catchup_episode_id(station_id, bid) + + ep = PodcastEpisode( + name=name, + item_id=eid, + provider=self.instance_id, + position=0, + duration=duration_sec or 0, + podcast=ItemMapping( + item_id=podcast_id, + provider=self.instance_id, + name=podcast_title, + media_type=MediaType.PODCAST, + ), + provider_mappings={ + ProviderMapping( + item_id=eid, + provider_domain=self.domain, + provider_instance=self.instance_id, + ) + }, + ) + + sub = self._strip_html(b.get("subtitle")) + if sub: + ep.metadata.description = sub + + # best image + imgs = b.get("images") + if isinstance(imgs, list) and imgs: + best_url: str | None = None + best_w = -1 + for img in imgs: + if not isinstance(img, dict): + continue + versions = img.get("versions") + if not isinstance(versions, list): + continue + for v in versions: + if not isinstance(v, dict): + continue + url = v.get("path") + if not isinstance(url, str) or not url.startswith("http"): + continue + w = int(v.get("width") or 0) + if w > best_w: + best_w = w + best_url = url + if best_url: + ep.metadata.add_image( + MediaItemImage( + type=ImageType.THUMB, + path=best_url, + provider=self.domain, + remotely_accessible=True, + ) + ) + + return ep + + def _podcast_from_orf_podcast_obj(self, pod: OrfPodcast) -> Podcast: + pid = pod.id + prov_id = self._podcast_id(pid) + p = Podcast( + name=pod.title or prov_id, + item_id=prov_id, + provider=self.instance_id, + provider_mappings={ + ProviderMapping( + item_id=prov_id, + provider_domain=self.domain, + provider_instance=self.instance_id, + ) + }, + ) + + if pod.description: + p.metadata.description = pod.description + + # image (best available) + if pod.image: + best = pod.image.best() + if best: + p.metadata.add_image( + MediaItemImage( + type=ImageType.THUMB, + path=best, + provider=self.domain, + remotely_accessible=True, + ) + ) + + return p + + @staticmethod + def iso_prefix(ts: str | None) -> str: + """Create a compact timestamp prefix for titles.""" + if not ts: + return "" + ts = ts.strip() + if "T" in ts: + return ts[:16].replace("T", " ") + return ts + + def _episode_from_orf_podcast_episode_obj( + self, ep: OrfPodcastEpisode, podcast: Podcast + ) -> PodcastEpisode: + guid = ep.guid + pid = int(podcast.item_id.split(":", 1)[1]) + eid = self._pod_episode_id(pid, guid) + + base_title = ep.title or guid + prefix = self.iso_prefix(ep.published) + name = f"{prefix} - {base_title}" if prefix else base_title + + duration_sec: int | None = None + if ep.duration_ms and ep.duration_ms > 0: + duration_sec = int(ep.duration_ms / 1000) + + pe = PodcastEpisode( + name=name, + item_id=eid, + provider=self.instance_id, + position=0, + duration=duration_sec or 0, + podcast=podcast, + provider_mappings={ + ProviderMapping( + item_id=eid, + provider_domain=self.domain, + provider_instance=self.instance_id, + ) + }, + ) + + if ep.description: + pe.metadata.description = ep.description + + # image (episode-level) + if ep.image: + best = ep.image.best() + if best: + pe.metadata.add_image( + MediaItemImage( + type=ImageType.THUMB, + path=best, + provider=self.domain, + remotely_accessible=True, + ) + ) + + if (not pe.metadata.images) and podcast.metadata.images: + for img in podcast.metadata.images: + pe.metadata.add_image(img) + return pe + + # ---------------------------- + # MA API: Radios + # ---------------------------- + + async def get_library_radios(self) -> AsyncGenerator[Radio, None]: + """Yield all radios exposed by this provider.""" + bundle = await self._get_bundle() + + # ORF stations (local icons) + for st in self._iter_orf_stations(bundle): + r = self._radio_item(st.id, st.name or st.id) + img = self._orf_local_icon_image(st.id) + if img: + r.metadata.add_image(img) + yield r + + # privates (remote icons) + for pst in self._iter_privates(bundle): + r = self._radio_item(pst.id, pst.name or pst.id) + for url in pst.image_urls: + r.metadata.add_image( + MediaItemImage( + type=ImageType.THUMB, + path=url, + provider=self.domain, + remotely_accessible=True, + ) + ) + yield r + + async def get_library_podcasts(self) -> AsyncGenerator[Podcast, None]: + """Yield all podcasts exposed by this provider.""" + bundle = await self._get_bundle() + + # A) catch-up “podcasts” (one per station, filtered) + stations = {s.id: s for s in self._iter_orf_stations(bundle)} + for station_id in self._catchup_station_ids(bundle): + st = stations.get(station_id) + if st: + yield self._podcast_from_station(st) + + # B) actual ORF podcasts + pods = await self._get_orf_podcasts_index() + for pod in pods: + yield self._podcast_from_orf_podcast_obj(pod) + + @use_cache(3600 * 24) + async def get_podcast(self, prov_podcast_id: str) -> Podcast: + """Get one specific Podcast by id.""" + bundle = await self._get_bundle() + + # catch-up station podcasts: br: + if prov_podcast_id.startswith("br:"): + station_id = prov_podcast_id.split(":", 1)[1] + stations = {s.id: s for s in self._iter_orf_stations(bundle)} + st = stations.get(station_id) + if not st: + raise MediaNotFoundError("Podcast not found.") + return self._podcast_from_station(st) + + # actual podcasts: pod: + if prov_podcast_id.startswith("pod:"): + try: + pid = int(prov_podcast_id.split(":", 1)[1]) + except (ValueError, IndexError) as err: + raise MediaNotFoundError("Podcast not found.") from err + + pods = await self._get_orf_podcasts_index() + pod = next((p for p in pods if p.id == pid), None) + if not pod: + detail = await self._get_orf_podcast_detail(pid) + if not detail: + raise MediaNotFoundError("Podcast not found.") + pod = OrfPodcast.from_index_item(detail) or OrfPodcast( + id=pid, title=str(detail.get("title") or pid) + ) + return self._podcast_from_orf_podcast_obj(pod) + + raise MediaNotFoundError("Podcast not found.") + + async def get_podcast_episodes( + self, prov_podcast_id: str + ) -> AsyncGenerator[PodcastEpisode, None]: + """Get episodes of a specific podcast.""" + bundle = await self._get_bundle() + + # ---------------------- + # actual ORF podcasts + # ---------------------- + if prov_podcast_id.startswith("pod:"): + pid = int(prov_podcast_id.split(":", 1)[1]) + pods = await self._get_orf_podcasts_index() + pod_obj = next((p for p in pods if p.id == pid), None) + if not pod_obj: + # allow if index missing but detail exists + detail = await self._get_orf_podcast_detail(pid) + if not detail: + raise MediaNotFoundError("Podcast not found.") + pod_obj = OrfPodcast.from_index_item(detail) or OrfPodcast( + id=pid, title=str(detail.get("title") or pid) + ) + + podcast = self._podcast_from_orf_podcast_obj(pod_obj) + + detail = await self._get_orf_podcast_detail(pid) + for orf_ep in parse_orf_podcast_episodes(detail): + if not orf_ep.enclosures or not orf_ep.enclosures[0].url: + continue + yield self._episode_from_orf_podcast_episode_obj(orf_ep, podcast) + return + + # ---------------------- + # catch-up station podcasts + # ---------------------- + if not prov_podcast_id.startswith("br:"): + raise MediaNotFoundError("Podcast not found.") + + station_id = prov_podcast_id.split(":", 1)[1] + + # enforce station filter + if self.catchup_stations: + allowed = {s.strip() for s in self.catchup_stations.split(",") if s.strip()} + if station_id not in allowed: + return + + stations = {s.id: s for s in self._iter_orf_stations(bundle)} + st = stations.get(station_id) + if not st: + raise MediaNotFoundError("Podcast not found.") + podcast_title = st.name or station_id + + today = datetime.now(UTC).date() + for day_offset in range(CATCHUP_DAYS): + d = today - timedelta(days=day_offset) + yyyymmdd = f"{d.year:04d}{d.month:02d}{d.day:02d}" + items = await self._get_broadcasts_for_day(station_id, yyyymmdd) + for b in items: + episode = self._episode_from_broadcast_obj( + b=b, + station_id=station_id, + podcast_title=podcast_title, + podcast_id=prov_podcast_id, + ) + if episode: + yield episode + + @use_cache(3600 * 24) + async def get_podcast_episode(self, prov_episode_id: str) -> PodcastEpisode: + """Get specific episode of specific podcast.""" + bundle = await self._get_bundle() + + # actual ORF podcasts: pod:: + if prov_episode_id.startswith("pod:"): + pid, guid = self._parse_pod_episode_id(prov_episode_id) + + pods = await self._get_orf_podcasts_index() + pod_obj = next((p for p in pods if p.id == pid), None) + if not pod_obj: + detail = await self._get_orf_podcast_detail(pid) + if not detail: + raise MediaNotFoundError("Podcast not found.") + pod_obj = OrfPodcast.from_index_item(detail) or OrfPodcast( + id=pid, title=str(detail.get("title") or pid) + ) + + podcast = self._podcast_from_orf_podcast_obj(pod_obj) + + detail = await self._get_orf_podcast_detail(pid) + for orf_ep in parse_orf_podcast_episodes(detail): + if orf_ep.guid == guid: + return self._episode_from_orf_podcast_episode_obj(orf_ep, podcast) + + raise MediaNotFoundError("Podcast episode not found.") + + # catch-up episodes: br:: + if prov_episode_id.startswith("br:"): + station_id, bid = self._parse_catchup_episode_id(prov_episode_id) + stations = {s.id: s for s in self._iter_orf_stations(bundle)} + st = stations.get(station_id) + if not st: + raise MediaNotFoundError("Podcast not found.") + podcast_title = st.name or station_id + podcast_id = self._catchup_podcast_id(station_id) + + b = await self._get_broadcast_detail(station_id, bid) + episode = self._episode_from_broadcast_obj( + b=b, + station_id=station_id, + podcast_title=podcast_title, + podcast_id=podcast_id, + ) + if not episode: + raise MediaNotFoundError("Podcast episode not found.") + + desc = self._strip_html(b.get("description")) + if desc: + episode.metadata.description = desc + + return episode + + raise MediaNotFoundError("Podcast episode not found.") + + # ---------------------------- + # MA API: Search + # ---------------------------- + + @use_cache(3600 * 6) + async def search( + self, + search_query: str, + media_types: list[MediaType], + limit: int = 10, + ) -> SearchResults: + """Search radios, podcasts or podcast episodes.""" + res = SearchResults() + q = search_query.strip().lower() + bundle = await self._get_bundle() + + if MediaType.RADIO in media_types: + radios: list[Radio] = [] + + for st in self._iter_orf_stations(bundle): + if q in st.id.lower() or q in (st.name or "").lower(): + r = self._radio_item(st.id, st.name or st.id) + img = self._orf_local_icon_image(st.id) + if img: + r.metadata.add_image(img) + radios.append(r) + if len(radios) >= limit: + break + + if len(radios) < limit: + for pst in self._iter_privates(bundle): + if q in pst.id.lower() or q in (pst.name or "").lower(): + r = self._radio_item(pst.id, pst.name or pst.id) + for url in pst.image_urls: + r.metadata.add_image( + MediaItemImage( + type=ImageType.THUMB, + path=url, + provider=self.domain, + remotely_accessible=True, + ) + ) + radios.append(r) + if len(radios) >= limit: + break + + res.radio = radios + + # Optional: podcast search (station catch-up podcasts + actual podcasts) + if MediaType.PODCAST in media_types and hasattr(res, "podcasts"): + podcasts: list[Podcast] = [] + + # catch-up station podcasts + stations: dict[str, OrfStation] = {s.id: s for s in self._iter_orf_stations(bundle)} + for station_id in self._catchup_station_ids(bundle): + if station_id not in stations: + continue + st = stations[station_id] + if q in station_id.lower() or q in (st.name or "").lower(): + podcasts.append(self._podcast_from_station(st)) + if len(podcasts) >= limit: + break + + # actual podcasts + if len(podcasts) < limit: + pods = await self._get_orf_podcasts_index() + for pod in pods: + title = (pod.title or "").lower() + author = (pod.author or "").lower() + if q in title or q in author: + podcasts.append(self._podcast_from_orf_podcast_obj(pod)) + if len(podcasts) >= limit: + break + + res.podcasts = podcasts + + return res + + # ---------------------------- + # MA API: Lookup radios + # ---------------------------- + + @use_cache(3600 * 24) + async def get_radio(self, prov_radio_id: str) -> Radio: + """Search single radio.""" + bundle = await self._get_bundle() + + stations = {s.id: s for s in self._iter_orf_stations(bundle)} + st = stations.get(prov_radio_id) + if st: + r = self._radio_item(prov_radio_id, st.name or prov_radio_id) + img = self._orf_local_icon_image(prov_radio_id) + if img: + r.metadata.add_image(img) + return r + + priv = self._privates_by_id(bundle).get(prov_radio_id) + if priv: + r = self._radio_item(prov_radio_id, priv.name or prov_radio_id) + for url in priv.image_urls: + r.metadata.add_image( + MediaItemImage( + type=ImageType.THUMB, + path=url, + provider=self.domain, + remotely_accessible=True, + ) + ) + return r + + raise MediaNotFoundError("Radio not found.") + + # ---------------------------- + # MA API: Playback + # ---------------------------- + + async def _get_radio_stream_details(self, item_id: str) -> StreamDetails: + bundle = await self._get_bundle() + + stations = {s.id: s for s in self._iter_orf_stations(bundle)} + if item_id in stations: + url = self._build_orf_url(stations[item_id]) + if not url: + raise UnplayableMediaError("No stream URL for ORF station.") + ctype = self._content_type_from_url_or_format(url, None) + return StreamDetails( + provider=self.domain, + item_id=item_id, + media_type=MediaType.RADIO, + stream_type=StreamType.HTTP, + path=url, + audio_format=AudioFormat(content_type=ctype), + can_seek=False, + allow_seek=False, + ) + + priv = self._privates_by_id(bundle).get(item_id) + if priv: + url, fmt = self._build_private_url(priv) + if not url: + raise UnplayableMediaError("No stream URL for private station.") + ctype = self._content_type_from_url_or_format(url, fmt) + return StreamDetails( + provider=self.domain, + item_id=item_id, + media_type=MediaType.RADIO, + stream_type=StreamType.HTTP, + path=url, + audio_format=AudioFormat(content_type=ctype), + can_seek=False, + allow_seek=False, + ) + + raise MediaNotFoundError("Radio not found.") + + async def _get_podcast_episode_stream_details(self, item_id: str) -> StreamDetails: + if item_id.startswith("pod:"): + return await self._get_orf_podcast_episode_stream_details(item_id) + + if item_id.startswith("br:"): + return await self._get_broadcast_episode_stream_details(item_id) + + raise MediaNotFoundError("Podcast episode not found.") + + async def _get_orf_podcast_episode_stream_details(self, item_id: str) -> StreamDetails: + pid, guid = self._parse_pod_episode_id(item_id) + detail = await self._get_orf_podcast_detail(pid) + + eps = detail.get("episodes") + if not isinstance(eps, list): + raise UnplayableMediaError("No episodes for podcast") + + target: dict[str, Any] | None = None + for ep in eps: + if isinstance(ep, dict) and ep.get("guid") == guid: + target = ep + break + if not target: + raise MediaNotFoundError("Podcast episode not found") + + enc = target.get("enclosures") + if not isinstance(enc, list) or not enc or not isinstance(enc[0], dict): + raise UnplayableMediaError("No enclosure for episode") + url = enc[0].get("url") + if not isinstance(url, str) or not url: + raise UnplayableMediaError("No playable url for episode") + + return StreamDetails( + provider=self.domain, + item_id=item_id, + media_type=MediaType.PODCAST_EPISODE, + stream_type=StreamType.HTTP, + path=url, + audio_format=AudioFormat(content_type=ContentType.try_parse("mp3")), + can_seek=True, + allow_seek=True, + ) + + async def _get_broadcast_episode_stream_details(self, item_id: str) -> StreamDetails: + station_id, bid = self._parse_catchup_episode_id(item_id) + b = await self._get_broadcast_detail(station_id, bid) + + streams = b.get("streams") + if not isinstance(streams, list) or not streams: + raise UnplayableMediaError("No streams for episode") + + s0 = streams[0] + urls = s0.get("urls") if isinstance(s0, dict) else None + if not isinstance(urls, dict): + raise UnplayableMediaError("No stream urls for episode") + + if self.catchup_proto == "hls": + url = urls.get("hls") + ctype = ContentType.try_parse("aac") + stream_type = StreamType.HLS + else: + url = urls.get("progressive") + ctype = ContentType.try_parse("mp3") + stream_type = StreamType.HTTP + + if not isinstance(url, str) or not url: + raise UnplayableMediaError("No playable url for episode") + + url = self._sanitize_template_url(url) + + return StreamDetails( + provider=self.domain, + item_id=item_id, + media_type=MediaType.PODCAST_EPISODE, + stream_type=stream_type, + path=url, + audio_format=AudioFormat(content_type=ctype), + can_seek=True, + allow_seek=True, + ) + + async def get_stream_details(self, item_id: str, media_type: MediaType) -> StreamDetails: + """Resolve Playable stream.""" + if media_type == MediaType.RADIO: + return await self._get_radio_stream_details(item_id) + + if media_type == MediaType.PODCAST_EPISODE: + return await self._get_podcast_episode_stream_details(item_id) + + raise UnplayableMediaError("Unsupported media type") diff --git a/music_assistant/providers/orf_radiothek/helpers.py b/music_assistant/providers/orf_radiothek/helpers.py new file mode 100644 index 00000000..814b1e5f --- /dev/null +++ b/music_assistant/providers/orf_radiothek/helpers.py @@ -0,0 +1,380 @@ +"""Typed dataclasses + parsers for ORF Radiothek / ORF Sound provider.""" + +from __future__ import annotations + +from collections.abc import Iterable +from dataclasses import dataclass +from typing import Any + + +@dataclass(frozen=True, slots=True) +class StreamRef: + """Stream reference parsed from ORF bundle.""" + + url: str + format: str | None = None + + +@dataclass(frozen=True, slots=True) +class OrfStation: + """Create an ORF station from a bundle entry.""" + + id: str + name: str + live_stream_url_template: str + hide_from_stations: bool = False + # optional fields that exist in bundle.json and can be useful later + timeshift_hls_url_template: str | None = None + timeshift_progressive_url_template: str | None = None + podcasts_available: bool | None = None + + @classmethod + def from_bundle_item(cls, station_id: str, obj: dict[str, Any]) -> OrfStation | None: + """Create an ORF station from a bundle entry.""" + tmpl = obj.get("liveStreamUrlTemplate") + if not isinstance(tmpl, str) or "{quality}" not in tmpl: + return None + name = obj.get("name") + if not isinstance(name, str) or not name: + name = station_id + + # optional extras (keep loose; bundle varies) + ts = obj.get("timeshift") + ts_hls = ts.get("liveStreamUrlTemplateHls") if isinstance(ts, dict) else None + ts_prog = ts.get("liveStreamUrlTemplateProgressive") if isinstance(ts, dict) else None + if not isinstance(ts_hls, str): + ts_hls = None + if not isinstance(ts_prog, str): + ts_prog = None + + podcasts = obj.get("podcasts") + podcasts_avail = podcasts.get("available") if isinstance(podcasts, dict) else None + if not isinstance(podcasts_avail, bool): + podcasts_avail = None + + return cls( + id=station_id, + name=name, + live_stream_url_template=tmpl, + hide_from_stations=bool(obj.get("hideFromStations")), + timeshift_hls_url_template=ts_hls, + timeshift_progressive_url_template=ts_prog, + podcasts_available=podcasts_avail, + ) + + +@dataclass(frozen=True, slots=True) +class PrivateStation: + """Private (non-ORF) radio station definition.""" + + id: str + name: str + streams: tuple[StreamRef, ...] = () + image_urls: tuple[str, ...] = () + + @classmethod + def from_bundle_item(cls, obj: dict[str, Any]) -> PrivateStation | None: + """Create a private station from a bundle entry.""" + sid = obj.get("station") + if not isinstance(sid, str) or not sid: + return None + name = obj.get("name") + if not isinstance(name, str) or not name: + name = sid + + # streams + streams_in = obj.get("streams") + streams: list[StreamRef] = [] + if isinstance(streams_in, list): + for s in streams_in: + if not isinstance(s, dict): + continue + url = s.get("url") + if not isinstance(url, str) or not url: + continue + fmt = s.get("format") + if not isinstance(fmt, str): + fmt = None + streams.append(StreamRef(url=url, format=fmt)) + + # images (provider only needs URLs; keep it flat) + imgs: list[str] = [] + image = obj.get("image") + if isinstance(image, dict) and isinstance(image.get("src"), str): + imgs.append(image["src"]) + image_large = obj.get("imageLarge") + if isinstance(image_large, dict): + for mode in ("light", "dark"): + v = image_large.get(mode) + if isinstance(v, dict) and isinstance(v.get("src"), str): + imgs.append(v["src"]) + + # dedupe while preserving order + seen: set[str] = set() + deduped = [] + for u in imgs: + if u in seen: + continue + seen.add(u) + deduped.append(u) + + return cls(id=sid, name=name, streams=tuple(streams), image_urls=tuple(deduped)) + + +@dataclass(frozen=True, slots=True) +class PodcastImage: + """Holds ORF image versions (path URLs).""" + + versions: dict[str, str] + + @classmethod + def from_obj(cls, obj: Any) -> PodcastImage | None: + """Create a podcast image from a raw object.""" + if not isinstance(obj, dict): + return None + image = obj.get("image") + if not isinstance(image, dict): + return None + versions = image.get("versions") + if not isinstance(versions, dict): + return None + out: dict[str, str] = {} + for k, v in versions.items(): + if not isinstance(v, dict): + continue + path = v.get("path") + if isinstance(path, str) and path: + out[str(k)] = path + return cls(out) if out else None + + def best( + self, preference: Iterable[str] = ("premium", "standard", "id3art", "thumbnail") + ) -> str | None: + """Return the best matching image URL by preference.""" + for key in preference: + p = self.versions.get(key) + if p: + return p + # fallback: any + for p in self.versions.values(): + if p: + return p + return None + + +@dataclass(frozen=True, slots=True) +class OrfPodcast: + """ORF podcast metadata.""" + + id: int + title: str + station: str | None = None + channel: str | None = None + slug: str | None = None + description: str | None = None + author: str | None = None + image: PodcastImage | None = None + + @classmethod + def from_index_item(cls, obj: dict[str, Any]) -> OrfPodcast | None: + """Create an ORF podcast from an index entry.""" + pid = obj.get("id") + if not isinstance(pid, int): + return None + title = obj.get("title") + if not isinstance(title, str) or not title: + title = str(pid) + + station = obj.get("station") + if not isinstance(station, str): + station = None + channel = obj.get("channel") + if not isinstance(channel, str): + channel = None + slug = obj.get("slug") + if not isinstance(slug, str): + slug = None + desc = obj.get("description") + if not isinstance(desc, str): + desc = None + author = obj.get("author") + if not isinstance(author, str): + author = None + + img = PodcastImage.from_obj(obj) + + return cls( + id=pid, + title=title, + station=station, + channel=channel, + slug=slug, + description=desc, + author=author, + image=img, + ) + + +@dataclass(frozen=True, slots=True) +class Enclosure: + """Podcast episode enclosure.""" + + url: str + mime_type: str | None = None + length_bytes: int | None = None + + @classmethod + def from_obj(cls, obj: dict[str, Any]) -> Enclosure | None: + """Create an enclosure from a raw object.""" + url = obj.get("url") + if not isinstance(url, str) or not url: + return None + mt = obj.get("type") + if not isinstance(mt, str): + mt = None + ln = obj.get("length") + if not isinstance(ln, int): + ln = None + return cls(url=url, mime_type=mt, length_bytes=ln) + + +@dataclass(frozen=True, slots=True) +class OrfPodcastEpisode: + """ORF podcast episode metadata.""" + + guid: str + title: str + description: str | None = None + published: str | None = None # keep as string; provider already formats timestamps itself + expiry: str | None = None + duration_ms: int | None = None + enclosures: tuple[Enclosure, ...] = () + link_url: str | None = None + image: PodcastImage | None = None + + @classmethod + def from_detail_item(cls, obj: dict[str, Any]) -> OrfPodcastEpisode | None: + """Create a podcast episode from a detail entry.""" + guid = obj.get("guid") + if not isinstance(guid, str) or not guid: + return None + title = obj.get("title") + if not isinstance(title, str) or not title: + title = guid + + desc = obj.get("description") + if not isinstance(desc, str): + desc = None + + published = obj.get("published") + if not isinstance(published, str): + published = None + expiry = obj.get("expiry") + if not isinstance(expiry, str): + expiry = None + + dur = obj.get("duration") + if not isinstance(dur, int) or dur <= 0: + dur = None + + link = obj.get("url") + if not isinstance(link, str): + link = None + + enc_in = obj.get("enclosures") + encs: list[Enclosure] = [] + if isinstance(enc_in, list): + for e in enc_in: + if isinstance(e, dict): + enc = Enclosure.from_obj(e) + if enc: + encs.append(enc) + + img = PodcastImage.from_obj(obj) + + return cls( + guid=guid, + title=title, + description=desc, + published=published, + expiry=expiry, + duration_ms=dur, + enclosures=tuple(encs), + link_url=link, + image=img, + ) + + +# ---------------------------- +# Parsers +# ---------------------------- + + +def parse_orf_stations(bundle: dict[str, Any], include_hidden: bool) -> list[OrfStation]: + """Parse ORF stations from the bundle payload.""" + stations = bundle.get("stations") + if not isinstance(stations, dict): + return [] + out: list[OrfStation] = [] + for sid, obj in stations.items(): + if not isinstance(sid, str) or not isinstance(obj, dict): + continue + st = OrfStation.from_bundle_item(sid, obj) + if not st: + continue + if st.hide_from_stations and not include_hidden: + continue + out.append(st) + return out + + +def parse_private_stations(bundle: dict[str, Any]) -> list[PrivateStation]: + """Parse private stations from the bundle payload.""" + priv = bundle.get("privates") + if not isinstance(priv, list): + return [] + out: list[PrivateStation] = [] + for obj in priv: + if not isinstance(obj, dict): + continue + st = PrivateStation.from_bundle_item(obj) + if st: + out.append(st) + return out + + +def parse_orf_podcasts_index(payload: Any) -> list[OrfPodcast]: + """Parse ORF podcast index payload.""" + # payload is expected to be dict[station_key -> list[podcast_obj]] + if not isinstance(payload, dict): + return [] + out: list[OrfPodcast] = [] + for arr in payload.values(): + if not isinstance(arr, list): + continue + for pod in arr: + if not isinstance(pod, dict): + continue + if pod.get("isOnline") is not True: + continue + item = OrfPodcast.from_index_item(pod) + if item: + out.append(item) + return out + + +def parse_orf_podcast_episodes(payload: Any) -> list[OrfPodcastEpisode]: + """Parse podcast episodes from a detail payload.""" + if not isinstance(payload, dict): + return [] + eps = payload.get("episodes") + if not isinstance(eps, list): + return [] + out: list[OrfPodcastEpisode] = [] + for ep in eps: + if not isinstance(ep, dict): + continue + item = OrfPodcastEpisode.from_detail_item(ep) + if item: + out.append(item) + return out diff --git a/music_assistant/providers/orf_radiothek/icon.svg b/music_assistant/providers/orf_radiothek/icon.svg new file mode 100644 index 00000000..038bb490 --- /dev/null +++ b/music_assistant/providers/orf_radiothek/icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/music_assistant/providers/orf_radiothek/icon_monochrome.svg b/music_assistant/providers/orf_radiothek/icon_monochrome.svg new file mode 100644 index 00000000..13fe2997 --- /dev/null +++ b/music_assistant/providers/orf_radiothek/icon_monochrome.svg @@ -0,0 +1,3 @@ + + + diff --git a/music_assistant/providers/orf_radiothek/manifest.json b/music_assistant/providers/orf_radiothek/manifest.json new file mode 100644 index 00000000..707cd965 --- /dev/null +++ b/music_assistant/providers/orf_radiothek/manifest.json @@ -0,0 +1,14 @@ +{ + "domain": "orf_radiothek", + "name": "ORF Radiothek", + "version": "0.1.0", + "stage": "beta", + "description": "Stream live radio and on-demand content from ORF Radiothek (Austrian public service broadcaster). Supports live streams from Ö1, Ö3, FM4, and regional stations, plus on-demand broadcasts and podcasts.", + "documentation": "https://music-assistant.io/music-providers/radiothek", + "requirements": [], + "icon": "mdi:radio", + "type": "music", + "dependencies": [], + "config_entries": [], + "codeowners": ["@DButter"] +} diff --git a/music_assistant/providers/orf_radiothek/media/bgl.png b/music_assistant/providers/orf_radiothek/media/bgl.png new file mode 100644 index 0000000000000000000000000000000000000000..f154ad157552132799d709d7390038bbf859121c GIT binary patch literal 1333 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 yctjVgsfkt7QdCpJs;Twc$iuz-e+>eH+ z6aC2t`osy#ULM?r80@GKzB(fCuMf{@9QC^l;*%A?KOwv{BiDNx-;Ea1a2v>0ALpGD z%wQhFNFm#U80w@E?W+)OdD)Qw00kyVL_t(|ob8?AR@y)ih1s}dSvH^uRuRFfwf6m= zu&t-`STW=#JM4@-_xo>--wA}ByR(zgh!8>uA%qY@2qAv3>L@I4Hh z+j#6!d%~hVq0b?5hRq`+7$2Kc`Wzx=ST8&zcvVAY4I%rKnY0Df+|ndu4+H^k~CKPeuqy=SOl8m$n))rGd;P{WjvddaVP zg^{OWm|<$>K)vLbXS32ihYT}>>LtJ284w(1SiK;E?#6=PAj9ejN=CP3lixN57*<~q zLH}$+aDZX;9a^g`iU*@D^fs)NvpuX+hEjAK)ReGF&N_KQ+>-wtk=E|7XjE4yz8HpI4H^rG!n zP(!ReZ zoi0NF+kygyMxyOjvJI^Z<{K`zwgs~d{k6r__FJ;=VZ1lGTHBNVq>0bAKc)iD($)WN z=z__@_b&p5EC@QV(5aw6mgG?p^H~W_OuTXGIY*BZ_vj` z8Tz@^&#Blww6`Vm2Qfnz7dF>6a)xecGmR27oZ1Y%1r1#sTU@IeiPI%%2i92n}-Z*RKpcY`P8K^^sK9zz@Hr_NY$7@UD*}C17XYQViZ@=np!9W((-R zg_#(QaKZNutG{Z2G21B3n}FoJZnxAR!BMB7(8><7jl|Lxt}O^ zUfbM!44!G2F1iJk`-yU=3W9}{Vhk=Y84`-YKkeMa5n4#;#o+mdU?HUzgA2@{g$gOZ z(ki4x<_IG@Qfe`{$h7Mk8Q!K9gNqnqh166h2A7%1-XNou{6ys@3eDBW3MrKsT*xq` zRkxu|3@-Ne2dt1%h{46);DPN(Da7D%Z()IUq!i}Y$Qgo#RPlZy!FL5=h17CX_^T*r z2o_SMyTK(5!9uF=v070>tdI(23n@`Uw2&%nDEHpA(d&5H?l-T+m!h9j$#>_Ceh=m| z_wqc^_aAm&PUQ`Vgb+dqA%qY@2qA=>fC+^@}VizE>W&i*H M07*qoM6N<$g41Kipa1{> literal 0 HcmV?d00001 diff --git a/music_assistant/providers/orf_radiothek/media/noe.png b/music_assistant/providers/orf_radiothek/media/noe.png new file mode 100644 index 0000000000000000000000000000000000000000..358eded1d5b5193ed52533054c48c6bd04255168 GIT binary patch literal 3647 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 W3|k)0qGTyw>B#2Rq+7(}XZ{Tzlt^v> literal 0 HcmV?d00001 diff --git a/music_assistant/providers/orf_radiothek/media/oe1.png b/music_assistant/providers/orf_radiothek/media/oe1.png new file mode 100644 index 0000000000000000000000000000000000000000..60fbb89105064ee091cfe3a2b1ff627507440a85 GIT binary patch literal 11771 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 literal 0 HcmV?d00001 diff --git a/music_assistant/providers/orf_radiothek/media/ooe.png b/music_assistant/providers/orf_radiothek/media/ooe.png new file mode 100644 index 0000000000000000000000000000000000000000..27d35f7b485113ea2cb711d4543f0dc8f7d9ed1f GIT binary patch literal 2619 zcmZ{mc{~%0AIB#|m|QtljtCFAXO78{oMFznJ-N%-SZ0Mq7!yU#LS&PWvr#cej$zDW z?hzK{NJJ#&=-2c2@AbT1pX-nBAKyRUI6Ig*kPE~G004lN7A6jV`qRJWWc`z8!lW(! zRHmJ^lWDV*?C;;d8vuZ22^k`N z0PyPoB1EztTiP@#nqI`eNHD=j^k) zu|#bBnsBWpt(uPOxN)M>E&uA!UoMH&76k*dyiLNWTq4Ux`p^^W&5qqOmFbO0Gmb6gfPJ+u z>%U$s362Lo-n{O|Wa~!x%gW41)C3I8*ehGXKS+kqbWp0dO7jxwIgR$PW|OGzt;#hPOF`Tpq{w`=zM?Kj-_aWG0|Rv_F&NB*p-K z+FK+kgiQP+pOB;Unu{GZ$HR#Ecun3mPqQLp{~1u-#t-cFX$HHd!Jb-31zfAGej&At70az4Q%LIM4ZvG^Ceni#eEd z=H&uM!!I*Th!cX1Yt{0*eT+wL^P2X$hmftYhDdn0Sd zFC+RE0z03e$@XhhU0LwYo_WmkZ ziin_$^bHw}><8$@b?x`(hf-ZW2aGtiXb1M1P%`lLvx|qrxpnpuC-NW1t0y{-ol4+m z&ZedlsnmJat``#RD}BA-Q8~S`UXuU@&d;JpT6`;8+85XsXPDqhNG`Q3OO4lJgeK!m z0~=UmJSUG|14-^6X^J!W2)Z zPL~3zbeP=$c*!(kEmrjxOI8%-x=TDJIDoU_BXEvT=#|msrvMgbo(dz7Jhf$nMcu!a zMo8AD6i{)Q;qtHaDTl1xEZuKdE^Vt1Jdj!iIWJN{xVpKeCx0C?t?~_)D`&__~7XrI}Y+>vf_^X^6C>i{^1-CzH}zi9}%jMS2!l$-?1L0gbm>H=*6;wMUME&g1kl z$OQR=*XLaT7>cPp=rAm1)vO*;-@}e+i%ds_Oq5D|3MJwR@teJ^+`ay9jOJAd*|f4k zxx=G%oWiFeTT(L7kTP?@&(}A!E1uhxaF|QbTCME*yL2O!4lAD^sz%N^0#EZQ0%XMD11B&JMZ8V-U0+}iRh$X^U z%!a&DSOrs|T_+r>9KWjM7m0>wPI?eFB-Lg}=5rr>x0zbtx4VLsr*p4(HN@%-h(@O@ zw_3iw^BL3)Z7Q?e<#C8J45;_S>o$2MBZ?sBygvp|Wo z+;{d4h3K$4P%+6ZD~Gi2#N1njcwKw$(nq~8+bZm`SiMk4yIe4+rZ?X4(p%*@%OALWde{WPZevZOixs4`D_mgKtR`;q-taD3@ZA18|Q^Rw>$$Muyw<1pkwM{tt{WSAMhLtaF=|%M3OD P&>+Cl6lPLu?ET<>n(+gA literal 0 HcmV?d00001 diff --git a/music_assistant/providers/orf_radiothek/media/sbg.png b/music_assistant/providers/orf_radiothek/media/sbg.png new file mode 100644 index 0000000000000000000000000000000000000000..7ac776b3711f93eef09f26d514291a8b2e500c8d GIT binary patch literal 1925 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 literal 0 HcmV?d00001 diff --git a/music_assistant/providers/orf_radiothek/media/vbg.png b/music_assistant/providers/orf_radiothek/media/vbg.png new file mode 100644 index 0000000000000000000000000000000000000000..6a637e21d4faeb610fdd09f6d773f3ef0f1a4740 GIT binary patch literal 1649 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 aWmja_y2R3=mlz@Z<%z(dju5tuPx8N(uIqCE literal 0 HcmV?d00001 -- 2.34.1