From 029f05cb29433e0fc662becf25810a1c0e79912a Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sun, 26 Mar 2023 03:22:27 +0200 Subject: [PATCH] Fix radio streams (#575) * fix typo in didl * fix for mpeg dash radio streams --- music_assistant/server/helpers/didl_lite.py | 2 +- music_assistant/server/providers/tunein/__init__.py | 11 ++++++++--- music_assistant/server/providers/url/__init__.py | 13 +++++++++---- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/music_assistant/server/helpers/didl_lite.py b/music_assistant/server/helpers/didl_lite.py index d5be2943..833a2e14 100644 --- a/music_assistant/server/helpers/didl_lite.py +++ b/music_assistant/server/helpers/didl_lite.py @@ -34,7 +34,7 @@ def create_didl_metadata(url: str, queue_item: QueueItem, flow_mode: bool = Fals if is_radio: # radio or other non-track item - image = queue_item.image_url if queue_item.image else "" + image = queue_item.image_url if queue_item.image_url else "" return ( '' f'' diff --git a/music_assistant/server/providers/tunein/__init__.py b/music_assistant/server/providers/tunein/__init__.py index 89c6a163..7f9864b8 100644 --- a/music_assistant/server/providers/tunein/__init__.py +++ b/music_assistant/server/providers/tunein/__init__.py @@ -201,9 +201,13 @@ class TuneInProvider(MusicProvider): continue # check if the radio stream is not a playlist url = stream["url"] - if url.endswith("m3u8") or url.endswith("m3u") or url.endswith("pls"): - playlist = await fetch_playlist(self.mass, url) - url = playlist[0] + direct = None + if url.endswith("m3u8") or url.endswith("m3u") or url.endswith("pls"): # noqa: SIM102 + if playlist := await fetch_playlist(self.mass, url): + if len(playlist) > 1 or ".m3u" in playlist[0] or ".pls" in playlist[0]: + # this is most likely an mpeg-dash stream, let ffmpeg handle that + direct = playlist[0] + url = playlist[0] return StreamDetails( provider=self.domain, item_id=item_id, @@ -211,6 +215,7 @@ class TuneInProvider(MusicProvider): media_type=MediaType.RADIO, data=url, expires=time() + 24 * 3600, + url=direct, ) raise MediaNotFoundError(f"Unable to retrieve stream details for {item_id}") diff --git a/music_assistant/server/providers/url/__init__.py b/music_assistant/server/providers/url/__init__.py index c3f2a36c..b319269c 100644 --- a/music_assistant/server/providers/url/__init__.py +++ b/music_assistant/server/providers/url/__init__.py @@ -53,6 +53,7 @@ class URLProvider(MusicProvider): Called when provider is registered. """ self._full_url = {} + # self.mass.register_api_command("music/tracks", self.db_items) async def get_track(self, prov_track_id: str) -> Track: """Get full track details by id.""" @@ -60,7 +61,7 @@ class URLProvider(MusicProvider): async def get_radio(self, prov_radio_id: str) -> Radio: """Get full radio details by id.""" - return await self.parse_item(prov_radio_id) + return await self.parse_item(prov_radio_id, force_radio=True) async def get_artist(self, prov_artist_id: str) -> Track: """Get full artist details by id.""" @@ -87,11 +88,13 @@ class URLProvider(MusicProvider): return await self.parse_item(prov_item_id) raise NotImplementedError - async def parse_item(self, item_id_or_url: str, force_refresh: bool = False) -> Track | Radio: + async def parse_item( + self, item_id_or_url: str, force_refresh: bool = False, force_radio: bool = False + ) -> Track | Radio: """Parse plain URL to MediaItem of type Radio or Track.""" item_id, url, media_info = await self._get_media_info(item_id_or_url, force_refresh) is_radio = media_info.get("icy-name") or not media_info.duration - if is_radio: + if is_radio or force_radio: # treat as radio media_item = Radio( item_id=item_id, @@ -163,6 +166,8 @@ class URLProvider(MusicProvider): """Get streamdetails for a track/radio.""" item_id, url, media_info = await self._get_media_info(item_id) is_radio = media_info.get("icy-name") or not media_info.duration + # we let ffmpeg handle with mpeg dash streams + mpeg_dash_stream = ".m3u" in url or ".pls" in url return StreamDetails( provider=self.instance_id, item_id=item_id, @@ -170,7 +175,7 @@ class URLProvider(MusicProvider): media_type=MediaType.RADIO if is_radio else MediaType.TRACK, sample_rate=media_info.sample_rate, bit_depth=media_info.bits_per_sample, - direct=None if is_radio else url, + direct=None if is_radio and not mpeg_dash_stream else url, data=url, ) -- 2.34.1