pinakes/crates/pinakes-core/src/analytics.rs
NotAShelf 3ccddce7fd
treewide: fix various UI bugs; optimize crypto dependencies & format
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: If8fe8b38c1d9c4fecd40ff71f88d2ae06a6a6964
2026-03-06 18:29:33 +03:00

68 lines
1.7 KiB
Rust

//! Usage analytics and watch history tracking.
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::{model::MediaId, users::UserId};
/// A tracked usage event for a media item.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UsageEvent {
pub id: Uuid,
pub media_id: Option<MediaId>,
pub user_id: Option<UserId>,
pub event_type: UsageEventType,
pub timestamp: DateTime<Utc>,
pub duration_secs: Option<f64>,
pub context_json: Option<String>,
}
/// Types of usage events that can be tracked.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum UsageEventType {
View,
Play,
Export,
Share,
Search,
}
impl std::fmt::Display for UsageEventType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
Self::View => "view",
Self::Play => "play",
Self::Export => "export",
Self::Share => "share",
Self::Search => "search",
};
write!(f, "{s}")
}
}
impl std::str::FromStr for UsageEventType {
type Err = String;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match s {
"view" => Ok(Self::View),
"play" => Ok(Self::Play),
"export" => Ok(Self::Export),
"share" => Ok(Self::Share),
"search" => Ok(Self::Search),
_ => Err(format!("unknown usage event type: {s}")),
}
}
}
/// Watch history entry tracking progress through media.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WatchHistory {
pub id: Uuid,
pub user_id: UserId,
pub media_id: MediaId,
pub progress_secs: f64,
pub last_watched: DateTime<Utc>,
}