various: simplify code; work on security and performance

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I9a5114addcab5fbff430ab2b919b83466a6a6964
This commit is contained in:
raf 2026-02-02 17:32:11 +03:00
commit c4adc4e3e0
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
75 changed files with 12921 additions and 358 deletions

View file

@ -7,9 +7,18 @@ use std::sync::Arc;
use uuid::Uuid;
use chrono::{DateTime, Utc};
use crate::analytics::UsageEvent;
use crate::enrichment::ExternalMetadata;
use crate::error::Result;
use crate::model::*;
use crate::playlists::Playlist;
use crate::search::{SearchRequest, SearchResults};
use crate::social::{Comment, Rating, ShareLink};
use crate::subtitles::Subtitle;
use crate::transcode::{TranscodeSession, TranscodeStatus};
use crate::users::UserId;
/// Statistics about the database.
#[derive(Debug, Clone, Default)]
@ -187,6 +196,167 @@ pub trait StorageBackend: Send + Sync + 'static {
// Library statistics
async fn library_statistics(&self) -> Result<LibraryStatistics>;
// User Management
async fn list_users(&self) -> Result<Vec<crate::users::User>>;
async fn get_user(&self, id: crate::users::UserId) -> Result<crate::users::User>;
async fn get_user_by_username(&self, username: &str) -> Result<crate::users::User>;
async fn create_user(
&self,
username: &str,
password_hash: &str,
role: crate::config::UserRole,
profile: Option<crate::users::UserProfile>,
) -> Result<crate::users::User>;
async fn update_user(
&self,
id: crate::users::UserId,
password_hash: Option<&str>,
role: Option<crate::config::UserRole>,
profile: Option<crate::users::UserProfile>,
) -> Result<crate::users::User>;
async fn delete_user(&self, id: crate::users::UserId) -> Result<()>;
async fn get_user_libraries(
&self,
user_id: crate::users::UserId,
) -> Result<Vec<crate::users::UserLibraryAccess>>;
async fn grant_library_access(
&self,
user_id: crate::users::UserId,
root_path: &str,
permission: crate::users::LibraryPermission,
) -> Result<()>;
async fn revoke_library_access(
&self,
user_id: crate::users::UserId,
root_path: &str,
) -> Result<()>;
// ===== Ratings =====
async fn rate_media(
&self,
user_id: UserId,
media_id: MediaId,
stars: u8,
review: Option<&str>,
) -> Result<Rating>;
async fn get_media_ratings(&self, media_id: MediaId) -> Result<Vec<Rating>>;
async fn get_user_rating(&self, user_id: UserId, media_id: MediaId) -> Result<Option<Rating>>;
async fn delete_rating(&self, id: Uuid) -> Result<()>;
// ===== Comments =====
async fn add_comment(
&self,
user_id: UserId,
media_id: MediaId,
text: &str,
parent_id: Option<Uuid>,
) -> Result<Comment>;
async fn get_media_comments(&self, media_id: MediaId) -> Result<Vec<Comment>>;
async fn delete_comment(&self, id: Uuid) -> Result<()>;
// ===== Favorites =====
async fn add_favorite(&self, user_id: UserId, media_id: MediaId) -> Result<()>;
async fn remove_favorite(&self, user_id: UserId, media_id: MediaId) -> Result<()>;
async fn get_user_favorites(
&self,
user_id: UserId,
pagination: &Pagination,
) -> Result<Vec<MediaItem>>;
async fn is_favorite(&self, user_id: UserId, media_id: MediaId) -> Result<bool>;
// ===== Share Links =====
async fn create_share_link(
&self,
media_id: MediaId,
created_by: UserId,
token: &str,
password_hash: Option<&str>,
expires_at: Option<DateTime<Utc>>,
) -> Result<ShareLink>;
async fn get_share_link(&self, token: &str) -> Result<ShareLink>;
async fn increment_share_views(&self, token: &str) -> Result<()>;
async fn delete_share_link(&self, id: Uuid) -> Result<()>;
// ===== Playlists =====
async fn create_playlist(
&self,
owner_id: UserId,
name: &str,
description: Option<&str>,
is_public: bool,
is_smart: bool,
filter_query: Option<&str>,
) -> Result<Playlist>;
async fn get_playlist(&self, id: Uuid) -> Result<Playlist>;
async fn list_playlists(&self, owner_id: Option<UserId>) -> Result<Vec<Playlist>>;
async fn update_playlist(
&self,
id: Uuid,
name: Option<&str>,
description: Option<&str>,
is_public: Option<bool>,
) -> Result<Playlist>;
async fn delete_playlist(&self, id: Uuid) -> Result<()>;
async fn add_to_playlist(
&self,
playlist_id: Uuid,
media_id: MediaId,
position: i32,
) -> Result<()>;
async fn remove_from_playlist(&self, playlist_id: Uuid, media_id: MediaId) -> Result<()>;
async fn get_playlist_items(&self, playlist_id: Uuid) -> Result<Vec<MediaItem>>;
async fn reorder_playlist(
&self,
playlist_id: Uuid,
media_id: MediaId,
new_position: i32,
) -> Result<()>;
// ===== Analytics =====
async fn record_usage_event(&self, event: &UsageEvent) -> Result<()>;
async fn get_usage_events(
&self,
media_id: Option<MediaId>,
user_id: Option<UserId>,
limit: u64,
) -> Result<Vec<UsageEvent>>;
async fn get_most_viewed(&self, limit: u64) -> Result<Vec<(MediaItem, u64)>>;
async fn get_recently_viewed(&self, user_id: UserId, limit: u64) -> Result<Vec<MediaItem>>;
async fn update_watch_progress(
&self,
user_id: UserId,
media_id: MediaId,
progress_secs: f64,
) -> Result<()>;
async fn get_watch_progress(&self, user_id: UserId, media_id: MediaId) -> Result<Option<f64>>;
async fn cleanup_old_events(&self, before: DateTime<Utc>) -> Result<u64>;
// ===== Subtitles =====
async fn add_subtitle(&self, subtitle: &Subtitle) -> Result<()>;
async fn get_media_subtitles(&self, media_id: MediaId) -> Result<Vec<Subtitle>>;
async fn delete_subtitle(&self, id: Uuid) -> Result<()>;
async fn update_subtitle_offset(&self, id: Uuid, offset_ms: i64) -> Result<()>;
// ===== External Metadata (Enrichment) =====
async fn store_external_metadata(&self, meta: &ExternalMetadata) -> Result<()>;
async fn get_external_metadata(&self, media_id: MediaId) -> Result<Vec<ExternalMetadata>>;
async fn delete_external_metadata(&self, id: Uuid) -> Result<()>;
// ===== Transcode Sessions =====
async fn create_transcode_session(&self, session: &TranscodeSession) -> Result<()>;
async fn get_transcode_session(&self, id: Uuid) -> Result<TranscodeSession>;
async fn list_transcode_sessions(
&self,
media_id: Option<MediaId>,
) -> Result<Vec<TranscodeSession>>;
async fn update_transcode_status(
&self,
id: Uuid,
status: TranscodeStatus,
progress: f32,
) -> Result<()>;
async fn cleanup_expired_transcodes(&self, before: DateTime<Utc>) -> Result<u64>;
}
/// Comprehensive library statistics.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff