fix(downloads): unverified review actions always load + show real quality on completed
Unverified review actions (play/audit/approve/delete) only rendered for persistent-history rows, so a freshly-completed unverified download — still a live task without a 'history-<id>' task_id — showed no buttons until it aged into history (Quarantine always worked because it uses the quarantine entry id). Thread the library_history row id from import through to the live task (add_library_history_entry now returns lastrowid -> context._history_id -> task.history_id -> /api/downloads/all), and resolve verifHistoryId from it. Also surface the real probed audio quality (mutagen-read from the file, e.g. 'FLAC 24bit') on completed rows as a chip, so you can see what was actually downloaded. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
975cf4cf3d
commit
62d5821d26
6 changed files with 43 additions and 6 deletions
|
|
@ -796,6 +796,13 @@ def build_unified_downloads_response(limit: int, deps: StatusDeps) -> dict:
|
|||
'progress': progress,
|
||||
'error': task.get('error_message'),
|
||||
'verification_status': task.get('verification_status'),
|
||||
# library_history row id (set at import) so the Unverified review
|
||||
# queue can act on a still-live completed task before it becomes
|
||||
# a persistent-history row.
|
||||
'history_id': task.get('history_id'),
|
||||
# Real probed audio quality (mutagen-read from the actual file),
|
||||
# surfaced so the Downloads page can show what was downloaded.
|
||||
'quality': task.get('quality') or '',
|
||||
'retry_info': task.get('retry_info'),
|
||||
'retry_trigger': task.get('retry_trigger'),
|
||||
'batch_id': batch_id,
|
||||
|
|
|
|||
|
|
@ -1157,6 +1157,10 @@ def post_process_matched_download_with_verification(context_key, context, file_p
|
|||
_mark_task_completed(task_id, context.get('track_info'))
|
||||
if context.get('_verification_status'):
|
||||
download_tasks[task_id]['verification_status'] = context['_verification_status']
|
||||
if context.get('_history_id'):
|
||||
download_tasks[task_id]['history_id'] = context['_history_id']
|
||||
if context.get('_audio_quality'):
|
||||
download_tasks[task_id]['quality'] = context['_audio_quality']
|
||||
with matched_context_lock:
|
||||
if context_key in matched_downloads_context:
|
||||
del matched_downloads_context[context_key]
|
||||
|
|
@ -1171,6 +1175,10 @@ def post_process_matched_download_with_verification(context_key, context, file_p
|
|||
download_tasks[task_id]['metadata_enhanced'] = True
|
||||
if context.get('_verification_status'):
|
||||
download_tasks[task_id]['verification_status'] = context['_verification_status']
|
||||
if context.get('_history_id'):
|
||||
download_tasks[task_id]['history_id'] = context['_history_id']
|
||||
if context.get('_audio_quality'):
|
||||
download_tasks[task_id]['quality'] = context['_audio_quality']
|
||||
redownload_ctx = download_tasks[task_id].get('_redownload_context')
|
||||
|
||||
with matched_context_lock:
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ def record_library_history_download(context: Dict[str, Any]) -> None:
|
|||
origin, origin_context = derive_download_origin(context)
|
||||
|
||||
db = get_database()
|
||||
db.add_library_history_entry(
|
||||
_history_id = db.add_library_history_entry(
|
||||
event_type="download",
|
||||
title=title,
|
||||
artist_name=artist_name,
|
||||
|
|
@ -270,6 +270,10 @@ def record_library_history_download(context: Dict[str, Any]) -> None:
|
|||
origin_context=origin_context,
|
||||
verification_status=context.get("_verification_status"),
|
||||
)
|
||||
# Stash the row id so the live download task can link to its
|
||||
# library_history row (the Unverified review queue needs it).
|
||||
if isinstance(_history_id, int) and _history_id > 0:
|
||||
context["_history_id"] = _history_id
|
||||
except Exception as e:
|
||||
logger.debug("library history record failed: %s", e)
|
||||
|
||||
|
|
|
|||
|
|
@ -13062,7 +13062,10 @@ class MusicDatabase:
|
|||
download_source, source_track_id, source_track_title, source_filename,
|
||||
acoustid_result, source_artist, origin, origin_context, verification_status))
|
||||
conn.commit()
|
||||
return True
|
||||
# Return the new row id (truthy on success) so callers can link the
|
||||
# live download task to its library_history row — e.g. the Unverified
|
||||
# review queue needs the id for its play/approve/delete actions.
|
||||
return cursor.lastrowid
|
||||
except Exception as e:
|
||||
logger.debug(f"Error adding library history entry: {e}")
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -2430,6 +2430,14 @@ function _updateDlNavBadge(count) {
|
|||
}
|
||||
}
|
||||
|
||||
function _adlQualityBadge(dl) {
|
||||
// Show the real audio quality of a completed download (probed from the
|
||||
// file itself — FLAC bit depth, MP3 bitrate, …), so you can see at a
|
||||
// glance what was actually fetched.
|
||||
if (dl.status !== 'completed' || !dl.quality) return '';
|
||||
return ` <span class="adl-quality-chip" title="Audio quality of the downloaded file (read from the file itself)">${_adlEsc(dl.quality)}</span>`;
|
||||
}
|
||||
|
||||
function _adlVerifBadge(dl) {
|
||||
// Verification badge for completed downloads — how this file passed
|
||||
// verification (status comes from library_history / the live task):
|
||||
|
|
@ -2457,9 +2465,15 @@ function _adlVerifBadge(dl) {
|
|||
|
||||
function verifHistoryId(dl) {
|
||||
// Persistent history rows carry task_id 'history-<dbid>'.
|
||||
if (!dl.is_persistent_history || !dl.task_id) return null;
|
||||
const m = String(dl.task_id).match(/^history-(\d+)$/);
|
||||
return m ? m[1] : null;
|
||||
if (dl.is_persistent_history && dl.task_id) {
|
||||
const m = String(dl.task_id).match(/^history-(\d+)$/);
|
||||
if (m) return m[1];
|
||||
}
|
||||
// Still-live completed tasks carry the library_history id directly, so the
|
||||
// review actions (play/audit/approve/delete) work before the task becomes
|
||||
// a persistent-history row — otherwise the buttons "didn't always load".
|
||||
if (dl.history_id) return String(dl.history_id);
|
||||
return null;
|
||||
}
|
||||
|
||||
function _verifTimeAgo(iso) {
|
||||
|
|
@ -3132,7 +3146,7 @@ function _adlRender() {
|
|||
</div>
|
||||
<div class="adl-row-status ${statusClass}">
|
||||
<span class="adl-status-dot ${statusClass}"></span>
|
||||
${statusLabel}${_adlVerifBadge(dl)}${dl.retry_info && (statusClass === 'active' || statusClass === 'queued') ? ` <span class="adl-retry-info" title="Retry engine: trying the next-best candidate (attempt ${_adlEsc(String(dl.retry_info))}${dl.retry_trigger ? ', triggered by ' + _adlEsc(dl.retry_trigger) : ''})">🔁 ${_adlEsc(String(dl.retry_info))}</span>` : ''}
|
||||
${statusLabel}${_adlVerifBadge(dl)}${_adlQualityBadge(dl)}${dl.retry_info && (statusClass === 'active' || statusClass === 'queued') ? ` <span class="adl-retry-info" title="Retry engine: trying the next-best candidate (attempt ${_adlEsc(String(dl.retry_info))}${dl.retry_trigger ? ', triggered by ' + _adlEsc(dl.retry_trigger) : ''})">🔁 ${_adlEsc(String(dl.retry_info))}</span>` : ''}
|
||||
</div>
|
||||
${_adlReviewActions(dl)}
|
||||
${cancelBtnHtml}
|
||||
|
|
|
|||
|
|
@ -68092,6 +68092,7 @@ body.em-scroll-lock { overflow: hidden; }
|
|||
.verif-badge.verif-unverified { color: #f1c40f; background: rgba(241,196,15,0.14); }
|
||||
.verif-badge.verif-force { color: #e67e22; background: rgba(230,126,34,0.16); }
|
||||
.adl-retry-info { margin-left: 6px; font-size: 11px; color: #e67e22; cursor: help; }
|
||||
.adl-quality-chip { display: inline-block; margin-left: 6px; font-size: 10px; font-weight: 600; letter-spacing: 0.02em; color: rgba(255,255,255,0.78); background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.12); border-radius: 6px; padding: 0 6px; line-height: 16px; cursor: help; vertical-align: middle; }
|
||||
.verif-badge.verif-human { color: #3498db; background: rgba(52,152,219,0.14); }
|
||||
.verif-actions { display: inline-flex; gap: 6px; margin-left: 10px; align-items: center; }
|
||||
.verif-act { border: 1px solid rgba(255,255,255,0.18); background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.85); border-radius: 6px; padding: 2px 8px; font-size: 12px; cursor: pointer; line-height: 18px; }
|
||||
|
|
|
|||
Loading…
Reference in a new issue