ensuring that slides can be created by different things

This commit is contained in:
Chris Cochrun 2024-10-08 06:18:26 -05:00
parent 887fc733e7
commit 8f065380aa
7 changed files with 270 additions and 50 deletions

23
Cargo.lock generated
View file

@ -499,6 +499,7 @@ dependencies = [
"dirs",
"fastrand 2.1.1",
"obws",
"pretty_assertions",
"quote",
"reqwest",
"rfd",
@ -781,6 +782,12 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "diff"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "digest"
version = "0.10.7"
@ -2054,6 +2061,16 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "pretty_assertions"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
dependencies = [
"diff",
"yansi",
]
[[package]]
name = "proc-macro-crate"
version = "1.3.1"
@ -3646,6 +3663,12 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "yansi"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
[[package]]
name = "youtube_dl"
version = "0.8.1"

View file

@ -42,6 +42,7 @@ time = { version = "0.3.29", features = ["formatting", "macros"] }
obws = "0.13.0"
reqwest = "0.11.23"
color-eyre = "0.6.3"
pretty_assertions = "1.4.1"
# ffmpeg-next = "6.0.0"
# cxx-qt-build generates C++ code from the `#[cxx_qt::bridge]` module

View file

@ -1,5 +1,5 @@
pub struct Image {
title: String,
_title: String,
}
#[cfg(test)]

View file

@ -91,5 +91,4 @@ pub trait Modeling {
#[cfg(test)]
mod test {
use super::*;
}

View file

@ -1,6 +1,7 @@
use std::path::PathBuf;
use std::{error::Error, fmt::Display, path::PathBuf};
use color_eyre::eyre::Result;
use color_eyre::eyre::{eyre, Result};
use tracing::debug;
use crate::{
images::Image, kinds::ServiceItemKind,
@ -21,19 +22,81 @@ pub enum TextAlignment {
BottomRight,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Background {
path: PathBuf,
kind: BackgroundKind,
}
impl TryFrom<String> for Background {
type Error = ParseError;
fn try_from(value: String) -> Result<Self, Self::Error> {
let extension = value.rsplit_once('.').unwrap_or_default();
match extension.0 {
"jpg" | "png" | "webp" => Ok(Self {
path: PathBuf::from(value),
kind: BackgroundKind::Image,
}),
"mp4" | "mkv" | "webm" => Ok(Self {
path: PathBuf::from(value),
kind: BackgroundKind::Video,
}),
_ => Err(ParseError::NonBackgroundFile)
}
}
}
impl TryFrom<PathBuf> for Background {
type Error = ParseError;
fn try_from(value: PathBuf) -> Result<Self, Self::Error> {
let extension = value.extension().unwrap_or_default().to_str().unwrap_or_default();
match extension {
"jpg" | "png" | "webp" => Ok(Self {
path: value,
kind: BackgroundKind::Image,
}),
"mp4" | "mkv" | "webm" => Ok(Self {
path: value,
kind: BackgroundKind::Video,
}),
_ => Err(ParseError::NonBackgroundFile)
}
}
}
#[derive(Debug)]
pub enum ParseError {
NonBackgroundFile,
}
impl Error for ParseError {}
impl Display for ParseError {
fn fmt(
&self,
f: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
let message = match self {
Self::NonBackgroundFile => "The file is not a recognized image or video type",
};
write!(f, "Error: {message}")
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum Background {
pub enum BackgroundKind {
#[default]
Image,
Video,
}
impl From<String> for Background {
impl From<String> for BackgroundKind {
fn from(value: String) -> Self {
if value == "image" {
Background::Image
BackgroundKind::Image
} else {
Background::Video
BackgroundKind::Video
}
}
}
@ -42,7 +105,7 @@ impl From<String> for Background {
struct Slide {
id: i32,
database_id: i32,
background: PathBuf,
background: Background,
text: String,
font: String,
font_size: i32,
@ -75,9 +138,13 @@ impl From<Song> for Slide {
}
impl From<Video> for Slide {
fn from(_video: Video) -> Self {
fn from(video: Video) -> Self {
Self {
kind: ServiceItemKind::Video,
background: Background::try_from(video.path).unwrap_or_default(),
video_loop: video.looping,
video_start_time: video.start_time.unwrap_or_default(),
video_end_time: video.end_time.unwrap_or_default(),
..Default::default()
}
}
@ -103,34 +170,158 @@ impl From<Presentation> for Slide {
}
impl SlideModel {
pub fn add_song_to_end(&mut self, song: Song) -> Result<()> {
pub fn add_song(&mut self, song: Song, index: i32) -> Result<()> {
let lyrics = song.get_lyrics()?;
let mut slides: Vec<Slide> = lyrics
let current_length = self.slides.len();
let slides: Vec<Slide> = lyrics
.iter()
.map(|lyric| Slide {
background: song.background.clone(),
background: song.background.clone().unwrap_or_default(),
text: lyric.to_owned(),
font: song.font.clone(),
font_size: song.font_size,
font: song.font.clone().unwrap_or_default(),
font_size: song.font_size.unwrap_or_default(),
kind: ServiceItemKind::Song,
text_alignment: song.text_alignment,
text_alignment: song.text_alignment.unwrap_or_default(),
..Default::default()
})
.collect();
self.slides.append(&mut slides);
for (location, slide) in slides.iter().enumerate() {
self.slides.insert(location + index as usize, slide.clone());
debug!("Here is the current slide_model: {:?}", self);
}
if self.slides.len() > current_length {
Ok(())
} else {
Err(eyre!("The size of the slides vector didn't change"))
}
}
pub fn get_slide(&self, index: i32) -> Option<&Slide> {
self.slides.get(index as usize)
}
pub fn add_video(&mut self, video: Video, index: i32) -> Result<()> {
self.slides.insert(index as usize, Slide::from(video));
Ok(())
}
pub fn add_video_to_end(&mut self, video: Video) -> Result<()> {
self.slides.push(Slide::from(video));
pub fn add_image(&mut self, image: Image, index: i32) -> Result<()> {
self.slides.insert(index as usize, Slide::from(image));
Ok(())
}
pub fn add_presentation(&mut self, presentation: Presentation, index: i32) -> Result<()> {
self.slides.insert(index as usize, Slide::from(presentation));
Ok(())
}
}
#[cfg(test)]
mod test {
use crate::songs::Song;
use pretty_assertions::{assert_eq, assert_ne};
use super::*;
fn test_song() -> Song {
Song {
title: "From The Day".to_string(),
lyrics: Some("Verse 1
When You found me,
I was so blind
My sin was before me,
I was swallowed by pride
Chorus 1
But out of the darkness,
You brought me to Your light
You showed me new mercy
And opened up my eyes
Chorus 2
From the day
You saved my soul
'Til the very moment
When I come home
I'll sing, I'll dance,
My heart will overflow
From the day
You saved my soul
Verse 2
Where brilliant light
Is all around
And endless joy
Is the only sound
Chorus 3
Oh, rest my heart
Forever now
Oh, in Your arms
I'll always be found
Bridge 1
My love is Yours
My heart is Yours
My life is Yours
Forever
My love is Yours
My heart is Yours
My life is Yours
Forever
Other 1
From the Day
I Am They
Other 2
Ending 1
Oh Oh Oh
From the day
You saved my soul".to_string()),
verse_order: Some("O1 V1 C1 C2 O2 V2 C3 C2 O2 B1 C2 C2 E1 O2"
.to_string()
.split(' ')
.map(|s| s.to_string())
.collect()),
..Default::default()
}
}
fn test_song_verse_one() -> String {
"When You found me,\nI was so blind\nMy sin was before me,\nI was swallowed by pride".to_string()
}
fn test_song_last_verse() -> String {
"Oh Oh Oh\nFrom the day\nYou saved my soul\n".to_string()
}
#[test]
pub fn test_slides() {
assert_eq!(true, true)
pub fn test_add_song_to_slides() {
let song = test_song();
let mut slide_model = SlideModel::default();
let result = slide_model.add_song(song, 0);
match result {
Ok(_) => {
let slide = slide_model.get_slide(15).unwrap();
let new_slide = Slide {
text: test_song_last_verse(),
..Default::default()
};
assert_eq!(slide, &new_slide);
let slide = slide_model.get_slide(1).unwrap();
let new_slide = Slide {
text: test_song_verse_one(),
..Default::default()
};
assert_eq!(slide, &new_slide);
},
Err(e) => {
panic!("There was a problem adding the slide: {:?}", e);
}
}
}
}

View file

@ -1,7 +1,7 @@
use std::{collections::HashMap, mem::replace, path::PathBuf};
use color_eyre::eyre::{eyre, Result};
use sqlx::{query, Connection, SqliteConnection};
use sqlx::query;
use tracing::{debug, error};
use crate::{
@ -13,15 +13,14 @@ use crate::{
pub struct Song {
pub title: String,
pub lyrics: Option<String>,
pub author: String,
pub ccli: String,
pub audio: PathBuf,
pub verse_order: Vec<String>,
pub background: PathBuf,
pub background_type: Background,
pub text_alignment: TextAlignment,
pub font: String,
pub font_size: i32,
pub author: Option<String>,
pub ccli: Option<String>,
pub audio: Option<PathBuf>,
pub verse_order: Option<Vec<String>>,
pub background: Option<Background>,
pub text_alignment: Option<TextAlignment>,
pub font: Option<String>,
pub font_size: Option<i32>,
}
const VERSE_KEYWORDS: [&'static str; 24] = [
@ -39,7 +38,7 @@ impl Modeling for Model<Song> {
Ok(())
}
fn add_to_db(&mut self, item: Self::Item) -> Result<()> {
fn add_to_db(&mut self, _item: Self::Item) -> Result<()> {
todo!()
}
@ -91,21 +90,20 @@ impl Model<Song> {
let _ = self.add_item(Song {
title: song.title,
lyrics: Some(song.lyrics),
author: song.author,
ccli: song.ccli,
audio: song.audio.into(),
verse_order: song.verse_order.split(" ").map(|s| s.to_string()).collect(),
background: song.background.into(),
background_type: song.background_type.into(),
author: Some(song.author),
ccli: Some(song.ccli),
audio: Some(song.audio.into()),
verse_order: Some(song.verse_order.split(" ").map(|s| s.to_string()).collect()),
background: Some(song.background.try_into().unwrap_or_default()),
text_alignment: {
if song.horizontal_text_alignment == "center" && song.vertical_text_alignment == "center" {
TextAlignment::MiddleCenter
Some(TextAlignment::MiddleCenter)
} else {
TextAlignment::TopCenter
Some(TextAlignment::TopCenter)
}
},
font: song.font,
font_size: song.font_size,
font: Some(song.font),
font_size: Some(song.font_size),
});
}
},
@ -120,6 +118,13 @@ impl Model<Song> {
impl Song {
pub fn get_lyrics(&self) -> Result<Vec<String>> {
let mut lyric_list = Vec::new();
if self.lyrics.is_none() {
return Err(eyre!("There is no lyrics here"))
} else if self.verse_order.is_none() {
return Err(eyre!("There is no verse_order here"))
} else if self.verse_order.clone().is_some_and(|v| v.is_empty()) {
return Err(eyre!("There is no verse_order here"))
}
if let Some(raw_lyrics) = self.lyrics.clone() {
let raw_lyrics = raw_lyrics.as_str();
let verse_order = self.verse_order.clone();
@ -143,7 +148,7 @@ impl Song {
}
lyric_map.insert(verse_title, lyric);
for verse in verse_order {
for verse in verse_order.unwrap_or_default() {
let mut verse_name = "";
debug!(verse = verse);
for word in VERSE_KEYWORDS.clone() {
@ -188,6 +193,7 @@ impl Song {
#[cfg(test)]
mod test {
use super::*;
use pretty_assertions::{assert_eq, assert_ne};
#[test]
pub fn test_song_lyrics() {
@ -256,7 +262,7 @@ You saved my soul"
"O1 V1 C1 C2 O2 V2 C3 C2 O2 B1 C2 C2 E1 O2"
.to_string()
.split(' ')
.map(|s| s.to_string())
.map(|s| Some(s.to_string()))
.collect();
let lyrics = song.get_lyrics();
match lyrics {

View file

@ -7,11 +7,11 @@ use std::path::PathBuf;
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Video {
title: String,
path: PathBuf,
start_time: f32,
end_time: f32,
looping: bool,
pub title: String,
pub path: PathBuf,
pub start_time: Option<f32>,
pub end_time: Option<f32>,
pub looping: bool,
}
impl Model<Video> {}
@ -24,7 +24,7 @@ impl Modeling for Model<Video> {
Ok(())
}
fn add_to_db(&mut self, item: Self::Item) -> Result<()> {
fn add_to_db(&mut self, _item: Self::Item) -> Result<()> {
todo!()
}