From: Marcel van der Veldt Date: Thu, 19 May 2022 09:33:20 +0000 (+0200) Subject: Fix issues with search (#326) X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=9c5c7500260e2a847426e9f18a168dbec732d20e;p=music-assistant-server.git Fix issues with search (#326) --- diff --git a/music_assistant/controllers/music/albums.py b/music_assistant/controllers/music/albums.py index a35d7076..6471aa65 100644 --- a/music_assistant/controllers/music/albums.py +++ b/music_assistant/controllers/music/albums.py @@ -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 diff --git a/music_assistant/controllers/music/artists.py b/music_assistant/controllers/music/artists.py index 169cf63e..854c3ed9 100644 --- a/music_assistant/controllers/music/artists.py +++ b/music_assistant/controllers/music/artists.py @@ -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% diff --git a/music_assistant/controllers/music/providers/filesystem.py b/music_assistant/controllers/music/providers/filesystem.py index e7ca33ec..e4f75ad0 100644 --- a/music_assistant/controllers/music/providers/filesystem.py +++ b/music_assistant/controllers/music/providers/filesystem.py @@ -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 diff --git a/music_assistant/controllers/music/tracks.py b/music_assistant/controllers/music/tracks.py index 899b4953..3e586a43 100644 --- a/music_assistant/controllers/music/tracks.py +++ b/music_assistant/controllers/music/tracks.py @@ -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( diff --git a/music_assistant/helpers/database.py b/music_assistant/helpers/database.py index 3ace0931..c73cdac8 100755 --- a/music_assistant/helpers/database.py +++ b/music_assistant/helpers/database.py @@ -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 diff --git a/music_assistant/models/media_controller.py b/music_assistant/models/media_controller.py index f8f32e8b..bc3b97ca 100644 --- a/music_assistant/models/media_controller.py +++ b/music_assistant/models/media_controller.py @@ -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]