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
This commit is contained in:
glenneth 2026-01-11 20:00:21 +03:00 committed by Brian O'Reilly
parent 8b6209e4e0
commit 249844160f
3 changed files with 34 additions and 4 deletions

View File

@ -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)))

View File

@ -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)))))

View File

@ -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 $$;