fix(repair-jobs): boolean settings saved as string 'true'/'false' by UI dropdown
HTML <select> options can only store string values, so setting_options booleans ([True, False]) were serialised as 'true'/'false' strings and sent to the API. Python's `x is True` check returned False for the string, making require_top_target and deep_audio_verify permanently read as False regardless of what the user saved. Fix JS: convert 'true'/'false' strings to real booleans before POSTing. Fix Python: _to_bool() in quality_upgrade + inline coercion in scanner to handle both existing string values in config and correct future booleans. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
94637cbe6f
commit
ff12d8bbf2
3 changed files with 19 additions and 3 deletions
|
|
@ -50,6 +50,15 @@ from utils.logging_config import get_logger
|
|||
logger = get_logger("repair_jobs.quality_upgrade")
|
||||
|
||||
|
||||
def _to_bool(val) -> bool:
|
||||
"""Coerce a setting value to bool. Handles Python bool, string 'true'/'false', and int."""
|
||||
if isinstance(val, bool):
|
||||
return val
|
||||
if isinstance(val, str):
|
||||
return val.lower() == 'true'
|
||||
return bool(val) if val is not None else False
|
||||
|
||||
|
||||
# Quality ranks — higher is better. Lossless tops everything; lossy tiers fall out
|
||||
# of bitrate. 0 means "below the lowest tracked tier / unknown".
|
||||
RANK_LOSSLESS = 4
|
||||
|
|
@ -494,8 +503,8 @@ class QualityUpgradeJob(RepairJob):
|
|||
merged['min_confidence'] = float(merged.get('min_confidence', 0.7))
|
||||
except (TypeError, ValueError):
|
||||
merged['min_confidence'] = 0.7
|
||||
merged['deep_audio_verify'] = merged.get('deep_audio_verify') is True
|
||||
merged['require_top_target'] = merged.get('require_top_target') is True
|
||||
merged['deep_audio_verify'] = _to_bool(merged.get('deep_audio_verify'))
|
||||
merged['require_top_target'] = _to_bool(merged.get('require_top_target'))
|
||||
return merged
|
||||
|
||||
def _load_tracks(self, db: Any, scope: str) -> List[dict]:
|
||||
|
|
|
|||
|
|
@ -297,6 +297,10 @@ class QualityUpgradeScannerJob(RepairJob):
|
|||
merged.update(cfg)
|
||||
except Exception as e:
|
||||
logger.debug("settings read failed: %s", e)
|
||||
for key in ('library_tracks_only', 'deep_audio_verify', 'require_top_target'):
|
||||
val = merged.get(key)
|
||||
if not isinstance(val, bool):
|
||||
merged[key] = str(val).lower() == 'true' if val is not None else False
|
||||
return merged
|
||||
|
||||
def _collect_music_dirs(self, context: JobContext) -> list:
|
||||
|
|
|
|||
|
|
@ -1988,7 +1988,10 @@ async function saveRepairJobSettings(jobId) {
|
|||
} else {
|
||||
if (input.type === 'checkbox') settings[key] = input.checked;
|
||||
else if (input.type === 'number') settings[key] = parseFloat(input.value);
|
||||
else settings[key] = input.value;
|
||||
else {
|
||||
const v = input.value;
|
||||
settings[key] = v === 'true' ? true : v === 'false' ? false : v;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue