update viewers page
This commit is contained in:
+74
-23
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user