Fixed video statistics
Build and Publish / Build and Publish Docker Image (push) Successful in 1m43s

This commit is contained in:
ab
2026-09-20 20:03:55 +03:00
parent 8168d33440
commit 95154c56e7
2 changed files with 35 additions and 5 deletions
+21
View File
@@ -315,6 +315,27 @@ pub async fn load_events(
) )
} }
/// Whether this visitor already opened this media within the given window.
///
/// Used to count a media open once regardless of storage backend or file type:
/// a video streams via many HTTP range requests, and this collapses them (plus
/// quick re-opens) into a single counted view.
pub async fn media_viewed_recently(
db: &Database,
media_id: i64,
visitor: &str,
within: Duration,
) -> cot::Result<bool> {
let cutoff = chrono::Utc::now().naive_utc() - within;
let visitor_owned = visitor.to_string();
let events = query!(AnalyticsEvent, $visitor_hash == visitor_owned)
.all(db)
.await?;
Ok(events.iter().any(|e| {
e.event_type == "media_view" && e.media_id == Some(media_id) && e.created_at >= cutoff
}))
}
/// Loads a page of recent events, newest first, for the event log. /// Loads a page of recent events, newest first, for the event log.
/// ///
/// Cursor pagination by descending id: pass the id of the oldest event already /// Cursor pagination by descending id: pass the id of the oldest event already
+12 -3
View File
@@ -940,11 +940,20 @@ async fn portal_media(
.and_then(|value| value.to_str().ok()) .and_then(|value| value.to_str().ok())
.map(str::to_owned); .map(str::to_owned);
// Analytics: count full-size media opens. Only count the initial request, // Analytics: count full-size media opens (photos and videos alike). A video
// not subsequent HTTP range/seek requests for the same file. // streams via many HTTP range requests, so we dedupe by visitor+media within
if range.is_none() { // a short window to count a single open instead of every chunk/seek.
let visitor_id = crate::analytics::visitor_id_from_request(&request) let visitor_id = crate::analytics::visitor_id_from_request(&request)
.unwrap_or_else(crate::analytics::new_visitor_id); .unwrap_or_else(crate::analytics::new_visitor_id);
let recently_viewed = crate::analytics::media_viewed_recently(
&db,
media_id,
&visitor_id,
chrono::Duration::minutes(30),
)
.await
.unwrap_or(false);
if !recently_viewed {
crate::analytics::record( crate::analytics::record(
&db, &db,
EventType::MediaView, EventType::MediaView,