Always detect charset for m3u playlists
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Thu, 17 Oct 2024 13:58:29 +0000 (15:58 +0200)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Thu, 17 Oct 2024 13:58:29 +0000 (15:58 +0200)
music_assistant/server/helpers/audio.py
music_assistant/server/helpers/playlists.py

index 30a05ecb330413a0770f6eae294be2882972f0ff..cce84fafc01898860adb11e0f5874f516d19a8cd 100644 (file)
@@ -604,7 +604,8 @@ async def get_hls_radio_stream(
         ) as resp:
             resp.raise_for_status()
             raw_data = await resp.read()
-            encoding = resp.charset or await detect_charset(raw_data)
+            # NOTE: using resp.charset is not reliable, we need to detect it ourselves
+            encoding = await detect_charset(raw_data)
             substream_m3u_data = raw_data.decode(encoding)
         # get chunk-parts from the substream
         hls_chunks = parse_m3u(substream_m3u_data)
@@ -681,7 +682,8 @@ async def get_hls_substream(
     ) as resp:
         resp.raise_for_status()
         raw_data = await resp.read()
-        encoding = resp.charset or await detect_charset(raw_data)
+        # NOTE: using resp.charset is not reliable, we need to detect it ourselves
+        encoding = await detect_charset(raw_data)
         master_m3u_data = raw_data.decode(encoding)
     substreams = parse_m3u(master_m3u_data)
     if any(x for x in substreams if x.length and not x.key):
index 8986de7fe2f9824accb9d57341d3aa396d60fb18..a4b14acde7cda83965e51c944e7d4d2e51c538f5 100644 (file)
@@ -11,6 +11,7 @@ from urllib.parse import urlparse
 from aiohttp import client_exceptions
 
 from music_assistant.common.models.errors import InvalidDataError
+from music_assistant.server.helpers.util import detect_charset
 
 if TYPE_CHECKING:
     from music_assistant.server import MusicAssistant
@@ -146,10 +147,12 @@ async def fetch_playlist(mass: MusicAssistant, url: str) -> list[PlaylistItem]:
     """Parse an online m3u or pls playlist."""
     try:
         async with mass.http_session.get(url, allow_redirects=True, timeout=5) as resp:
-            charset = resp.charset or "utf-8"
             try:
-                playlist_data = (await resp.content.read(64 * 1024)).decode(charset)
-            except ValueError as err:
+                raw_data = await resp.content.read(64 * 1024)
+                # NOTE: using resp.charset is not reliable, we need to detect it ourselves
+                encoding = await detect_charset(raw_data)
+                playlist_data = raw_data.decode(encoding, errors="replace")
+            except (ValueError, UnicodeDecodeError) as err:
                 msg = f"Could not decode playlist {url}"
                 raise InvalidDataError(msg) from err
     except TimeoutError as err: