feat(quality): derive per-source download tier from the global profile
Remove the per-source download-quality dropdowns (Tidal/HiFi/Qobuz/Deezer/
Amazon) — with the global ranked-targets system they were redundant and
conflicting. Add quality_tier_for_source(): picks the LOWEST source tier
that satisfies the user's top target (respects the quality ceiling, saves
bandwidth) or the source's max as best effort. Every source's search +
download + retry path now derives its tier from the global profile instead
of config_manager.get('<source>_download.quality').
Settings keep the per-source allow_fallback toggles; the quality selects are
replaced with a note pointing at Quality Profile.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
6046a814cb
commit
fe78a3cdc3
11 changed files with 154 additions and 61 deletions
|
|
@ -33,6 +33,7 @@ from core.amazon_client import AmazonClient, AmazonClientError
|
|||
from core.download_plugins.base import DownloadSourcePlugin
|
||||
from core.download_plugins.types import AlbumResult, DownloadStatus, TrackResult
|
||||
from core.quality.model import AudioQuality
|
||||
from core.quality.source_map import quality_tier_for_source
|
||||
from utils.logging_config import get_logger
|
||||
|
||||
logger = get_logger("amazon_download_client")
|
||||
|
|
@ -79,7 +80,7 @@ class AmazonDownloadClient(DownloadSourcePlugin):
|
|||
self.download_path = Path(download_path)
|
||||
self.download_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
self._quality = config_manager.get("amazon_download.quality", "flac")
|
||||
self._quality = quality_tier_for_source("amazon", default="flac")
|
||||
self._allow_fallback = config_manager.get("amazon_download.allow_fallback", True)
|
||||
|
||||
self._client = AmazonClient(preferred_codec=self._quality)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ from typing import Any, Dict, List, Optional, Tuple
|
|||
import requests
|
||||
|
||||
from core.download_plugins.types import AlbumResult, DownloadStatus, TrackResult
|
||||
from core.quality.source_map import quality_from_deezer
|
||||
from core.quality.source_map import quality_from_deezer, quality_tier_for_source
|
||||
from utils.logging_config import get_logger
|
||||
|
||||
logger = get_logger("deezer_download")
|
||||
|
|
@ -120,7 +120,7 @@ class DeezerDownloadClient(DownloadSourcePlugin):
|
|||
self._authenticated = False
|
||||
|
||||
# Quality preference
|
||||
self._quality = config_manager.get('deezer_download.quality', 'flac')
|
||||
self._quality = quality_tier_for_source('deezer', default='flac')
|
||||
|
||||
# Try to authenticate on init if ARL is configured
|
||||
arl = config_manager.get('deezer_download.arl', '')
|
||||
|
|
|
|||
|
|
@ -102,12 +102,14 @@ class DownloadOrchestrator:
|
|||
deezer_dl = self.client('deezer_dl')
|
||||
if deezer_arl and deezer_dl:
|
||||
deezer_dl.reconnect(deezer_arl)
|
||||
deezer_dl._quality = config_manager.get('deezer_download.quality', 'flac')
|
||||
from core.quality.source_map import quality_tier_for_source
|
||||
deezer_dl._quality = quality_tier_for_source('deezer', default='flac')
|
||||
|
||||
# Reload Amazon quality preference (T2Tunes needs no reconnect — public proxy)
|
||||
amazon = self.client('amazon')
|
||||
if amazon:
|
||||
quality = config_manager.get('amazon_download.quality', 'flac')
|
||||
from core.quality.source_map import quality_tier_for_source
|
||||
quality = quality_tier_for_source('amazon', default='flac')
|
||||
amazon._quality = quality
|
||||
amazon._allow_fallback = config_manager.get('amazon_download.allow_fallback', True)
|
||||
if hasattr(amazon, '_client') and amazon._client:
|
||||
|
|
|
|||
|
|
@ -760,7 +760,8 @@ class WebUIDownloadMonitor:
|
|||
# used_sources keys are formatted as "{username}_{filename}", so startswith is exact.
|
||||
is_tidal = any(s.startswith('tidal_') for s in tried_sources)
|
||||
if is_tidal:
|
||||
tidal_quality = config_manager.get('tidal_download.quality', 'lossless')
|
||||
from core.quality.source_map import quality_tier_for_source
|
||||
tidal_quality = quality_tier_for_source('tidal', default='lossless')
|
||||
allow_fb = config_manager.get('tidal_download.allow_fallback', True)
|
||||
if tidal_quality == 'hires' and not allow_fb:
|
||||
task['error_message'] = (
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ import requests as http_requests
|
|||
from utils.logging_config import get_logger
|
||||
from config.settings import config_manager
|
||||
from core.download_plugins.types import TrackResult, AlbumResult, DownloadStatus
|
||||
from core.quality.source_map import quality_from_tidal_tier
|
||||
from core.quality.source_map import quality_from_tidal_tier, quality_tier_for_source
|
||||
|
||||
logger = get_logger("hifi_client")
|
||||
|
||||
|
|
@ -752,7 +752,7 @@ class HiFiClient(DownloadSourcePlugin):
|
|||
loop = asyncio.get_event_loop()
|
||||
tracks = await loop.run_in_executor(None, lambda: self.search_raw(query))
|
||||
|
||||
quality_key = config_manager.get('hifi_download.quality', 'lossless')
|
||||
quality_key = quality_tier_for_source('hifi', default='lossless')
|
||||
q_info = HLS_QUALITY_MAP.get(quality_key, HLS_QUALITY_MAP['lossless'])
|
||||
|
||||
# HiFi is Tidal-backed; stamp the configured tier so the global
|
||||
|
|
@ -834,7 +834,7 @@ class HiFiClient(DownloadSourcePlugin):
|
|||
)
|
||||
|
||||
def _download_sync(self, download_id: str, track_id: int, display_name: str) -> Optional[str]:
|
||||
quality_key = config_manager.get('hifi_download.quality', 'lossless')
|
||||
quality_key = quality_tier_for_source('hifi', default='lossless')
|
||||
chain = ['hires', 'lossless', 'high', 'low']
|
||||
start = chain.index(quality_key) if quality_key in chain else 1
|
||||
allow_fallback = config_manager.get('hifi_download.allow_fallback', True)
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ from config.settings import config_manager
|
|||
|
||||
# Import Soulseek data structures for drop-in replacement compatibility
|
||||
from core.download_plugins.types import TrackResult, AlbumResult, DownloadStatus
|
||||
from core.quality.source_map import quality_from_qobuz
|
||||
from core.quality.source_map import quality_from_qobuz, quality_tier_for_source
|
||||
|
||||
logger = get_logger("qobuz_client")
|
||||
|
||||
|
|
@ -988,7 +988,7 @@ class QobuzClient(DownloadSourcePlugin):
|
|||
return ([], [])
|
||||
|
||||
# Get configured quality for display
|
||||
quality_key = config_manager.get('qobuz.quality', 'lossless')
|
||||
quality_key = quality_tier_for_source('qobuz', default='lossless')
|
||||
quality_info = QOBUZ_QUALITY_MAP.get(quality_key, QOBUZ_QUALITY_MAP['lossless'])
|
||||
|
||||
track_results = []
|
||||
|
|
@ -1190,7 +1190,7 @@ class QobuzClient(DownloadSourcePlugin):
|
|||
|
||||
try:
|
||||
# Determine quality
|
||||
quality_key = config_manager.get('qobuz.quality', 'lossless')
|
||||
quality_key = quality_tier_for_source('qobuz', default='lossless')
|
||||
quality_info = QOBUZ_QUALITY_MAP.get(quality_key, QOBUZ_QUALITY_MAP['lossless'])
|
||||
|
||||
# Quality fallback chain: hires_max → hires → lossless → mp3
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ from __future__ import annotations
|
|||
from typing import Optional
|
||||
|
||||
from core.quality.model import AudioQuality
|
||||
from core.quality.selection import load_profile_targets
|
||||
|
||||
|
||||
# ── Tidal / HiFi (Monochrome is Tidal-backed) ──────────────────────────────
|
||||
|
|
@ -102,3 +103,66 @@ def quality_from_amazon(
|
|||
sample_rate=sample_rate if sample_rate is not None else base.sample_rate,
|
||||
bit_depth=bit_depth if bit_depth is not None else base.bit_depth,
|
||||
)
|
||||
|
||||
|
||||
# ── Profile-driven download tier (replaces per-source quality settings) ─────
|
||||
#
|
||||
# Each source's selectable download tiers, ordered best → worst, with the
|
||||
# AudioQuality the tier delivers. ``quality_tier_for_source`` walks these to
|
||||
# request the LOWEST tier that satisfies the user's top global target — so the
|
||||
# global quality profile, not a per-source dropdown, decides what each source
|
||||
# fetches.
|
||||
|
||||
_SOURCE_TIER_LADDERS: dict[str, list[tuple[str, AudioQuality]]] = {
|
||||
'tidal': [
|
||||
('hires', AudioQuality('flac', sample_rate=96000, bit_depth=24)),
|
||||
('lossless', AudioQuality('flac', sample_rate=44100, bit_depth=16)),
|
||||
('high', AudioQuality('aac', bitrate=320)),
|
||||
('low', AudioQuality('aac', bitrate=96)),
|
||||
],
|
||||
'hifi': [
|
||||
('hires', AudioQuality('flac', sample_rate=96000, bit_depth=24)),
|
||||
('lossless', AudioQuality('flac', sample_rate=44100, bit_depth=16)),
|
||||
('high', AudioQuality('aac', bitrate=320)),
|
||||
('low', AudioQuality('aac', bitrate=96)),
|
||||
],
|
||||
'qobuz': [
|
||||
('hires_max', AudioQuality('flac', sample_rate=192000, bit_depth=24)),
|
||||
('hires', AudioQuality('flac', sample_rate=96000, bit_depth=24)),
|
||||
('lossless', AudioQuality('flac', sample_rate=44100, bit_depth=16)),
|
||||
('mp3', AudioQuality('mp3', bitrate=320)),
|
||||
],
|
||||
'deezer': [
|
||||
('flac', AudioQuality('flac', sample_rate=44100, bit_depth=16)),
|
||||
('mp3_320', AudioQuality('mp3', bitrate=320)),
|
||||
('mp3_128', AudioQuality('mp3', bitrate=128)),
|
||||
],
|
||||
'amazon': [
|
||||
('flac', AudioQuality('flac', sample_rate=48000, bit_depth=24)),
|
||||
('opus', AudioQuality('aac', bitrate=320)),
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def quality_tier_for_source(source_name: str, *, default: Optional[str] = None) -> Optional[str]:
|
||||
"""Return the source tier key to request, derived from the global profile.
|
||||
|
||||
Picks the lowest tier in the source's ladder that satisfies the user's
|
||||
top (most-preferred) target — respecting the quality ceiling and saving
|
||||
bandwidth. Falls back to the source's max tier when none can satisfy it
|
||||
(best effort), or to the source's max when no targets are configured.
|
||||
Returns *default* for an unknown source.
|
||||
"""
|
||||
ladder = _SOURCE_TIER_LADDERS.get(source_name)
|
||||
if not ladder:
|
||||
return default
|
||||
|
||||
targets, _ = load_profile_targets()
|
||||
if not targets:
|
||||
return ladder[0][0]
|
||||
|
||||
top = targets[0]
|
||||
for key, aq in reversed(ladder): # low → high
|
||||
if aq.matches_target(top):
|
||||
return key
|
||||
return ladder[0][0] # best effort: max tier
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ from config.settings import config_manager
|
|||
|
||||
# Import Soulseek data structures for drop-in replacement compatibility
|
||||
from core.download_plugins.types import TrackResult, AlbumResult, DownloadStatus
|
||||
from core.quality.source_map import quality_from_tidal_tier
|
||||
from core.quality.source_map import quality_from_tidal_tier, quality_tier_for_source
|
||||
|
||||
logger = get_logger("tidal_download_client")
|
||||
|
||||
|
|
@ -456,7 +456,7 @@ class TidalDownloadClient(DownloadSourcePlugin):
|
|||
if successful_query and successful_query != query:
|
||||
logger.info(f"Tidal fallback query succeeded: '{successful_query}' (original: '{query}')")
|
||||
|
||||
quality_key = config_manager.get('tidal_download.quality', 'lossless')
|
||||
quality_key = quality_tier_for_source('tidal', default='lossless')
|
||||
quality_info = QUALITY_MAP.get(quality_key, QUALITY_MAP['lossless'])
|
||||
# Stamp the configured tier (what will actually be downloaded) so
|
||||
# the global ranker sees real sample_rate/bit_depth.
|
||||
|
|
@ -779,7 +779,7 @@ class TidalDownloadClient(DownloadSourcePlugin):
|
|||
logger.error("Tidal session not authenticated")
|
||||
return None
|
||||
|
||||
quality_key = config_manager.get('tidal_download.quality', 'lossless')
|
||||
quality_key = quality_tier_for_source('tidal', default='lossless')
|
||||
chain = ['hires', 'lossless', 'high', 'low']
|
||||
start = chain.index(quality_key) if quality_key in chain else 1
|
||||
allow_fallback = config_manager.get('tidal_download.allow_fallback', True)
|
||||
|
|
|
|||
62
tests/quality/test_source_tier.py
Normal file
62
tests/quality/test_source_tier.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
"""quality_tier_for_source — derive a source's requested download tier from
|
||||
the GLOBAL quality profile instead of a per-source setting.
|
||||
|
||||
Rule: pick the LOWEST source tier that satisfies the user's top (most
|
||||
preferred) target — respecting the user's quality ceiling and saving
|
||||
bandwidth — or the source's max tier when none can satisfy it (best effort).
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
import core.quality.source_map as sm
|
||||
from core.quality.model import QualityTarget
|
||||
|
||||
|
||||
def _patch_targets(monkeypatch, targets, fallback=True):
|
||||
monkeypatch.setattr(sm, 'load_profile_targets', lambda: (targets, fallback))
|
||||
|
||||
|
||||
T_FLAC24_96 = [QualityTarget(label='', format='flac', bit_depth=24, min_sample_rate=96000)]
|
||||
T_FLAC24_192 = [QualityTarget(label='', format='flac', bit_depth=24, min_sample_rate=192000)]
|
||||
T_FLAC16 = [QualityTarget(label='', format='flac', bit_depth=16)]
|
||||
T_MP3_320 = [QualityTarget(label='', format='mp3', min_bitrate=320)]
|
||||
|
||||
|
||||
def test_tidal_hires_when_top_wants_24_96(monkeypatch):
|
||||
_patch_targets(monkeypatch, T_FLAC24_96)
|
||||
assert sm.quality_tier_for_source('tidal') == 'hires'
|
||||
|
||||
|
||||
def test_tidal_lossless_respects_16bit_ceiling(monkeypatch):
|
||||
# User caps at 16-bit → request lossless, NOT hires (saves bandwidth).
|
||||
_patch_targets(monkeypatch, T_FLAC16)
|
||||
assert sm.quality_tier_for_source('tidal') == 'lossless'
|
||||
|
||||
|
||||
def test_tidal_best_effort_max_when_unsatisfiable(monkeypatch):
|
||||
# Source maxes at 24/96 but user wants 24/192 → best effort = max tier.
|
||||
_patch_targets(monkeypatch, T_FLAC24_192)
|
||||
assert sm.quality_tier_for_source('tidal') == 'hires'
|
||||
|
||||
|
||||
def test_no_targets_requests_max(monkeypatch):
|
||||
_patch_targets(monkeypatch, [])
|
||||
assert sm.quality_tier_for_source('tidal') == 'hires'
|
||||
assert sm.quality_tier_for_source('deezer') == 'flac'
|
||||
|
||||
|
||||
def test_deezer_flac_and_mp3(monkeypatch):
|
||||
_patch_targets(monkeypatch, T_FLAC16)
|
||||
assert sm.quality_tier_for_source('deezer') == 'flac'
|
||||
_patch_targets(monkeypatch, T_MP3_320)
|
||||
assert sm.quality_tier_for_source('deezer') == 'mp3_320'
|
||||
|
||||
|
||||
def test_qobuz_hires_max(monkeypatch):
|
||||
_patch_targets(monkeypatch, T_FLAC24_192)
|
||||
assert sm.quality_tier_for_source('qobuz') == 'hires_max'
|
||||
|
||||
|
||||
def test_unknown_source_returns_default(monkeypatch):
|
||||
_patch_targets(monkeypatch, T_FLAC16)
|
||||
assert sm.quality_tier_for_source('nope', default='x') == 'x'
|
||||
|
|
@ -4740,21 +4740,15 @@
|
|||
<div id="tidal-download-settings-container" style="display: none;">
|
||||
<div class="form-group">
|
||||
<label>Tidal Download Quality:</label>
|
||||
<select id="tidal-download-quality" class="form-select">
|
||||
<option value="low">Low (AAC 96kbps)</option>
|
||||
<option value="high">High (AAC 320kbps)</option>
|
||||
<option value="lossless">Lossless (FLAC 16-bit/44.1kHz)</option>
|
||||
<option value="hires">HiRes (FLAC 24-bit/96kHz)</option>
|
||||
</select>
|
||||
<div class="setting-help-text">
|
||||
Audio quality for Tidal downloads. HiRes requires a Tidal HiFi Plus subscription.
|
||||
Quality is set globally in <strong>Quality Profile</strong> (ranked targets) — Tidal fetches the highest tier your profile accepts.
|
||||
</div>
|
||||
<label class="checkbox-inline" style="margin-top: 8px;">
|
||||
<input type="checkbox" id="tidal-allow-fallback" checked>
|
||||
Allow quality fallback
|
||||
</label>
|
||||
<div class="setting-help-text">
|
||||
When disabled, only downloads at the exact quality selected. If unavailable, skips to the next source.
|
||||
When disabled, only downloads at the exact derived quality. If unavailable, skips to the next source.
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
|
|
@ -4774,14 +4768,8 @@
|
|||
<div id="qobuz-settings-container" style="display: none;">
|
||||
<div class="form-group">
|
||||
<label>Qobuz Download Quality:</label>
|
||||
<select id="qobuz-quality" class="form-select">
|
||||
<option value="mp3">MP3 320kbps</option>
|
||||
<option value="lossless">Lossless (FLAC 16-bit/44.1kHz)</option>
|
||||
<option value="hires">Hi-Res (FLAC 24-bit/96kHz)</option>
|
||||
<option value="hires_max">Hi-Res Max (FLAC 24-bit/192kHz)</option>
|
||||
</select>
|
||||
<div class="setting-help-text">
|
||||
Audio quality for Qobuz downloads. Hi-Res requires a Qobuz Studio or Sublime subscription.
|
||||
Quality is set globally in <strong>Quality Profile</strong> (ranked targets) — Qobuz fetches the highest tier your profile accepts. Hi-Res requires a Qobuz Studio or Sublime subscription.
|
||||
</div>
|
||||
<label class="checkbox-inline" style="margin-top: 8px;">
|
||||
<input type="checkbox" id="qobuz-allow-fallback" checked>
|
||||
|
|
@ -4840,14 +4828,8 @@
|
|||
<div id="hifi-download-settings-container" style="display: none;">
|
||||
<div class="form-group">
|
||||
<label>HiFi Download Quality:</label>
|
||||
<select id="hifi-download-quality" class="form-select">
|
||||
<option value="low">Low (AAC 96kbps)</option>
|
||||
<option value="high">High (AAC 320kbps)</option>
|
||||
<option value="lossless">Lossless (FLAC 16-bit/44.1kHz)</option>
|
||||
<option value="hires">HiRes (FLAC 24-bit/96kHz)</option>
|
||||
</select>
|
||||
<div class="setting-help-text">
|
||||
Audio quality for HiFi downloads. Uses public API instances — no account required.
|
||||
Quality is set globally in <strong>Quality Profile</strong> (ranked targets) — HiFi fetches the highest tier your profile accepts. Uses public API instances — no account required.
|
||||
</div>
|
||||
<label class="checkbox-inline" style="margin-top: 8px;">
|
||||
<input type="checkbox" id="hifi-allow-fallback" checked>
|
||||
|
|
@ -4888,14 +4870,8 @@
|
|||
<div id="deezer-download-settings-container" style="display: none;">
|
||||
<div class="form-group">
|
||||
<label>Deezer Download Quality:</label>
|
||||
<select id="deezer-download-quality" class="form-select">
|
||||
<option value="mp3_128">MP3 128kbps (Free)</option>
|
||||
<option value="mp3_320">MP3 320kbps (Premium)</option>
|
||||
<option value="flac">FLAC Lossless (HiFi)</option>
|
||||
</select>
|
||||
<div class="setting-help-text">
|
||||
Audio quality for Deezer downloads. FLAC requires a Deezer HiFi subscription.
|
||||
MP3 320 requires Premium or higher.
|
||||
Quality is set globally in <strong>Quality Profile</strong> (ranked targets) — Deezer fetches the highest tier your profile accepts. FLAC requires a Deezer HiFi subscription.
|
||||
</div>
|
||||
<label class="checkbox-inline" style="margin-top: 8px;">
|
||||
<input type="checkbox" id="deezer-allow-fallback" checked>
|
||||
|
|
@ -4930,14 +4906,8 @@
|
|||
<div id="amazon-download-settings-container" style="display: none;">
|
||||
<div class="form-group">
|
||||
<label>Amazon Music Quality:</label>
|
||||
<select id="amazon-quality" class="form-select">
|
||||
<option value="flac">FLAC Lossless (24-bit/48kHz Hi-Res)</option>
|
||||
<option value="opus">Opus (320kbps)</option>
|
||||
<option value="eac3">EAC3 Dolby Atmos (768kbps 5.1)</option>
|
||||
</select>
|
||||
<div class="setting-help-text">
|
||||
Preferred codec tier. FLAC is 24-bit/48kHz Hi-Res — no subscription required.
|
||||
Downloads via T2Tunes proxy.
|
||||
Quality is set globally in <strong>Quality Profile</strong> (ranked targets) — Amazon fetches FLAC (24-bit/48kHz Hi-Res) when your profile wants lossless, otherwise a lossy tier. Downloads via T2Tunes proxy.
|
||||
</div>
|
||||
<label class="checkbox-inline" style="margin-top: 8px;">
|
||||
<input type="checkbox" id="amazon-allow-fallback" checked>
|
||||
|
|
|
|||
|
|
@ -1138,17 +1138,14 @@ async function loadSettingsData() {
|
|||
document.getElementById('max-concurrent-downloads').value = settings.download_source?.max_concurrent || '3';
|
||||
loadHybridSourceOrder(settings);
|
||||
loadArtSourceOrder(settings);
|
||||
document.getElementById('tidal-download-quality').value = settings.tidal_download?.quality || 'lossless';
|
||||
// Per-source download quality is now derived from the global Quality
|
||||
// Profile (ranked targets) — the per-source quality selects were removed.
|
||||
document.getElementById('tidal-allow-fallback').checked = settings.tidal_download?.allow_fallback !== false;
|
||||
document.getElementById('qobuz-quality').value = settings.qobuz?.quality || 'lossless';
|
||||
document.getElementById('qobuz-allow-fallback').checked = settings.qobuz?.allow_fallback !== false;
|
||||
document.getElementById('hifi-download-quality').value = settings.hifi_download?.quality || 'lossless';
|
||||
document.getElementById('hifi-allow-fallback').checked = settings.hifi_download?.allow_fallback !== false;
|
||||
loadHiFiInstances();
|
||||
document.getElementById('deezer-download-quality').value = settings.deezer_download?.quality || 'flac';
|
||||
document.getElementById('deezer-allow-fallback').checked = settings.deezer_download?.allow_fallback !== false;
|
||||
document.getElementById('deezer-download-arl').value = settings.deezer_download?.arl || '';
|
||||
document.getElementById('amazon-quality').value = settings.amazon_download?.quality || 'flac';
|
||||
document.getElementById('amazon-allow-fallback').checked = settings.amazon_download?.allow_fallback !== false;
|
||||
document.getElementById('lidarr-url').value = settings.lidarr_download?.url || '';
|
||||
document.getElementById('lidarr-api-key').value = settings.lidarr_download?.api_key || '';
|
||||
|
|
@ -2946,11 +2943,10 @@ async function saveSettings(quiet = false) {
|
|||
usenet_download_path: document.getElementById('usenet-download-path')?.value || '',
|
||||
},
|
||||
tidal_download: {
|
||||
quality: document.getElementById('tidal-download-quality').value || 'lossless',
|
||||
// quality derived from the global Quality Profile (ranked targets)
|
||||
allow_fallback: document.getElementById('tidal-allow-fallback').checked,
|
||||
},
|
||||
hifi_download: {
|
||||
quality: document.getElementById('hifi-download-quality').value || 'lossless',
|
||||
allow_fallback: document.getElementById('hifi-allow-fallback').checked,
|
||||
},
|
||||
hifi: {
|
||||
|
|
@ -2958,12 +2954,10 @@ async function saveSettings(quiet = false) {
|
|||
tags: _collectServiceTags('hifi')
|
||||
},
|
||||
deezer_download: {
|
||||
quality: document.getElementById('deezer-download-quality').value || 'flac',
|
||||
arl: document.getElementById('deezer-download-arl').value || '',
|
||||
allow_fallback: document.getElementById('deezer-allow-fallback').checked,
|
||||
},
|
||||
amazon_download: {
|
||||
quality: document.getElementById('amazon-quality').value || 'flac',
|
||||
allow_fallback: document.getElementById('amazon-allow-fallback').checked,
|
||||
},
|
||||
lidarr_download: {
|
||||
|
|
@ -2997,7 +2991,6 @@ async function saveSettings(quiet = false) {
|
|||
// to migrate existing configs.
|
||||
},
|
||||
qobuz: {
|
||||
quality: document.getElementById('qobuz-quality').value || 'lossless',
|
||||
embed_tags: document.getElementById('embed-qobuz').checked,
|
||||
tags: _collectServiceTags('qobuz'),
|
||||
allow_fallback: document.getElementById('qobuz-allow-fallback').checked,
|
||||
|
|
|
|||
Loading…
Reference in a new issue