Add optional ReplayGain analysis to post-processing pipeline
New toggle in Settings → Library → Post-Processing: "Apply ReplayGain tags after download". When enabled, analyzes loudness via ffmpeg's ebur128 filter and writes track-level ReplayGain gain/peak tags. Runs after metadata tagging but before lossy copy so both files get the tags. Off by default — adds a few seconds per track. Applied to both album and playlist/single download paths.
This commit is contained in:
parent
461f28f084
commit
aa8f97e3d5
3 changed files with 36 additions and 1 deletions
|
|
@ -5931,7 +5931,7 @@ def handle_settings():
|
|||
if 'active_media_server' in new_settings:
|
||||
config_manager.set_active_media_server(new_settings['active_media_server'])
|
||||
|
||||
for service in ['spotify', 'plex', 'jellyfin', 'navidrome', 'soulseek', 'download_source', 'settings', 'database', 'metadata_enhancement', 'file_organization', 'playlist_sync', 'tidal', 'tidal_download', 'qobuz', 'hifi_download', 'deezer_download', 'lidarr_download', 'listenbrainz', 'acoustid', 'lastfm', 'genius', 'import', 'lossy_copy', 'listening_stats', 'ui_appearance', 'youtube', 'content_filter', 'itunes', 'm3u_export', 'musicbrainz', 'deezer', 'audiodb', 'metadata', 'hydrabase', 'security', 'discogs', 'library', 'discover', 'wishlist', 'genre_whitelist']:
|
||||
for service in ['spotify', 'plex', 'jellyfin', 'navidrome', 'soulseek', 'download_source', 'settings', 'database', 'metadata_enhancement', 'file_organization', 'playlist_sync', 'tidal', 'tidal_download', 'qobuz', 'hifi_download', 'deezer_download', 'lidarr_download', 'listenbrainz', 'acoustid', 'lastfm', 'genius', 'import', 'lossy_copy', 'listening_stats', 'ui_appearance', 'youtube', 'content_filter', 'itunes', 'm3u_export', 'musicbrainz', 'deezer', 'audiodb', 'metadata', 'hydrabase', 'security', 'discogs', 'library', 'discover', 'wishlist', 'genre_whitelist', 'post_processing']:
|
||||
if service in new_settings:
|
||||
for key, value in new_settings[service].items():
|
||||
config_manager.set(f'{service}.{key}', value)
|
||||
|
|
@ -21346,6 +21346,18 @@ def _post_process_matched_download(context_key, context, file_path):
|
|||
# Store final path for verification wrapper (before conversions may override)
|
||||
context['_final_processed_path'] = final_path
|
||||
|
||||
# ReplayGain analysis — write track-level gain tags if enabled
|
||||
if config_manager.get('post_processing.replaygain_enabled', False):
|
||||
try:
|
||||
from core.replaygain import analyze_track as _rg_analyze, write_replaygain_tags as _rg_write, is_ffmpeg_available as _rg_ffmpeg_ok, RG_REFERENCE_LUFS as _RG_REF
|
||||
if _rg_ffmpeg_ok():
|
||||
lufs, peak_dbfs = _rg_analyze(final_path)
|
||||
gain_db = _RG_REF - lufs
|
||||
_rg_write(final_path, gain_db, peak_dbfs)
|
||||
pp_logger.info(f"ReplayGain: {gain_db:+.2f} dB — {os.path.basename(final_path)}")
|
||||
except Exception as rg_err:
|
||||
pp_logger.debug(f"ReplayGain analysis skipped: {rg_err}")
|
||||
|
||||
# Downsample hi-res FLAC to CD quality if enabled (must run before lossy copy)
|
||||
downsampled_path = _downsample_hires_flac(final_path, context)
|
||||
if downsampled_path:
|
||||
|
|
@ -21723,6 +21735,18 @@ def _post_process_matched_download(context_key, context, file_path):
|
|||
# 4. Generate LRC lyrics file at final location (elegant addition)
|
||||
_generate_lrc_file(final_path, context, spotify_artist, album_info)
|
||||
|
||||
# 5. ReplayGain analysis — write track-level gain tags if enabled
|
||||
if config_manager.get('post_processing.replaygain_enabled', False):
|
||||
try:
|
||||
from core.replaygain import analyze_track as _rg_analyze, write_replaygain_tags as _rg_write, is_ffmpeg_available as _rg_ffmpeg_ok, RG_REFERENCE_LUFS as _RG_REF
|
||||
if _rg_ffmpeg_ok():
|
||||
lufs, peak_dbfs = _rg_analyze(final_path)
|
||||
gain_db = _RG_REF - lufs
|
||||
_rg_write(final_path, gain_db, peak_dbfs)
|
||||
pp_logger.info(f"ReplayGain: {gain_db:+.2f} dB, peak {peak_dbfs:.2f} dBFS — {os.path.basename(final_path)}")
|
||||
except Exception as rg_err:
|
||||
pp_logger.debug(f"ReplayGain analysis skipped: {rg_err}")
|
||||
|
||||
# Downsample hi-res FLAC to CD quality if enabled (must run before lossy copy)
|
||||
downsampled_path = _downsample_hires_flac(final_path, context)
|
||||
if downsampled_path:
|
||||
|
|
|
|||
|
|
@ -5195,6 +5195,13 @@
|
|||
Generate .lrc lyrics files (LRClib)
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="replaygain-enabled">
|
||||
Apply ReplayGain tags after download
|
||||
</label>
|
||||
<small class="settings-hint">Analyzes loudness and writes ReplayGain track gain/peak tags. Requires ffmpeg. Adds a few seconds per track.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tag Embedding — per-tag toggles grouped by source -->
|
||||
|
|
|
|||
|
|
@ -6123,6 +6123,7 @@ async function loadSettingsData() {
|
|||
document.getElementById('cover-art-download').checked = settings.metadata_enhancement?.cover_art_download !== false;
|
||||
document.getElementById('prefer-caa-art').checked = settings.metadata_enhancement?.prefer_caa_art === true;
|
||||
document.getElementById('lrclib-enabled').checked = settings.metadata_enhancement?.lrclib_enabled !== false;
|
||||
document.getElementById('replaygain-enabled').checked = settings.post_processing?.replaygain_enabled === true;
|
||||
// Load service master toggles
|
||||
document.getElementById('embed-spotify').checked = settings.spotify?.embed_tags !== false;
|
||||
document.getElementById('embed-itunes').checked = settings.itunes?.embed_tags !== false;
|
||||
|
|
@ -7456,6 +7457,9 @@ async function saveSettings(quiet = false) {
|
|||
enabled: document.getElementById('genre-whitelist-enabled').checked,
|
||||
genres: _collectGenreWhitelist(),
|
||||
},
|
||||
post_processing: {
|
||||
replaygain_enabled: document.getElementById('replaygain-enabled').checked,
|
||||
},
|
||||
library: {
|
||||
music_paths: collectMusicPaths(),
|
||||
music_videos_path: document.getElementById('music-videos-path').value || './MusicVideos'
|
||||
|
|
|
|||
Loading…
Reference in a new issue