pub mod api; pub mod auth; use std::sync::Arc; use std::path::PathBuf; use axum::{Router, routing::get, middleware}; use sqlx::PgPool; #[derive(Clone)] pub struct AppState { pub pool: PgPool, #[allow(dead_code)] pub storage_dir: Arc, pub oidc: Option>, } pub fn build_router(state: Arc) -> Router { let library = Router::new() .route("/artists", get(api::list_artists)) .route("/artists/:slug", get(api::get_artist)) .route("/artists/:slug/albums", get(api::list_artist_albums)) .route("/artists/:slug/tracks", get(api::list_artist_all_tracks)) .route("/albums/:slug", get(api::get_album_tracks)) .route("/albums/:slug/cover", get(api::album_cover)) .route("/tracks/:slug", get(api::get_track_detail)) .route("/tracks/:slug/cover", get(api::track_cover)) .route("/stream/:slug", get(api::stream_track)) .route("/search", get(api::search)); let authed = Router::new() .route("/", get(player_html)) .nest("/api", library); let has_oidc = state.oidc.is_some(); let app = if has_oidc { authed .route_layer(middleware::from_fn_with_state(state.clone(), auth::require_auth)) } else { authed }; Router::new() .route("/login", get(auth::login_page)) .route("/logout", get(auth::logout)) .route("/auth/login", get(auth::oidc_login)) .route("/auth/callback", get(auth::oidc_callback)) .merge(app) .with_state(state) } async fn player_html() -> axum::response::Html { let html = include_str!("player.html") .replace("", option_env!("FURUMI_VERSION").unwrap_or(env!("CARGO_PKG_VERSION"))); axum::response::Html(html) }