use {
crate::{
getopt,
serve::{
media::{
filter::MediaFilter, gallery::MediaGallery, item::MediaItem, stats::FilterStats,
},
theme::registry::ThemeRegistry,
},
},
rocket::{
State, get,
http::Status,
response::content::{RawCss, RawHtml, RawJavaScript},
serde::json::Json,
},
std::sync::Arc,
tokio::sync::RwLock,
};
const HTML_TEMPLATE: &str = include_str!("../../resources/gallery/index.html");
const CSS: &str = include_str!("../../resources/gallery/styles.css");
const JS: &str = include_str!("../../resources/gallery/script.js");
pub struct AppState {
pub gallery: Arc<RwLock<MediaGallery>>,
}
impl AppState {
pub fn new(gallery: MediaGallery) -> Self {
Self {
gallery: Arc::new(RwLock::new(gallery)),
}
}
}
#[get("/")]
pub async fn index_handler() -> RawHtml<String> {
RawHtml(HTML_TEMPLATE.to_string())
}
#[get("/styles.css")]
pub async fn css_handler() -> RawCss<String> {
let configured_theme = getopt!(gallery.theme);
let registry = ThemeRegistry::new();
let css_vars = registry
.get_theme_css_vars(&configured_theme)
.unwrap_or("".to_string());
let css_code = CSS.replace("/* {{THEME_CSS_VARS}} */", &css_vars);
RawCss(css_code)
}
#[get("/script.js")]
pub async fn js_handler() -> RawJavaScript<String> {
RawJavaScript(JS.to_string())
}
#[get("/api/media?<filter..>")]
pub async fn list_media_handler(
state: &State<Arc<AppState>>,
filter: Option<MediaFilter>,
) -> Result<Json<Vec<MediaItem>>, Status> {
let mut gallery = state.gallery.write().await;
let filter = filter.unwrap_or_default();
let items = gallery
.get_filtered_items(&filter)
.await
.map_err(|_| Status::InternalServerError)?;
Ok(Json(items))
}
#[get("/api/stats")]
pub async fn stats_handler(state: &State<Arc<AppState>>) -> Result<Json<FilterStats>, Status> {
let gallery = state.gallery.read().await;
let stats = gallery.get_filter_stats();
Ok(Json(stats))
}