feat: add local files provider with indexing and rescan functionality

- Implemented LocalFilesProvider to manage local video files.
- Added LocalIndex for in-memory and SQLite-backed indexing of video files.
- Introduced scanning functionality to detect video files and extract metadata.
- Added API endpoints for listing collections, genres, and series based on provider capabilities.
- Enhanced existing routes to check for provider capabilities before processing requests.
- Updated frontend to utilize provider capabilities for conditional rendering of UI elements.
- Implemented rescan functionality to refresh the local files index.
- Added database migration for local files index schema.
This commit is contained in:
2026-03-14 03:44:32 +01:00
parent 9b6bcfc566
commit 8f42164bce
30 changed files with 1033 additions and 59 deletions

View File

@@ -14,7 +14,7 @@ pub mod value_objects;
// Re-export commonly used types
pub use entities::*;
pub use errors::{DomainError, DomainResult};
pub use ports::{Collection, IMediaProvider, SeriesSummary};
pub use ports::{Collection, IMediaProvider, ProviderCapabilities, SeriesSummary, StreamingProtocol};
pub use repositories::*;
pub use iptv::{generate_m3u, generate_xmltv};
pub use services::{ChannelService, ScheduleEngineService, UserService};

View File

@@ -12,6 +12,37 @@ use crate::entities::MediaItem;
use crate::errors::{DomainError, DomainResult};
use crate::value_objects::{ContentType, MediaFilter, MediaItemId};
// ============================================================================
// Provider capabilities
// ============================================================================
/// How a provider delivers video to the client.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum StreamingProtocol {
/// HLS playlist (`.m3u8`). Requires hls.js on non-Safari browsers.
Hls,
/// Direct file URL with Range-header support. Native `<video>` element.
DirectFile,
}
/// Feature matrix for a media provider.
///
/// The API and frontend use this to gate calls and hide UI controls that
/// the active provider does not support.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProviderCapabilities {
pub collections: bool,
pub series: bool,
pub genres: bool,
pub tags: bool,
pub decade: bool,
pub search: bool,
pub streaming_protocol: StreamingProtocol,
/// Whether `POST /files/rescan` is available.
pub rescan: bool,
}
// ============================================================================
// Library browsing types
// ============================================================================
@@ -58,6 +89,12 @@ pub struct SeriesSummary {
/// `NoopMediaProvider`) inherit the default and return a clear error.
#[async_trait]
pub trait IMediaProvider: Send + Sync {
/// Declare what features this provider supports.
///
/// Called at request time (not cached) so the response always reflects the
/// active provider. Implementations return a plain struct — no I/O needed.
fn capabilities(&self) -> ProviderCapabilities;
/// Fetch metadata for all items matching `filter` from this provider.
///
/// The provider interprets each field of `MediaFilter` in terms of its own