Fixed video statistics
Build and Publish / Build and Publish Docker Image (push) Successful in 1m43s
Build and Publish / Build and Publish Docker Image (push) Successful in 1m43s
This commit is contained in:
@@ -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
|
||||||
|
|||||||
+14
-5
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user