diff --git a/public/index.html b/public/index.html
index 7e5f1bf..b8e7dac 100644
--- a/public/index.html
+++ b/public/index.html
@@ -1102,13 +1102,18 @@
useEffect(() => {
const fetchDXpeditions = async () => {
try {
+ console.log('[DXpeditions] Fetching...');
const response = await fetch('/api/dxpeditions');
+ console.log('[DXpeditions] Response status:', response.status);
if (response.ok) {
const result = await response.json();
+ console.log('[DXpeditions] Received:', result.dxpeditions?.length, 'entries');
setData(result);
+ } else {
+ console.error('[DXpeditions] Failed:', response.status);
}
} catch (err) {
- console.error('DXpedition fetch error:', err);
+ console.error('[DXpeditions] Fetch error:', err);
} finally {
setLoading(false);
}
diff --git a/server.js b/server.js
index f90f5fd..18ef867 100644
--- a/server.js
+++ b/server.js
@@ -151,22 +151,32 @@ let dxpeditionCache = { data: null, timestamp: 0, maxAge: 30 * 60 * 1000 }; // 3
app.get('/api/dxpeditions', async (req, res) => {
try {
const now = Date.now();
+ console.log('[DXpeditions] API called');
// Return cached data if fresh
if (dxpeditionCache.data && (now - dxpeditionCache.timestamp) < dxpeditionCache.maxAge) {
+ console.log('[DXpeditions] Returning cached data:', dxpeditionCache.data.dxpeditions?.length, 'entries');
return res.json(dxpeditionCache.data);
}
// Fetch NG3K ADXO plain text version (easier to parse)
+ console.log('[DXpeditions] Fetching from NG3K...');
const response = await fetch('https://www.ng3k.com/Misc/adxoplain.html');
- if (!response.ok) throw new Error('Failed to fetch NG3K');
+ if (!response.ok) {
+ console.log('[DXpeditions] NG3K fetch failed:', response.status);
+ throw new Error('Failed to fetch NG3K: ' + response.status);
+ }
const text = await response.text();
+ console.log('[DXpeditions] Received', text.length, 'bytes from NG3K');
+
const dxpeditions = [];
// Split by the bullet separator used in the plain text version
const entries = text.split(/\s*ยท\s*/);
+ console.log('[DXpeditions] Found', entries.length, 'entries to parse');
+ let parseCount = 0;
for (const entry of entries) {
if (!entry.trim() || entry.length < 20) continue;
@@ -180,6 +190,14 @@ app.get('/api/dxpeditions', async (req, res) => {
// Date pattern at the start: "Jan 1, 2026-Feb 16, 2026" or "Jan 1-16, 2026"
const dateMatch = entry.match(/^([A-Za-z]+\s+\d+[^D]*?)(?=\s*DXCC:)/i);
+ // Log first few entries for debugging
+ if (parseCount < 3) {
+ console.log('[DXpeditions] Entry sample:', entry.substring(0, 150));
+ console.log('[DXpeditions] DXCC match:', dxccMatch?.[1]);
+ console.log('[DXpeditions] Call match:', callMatch?.[1]);
+ }
+ parseCount++;
+
// Must have both DXCC and Callsign to be valid
if (!callMatch || !dxccMatch) continue;
@@ -274,16 +292,19 @@ app.get('/api/dxpeditions', async (req, res) => {
timestamp: new Date().toISOString()
};
+ console.log('[DXpeditions] Parsed', dxpeditions.length, 'valid entries,', result.active, 'active,', result.upcoming, 'upcoming');
+
// Cache the result
dxpeditionCache.data = result;
dxpeditionCache.timestamp = now;
res.json(result);
} catch (error) {
- console.error('DXpedition API error:', error.message);
+ console.error('[DXpeditions] API error:', error.message);
// Return cached data if available, even if stale
if (dxpeditionCache.data) {
+ console.log('[DXpeditions] Returning stale cache');
return res.json({ ...dxpeditionCache.data, stale: true });
}