Settings UI: 'Match singles to their parent album' toggle (Library > Post-Processing)

Surfaces metadata_enhancement.single_to_album as a checkbox in the Post-Processing
> Core Features section, next to the cover-art settings (it's about getting the
right album cover). Default OFF, wired like the replaygain toggle (load '=== true',
save raw .checked) since the generic data-config binding defaults a missing key to
ON. Registered the default in settings.py DEFAULT_CONFIG + config.example.json.
This commit is contained in:
BoulderBadgeDad 2026-06-18 09:44:17 -07:00
parent 58363ae510
commit 820ff20139
4 changed files with 17 additions and 2 deletions

View file

@ -44,7 +44,8 @@
}, },
"metadata_enhancement": { "metadata_enhancement": {
"enabled": true, "enabled": true,
"embed_album_art": true "embed_album_art": true,
"single_to_album": false
}, },
"file_organization": { "file_organization": {
"enabled": true, "enabled": true,

View file

@ -662,7 +662,12 @@ class ConfigManager:
# source whose art is smaller is skipped so the next source is # source whose art is smaller is skipped so the next source is
# tried — stops a low-res Cover Art Archive upload from winning. # tried — stops a low-res Cover Art Archive upload from winning.
# 0 disables the size gate. # 0 disables the size gate.
"min_art_size": 1000 "min_art_size": 1000,
# When a track matches a SINGLE release, look up the parent ALBUM
# that contains it and tag it as that album, so it groups with its
# album-mates and gets the album cover (not the single's). Off by
# default — it's an extra per-import metadata lookup.
"single_to_album": False
}, },
"musicbrainz": { "musicbrainz": {
"embed_tags": True "embed_tags": True

View file

@ -5730,6 +5730,13 @@
<small class="settings-hint">Order the sources to choose whose cover art is used. The first source that has a cover wins; misses fall through to the next, and if none match, your download's own art is kept. Only sources you're connected to are shown — leave all off to keep current behavior.</small> <small class="settings-hint">Order the sources to choose whose cover art is used. The first source that has a cover wins; misses fall through to the next, and if none match, your download's own art is kept. Only sources you're connected to are shown — leave all off to keep current behavior.</small>
<div class="hybrid-source-list" id="art-source-list"></div> <div class="hybrid-source-list" id="art-source-list"></div>
</div> </div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" id="single-to-album-enabled">
Match singles to their parent album
</label>
<small class="settings-hint">When a track matches a single release, look up the album that contains it and tag it as that album — so every song in an album gets the same (album) cover instead of some getting the single's art. Off by default: adds an extra metadata lookup per single-matched track.</small>
</div>
<div class="form-group"> <div class="form-group">
<label class="checkbox-label"> <label class="checkbox-label">
<input type="checkbox" id="lrclib-enabled" checked> <input type="checkbox" id="lrclib-enabled" checked>

View file

@ -1235,6 +1235,7 @@ async function loadSettingsData() {
document.getElementById('embed-album-art').checked = settings.metadata_enhancement?.embed_album_art !== false; document.getElementById('embed-album-art').checked = settings.metadata_enhancement?.embed_album_art !== false;
document.getElementById('cover-art-download').checked = settings.metadata_enhancement?.cover_art_download !== false; 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('prefer-caa-art').checked = settings.metadata_enhancement?.prefer_caa_art === true;
document.getElementById('single-to-album-enabled').checked = settings.metadata_enhancement?.single_to_album === true;
document.getElementById('lrclib-enabled').checked = settings.metadata_enhancement?.lrclib_enabled !== false; document.getElementById('lrclib-enabled').checked = settings.metadata_enhancement?.lrclib_enabled !== false;
document.getElementById('replaygain-enabled').checked = settings.post_processing?.replaygain_enabled === true; document.getElementById('replaygain-enabled').checked = settings.post_processing?.replaygain_enabled === true;
document.getElementById('duration-tolerance-seconds').value = settings.post_processing?.duration_tolerance_seconds ?? 0; document.getElementById('duration-tolerance-seconds').value = settings.post_processing?.duration_tolerance_seconds ?? 0;
@ -3104,6 +3105,7 @@ async function saveSettings(quiet = false) {
cover_art_download: document.getElementById('cover-art-download').checked, cover_art_download: document.getElementById('cover-art-download').checked,
prefer_caa_art: document.getElementById('prefer-caa-art').checked, prefer_caa_art: document.getElementById('prefer-caa-art').checked,
album_art_order: getArtOrder(), album_art_order: getArtOrder(),
single_to_album: document.getElementById('single-to-album-enabled').checked,
lrclib_enabled: document.getElementById('lrclib-enabled').checked, lrclib_enabled: document.getElementById('lrclib-enabled').checked,
tags: { tags: {
quality_tag: _getTagConfig('metadata_enhancement.tags.quality_tag'), quality_tag: _getTagConfig('metadata_enhancement.tags.quality_tag'),