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
This commit is contained in:
parent
c7d6cc21e8
commit
5d8f3bcaec
3 changed files with 38 additions and 4 deletions
|
|
@ -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…
Reference in a new issue