diff --git a/core/spotify_client.py b/core/spotify_client.py index d3a63e5..6e3d496 100644 --- a/core/spotify_client.py +++ b/core/spotify_client.py @@ -61,9 +61,18 @@ class Track: popularity: int preview_url: Optional[str] = None external_urls: Optional[Dict[str, str]] = None - + image_url: Optional[str] = None + @classmethod def from_spotify_track(cls, track_data: Dict[str, Any]) -> 'Track': + # Extract album image (medium size preferred) + album_image_url = None + if 'album' in track_data and 'images' in track_data['album']: + images = track_data['album']['images'] + if images: + # Get medium size image (usually index 1), or largest if not available + album_image_url = images[1]['url'] if len(images) > 1 else images[0]['url'] + return cls( id=track_data['id'], name=track_data['name'], @@ -72,7 +81,8 @@ class Track: duration_ms=track_data['duration_ms'], popularity=track_data['popularity'], preview_url=track_data.get('preview_url'), - external_urls=track_data.get('external_urls') + external_urls=track_data.get('external_urls'), + image_url=album_image_url ) @dataclass diff --git a/web_server.py b/web_server.py index d1e354f..9f1c4e0 100644 --- a/web_server.py +++ b/web_server.py @@ -3224,6 +3224,102 @@ def search_music(): print(f"Search error: {e}") return jsonify({"error": str(e)}), 500 +@app.route('/api/enhanced-search', methods=['POST']) +def enhanced_search(): + """ + Unified search across Spotify and local database for enhanced search mode. + Returns categorized results: DB artists, Spotify artists, albums, and tracks. + """ + data = request.get_json() + query = data.get('query', '').strip() + + if not query: + return jsonify({ + "db_artists": [], + "spotify_artists": [], + "spotify_albums": [], + "spotify_tracks": [] + }) + + logger.info(f"Enhanced search initiated for: '{query}'") + + try: + # Search local database for artists + database = get_database() + db_artists_objs = database.search_artists(query, limit=5) + + # Convert database artists to dictionaries + db_artists = [] + for artist in db_artists_objs: + image_url = None + if hasattr(artist, 'thumb_url') and artist.thumb_url: + image_url = fix_artist_image_url(artist.thumb_url) + + db_artists.append({ + "id": artist.id, + "name": artist.name, + "image_url": image_url + }) + logger.debug(f"DB Artist: {artist.name}, thumb_url: {artist.thumb_url if hasattr(artist, 'thumb_url') else None}, fixed_url: {image_url}") + + # Search Spotify for artists, albums, tracks + spotify_artists = [] + spotify_albums = [] + spotify_tracks = [] + + if spotify_client and spotify_client.is_authenticated(): + # Search for artists + artist_objs = spotify_client.search_artists(query, limit=5) + for artist in artist_objs: + spotify_artists.append({ + "id": artist.id, + "name": artist.name, + "image_url": artist.image_url + }) + + # Search for albums + album_objs = spotify_client.search_albums(query, limit=10) + for album in album_objs: + # Album has 'artists' (list), convert to string + artist_name = ', '.join(album.artists) if album.artists else 'Unknown Artist' + + spotify_albums.append({ + "id": album.id, + "name": album.name, + "artist": artist_name, + "image_url": album.image_url, + "release_date": album.release_date, + "total_tracks": album.total_tracks + }) + + # Search for tracks + track_objs = spotify_client.search_tracks(query, limit=10) + for track in track_objs: + # Track has 'artists' (list), convert to string + artist_name = ', '.join(track.artists) if track.artists else 'Unknown Artist' + + spotify_tracks.append({ + "id": track.id, + "name": track.name, + "artist": artist_name, + "album": track.album, + "duration_ms": track.duration_ms, + "image_url": track.image_url + }) + + logger.info(f"Enhanced search results: {len(db_artists)} DB artists, {len(spotify_artists)} Spotify artists, {len(spotify_albums)} albums, {len(spotify_tracks)} tracks") + + return jsonify({ + "db_artists": db_artists, + "spotify_artists": spotify_artists, + "spotify_albums": spotify_albums, + "spotify_tracks": spotify_tracks + }) + + except Exception as e: + logger.error(f"Enhanced search error: {e}") + return jsonify({"error": str(e)}), 500 + @app.route('/api/download', methods=['POST']) def start_download(): """Simple download route""" diff --git a/webui/index.html b/webui/index.html index f77b35c..9c599f3 100644 --- a/webui/index.html +++ b/webui/index.html @@ -1273,36 +1273,94 @@
Enhanced Search Ready
-Intelligent filtering • Smart ranking • Better results
+Search results will appear here when you select an album or track.
Searching for ${type === 'album' ? 'album' : 'track'}...
+Search failed. Please try again.
No matches found for this ' + type + '.