From 27dd868d974fab650eb575a183719aeba3ffe581 Mon Sep 17 00:00:00 2001 From: Smittix Date: Wed, 7 Jan 2026 20:14:46 +0000 Subject: [PATCH] Add pager message filtering (closes #40) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add ability to filter out unwanted pager messages from display: - Hide "Tone Only" messages by default (toggle in UI) - Custom keyword filter (comma-separated list) - Filtered messages are still logged and counted, just hidden from view - Filter settings persist in localStorage 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- templates/index.html | 100 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 91 insertions(+), 9 deletions(-) diff --git a/templates/index.html b/templates/index.html index 2a23c0f..6a10fbc 100644 --- a/templates/index.html +++ b/templates/index.html @@ -403,6 +403,23 @@ +
+

Message Filters

+
+ +
+
+ + +
+
+ Messages matching these keywords will be hidden from display but still logged. +
+
+ @@ -1711,8 +1728,15 @@ let pocsagCount = 0; let flexCount = 0; let sensorCount = 0; + let filteredCount = 0; // Count of filtered messages let deviceList = {{ devices | tojson | safe }}; + // Pager message filter settings + let pagerFilters = { + hideToneOnly: true, + keywords: [] + }; + // Aircraft (ADS-B) state let adsbAircraft = {}; let adsbMsgCount = 0; @@ -1732,6 +1756,50 @@ setInterval(updateHeaderClock, 1000); updateHeaderClock(); // Initial call + // Pager message filter functions + function loadPagerFilters() { + const saved = localStorage.getItem('pagerFilters'); + if (saved) { + try { + pagerFilters = JSON.parse(saved); + } catch (e) { + console.warn('Failed to load pager filters:', e); + } + } + // Update UI + document.getElementById('filterToneOnly').checked = pagerFilters.hideToneOnly; + document.getElementById('filterKeywords').value = pagerFilters.keywords.join(', '); + } + + function savePagerFilters() { + pagerFilters.hideToneOnly = document.getElementById('filterToneOnly').checked; + const keywordsInput = document.getElementById('filterKeywords').value; + pagerFilters.keywords = keywordsInput + .split(',') + .map(k => k.trim().toLowerCase()) + .filter(k => k.length > 0); + localStorage.setItem('pagerFilters', JSON.stringify(pagerFilters)); + } + + function shouldFilterMessage(msg) { + // Check for Tone Only filter + if (pagerFilters.hideToneOnly) { + if (msg.message === '[Tone Only]' || msg.msg_type === 'Tone') { + return true; + } + } + // Check keyword filters + if (pagerFilters.keywords.length > 0) { + const msgLower = (msg.message || '').toLowerCase(); + for (const keyword of pagerFilters.keywords) { + if (msgLower.includes(keyword)) { + return true; + } + } + } + return false; + } + // Sync header stats with output panel stats function syncHeaderStats() { // Pager stats @@ -2136,6 +2204,9 @@ // Auto-connect to gpsd if available autoConnectGps(); + + // Load pager message filters + loadPagerFilters(); }); // Toggle section collapse @@ -3092,18 +3163,13 @@ placeholder.remove(); } - // Store message for export + // Store message for export (always, even if filtered) allMessages.push(msg); - // Play audio alert - playAlert(); - - // Update signal meter - pulseSignal(); - - // Add to waterfall - addWaterfallPoint(Date.now(), 0.8); + // Check if message should be filtered from display + const isFiltered = shouldFilterMessage(msg); + // Update counts (always, even if filtered) msgCount++; document.getElementById('msgCount').textContent = msgCount; @@ -3118,6 +3184,21 @@ document.getElementById('flexCount').textContent = flexCount; } + // If filtered, skip display but update filtered count + if (isFiltered) { + filteredCount++; + return; + } + + // Play audio alert (only for non-filtered messages) + playAlert(); + + // Update signal meter + pulseSignal(); + + // Add to waterfall + addWaterfallPoint(Date.now(), 0.8); + const isNumeric = /^[0-9\s\-\*\#U]+$/.test(msg.message); const relativeTime = getRelativeTime(msg.timestamp); @@ -3216,6 +3297,7 @@ pocsagCount = 0; flexCount = 0; sensorCount = 0; + filteredCount = 0; allMessages = []; uniqueDevices.clear(); document.getElementById('msgCount').textContent = '0';