diff --git a/routes/space_weather.py b/routes/space_weather.py index 603ea9c..84a0308 100644 --- a/routes/space_weather.py +++ b/routes/space_weather.py @@ -304,3 +304,36 @@ def get_image(key: str): _cache_set(cache_key, img_data, TTL_IMAGE) return Response(img_data, content_type=entry['content_type'], headers={'Cache-Control': 'public, max-age=300'}) + + +@space_weather_bp.route('/prefetch-images') +def prefetch_images(): + """Warm the image cache by fetching all whitelisted images in parallel.""" + # Only fetch images not already cached + to_fetch = {} + for key, entry in IMAGE_WHITELIST.items(): + cache_key = f'img_{key}' + if _cache_get(cache_key) is None: + to_fetch[key] = entry + + if not to_fetch: + return jsonify({'status': 'all cached', 'count': 0}) + + def _fetch_and_cache(key: str, entry: dict) -> bool: + img_data = _fetch_bytes(entry['url']) + if img_data: + _cache_set(f'img_{key}', img_data, TTL_IMAGE) + return True + return False + + fetched = 0 + with concurrent.futures.ThreadPoolExecutor(max_workers=6) as executor: + futures = { + executor.submit(_fetch_and_cache, k, e): k + for k, e in to_fetch.items() + } + for future in concurrent.futures.as_completed(futures): + if future.result(): + fetched += 1 + + return jsonify({'status': 'ok', 'fetched': fetched, 'cached': len(IMAGE_WHITELIST) - len(to_fetch)}) diff --git a/static/js/modes/space-weather.js b/static/js/modes/space-weather.js index 24e0ccb..fa2472c 100644 --- a/static/js/modes/space-weather.js +++ b/static/js/modes/space-weather.js @@ -19,6 +19,11 @@ const SpaceWeather = (function () { let _solarImageKey = 'sdo_193'; let _drapFreq = 'drap_global'; + /** Stable cache-bust key that rotates every 5 minutes (matches backend max-age). */ + function _cacheBust() { + return 'v=' + Math.floor(Date.now() / 300000); + } + // ------------------------------------------------------------------- // Public API // ------------------------------------------------------------------- @@ -27,6 +32,8 @@ const SpaceWeather = (function () { if (!_initialized) { _initialized = true; } + // Warm the backend image cache in parallel before rendering + fetch('/space-weather/prefetch-images').catch(function () {}); refresh(); _startAutoRefresh(); } @@ -50,7 +57,7 @@ const SpaceWeather = (function () { const img = new Image(); img.onload = function () { frame.innerHTML = ''; frame.appendChild(img); }; img.onerror = function () { frame.innerHTML = '