Clarify persisted Meteor decode failures

This commit is contained in:
James Smith
2026-03-18 22:23:09 +00:00
parent 2a9c98a83d
commit a995fceb8c

View File

@@ -1820,31 +1820,34 @@ const WeatherSat = (function() {
const captureStatus = document.getElementById('wxsatCaptureStatus'); const captureStatus = document.getElementById('wxsatCaptureStatus');
const captureMsg = document.getElementById('wxsatCaptureMsg'); const captureMsg = document.getElementById('wxsatCaptureMsg');
const captureElapsed = document.getElementById('wxsatCaptureElapsed'); const captureElapsed = document.getElementById('wxsatCaptureElapsed');
const summary = formatDecodeJobSummary(job, details);
if (!isRunning) { if (!isRunning) {
if (job.status === 'queued') { if (job.status === 'queued') {
updateStatusUI('idle', 'Decode queued'); updateStatusUI('idle', 'Decode queued');
if (captureMsg) captureMsg.textContent = 'Ground-station decode queued'; if (captureMsg) captureMsg.textContent = summary;
if (captureElapsed) captureElapsed.textContent = '--'; if (captureElapsed) captureElapsed.textContent = '--';
if (captureStatus) captureStatus.classList.add('active'); if (captureStatus) captureStatus.classList.add('active');
} else if (job.status === 'decoding') { } else if (job.status === 'decoding') {
updateStatusUI('decoding', 'Ground-station decode running'); updateStatusUI('decoding', 'Ground-station decode running');
if (captureMsg) captureMsg.textContent = details.message || 'Ground-station decode in progress'; if (captureMsg) captureMsg.textContent = summary;
if (captureStatus) captureStatus.classList.add('active'); if (captureStatus) captureStatus.classList.add('active');
} else if (job.status === 'failed') { } else if (job.status === 'failed') {
updateStatusUI('idle', 'Last decode failed'); updateStatusUI('idle', 'Last decode failed');
if (captureMsg) captureMsg.textContent = job.error_message || details.message || 'Decode failed'; if (captureMsg) captureMsg.textContent = summary;
if (captureElapsed) captureElapsed.textContent = '--'; if (captureElapsed) captureElapsed.textContent = formatDecodeJobMeta(details);
if (captureStatus) captureStatus.classList.remove('active'); if (captureStatus) captureStatus.classList.remove('active');
if (signature !== lastDecodeJobSignature) { if (signature !== lastDecodeJobSignature) {
showConsole(true); showConsole(true);
addConsoleEntry(job.error_message || details.message || 'Last decode failed', 'error'); addConsoleEntry(summary, 'error');
const context = formatDecodeJobContext(details);
if (context) addConsoleEntry(context, 'warning');
} }
} else if (job.status === 'complete') { } else if (job.status === 'complete') {
const count = details.output_count; const count = details.output_count;
updateStatusUI('idle', count ? `Last decode: ${count} image${count === 1 ? '' : 's'}` : 'Last decode complete'); updateStatusUI('idle', count ? `Last decode: ${count} image${count === 1 ? '' : 's'}` : 'Last decode complete');
if (captureMsg) captureMsg.textContent = details.message || 'Ground-station decode complete'; if (captureMsg) captureMsg.textContent = summary;
if (captureElapsed) captureElapsed.textContent = '--'; if (captureElapsed) captureElapsed.textContent = formatDecodeJobMeta(details);
if (captureStatus) captureStatus.classList.remove('active'); if (captureStatus) captureStatus.classList.remove('active');
if (signature !== lastDecodeJobSignature) { if (signature !== lastDecodeJobSignature) {
addConsoleEntry( addConsoleEntry(
@@ -1862,6 +1865,48 @@ const WeatherSat = (function() {
} }
} }
function formatDecodeJobSummary(job, details) {
if (job.status === 'queued') return 'Ground-station decode queued';
if (job.status === 'decoding') return details.message || 'Ground-station decode in progress';
if (job.status === 'complete') {
const count = details.output_count;
return count ? `Ground-station decode complete: ${count} image${count === 1 ? '' : 's'} produced`
: 'Ground-station decode complete';
}
if (job.status === 'failed') {
const reasonLabels = {
sample_rate_too_low: 'Sample rate too low for Meteor LRPT',
invalid_sample_rate: 'Sample rate rejected by decoder',
recording_too_small: 'Recording too small for useful decode',
satdump_failed: 'SatDump decode failed',
permission_error: 'Decoder could not access recording/output path',
input_missing: 'Input recording was not accessible',
missing_recording: 'Recording was missing when decode started',
no_imagery_produced: 'Decode produced no imagery',
};
return job.error_message || reasonLabels[details.reason] || details.message || 'Last decode failed';
}
return details.message || 'Decode status unavailable';
}
function formatDecodeJobMeta(details) {
const parts = [];
if (details.sample_rate) parts.push(`${Number(details.sample_rate).toLocaleString()} Hz`);
if (details.file_size_human) parts.push(details.file_size_human);
return parts.join(' / ') || '--';
}
function formatDecodeJobContext(details) {
const parts = [];
if (details.reason) parts.push(`Reason: ${String(details.reason).replace(/_/g, ' ')}`);
if (details.sample_rate) parts.push(`Sample rate ${Number(details.sample_rate).toLocaleString()} Hz`);
if (details.file_size_human) parts.push(`Recording ${details.file_size_human}`);
if (details.last_returncode !== undefined && details.last_returncode !== null) {
parts.push(`Exit code ${details.last_returncode}`);
}
return parts.join(' | ');
}
/** /**
* Escape HTML * Escape HTML
*/ */