Store original audio details in track provenance (#245)

- Add bit_depth, sample_rate, bitrate columns to track_downloads table
- Read audio info from file via Mutagen when recording provenance
- Source Info popover shows "Audio: 24-bit · 96.0kHz · 2304kbps"
- These values are captured from the original file before transcoding,
  so users can see the original specs even after Blasphemy Mode converts
  FLAC to lossy format
pull/253/head
Broque Thomas 1 month ago
parent c7d6cc21e8
commit 5d8f3bcaec

@ -1156,6 +1156,15 @@ class MusicDatabase:
cursor.execute("CREATE INDEX IF NOT EXISTS idx_td_file_path ON track_downloads (file_path)")
cursor.execute("CREATE INDEX IF NOT EXISTS idx_td_source ON track_downloads (source_username, source_filename)")
# Migration: Add audio detail columns to track_downloads
cursor.execute("PRAGMA table_info(track_downloads)")
td_columns = [c[1] for c in cursor.fetchall()]
if 'bit_depth' not in td_columns:
cursor.execute("ALTER TABLE track_downloads ADD COLUMN bit_depth INTEGER")
cursor.execute("ALTER TABLE track_downloads ADD COLUMN sample_rate INTEGER")
cursor.execute("ALTER TABLE track_downloads ADD COLUMN bitrate INTEGER")
logger.info("Added audio detail columns (bit_depth, sample_rate, bitrate) to track_downloads")
# Discovery artist blacklist — artists users never want to see in discovery
cursor.execute("""
CREATE TABLE IF NOT EXISTS discovery_artist_blacklist (
@ -8626,7 +8635,8 @@ class MusicDatabase:
def record_track_download(self, file_path: str, source_service: str, source_username: str,
source_filename: str, source_size: int = 0, audio_quality: str = '',
track_title: str = '', track_artist: str = '', track_album: str = '',
status: str = 'completed', track_id: str = None) -> Optional[int]:
status: str = 'completed', track_id: str = None,
bit_depth: int = None, sample_rate: int = None, bitrate: int = None) -> Optional[int]:
"""Record a download with full source provenance. Returns the record ID."""
try:
conn = self._get_connection()
@ -8642,10 +8652,12 @@ class MusicDatabase:
cursor.execute("""
INSERT INTO track_downloads
(track_id, file_path, source_service, source_username, source_filename,
source_size, audio_quality, track_title, track_artist, track_album, status)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
source_size, audio_quality, track_title, track_artist, track_album, status,
bit_depth, sample_rate, bitrate)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""", (track_id, file_path, source_service, source_username, source_filename,
source_size, audio_quality, track_title, track_artist, track_album, status))
source_size, audio_quality, track_title, track_artist, track_album, status,
bit_depth, sample_rate, bitrate))
conn.commit()
return cursor.lastrowid
except Exception as e:

@ -1728,6 +1728,21 @@ def _record_download_provenance(context):
quality = context.get('_audio_quality', '')
size = search_result.get('size', 0)
# Read audio details from the file for provenance (survives transcoding)
bit_depth = None
sample_rate = None
bitrate = None
try:
if file_path and os.path.isfile(file_path):
from mutagen import File as MutagenFile
audio = MutagenFile(file_path)
if audio and audio.info:
sample_rate = getattr(audio.info, 'sample_rate', None)
bitrate = getattr(audio.info, 'bitrate', None)
bit_depth = getattr(audio.info, 'bits_per_sample', None)
except Exception:
pass
db = get_database()
db.record_track_download(
file_path=file_path,
@ -1739,6 +1754,9 @@ def _record_download_provenance(context):
track_title=title,
track_artist=artist_name,
track_album=album_name,
bit_depth=bit_depth,
sample_rate=sample_rate,
bitrate=bitrate,
)
except Exception:
pass # Non-critical, never block download flow

@ -44658,6 +44658,10 @@ async function showTrackSourceInfo(track, anchorEl) {
<span class="source-info-label">Quality</span>
<span class="source-info-value">${_esc(dl.audio_quality)}</span>
</div>` : ''}
${dl.bit_depth || dl.sample_rate || dl.bitrate ? `<div class="source-info-row">
<span class="source-info-label">Audio</span>
<span class="source-info-value">${[dl.bit_depth ? `${dl.bit_depth}-bit` : '', dl.sample_rate ? `${(dl.sample_rate / 1000).toFixed(1)}kHz` : '', dl.bitrate ? `${Math.round(dl.bitrate / 1000)}kbps` : ''].filter(Boolean).join(' · ')}</span>
</div>` : ''}
${dateStr ? `<div class="source-info-row">
<span class="source-info-label">Downloaded</span>
<span class="source-info-value">${dateStr}</span>

Loading…
Cancel
Save