#![feature(box_syntax)] use crate::frontend::pages::MyError; use anyhow::{anyhow, Context}; use database::Database; use frontend::{ pages::{home::page_home, node::page_library_node}, style::{css_bundle, font_bundle}, }; use jellyremuxer::RemuxerContext; use library::Library; use log::{debug, warn}; use rocket::{get, http::ContentType, launch, response::stream::ReaderStream, routes, State}; use std::{path::PathBuf, sync::Arc}; use tokio::io::{duplex, DuplexStream}; use tokio_util::io::SyncIoBridge; pub mod database; pub mod frontend; pub mod library; #[get("/assets/style.css")] async fn assets_style() -> (ContentType, String) { (ContentType::CSS, css_bundle()) } #[get("/assets/cantarell.woff2")] async fn assets_font() -> (ContentType, Vec) { (ContentType::WOFF2, font_bundle()) } #[get("/stream/?")] fn stream( path: PathBuf, selection: String, state: &State, ) -> Result<(ContentType, ReaderStream![DuplexStream]), MyError> { let (a, b) = duplex(1024); let path = path.to_str().unwrap().to_string(); let item = state .library .nested(&path) .context("retrieving library node")? .get_item()?; let remuxer = state.remuxer.clone(); let selection = selection .split(",") .map(|e| e.parse().map_err(|_| anyhow!("invalid number"))) .into_iter() .collect::, _>>()?; let b = SyncIoBridge::new(b); tokio::task::spawn_blocking(move || { if let Err(e) = remuxer.generate_into( b, 0, item.fs_path.parent().unwrap().to_path_buf(), item.data.clone(), selection, ) { warn!("stream stopped: {e}") } }); debug!("starting stream"); Ok((ContentType::WEBM, ReaderStream::one(a))) } pub struct AppState { pub database: Database, pub library: Library, pub remuxer: Arc, } #[launch] fn rocket() -> _ { env_logger::init_from_env("LOG"); let db_path = std::env::var("DB_PATH").unwrap_or("data/db".to_string()); let lib_path = std::env::var("LIB_PATH").unwrap_or("data/library".to_string()); let state = AppState { remuxer: RemuxerContext::new(), library: Library::open(&lib_path).unwrap(), database: Database::open(&db_path).unwrap(), }; rocket::build().manage(state).mount( "/", routes![ page_home, page_library_node, assets_style, assets_font, stream ], ) }