Add opt-in setting to replace lower quality files on import
New toggle in Settings > Library: "Replace lower quality files on import". When enabled, if a track already exists in the library at a lower quality tier (e.g. MP3) and a higher quality version (e.g. FLAC) is imported from staging, the existing file is replaced. Comparison uses the existing QUALITY_TIERS system (lossless > opus/ ogg > m4a > mp3). When disabled (default), existing behavior is unchanged — existing tracks are always kept. Also applies to regular downloads that land on an existing file.
This commit is contained in:
parent
e1c5ae0eb5
commit
c6bebd5e09
4 changed files with 57 additions and 10 deletions
|
|
@ -461,7 +461,8 @@ class ConfigManager:
|
||||||
"poll_interval": 30
|
"poll_interval": 30
|
||||||
},
|
},
|
||||||
"import": {
|
"import": {
|
||||||
"staging_path": "./Staging"
|
"staging_path": "./Staging",
|
||||||
|
"replace_lower_quality": False
|
||||||
},
|
},
|
||||||
"m3u_export": {
|
"m3u_export": {
|
||||||
"enabled": False
|
"enabled": False
|
||||||
|
|
|
||||||
|
|
@ -20076,15 +20076,37 @@ def _post_process_matched_download(context_key, context, file_path):
|
||||||
has_metadata = existing_file is not None and len(existing_file.tags or {}) > 2 # More than basic tags
|
has_metadata = existing_file is not None and len(existing_file.tags or {}) > 2 # More than basic tags
|
||||||
|
|
||||||
if has_metadata and not is_enhance_download:
|
if has_metadata and not is_enhance_download:
|
||||||
print(f"⚠️ [Protection] Existing file already has metadata enhancement - skipping overwrite: {os.path.basename(final_path)}")
|
# Check if incoming file is higher quality and setting is enabled
|
||||||
print(f"🗑️ [Protection] Removing redundant download file: {os.path.basename(file_path)}")
|
_replace_lower = config_manager.get('import.replace_lower_quality', False)
|
||||||
try:
|
if _replace_lower:
|
||||||
os.remove(file_path) # Remove the redundant file
|
_existing_tier = _get_quality_tier_from_extension(final_path)
|
||||||
except FileNotFoundError:
|
_incoming_tier = _get_quality_tier_from_extension(file_path)
|
||||||
print(f"⚠️ [Protection] Could not remove redundant file (already gone): {file_path}")
|
if _incoming_tier[1] < _existing_tier[1]:
|
||||||
except Exception as e:
|
# Incoming is higher quality (lower tier number) — replace
|
||||||
print(f"⚠️ [Protection] Error removing redundant file: {e}")
|
print(f"🔄 [Quality Replace] Replacing {_existing_tier[0]} with {_incoming_tier[0]}: {os.path.basename(final_path)}")
|
||||||
return # Don't overwrite the good file
|
try:
|
||||||
|
os.remove(final_path)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ [Quality Replace] Could not remove existing file: {e}")
|
||||||
|
else:
|
||||||
|
print(f"⚠️ [Protection] Existing file is same or better quality ({_existing_tier[0]} vs {_incoming_tier[0]}) - skipping: {os.path.basename(final_path)}")
|
||||||
|
try:
|
||||||
|
os.remove(file_path)
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ [Protection] Error removing redundant file: {e}")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
print(f"⚠️ [Protection] Existing file already has metadata enhancement - skipping overwrite: {os.path.basename(final_path)}")
|
||||||
|
print(f"🗑️ [Protection] Removing redundant download file: {os.path.basename(file_path)}")
|
||||||
|
try:
|
||||||
|
os.remove(file_path)
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"⚠️ [Protection] Could not remove redundant file (already gone): {file_path}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ [Protection] Error removing redundant file: {e}")
|
||||||
|
return # Don't overwrite the good file
|
||||||
elif is_enhance_download:
|
elif is_enhance_download:
|
||||||
# ENHANCE BYPASS: Allow overwrite — backup original, then remove to allow move
|
# ENHANCE BYPASS: Allow overwrite — backup original, then remove to allow move
|
||||||
print(f"🔄 [Enhance] Quality enhance mode — replacing existing file: {os.path.basename(final_path)}")
|
print(f"🔄 [Enhance] Quality enhance mode — replacing existing file: {os.path.basename(final_path)}")
|
||||||
|
|
|
||||||
|
|
@ -5710,6 +5710,24 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Import Quality Settings -->
|
||||||
|
<div class="settings-group" data-stg="library">
|
||||||
|
<h3>📥 Import Settings</h3>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="checkbox-label">
|
||||||
|
<input type="checkbox" id="import-replace-lower-quality">
|
||||||
|
Replace lower quality files on import
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="help-text">
|
||||||
|
When importing from Staging, if a track already exists in your library at a lower quality
|
||||||
|
(e.g. MP3), it will be replaced with the higher quality version (e.g. FLAC).
|
||||||
|
If disabled, existing tracks are always kept and the import file is skipped.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- M3U Export Settings -->
|
<!-- M3U Export Settings -->
|
||||||
<div class="settings-group" data-stg="library">
|
<div class="settings-group" data-stg="library">
|
||||||
<h3>📋 M3U Playlist Export</h3>
|
<h3>📋 M3U Playlist Export</h3>
|
||||||
|
|
|
||||||
|
|
@ -5972,6 +5972,9 @@ async function loadSettingsData() {
|
||||||
// Populate Content Filter settings
|
// Populate Content Filter settings
|
||||||
document.getElementById('allow-explicit').checked = settings.content_filter?.allow_explicit !== false;
|
document.getElementById('allow-explicit').checked = settings.content_filter?.allow_explicit !== false;
|
||||||
|
|
||||||
|
// Populate Import settings
|
||||||
|
document.getElementById('import-replace-lower-quality').checked = settings.import?.replace_lower_quality === true;
|
||||||
|
|
||||||
// Populate M3U Export settings
|
// Populate M3U Export settings
|
||||||
document.getElementById('m3u-export-enabled').checked = settings.m3u_export?.enabled === true;
|
document.getElementById('m3u-export-enabled').checked = settings.m3u_export?.enabled === true;
|
||||||
|
|
||||||
|
|
@ -7076,6 +7079,9 @@ async function saveSettings(quiet = false) {
|
||||||
content_filter: {
|
content_filter: {
|
||||||
allow_explicit: document.getElementById('allow-explicit').checked
|
allow_explicit: document.getElementById('allow-explicit').checked
|
||||||
},
|
},
|
||||||
|
import: {
|
||||||
|
replace_lower_quality: document.getElementById('import-replace-lower-quality').checked
|
||||||
|
},
|
||||||
lossy_copy: {
|
lossy_copy: {
|
||||||
enabled: document.getElementById('lossy-copy-enabled').checked,
|
enabled: document.getElementById('lossy-copy-enabled').checked,
|
||||||
codec: document.getElementById('lossy-copy-codec').value,
|
codec: document.getElementById('lossy-copy-codec').value,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue