update viewers page

This commit is contained in:
2026-05-16 07:42:53 +01:00
parent eec70b39aa
commit a586282b3f
4 changed files with 305 additions and 100 deletions
+74 -23
View File
@@ -500,15 +500,18 @@ function readJsonBody(req) {
}
function purgeOldAnalytics(db) {
const eventCutoff = new Date(Date.now() - ANALYTICS_RETENTION_DAYS * 24 * 60 * 60 * 1000).toISOString()
const activeCutoff = new Date(Date.now() - ANALYTICS_ACTIVE_WINDOW_SECONDS * 3 * 1000).toISOString()
db.prepare(`
delete from viewer_events
where occurred_at < datetime('now', ?)
`).run(`-${ANALYTICS_RETENTION_DAYS} days`)
where occurred_at < ?
`).run(eventCutoff)
db.prepare(`
delete from active_viewers
where last_seen_at < datetime('now', ?)
`).run(`-${ANALYTICS_ACTIVE_WINDOW_SECONDS * 3} seconds`)
where last_seen_at < ?
`).run(activeCutoff)
}
function recordViewerEvent(req, payload) {
@@ -612,12 +615,14 @@ function viewerDashboard() {
const db = ensureAnalyticsDb()
purgeOldAnalytics(db)
const activeSince = `-${ANALYTICS_ACTIVE_WINDOW_SECONDS} seconds`
const activeSince = new Date(Date.now() - ANALYTICS_ACTIVE_WINDOW_SECONDS * 1000).toISOString()
const daySince = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString()
const thirtyDaysSince = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString()
const active = db.prepare(`
select session_id, visitor_id, first_seen_at, last_seen_at, page_path, page_title,
referrer, browser, os, device, screen, language, timezone, country
from active_viewers
where last_seen_at >= datetime('now', ?)
where last_seen_at >= ?
order by last_seen_at desc
limit 100
`).all(activeSince).map((row) => ({
@@ -637,65 +642,110 @@ function viewerDashboard() {
country: row.country,
}))
const activePageMap = new Map()
for (const viewer of active) {
const key = `${viewer.page_path}|${viewer.page_title}`
const existing = activePageMap.get(key) || {
page_path: viewer.page_path,
page_title: viewer.page_title,
viewers: 0,
visitors: new Set(),
clients: new Map(),
countries: new Set(),
last_seen_at: viewer.last_seen_at,
}
existing.viewers += 1
existing.visitors.add(viewer.visitor)
if (viewer.country) existing.countries.add(viewer.country)
const clientKey = `${viewer.browser} on ${viewer.os}`
existing.clients.set(clientKey, (existing.clients.get(clientKey) || 0) + 1)
if (new Date(viewer.last_seen_at).getTime() > new Date(existing.last_seen_at).getTime()) {
existing.last_seen_at = viewer.last_seen_at
}
activePageMap.set(key, existing)
}
const activePages = Array.from(activePageMap.values())
.map((page) => ({
page_path: page.page_path,
page_title: page.page_title,
viewers: page.viewers,
visitors: page.visitors.size,
countries: Array.from(page.countries).sort(),
clients: Array.from(page.clients.entries())
.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))
.slice(0, 4)
.map(([label, count]) => ({ label, count })),
last_seen_at: page.last_seen_at,
}))
.sort((a, b) => b.viewers - a.viewers || new Date(b.last_seen_at) - new Date(a.last_seen_at))
const topPages = db.prepare(`
select page_path, page_title, count(*) as views
from viewer_events
where event_type = 'page_view'
and occurred_at >= datetime('now', '-24 hours')
and occurred_at >= ?
group by page_path, page_title
order by views desc, page_path asc
limit 12
`).all()
`).all(daySince)
const clients = db.prepare(`
select browser, os, device, count(*) as events
from viewer_events
where occurred_at >= datetime('now', '-24 hours')
where occurred_at >= ?
group by browser, os, device
order by events desc
limit 12
`).all()
`).all(daySince)
const clients30d = db.prepare(`
select browser, os, device, count(*) as events, count(distinct visitor_id) as visitors
from viewer_events
where occurred_at >= datetime('now', '-30 days')
where occurred_at >= ?
group by browser, os, device
order by events desc
limit 12
`).all()
`).all(thirtyDaysSince)
const activity30d = db.prepare(`
select
date(occurred_at) as date,
count(*) as events,
count(distinct visitor_id) as visitors,
sum(case when event_type = 'page_view' then 1 else 0 end) as page_views
sum(case when event_type = 'page_view' then 1 else 0 end) as page_views,
count(distinct browser || '|' || os || '|' || device) as clients,
count(distinct case
when country != '' then country
when timezone != '' and timezone != 'Not shared' then timezone
else null
end) as locations
from viewer_events
where occurred_at >= datetime('now', '-30 days')
where occurred_at >= ?
group by date(occurred_at)
order by date asc
`).all()
`).all(thirtyDaysSince)
const countries = db.prepare(`
select country, count(*) as events, count(distinct visitor_id) as visitors
from viewer_events
where occurred_at >= datetime('now', '-30 days')
where occurred_at >= ?
and country != ''
group by country
order by visitors desc, events desc
limit 80
`).all()
`).all(thirtyDaysSince)
const locations = db.prepare(`
select country, timezone, language, count(*) as events, count(distinct visitor_id) as visitors
from viewer_events
where occurred_at >= datetime('now', '-30 days')
where occurred_at >= ?
and (country != '' or (timezone != '' and timezone != 'Not shared'))
group by country, timezone, language
order by visitors desc, events desc
limit 32
`).all()
`).all(thirtyDaysSince)
const totals = db.prepare(`
select
@@ -703,8 +753,8 @@ function viewerDashboard() {
count(distinct visitor_id) as visitors_24h,
sum(case when event_type = 'page_view' then 1 else 0 end) as page_views_24h
from viewer_events
where occurred_at >= datetime('now', '-24 hours')
`).get()
where occurred_at >= ?
`).get(daySince)
const totals30d = db.prepare(`
select
@@ -713,13 +763,14 @@ function viewerDashboard() {
count(distinct session_id) as sessions_30d,
sum(case when event_type = 'page_view' then 1 else 0 end) as page_views_30d
from viewer_events
where occurred_at >= datetime('now', '-30 days')
`).get()
where occurred_at >= ?
`).get(thirtyDaysSince)
return {
active_window_seconds: ANALYTICS_ACTIVE_WINDOW_SECONDS,
generated_at: new Date().toISOString(),
active,
active_pages: activePages,
top_pages: topPages,
clients,
clients_30d: clients30d,