various: simplify code; work on security and performance
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I9a5114addcab5fbff430ab2b919b83466a6a6964
This commit is contained in:
parent
016841b200
commit
c4adc4e3e0
75 changed files with 12921 additions and 358 deletions
|
|
@ -551,3 +551,431 @@ impl From<pinakes_core::model::AuditEntry> for AuditEntryResponse {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Plugins
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct PluginResponse {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub version: String,
|
||||
pub author: String,
|
||||
pub description: String,
|
||||
pub api_version: String,
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct InstallPluginRequest {
|
||||
pub source: String, // URL or file path
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct TogglePluginRequest {
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
impl PluginResponse {
|
||||
pub fn new(meta: pinakes_plugin_api::PluginMetadata, enabled: bool) -> Self {
|
||||
Self {
|
||||
id: meta.id,
|
||||
name: meta.name,
|
||||
version: meta.version,
|
||||
author: meta.author,
|
||||
description: meta.description,
|
||||
api_version: meta.api_version,
|
||||
enabled,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Users
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct UserResponse {
|
||||
pub id: String,
|
||||
pub username: String,
|
||||
pub role: String,
|
||||
pub profile: UserProfileResponse,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct UserProfileResponse {
|
||||
pub avatar_path: Option<String>,
|
||||
pub bio: Option<String>,
|
||||
pub preferences: UserPreferencesResponse,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct UserPreferencesResponse {
|
||||
pub theme: Option<String>,
|
||||
pub language: Option<String>,
|
||||
pub default_video_quality: Option<String>,
|
||||
pub auto_play: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct UserLibraryResponse {
|
||||
pub user_id: String,
|
||||
pub root_path: String,
|
||||
pub permission: String,
|
||||
pub granted_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct GrantLibraryAccessRequest {
|
||||
pub root_path: String,
|
||||
pub permission: pinakes_core::users::LibraryPermission,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct RevokeLibraryAccessRequest {
|
||||
pub root_path: String,
|
||||
}
|
||||
|
||||
impl From<pinakes_core::users::User> for UserResponse {
|
||||
fn from(user: pinakes_core::users::User) -> Self {
|
||||
Self {
|
||||
id: user.id.0.to_string(),
|
||||
username: user.username,
|
||||
role: user.role.to_string(),
|
||||
profile: UserProfileResponse {
|
||||
avatar_path: user.profile.avatar_path,
|
||||
bio: user.profile.bio,
|
||||
preferences: UserPreferencesResponse {
|
||||
theme: user.profile.preferences.theme,
|
||||
language: user.profile.preferences.language,
|
||||
default_video_quality: user.profile.preferences.default_video_quality,
|
||||
auto_play: user.profile.preferences.auto_play,
|
||||
},
|
||||
},
|
||||
created_at: user.created_at,
|
||||
updated_at: user.updated_at,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pinakes_core::users::UserLibraryAccess> for UserLibraryResponse {
|
||||
fn from(access: pinakes_core::users::UserLibraryAccess) -> Self {
|
||||
Self {
|
||||
user_id: access.user_id.0.to_string(),
|
||||
root_path: access.root_path,
|
||||
permission: format!("{:?}", access.permission).to_lowercase(),
|
||||
granted_at: access.granted_at,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Social (Ratings, Comments, Favorites, Shares) =====
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct RatingResponse {
|
||||
pub id: String,
|
||||
pub user_id: String,
|
||||
pub media_id: String,
|
||||
pub stars: u8,
|
||||
pub review_text: Option<String>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl From<pinakes_core::social::Rating> for RatingResponse {
|
||||
fn from(r: pinakes_core::social::Rating) -> Self {
|
||||
Self {
|
||||
id: r.id.to_string(),
|
||||
user_id: r.user_id.0.to_string(),
|
||||
media_id: r.media_id.0.to_string(),
|
||||
stars: r.stars,
|
||||
review_text: r.review_text,
|
||||
created_at: r.created_at,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct CreateRatingRequest {
|
||||
pub stars: u8,
|
||||
pub review_text: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct CommentResponse {
|
||||
pub id: String,
|
||||
pub user_id: String,
|
||||
pub media_id: String,
|
||||
pub parent_comment_id: Option<String>,
|
||||
pub text: String,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl From<pinakes_core::social::Comment> for CommentResponse {
|
||||
fn from(c: pinakes_core::social::Comment) -> Self {
|
||||
Self {
|
||||
id: c.id.to_string(),
|
||||
user_id: c.user_id.0.to_string(),
|
||||
media_id: c.media_id.0.to_string(),
|
||||
parent_comment_id: c.parent_comment_id.map(|id| id.to_string()),
|
||||
text: c.text,
|
||||
created_at: c.created_at,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct CreateCommentRequest {
|
||||
pub text: String,
|
||||
pub parent_id: Option<Uuid>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct FavoriteRequest {
|
||||
pub media_id: Uuid,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct CreateShareLinkRequest {
|
||||
pub media_id: Uuid,
|
||||
pub password: Option<String>,
|
||||
pub expires_in_hours: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct ShareLinkResponse {
|
||||
pub id: String,
|
||||
pub media_id: String,
|
||||
pub token: String,
|
||||
pub expires_at: Option<DateTime<Utc>>,
|
||||
pub view_count: u64,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl From<pinakes_core::social::ShareLink> for ShareLinkResponse {
|
||||
fn from(s: pinakes_core::social::ShareLink) -> Self {
|
||||
Self {
|
||||
id: s.id.to_string(),
|
||||
media_id: s.media_id.0.to_string(),
|
||||
token: s.token,
|
||||
expires_at: s.expires_at,
|
||||
view_count: s.view_count,
|
||||
created_at: s.created_at,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Playlists =====
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct PlaylistResponse {
|
||||
pub id: String,
|
||||
pub owner_id: String,
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub is_public: bool,
|
||||
pub is_smart: bool,
|
||||
pub filter_query: Option<String>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl From<pinakes_core::playlists::Playlist> for PlaylistResponse {
|
||||
fn from(p: pinakes_core::playlists::Playlist) -> Self {
|
||||
Self {
|
||||
id: p.id.to_string(),
|
||||
owner_id: p.owner_id.0.to_string(),
|
||||
name: p.name,
|
||||
description: p.description,
|
||||
is_public: p.is_public,
|
||||
is_smart: p.is_smart,
|
||||
filter_query: p.filter_query,
|
||||
created_at: p.created_at,
|
||||
updated_at: p.updated_at,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct CreatePlaylistRequest {
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
pub is_public: Option<bool>,
|
||||
pub is_smart: Option<bool>,
|
||||
pub filter_query: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct UpdatePlaylistRequest {
|
||||
pub name: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub is_public: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct PlaylistItemRequest {
|
||||
pub media_id: Uuid,
|
||||
pub position: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ReorderPlaylistRequest {
|
||||
pub media_id: Uuid,
|
||||
pub new_position: i32,
|
||||
}
|
||||
|
||||
// ===== Analytics =====
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct UsageEventResponse {
|
||||
pub id: String,
|
||||
pub media_id: Option<String>,
|
||||
pub user_id: Option<String>,
|
||||
pub event_type: String,
|
||||
pub timestamp: DateTime<Utc>,
|
||||
pub duration_secs: Option<f64>,
|
||||
}
|
||||
|
||||
impl From<pinakes_core::analytics::UsageEvent> for UsageEventResponse {
|
||||
fn from(e: pinakes_core::analytics::UsageEvent) -> Self {
|
||||
Self {
|
||||
id: e.id.to_string(),
|
||||
media_id: e.media_id.map(|m| m.0.to_string()),
|
||||
user_id: e.user_id.map(|u| u.0.to_string()),
|
||||
event_type: e.event_type.to_string(),
|
||||
timestamp: e.timestamp,
|
||||
duration_secs: e.duration_secs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct RecordUsageEventRequest {
|
||||
pub media_id: Option<Uuid>,
|
||||
pub event_type: String,
|
||||
pub duration_secs: Option<f64>,
|
||||
pub context: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct MostViewedResponse {
|
||||
pub media: MediaResponse,
|
||||
pub view_count: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct WatchProgressRequest {
|
||||
pub progress_secs: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct WatchProgressResponse {
|
||||
pub progress_secs: f64,
|
||||
}
|
||||
|
||||
// ===== Subtitles =====
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct SubtitleResponse {
|
||||
pub id: String,
|
||||
pub media_id: String,
|
||||
pub language: Option<String>,
|
||||
pub format: String,
|
||||
pub is_embedded: bool,
|
||||
pub track_index: Option<usize>,
|
||||
pub offset_ms: i64,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl From<pinakes_core::subtitles::Subtitle> for SubtitleResponse {
|
||||
fn from(s: pinakes_core::subtitles::Subtitle) -> Self {
|
||||
Self {
|
||||
id: s.id.to_string(),
|
||||
media_id: s.media_id.0.to_string(),
|
||||
language: s.language,
|
||||
format: s.format.to_string(),
|
||||
is_embedded: s.is_embedded,
|
||||
track_index: s.track_index,
|
||||
offset_ms: s.offset_ms,
|
||||
created_at: s.created_at,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct AddSubtitleRequest {
|
||||
pub language: Option<String>,
|
||||
pub format: String,
|
||||
pub file_path: Option<String>,
|
||||
pub is_embedded: Option<bool>,
|
||||
pub track_index: Option<usize>,
|
||||
pub offset_ms: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct UpdateSubtitleOffsetRequest {
|
||||
pub offset_ms: i64,
|
||||
}
|
||||
|
||||
// ===== Enrichment =====
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct ExternalMetadataResponse {
|
||||
pub id: String,
|
||||
pub media_id: String,
|
||||
pub source: String,
|
||||
pub external_id: Option<String>,
|
||||
pub metadata: serde_json::Value,
|
||||
pub confidence: f64,
|
||||
pub last_updated: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl From<pinakes_core::enrichment::ExternalMetadata> for ExternalMetadataResponse {
|
||||
fn from(m: pinakes_core::enrichment::ExternalMetadata) -> Self {
|
||||
let metadata = serde_json::from_str(&m.metadata_json).unwrap_or_else(|e| {
|
||||
tracing::warn!(
|
||||
"failed to deserialize external metadata JSON for media {}: {}",
|
||||
m.media_id.0,
|
||||
e
|
||||
);
|
||||
serde_json::Value::Null
|
||||
});
|
||||
Self {
|
||||
id: m.id.to_string(),
|
||||
media_id: m.media_id.0.to_string(),
|
||||
source: m.source.to_string(),
|
||||
external_id: m.external_id,
|
||||
metadata,
|
||||
confidence: m.confidence,
|
||||
last_updated: m.last_updated,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Transcode =====
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct TranscodeSessionResponse {
|
||||
pub id: String,
|
||||
pub media_id: String,
|
||||
pub profile: String,
|
||||
pub status: String,
|
||||
pub progress: f32,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub expires_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl From<pinakes_core::transcode::TranscodeSession> for TranscodeSessionResponse {
|
||||
fn from(s: pinakes_core::transcode::TranscodeSession) -> Self {
|
||||
Self {
|
||||
id: s.id.to_string(),
|
||||
media_id: s.media_id.0.to_string(),
|
||||
profile: s.profile,
|
||||
status: s.status.as_str().to_string(),
|
||||
progress: s.progress,
|
||||
created_at: s.created_at,
|
||||
expires_at: s.expires_at,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct CreateTranscodeRequest {
|
||||
pub profile: String,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue