Fix search on filesystem provider (#321)
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Wed, 18 May 2022 15:58:31 +0000 (17:58 +0200)
committerGitHub <noreply@github.com>
Wed, 18 May 2022 15:58:31 +0000 (17:58 +0200)
fix search filesystem provider

music_assistant/controllers/music/albums.py
music_assistant/controllers/music/providers/filesystem.py
music_assistant/controllers/music/tracks.py

index c315c82f4934bf507541a1c845ac86144675f207..6e5cd90665d097cadbed7ab6b06db7a77ef330be 100644 (file)
@@ -231,7 +231,7 @@ class AlbumsController(MediaControllerBase[Album]):
                     await self.update_db_item(db_album.item_id, prov_album)
                     match_found = True
                     # while we're here, also match the artist
-                    if db_album.artist.provider == "database":
+                    if db_album.artist.provider == ProviderType.DATABASE:
                         await self.mass.music.artists.update_db_item(
                             db_album.artist.item_id, prov_album.artist
                         )
@@ -264,7 +264,7 @@ class AlbumsController(MediaControllerBase[Album]):
             if isinstance(album.artist, ItemMapping):
                 return album.artist
 
-            if album.artist.provider == "database":
+            if album.artist.provider == ProviderType.DATABASE:
                 return ItemMapping.from_item(album.artist)
 
             if album.artist.musicbrainz_id:
index 6fee25634b4f2a2311805f906b0fe32c176aa301..f96db1f2913f3ee979827249c05adfa3165936d7 100644 (file)
@@ -1,7 +1,6 @@
 """Filesystem musicprovider support for MusicAssistant."""
 from __future__ import annotations
 
-import asyncio
 import os
 import urllib.parse
 from contextlib import asynccontextmanager
@@ -86,11 +85,6 @@ class FileSystemProvider(MusicProvider):
         MediaType.ALBUM,
     ]
 
-    def __init__(self, *args, **kwargs) -> None:
-        """Initialize MusicProvider."""
-        super().__init__(*args, **kwargs)
-        self._cache_built = asyncio.Event()
-
     async def setup(self) -> bool:
         """Handle async initialization of the provider."""
 
@@ -101,11 +95,43 @@ class FileSystemProvider(MusicProvider):
 
         return True
 
-    @staticmethod
-    async def search(*args, **kwargs) -> List[MediaItemType]:
+    async def search(
+        self, search_query: str, media_types=Optional[List[MediaType]], limit: int = 5
+    ) -> List[MediaItemType]:
         """Perform search on musicprovider."""
-        # items for the filesystem provider are already returned by the database
-        return []
+        result = []
+        # searching the filesystem is slow and unreliable,
+        # instead we make some (slow) freaking queries to the db ;-)
+        if " - " in search_query:
+            artist, title = search_query.split(" - ", 1)
+        else:
+            artist = None
+            title = search_query
+        if media_types is None or MediaType.TRACK in media_types:
+            query = f"SELECT * FROM tracks WHERE name LIKE '%{title}%'"
+            query += f" AND provider_ids LIKE '%\"{self.type.value}\"%')"
+            if artist:
+                query += f" AND artists LIKE '%{artist}%')"
+            tracks = await self.mass.music.tracks.get_db_items(query)
+            result.append(tracks)
+        if media_types is None or MediaType.ALBUM in media_types:
+            query = f"SELECT * FROM albums WHERE name LIKE '%{title}%'"
+            query += f" AND provider_ids LIKE '%\"{self.type.value}\"%')"
+            if artist:
+                query += f" AND artist LIKE '%{artist}%')"
+            albums = await self.mass.music.albums.get_db_items(query)
+            result.append(albums)
+        if media_types is None or MediaType.ARTIST in media_types:
+            query = f"SELECT * FROM artists WHERE name LIKE '%{title}%'"
+            query += f" AND provider_ids LIKE '%\"{self.type.value}\"%')"
+            artists = await self.mass.music.artists.get_db_items(query)
+            result.append(artists)
+        if media_types is None or MediaType.PLAYLIST in media_types:
+            query = f"SELECT * FROM playlists WHERE name LIKE '%{title}%'"
+            query += f" AND provider_ids LIKE '%\"{self.type.value}\"%')"
+            playlists = await self.mass.music.playlists.get_db_items(query)
+            result.append(playlists)
+        return result
 
     async def sync_library(self) -> None:
         """Run library sync for this provider."""
@@ -292,7 +318,7 @@ class FileSystemProvider(MusicProvider):
     async def library_remove(self, *args, **kwargs) -> bool:
         """Remove item from provider's library. Return true on succes."""
         # already handled by database
-        # TODO: do we want to process deletions here ?
+        # TODO: do we want to process/offer deletions here ?
 
     async def add_playlist_tracks(
         self, prov_playlist_id: str, prov_track_ids: List[str]
index 1bedf8803b505c514200eeb06222df6ca0baf13f..6b4309d86bbf847c4206ac548b8874e499c580d0 100644 (file)
@@ -109,7 +109,7 @@ class TracksController(MediaControllerBase[Track]):
                         match_found = True
                         await self.update_db_item(db_track.item_id, search_result_item)
                         # while we're here, also match the artist
-                        if db_track_artist.provider == "database":
+                        if db_track_artist.provider == ProviderType.DATABASE:
                             for artist in search_result_item.artists:
                                 if not compare_strings(
                                     db_track_artist.name, artist.name