now we can parse an entire presentation to a list of slides

This commit is contained in:
Chris Cochrun 2024-12-06 11:15:41 -06:00
parent 6779b0c77c
commit 87a26642fa
5 changed files with 193 additions and 19 deletions

View file

@ -9,6 +9,8 @@ use std::{
}; };
use tracing::error; use tracing::error;
use super::songs::Song;
#[derive( #[derive(
Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize, Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
)] )]
@ -174,6 +176,7 @@ pub struct Slide {
font: String, font: String,
font_size: i32, font_size: i32,
text_alignment: TextAlignment, text_alignment: TextAlignment,
audio: Option<PathBuf>,
video_loop: bool, video_loop: bool,
video_start_time: f32, video_start_time: f32,
video_end_time: f32, video_end_time: f32,
@ -199,10 +202,42 @@ impl Slide {
pub fn video_loop(&self) -> bool { pub fn video_loop(&self) -> bool {
self.video_loop self.video_loop
} }
pub fn song_slides(song: &Song) -> Result<Vec<Self>> {
let lyrics = song.get_lyrics()?;
let slides: Vec<Slide> = lyrics
.iter()
.map(|l| {
let song = song.clone();
SlideBuilder::new()
.background(song.background.unwrap_or_default())
.font(song.font.unwrap_or_default())
.font_size(song.font_size.unwrap_or_default())
.text_alignment(
song.text_alignment.unwrap_or_default(),
)
.audio(song.audio.unwrap_or_default())
.video_loop(true)
.video_start_time(0.0)
.video_end_time(0.0)
.text(l)
.build()
.unwrap_or_default()
})
.collect();
Ok(slides)
}
} }
impl From<Value> for Slide { impl From<Value> for Slide {
fn from(value: Value) -> Self { fn from(value: Value) -> Self {
Self::from(&value)
}
}
impl From<&Value> for Slide {
fn from(value: &Value) -> Self {
match value { match value {
Value::List(list) => lisp_to_slide(list), Value::List(list) => lisp_to_slide(list),
_ => Slide::default(), _ => Slide::default(),
@ -210,7 +245,7 @@ impl From<Value> for Slide {
} }
} }
fn lisp_to_slide(lisp: Vec<Value>) -> Slide { fn lisp_to_slide(lisp: &Vec<Value>) -> Slide {
const DEFAULT_BACKGROUND_LOCATION: usize = 1; const DEFAULT_BACKGROUND_LOCATION: usize = 1;
const DEFAULT_TEXT_LOCATION: usize = 0; const DEFAULT_TEXT_LOCATION: usize = 0;
@ -327,11 +362,9 @@ pub fn lisp_to_background(lisp: &Value) -> Background {
home.push_str("/"); home.push_str("/");
let s = s.replace("./", &home); let s = s.replace("./", &home);
dbg!(&s);
match Background::try_from(s.as_str()) { match Background::try_from(s.as_str()) {
Ok(background) => background, Ok(background) => background,
Err(e) => { Err(e) => {
dbg!(&e);
error!( error!(
"Couldn't load background: {e}" "Couldn't load background: {e}"
); );
@ -368,6 +401,7 @@ pub struct SlideBuilder {
text: Option<String>, text: Option<String>,
font: Option<String>, font: Option<String>,
font_size: Option<i32>, font_size: Option<i32>,
audio: Option<PathBuf>,
text_alignment: Option<TextAlignment>, text_alignment: Option<TextAlignment>,
video_loop: Option<bool>, video_loop: Option<bool>,
video_start_time: Option<f32>, video_start_time: Option<f32>,
@ -401,6 +435,11 @@ impl SlideBuilder {
self self
} }
pub(crate) fn audio(mut self, audio: impl Into<PathBuf>) -> Self {
let _ = self.audio.insert(audio.into());
self
}
pub(crate) fn font(mut self, font: impl Into<String>) -> Self { pub(crate) fn font(mut self, font: impl Into<String>) -> Self {
let _ = self.font.insert(font.into()); let _ = self.font.insert(font.into());
self self
@ -471,6 +510,7 @@ impl SlideBuilder {
font, font,
font_size, font_size,
text_alignment, text_alignment,
audio: self.audio,
video_loop, video_loop,
video_start_time, video_start_time,
video_end_time, video_end_time,

View file

@ -103,7 +103,7 @@ impl From<Value> for Song {
} }
} }
fn lisp_to_song(list: Vec<Value>) -> Song { pub fn lisp_to_song(list: Vec<Value>) -> Song {
const DEFAULT_SONG_ID: i32 = 0; const DEFAULT_SONG_ID: i32 = 0;
const DEFAULT_SONG_LOCATION: usize = 0; const DEFAULT_SONG_LOCATION: usize = 0;
@ -273,7 +273,6 @@ fn lisp_to_song(list: Vec<Value>) -> Song {
}; };
let lyric = format!("{verse_title}{lyric}"); let lyric = format!("{verse_title}{lyric}");
println!("lyric_final: {lyric}");
let lyric = lyric.replace( let lyric = lyric.replace(
"\\n", r#" "\\n", r#"
"#, "#,
@ -592,8 +591,6 @@ You saved my soul"
let value = test_lisp_song(); let value = test_lisp_song();
let lisp_song = Song::from(value); let lisp_song = Song::from(value);
let test_song = test_song(); let test_song = test_song();
println!("test_song: {}", test_song.lyrics.clone().unwrap());
println!("lisp_song: {}", lisp_song.lyrics.clone().unwrap());
assert_eq!(test_song, lisp_song); assert_eq!(test_song, lisp_song);
} }
} }

View file

@ -1,6 +1,7 @@
use crisp::types::{Symbol, Value}; use crisp::types::{Symbol, Value};
use tracing::error;
use crate::Slide; use crate::{core::songs::lisp_to_song, Slide};
pub fn parse_lisp(value: Value) -> Vec<Slide> { pub fn parse_lisp(value: Value) -> Vec<Slide> {
match &value { match &value {
@ -10,7 +11,14 @@ pub fn parse_lisp(value: Value) -> Vec<Slide> {
vec![slide] vec![slide]
} }
Value::Symbol(Symbol(s)) if s == "song" => { Value::Symbol(Symbol(s)) if s == "song" => {
vec![Slide::default()] let song = lisp_to_song(vec.clone());
match Slide::song_slides(&song) {
Ok(s) => s,
Err(e) => {
error!("Couldn't load song: {e}");
vec![Slide::default()]
}
}
} }
Value::Symbol(Symbol(s)) if s == "load" => { Value::Symbol(Symbol(s)) if s == "load" => {
vec![Slide::default()] vec![Slide::default()]
@ -23,7 +31,7 @@ pub fn parse_lisp(value: Value) -> Vec<Slide> {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use std::fs::read_to_string; use std::{fs::read_to_string, path::PathBuf};
use crate::{Background, SlideBuilder, TextAlignment}; use crate::{Background, SlideBuilder, TextAlignment};
@ -49,6 +57,31 @@ mod test {
} }
} }
#[test]
fn test_parsing_lisp_presentation() {
let lisp =
read_to_string("./test_presentation.lisp").expect("oops");
let lisp_value = crisp::reader::read(&lisp);
let test_vec =
vec![test_slide(), test_second_slide(), song_slide()];
match lisp_value {
Value::List(value) => {
let mut slide_vec = vec![];
for value in value {
let mut vec = parse_lisp(value);
slide_vec.append(&mut vec);
}
let first_lisp_slide = &slide_vec[0];
let second_lisp_slide = &slide_vec[1];
let third_lisp_slide = &slide_vec[2];
assert_eq!(first_lisp_slide, &test_vec[0]);
assert_eq!(second_lisp_slide, &test_vec[1]);
assert_eq!(third_lisp_slide, &test_vec[2]);
}
_ => panic!("this should be a lisp"),
}
}
fn test_slide() -> Slide { fn test_slide() -> Slide {
SlideBuilder::new() SlideBuilder::new()
.text("This is frodo") .text("This is frodo")
@ -81,4 +114,22 @@ mod test {
.build() .build()
.unwrap() .unwrap()
} }
fn song_slide() -> Slide {
SlideBuilder::new()
.text("Death Was Arrested\nNorth Point Worship")
.background(
Background::try_from("~/nc/tfc/openlp/CMG - Bright Mountains 01.jpg")
.unwrap(),
)
.font("Quicksand Bold")
.font_size(60)
.text_alignment(TextAlignment::MiddleCenter)
.audio(PathBuf::from("file:///home/chris/music/North Point InsideOut/Nothing Ordinary, Pt. 1 (Live)/05 Death Was Arrested (feat. Seth Condrey).mp3"))
.video_loop(true)
.video_start_time(0.0)
.video_end_time(0.0)
.build()
.unwrap()
}
} }

View file

@ -1,13 +1,100 @@
(slide :background (image :source "~/pics/frodo.jpg" :fit fill) (slide :background (image :source "~/pics/frodo.jpg" :fit fill)
(text "This is frodo" :font-size 70)) (text "This is frodo" :font-size 70))
(slide (video :source "~/vids/test/camprules2024.mp4" :fit contain)) (slide (video :source "~/vids/test/camprules2024.mp4" :fit contain))
(song :author "Jordan Feliz" :ccli 97987 (song :id 7 :author "North Point Worship"
:font "Quicksand" :font-size 80 :font "Quicksand Bold" :font-size 60
:title "The River" :title "Death Was Arrested"
:background (image :source "./coolbg.jpg") :background (image :source "file:///home/chris/nc/tfc/openlp/CMG - Bright Mountains 01.jpg" :fit cover)
(text "I'm going down to the river") :text-alignment center
(text "Down to the river") :audio "file:///home/chris/music/North Point InsideOut/Nothing Ordinary, Pt. 1 (Live)/05 Death Was Arrested (feat. Seth Condrey).mp3"
(text "Down to the river to pray ay ay!")) :verse-order (i1 v1 v2 c1 v3 c1 v4 c1 b1 b1 e1 e2)
(i1 "Death Was Arrested\nNorth Point Worship")
(v1 "Alone in my sorrow
And dead in my sin
Lost without hope
With no place to begin
Your love made a way
To let mercy come in
When death was arrested
And my life began")
(v2 "Ash was redeemed
Only beauty remains
My orphan heart
Was given a name
My mourning grew quiet,
My feet rose to dance
When death was arrested
And my life began")
(c1 "Oh, Your grace so free,
Washes over me
You have made me new,
Now life begins with You
It's Your endless love,
Pouring down on us
You have made us new,
Now life begins with You")
(v3 "Released from my chains,
I'm a prisoner no more
My shame was a ransom
He faithfully bore
He cancelled my debt and
He called me His friend
When death was arrested
And my life began")
(v4 "Our Savior displayed
On a criminal's cross
Darkness rejoiced as though
Heaven had lost
But then Jesus arose
With our freedom in hand
That's when death was arrested
And my life began
That's when death was arrested
And my life began")
(b1 "Oh, we're free, free,
Forever we're free
Come join the song
Of all the redeemed
Yes, we're free, free,
Forever amen
When death was arrested
And my life began
Oh, we're free, free,
Forever we're free
Come join the song
Of all the redeemed
Yes, we're free, free,
Forever amen
When death was arrested
And my life began")
(e1 "When death was arrested
And my life began
That's when death was arrested
And my life began"))
(song :author "Jordan Feliz" :ccli 97987 (song :author "Jordan Feliz" :ccli 97987
:font "Quicksand" :font-size 80 :font "Quicksand" :font-size 80
:title "The River" :title "The River"

View file

@ -91,5 +91,4 @@ And my life began")
And my life began And my life began
That's when death was arrested That's when death was arrested
And my life began") And my life began"))
)