From 6d5bb7b46eb9533f6ef133d5fbbcc63fd98a6c80 Mon Sep 17 00:00:00 2001 From: Szymon Porwolik Date: Mon, 3 Nov 2025 00:38:30 +0100 Subject: [PATCH] One band operation with CAT - server load reduced --- assets/js/sections/bandmap_list.js | 195 ++++++++++++++++++++++------- 1 file changed, 149 insertions(+), 46 deletions(-) diff --git a/assets/js/sections/bandmap_list.js b/assets/js/sections/bandmap_list.js index aa753cdc1..970fc8508 100644 --- a/assets/js/sections/bandmap_list.js +++ b/assets/js/sections/bandmap_list.js @@ -477,8 +477,10 @@ $(function() { // Track what backend parameters were used for last data fetch // NOTE: Changed architecture - only de continent affects backend now // Band and Mode are now client-side filters only + // UPDATE: Band becomes backend filter when CAT Control is active (single-band fetch mode) var loadedBackendFilters = { - continent: 'Any' + continent: 'Any', + band: 'All' }; // Initialize backend filter state from form values @@ -521,6 +523,12 @@ $(function() { return spot.spotted + '_' + spot.frequency + '_' + spot.spotter; } + // Extract frequency from spot key for band determination + function getFrequencyFromKey(key) { + let parts = key.split('_'); + return parseFloat(parts[1]); // frequency is the second part + } + // Auto-refresh timer state var refreshCountdown = SPOT_REFRESH_INTERVAL; var refreshTimerInterval = null; @@ -640,7 +648,17 @@ $(function() { console.log('Timer countdown: reloading spot data with current filters'); let table = get_dtable(); table.clear(); - fill_list(currentFilters.deContinent, dxcluster_maxage); + + // Determine band for API fetch based on CAT Control state and current filter + let bandForRefresh = 'All'; + if (isCatTrackingEnabled) { + let currentBand = currentFilters.band || []; + if (currentBand.length === 1 && !currentBand.includes('All') && currentBand[0] !== '') { + bandForRefresh = currentBand[0]; + } + } + + fill_list(currentFilters.deContinent, dxcluster_maxage, bandForRefresh); refreshCountdown = SPOT_REFRESH_INTERVAL; } else { if (!isFetchInProgress && lastFetchParams.timestamp !== null) { @@ -1153,9 +1171,21 @@ $(function() { // Update badge counts on band and mode filter buttons function updateBandCountBadges() { + // Check if we fetched only a specific band (single band fetch mode) + // This happens when CAT Control is active and limited the API fetch to current band + let fetchedBand = null; + if (loadedBackendFilters && loadedBackendFilters.band && loadedBackendFilters.band !== 'All') { + fetchedBand = loadedBackendFilters.band; + } + if (!cachedSpotData || cachedSpotData.length === 0) { // Clear all badges when no data - $('.band-count-badge, .mode-count-badge').text('0'); + if (fetchedBand) { + // Set all to "-" when in single band fetch mode but no data + $('.band-count-badge, .mode-count-badge').text('-'); + } else { + $('.band-count-badge, .mode-count-badge').text('0'); + } return; } @@ -1302,37 +1332,62 @@ $(function() { } }); - // Update individual MF/HF band button badges - const mfHfBands = [ - '160m', '80m', '60m', '40m', '30m', '20m', '17m', '15m', '12m', '10m' - ]; + // Update individual MF/HF band button badges + const mfHfBands = [ + '160m', '80m', '60m', '40m', '30m', '20m', '17m', '15m', '12m', '10m' + ]; - mfHfBands.forEach(band => { - let count = bandCounts[band] || 0; - let $badge = $('#toggle' + band + 'Filter .band-count-badge'); - if ($badge.length === 0) { - // Badge doesn't exist yet, create it - $('#toggle' + band + 'Filter').append(' ' + count + ''); - } else { - // Update existing badge - $badge.text(count); - } - }); + mfHfBands.forEach(band => { + let count; + let displayText; - // Update band group button badges (VHF, UHF, SHF) - ['VHF', 'UHF', 'SHF'].forEach(group => { - let count = groupCounts[group] || 0; - let $badge = $('#toggle' + group + 'Filter .band-count-badge'); - if ($badge.length === 0) { - // Badge doesn't exist yet, create it - $('#toggle' + group + 'Filter').append(' ' + count + ''); - } else { - // Update existing badge - $badge.text(count); - } - }); + // If in single band fetch mode and this is not the fetched band, show "-" + if (fetchedBand && band !== fetchedBand) { + displayText = '-'; + } else { + count = bandCounts[band] || 0; + displayText = count.toString(); + } - // Update mode button badges + let $badge = $('#toggle' + band + 'Filter .band-count-badge'); + if ($badge.length === 0) { + // Badge doesn't exist yet, create it + $('#toggle' + band + 'Filter').append(' ' + displayText + ''); + } else { + // Update existing badge + $badge.text(displayText); + } + }); + + // Update band group button badges (VHF, UHF, SHF) + ['VHF', 'UHF', 'SHF'].forEach(group => { + let count; + let displayText; + + // Check if fetched band is in this group + let isActiveGroup = false; + if (fetchedBand) { + let fetchedBandGroup = getBandGroup(fetchedBand); + isActiveGroup = (fetchedBandGroup === group); + } + + // If in single band fetch mode and this is not the fetched band's group, show "-" + if (fetchedBand && !isActiveGroup) { + displayText = '-'; + } else { + count = groupCounts[group] || 0; + displayText = count.toString(); + } + + let $badge = $('#toggle' + group + 'Filter .band-count-badge'); + if ($badge.length === 0) { + // Badge doesn't exist yet, create it + $('#toggle' + group + 'Filter').append(' ' + displayText + ''); + } else { + // Update existing badge + $badge.text(displayText); + } + }); // Update mode button badges const modeButtons = ['Cw', 'Digi', 'Phone']; modeButtons.forEach(mode => { let modeKey = mode.toLowerCase(); @@ -1452,7 +1507,7 @@ $(function() { // Fetch spot data from DX cluster API // Backend filters: band, de continent (where spotter is), mode // Client filters applied after fetch: cwn, spotted continent, additionalFlags - function fill_list(de, maxAgeMinutes) { + function fill_list(de, maxAgeMinutes, bandForAPI = 'All') { var table = get_dtable(); // Normalize de continent parameter to array @@ -1460,21 +1515,28 @@ $(function() { if (deContinent.includes('Any') || deContinent.length === 0) deContinent = ['Any']; // Backend API only accepts single values for continent - // Band and mode are always 'All' - filtering happens client-side let continentForAPI = 'Any'; if (deContinent.length === 1 && !deContinent.includes('Any')) continentForAPI = deContinent[0]; - // Update backend filter state (only continent now) + // bandForAPI is now passed as a parameter from applyFilters() + // Log if CAT Control influenced the band selection + if (bandForAPI !== 'All') { + console.log('Fetching specific band from server:', bandForAPI); + } + + // Update backend filter state loadedBackendFilters = { - continent: continentForAPI + continent: continentForAPI, + band: bandForAPI }; lastFetchParams.continent = continentForAPI; + lastFetchParams.band = bandForAPI; lastFetchParams.maxAge = maxAgeMinutes; // Build API URL: /spots/{band}/{maxAge}/{continent}/{mode} - // Always use 'All' for band and mode - we filter client-side - let dxurl = dxcluster_provider + "/spots/All/" + maxAgeMinutes + "/" + continentForAPI + "/All"; + // Mode is always 'All' - filtering happens client-side + let dxurl = dxcluster_provider + "/spots/" + bandForAPI + "/" + maxAgeMinutes + "/" + continentForAPI + "/All"; console.log('Loading from backend: ' + dxurl); // Cancel any in-flight request before starting new one @@ -1500,6 +1562,7 @@ $(function() { dxspots.sort(SortByQrg); // Sort by frequency // TTL Management: Process new spots and update TTL values + // In single-band fetch mode, only update TTL for spots in the fetched band let newSpotKeys = new Set(); // First pass: identify all spots in the new data @@ -1508,20 +1571,36 @@ $(function() { newSpotKeys.add(key); }); - // Second pass: Update TTL for all existing spots - // - Decrement all TTL values by 1 + // Second pass: Update TTL for existing spots + // - In single-band mode (bandForAPI != 'All'), only decrement TTL for spots in the fetched band + // - In all-band mode, decrement all TTL values // - If spot exists in new data, set TTL back to 1 (stays valid) // - Remove spots with TTL < -1 let ttlStats = { stillValid: 0, expiring: 0, removed: 0, added: 0 }; let expiringSpots = []; // Store spots with TTL=0 that need to be shown for (let [key, ttl] of spotTTLMap.entries()) { - let newTTL = ttl - 1; // Decrement all spots + let newTTL = ttl; + + // Only decrement TTL if: + // - We fetched all bands (bandForAPI === 'All'), OR + // - This spot is in the band we just fetched + let shouldDecrementTTL = (bandForAPI === 'All'); + if (!shouldDecrementTTL) { + // Extract frequency from the spot key and determine its band + let spotFrequency = getFrequencyFromKey(key); + let spotBand = getBandFromFrequency(spotFrequency); + shouldDecrementTTL = (spotBand === bandForAPI); + } + + if (shouldDecrementTTL) { + newTTL = ttl - 1; // Decrement only if in scope of this fetch + } if (newSpotKeys.has(key)) { newTTL = 1; // Reset to 1 if spot still exists (keeps it valid) ttlStats.stillValid++; - } else { + } else if (shouldDecrementTTL) { if (newTTL === 0) { ttlStats.expiring++; // Find the spot in previous cachedSpotData to keep it for display @@ -1719,13 +1798,27 @@ $(function() { } // If multiple continents selected, fetch 'Any' from backend and filter client-side + // Determine if we're in single-band fetch mode (CAT Control active) + // In this mode, band changes require a new server fetch + // Use the selected band filter value when CAT is active and a single band is selected + let bandForAPI = 'All'; + let isSingleBandMode = false; + if (isCatTrackingEnabled) { + // Check if a single specific band is selected (not 'All') + if (band.length === 1 && !band.includes('All') && band[0] !== '') { + bandForAPI = band[0]; + isSingleBandMode = true; + } + } + console.log('applyFilters - Current backend filters:', loadedBackendFilters); - console.log('applyFilters - Requested backend params:', {continent: continentForAPI}); + console.log('applyFilters - Requested backend params:', {continent: continentForAPI, band: bandForAPI, singleBandMode: isSingleBandMode}); // Check if backend parameters changed (requires new data fetch) - // Only de continent affects backend now - band and mode are client-side only + // In single-band mode, band selection changes also require server fetch let backendParamsChanged = forceReload || - loadedBackendFilters.continent !== continentForAPI; + loadedBackendFilters.continent !== continentForAPI || + (isSingleBandMode && loadedBackendFilters.band !== bandForAPI); console.log('applyFilters - backendParamsChanged:', backendParamsChanged); @@ -1741,9 +1834,9 @@ $(function() { }; if (backendParamsChanged) { - console.log('Reloading from backend: continent=' + continentForAPI); + console.log('Reloading from backend: continent=' + continentForAPI + ' band=' + bandForAPI); table.clear(); - fill_list(de, dxcluster_maxage); + fill_list(de, dxcluster_maxage, bandForAPI); } else { console.log('Client-side filtering changed - using cached data'); renderFilteredSpots(); @@ -3296,6 +3389,16 @@ $(function() { // Unlock table sorting unlockTableSorting(); + + // Reset band filter to 'All' and fetch all bands + const currentBands = $("#band").val() || []; + if (currentBands.length !== 1 || currentBands[0] !== 'All') { + console.log('CAT Control disabled - resetting to all bands'); + $("#band").val(['All']); + updateSelectCheckboxes('band'); + syncQuickFilterButtons(); + applyFilters(true); // Force reload to fetch all bands + } } else { // Enable CAT Control btn.removeClass('btn-secondary').addClass('btn-success');