Some small fixes and improvements (#721)
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Fri, 16 Jun 2023 01:04:27 +0000 (03:04 +0200)
committerGitHub <noreply@github.com>
Fri, 16 Jun 2023 01:04:27 +0000 (03:04 +0200)
* Support m3u8 playlists in file providers

* Fix creating collage/thumbnail for local playlists

* bump frontend to 20230616.0

* support relative filenames in playlists

music_assistant/server/controllers/metadata.py
music_assistant/server/helpers/images.py
music_assistant/server/providers/filesystem_local/base.py
pyproject.toml
requirements_all.txt

index 28eff55a2035cd3e465ec458c30cf27c5ca4b56b..fa435bcc86cf9c19d260a131fb510aab173af1f1 100755 (executable)
@@ -172,14 +172,14 @@ class MetaDataController:
         # retrieve genres from tracks
         # TODO: retrieve style/mood ?
         playlist.metadata.genres = set()
-        image_urls = set()
+        images = set()
         try:
             playlist_genres: dict[str, int] = {}
             async for track in self.mass.music.playlists.tracks(
                 playlist.item_id, playlist.provider
             ):
                 if not playlist.image and track.image:
-                    image_urls.add(track.image.path)
+                    images.add(track.image)
                 if track.media_type != MediaType.TRACK:
                     # filter out radio items
                     continue
@@ -202,12 +202,12 @@ class MetaDataController:
             playlist.metadata.genres.update(playlist_genres_filtered)
 
             # create collage thumb/fanart from playlist tracks
-            if image_urls:
+            if images:
                 if playlist.image and self.mass.storage_path in playlist.image:
                     img_path = playlist.image
                 else:
                     img_path = os.path.join(self.mass.storage_path, f"{uuid4().hex}.png")
-                    img_data = await create_collage(self.mass, list(image_urls))
+                    img_data = await create_collage(self.mass, list(images))
                 async with aiofiles.open(img_path, "wb") as _file:
                     await _file.write(img_data)
                 playlist.metadata.images = [MediaItemImage(ImageType.THUMB, img_path, True)]
index 15896f6ee0714004e39e41e4a0c0dcfb19da2c6d..fa1536270cdfe34119b65befb6a453175e416d8e 100644 (file)
@@ -10,6 +10,7 @@ from typing import TYPE_CHECKING
 import aiofiles
 from PIL import Image
 
+from music_assistant.common.models.media_items import MediaItemImage
 from music_assistant.server.helpers.tags import get_embedded_image
 
 if TYPE_CHECKING:
@@ -49,7 +50,7 @@ async def get_image_thumb(
     return await asyncio.to_thread(_create_image)
 
 
-async def create_collage(mass: MusicAssistant, images: list[str]) -> bytes:
+async def create_collage(mass: MusicAssistant, images: list[MediaItemImage]) -> bytes:
     """Create a basic collage image from multiple image urls."""
 
     def _new_collage():
@@ -65,7 +66,8 @@ async def create_collage(mass: MusicAssistant, images: list[str]) -> bytes:
 
     for x_co in range(0, 1500, 500):
         for y_co in range(0, 1500, 500):
-            img_data = await get_image_data(mass, random.choice(images))
+            img = random.choice(images)
+            img_data = await get_image_data(mass, img.path, img.provider)
             await asyncio.to_thread(_add_to_collage, img_data, x_co, y_co)
 
     def _save_collage():
index fc47b44d9b1e430f4d661a756e86a34e02800d90..e42351496f110c7b61c1b61510c2f5b53bb8be6e 100644 (file)
@@ -67,7 +67,7 @@ CONF_ENTRY_MISSING_ALBUM_ARTIST = ConfigEntry(
 )
 
 TRACK_EXTENSIONS = ("mp3", "m4a", "m4b", "mp4", "flac", "wav", "ogg", "aiff", "wma", "dsf")
-PLAYLIST_EXTENSIONS = ("m3u", "pls")
+PLAYLIST_EXTENSIONS = ("m3u", "pls", "m3u8")
 SUPPORTED_EXTENSIONS = TRACK_EXTENSIONS + PLAYLIST_EXTENSIONS
 IMAGE_EXTENSIONS = ("jpg", "jpeg", "JPG", "JPEG", "png", "PNG", "gif", "GIF")
 SEEKABLE_FILES = (ContentType.MP3, ContentType.WAV, ContentType.FLAC)
@@ -472,14 +472,25 @@ class FileSystemProviderBase(MusicProvider):
     async def _parse_playlist_line(self, line: str, playlist_path: str) -> Track | Radio | None:
         """Try to parse a track from a playlist line."""
         try:
-            # try to treat uri as (relative) filename
-            if "://" not in line:
-                for filename in (line, os.path.join(playlist_path, line)):
-                    if not await self.exists(filename):
-                        continue
-                    return await self.get_track(filename)
-            # fallback to generic uri parsing
-            return await self.mass.music.get_item_by_uri(line)
+            if "://" in line:
+                # handle as generic uri
+                return await self.mass.music.get_item_by_uri(line)
+
+            # if a relative path was given in an upper level from the playlist,
+            # try to resolve it
+            for parentpart in ("../", "..\\"):
+                while line.startswith(parentpart):
+                    if len(playlist_path) < 3:
+                        break  # guard
+                    playlist_path = parentpart[:-3]
+                    line = line[3:]
+
+            # try to resolve the filename
+            for filename in (line, os.path.join(playlist_path, line)):
+                with contextlib.suppress(FileNotFoundError):
+                    item = await self.resolve(filename)
+                    return await self._parse_track(item)
+
         except MusicAssistantError as err:
             self.logger.warning("Could not parse uri/file %s to track: %s", line, str(err))
             return None
index 0ff7c95822b991e044fc3a58d47d4bb87556a143..369da27197d71446532446267c5bab93c4ae83c4 100644 (file)
@@ -36,7 +36,7 @@ server = [
   "python-slugify==8.0.1",
   "mashumaro==3.7",
   "memory-tempfile==2.2.3",
-  "music-assistant-frontend==20230609.0",
+  "music-assistant-frontend==20230616.0",
   "pillow==9.5.0",
   "unidecode==1.3.6",
   "xmltodict==0.13.0",
index e7a6ebaa02c3bbf3e07f3332e932a2eab218b0aa..8d705aa02fdf9308003e5b3d618d41638b186ba8 100644 (file)
@@ -18,7 +18,7 @@ git+https://github.com/jozefKruszynski/python-tidal.git@v0.7.1
 git+https://github.com/pytube/pytube.git@refs/pull/1501/head
 mashumaro==3.7
 memory-tempfile==2.2.3
-music-assistant-frontend==20230609.0
+music-assistant-frontend==20230616.0
 orjson==3.9.1
 pillow==9.5.0
 plexapi==4.14.0