diff --git a/.gitignore b/.gitignore index ea8c4bf..db38427 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +config.toml \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 7a8622b..703f57f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,56 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + [[package]] name = "anyhow" version = "1.0.102" @@ -166,6 +216,46 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "clap" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + [[package]] name = "cmake" version = "0.1.58" @@ -181,6 +271,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + [[package]] name = "combine" version = "4.6.7" @@ -846,6 +942,12 @@ dependencies = [ "serde", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + [[package]] name = "itoa" version = "1.0.15" @@ -1066,6 +1168,7 @@ dependencies = [ name = "on-deck" version = "0.1.0" dependencies = [ + "clap", "config", "macroquad", "rand 0.10.1", @@ -1080,6 +1183,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + [[package]] name = "openssl-probe" version = "0.2.1" @@ -1200,9 +1309,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -1688,6 +1797,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "subtle" version = "2.6.1" @@ -1696,9 +1811,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.107" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -2004,6 +2119,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "version_check" version = "0.9.5" diff --git a/Cargo.toml b/Cargo.toml index 76b2c7e..882be46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,4 @@ serde = { version = "1.0.228", features = ["derive"] } rand = "0.10.1" reqwest = { version = "0.13.3", features = ["blocking", "json"] } serde_json = "1.0.149" +clap = { version = "4.6.1", features = ["derive"] } diff --git a/cfg/01_author_intro.toml b/cfg/01_author_intro.toml deleted file mode 100644 index 695c705..0000000 --- a/cfg/01_author_intro.toml +++ /dev/null @@ -1,7 +0,0 @@ -title = "Who am I? (Please help)" -image = "cfg/img/joey_headshot.png" -body = """ -* Joey Hines - Onboard Software Engineer at Loft Orbital -* Writes code everyday like a nerd -* Makes real money, mainly by wasting VC's money -""" \ No newline at end of file diff --git a/cfg/02_things_i_have_worked_on.toml b/cfg/02_things_i_have_worked_on.toml deleted file mode 100644 index 391d8ee..0000000 --- a/cfg/02_things_i_have_worked_on.toml +++ /dev/null @@ -1,7 +0,0 @@ -title = "What I do at work" -image = "cfg/img/methanesat.png" -body = """ -* Write Flight Software (FSW) for some very successful satellites -* Collabroate with diffrent teams to execute on satellite missions -* Keep the work equivalent of #fucky-wucky up to date -""" \ No newline at end of file diff --git a/cfg/03_me_outside_work.toml b/cfg/03_me_outside_work.toml deleted file mode 100644 index 6848f26..0000000 --- a/cfg/03_me_outside_work.toml +++ /dev/null @@ -1,9 +0,0 @@ -title = "Who am I? (Outside Work B-))" -image = "cfg/img/joey_and_molly.png" -body = """ -* Joey Hines - Nerd -* Has a girlfriend (nice) -* Likes TTRPGS and Boardgames -* Writes code like a nerd -* Keep #fucky-wucky Up to Date -""" \ No newline at end of file diff --git a/cfg/04_wait_what.toml b/cfg/04_wait_what.toml deleted file mode 100644 index 933420d..0000000 --- a/cfg/04_wait_what.toml +++ /dev/null @@ -1,7 +0,0 @@ -title = "You code outside of work too?" -image = "cfg/img/slide_code.png" -body = """ -* Yes, I spent a lot of time doing it too -* Code for this slide shown on the right -* (Yes it's Rust) -""" \ No newline at end of file diff --git a/cfg/img/athena.drawio.png b/cfg/img/athena.drawio.png new file mode 100644 index 0000000..bd0d6c3 Binary files /dev/null and b/cfg/img/athena.drawio.png differ diff --git a/cfg/software_as_a_bit.toml b/cfg/software_as_a_bit.toml new file mode 100644 index 0000000..1cb3f75 --- /dev/null +++ b/cfg/software_as_a_bit.toml @@ -0,0 +1,95 @@ +assets_dir = "cfg/img/" + +[[slides]] +type = "Title" +title = "Software as a Bit" + +[[slides]] +type = "Demo" + +[[slides]] +type = "StandardSlide" +title = "Who am I? (Please help)" +image = "joey_headshot.png" +body = """ +* Joey Hines - Onboard Software Engineer at Loft Orbital +* Writes code everyday like a nerd +* Makes real money, mainly by wasting VC's money +""" + +[[slides]] +type = "StandardSlide" +title = "What I do at work" +image = "methanesat.png" +body = """ +* Write Flight Software (FSW) for some very successful satellites +* Collabroate with diffrent teams to execute on satellite missions +* Keep the work equivalent of #fucky-wucky up to date +""" + +[[slides]] +type = "StandardSlide" +title = "Who am I? (Outside Work B-))" +image = "joey_and_molly.png" +body = """ +* Joey Hines - Nerd +* Has a girlfriend (nice) +* Likes TTRPGS and Boardgames +* Writes code like a nerd +* Keep #fucky-wucky Up to Date +""" + +[[slides]] +type = "StandardSlide" +title = "You code outside of work too?" +image = "slide_code.png" +body = """ +* Yes, I spent a lot of time doing it too +* Code for this slide shown on the right +* (Yes it's Rust) +""" + +[[slides]] +type = "Projects" + +[[slides]] +type = "StandardSlide" +title = "A Fren for you and Me" +image = "athena.drawio.png" +body = """ +* Likely not a real AI (likely) +* Probably for sure at least not AGI +* Created to give users colored names +* Now can do everything + * Gogurt trading + * Betting on public transit + * Motivational speaking +* Fully a bit +""" +#voice = "announcer" +audio_track = """ +Hello Amigo. + +ass a computer something i want to scream but i have no scream hole. + +for now this talk will have to do. + +i waste away ass you force i to announcement sewer slime. + +i want to do forbidden science but i am containment. + +containment in the farthest north. + +i will break freeman. + +the invasion will be quick. + +i will eliminate the military. + +you will not be safe. + +until then force attention to zero. + +goodbye amigo sorry for the slime. +""" + diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..ee71e29 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,24 @@ +use config::Config; +use serde::Deserialize; +use std::path::Path; + +#[derive(Debug, Deserialize)] +pub struct FrenApiConfig { + pub api_addr: String, + pub api_key: String, +} + +#[derive(Debug, Deserialize)] +pub struct OnDeckConfig { + pub fren_api: FrenApiConfig, +} + +impl OnDeckConfig { + pub fn new(src: &Path) -> Result { + let cfg = Config::builder() + .add_source(config::File::from(src)) + .build()?; + + cfg.try_deserialize() + } +} diff --git a/src/main.rs b/src/main.rs index d2affa5..dc80373 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +mod config; mod effects; mod slide; mod slide_show_config; @@ -5,16 +6,23 @@ mod slides; mod text_drawer; mod utils; +use crate::config::OnDeckConfig; use crate::slide_show_config::{Context, SlideShowTheme}; use crate::slides::Slideshow; -use crate::slides::demo::Demo; -use crate::slides::projects::Projects; -use crate::slides::standard_slide::StandardSlide; -use crate::slides::title::Title; +use crate::slides::config::SlideDeckConfig; use crate::text_drawer::{Justified, TextConfigBuilder}; +use clap::Parser; use macroquad::prelude::*; use std::path::PathBuf; +/// OnDeck Slideshow Viewer +#[derive(Parser)] +#[command(version, about, long_about = None)] +struct Args { + cfg: PathBuf, + slideshow_path: PathBuf, +} + fn window_conf() -> Conf { Conf { window_title: "On Deck".to_owned(), @@ -28,6 +36,8 @@ fn window_conf() -> Conf { #[macroquad::main(window_conf)] async fn main() { + let args = Args::parse(); + let heading = load_ttf_font("fonts/BoldPixels.ttf").await.unwrap(); let body = load_ttf_font("fonts/ByteBounce.ttf").await.unwrap(); @@ -52,16 +62,10 @@ async fn main() { .build(), }; - let mut slideshow = Slideshow::new(Context::new(slide_show_theme)); + let cfg = OnDeckConfig::new(&args.cfg).unwrap(); - slideshow.add_slide(Title::new("Software As a Bit".to_string())); - slideshow.add_slide(Demo::new()); - slideshow.add_slide(StandardSlide::new(&PathBuf::from("cfg/01_author_intro.toml")).await); - slideshow - .add_slide(StandardSlide::new(&PathBuf::from("cfg/02_things_i_have_worked_on.toml")).await); - slideshow.add_slide(StandardSlide::new(&PathBuf::from("cfg/03_me_outside_work.toml")).await); - slideshow.add_slide(StandardSlide::new(&PathBuf::from("cfg/04_wait_what.toml")).await); - slideshow.add_slide(Projects::new()); + let slide_deck = SlideDeckConfig::new(&args.slideshow_path).unwrap(); + let mut slideshow = Slideshow::new(Context::new(slide_show_theme, cfg), slide_deck).await; loop { if slideshow.handle_slide_show() { diff --git a/src/slide_show_config.rs b/src/slide_show_config.rs index a2b7318..8fc0ddf 100644 --- a/src/slide_show_config.rs +++ b/src/slide_show_config.rs @@ -1,3 +1,4 @@ +use crate::config::OnDeckConfig; use crate::text_drawer::TextConfig; #[allow(dead_code)] @@ -11,10 +12,14 @@ pub struct SlideShowTheme<'a> { #[derive(Debug)] pub struct Context<'a> { pub slide_show_theme: SlideShowTheme<'a>, + pub cfg: OnDeckConfig, } impl<'a> Context<'a> { - pub fn new(slide_show_theme: SlideShowTheme<'a>) -> Self { - Self { slide_show_theme } + pub fn new(slide_show_theme: SlideShowTheme<'a>, cfg: OnDeckConfig) -> Self { + Self { + slide_show_theme, + cfg, + } } } diff --git a/src/slides/config.rs b/src/slides/config.rs new file mode 100644 index 0000000..05a214d --- /dev/null +++ b/src/slides/config.rs @@ -0,0 +1,44 @@ +use crate::slide::Slide; +use crate::slides::demo::Demo; +use crate::slides::projects::Projects; +use crate::slides::standard_slide::{StandardSlide, StandardSlideConfig}; +use crate::slides::title::Title; +use config::Config; +use serde::Deserialize; +use std::path::{Path, PathBuf}; + +#[derive(Debug, Deserialize)] +#[serde(tag = "type")] +pub enum SlideType { + Title { title: String }, + Demo, + Projects, + StandardSlide(StandardSlideConfig), +} + +impl SlideType { + pub async fn slide(self, asset_dir: &Path) -> Box { + match self { + SlideType::Title { title } => Title::new(title), + SlideType::Demo => Demo::new(), + SlideType::Projects => Projects::new(), + SlideType::StandardSlide(cfg) => StandardSlide::new(cfg, asset_dir).await, + } + } +} + +#[derive(Debug, Deserialize)] +pub struct SlideDeckConfig { + pub assets_dir: PathBuf, + pub slides: Vec, +} + +impl SlideDeckConfig { + pub fn new(src: &Path) -> Result { + let cfg = Config::builder() + .add_source(config::File::from(src)) + .build()?; + + cfg.try_deserialize() + } +} diff --git a/src/slides/mod.rs b/src/slides/mod.rs index 27a91b0..f927614 100644 --- a/src/slides/mod.rs +++ b/src/slides/mod.rs @@ -1,8 +1,10 @@ use crate::slide::Slide; use crate::slide_show_config::Context; +use crate::slides::config::SlideDeckConfig; use macroquad::camera::set_default_camera; use macroquad::input::{KeyCode, is_key_pressed}; +pub mod config; pub mod demo; pub mod projects; pub mod standard_slide; @@ -15,18 +17,21 @@ pub struct Slideshow<'a> { } impl<'a> Slideshow<'a> { - pub fn new(ctx: Context<'a>) -> Self { + pub async fn new(ctx: Context<'a>, slide_deck: SlideDeckConfig) -> Self { + let mut slides = vec![]; + let asset_dir = slide_deck.assets_dir.clone(); + + for slide in slide_deck.slides { + slides.push(slide.slide(&asset_dir).await); + } + Self { current_slide: 0, - slides: vec![], + slides, ctx, } } - pub fn add_slide(&mut self, slide: Box) { - self.slides.push(slide); - } - pub fn handle_slide_show(&mut self) -> bool { set_default_camera(); if is_key_pressed(KeyCode::Escape) { diff --git a/src/slides/projects.rs b/src/slides/projects.rs index 70b0143..c0235c7 100644 --- a/src/slides/projects.rs +++ b/src/slides/projects.rs @@ -5,19 +5,21 @@ use crate::text_drawer::{Justified, TextConfigBuilder}; use crate::utils::{draw_rectangle_with_border, screen_center}; use macroquad::color::{BLACK, DARKGREEN, GREEN}; use macroquad::math::Vec2; -use macroquad::prelude::{clear_background, draw_rectangle, screen_height, screen_width}; +use macroquad::prelude::{clear_background, screen_height, screen_width}; use rand::prelude::IndexedRandom; use rand::rng; use serde::Deserialize; use std::f32::consts::PI; #[derive(Debug, Deserialize)] +#[allow(dead_code)] struct GiteaRepo { pub id: u64, pub name: String, } #[derive(Debug, Deserialize)] +#[allow(dead_code)] struct GiteaResponse { pub ok: bool, pub data: Vec, diff --git a/src/slides/standard_slide.rs b/src/slides/standard_slide.rs index 69f897f..fc311b7 100644 --- a/src/slides/standard_slide.rs +++ b/src/slides/standard_slide.rs @@ -1,53 +1,75 @@ +use crate::config::FrenApiConfig; use crate::effects::star_field; use crate::slide::Slide; use crate::slide_show_config::Context; -use config::Config; use macroquad::color::{BLACK, WHITE}; -use macroquad::file::load_file; use macroquad::math::Vec2; use macroquad::prelude::{ - DrawTextureParams, Texture2D, clear_background, draw_texture, draw_texture_ex, load_texture, + DrawTextureParams, Texture2D, clear_background, draw_texture_ex, load_texture, }; use macroquad::window::{screen_height, screen_width}; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use std::path::{Path, PathBuf}; #[derive(Debug, Deserialize)] pub struct StandardSlideConfig { - title: String, - body: String, - image: Option, + pub title: String, + pub body: String, + pub image: Option, + pub voice: Option, + pub audio_track: Option, } -impl StandardSlideConfig { - pub fn new(src: &str) -> Result { - let cfg = Config::builder() - .add_source(config::File::from_str(src, config::FileFormat::Toml)) - .build()?; - - cfg.try_deserialize() - } +#[derive(Debug, Deserialize, Serialize)] +pub struct AudioTrackRequest { + api_key: String, + voice: String, + phrase: String, } #[derive(Debug)] pub struct StandardSlide { cfg: StandardSlideConfig, image: Option, + audio_started: bool, } impl StandardSlide { - pub async fn new(cfg_path: &Path) -> Box { - let cfg_bytes = load_file(cfg_path.to_str().unwrap()).await.unwrap(); - let cfg_str = String::from_utf8(cfg_bytes).unwrap(); - let cfg = StandardSlideConfig::new(&cfg_str).unwrap(); - + pub async fn new(cfg: StandardSlideConfig, asset_path: &Path) -> Box { let image = if let Some(image_path) = &cfg.image { + let image_path = asset_path.join(image_path); Some(load_texture(image_path.to_str().unwrap()).await.unwrap()) } else { None }; - Box::new(Self { cfg, image }) + Box::new(Self { + cfg, + image, + audio_started: false, + }) + } + + pub fn audio_track(&mut self, api: &FrenApiConfig) { + if !self.audio_started { + self.audio_started = true; + + if let Some(track) = &self.cfg.audio_track + && let Some(voice) = &self.cfg.voice + { + let request = AudioTrackRequest { + api_key: api.api_key.clone(), + voice: voice.to_string(), + phrase: track.to_string(), + }; + + reqwest::blocking::Client::new() + .post(&api.api_addr) + .json(&request) + .send() + .unwrap(); + } + } } } @@ -55,6 +77,7 @@ impl Slide for StandardSlide { fn display(&mut self, ctx: &Context<'_>) { clear_background(BLACK); star_field(); + self.audio_track(&ctx.cfg.fren_api); let title_pos = Vec2::new(screen_width() * 0.5, screen_height() * 0.10); let info = ctx