various/stale
This commit is contained in:
@@ -1081,6 +1081,27 @@ class SRUtil:
|
||||
return combined_metadata
|
||||
|
||||
except Exception as e:
|
||||
err_str = str(e).lower()
|
||||
# If this is a permanent not found error, abort retries immediately
|
||||
if any(
|
||||
phrase in err_str
|
||||
for phrase in [
|
||||
"track not found",
|
||||
"not found",
|
||||
"404",
|
||||
"does not exist",
|
||||
"no longer available",
|
||||
"asset is not ready",
|
||||
]
|
||||
):
|
||||
logging.error(
|
||||
"Metadata fetch permanent failure for track %s: %s (not retrying)",
|
||||
track_id,
|
||||
str(e),
|
||||
)
|
||||
raise MetadataFetchError(
|
||||
f"Metadata fetch failed permanently for track {track_id}: {e}"
|
||||
)
|
||||
# Exponential backoff with jitter for 429 or other errors
|
||||
delay = self.RETRY_DELAY * (2 ** (attempt - 1)) + random.uniform(0, 0.5)
|
||||
if attempt < self.MAX_METADATA_RETRIES:
|
||||
@@ -1179,6 +1200,47 @@ class SRUtil:
|
||||
if not tracks:
|
||||
return None
|
||||
|
||||
# Prefer exact title matches first (highest confidence)
|
||||
exact_title_matches = []
|
||||
for t in tracks:
|
||||
found_title = t.get("title")
|
||||
if found_title and found_title.strip().lower() == song.strip().lower():
|
||||
exact_title_matches.append(t)
|
||||
if exact_title_matches:
|
||||
logging.info(f"SR: {len(exact_title_matches)} exact title matches found")
|
||||
tracks = exact_title_matches
|
||||
else:
|
||||
# Prefer tracks that match artist/title fuzzily
|
||||
filtered_by_metadata = []
|
||||
for t in tracks:
|
||||
found_artist = (
|
||||
t.get("artist", {}).get("name")
|
||||
if isinstance(t.get("artist"), dict)
|
||||
else t.get("artist")
|
||||
)
|
||||
found_album = (
|
||||
t.get("album", {}).get("title") if t.get("album") else None
|
||||
)
|
||||
found_title = t.get("title")
|
||||
try:
|
||||
if self.is_metadata_match(
|
||||
artist, album, song, found_artist, found_album, found_title
|
||||
):
|
||||
filtered_by_metadata.append(t)
|
||||
except Exception:
|
||||
# On any error, skip strict metadata matching for this candidate
|
||||
continue
|
||||
|
||||
if filtered_by_metadata:
|
||||
logging.info(
|
||||
f"SR: {len(filtered_by_metadata)} candidates after metadata filtering"
|
||||
)
|
||||
tracks = filtered_by_metadata
|
||||
else:
|
||||
logging.info(
|
||||
"SR: No candidates passed metadata match filter; falling back to search results"
|
||||
)
|
||||
|
||||
# If duration provided, select the track with closest duration match
|
||||
if duration is not None:
|
||||
tracks_with_diff = [
|
||||
@@ -1195,7 +1257,88 @@ class SRUtil:
|
||||
best_track = tracks[0]
|
||||
|
||||
track_id = best_track.get("id")
|
||||
logging.info(f"SR: Using track ID {track_id}")
|
||||
# Ensure the selected candidate reasonably matches expected metadata
|
||||
selected_artist = (
|
||||
best_track.get("artist", {}).get("name")
|
||||
if isinstance(best_track.get("artist"), dict)
|
||||
else best_track.get("artist")
|
||||
)
|
||||
selected_title = best_track.get("title")
|
||||
if not self.is_metadata_match(
|
||||
artist,
|
||||
album,
|
||||
song,
|
||||
selected_artist,
|
||||
best_track.get("album", {}).get("title")
|
||||
if best_track.get("album")
|
||||
else None,
|
||||
selected_title,
|
||||
):
|
||||
# Try to find another candidate that does match metadata
|
||||
logging.warning(
|
||||
"SR: Selected candidate failed metadata check: id=%s artist=%s title=%s; searching for better match",
|
||||
track_id,
|
||||
selected_artist,
|
||||
selected_title,
|
||||
)
|
||||
found_better = None
|
||||
for candidate in tracks:
|
||||
cand_artist = (
|
||||
candidate.get("artist", {}).get("name")
|
||||
if isinstance(candidate.get("artist"), dict)
|
||||
else candidate.get("artist")
|
||||
)
|
||||
cand_title = candidate.get("title")
|
||||
if self.is_metadata_match(
|
||||
artist,
|
||||
album,
|
||||
song,
|
||||
cand_artist,
|
||||
candidate.get("album", {}).get("title")
|
||||
if candidate.get("album")
|
||||
else None,
|
||||
cand_title,
|
||||
):
|
||||
found_better = candidate
|
||||
break
|
||||
if found_better:
|
||||
logging.warning(
|
||||
"SR: Switching to better candidate id=%s artist=%s title=%s",
|
||||
found_better.get("id"),
|
||||
(
|
||||
found_better.get("artist", {}).get("name")
|
||||
if isinstance(found_better.get("artist"), dict)
|
||||
else found_better.get("artist")
|
||||
),
|
||||
found_better.get("title"),
|
||||
)
|
||||
best_track = found_better
|
||||
track_id = best_track.get("id")
|
||||
else:
|
||||
# No matching candidate passed metadata checks; log candidates and abort
|
||||
logging.warning(
|
||||
"SR: No candidates passed metadata checks for %s - %s; candidates: %s",
|
||||
artist,
|
||||
song,
|
||||
[
|
||||
{
|
||||
"id": t.get("id"),
|
||||
"artist": (
|
||||
t.get("artist", {}).get("name")
|
||||
if isinstance(t.get("artist"), dict)
|
||||
else t.get("artist")
|
||||
),
|
||||
"title": t.get("title"),
|
||||
"duration": t.get("duration"),
|
||||
}
|
||||
for t in tracks[:10]
|
||||
],
|
||||
)
|
||||
return None
|
||||
|
||||
logging.info(
|
||||
f"SR: Using track ID {track_id} (artist={best_track.get('artist')}, title={best_track.get('title')})"
|
||||
)
|
||||
if not track_id:
|
||||
return None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user