Clarify hybrid source album behavior

Add dynamic level badges to the hybrid source order settings. The first enabled source shows Album-level only when it supports album-bundle downloads; every other source shows Track-level to make fallback behavior visible.

Update the helper copy and badge styling so users can understand why putting Soulseek, Torrent, or Usenet first changes album-download behavior.
This commit is contained in:
Broque Thomas 2026-05-23 15:15:28 -07:00
parent 6c226613bf
commit 94129d3099
3 changed files with 27 additions and 0 deletions

View file

@ -4372,6 +4372,7 @@
<div id="hybrid-settings-container" style="display: none;"> <div id="hybrid-settings-container" style="display: none;">
<div class="setting-help-text"> <div class="setting-help-text">
Drag to reorder source priority. Enable sources you want to use. Downloads try each enabled source in order. Drag to reorder source priority. Enable sources you want to use. Downloads try each enabled source in order.
The first source can use album-level downloads when supported; later sources stay track-level fallback.
</div> </div>
<div class="hybrid-source-list" id="hybrid-source-list"> <div class="hybrid-source-list" id="hybrid-source-list">
<!-- Populated by JS --> <!-- Populated by JS -->

View file

@ -600,6 +600,7 @@ const HYBRID_SOURCES = [
{ id: 'torrent', name: 'Torrent', icon: null, emoji: '🧲' }, { id: 'torrent', name: 'Torrent', icon: null, emoji: '🧲' },
{ id: 'usenet', name: 'Usenet', icon: null, emoji: '📰' }, { id: 'usenet', name: 'Usenet', icon: null, emoji: '📰' },
]; ];
const ALBUM_LEVEL_HYBRID_SOURCES = new Set(['soulseek', 'torrent', 'usenet']);
let _hybridSourceOrder = ['soulseek', 'youtube']; let _hybridSourceOrder = ['soulseek', 'youtube'];
let _hybridSourceEnabled = { soulseek: true, youtube: true, tidal: false, qobuz: false, hifi: false, deezer_dl: false, amazon: false, lidarr: false, soundcloud: false, torrent: false, usenet: false }; let _hybridSourceEnabled = { soulseek: true, youtube: true, tidal: false, qobuz: false, hifi: false, deezer_dl: false, amazon: false, lidarr: false, soundcloud: false, torrent: false, usenet: false };
@ -625,6 +626,13 @@ function buildHybridSourceList() {
const enabled = _hybridSourceEnabled[srcId] !== false; const enabled = _hybridSourceEnabled[srcId] !== false;
const isInOrder = _hybridSourceOrder.includes(srcId); const isInOrder = _hybridSourceOrder.includes(srcId);
const priorityNum = isInOrder && enabled ? _hybridSourceOrder.indexOf(srcId) + 1 : ''; const priorityNum = isInOrder && enabled ? _hybridSourceOrder.indexOf(srcId) + 1 : '';
const canOwnAlbum = enabled && priorityNum === 1 && ALBUM_LEVEL_HYBRID_SOURCES.has(srcId);
const sourceLevel = canOwnAlbum ? 'Album-level' : 'Track-level';
const sourceLevelClass = canOwnAlbum ? 'album' : 'track';
const sourceLevelTitle = canOwnAlbum
? 'This first source can download a whole album release before per-track fallback.'
: 'This source runs as per-track fallback in the current hybrid order.';
const sourceLevelBadge = `<span class="hybrid-source-badge hybrid-source-badge-${sourceLevelClass}" title="${sourceLevelTitle}">${sourceLevel}</span>`;
const item = document.createElement('div'); const item = document.createElement('div');
item.className = `hybrid-source-item${enabled ? '' : ' disabled'}`; item.className = `hybrid-source-item${enabled ? '' : ' disabled'}`;
@ -641,6 +649,7 @@ function buildHybridSourceList() {
: `<span class="hybrid-source-icon emoji-icon">${src.emoji}</span>` : `<span class="hybrid-source-icon emoji-icon">${src.emoji}</span>`
} }
<span class="hybrid-source-name">${src.name}</span> <span class="hybrid-source-name">${src.name}</span>
${sourceLevelBadge}
<span class="hybrid-source-priority">${priorityNum}</span> <span class="hybrid-source-priority">${priorityNum}</span>
<label class="hybrid-source-toggle"> <label class="hybrid-source-toggle">
<input type="checkbox" ${enabled ? 'checked' : ''} onchange="toggleHybridSource('${srcId}', this.checked)"> <input type="checkbox" ${enabled ? 'checked' : ''} onchange="toggleHybridSource('${srcId}', this.checked)">

View file

@ -52933,6 +52933,23 @@ tr.tag-diff-same {
color: rgba(255, 255, 255, 0.85); color: rgba(255, 255, 255, 0.85);
font-weight: 500; font-weight: 500;
} }
.hybrid-source-badge {
flex-shrink: 0;
font-size: 0.68em;
line-height: 1;
font-weight: 700;
letter-spacing: 0.01em;
padding: 4px 7px;
border-radius: 6px;
border: 1px solid rgba(125, 211, 252, 0.24);
background: rgba(125, 211, 252, 0.1);
color: #7dd3fc;
}
.hybrid-source-badge-track {
border-color: rgba(255, 255, 255, 0.12);
background: rgba(255, 255, 255, 0.05);
color: rgba(255, 255, 255, 0.48);
}
.hybrid-source-priority { .hybrid-source-priority {
font-size: 0.75em; font-size: 0.75em;
color: rgba(255, 255, 255, 0.3); color: rgba(255, 255, 255, 0.3);