some small tweaks
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Mon, 16 May 2022 19:44:20 +0000 (21:44 +0200)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Mon, 16 May 2022 19:44:20 +0000 (21:44 +0200)
music_assistant/controllers/music/providers/filesystem.py
music_assistant/controllers/music/tracks.py
music_assistant/helpers/audio.py
music_assistant/helpers/images.py

index 3ebb424daecddb9ddca2efa723aaa43fc3ed8fdf..efc05d63e742a3af711eda639d909d7611ee1e53 100644 (file)
@@ -43,7 +43,7 @@ def scantree(path: str) -> Generator[os.DirEntry]:
     """Recursively yield DirEntry objects for given directory."""
     for entry in os.scandir(path):
         if entry.is_dir(follow_symlinks=False):
-            yield from scantree(entry.path)  # see below for Python 2.x
+            yield from scantree(entry.path)
         else:
             yield entry
 
@@ -70,10 +70,10 @@ class FileSystemProvider(MusicProvider):
     """
     Implementation of a musicprovider for local files.
 
-    Assumes files are stored on disk in format <artist>/<album>/<track.ext>
-    Reads ID3 tags from file and falls back to parsing filename
-    Supports m3u files only for playlists
-    Supports having URI's from streaming providers within m3u playlist
+    Reads ID3 tags from file and falls back to parsing filename.
+    Optionally reads metadata from nfo files and images in folder structure <artist>/<album>.
+    Supports m3u files only for playlists.
+    Supports having URI's from streaming providers within m3u playlist.
     """
 
     _attr_name = "Filesystem"
@@ -617,8 +617,7 @@ class FileSystemProvider(MusicProvider):
         self, playlist_path: str, checksum: Optional[str] = None
     ) -> Playlist | None:
         """Parse playlist from file."""
-        if self.config.path not in playlist_path:
-            playlist_path = os.path.join(self.config.path, playlist_path)
+        playlist_path = self._get_absolute_path(playlist_path)
         playlist_path_base = self._get_relative_path(playlist_path)
         playlist_item_id = self._get_item_id(playlist_path_base)
         checksum = checksum or self._get_checksum(playlist_path)
@@ -694,6 +693,8 @@ class FileSystemProvider(MusicProvider):
 
     def _get_relative_path(self, filename: str) -> str:
         """Get relative path for filename (without the base dir)."""
+        if self.config.path not in filename:
+            return filename
         filename = filename.replace(self.config.path, "")
         if filename.startswith(os.sep):
             filename = filename[1:]
@@ -703,6 +704,8 @@ class FileSystemProvider(MusicProvider):
 
     def _get_absolute_path(self, filename: str) -> str:
         """Get absolute path for filename (including the base dir)."""
+        if self.config.path in filename:
+            return filename
         return os.path.join(self.config.path, filename)
 
     def _get_item_id(self, filename: str) -> str:
index 80e0ba08a7fdaa2717472f62ff5d217dcfabca5c..1bedf8803b505c514200eeb06222df6ca0baf13f 100644 (file)
@@ -90,8 +90,6 @@ class TracksController(MediaControllerBase[Track]):
         for provider in self.mass.music.providers:
             if MediaType.TRACK not in provider.supported_mediatypes:
                 continue
-            if provider.type.is_file():
-                continue
             self.logger.debug(
                 "Trying to match track %s on provider %s", db_track.name, provider.name
             )
index 22f5dd49942e99e950bf024db8e913c52e782279..8a7bb9463da0bf64dcc6a426ac26bf3de09d84f2 100644 (file)
@@ -481,6 +481,12 @@ async def get_media_stream(
             await mass.music.mark_item_played(
                 streamdetails.item_id, streamdetails.provider
             )
+            # send analyze job to background worker
+            if streamdetails.loudness is None and streamdetails.provider != "url":
+                uri = f"{streamdetails.provider}://{streamdetails.media_type.value}/{streamdetails.item_id}"
+                mass.add_job(
+                    analyze_audio(mass, streamdetails), f"Analyze audio for {uri}"
+                )
         finally:
             mass.signal_event(
                 MassEvent(
@@ -489,12 +495,6 @@ async def get_media_stream(
                     data=streamdetails,
                 )
             )
-            # send analyze job to background worker
-            if streamdetails.loudness is None and streamdetails.provider != "url":
-                uri = f"{streamdetails.provider}://{streamdetails.media_type.value}/{streamdetails.item_id}"
-                mass.add_job(
-                    analyze_audio(mass, streamdetails), f"Analyze audio for {uri}"
-                )
 
 
 async def check_audio_support(try_install: bool = False) -> Tuple[bool, bool, bool]:
index 752038805a2b9377efccccb92e2d199c5cd4fe7c..2cce16e4cd1d80fc3b60d829a745950525ec2491 100644 (file)
@@ -5,7 +5,6 @@ from io import BytesIO
 from typing import TYPE_CHECKING, Optional
 
 from PIL import Image
-from tinytag import TinyTag
 
 if TYPE_CHECKING:
     from music_assistant.mass import MusicAssistant
@@ -29,15 +28,10 @@ async def create_thumbnail(
                 continue
             if not prov.exists(path):
                 continue
-            if TinyTag.is_supported(path):
-                # embedded image in music file
-                def get_embedded_image():
-                    tags = TinyTag.get(path, image=True)
-                    return tags.get_image()
-
-                img_data = await mass.loop.run_in_executor(None, get_embedded_image)
-            else:
-                # regular image file on disk
+            # embedded image in music file
+            img_data = await prov.get_embedded_image(path)
+            # regular image file on disk
+            if not img_data:
                 async with prov.open_file(path) as _file:
                     img_data = await _file.read()
             break