This repository has no description
1use crate::{Video, ui::Log};
2use axum::{Router, extract::Path, response::Html, routing};
3use std::sync::Arc;
4
5pub struct VideoServer {
6 pub router: Router,
7}
8
9const PREVIEW_HTML: &str = include_str!("preview.html");
10
11impl VideoServer {
12 pub fn new<C: 'static + Default>(video: Arc<Video<C>>) -> Self {
13 let _ = video.progress.clear();
14
15 let total_frames_count = video.ms_to_frames(video.total_duration_ms());
16
17 let router = Router::new()
18 .route("/", routing::get(async move || Html(PREVIEW_HTML.replace("%frames_count%", &total_frames_count.to_string()))))
19 .route("/frame/{number_dot_svg}", routing::get(async move |Path(number_dot_svg): Path<String>| {
20 let number: usize = number_dot_svg
21 .strip_suffix(".svg")
22 .expect("Expecting /frame/{number}.svg, didn't find .svg at the end")
23 .parse()
24 .expect("Expecting /frame/{number}.svg, couldn't parse {number} to an integer");
25
26 println!("");
27 println!("Frame number requested: {number}");
28
29 match video.render_frame(number, 500) {
30 // Ok((timecode, svg)) => svg.to_string().replace(
31 // "</svg>",
32 // &format!(r#"<meta name="shapemaker:timecode" content="{timecode}" /></svg>"#)
33 // ),
34 Ok(svg) => svg.to_string(),
35 Err(err) => format!("{err:?}"),
36 }
37 }),
38 );
39
40 Self { router }
41 }
42
43 pub async fn start(self, address: &str) {
44 axum::serve(
45 tokio::net::TcpListener::bind(address).await.unwrap(),
46 self.router,
47 )
48 .await
49 .unwrap();
50 }
51}
52
53impl<C: 'static + Default> Video<C> {
54 pub async fn serve(self, address: &str) {
55 self.progress_bars
56 .loading
57 .log_cyan("Listening", &format!("on {address}"));
58 VideoServer::new(Arc::new(self)).start(address).await;
59 }
60}