pull/2/head
Broque Thomas 10 months ago
parent 6358de554f
commit 8e0e77f4d2

@ -250,9 +250,8 @@ class PlexClient:
def search_tracks(self, title: str, artist: str, limit: int = 15) -> List[PlexTrackInfo]:
"""
Searches for tracks in the Plex music library. If an artist is provided, it
searches within that artist's scope. If the artist is empty or not found,
it falls back to a library-wide search for the title.
Searches for tracks using a robust, multi-stage fallback strategy to find
the best possible candidates for matching.
"""
if not self.music_library:
logger.warning("Plex music library not found. Cannot perform search.")
@ -260,41 +259,56 @@ class PlexClient:
try:
candidate_tracks = []
# If an artist is provided, perform a targeted search.
# Use a set to keep track of found track keys to avoid duplicates
found_track_keys = set()
def add_candidates(tracks):
"""Helper function to add unique tracks to the main candidate list."""
for track in tracks:
if track.ratingKey not in found_track_keys:
candidate_tracks.append(track)
found_track_keys.add(track.ratingKey)
# --- Stage 1: High-Precision Search (Artist -> then filter by Title) ---
if artist:
logger.debug(f"Stage 1: Searching for artist '{artist}'")
artist_results = self.music_library.searchArtists(title=artist, limit=1)
if artist_results:
plex_artist = artist_results[0]
all_artist_tracks = plex_artist.tracks()
lower_title = title.lower()
for track in all_artist_tracks:
if lower_title in track.title.lower():
candidate_tracks.append(track)
else:
# If artist not found, still fall back to a general title search
logger.debug(f"Artist '{artist}' not found. Falling back to title search for '{title}'.")
candidate_tracks = self.music_library.searchTracks(title=title, limit=limit)
# If no artist is provided, perform a library-wide title search directly.
else:
logger.debug(f"Performing title-only search for '{title}'.")
candidate_tracks = self.music_library.searchTracks(title=title, limit=limit)
# Find all tracks by this artist that contain the title text
stage1_results = [track for track in all_artist_tracks if lower_title in track.title.lower()]
add_candidates(stage1_results)
logger.debug(f"Stage 1 found {len(stage1_results)} candidates.")
# --- Stage 2: Flexible Keyword Search (Artist + Title combined) ---
# This is good for artist variations like "The Dare" vs "Dare"
search_query = f"{artist} {title}".strip()
logger.debug(f"Stage 2: Performing keyword search for '{search_query}'")
stage2_results = self.music_library.search(title=search_query, libtype='track', limit=limit)
add_candidates(stage2_results)
# --- Stage 3: Title-Only Fallback Search ---
# This is the broadest search for cases where artist metadata is wrong or missing.
logger.debug(f"Stage 3: Performing title-only search for '{title}'")
stage3_results = self.music_library.searchTracks(title=title, limit=limit)
add_candidates(stage3_results)
# Convert the raw Plex track objects to our simplified PlexTrackInfo dataclass
tracks = [PlexTrackInfo.from_plex_track(track) for track in candidate_tracks[:limit]]
if tracks:
logger.debug(f"Plex search for title='{title}', artist='{artist or 'N/A'}' found {len(tracks)} potential matches.")
logger.info(f"Found {len(tracks)} total potential matches for '{title}' by '{artist}' after all stages.")
return tracks
except Exception as e:
logger.error(f"Error searching Plex tracks for title='{title}', artist='{artist}': {e}")
logger.error(f"Error during multi-stage search for title='{title}', artist='{artist}': {e}")
import traceback
traceback.print_exc()
return []
def get_library_stats(self) -> Dict[str, int]:
if not self.music_library:
return {}

Loading…
Cancel
Save