From 249844160fe845f05ff2e603a886c2072ee1391f Mon Sep 17 00:00:00 2001 From: glenneth Date: Sun, 11 Jan 2026 20:00:21 +0300 Subject: [PATCH] Fix listener minutes tracking for accurate geo stats - Add register-web-listener to now-playing-json API endpoint This keeps listeners registered during continuous playback instead of timing out after 5 minutes of inactivity - Fix listen_minutes calculation to increment by listener_count per poll Previously incremented by 1 regardless of how many listeners, now properly tracks listener-minutes (1 minute per listener per 60s poll interval) - Add migration 009 documenting the calculation fix --- frontend-partials.lisp | 2 ++ listener-stats.lisp | 8 +++--- .../009-fix-listen-minutes-calculation.sql | 28 +++++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 migrations/009-fix-listen-minutes-calculation.sql diff --git a/frontend-partials.lisp b/frontend-partials.lisp index 88018e6..62b856f 100644 --- a/frontend-partials.lisp +++ b/frontend-partials.lisp @@ -138,6 +138,8 @@ (define-api-with-limit asteroid/partial/now-playing-json (&optional mount) (:limit 2 :timeout 1) "Get JSON with now playing info including track ID for favorites. Optional MOUNT parameter specifies which stream to get metadata from." + ;; Register web listener for geo stats (keeps listener active during playback) + (register-web-listener) (with-error-handling (let* ((mount-name (or mount "asteroid.mp3")) (now-playing-stats (icecast-now-playing *stream-base-url* mount-name))) diff --git a/listener-stats.lisp b/listener-stats.lisp index d6d9ec6..69dbb3e 100644 --- a/listener-stats.lisp +++ b/listener-stats.lisp @@ -268,18 +268,18 @@ (defun update-geo-stats (country-code listener-count &optional city) "Update geo stats for today, optionally including city. listener_count tracks peak concurrent listeners (max seen today). - listen_minutes increments by 1 per poll (approximates total listen time)." + listen_minutes increments by listener_count per poll (1 minute per listener per poll)." (when country-code (handler-case (with-db (let ((city-sql (if city (format nil "'~a'" city) "NULL"))) (postmodern:execute (format nil "INSERT INTO listener_geo_stats (date, country_code, city, listener_count, listen_minutes) - VALUES (CURRENT_DATE, '~a', ~a, ~a, 1) + VALUES (CURRENT_DATE, '~a', ~a, ~a, ~a) ON CONFLICT (date, country_code, city) DO UPDATE SET listener_count = GREATEST(listener_geo_stats.listener_count, ~a), - listen_minutes = listener_geo_stats.listen_minutes + 1" - country-code city-sql listener-count listener-count)))) + listen_minutes = listener_geo_stats.listen_minutes + ~a" + country-code city-sql listener-count listener-count listener-count listener-count)))) (error (e) (log:error "Failed to update geo stats: ~a" e))))) diff --git a/migrations/009-fix-listen-minutes-calculation.sql b/migrations/009-fix-listen-minutes-calculation.sql new file mode 100644 index 0000000..544ff55 --- /dev/null +++ b/migrations/009-fix-listen-minutes-calculation.sql @@ -0,0 +1,28 @@ +-- Migration: Fix Listen Minutes Calculation +-- Version: 009 +-- Date: 2026-01-11 +-- Description: Document the fix for listen_minutes calculation +-- +-- ISSUE: listen_minutes was incrementing by 1 per poll regardless of listener count. +-- This meant a country with 5 listeners for 1 hour would only show 60 minutes, +-- not 300 listener-minutes. +-- +-- FIX: Application code in listener-stats.lisp now increments listen_minutes by +-- the listener_count value (1 minute per listener per poll interval). +-- +-- ADDITIONAL FIX: register-web-listener is now called from the now-playing-json API +-- endpoint, keeping listeners registered during continuous playback +-- instead of timing out after 5 minutes. +-- +-- No schema changes required - this migration documents the application logic fix. + +-- Add a comment to the table for future reference +COMMENT ON COLUMN listener_geo_stats.listen_minutes IS + 'Total listener-minutes: increments by listener_count per poll (1 min per listener per 60s poll)'; + +-- Success message +DO $$ +BEGIN + RAISE NOTICE 'Migration 009: listen_minutes calculation fix documented'; + RAISE NOTICE 'listen_minutes now represents true listener-minutes (count * time)'; +END $$;