Skip to content

Commit 1fc298f

Browse files
committed
feat: live feed shows last 10 mins only, history excludes last 10 mins and auto-refreshes as events age out
1 parent dbc01b8 commit 1fc298f

3 files changed

Lines changed: 38 additions & 9 deletions

File tree

src/db.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -128,14 +128,15 @@ export function getRecentActivity(limit = 100) {
128128
).all(limit);
129129
}
130130

131-
export function getActivityFiltered({ show, type, from, to } = {}, limit = 50, offset = 0) {
131+
export function getActivityFiltered({ show, type, from, to, before } = {}, limit = 50, offset = 0) {
132132
const conditions = [];
133133
const params = [];
134134

135-
if (show) { conditions.push('show_title LIKE ?'); params.push('%' + show + '%'); }
136-
if (type) { conditions.push('event_type = ?'); params.push(type); }
137-
if (from) { conditions.push('timestamp >= ?'); params.push(from); }
138-
if (to) { conditions.push('timestamp <= ?'); params.push(to); }
135+
if (show) { conditions.push('show_title LIKE ?'); params.push('%' + show + '%'); }
136+
if (type) { conditions.push('event_type = ?'); params.push(type); }
137+
if (from) { conditions.push('timestamp >= ?'); params.push(from); }
138+
if (to) { conditions.push('timestamp <= ?'); params.push(to); }
139+
if (before) { conditions.push('timestamp < ?'); params.push(before); }
139140

140141
const where = conditions.length ? 'WHERE ' + conditions.join(' AND ') : '';
141142

src/public/index.html

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,7 @@ <h1>Episode<span>Guard</span><span class="version-badge" id="version-badge"></sp
580580
if (d.message && !d.reason) detail += (detail?' - ':'')+String(d.message).slice(0,60);
581581
const el = document.createElement('div');
582582
el.className = 'live-row'+(animate?' new':'');
583+
el.dataset.ts = String(new Date(row.timestamp).getTime());
583584
el.innerHTML = '<span class="live-time">'+relativeTime(row.timestamp)+'</span>'+
584585
'<span class="live-type">'+badgeHtml(row.event_type)+'</span>'+
585586
'<span class="live-show">'+esc(row.show_title??'-')+'<span class="live-ep">'+epLabel(row.season,row.episode)+'</span></span>'+
@@ -601,6 +602,9 @@ <h1>Episode<span>Guard</span><span class="version-badge" id="version-badge"></sp
601602

602603
let histPage=1;
603604
const HIST_LIMIT=50;
605+
const LIVE_WINDOW_MS = 10 * 60 * 1000; // 10 minutes
606+
607+
function liveCutoff() { return new Date(Date.now() - LIVE_WINDOW_MS).toISOString(); }
604608

605609
function applyFilters(){histPage=1;loadHistLog();}
606610
function clearFilters(){
@@ -618,6 +622,9 @@ <h1>Episode<span>Guard</span><span class="version-badge" id="version-badge"></sp
618622
if (type) params.set('type',type);
619623
if (from) params.set('from',from+'T00:00:00Z');
620624
if (to) params.set('to',to+'T23:59:59Z');
625+
// Default: exclude last 10 mins (those are in the live feed)
626+
// Only apply if user hasn't set an explicit date range
627+
if (!from && !to) params.set('before', liveCutoff());
621628
try {
622629
const res = await fetch('/api/logs?'+params);
623630
const data = await res.json();
@@ -639,7 +646,26 @@ <h1>Episode<span>Guard</span><span class="version-badge" id="version-badge"></sp
639646
}
640647

641648
function goPage(p){histPage=p;loadHistLog();}
642-
function initLogsView(){initLiveFeed();loadHistLog();}
649+
650+
// Prune live feed rows older than 10 mins and refresh history to pick them up
651+
function pruneLiveFeed() {
652+
const cutoff = Date.now() - LIVE_WINDOW_MS;
653+
const feed = document.getElementById('live-feed');
654+
if (!feed) return;
655+
let pruned = 0;
656+
feed.querySelectorAll('.live-row').forEach(el => {
657+
const ts = el.dataset.ts ? parseInt(el.dataset.ts, 10) : 0;
658+
if (ts && ts < cutoff) { el.remove(); pruned++; }
659+
});
660+
if (pruned > 0) loadHistLog();
661+
}
662+
663+
let logsViewTimer = null;
664+
function initLogsView() {
665+
initLiveFeed();
666+
loadHistLog();
667+
if (!logsViewTimer) logsViewTimer = setInterval(pruneLiveFeed, 60000);
668+
}
643669

644670
function showSettingsTab(name, btn) {
645671
document.querySelectorAll('.settings-pane').forEach(p => p.classList.remove('active'));

src/routes/api.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@ router.get('/dashboard', async (req, res) => {
5353
});
5454

5555
router.get('/logs', (req, res) => {
56-
const { show, type, from, to } = req.query;
56+
const { show, type, from, to, before } = req.query;
5757
const limit = Math.min(parseInt(req.query.limit ?? '50', 10), 200);
5858
const page = Math.max(parseInt(req.query.page ?? '1', 10), 1);
5959
const offset = (page - 1) * limit;
6060
try {
61-
const result = getActivityFiltered({ show, type, from, to }, limit, offset);
61+
const result = getActivityFiltered({ show, type, from, to, before }, limit, offset);
6262
res.json({ rows: result.rows, total: result.total, page, limit, totalPages: Math.ceil(result.total / limit) });
6363
} catch (err) { res.status(500).json({ error: err.message }); }
6464
});
@@ -69,7 +69,9 @@ router.get('/logs/stream', (req, res) => {
6969
res.setHeader('Connection', 'keep-alive');
7070
res.flushHeaders();
7171

72-
const recent = getRecentActivity(20).reverse();
72+
// Seed with events from the last 10 minutes only
73+
const tenMinsAgo = new Date(Date.now() - 10 * 60 * 1000).toISOString();
74+
const recent = getActivityFiltered({ from: tenMinsAgo }, 200, 0).rows.reverse();
7375
for (const row of recent) res.write('data: ' + JSON.stringify(row) + '\n\n');
7476

7577
addSseClient(res);

0 commit comments

Comments
 (0)