Add tag-based fallback to orphan detector to prevent false positives
When suffix path matching fails, reads file tags (title+artist) and checks against DB tracks. Prevents false orphan detection from path mismatches in Docker where DB paths differ from filesystem paths. Only runs for files that fail suffix matching — zero overhead in normal cases.
This commit is contained in:
parent
c53583716a
commit
dadc489b08
1 changed files with 27 additions and 0 deletions
|
|
@ -46,6 +46,7 @@ class OrphanFileDetectorJob(RepairJob):
|
|||
# of depth 1-3 (filename, album/filename, artist/album/filename) which
|
||||
# covers all realistic path-prefix mismatches.
|
||||
known_suffixes = set()
|
||||
known_titles = set() # (title_lower, artist_lower) for tag-based fallback
|
||||
conn = None
|
||||
try:
|
||||
conn = context.db._get_connection()
|
||||
|
|
@ -57,6 +58,18 @@ class OrphanFileDetectorJob(RepairJob):
|
|||
for depth in range(1, min(4, len(parts) + 1)):
|
||||
suffix = '/'.join(parts[-depth:]).lower()
|
||||
known_suffixes.add(suffix)
|
||||
|
||||
# Build title+artist set for tag-based fallback matching
|
||||
cursor.execute("""
|
||||
SELECT t.title, ar.name FROM tracks t
|
||||
LEFT JOIN artists ar ON ar.id = t.artist_id
|
||||
WHERE t.title IS NOT NULL AND t.title != ''
|
||||
""")
|
||||
for row in cursor.fetchall():
|
||||
title = (row[0] or '').lower().strip()
|
||||
artist = (row[1] or '').lower().strip()
|
||||
if title:
|
||||
known_titles.add((title, artist))
|
||||
except Exception as e:
|
||||
logger.error("Error reading known file paths from DB: %s", e, exc_info=True)
|
||||
result.errors += 1
|
||||
|
|
@ -108,6 +121,20 @@ class OrphanFileDetectorJob(RepairJob):
|
|||
is_known = True
|
||||
break
|
||||
|
||||
# Fallback: read file tags and check if title+artist exists in DB
|
||||
# Catches path mismatches where the file is tracked but under a different path
|
||||
if not is_known and known_titles:
|
||||
try:
|
||||
from mutagen import File as MutagenFile
|
||||
audio = MutagenFile(fpath, easy=True)
|
||||
if audio:
|
||||
file_title = ((audio.get('title') or [None])[0] or '').lower().strip()
|
||||
file_artist = ((audio.get('artist') or [None])[0] or '').lower().strip()
|
||||
if file_title and (file_title, file_artist) in known_titles:
|
||||
is_known = True
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if not is_known:
|
||||
orphan_files.append(fpath)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue