Fix issues with search (#326)
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Thu, 19 May 2022 09:33:20 +0000 (11:33 +0200)
committerGitHub <noreply@github.com>
Thu, 19 May 2022 09:33:20 +0000 (11:33 +0200)
music_assistant/controllers/music/albums.py
music_assistant/controllers/music/artists.py
music_assistant/controllers/music/providers/filesystem.py
music_assistant/controllers/music/tracks.py
music_assistant/helpers/database.py
music_assistant/models/media_controller.py

index a35d70767a0add559c82b0c2dd4b5c77aa5d18af..6471aa65c0fdeaf5d5eb7b519ffac4b86fe31fc0 100644 (file)
@@ -214,10 +214,7 @@ class AlbumsController(MediaControllerBase[Album]):
                 "Trying to match album %s on provider %s", db_album.name, provider.name
             )
             match_found = False
-            searchstr = f"{db_album.artist.name} {db_album.name}"
-            if db_album.version:
-                searchstr += " " + db_album.version
-            search_result = await self.search(searchstr, provider.id)
+            search_result = await self.search(db_album.name, provider.id)
             for search_result_item in search_result:
                 if not search_result_item.available:
                     continue
@@ -231,11 +228,6 @@ class AlbumsController(MediaControllerBase[Album]):
                     # 100% match, we can simply update the db with additional provider ids
                     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 == ProviderType.DATABASE:
-                        await self.mass.music.artists.update_db_item(
-                            db_album.artist.item_id, prov_album.artist
-                        )
             return match_found
 
         # try to find match on all providers
index 169cf63ea3a48b366d1d69da7af402c79dec0cb8..854c3ed97f5c45340d84f4804b6ab685f371bde2 100644 (file)
@@ -204,9 +204,8 @@ class ArtistsController(MediaControllerBase[Artist]):
                 ref_track = await self.mass.music.tracks.get(
                     ref_track.item_id, ref_track.provider
                 )
-            searchstr = f"{db_artist.name} {ref_track.name}"
             search_results = await self.mass.music.tracks.search(
-                searchstr, provider.type
+                ref_track.name, provider.type
             )
             for search_result_item in search_results:
                 if not compare_track(search_result_item, ref_track):
@@ -227,9 +226,8 @@ class ArtistsController(MediaControllerBase[Artist]):
         for ref_album in artist_albums:
             if ref_album.album_type == AlbumType.COMPILATION:
                 continue
-            searchstr = f"{db_artist.name} {ref_album.name}"
             search_result = await self.mass.music.albums.search(
-                searchstr, provider.type
+                ref_album.name, provider.type
             )
             for search_result_item in search_result:
                 # artist must match 100%
index e7ca33ec22ba57535f71f4cc347bcd46169165f5..e4f75ad0ee3c812a5d6705c4f451a31ed5bf5c41 100644 (file)
@@ -106,34 +106,22 @@ class FileSystemProvider(MusicProvider):
         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
+        params = {"name": f"%{search_query}%", "prov_type": f"%{self.type.value}%"}
         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)
+            query = "SELECT * FROM tracks WHERE name LIKE :name AND provider_ids LIKE :prov_type"
+            tracks = await self.mass.music.tracks.get_db_items(query, params)
             result += 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)
+            query = "SELECT * FROM albums WHERE name LIKE :name AND provider_ids LIKE :prov_type"
+            albums = await self.mass.music.albums.get_db_items(query, params)
             result += 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)
+            query = "SELECT * FROM artists WHERE name LIKE :name AND provider_ids LIKE :prov_type"
+            artists = await self.mass.music.artists.get_db_items(query, params)
             result += 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)
+            query = "SELECT * FROM playlists WHERE name LIKE :name AND provider_ids LIKE :prov_type"
+            playlists = await self.mass.music.playlists.get_db_items(query, params)
             result += playlists
         return result
 
index 899b4953e57bfad711c9dfda821791fede4ca4b5..3e586a4318757cf28eab15249126909e2f713373 100644 (file)
@@ -4,11 +4,7 @@ from __future__ import annotations
 import asyncio
 from typing import List, Optional, Union
 
-from music_assistant.helpers.compare import (
-    compare_artists,
-    compare_strings,
-    compare_track,
-)
+from music_assistant.helpers.compare import compare_artists, compare_track
 from music_assistant.helpers.database import TABLE_TRACKS
 from music_assistant.helpers.json import json_serializer
 from music_assistant.models.enums import EventType, MediaType, ProviderType
@@ -65,12 +61,10 @@ class TracksController(MediaControllerBase[Track]):
         """Return all versions of a track we can find on all providers."""
         track = await self.get(item_id, provider, provider_id)
         prov_types = {item.type for item in self.mass.music.providers}
-        first_artist = next(iter(track.artists))
-        search_query = f"{first_artist.name} {track.name}"
         return [
             prov_item
             for prov_items in await asyncio.gather(
-                *[self.search(search_query, prov_type) for prov_type in prov_types]
+                *[self.search(track.name, prov_type) for prov_type in prov_types]
             )
             for prov_item in prov_items
             if compare_artists(prov_item.artists, track.artists)
@@ -94,35 +88,14 @@ class TracksController(MediaControllerBase[Track]):
                 "Trying to match track %s on provider %s", db_track.name, provider.name
             )
             match_found = False
-            for db_track_artist in db_track.artists:
-                if match_found:
-                    break
-                searchstr = f"{db_track_artist.name} {db_track.name}"
-                if db_track.version:
-                    searchstr += " " + db_track.version
-                search_result = await self.search(searchstr, provider.type)
-                for search_result_item in search_result:
-                    if not search_result_item.available:
-                        continue
-                    if compare_track(search_result_item, db_track):
-                        # 100% match, we can simply update the db with additional provider ids
-                        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 == ProviderType.DATABASE:
-                            for artist in search_result_item.artists:
-                                if not compare_strings(
-                                    db_track_artist.name, artist.name
-                                ):
-                                    continue
-                                prov_artist = (
-                                    await self.mass.music.artists.get_provider_item(
-                                        artist.item_id, artist.provider
-                                    )
-                                )
-                                await self.mass.music.artists.update_db_item(
-                                    db_track_artist.item_id, prov_artist
-                                )
+            search_result = await self.search(db_track.name, provider.type)
+            for search_result_item in search_result:
+                if not search_result_item.available:
+                    continue
+                if compare_track(search_result_item, db_track):
+                    # 100% match, we can simply update the db with additional provider ids
+                    match_found = True
+                    await self.update_db_item(db_track.item_id, search_result_item)
 
             if not match_found:
                 self.logger.debug(
index 3ace0931d63ebad7d3aeabce016aa959fcd3b384..c73cdac8f7789944858ee93893726cefd678a77d 100755 (executable)
@@ -98,19 +98,20 @@ class Database:
             return await _db.fetch_all(sql_query, match)
 
     async def get_rows_from_query(
-        self, query: str, db: Optional[Db] = None
+        self, query: str, params: Optional[dict] = None, db: Optional[Db] = None
     ) -> List[Mapping]:
         """Get all rows for given custom query."""
         async with self.get_db(db) as _db:
-            return await _db.fetch_all(query)
+            return await _db.fetch_all(query, params)
 
     async def search(
         self, table: str, search: str, column: str = "name", db: Optional[Db] = None
     ) -> List[Mapping]:
         """Search table by column."""
         async with self.get_db(db) as _db:
-            sql_query = f'SELECT * FROM {table} WHERE {column} LIKE "{search}"'
-            return await _db.fetch_all(sql_query)
+            sql_query = f"SELECT * FROM {table} WHERE {column} LIKE :search"
+            params = {"search": f"%{search}%"}
+            return await _db.fetch_all(sql_query, params)
 
     async def get_row(
         self, table: str, match: Dict[str, Any] = None, db: Optional[Db] = None
index f8f32e8bed0eda702b8ec7eba0b1b242af5283a2..bc3b97ca1211b8f68e022951a9a7ca37cd4de5d2 100644 (file)
@@ -175,11 +175,14 @@ class MediaControllerBase(Generic[ItemCls], metaclass=ABCMeta):
         return None, None
 
     async def get_db_items(
-        self, custom_query: Optional[str] = None, db: Optional[Db] = None
+        self,
+        query: Optional[str] = None,
+        query_params: Optional[dict] = None,
+        db: Optional[Db] = None,
     ) -> List[ItemCls]:
         """Fetch all records from database."""
-        if custom_query is not None:
-            func = self.mass.database.get_rows_from_query(custom_query, db=db)
+        if query is not None:
+            func = self.mass.database.get_rows_from_query(query, query_params, db=db)
         else:
             func = self.mass.database.get_rows(self.db_table, db=db)
         return [self.item_cls.from_db_row(db_row) for db_row in await func]