Add audio verification and duplicate tracking features
- Integrated `plexapi` and `python-dotenv` as dependencies in `flake.nix` and `pyproject.toml` for enhanced functionality. - Implemented new modules for audio verification and duplicate tracking, including `audio_verification.py`, `duplicate_finder.py`, and `track_verification.py`. - Updated `main.py` to utilize the new modules for identifying and managing duplicate single tracks in Lidarr, with detailed logging and confidence scoring. - Enhanced the `find_duplicate_singles` function to support audio verification results and metadata migration to Plex. - Refactored existing code for improved structure and maintainability, ensuring better integration of new features.
This commit is contained in:
85
src-cleanup/track_verification.py
Normal file
85
src-cleanup/track_verification.py
Normal file
@@ -0,0 +1,85 @@
|
||||
"""Track verification using multiple methods"""
|
||||
|
||||
import logging
|
||||
from typing import Dict, Optional, Tuple
|
||||
|
||||
from audio_verification import (
|
||||
check_file_properties,
|
||||
check_mb_recording_id,
|
||||
check_quality_profile,
|
||||
compare_fingerprints,
|
||||
get_audio_fingerprint,
|
||||
get_file_properties,
|
||||
)
|
||||
from lidarr_client import get_track_info, get_trackfile_info
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def verify_audio_match(
|
||||
base_url: str,
|
||||
headers: Dict[str, str],
|
||||
single_track_id: int,
|
||||
single_track_file_id: int,
|
||||
album_track_id: int,
|
||||
album_track_file_id: int,
|
||||
docker_mount: Optional[str] = None,
|
||||
) -> Tuple[bool, Optional[str], int]:
|
||||
"""Verify tracks using multiple methods. Returns (match, message, confidence_score)"""
|
||||
logger.debug(
|
||||
f"Verifying audio match: single trackFileId {single_track_file_id} vs album trackFileId {album_track_file_id}"
|
||||
)
|
||||
|
||||
single_file_info = get_trackfile_info(base_url, single_track_file_id, headers)
|
||||
album_file_info = get_trackfile_info(base_url, album_track_file_id, headers)
|
||||
|
||||
if not (single_file_info and album_file_info):
|
||||
return False, "Could not fetch track file info", 0
|
||||
|
||||
single_path = single_file_info.get("path")
|
||||
album_path = album_file_info.get("path")
|
||||
if not (single_path and album_path):
|
||||
return False, "Missing file paths", 0
|
||||
|
||||
single_track_info = get_track_info(base_url, single_track_id, headers)
|
||||
album_track_info = get_track_info(base_url, album_track_id, headers)
|
||||
|
||||
mb_score, mb_msg = check_mb_recording_id(single_track_info, album_track_info)
|
||||
quality_score, quality_msg = check_quality_profile(
|
||||
single_file_info, album_file_info
|
||||
)
|
||||
|
||||
single_props = get_file_properties(single_path, docker_mount)
|
||||
album_props = get_file_properties(album_path, docker_mount)
|
||||
prop_checks = check_file_properties(single_props, album_props)
|
||||
|
||||
single_fp = get_audio_fingerprint(single_path, docker_mount)
|
||||
album_fp = get_audio_fingerprint(album_path, docker_mount)
|
||||
log_context = f"single trackFileId {single_track_file_id} vs album trackFileId {album_track_file_id}"
|
||||
|
||||
if single_fp and album_fp:
|
||||
fp_match, fp_message = compare_fingerprints(
|
||||
single_fp, album_fp, log_context, return_message=True
|
||||
)
|
||||
fp_score = 20 if fp_match else 0
|
||||
fp_msg = f"✓ Audio fingerprint match (+20)" if fp_match else f"⚠ {fp_message}"
|
||||
else:
|
||||
fp_score, fp_msg = 0, "⚠ Audio fingerprint unavailable"
|
||||
|
||||
all_checks = [
|
||||
(mb_score, mb_msg),
|
||||
(quality_score, quality_msg) if quality_msg else None,
|
||||
*prop_checks,
|
||||
(fp_score, fp_msg),
|
||||
]
|
||||
|
||||
valid_checks = list(filter(lambda x: x is not None, all_checks))
|
||||
confidence_score = sum(score for score, _ in valid_checks)
|
||||
verification_results = [msg for _, msg in valid_checks]
|
||||
|
||||
match = confidence_score >= 70
|
||||
result_message = f"Confidence: {confidence_score}/100 | " + " | ".join(
|
||||
verification_results
|
||||
)
|
||||
|
||||
return match, result_message, confidence_score
|
||||
Reference in New Issue
Block a user