Add duplicate audio hash detection

This commit is contained in:
Philip Guzman
2026-07-01 16:36:21 -07:00
parent ec646479d2
commit 4d04939846
8 changed files with 186 additions and 4 deletions
+25 -1
View File
@@ -18,6 +18,7 @@ from serato_doctor.crate_parser import load_library_crates
from serato_doctor.database_parser import parse_database
from serato_doctor.duplicates import find_duplicate_groups
from serato_doctor.health import analyze_health
from serato_doctor.hashing import compare_audio_files
from serato_doctor.matching import MatchingEngine, normalize
from serato_doctor.models.crate import CrateKind
from serato_doctor.models.duplicate import DuplicateKind
@@ -357,6 +358,9 @@ def duplicate_repair_batch(
if not plans:
raise ValueError("Choose at least one duplicate group")
replaced = [str(path) for plan in plans for path in plan.replaced]
comparisons = [
compare_audio_files((plan.keeper,) + plan.replaced) for plan in plans
]
result = {
"choice_count": len(plans),
"replaced": replaced,
@@ -364,8 +368,9 @@ def duplicate_repair_batch(
{
"keeper": str(plan.keeper),
"replaced": [str(path) for path in plan.replaced],
"hash_status": comparison["status"],
}
for plan in plans
for plan, comparison in zip(plans, comparisons)
],
"metadata_backups": len(plans[0].metadata_files),
"strategy": "shortcut",
@@ -438,6 +443,7 @@ class SeratoDoctorHandler(BaseHTTPRequestHandler):
"/api/duplicates/apply",
"/api/duplicates/batch/preview",
"/api/duplicates/batch/apply",
"/api/duplicates/hash",
"/api/backups/restore",
"/api/backups",
"/api/reveal",
@@ -471,6 +477,24 @@ class SeratoDoctorHandler(BaseHTTPRequestHandler):
raise ValueError("That backup does not belong to this library")
restored = restore_backup(backup)
result = {"restored": [str(path) for path in restored]}
elif self.path == "/api/duplicates/hash":
tokens = payload["tokens"]
if not isinstance(tokens, list) or not 2 <= len(tokens) <= 10:
raise ValueError("Compare between 2 and 10 audio files")
comparison = compare_audio_files(
_verified_audio(token) for token in tokens
)
result = {
"status": comparison["status"],
"files": [
{
"path": item["path"],
"size": item["size"],
"fingerprint": item["sha256"][:12],
}
for item in comparison["files"]
],
}
elif self.path.startswith("/api/duplicates/batch/"):
raw_limit = payload.get("backup_limit", 10)
backup_limit = None if raw_limit is None else int(raw_limit)