From e60f64ee2b009d1cbfc85f41c8aeadb0bd10287d Mon Sep 17 00:00:00 2001 From: Lukas Kreussel <65088241+LLukas22@users.noreply.github.com> Date: Sun, 1 Feb 2026 14:43:28 +0100 Subject: [PATCH] =?UTF-8?q?Fetch=20Custom=20CSS=20in=20`=E2=80=8B/Branding?= =?UTF-8?q?=E2=80=8B/Configuration`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/jellyfin-api/src/client.rs | 39 +++++++++++++++++++ crates/jellyfin-api/src/models.rs | 10 +++++ .../src/handlers/branding.rs | 26 ++++++++++++- .../jellyswarrm-proxy/src/server_storage.rs | 4 +- 4 files changed, 76 insertions(+), 3 deletions(-) diff --git a/crates/jellyfin-api/src/client.rs b/crates/jellyfin-api/src/client.rs index 4feb84a..3ab9e6a 100644 --- a/crates/jellyfin-api/src/client.rs +++ b/crates/jellyfin-api/src/client.rs @@ -236,6 +236,13 @@ impl JellyfinClient { .await } + pub async fn get_branding_configuration( + &self, + ) -> Result { + self.request(reqwest::Method::GET, "Branding/Configuration", None) + .await + } + // Admin methods pub async fn get_users(&self) -> Result, Error> { @@ -401,4 +408,36 @@ mod tests { assert_eq!(folders.len(), 1); assert_eq!(folders[0].name, "Movies"); } + + #[tokio::test] + async fn test_get_branding_configuration() { + let mock_server = MockServer::start().await; + + let branding_response = json!({ + "LoginDisclaimer": "Welcome to Jellyfin", + "CustomCss": "body { background: black; }", + "SplashscreenEnabled": true + }); + + Mock::given(method("GET")) + .and(path("/Branding/Configuration")) + .respond_with(ResponseTemplate::new(200).set_body_json(branding_response)) + .mount(&mock_server) + .await; + + let client_info = ClientInfo::default(); + let client = JellyfinClient::new(&mock_server.uri(), client_info).unwrap(); + + let config = client.get_branding_configuration().await.unwrap(); + + assert_eq!( + config.login_disclaimer, + Some("Welcome to Jellyfin".to_string()) + ); + assert_eq!( + config.custom_css, + Some("body { background: black; }".to_string()) + ); + assert_eq!(config.splashscreen_enabled, Some(true)); + } } diff --git a/crates/jellyfin-api/src/models.rs b/crates/jellyfin-api/src/models.rs index c4584a3..f32abcc 100644 --- a/crates/jellyfin-api/src/models.rs +++ b/crates/jellyfin-api/src/models.rs @@ -91,3 +91,13 @@ pub struct ItemsResponse { #[serde(rename = "TotalRecordCount")] pub total_record_count: i32, } + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BrandingConfiguration { + #[serde(rename = "LoginDisclaimer")] + pub login_disclaimer: Option, + #[serde(rename = "CustomCss")] + pub custom_css: Option, + #[serde(rename = "SplashscreenEnabled")] + pub splashscreen_enabled: Option, +} diff --git a/crates/jellyswarrm-proxy/src/handlers/branding.rs b/crates/jellyswarrm-proxy/src/handlers/branding.rs index 6dcfe31..e0444f8 100644 --- a/crates/jellyswarrm-proxy/src/handlers/branding.rs +++ b/crates/jellyswarrm-proxy/src/handlers/branding.rs @@ -1,5 +1,6 @@ use axum::{extract::State, Json}; use hyper::StatusCode; +use jellyfin_api::JellyfinClient; use crate::{models::BrandingConfig, AppState}; @@ -13,6 +14,8 @@ pub async fn handle_branding( .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; let mut message = "Jellyswarrm proxying to the following servers: ".to_string(); + let mut custom_css = String::new(); + if !servers.is_empty() { let server_links: Vec = servers .iter() @@ -24,13 +27,34 @@ pub async fn handle_branding( }) .collect(); message.push_str(&server_links.join(", ")); + + for server in servers { + if state + .server_storage + .server_status(server.id) + .await + .is_healthy() + { + if let Ok(client) = JellyfinClient::new_with_client( + server.url.as_ref(), + state.server_storage.client_info.clone(), + state.server_storage.http_client.clone(), + ) { + if let Ok(branding) = client.get_branding_configuration().await { + if let Some(remote_custom_css) = branding.custom_css { + custom_css = remote_custom_css; + } + } + } + } + } } else { message.push_str("No servers configured."); } let config = BrandingConfig { login_disclaimer: message, - custom_css: String::new(), + custom_css, splashscreen_enabled: false, }; Ok(Json(config)) diff --git a/crates/jellyswarrm-proxy/src/server_storage.rs b/crates/jellyswarrm-proxy/src/server_storage.rs index 175dca0..9f45207 100644 --- a/crates/jellyswarrm-proxy/src/server_storage.rs +++ b/crates/jellyswarrm-proxy/src/server_storage.rs @@ -52,8 +52,8 @@ impl ServerHealthStatus { pub struct ServerStorageService { pool: SqlitePool, health_status: Arc>>, - http_client: reqwest::Client, - client_info: ClientInfo, + pub http_client: reqwest::Client, + pub client_info: ClientInfo, } impl ServerStorageService {