feat: implement multi-provider support in media library

- Introduced IProviderRegistry to manage multiple media providers.
- Updated AppState to use provider_registry instead of a single media_provider.
- Refactored library routes to support provider-specific queries for collections, series, genres, and items.
- Enhanced ProgrammingBlock to include provider_id for algorithmic and manual content types.
- Modified frontend components to allow selection of providers and updated API calls to include provider parameters.
- Adjusted hooks and types to accommodate provider-specific functionality.
This commit is contained in:
2026-03-14 23:59:21 +01:00
parent c53892159a
commit ead65e6be2
21 changed files with 468 additions and 150 deletions

View File

@@ -1,8 +1,7 @@
use std::sync::Arc;
use domain::{
ChannelService, ContentType, IMediaProvider, ProgrammingBlock, ScheduleConfig,
ScheduleEngineService,
ChannelService, ContentType, ProgrammingBlock, ScheduleConfig, ScheduleEngineService,
};
use rmcp::{
ServerHandler,
@@ -19,7 +18,7 @@ use crate::tools::{channels, library, schedule};
pub struct KTvMcpServer {
pub channel_service: Arc<ChannelService>,
pub schedule_engine: Arc<ScheduleEngineService>,
pub media_provider: Arc<dyn IMediaProvider>,
pub provider_registry: Arc<infra::ProviderRegistry>,
pub owner_id: Uuid,
}
@@ -244,7 +243,7 @@ impl KTvMcpServer {
#[tool(description = "List media collections/libraries available in the configured provider")]
async fn list_collections(&self) -> String {
library::list_collections(&self.media_provider).await
library::list_collections(&self.provider_registry).await
}
#[tool(
@@ -252,7 +251,7 @@ impl KTvMcpServer {
)]
async fn list_genres(&self, #[tool(aggr)] p: ListGenresParams) -> String {
let ct = p.content_type.as_deref().and_then(parse_content_type);
library::list_genres(&self.media_provider, ct).await
library::list_genres(&self.provider_registry, ct).await
}
#[tool(
@@ -261,7 +260,7 @@ impl KTvMcpServer {
async fn search_media(&self, #[tool(aggr)] p: SearchMediaParams) -> String {
let ct = p.content_type.as_deref().and_then(parse_content_type);
library::search_media(
&self.media_provider,
&self.provider_registry,
ct,
p.genres.unwrap_or_default(),
p.search_term,