Fix str(e) in error responses, remove location modal, document GTK dependency

Co-authored-by: mitchross <6330506+mitchross@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-02-09 21:55:30 +00:00
parent 4a6dddbb48
commit aa963519e9
3 changed files with 14 additions and 169 deletions

View File

@@ -70,6 +70,10 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
cmake \ cmake \
libncurses-dev \ libncurses-dev \
libsndfile1-dev \ libsndfile1-dev \
# GTK is required for slowrx (SSTV decoder GUI dependency).
# Note: slowrx is kept for backwards compatibility, but the pure Python
# SSTV decoder in utils/sstv/ is now the primary implementation.
# GTK can be removed if slowrx is deprecated in future releases.
libgtk-3-dev \ libgtk-3-dev \
libasound2-dev \ libasound2-dev \
libsoapysdr-dev \ libsoapysdr-dev \
@@ -195,6 +199,10 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
&& ldconfig \ && ldconfig \
&& rm -rf /tmp/dsd-fme \ && rm -rf /tmp/dsd-fme \
# Cleanup build tools to reduce image size # Cleanup build tools to reduce image size
# Note: libgtk-3-dev is removed here but runtime GTK libs (from first stage)
# remain for slowrx. This adds ~10MB to the image but is required for slowrx
# to function. Consider removing slowrx build entirely if moving fully to
# the pure Python SSTV decoder.
&& apt-get remove -y \ && apt-get remove -y \
build-essential \ build-essential \
git \ git \

View File

@@ -120,9 +120,10 @@ def start_capture():
device_index = validate_device_index(data.get('device', 0)) device_index = validate_device_index(data.get('device', 0))
gain = validate_gain(data.get('gain', 40.0)) gain = validate_gain(data.get('gain', 40.0))
except ValueError as e: except ValueError as e:
logger.warning('Invalid parameter in start_capture: %s', e)
return jsonify({ return jsonify({
'status': 'error', 'status': 'error',
'message': str(e) 'message': 'Invalid parameter value'
}), 400 }), 400
bias_t = bool(data.get('bias_t', False)) bias_t = bool(data.get('bias_t', False))
@@ -464,7 +465,8 @@ def get_passes():
lat = validate_latitude(raw_lat) lat = validate_latitude(raw_lat)
lon = validate_longitude(raw_lon) lon = validate_longitude(raw_lon)
except ValueError as e: except ValueError as e:
return jsonify({'status': 'error', 'message': str(e)}), 400 logger.warning('Invalid coordinates in get_passes: %s', e)
return jsonify({'status': 'error', 'message': 'Invalid coordinates'}), 400
hours = max(1, min(request.args.get('hours', 24, type=int), 72)) hours = max(1, min(request.args.get('hours', 24, type=int), 72))
min_elevation = max(0, min(request.args.get('min_elevation', 15, type=float), 90)) min_elevation = max(0, min(request.args.get('min_elevation', 15, type=float), 90))
@@ -555,9 +557,10 @@ def enable_schedule():
device = validate_device_index(data.get('device', 0)) device = validate_device_index(data.get('device', 0))
gain_val = validate_gain(data.get('gain', 40.0)) gain_val = validate_gain(data.get('gain', 40.0))
except ValueError as e: except ValueError as e:
logger.warning('Invalid parameter in enable_schedule: %s', e)
return jsonify({ return jsonify({
'status': 'error', 'status': 'error',
'message': str(e) 'message': 'Invalid parameter value'
}), 400 }), 400
scheduler = get_weather_sat_scheduler() scheduler = get_weather_sat_scheduler()

View File

@@ -15270,172 +15270,6 @@
<!-- Settings Modal --> <!-- Settings Modal -->
{% include 'partials/settings-modal.html' %} {% include 'partials/settings-modal.html' %}
<!-- Location Prompt (first-run) -->
<div id="locationPromptModal" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.85); z-index:10001; backdrop-filter:blur(4px); align-items:center; justify-content:center;">
<div style="background:var(--bg-secondary); border:1px solid var(--accent-cyan); border-radius:10px; max-width:420px; width:90%; box-shadow:0 8px 32px rgba(0,0,0,0.6), 0 0 20px rgba(0,255,255,0.15); animation:locFadeIn 0.3s ease-out;">
<style>
@keyframes locFadeIn { from { transform:scale(0.95); opacity:0; } to { transform:scale(1); opacity:1; } }
@keyframes locSpin { to { transform:rotate(360deg); } }
</style>
<div style="padding:24px;">
<div style="text-align:center; margin-bottom:18px;">
<svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="var(--accent-cyan)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/>
</svg>
<h3 style="margin:10px 0 4px; color:var(--text-primary); font-size:16px;">Set Your Location</h3>
<p style="color:var(--text-dim); font-size:12px; margin:0; line-height:1.4;">
INTERCEPT needs your location for satellite pass predictions,<br>weather satellite scheduling, and distance calculations.
</p>
</div>
<div id="locPromptGpsSection" style="margin-bottom:16px;">
<button id="locPromptGpsBtn" onclick="locationPromptDetectGPS()" style="width:100%; padding:12px; background:var(--accent-cyan); color:#000; border:none; border-radius:6px; font-size:13px; font-weight:600; cursor:pointer; font-family:var(--font-mono); display:flex; align-items:center; justify-content:center; gap:8px;">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="3"/><line x1="12" y1="2" x2="12" y2="6"/><line x1="12" y1="18" x2="12" y2="22"/><line x1="2" y1="12" x2="6" y2="12"/><line x1="18" y1="12" x2="22" y2="12"/>
</svg>
Auto-Detect (GPS)
</button>
<p id="locPromptGpsStatus" style="font-size:11px; color:var(--text-dim); text-align:center; margin:6px 0 0; min-height:16px;"></p>
</div>
<div style="display:flex; align-items:center; gap:10px; margin-bottom:14px;">
<div style="flex:1; height:1px; background:var(--border-color);"></div>
<span style="color:var(--text-dim); font-size:11px;">or enter manually</span>
<div style="flex:1; height:1px; background:var(--border-color);"></div>
</div>
<div style="display:flex; gap:10px; margin-bottom:16px;">
<div style="flex:1;">
<label style="display:block; font-size:11px; color:var(--text-dim); margin-bottom:4px;">Latitude</label>
<input type="number" id="locPromptLat" step="0.0001" min="-90" max="90" placeholder="51.5074" style="width:100%; padding:8px 10px; background:var(--bg-primary); border:1px solid var(--border-color); border-radius:4px; color:var(--text-primary); font-family:var(--font-mono); font-size:13px; box-sizing:border-box;">
</div>
<div style="flex:1;">
<label style="display:block; font-size:11px; color:var(--text-dim); margin-bottom:4px;">Longitude</label>
<input type="number" id="locPromptLon" step="0.0001" min="-180" max="180" placeholder="-0.1278" style="width:100%; padding:8px 10px; background:var(--bg-primary); border:1px solid var(--border-color); border-radius:4px; color:var(--text-primary); font-family:var(--font-mono); font-size:13px; box-sizing:border-box;">
</div>
</div>
<div style="display:flex; gap:10px;">
<button onclick="locationPromptSave()" style="flex:1; padding:10px; background:var(--accent-cyan); color:#000; border:none; border-radius:6px; font-size:12px; font-weight:600; cursor:pointer; font-family:var(--font-mono);">
Save Location
</button>
<button onclick="locationPromptSkip()" style="flex:1; padding:10px; background:transparent; color:var(--text-dim); border:1px solid var(--border-color); border-radius:6px; font-size:12px; cursor:pointer; font-family:var(--font-mono);">
Skip for Now
</button>
</div>
<p style="font-size:10px; color:var(--text-dim); text-align:center; margin:12px 0 0; opacity:0.7;">
Stored locally in your browser. Never sent to external servers.
</p>
</div>
</div>
</div>
<script>
(function() {
// Show location prompt on first load if no location has been set
function checkLocationPrompt() {
if (!window.ObserverLocation) return;
if (ObserverLocation.hasStoredLocation()) return;
// Don't show if disclaimer hasn't been accepted yet
if (localStorage.getItem('disclaimerAccepted') !== 'true') return;
// If server provided default lat/lon via env vars, auto-save without prompting
if (window.INTERCEPT_DEFAULT_LAT && window.INTERCEPT_DEFAULT_LON) {
ObserverLocation.setShared({
lat: window.INTERCEPT_DEFAULT_LAT,
lon: window.INTERCEPT_DEFAULT_LON
});
return;
}
// Don't show if user explicitly skipped
if (localStorage.getItem('locationPromptSkipped') === 'true') return;
var modal = document.getElementById('locationPromptModal');
if (modal) modal.style.display = 'flex';
}
// Run after a short delay so disclaimer can show first
document.addEventListener('DOMContentLoaded', function() {
setTimeout(checkLocationPrompt, 1500);
});
})();
function locationPromptDetectGPS() {
var btn = document.getElementById('locPromptGpsBtn');
var status = document.getElementById('locPromptGpsStatus');
if (!navigator.geolocation) {
status.textContent = 'Geolocation not supported by this browser.';
status.style.color = 'var(--accent-red, #ff4444)';
return;
}
if (!window.isSecureContext) {
status.textContent = 'GPS requires HTTPS or localhost.';
status.style.color = 'var(--accent-red, #ff4444)';
return;
}
btn.disabled = true;
btn.innerHTML = '<span style="display:inline-block; width:14px; height:14px; border:2px solid #000; border-top-color:transparent; border-radius:50%; animation:locSpin 0.8s linear infinite;"></span> Detecting...';
status.textContent = '';
navigator.geolocation.getCurrentPosition(
function(pos) {
var lat = pos.coords.latitude;
var lon = pos.coords.longitude;
document.getElementById('locPromptLat').value = lat.toFixed(4);
document.getElementById('locPromptLon').value = lon.toFixed(4);
status.textContent = 'Location detected! Click Save to confirm.';
status.style.color = 'var(--accent-green, #00ff88)';
btn.disabled = false;
btn.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg> Detected';
},
function(err) {
status.textContent = 'Could not detect: ' + err.message;
status.style.color = 'var(--accent-red, #ff4444)';
btn.disabled = false;
btn.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="3"/><line x1="12" y1="2" x2="12" y2="6"/><line x1="12" y1="18" x2="12" y2="22"/><line x1="2" y1="12" x2="6" y2="12"/><line x1="18" y1="12" x2="22" y2="12"/></svg> Auto-Detect (GPS)';
},
{ enableHighAccuracy: true, timeout: 15000 }
);
}
function locationPromptSave() {
var lat = parseFloat(document.getElementById('locPromptLat').value);
var lon = parseFloat(document.getElementById('locPromptLon').value);
if (isNaN(lat) || lat < -90 || lat > 90) {
document.getElementById('locPromptGpsStatus').textContent = 'Invalid latitude (-90 to 90)';
document.getElementById('locPromptGpsStatus').style.color = 'var(--accent-red, #ff4444)';
return;
}
if (isNaN(lon) || lon < -180 || lon > 180) {
document.getElementById('locPromptGpsStatus').textContent = 'Invalid longitude (-180 to 180)';
document.getElementById('locPromptGpsStatus').style.color = 'var(--accent-red, #ff4444)';
return;
}
if (window.ObserverLocation) {
ObserverLocation.setShared({ lat: lat, lon: lon });
}
localStorage.removeItem('locationPromptSkipped');
var modal = document.getElementById('locationPromptModal');
if (modal) modal.style.display = 'none';
if (typeof showNotification === 'function') {
showNotification('Location', 'Location set to ' + lat.toFixed(4) + ', ' + lon.toFixed(4));
}
}
function locationPromptSkip() {
localStorage.setItem('locationPromptSkipped', 'true');
var modal = document.getElementById('locationPromptModal');
if (modal) modal.style.display = 'none';
}
</script>
<!-- Toast Container --> <!-- Toast Container -->
<div id="toastContainer"></div> <div id="toastContainer"></div>