This repository has no description
1mod scenes;
2
3use anyhow::anyhow;
4use schedule_hell::State;
5use shapemaker::{ui::Log, *};
6use std::{fs, path::PathBuf, time::Duration};
7
8#[tokio::main]
9pub async fn main() {
10 let canvas = Canvas::new(16, 9);
11
12 let mut video = Video::<State>::new(canvas);
13 let mut args = pico_args::Arguments::from_env();
14
15 video = video
16 // Sync inputs //
17 .sync_audio_with("schedule-hell.midi")
18 .expect("Failed to sync from MIDI file")
19 .sync_audio_with("schedule-hell.wav")
20 .expect("Failed to sync from WAV file");
21
22 if let Ok(marker) = args.value_from_str::<_, String>("--marker") {
23 let range = video
24 .syncdata
25 .marker_ms_range(marker)
26 .expect("Cannot find marker {marker:?} in sync data");
27
28 video.start_rendering_at = Timestamp::from_ms(range.start);
29 video.duration_override = Some(Duration::from_millis(range.len() as _));
30 }
31
32 if let Ok(duration) = args.value_from_str("--duration") {
33 video.duration_override = Some(Duration::from_secs(duration));
34 }
35
36 if let Ok(start) = args.value_from_str("--start") {
37 video.start_rendering_at = Timestamp::from_seconds(start);
38 }
39
40 video.resolution = args.value_from_str("--resolution").ok().unwrap_or(480);
41 video.fps = args.value_from_str("--fps").ok().unwrap_or(30);
42
43 video.audiofile = PathBuf::from("schedule-hell.wav");
44 video = video
45 // Scenes //
46 .with_scene(scenes::starry_sky())
47 .with_init_scene(scenes::intro())
48 .with_marked_scene(scenes::first_break())
49 .with_scene(scenes::backbone())
50 .with_scene(scenes::dices())
51 .assign_scene_to("end of first break", "intro")
52 .assign_scene_to("second break", "starry sky")
53 // "end first break" means "end of second break" lol
54 .assign_scene_to("end first break", "dices")
55 // Credits //
56 .when_remaining(10, &|canvas, _| {
57 let world = canvas.world_region;
58 canvas.root().set(
59 "credits text",
60 Shape::Text(
61 world.start,
62 "Postamble / Schedule Hell".into(),
63 12.0,
64 )
65 .colored(Color::White),
66 );
67 Ok(())
68 });
69
70 let destination: String = args
71 .free_from_str()
72 .unwrap_or(String::from("schedule-hell.mp4"));
73
74 if destination.starts_with("localhost:") {
75 video.serve(&destination).await;
76 } else {
77 let result = if destination.ends_with(".svg") {
78 let render_ahead = 1_000;
79
80 let frame_no = destination
81 .trim_end_matches(".svg")
82 .parse::<usize>()
83 .expect("Provide a integer when rendering a frame");
84
85 video.progress_bars.loading.log(
86 "Constrained",
87 &format!(
88 "to frame #{frame_no}, with {render_ahead}-frame context"
89 ),
90 );
91
92 video
93 .render_frame(frame_no, render_ahead)
94 .and_then(|svg| {
95 fs::write(destination, svg.to_string())
96 .map_err(|e| anyhow!("{e:?}"))
97 })
98 .map(|_| Duration::default())
99 } else {
100 video.encode(destination)
101 };
102
103 match result {
104 Ok(_) => (),
105 Err(e) => {
106 let _ = video.progress.clear();
107 ().log_error("Failed", &format!("{e:?}"));
108 }
109 };
110 }
111}