From 44749e154fc7a5727223dffc973f110e9c52e6eb Mon Sep 17 00:00:00 2001 From: Chris Cochrun Date: Tue, 28 Apr 2026 12:24:03 -0500 Subject: [PATCH] [formatting] --- clippy.toml | 2 +- rustfmt.toml | 2 +- src/core/file.rs | 115 +- src/core/images.rs | 68 +- src/core/kinds.rs | 31 +- src/core/model.rs | 47 +- src/core/presentations.rs | 103 +- src/core/service_items.rs | 122 +-- src/core/settings.rs | 23 +- src/core/slide.rs | 171 +-- src/core/song_search.rs | 221 ++-- src/core/songs.rs | 353 ++----- src/core/thumbnail.rs | 27 +- src/core/videos.rs | 61 +- src/main.rs | 1561 +++++++++++----------------- src/ui/gst_video.rs | 149 ++- src/ui/image_editor.rs | 55 +- src/ui/image_loader.rs | 10 +- src/ui/library.rs | 510 +++------ src/ui/presentation_editor.rs | 451 +++----- src/ui/presenter.rs | 566 ++++------ src/ui/slide_editor.rs | 33 +- src/ui/song_editor.rs | 1143 ++++++++------------ src/ui/text_svg.rs | 160 +-- src/ui/video_editor.rs | 75 +- src/ui/widgets/draggable/column.rs | 347 +++---- src/ui/widgets/draggable/row.rs | 429 +++----- src/ui/widgets/loaded_image.rs | 36 +- src/ui/widgets/verse_editor.rs | 89 +- 29 files changed, 2548 insertions(+), 4412 deletions(-) diff --git a/clippy.toml b/clippy.toml index 6d6789d..b82e1c5 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1 +1 @@ -excessive-nesting-threshold = 5 \ No newline at end of file +excessive-nesting-threshold = 7 \ No newline at end of file diff --git a/rustfmt.toml b/rustfmt.toml index bfddb63..5778788 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1,4 @@ -max_width = 70 +max_width = 90 style_edition = "2024" # version = "Two" imports_granularity = "Module" \ No newline at end of file diff --git a/src/core/file.rs b/src/core/file.rs index cb498de..c7fa1e4 100644 --- a/src/core/file.rs +++ b/src/core/file.rs @@ -24,8 +24,7 @@ pub fn save( } let save_file = File::create(path).into_diagnostic()?; let ron_pretty = ron::ser::PrettyConfig::default(); - let ron = ron::ser::to_string_pretty(&list, ron_pretty) - .into_diagnostic()?; + let ron = ron::ser::to_string_pretty(&list, ron_pretty).into_diagnostic()?; let encoder = Encoder::new(save_file, 3) .expect("file encoder shouldn't fail") @@ -35,8 +34,7 @@ pub fn save( "there should be a data directory, ~/.local/share/ for linux, but couldn't find it", ); temp_dir.push("lumina"); - let mut s: String = - iter::repeat_with(fastrand::alphanumeric).take(5).collect(); + let mut s: String = iter::repeat_with(fastrand::alphanumeric).take(5).collect(); s.insert_str(0, "temp_"); temp_dir.push(s); fs::create_dir_all(&temp_dir).into_diagnostic()?; @@ -60,9 +58,7 @@ pub fn save( } match tar.append_file("serviceitems.ron", &mut f) { Ok(()) => { - debug!( - "should have added serviceitems.ron to the file" - ); + debug!("should have added serviceitems.ron to the file"); } Err(e) => { error!(?e); @@ -92,23 +88,18 @@ pub fn save( audio = song.audio.clone(); } ServiceItemKind::Image(image) => { - background = Some( - Background::try_from(image.path.clone()) - .into_diagnostic()?, - ); + background = + Some(Background::try_from(image.path.clone()).into_diagnostic()?); audio = None; } ServiceItemKind::Video(video) => { - background = Some( - Background::try_from(video.path.clone()) - .into_diagnostic()?, - ); + background = + Some(Background::try_from(video.path.clone()).into_diagnostic()?); audio = None; } ServiceItemKind::Presentation(presentation) => { background = Some( - Background::try_from(presentation.path.clone()) - .into_diagnostic()?, + Background::try_from(presentation.path.clone()).into_diagnostic()?, ); audio = None; } @@ -151,12 +142,10 @@ pub fn save( #[allow(clippy::too_many_lines)] pub fn load(path: impl AsRef) -> Result> { let decoder = - Decoder::new(fs::File::open(&path).into_diagnostic()?) - .into_diagnostic()?; + Decoder::new(fs::File::open(&path).into_diagnostic()?).into_diagnostic()?; let mut tar = Archive::new(decoder); - let mut cache_dir = - dirs::cache_dir().expect("Should be a cache dir"); + let mut cache_dir = dirs::cache_dir().expect("Should be a cache dir"); cache_dir.push("lumina"); cache_dir.push("cached_save_files"); @@ -173,8 +162,7 @@ pub fn load(path: impl AsRef) -> Result> { .to_os_string() .into_string() .expect("Should be fine"); - let save_name = save_name_string - .trim_end_matches(&format!(".{save_name_ext}")); + let save_name = save_name_string.trim_end_matches(&format!(".{save_name_ext}")); cache_dir.push(save_name); if let Err(e) = fs::remove_dir_all(&cache_dir) { @@ -190,9 +178,7 @@ pub fn load(path: impl AsRef) -> Result> { let mut dir = fs::read_dir(&cache_dir).into_diagnostic()?; let ron_file = dir .find_map(|file| { - if file.as_ref().ok()?.path().extension()?.to_str()? - == "ron" - { + if file.as_ref().ok()?.path().extension()?.to_str()? == "ron" { Some(file.ok()?.path()) } else { None @@ -200,12 +186,10 @@ pub fn load(path: impl AsRef) -> Result> { }) .expect("Should have a ron file"); - let ron_string = - fs::read_to_string(ron_file).into_diagnostic()?; + let ron_string = fs::read_to_string(ron_file).into_diagnostic()?; let mut items = - ron::de::from_str::>(&ron_string) - .into_diagnostic()?; + ron::de::from_str::>(&ron_string).into_diagnostic()?; for item in &mut items { let dir = fs::read_dir(&cache_dir).into_diagnostic()?; @@ -213,33 +197,20 @@ pub fn load(path: impl AsRef) -> Result> { for slide in &mut item.slides { if let Ok(file) = file.as_ref() { let file_name = file.file_name(); - let audio_path = - slide.audio().clone().unwrap_or_default(); - let text_path = slide - .text_svg - .as_ref() - .and_then(|svg| svg.path.clone()); - if Some(file_name.as_os_str()) - == slide.background.path.file_name() - { + let audio_path = slide.audio().clone().unwrap_or_default(); + let text_path = + slide.text_svg.as_ref().and_then(|svg| svg.path.clone()); + if Some(file_name.as_os_str()) == slide.background.path.file_name() { slide.background.path = file.path(); - } else if Some(file_name.as_os_str()) - == audio_path.file_name() - { - let new_slide = slide - .clone() - .set_audio(Some(file.path())); + } else if Some(file_name.as_os_str()) == audio_path.file_name() { + let new_slide = slide.clone().set_audio(Some(file.path())); *slide = new_slide; } else if Some(file_name.as_os_str()) - == text_path - .clone() - .unwrap_or_default() - .file_name() + == text_path.clone().unwrap_or_default().file_name() && let Some(svg) = slide.text_svg.as_mut() { svg.path = Some(file.path()); - svg.handle = - Some(Handle::from_path(file.path())); + svg.handle = Some(Handle::from_path(file.path())); } } } @@ -248,8 +219,7 @@ pub fn load(path: impl AsRef) -> Result> { ServiceItemKind::Song(song) => { if let Ok(file) = file.as_ref() { let file_name = file.file_name(); - let audio_path = - song.audio.clone().unwrap_or_default(); + let audio_path = song.audio.clone().unwrap_or_default(); if Some(file_name.as_os_str()) == song .background @@ -259,14 +229,11 @@ pub fn load(path: impl AsRef) -> Result> { .file_name() { let background = song.background.clone(); - song.background = - background.map(|mut background| { - background.path = file.path(); - background - }); - } else if Some(file_name.as_os_str()) - == audio_path.file_name() - { + song.background = background.map(|mut background| { + background.path = file.path(); + background + }); + } else if Some(file_name.as_os_str()) == audio_path.file_name() { song.audio = Some(file.path()); } } @@ -274,9 +241,7 @@ pub fn load(path: impl AsRef) -> Result> { ServiceItemKind::Video(video) => { if let Ok(file) = file.as_ref() { let file_name = file.file_name(); - if Some(file_name.as_os_str()) - == video.path.file_name() - { + if Some(file_name.as_os_str()) == video.path.file_name() { video.path = file.path(); } } @@ -284,9 +249,7 @@ pub fn load(path: impl AsRef) -> Result> { ServiceItemKind::Image(image) => { if let Ok(file) = file.as_ref() { let file_name = file.file_name(); - if Some(file_name.as_os_str()) - == image.path.file_name() - { + if Some(file_name.as_os_str()) == image.path.file_name() { image.path = file.path(); } } @@ -294,9 +257,7 @@ pub fn load(path: impl AsRef) -> Result> { ServiceItemKind::Presentation(presentation) => { if let Ok(file) = file.as_ref() { let file_name = file.file_name(); - if Some(file_name.as_os_str()) - == presentation.path.file_name() - { + if Some(file_name.as_os_str()) == presentation.path.file_name() { presentation.path = file.path(); } } @@ -361,10 +322,9 @@ mod test { .expect("") .into_par_iter() .map(|slide| { - text_svg_generator(slide, &Arc::clone(&fontdb)) - .unwrap_or_else(|e| { - panic!("Couldn't create svg: {e}"); - }) + text_svg_generator(slide, &Arc::clone(&fontdb)).unwrap_or_else(|e| { + panic!("Couldn't create svg: {e}"); + }) }) .collect::>(); let items = vec![ @@ -404,9 +364,7 @@ mod test { find_svgs(&items)?; Ok(()) } - Err(e) => { - Err(format!("Error in the loading process: {e}")) - } + Err(e) => Err(format!("Error in the loading process: {e}")), } } @@ -511,8 +469,7 @@ mod test { let Ok(file) = fs::File::open(path) else { panic!("couldn't open file"); }; - let Ok(size) = file.metadata().map(|data| data.len()) - else { + let Ok(size) = file.metadata().map(|data| data.len()) else { panic!("couldn't get file metadata"); }; assert!(size > 0); diff --git a/src/core/images.rs b/src/core/images.rs index f0db4ef..be44eda 100644 --- a/src/core/images.rs +++ b/src/core/images.rs @@ -14,9 +14,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use tracing::error; -#[derive( - Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, -)] +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] pub struct Image { pub id: i32, pub title: String, @@ -91,22 +89,19 @@ impl From<&Value> for Image { fn from(value: &Value) -> Self { match value { Value::List(list) => { - let path = if let Some(path_pos) = - list.iter().position(|v| { - v == &Value::Keyword(Keyword::from("source")) - }) { + let path = if let Some(path_pos) = list + .iter() + .position(|v| v == &Value::Keyword(Keyword::from("source"))) + { let pos = path_pos + 1; - list.get(pos) - .map(|p| PathBuf::from(String::from(p))) + list.get(pos).map(|p| PathBuf::from(String::from(p))) } else { None }; let title = path.clone().map(|p| { - let path = - p.to_str().unwrap_or_default().to_string(); - let title = - path.rsplit_once('/').unwrap_or_default().1; + let path = p.to_str().unwrap_or_default().to_string(); + let title = path.rsplit_once('/').unwrap_or_default().1; title.to_string() }); Self { @@ -131,10 +126,7 @@ impl ServiceTrait for Image { fn to_slides(&self) -> Result> { let slide = SlideBuilder::new() - .background( - Background::try_from(self.path.clone()) - .into_diagnostic()?, - ) + .background(Background::try_from(self.path.clone()).into_diagnostic()?) .text("") .audio("") .font("") @@ -180,9 +172,7 @@ impl Model { } } Err(e) => { - error!( - "There was an error in converting images: {e}" - ); + error!("There was an error in converting images: {e}"); } } } @@ -241,13 +231,13 @@ pub async fn add_image( .unwrap_or_default(); query!( - r#"INSERT INTO images (title, file_path) VALUES ($1, $2)"#, - image.title, - path, - ) - .execute(&*db) - .await - .into_diagnostic()?; + r#"INSERT INTO images (title, file_path) VALUES ($1, $2)"#, + image.title, + path, + ) + .execute(&*db) + .await + .into_diagnostic()?; current_images.push(image); } @@ -271,8 +261,9 @@ pub async fn update_image( image.title, path, ) - .execute(&*db) - .await.into_diagnostic()?; + .execute(&*db) + .await + .into_diagnostic()?; let current_image = images .iter() @@ -288,10 +279,7 @@ pub async fn update_image( Ok(images) } -pub async fn get_from_db( - database_id: i32, - db: &mut SqliteConnection, -) -> Result { +pub async fn get_from_db(database_id: i32, db: &mut SqliteConnection) -> Result { query_as!(Image, r#"SELECT title as "title!", file_path as "path!", id as "id: i32" from images where id = ?"#, database_id).fetch_one(db).await.into_diagnostic() } @@ -303,9 +291,7 @@ mod test { fn test_image(title: String) -> Image { Image { title, - path: PathBuf::from( - "/home/chris/pics/memes/no-i-dont-think.gif", - ), + path: PathBuf::from("/home/chris/pics/memes/no-i-dont-think.gif"), ..Default::default() } } @@ -342,14 +328,8 @@ mod test { let new_image = test_image("A newer image".into()); match result { Ok(()) => { - assert_eq!( - &image, - image_model.find(|i| i.id == 0).expect("") - ); - assert_ne!( - &new_image, - image_model.find(|i| i.id == 0).expect("") - ); + assert_eq!(&image, image_model.find(|i| i.id == 0).expect("")); + assert_ne!(&new_image, image_model.find(|i| i.id == 0).expect("")); } Err(e) => { panic!("There was an error adding the image: {e:?}",) diff --git a/src/core/kinds.rs b/src/core/kinds.rs index 2bddd43..d120542 100644 --- a/src/core/kinds.rs +++ b/src/core/kinds.rs @@ -29,18 +29,10 @@ impl TryFrom for ServiceItemKind { let ext = path .extension() .and_then(|ext| ext.to_str()) - .ok_or_else(|| { - miette::miette!( - "There isn't an extension on this file" - ) - })?; + .ok_or_else(|| miette::miette!("There isn't an extension on this file"))?; match ext { - "png" | "jpg" | "jpeg" => { - Ok(Self::Image(Image::from(path))) - } - "mp4" | "mkv" | "webm" => { - Ok(Self::Video(Video::from(path))) - } + "png" | "jpg" | "jpeg" => Ok(Self::Image(Image::from(path))), + "mp4" | "mkv" | "webm" => Ok(Self::Video(Video::from(path))), "pdf" => Ok(Self::Presentation(Presentation::from(path))), _ => Err(miette::miette!("Unknown item")), } @@ -53,9 +45,7 @@ impl ServiceItemKind { Self::Song(song) => song.title.clone(), Self::Video(video) => video.title.clone(), Self::Image(image) => image.title.clone(), - Self::Presentation(presentation) => { - presentation.title.clone() - } + Self::Presentation(presentation) => presentation.title.clone(), Self::Content(_slide) => todo!(), } } @@ -65,9 +55,7 @@ impl ServiceItemKind { Self::Song(song) => song.to_service_item(), Self::Video(video) => video.to_service_item(), Self::Image(image) => image.to_service_item(), - Self::Presentation(presentation) => { - presentation.to_service_item() - } + Self::Presentation(presentation) => presentation.to_service_item(), Self::Content(_slide) => { todo!() } @@ -112,9 +100,7 @@ impl From for String { ServiceItemKind::Song(_) => "song".to_owned(), ServiceItemKind::Video(_) => "video".to_owned(), ServiceItemKind::Image(_) => "image".to_owned(), - ServiceItemKind::Presentation(_) => { - "presentation".to_owned() - } + ServiceItemKind::Presentation(_) => "presentation".to_owned(), ServiceItemKind::Content(_) => "content".to_owned(), } } @@ -128,10 +114,7 @@ pub enum ParseError { impl Error for ParseError {} impl Display for ParseError { - fn fmt( - &self, - f: &mut std::fmt::Formatter<'_>, - ) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let message = match self { Self::UnknownType => { "The type does not exist. It needs to be one of 'song', 'video', 'image', 'presentation', or 'content'" diff --git a/src/core/model.rs b/src/core/model.rs index 35e3ad4..7482709 100644 --- a/src/core/model.rs +++ b/src/core/model.rs @@ -15,9 +15,7 @@ pub struct Model { pub kind: LibraryKind, } -#[derive( - Debug, Clone, PartialEq, Eq, Copy, Hash, Serialize, Deserialize, -)] +#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash, Serialize, Deserialize)] pub enum LibraryKind { Song, Video, @@ -25,9 +23,7 @@ pub enum LibraryKind { Presentation, } -#[derive( - Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, -)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct KindWrapper(pub (LibraryKind, i32)); impl From for LibraryKind { @@ -39,14 +35,10 @@ impl From for LibraryKind { impl TryFrom<(Vec, String)> for KindWrapper { type Error = miette::Error; - fn try_from( - value: (Vec, String), - ) -> std::result::Result { + fn try_from(value: (Vec, String)) -> std::result::Result { let (data, mime) = value; match mime.as_str() { - "application/service-item" => { - ron::de::from_bytes(&data).into_diagnostic() - } + "application/service-item" => ron::de::from_bytes(&data).into_diagnostic(), _ => Err(miette!("Wrong mime type: {mime}")), } } @@ -64,10 +56,7 @@ impl AsMimeTypes for KindWrapper { Cow::from(vec!["application/service-item".to_string()]) } - fn as_bytes( - &self, - mime_type: &str, - ) -> Option> { + fn as_bytes(&self, mime_type: &str) -> Option> { debug!(?self); debug!(mime_type); let ron = ron::ser::to_string(self).ok()?; @@ -86,11 +75,7 @@ impl Model { todo!() } - pub fn update_item

( - &mut self, - item: T, - predicate: P, - ) -> Result<()> + pub fn update_item

(&mut self, item: T, predicate: P) -> Result<()> where P: Fn(&T) -> bool, { @@ -98,7 +83,11 @@ impl Model { .iter() .position(predicate) .ok_or_else(|| miette!("Item cannot be found")) - .map(|index| self.items.get_mut(index).expect("Since we found position this should always exist")) + .map(|index| { + self.items + .get_mut(index) + .expect("Since we found position this should always exist") + }) .map(|current_item| { let _old_item = replace(current_item, item); }) @@ -119,9 +108,8 @@ impl Model { #[must_use] pub fn get_item(&self, index: i32) -> Option<&T> { - self.items.get( - usize::try_from(index).expect("shouldn't be negative"), - ) + self.items + .get(usize::try_from(index).expect("shouldn't be negative")) } pub fn find

(&self, f: P) -> Option<&T> @@ -131,11 +119,7 @@ impl Model { self.items.iter().find(f) } - pub fn insert_item( - &mut self, - item: T, - index: usize, - ) -> Result<()> { + pub fn insert_item(&mut self, item: T, index: usize) -> Result<()> { self.items.insert(index, item); Ok(()) } @@ -153,8 +137,7 @@ impl Model { // } pub async fn get_db() -> SqliteConnection { - let mut data = dirs::data_local_dir() - .expect("Should be able to find a data dir"); + let mut data = dirs::data_local_dir().expect("Should be able to find a data dir"); data.push("lumina"); let _ = fs::create_dir_all(&data); data.push("library-db.sqlite3"); diff --git a/src/core/presentations.rs b/src/core/presentations.rs index 71ab939..d568123 100644 --- a/src/core/presentations.rs +++ b/src/core/presentations.rs @@ -19,9 +19,7 @@ use super::kinds::ServiceItemKind; use super::model::{LibraryKind, Model}; use super::service_items::ServiceTrait; -#[derive( - Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, -)] +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] pub enum PresKind { Html, Pdf { @@ -147,20 +145,19 @@ impl From<&Value> for Presentation { fn from(value: &Value) -> Self { match value { Value::List(list) => { - let path = if let Some(path_pos) = - list.iter().position(|v| { - v == &Value::Keyword(Keyword::from("source")) - }) { + let path = if let Some(path_pos) = list + .iter() + .position(|v| v == &Value::Keyword(Keyword::from("source"))) + { let pos = path_pos + 1; - list.get(pos) - .map(|p| PathBuf::from(String::from(p))) + list.get(pos).map(|p| PathBuf::from(String::from(p))) } else { None }; - let title = path.clone().map(|p| { - p.to_str().unwrap_or_default().to_string() - }); + let title = path + .clone() + .map(|p| p.to_str().unwrap_or_default().to_string()); Self { title: title.unwrap_or_default(), path: path.unwrap_or_default(), @@ -188,23 +185,18 @@ impl ServiceTrait for Presentation { ending_index, } = self.kind else { - return Err(miette::miette!( - "This is not a pdf presentation" - )); + return Err(miette::miette!("This is not a pdf presentation")); }; - let background = Background::try_from(self.path.clone()) - .into_diagnostic()?; + let background = Background::try_from(self.path.clone()).into_diagnostic()?; debug!(?background); - let document = Document::open(background.path.as_path()) - .into_diagnostic()?; + let document = Document::open(background.path.as_path()).into_diagnostic()?; debug!(?document); let pages = document.pages().into_diagnostic()?; debug!(?pages); let pages: Vec = pages .enumerate() .filter_map(|(index, page)| { - let index = i32::try_from(index) - .expect("Shouldn't be that high"); + let index = i32::try_from(index).expect("Shouldn't be that high"); if index < starting_index || index > ending_index { return None; @@ -232,10 +224,7 @@ impl ServiceTrait for Presentation { let mut slides: Vec = vec![]; for (index, page) in pages.into_iter().enumerate() { let slide = SlideBuilder::new() - .background( - Background::try_from(self.path.clone()) - .into_diagnostic()?, - ) + .background(Background::try_from(self.path.clone()).into_diagnostic()?) .text("") .audio("") .font("") @@ -244,10 +233,7 @@ impl ServiceTrait for Presentation { .video_loop(false) .video_start_time(0.0) .video_end_time(0.0) - .pdf_index( - u32::try_from(index) - .expect("Shouldn't get that high"), - ) + .pdf_index(u32::try_from(index).expect("Shouldn't get that high")) .pdf_page(page) .build()?; slides.push(slide); @@ -323,26 +309,17 @@ impl Model { path: presentation.path.clone().into(), kind: if presentation.html { PresKind::Html - } else if let ( - Some(starting_index), - Some(ending_index), - ) = ( - presentation.starting_index, - presentation.ending_index, - ) { + } else if let (Some(starting_index), Some(ending_index)) = + (presentation.starting_index, presentation.ending_index) + { PresKind::Pdf { - starting_index: i32::try_from( - starting_index, - ) - .expect("Shouldn't get that high"), - ending_index: i32::try_from( - ending_index, - ) - .expect("Shouldn't get that high"), + starting_index: i32::try_from(starting_index) + .expect("Shouldn't get that high"), + ending_index: i32::try_from(ending_index) + .expect("Shouldn't get that high"), } } else { - let path = - PathBuf::from(presentation.path); + let path = PathBuf::from(presentation.path); Document::open(path.as_path()).map_or( PresKind::Generic, @@ -353,8 +330,7 @@ impl Model { ending_index: 0, }, |count| { - let ending_index = - count - 1; + let ending_index = count - 1; PresKind::Pdf { starting_index: 0, ending_index, @@ -367,9 +343,7 @@ impl Model { }); } } - Err(e) => error!( - "There was an error in converting presentations: {e}" - ), + Err(e) => error!("There was an error in converting presentations: {e}"), } } } @@ -381,9 +355,7 @@ pub async fn remove_presentations( ) -> Result> { let presentations = presentations .into_iter() - .filter(|current_presentation| { - !ids.contains(¤t_presentation.id) - }) + .filter(|current_presentation| !ids.contains(¤t_presentation.id)) .collect(); let delete = format!( @@ -411,12 +383,8 @@ pub async fn remove_presentation( let index = presentations .iter() - .position(|current_presentation| { - current_presentation.id == id - }) - .ok_or_else(|| { - miette!("Could not find presentation in model") - })?; + .position(|current_presentation| current_presentation.id == id) + .ok_or_else(|| miette!("Could not find presentation in model"))?; presentations.remove(index); Ok(presentations) } @@ -473,8 +441,7 @@ pub async fn update_presentation( let (starting_index, ending_index) = if let PresKind::Pdf { starting_index: s_index, ending_index: e_index, - } = - presentation.get_kind() + } = presentation.get_kind() { (*s_index, *e_index) } else { @@ -496,12 +463,8 @@ pub async fn update_presentation( let current_presentation = presentations .iter() - .position(|current_presentation| { - current_presentation.id == presentation.id - }) - .ok_or_else(|| { - miette!("Could not find presentation in model") - }) + .position(|current_presentation| current_presentation.id == presentation.id) + .ok_or_else(|| miette!("Could not find presentation in model")) .map(|index| { presentations .get_mut(index) @@ -556,9 +519,7 @@ mod test { }; let db = Arc::new(add_db().await.expect("Getting db error")); presentation_model.load_from_db(db).await; - if let Some(presentation) = - presentation_model.find(|p| p.id == 4) - { + if let Some(presentation) = presentation_model.find(|p| p.id == 4) { let test_presentation = test_presentation(); assert_eq!(&test_presentation, presentation); } else { diff --git a/src/core/service_items.rs b/src/core/service_items.rs index fb341fa..5b89ebb 100644 --- a/src/core/service_items.rs +++ b/src/core/service_items.rs @@ -45,9 +45,7 @@ impl Ord for ServiceItem { impl TryFrom<(Vec, String)> for ServiceItem { type Error = miette::Error; - fn try_from( - value: (Vec, String), - ) -> std::result::Result { + fn try_from(value: (Vec, String)) -> std::result::Result { let (data, mime) = value; debug!(?mime); ron::de::from_bytes(&data).into_diagnostic() @@ -70,10 +68,7 @@ impl AsMimeTypes for ServiceItem { Cow::from(vec!["application/service-item".to_string()]) } - fn as_bytes( - &self, - mime_type: &str, - ) -> Option> { + fn as_bytes(&self, mime_type: &str) -> Option> { debug!(?self); debug!(mime_type); let ron = ron::ser::to_string(self).ok()?; @@ -89,18 +84,10 @@ impl TryFrom for ServiceItem { let ext = path .extension() .and_then(|ext| ext.to_str()) - .ok_or_else(|| { - miette::miette!( - "There isn't an extension on this file" - ) - })?; + .ok_or_else(|| miette::miette!("There isn't an extension on this file"))?; match ext { - "png" | "jpg" | "jpeg" => { - Ok(Self::from(&Image::from(path))) - } - "mp4" | "mkv" | "webm" => { - Ok(Self::from(&Video::from(path))) - } + "png" | "jpg" | "jpeg" => Ok(Self::from(&Image::from(path))), + "mp4" | "mkv" | "webm" => Ok(Self::from(&Video::from(path))), _ => Err(miette!("Unkown service item")), } } @@ -112,9 +99,7 @@ impl From<&ServiceItem> for Value { ServiceItemKind::Song(song) => Self::from(song), ServiceItemKind::Video(video) => Self::from(video), ServiceItemKind::Image(image) => Self::from(image), - ServiceItemKind::Presentation(presentation) => { - Self::from(presentation) - } + ServiceItemKind::Presentation(presentation) => Self::from(presentation), ServiceItemKind::Content(slide) => Self::from(slide), } } @@ -130,12 +115,8 @@ impl ServiceItem { ServiceItemKind::Song(song) => song.to_slides(), ServiceItemKind::Video(video) => video.to_slides(), ServiceItemKind::Image(image) => image.to_slides(), - ServiceItemKind::Presentation(presentation) => { - presentation.to_slides() - } - ServiceItemKind::Content(slide) => { - Ok(vec![slide.clone()]) - } + ServiceItemKind::Presentation(presentation) => presentation.to_slides(), + ServiceItemKind::Content(slide) => Ok(vec![slide.clone()]), } } } @@ -177,70 +158,44 @@ impl From<&Value> for ServiceItem { _ => false, }) .map_or_else(|| 1, |pos| pos + 1); - if let Some(_content) = - list.iter().position(|v| match v { - Value::List(list) - if list.iter().next() - == Some(&Value::Symbol( - Symbol("text".into()), - )) => - { - list.iter().next().is_some() - } - _ => false, - }) - { + if let Some(_content) = list.iter().position(|v| match v { + Value::List(list) + if list.iter().next() + == Some(&Value::Symbol(Symbol("text".into()))) => + { + list.iter().next().is_some() + } + _ => false, + }) { let slide = Slide::from(value); let title = slide.text(); Self { id: 0, title, database_id: 0, - kind: ServiceItemKind::Content( - slide.clone(), - ), + kind: ServiceItemKind::Content(slide.clone()), slides: vec![slide], } - } else if let Some(background) = - list.get(background_pos) - { + } else if let Some(background) = list.get(background_pos) { if let Value::List(item) = background { match &item[0] { - Value::Symbol(Symbol(s)) - if s == "image" => - { - Self::from(&Image::from( - background, - )) + Value::Symbol(Symbol(s)) if s == "image" => { + Self::from(&Image::from(background)) } - Value::Symbol(Symbol(s)) - if s == "video" => - { - Self::from(&Video::from( - background, - )) + Value::Symbol(Symbol(s)) if s == "video" => { + Self::from(&Video::from(background)) } - Value::Symbol(Symbol(s)) - if s == "presentation" => - { - Self::from(&Presentation::from( - background, - )) + Value::Symbol(Symbol(s)) if s == "presentation" => { + Self::from(&Presentation::from(background)) } _ => todo!(), } } else { - error!( - "There is no background here: {:?}", - background - ); + error!("There is no background here: {:?}", background); Self::default() } } else { - error!( - "There is no background here: {:?}", - background_pos - ); + error!("There is no background here: {:?}", background_pos); Self::default() } } @@ -346,9 +301,7 @@ impl From<&Presentation> for ServiceItem { fn from(presentation: &Presentation) -> Self { match presentation.to_slides() { Ok(slides) => Self { - kind: ServiceItemKind::Presentation( - presentation.clone(), - ), + kind: ServiceItemKind::Presentation(presentation.clone()), database_id: presentation.id, title: presentation.title.clone(), slides, @@ -357,9 +310,7 @@ impl From<&Presentation> for ServiceItem { Err(e) => { error!(?e); Self { - kind: ServiceItemKind::Presentation( - presentation.clone(), - ), + kind: ServiceItemKind::Presentation(presentation.clone()), database_id: presentation.id, title: presentation.title.clone(), ..Default::default() @@ -410,10 +361,7 @@ impl Clone for Box { } impl std::fmt::Debug for Box { - fn fmt( - &self, - f: &mut std::fmt::Formatter<'_>, - ) -> Result<(), std::fmt::Error> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { write!(f, "{}: {}", self.id(), self.title()) } } @@ -453,14 +401,8 @@ mod test { let pres_item = ServiceItem::from(&pres); let mut service_model = Service::default(); service_model.add_item(&song); - assert_eq!( - ServiceItemKind::Song(song), - service_model.items[0].kind - ); - assert_eq!( - ServiceItemKind::Presentation(pres), - pres_item.kind - ); + assert_eq!(ServiceItemKind::Song(song), service_model.items[0].kind); + assert_eq!(ServiceItemKind::Presentation(pres), pres_item.kind); assert_eq!(service_item, service_model.items[0]); } } diff --git a/src/core/settings.rs b/src/core/settings.rs index d64e79a..baf4ee4 100644 --- a/src/core/settings.rs +++ b/src/core/settings.rs @@ -9,9 +9,7 @@ use std::path::PathBuf; pub const SETTINGS_VERSION: u64 = 1; -#[derive( - Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, -)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] pub enum AppTheme { Dark, Light, @@ -28,15 +26,7 @@ impl AppTheme { } } -#[derive( - Clone, - CosmicConfigEntry, - Debug, - Deserialize, - Eq, - PartialEq, - Serialize, -)] +#[derive(Clone, CosmicConfigEntry, Debug, Deserialize, Eq, PartialEq, Serialize)] #[serde(default)] pub struct Settings { pub app_theme: AppTheme, @@ -55,14 +45,7 @@ impl Default for Settings { } #[derive( - Clone, - CosmicConfigEntry, - Debug, - Deserialize, - Eq, - PartialEq, - Serialize, - Default, + Clone, CosmicConfigEntry, Debug, Deserialize, Eq, PartialEq, Serialize, Default, )] pub struct PersistentState { pub recent_files: VecDeque, diff --git a/src/core/slide.rs b/src/core/slide.rs index eecafcf..8166938 100755 --- a/src/core/slide.rs +++ b/src/core/slide.rs @@ -12,13 +12,12 @@ use std::fmt::Display; use std::path::{Path, PathBuf}; use tracing::error; +use crate::ui::gst_video; use crate::ui::text_svg::{Color, Font, Shadow, Stroke, TextSvg}; use super::songs::Song; -#[derive( - Clone, Debug, Default, PartialEq, Serialize, Deserialize, -)] +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct Slide { id: i32, pub(crate) background: Background, @@ -39,9 +38,7 @@ pub struct Slide { pdf_page: Option, } -#[derive( - Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize, -)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] pub enum BackgroundKind { #[default] Image, @@ -50,17 +47,7 @@ pub enum BackgroundKind { Html, } -#[derive( - Clone, - Copy, - Debug, - Default, - PartialEq, - Eq, - Serialize, - Deserialize, - Hash, -)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize, Hash)] pub enum TextAlignment { TopLeft, TopCenter, @@ -90,9 +77,7 @@ impl From<&Value> for TextAlignment { } } -#[derive( - Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, -)] +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] pub struct Background { pub path: PathBuf, pub kind: BackgroundKind, @@ -103,9 +88,7 @@ pub struct Background { impl TryFrom<&Background> for Video { type Error = ParseError; - fn try_from( - value: &Background, - ) -> std::result::Result { + fn try_from(value: &Background) -> std::result::Result { Self::new( &url::Url::from_file_path(value.path.clone()) .map_err(|()| ParseError::BackgroundNotVideo)?, @@ -117,14 +100,16 @@ impl TryFrom<&Background> for Video { impl TryFrom for Video { type Error = ParseError; - fn try_from( - value: Background, - ) -> std::result::Result { - Self::new( - &url::Url::from_file_path(value.path) - .map_err(|()| ParseError::BackgroundNotVideo)?, - ) - .map_err(|_| ParseError::BackgroundNotVideo) + fn try_from(value: Background) -> std::result::Result { + let url = &url::Url::from_file_path(value.path) + .map_err(|()| ParseError::BackgroundNotVideo)?; + + let settings = gst_video::VideoSettings { + mute: true, + framerate: 30, + }; + gst_video::create_video(url, &settings) + .map_err(|_| ParseError::BackgroundNotVideo) } } @@ -139,10 +124,7 @@ impl TryFrom for Background { type Error = ParseError; fn try_from(path: PathBuf) -> Result { let path = if path.starts_with("~") { - let path = path - .to_str() - .expect("Should have a string") - .to_string(); + let path = path.to_str().expect("Should have a string").to_string(); let path = path.trim_start_matches("file://"); let home = dirs::home_dir() .expect("We should have a home directory") @@ -237,21 +219,12 @@ pub enum ParseError { impl std::error::Error for ParseError {} impl Display for ParseError { - fn fmt( - &self, - f: &mut std::fmt::Formatter<'_>, - ) -> std::fmt::Result { + 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" - } + Self::NonBackgroundFile => "The file is not a recognized image or video type", Self::DoesNotExist => "This file doesn't exist", - Self::CannotCanonicalize => { - "Could not canonicalize this file" - } - Self::BackgroundNotVideo => { - "This background isn't a video" - } + Self::CannotCanonicalize => "Could not canonicalize this file", + Self::BackgroundNotVideo => "This background isn't a video", }; write!(f, "Error: {message}") } @@ -398,9 +371,7 @@ impl Slide { .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(), - ) + .text_alignment(song.text_alignment.unwrap_or_default()) .audio(song.audio.unwrap_or_default()) .video_loop(true) .video_start_time(0.0) @@ -444,10 +415,10 @@ fn lisp_to_slide(lisp: &[Value]) -> Slide { const DEFAULT_TEXT_LOCATION: usize = 0; let mut slide = SlideBuilder::new(); - let background_position = if let Some(background) = - lisp.iter().position(|v| { - v == &Value::Keyword(Keyword::from("background")) - }) { + let background_position = if let Some(background) = lisp + .iter() + .position(|v| v == &Value::Keyword(Keyword::from("background"))) + { background + 1 } else { DEFAULT_BACKGROUND_LOCATION @@ -461,8 +432,7 @@ fn lisp_to_slide(lisp: &[Value]) -> Slide { let text_position = lisp.iter().position(|v| match v { Value::List(vec) => { - vec[DEFAULT_TEXT_LOCATION] - == Value::Symbol(Symbol::from("text")) + vec[DEFAULT_TEXT_LOCATION] == Value::Symbol(Symbol::from("text")) } _ => false, }); @@ -507,14 +477,11 @@ fn lisp_to_slide(lisp: &[Value]) -> Slide { fn lisp_to_font_size(lisp: &Value) -> i32 { match lisp { Value::List(list) => { - if let Some(font_size_position) = - list.iter().position(|v| { - v == &Value::Keyword(Keyword::from("font-size")) - }) + if let Some(font_size_position) = list + .iter() + .position(|v| v == &Value::Keyword(Keyword::from("font-size"))) { - if let Some(font_size_value) = - list.get(font_size_position + 1) - { + if let Some(font_size_value) = list.get(font_size_position + 1) { font_size_value.into() } else { 50 @@ -541,9 +508,10 @@ pub fn lisp_to_background(lisp: &Value) -> Background { match lisp { Value::List(list) => { let _kind = list[0].clone(); - if let Some(source) = list.iter().position(|v| { - v == &Value::Keyword(Keyword::from("source")) - }) { + if let Some(source) = list + .iter() + .position(|v| v == &Value::Keyword(Keyword::from("source"))) + { let source = &list[source + 1]; match source { Value::String(s) => { @@ -561,9 +529,7 @@ pub fn lisp_to_background(lisp: &Value) -> Background { match Background::try_from(s.as_str()) { Ok(background) => background, Err(e) => { - error!( - "Couldn't load background: {e}" - ); + error!("Couldn't load background: {e}"); Background::default() } } @@ -571,9 +537,7 @@ pub fn lisp_to_background(lisp: &Value) -> Background { match Background::try_from(s.as_str()) { Ok(background) => background, Err(e) => { - error!( - "Couldn't load background: {e}" - ); + error!("Couldn't load background: {e}"); Background::default() } } @@ -589,9 +553,7 @@ pub fn lisp_to_background(lisp: &Value) -> Background { } } -#[derive( - Clone, Debug, Default, PartialEq, Serialize, Deserialize, -)] +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct SlideBuilder { background: Option, text: Option, @@ -626,10 +588,7 @@ impl SlideBuilder { Ok(self) } - pub(crate) fn background( - mut self, - background: Background, - ) -> Self { + pub(crate) fn background(mut self, background: Background) -> Self { let _ = self.background.insert(background); self } @@ -639,10 +598,7 @@ impl SlideBuilder { self } - pub(crate) fn text_color( - mut self, - text_color: impl Into, - ) -> Self { + pub(crate) fn text_color(mut self, text_color: impl Into) -> Self { let _ = self.text_color.insert(text_color.into()); self } @@ -667,26 +623,17 @@ impl SlideBuilder { self } - pub(crate) fn stroke( - mut self, - stroke: impl Into, - ) -> Self { + pub(crate) fn stroke(mut self, stroke: impl Into) -> Self { let _ = self.stroke.insert(stroke.into()); self } - pub(crate) fn shadow( - mut self, - shadow: impl Into, - ) -> Self { + pub(crate) fn shadow(mut self, shadow: impl Into) -> Self { let _ = self.shadow.insert(shadow.into()); self } - pub(crate) fn text_alignment( - mut self, - text_alignment: TextAlignment, - ) -> Self { + pub(crate) fn text_alignment(mut self, text_alignment: TextAlignment) -> Self { let _ = self.text_alignment.insert(text_alignment); self } @@ -696,26 +643,17 @@ impl SlideBuilder { self } - pub(crate) fn video_start_time( - mut self, - video_start_time: f32, - ) -> Self { + pub(crate) fn video_start_time(mut self, video_start_time: f32) -> Self { let _ = self.video_start_time.insert(video_start_time); self } - pub(crate) fn video_end_time( - mut self, - video_end_time: f32, - ) -> Self { + pub(crate) fn video_end_time(mut self, video_end_time: f32) -> Self { let _ = self.video_end_time.insert(video_end_time); self } - pub(crate) fn text_svg( - mut self, - text_svg: impl Into, - ) -> Self { + pub(crate) fn text_svg(mut self, text_svg: impl Into) -> Self { let _ = self.text_svg.insert(text_svg.into()); self } @@ -725,10 +663,7 @@ impl SlideBuilder { self } - pub(crate) fn pdf_index( - mut self, - pdf_index: impl Into, - ) -> Self { + pub(crate) fn pdf_index(mut self, pdf_index: impl Into) -> Self { let _ = self.pdf_index.insert(pdf_index.into()); self } @@ -786,8 +721,7 @@ mod test { fn test_slide() -> Slide { Slide { text: "This is frodo".to_string(), - background: Background::try_from("~/pics/frodo.jpg") - .expect(""), + background: Background::try_from("~/pics/frodo.jpg").expect(""), font: Some("Quicksand".to_string().into()), font_size: 140, ..Default::default() @@ -797,10 +731,7 @@ mod test { fn test_second_slide() -> Slide { Slide { text: String::new(), - background: Background::try_from( - "~/vids/test/camprules2024.mp4", - ) - .expect(""), + background: Background::try_from("~/vids/test/camprules2024.mp4").expect(""), font: Some("Quicksand".to_string().into()), ..Default::default() } @@ -808,8 +739,8 @@ mod test { #[test] fn test_ron_deserialize() { - let slide = read_to_string("./test_presentation.ron") - .expect("Problem getting file read"); + let slide = + read_to_string("./test_presentation.ron").expect("Problem getting file read"); if let Err(e) = ron::from_str::>(&slide) { panic!("{e:?}") } diff --git a/src/core/song_search.rs b/src/core/song_search.rs index 97b00f8..d913c19 100644 --- a/src/core/song_search.rs +++ b/src/core/song_search.rs @@ -16,15 +16,7 @@ use std::fmt::Display; use tracing::error; #[derive( - Clone, - Debug, - Default, - PartialEq, - Eq, - PartialOrd, - Ord, - Serialize, - Deserialize, + Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, )] pub struct OnlineSong { pub lyrics: String, @@ -35,15 +27,7 @@ pub struct OnlineSong { } #[derive( - Debug, - Clone, - Default, - PartialEq, - Eq, - PartialOrd, - Ord, - Serialize, - Deserialize, + Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, )] pub enum Provider { Genius { @@ -54,10 +38,7 @@ pub enum Provider { } impl Display for Provider { - fn fmt( - &self, - f: &mut std::fmt::Formatter<'_>, - ) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Genius { .. } => f.write_str("Genius"), Self::LyricsCom => f.write_str("Lyrics.com"), @@ -67,13 +48,8 @@ impl Display for Provider { impl From for Song { fn from(online_song: OnlineSong) -> Self { - let verse_map = if online_song.provider - == (Provider::Genius { parsable: true }) - { - parse_genius_lyrics( - &online_song.lyrics.replace("\\n", "\n"), - ) - .ok() + let verse_map = if online_song.provider == (Provider::Genius { parsable: true }) { + parse_genius_lyrics(&online_song.lyrics.replace("\\n", "\n")).ok() } else { let mut map = HashMap::new(); map.entry(VerseName::Verse { number: 1 }) @@ -103,14 +79,11 @@ impl From for Song { } #[allow(clippy::redundant_closure_for_method_calls)] -fn parse_genius_lyrics( - lyrics: &str, -) -> Result> { - let (input, chunks) = - many1(pair(parse_verse_name, alt((take_until("["), rest)))) - .parse(lyrics) - .map_err(|e| e.to_owned()) - .into_diagnostic()?; +fn parse_genius_lyrics(lyrics: &str) -> Result> { + let (input, chunks) = many1(pair(parse_verse_name, alt((take_until("["), rest)))) + .parse(lyrics) + .map_err(|e| e.to_owned()) + .into_diagnostic()?; dbg!(input); dbg!(&chunks); @@ -160,16 +133,12 @@ fn parse_verse_name(line: &str) -> IResult<&str, VerseName> { Ok((input, verse_name)) } -pub async fn search_genius( - query: String, - auth_token: String, -) -> Result> { +pub async fn search_genius(query: String, auth_token: String) -> Result> { // let Some(auth_token) = option_env!("GENIUS_TOKEN") else { // return Err(miette!("No Genius Token")); // }; - let head_value = header::HeaderValue::from_str(&auth_token) - .into_diagnostic()?; + let head_value = header::HeaderValue::from_str(&auth_token).into_diagnostic()?; let mut headers = header::HeaderMap::new(); headers.insert(header::AUTHORIZATION, head_value); let client = reqwest::Client::builder() @@ -186,8 +155,7 @@ pub async fn search_genius( .text() .await .into_diagnostic()?; - let json: Value = - serde_json::from_str(&response).into_diagnostic()?; + let json: Value = serde_json::from_str(&response).into_diagnostic()?; let hits = json .get("response") .expect("respose") @@ -196,52 +164,48 @@ pub async fn search_genius( .as_array() .expect("array"); let songs: Vec> = - cosmic::iced::futures::future::join_all(hits.iter().map( - |hit| async { - let result = hit.get("result").expect("result"); - let title = result - .get("title") - .expect("title") - .as_str() - .expect("title") - .to_string(); - let title = title.replace("\u{a0}", " "); - let author = result - .get("artist_names") - .expect("artists") - .as_str() - .expect("artists") - .to_string(); - let link = result - .get("url") - .expect("url") - .as_str() - .expect("url") - .to_string(); - let song = OnlineSong { - lyrics: String::new(), - title, - author, - provider: Provider::Genius { parsable: false }, - link, - }; + cosmic::iced::futures::future::join_all(hits.iter().map(|hit| async { + let result = hit.get("result").expect("result"); + let title = result + .get("title") + .expect("title") + .as_str() + .expect("title") + .to_string(); + let title = title.replace("\u{a0}", " "); + let author = result + .get("artist_names") + .expect("artists") + .as_str() + .expect("artists") + .to_string(); + let link = result + .get("url") + .expect("url") + .as_str() + .expect("url") + .to_string(); + let song = OnlineSong { + lyrics: String::new(), + title, + author, + provider: Provider::Genius { parsable: false }, + link, + }; - match get_genius_lyrics(song).await { - Ok(song) => Some(song), - Err(e) => { - error!("Couldn't get lyrics: {e}"); - None - } + match get_genius_lyrics(song).await { + Ok(song) => Some(song), + Err(e) => { + error!("Couldn't get lyrics: {e}"); + None } - }, - )) + } + })) .await; Ok(songs.into_iter().flatten().collect()) } -pub async fn get_genius_lyrics( - mut song: OnlineSong, -) -> Result { +pub async fn get_genius_lyrics(mut song: OnlineSong) -> Result { let html = reqwest::get(&song.link) .await .into_diagnostic()? @@ -251,17 +215,15 @@ pub async fn get_genius_lyrics( .await .into_diagnostic()?; let document = scraper::Html::parse_document(&html); - let Ok(lyrics_root_selector) = scraper::Selector::parse( - r#"div[data-lyrics-container="true"]"#, - ) else { + let Ok(lyrics_root_selector) = + scraper::Selector::parse(r#"div[data-lyrics-container="true"]"#) + else { return Err(miette!("error in finding lyrics_root")); }; let lyrics = document .select(&lyrics_root_selector) - .filter(|element| { - element.attr("data-exclude-from-selection").is_none() - }) + .filter(|element| element.attr("data-exclude-from-selection").is_none()) .filter(|element| { !element.value().classes().any(|class| { class.contains("Contrib") @@ -278,11 +240,7 @@ pub async fn get_genius_lyrics( line_broken .root_element() .descendent_elements() - .filter(|element| { - element - .attr("data-exclude-from-selection") - .is_none() - }) + .filter(|element| element.attr("data-exclude-from-selection").is_none()) .filter(|element| { let element_name = element.value().name(); element_name != "div" && element_name != "path" @@ -307,9 +265,7 @@ pub async fn get_genius_lyrics( || { lyrics.find("").map_or_else( || lyrics.clone(), - |position| { - lyrics.split_at(position + 18).1.to_string() - }, + |position| lyrics.split_at(position + 18).1.to_string(), ) }, |position| lyrics.split_at(position).1.to_string(), @@ -324,20 +280,17 @@ pub async fn get_genius_lyrics( pub async fn search_lyrics_com_links( query: impl AsRef + std::fmt::Display, ) -> Result> { - let html = - reqwest::get(format!("http://www.lyrics.com/lyrics/{query}")) - .await - .into_diagnostic()? - .error_for_status() - .into_diagnostic()? - .text() - .await - .into_diagnostic()?; + let html = reqwest::get(format!("http://www.lyrics.com/lyrics/{query}")) + .await + .into_diagnostic()? + .error_for_status() + .into_diagnostic()? + .text() + .await + .into_diagnostic()?; let document = scraper::Html::parse_document(&html); - let Ok(best_matches_selector) = - scraper::Selector::parse(".best-matches") - else { + let Ok(best_matches_selector) = scraper::Selector::parse(".best-matches") else { return Err(miette!("error in finding matches")); }; let Ok(lyric_selector) = scraper::Selector::parse("a") else { @@ -347,9 +300,7 @@ pub async fn search_lyrics_com_links( Ok(document .select(&best_matches_selector) .flat_map(|best_section| best_section.select(&lyric_selector)) - .map(|a| { - a.value().attr("href").unwrap_or("").trim().to_string() - }) + .map(|a| a.value().attr("href").unwrap_or("").trim().to_string()) .filter(|a| a.contains("/lyric/")) .dedup() .map(|link| { @@ -389,9 +340,7 @@ pub async fn lyrics_com_link_to_song( .into_diagnostic()?; let document = scraper::Html::parse_document(&html); - let Ok(lyric_selector) = - scraper::Selector::parse(".lyric-body") - else { + let Ok(lyric_selector) = scraper::Selector::parse(".lyric-body") else { return Err(miette!("error in finding lyric-body",)); }; @@ -430,7 +379,8 @@ mod test { title: "Death Was Arrested".to_string(), author: "North Point Worship (Ft. Seth Condrey)".to_string(), provider: Provider::Genius { parsable: false }, - link: "https://genius.com/North-point-worship-death-was-arrested-lyrics".to_string(), + link: "https://genius.com/North-point-worship-death-was-arrested-lyrics" + .to_string(), }; let hits = search_genius( "Death was arrested".to_string(), @@ -444,13 +394,10 @@ mod test { "There was no song that matched on Genius" ); - let titles: Vec = - hits.iter().map(|song| song.title.clone()).collect(); + let titles: Vec = hits.iter().map(|song| song.title.clone()).collect(); dbg!(titles); for hit in hits { - let new_song = get_genius_lyrics(hit) - .await - .map_err(|e| e.to_string())?; + let new_song = get_genius_lyrics(hit).await.map_err(|e| e.to_string())?; dbg!(&new_song); dbg!(&new_song.provider); if new_song.lyrics.starts_with("[Verse 1]") { @@ -467,13 +414,12 @@ mod test { assert!(!map.is_empty()); // Need to leave commented until I work on more robust tests. assert!( - map.keys() - .contains(&VerseName::Verse { number: 1 }) // && map.keys().contains(&VerseName::Verse { - // number: 2 - // }) - // && map.keys().contains(&VerseName::Chorus { - // number: 1 - // }) + map.keys().contains(&VerseName::Verse { number: 1 }) // && map.keys().contains(&VerseName::Verse { + // number: 2 + // }) + // && map.keys().contains(&VerseName::Chorus { + // number: 1 + // }) ); } else { assert!( @@ -502,9 +448,10 @@ mod test { let songs = lyrics_com_link_to_song(links) .await .map_err(|e| format!("{e}"))?; - if let Some(first) = songs.iter().find_or_first(|song| { - song.author == "North Point InsideOut" - }) { + if let Some(first) = songs + .iter() + .find_or_first(|song| song.author == "North Point InsideOut") + { assert_eq!(&song, first); // online_song_to_song(song)?; } @@ -516,14 +463,10 @@ mod test { let song = Song::from(song); if let Some(verse_map) = song.verse_map.as_ref() { if verse_map.is_empty() { - return Err(format!( - "VerseMap wasn't built right likely: {song:?}", - )); + return Err(format!("VerseMap wasn't built right likely: {song:?}",)); } } else { - return Err(String::from( - "There is no VerseMap in this song", - )); + return Err(String::from("There is no VerseMap in this song")); } Ok(()) } diff --git a/src/core/songs.rs b/src/core/songs.rs index 2b25440..97c0921 100644 --- a/src/core/songs.rs +++ b/src/core/songs.rs @@ -24,9 +24,7 @@ use crate::core::slide::{self, Background, TextAlignment}; use crate::ui::text_svg::{Color, Font, Stroke, shadow, stroke}; use crate::{Slide, SlideBuilder}; -#[derive( - Clone, Debug, Default, PartialEq, Serialize, Deserialize, -)] +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct Song { pub id: i32, pub title: String, @@ -54,16 +52,7 @@ pub struct Song { } #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Serialize, - Deserialize, - Hash, - PartialOrd, - Ord, + Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Hash, PartialOrd, Ord, )] pub enum VerseName { Verse { number: usize }, @@ -115,33 +104,15 @@ impl VerseName { #[must_use] pub fn next(&self) -> Self { match self { - Self::Verse { number } => { - Self::Verse { number: number + 1 } - } - Self::PreChorus { number } => { - Self::PreChorus { number: number + 1 } - } - Self::Chorus { number } => { - Self::Chorus { number: number + 1 } - } - Self::PostChorus { number } => { - Self::PostChorus { number: number + 1 } - } - Self::Bridge { number } => { - Self::Bridge { number: number + 1 } - } - Self::Intro { number } => { - Self::Intro { number: number + 1 } - } - Self::Outro { number } => { - Self::Outro { number: number + 1 } - } - Self::Instrumental { number } => { - Self::Instrumental { number: number + 1 } - } - Self::Other { number } => { - Self::Other { number: number + 1 } - } + Self::Verse { number } => Self::Verse { number: number + 1 }, + Self::PreChorus { number } => Self::PreChorus { number: number + 1 }, + Self::Chorus { number } => Self::Chorus { number: number + 1 }, + Self::PostChorus { number } => Self::PostChorus { number: number + 1 }, + Self::Bridge { number } => Self::Bridge { number: number + 1 }, + Self::Intro { number } => Self::Intro { number: number + 1 }, + Self::Outro { number } => Self::Outro { number: number + 1 }, + Self::Instrumental { number } => Self::Instrumental { number: number + 1 }, + Self::Other { number } => Self::Other { number: number + 1 }, Self::Blank => Self::Blank, } } @@ -202,9 +173,7 @@ impl VerseName { impl TryFrom<(Vec, String)> for VerseName { type Error = miette::Error; - fn try_from( - value: (Vec, String), - ) -> std::result::Result { + fn try_from(value: (Vec, String)) -> std::result::Result { let (data, mime) = value; debug!(?mime); ron::de::from_bytes(&data).into_diagnostic() @@ -216,10 +185,7 @@ impl AsMimeTypes for VerseName { Cow::from(vec!["application/verse".to_string()]) } - fn as_bytes( - &self, - _mime_type: &str, - ) -> Option> { + fn as_bytes(&self, _mime_type: &str) -> Option> { let ron = ron::ser::to_string(self).ok()?; Some(Cow::from(ron.into_bytes())) } @@ -275,9 +241,7 @@ impl ServiceTrait for Song { let lyrics: Vec = self .verses .as_ref() - .ok_or_else(|| { - miette!("There are no verses assigned yet.") - })? + .ok_or_else(|| miette!("There are no verses assigned yet."))? .iter() .filter_map(|verse| self.get_lyric(verse)) .flat_map(|lyric| { @@ -293,34 +257,21 @@ impl ServiceTrait for Song { .iter() .filter_map(|l| { let font = Font::default() - .name( - self.font - .clone() - .unwrap_or_else(|| "Calibri".into()), - ) + .name(self.font.clone().unwrap_or_else(|| "Calibri".into())) .style(self.font_style.unwrap_or_default()) .weight(self.font_weight.unwrap_or_default()) - .size( - u8::try_from(self.font_size.unwrap_or(100)) - .unwrap_or(100), - ); - let stroke_size = - self.stroke_size.unwrap_or_default(); + .size(u8::try_from(self.font_size.unwrap_or(100)).unwrap_or(100)); + let stroke_size = self.stroke_size.unwrap_or_default(); let stroke: Stroke = stroke( stroke_size, - self.stroke_color - .map(Color::from) - .unwrap_or_default(), + self.stroke_color.map(Color::from).unwrap_or_default(), ); - let shadow_size = - self.shadow_size.unwrap_or_default(); + let shadow_size = self.shadow_size.unwrap_or_default(); let shadow = shadow( self.shadow_offset.unwrap_or_default().0, self.shadow_offset.unwrap_or_default().1, shadow_size, - self.shadow_color - .map(Color::from) - .unwrap_or_default(), + self.shadow_color.map(Color::from).unwrap_or_default(), ); let builder = SlideBuilder::new(); let builder = if shadow_size > 0 { @@ -334,18 +285,12 @@ impl ServiceTrait for Song { builder }; builder - .background( - self.background.clone().unwrap_or_default(), - ) + .background(self.background.clone().unwrap_or_default()) .font(font) .font_size(self.font_size.unwrap_or_default()) - .text_alignment( - self.text_alignment.unwrap_or_default(), - ) + .text_alignment(self.text_alignment.unwrap_or_default()) .text_color( - self.text_color.unwrap_or_else(|| { - Srgb::new(1.0, 1.0, 1.0) - }), + self.text_color.unwrap_or_else(|| Srgb::new(1.0, 1.0, 1.0)), ) .audio(self.audio.clone().unwrap_or_default()) .video_loop(true) @@ -370,27 +315,19 @@ impl FromRow<'_, SqliteRow> for Song { fn from_row(row: &SqliteRow) -> sqlx::Result { let lyrics: &str = row.try_get("lyrics")?; - let Ok(verse_map) = ron::de::from_str::< - Option>, - >(lyrics) else { + let Ok(verse_map) = + ron::de::from_str::>>(lyrics) + else { return Err(sqlx::Error::ColumnDecode { index: "8".into(), - source: miette!( - "Couldn't decode the song into verses" - ) - .into(), + source: miette!("Couldn't decode the song into verses").into(), }); }; let verse_order: &str = row.try_get("verse_order")?; - let Ok(verses) = - ron::de::from_str::>>(verse_order) - else { + let Ok(verses) = ron::de::from_str::>>(verse_order) else { return Err(sqlx::Error::ColumnDecode { index: "0".into(), - source: miette!( - "Couldn't decode the song into verses" - ) - .into(), + source: miette!("Couldn't decode the song into verses").into(), }); }; @@ -411,17 +348,13 @@ impl FromRow<'_, SqliteRow> for Song { let stroke_color = row .try_get("stroke_color") .ok() - .and_then(|color: String| { - ron::de::from_str::>(&color).ok() - }) + .and_then(|color: String| ron::de::from_str::>(&color).ok()) .flatten(); let shadow_size = row.try_get("shadow_size").ok(); let shadow_color = row .try_get("shadow_color") .ok() - .and_then(|color: String| { - ron::de::from_str::>(&color).ok() - }) + .and_then(|color: String| ron::de::from_str::>(&color).ok()) .flatten(); let shadow_offset = match ( row.try_get("shadow_offset_x").ok(), @@ -432,16 +365,14 @@ impl FromRow<'_, SqliteRow> for Song { }; let style_string: String = row.try_get("style")?; - let font_style = - ron::de::from_str::>(&style_string) - .ok() - .flatten(); + let font_style = ron::de::from_str::>(&style_string) + .ok() + .flatten(); let weight_string: String = row.try_get("weight")?; - let font_weight = - ron::de::from_str::>(&weight_string) - .ok() - .flatten(); + let font_weight = ron::de::from_str::>(&weight_string) + .ok() + .flatten(); let lyric_video = row .try_get::("lyric_video") @@ -480,12 +411,8 @@ impl FromRow<'_, SqliteRow> for Song { ("left", "center") => TextAlignment::MiddleLeft, ("left", "bottom") => TextAlignment::BottomLeft, ("center", "top") => TextAlignment::TopCenter, - ("center", "center") => { - TextAlignment::MiddleCenter - } - ("center", "bottom") => { - TextAlignment::BottomCenter - } + ("center", "center") => TextAlignment::MiddleCenter, + ("center", "bottom") => TextAlignment::BottomCenter, ("right", "top") => TextAlignment::TopRight, ("right", "center") => TextAlignment::MiddleRight, ("right", "bottom") => TextAlignment::BottomRight, @@ -536,10 +463,10 @@ pub fn lisp_to_song(list: Vec) -> Song { DEFAULT_SONG_ID }; - let background = if let Some(key_pos) = - list.iter().position(|v| { - v == &Value::Keyword(Keyword::from("background")) - }) { + let background = if let Some(key_pos) = list + .iter() + .position(|v| v == &Value::Keyword(Keyword::from("background"))) + { let pos = key_pos + 1; list.get(pos).map(slide::lisp_to_background) } else { @@ -586,9 +513,10 @@ pub fn lisp_to_song(list: Vec) -> Song { None }; - let font_size = if let Some(key_pos) = list.iter().position(|v| { - v == &Value::Keyword(Keyword::from("font-size")) - }) { + let font_size = if let Some(key_pos) = list + .iter() + .position(|v| v == &Value::Keyword(Keyword::from("font-size"))) + { let pos = key_pos + 1; list.get(pos).map(i32::from) } else { @@ -606,20 +534,20 @@ pub fn lisp_to_song(list: Vec) -> Song { String::from("song") }; - let text_alignment = if let Some(key_pos) = - list.iter().position(|v| { - v == &Value::Keyword(Keyword::from("text-alignment")) - }) { + let text_alignment = if let Some(key_pos) = list + .iter() + .position(|v| v == &Value::Keyword(Keyword::from("text-alignment"))) + { let pos = key_pos + 1; list.get(pos).map(TextAlignment::from) } else { None }; - let verse_order = if let Some(key_pos) = - list.iter().position(|v| { - v == &Value::Keyword(Keyword::from("verse-order")) - }) { + let verse_order = if let Some(key_pos) = list + .iter() + .position(|v| v == &Value::Keyword(Keyword::from("verse-order"))) + { let pos = key_pos + 1; list.get(pos).map(|v| match v { Value::List(vals) => vals @@ -693,8 +621,7 @@ pub fn lisp_to_song(list: Vec) -> Song { lyrics.push(lyric); } - let lyrics: String = - lyrics.iter().flat_map(|s| s.chars()).collect(); + let lyrics: String = lyrics.iter().flat_map(|s| s.chars()).collect(); let lyrics = lyrics.trim_start().to_string(); Song { @@ -713,10 +640,7 @@ pub fn lisp_to_song(list: Vec) -> Song { } } -pub async fn get_song_from_db( - id: i32, - db: Arc, -) -> Result { +pub async fn get_song_from_db(id: i32, db: Arc) -> Result { let row = query("SELECT verse_order, font_size, background_type, horizontal_text_alignment, vertical_text_alignment, title, font, background, lyrics, ccli, author, audio, stroke_size, stroke_color, shadow_color, shadow_size, shadow_offset_x, shadow_offset_y, style, weight, id from songs where id = $1").bind(id).fetch_one(&*db).await.into_diagnostic()?; Song::from_row(&row).into_diagnostic() } @@ -786,9 +710,7 @@ pub async fn remove_song( mut songs: Vec, id: i32, ) -> Result> { - if let Some(index) = - songs.iter().position(|current_song| current_song.id == id) - { + if let Some(index) = songs.iter().position(|current_song| current_song.id == id) { songs.remove(index); query!("DELETE FROM songs WHERE id = $1", id) .execute(&*db) @@ -853,17 +775,13 @@ pub async fn insert_song( .execute(&*db) .await .into_diagnostic()?; - song.id = i32::try_from(res.last_insert_rowid()).expect( - "Fairly confident that this number won't get that high", - ); + song.id = i32::try_from(res.last_insert_rowid()) + .expect("Fairly confident that this number won't get that high"); songs.push(song); Ok(songs) } -pub async fn add_song( - songs: Vec, - db: Arc, -) -> Result> { +pub async fn add_song(songs: Vec, db: Arc) -> Result> { let song = Song::default(); insert_song(song, songs, db).await } @@ -876,8 +794,7 @@ pub async fn update_song( // self.update_item(item.clone(), index)?; // debug!(?item); - let verse_order = - ron::ser::to_string(&song.verses).into_diagnostic()?; + let verse_order = ron::ser::to_string(&song.verses).into_diagnostic()?; let audio = song .audio @@ -909,36 +826,30 @@ pub async fn update_song( }); let lyrics = ron::ser::to_string(&lyrics).into_diagnostic()?; - let (vertical_alignment, horizontal_alignment) = - song.text_alignment.map_or_else( - || ("center", "center"), - |ta| match ta { - TextAlignment::TopLeft => ("top", "left"), - TextAlignment::TopCenter => ("top", "center"), - TextAlignment::TopRight => ("top", "right"), - TextAlignment::MiddleLeft => ("center", "left"), - TextAlignment::MiddleCenter => ("center", "center"), - TextAlignment::MiddleRight => ("center", "right"), - TextAlignment::BottomLeft => ("bottom", "left"), - TextAlignment::BottomCenter => ("bottom", "center"), - TextAlignment::BottomRight => ("bottom", "right"), - }, - ); + let (vertical_alignment, horizontal_alignment) = song.text_alignment.map_or_else( + || ("center", "center"), + |ta| match ta { + TextAlignment::TopLeft => ("top", "left"), + TextAlignment::TopCenter => ("top", "center"), + TextAlignment::TopRight => ("top", "right"), + TextAlignment::MiddleLeft => ("center", "left"), + TextAlignment::MiddleCenter => ("center", "center"), + TextAlignment::MiddleRight => ("center", "right"), + TextAlignment::BottomLeft => ("bottom", "left"), + TextAlignment::BottomCenter => ("bottom", "center"), + TextAlignment::BottomRight => ("bottom", "right"), + }, + ); let stroke_size = song.stroke_size.unwrap_or_default(); let shadow_size = song.shadow_size.unwrap_or_default(); - let (shadow_offset_x, shadow_offset_y) = - song.shadow_offset.unwrap_or_default(); + let (shadow_offset_x, shadow_offset_y) = song.shadow_offset.unwrap_or_default(); - let stroke_color = - ron::ser::to_string(&song.stroke_color).into_diagnostic()?; - let shadow_color = - ron::ser::to_string(&song.shadow_color).into_diagnostic()?; + let stroke_color = ron::ser::to_string(&song.stroke_color).into_diagnostic()?; + let shadow_color = ron::ser::to_string(&song.shadow_color).into_diagnostic()?; - let style = - ron::ser::to_string(&song.font_style).into_diagnostic()?; - let weight = - ron::ser::to_string(&song.font_weight).into_diagnostic()?; + let style = ron::ser::to_string(&song.font_style).into_diagnostic()?; + let weight = ron::ser::to_string(&song.font_weight).into_diagnostic()?; // debug!( // ?stroke_size, @@ -997,17 +908,14 @@ impl Song { #[must_use] pub fn get_lyric(&self, verse: &VerseName) -> Option { self.verse_map.as_ref().and_then(|verse_map| { - verse_map.get(verse).cloned().map(|lyric| { - lyric.trim().trim_end_matches('\n').to_string() - }) + verse_map + .get(verse) + .cloned() + .map(|lyric| lyric.trim().trim_end_matches('\n').to_string()) }) } - pub fn set_lyrics>( - &mut self, - verse: &VerseName, - lyrics: T, - ) { + pub fn set_lyrics>(&mut self, verse: &VerseName, lyrics: T) { let lyric_copy = lyrics.into().trim().to_string(); if let Some(verse_map) = self.verse_map.as_mut() { // debug!(?verse_map, "should update"); @@ -1044,11 +952,7 @@ impl Song { Err(miette!("No verses in this song yet")) } - pub fn update_verse_name( - &mut self, - verse: VerseName, - old_verse: &VerseName, - ) { + pub fn update_verse_name(&mut self, verse: VerseName, old_verse: &VerseName) { if let Some(verse_map) = self.verse_map.as_mut() && let Some(lyric) = verse_map.remove(old_verse) { @@ -1073,12 +977,7 @@ impl Song { // the song can be sent to the db and it's lyrics will actually change. Or we // could have the update_song_in_db function recreate the lyrics from the new // verse layout. But I do feel like it belongs here more. - pub fn update_verse( - &mut self, - index: usize, - verse: VerseName, - lyric: String, - ) { + pub fn update_verse(&mut self, index: usize, verse: VerseName, lyric: String) { debug!(index, ?verse, lyric); self.set_lyrics(&verse, lyric); if let Some(verses) = self.verses.as_mut() @@ -1148,25 +1047,21 @@ impl Song { if let Some(verse_names) = &self.verses { let verses = verse_names .iter() - .filter(|verse| { - matches!(verse, VerseName::Verse { .. }) - }) + .filter(|verse| matches!(verse, VerseName::Verse { .. })) .sorted(); - let mut choruses = verse_names.iter().filter(|verse| { - matches!(verse, VerseName::Chorus { .. }) - }); - let mut bridges = verse_names.iter().filter(|verse| { - matches!(verse, VerseName::Bridge { .. }) - }); + let mut choruses = verse_names + .iter() + .filter(|verse| matches!(verse, VerseName::Chorus { .. })); + let mut bridges = verse_names + .iter() + .filter(|verse| matches!(verse, VerseName::Bridge { .. })); if verses.len() == 0 { VerseName::Verse { number: 1 } } else if choruses.next().is_none() { VerseName::Chorus { number: 1 } } else if verses.len() == 1 { let verse_number = - if let Some(VerseName::Verse { number }) = - verses.last() - { + if let Some(VerseName::Verse { number }) = verses.last() { *number } else { 0 @@ -1190,11 +1085,7 @@ impl Song { } } - pub fn add_verse( - &mut self, - verse: VerseName, - lyric: impl Into, - ) { + pub fn add_verse(&mut self, verse: VerseName, lyric: impl Into) { let lyric: String = lyric.into(); self.set_lyrics(&verse, lyric); if let Some(verses) = self.verses.as_mut() { @@ -1348,11 +1239,10 @@ You saved my soul" VerseName::Outro { number: 1 }, VerseName::Blank, ]); - song.verse_order = - "O1 V1 C1 C2 O2 V2 C3 C2 O2 B1 C2 C2 E1 O2" - .split(' ') - .map(|s| Some(s.to_string())) - .collect(); + song.verse_order = "O1 V1 C1 C2 O2 V2 C3 C2 O2 B1 C2 C2 E1 O2" + .split(' ') + .map(|s| Some(s.to_string())) + .collect(); let lyrics = song.get_lyrics(); match lyrics { Ok(lyrics) => { @@ -1394,8 +1284,7 @@ You saved my soul" pub async fn add_db() -> Result { let db_url = String::from("sqlite::memory:"); - let pool = - SqlitePool::connect(&db_url).await.into_diagnostic()?; + let pool = SqlitePool::connect(&db_url).await.into_diagnostic()?; migrate!() .run(&pool) .await @@ -1426,8 +1315,7 @@ You saved my soul" let song_model = Model::new_song_model(Arc::clone(&db)).await; let length = song_model.items.len(); assert!(song_model.items.len() == 20, "Length is {length}"); - let ids: Vec = - song_model.items.iter().map(|s| s.id).collect(); + let ids: Vec = song_model.items.iter().map(|s| s.id).collect(); if let Some(song) = song_model.find(|s| s.id == 7) { let test_song = test_song(); if let Ok(song_lyrics) = song.get_lyrics() @@ -1439,9 +1327,7 @@ You saved my soul" } } else { dbg!(song_model); - panic!( - "Failed to find song in model: Id's of all songs are {ids:?}" - ); + panic!("Failed to find song in model: Id's of all songs are {ids:?}"); } } @@ -1490,9 +1376,7 @@ You saved my soul" assert_ne!(test_song, Some(&cloned_song)); let songs = song_model.items.clone(); - match update_song(cloned_song.clone(), songs, Arc::clone(&db)) - .await - { + match update_song(cloned_song.clone(), songs, Arc::clone(&db)).await { Ok(_) => { let db_song = get_song_from_db(7, db) .await @@ -1501,10 +1385,7 @@ You saved my soul" // lyrics will be in the wrong order since serialization // can sometimes change the order of the verse_map assert_eq!(db_song.id, cloned_song.id); - assert_eq!( - db_song.verse_order, - cloned_song.verse_order - ); + assert_eq!(db_song.verse_order, cloned_song.verse_order); assert_eq!(db_song.verse_map, cloned_song.verse_map); } Err(e) => panic!("{e}"), @@ -1515,8 +1396,7 @@ You saved my soul" pub fn test_song() -> Song { let lyrics = "Some({Verse(number:4):\"Our Savior displayed\\nOn a criminal\\'s cross\\n\\nDarkness rejoiced as though\\nHeaven had lost\\n\\nBut then Jesus arose\\nWith our freedom in hand\\n\\nThat\\'s when death was arrested\\nAnd my life began\\n\\nThat\\'s when death was arrested\\nAnd my life began\",Intro(number:1):\"Death Was Arrested\\nNorth Point Worship\",Verse(number:3):\"Released from my chains,\\nI\\'m a prisoner no more\\n\\nMy shame was a ransom\\nHe faithfully bore\\n\\nHe cancelled my debt and\\nHe called me His friend\\n\\nWhen death was arrested\\nAnd my life began\",Bridge(number:1):\"Oh, we\\'re free, free,\\nForever we\\'re free\\n\\nCome join the song\\nOf all the redeemed\\n\\nYes, we\\'re free, free,\\nForever amen\\n\\nWhen death was arrested\\nAnd my life began\\n\\nOh, we\\'re free, free,\\nForever we\\'re free\\n\\nCome join the song\\nOf all the redeemed\\n\\nYes, we\\'re free, free,\\nForever amen\\n\\nWhen death was arrested\\nAnd my life began\",Other(number:99):\"When death was arrested\\nAnd my life began\\n\\nThat\\'s when death was arrested\\nAnd my life began\",Verse(number:2):\"Ash was redeemed\\nOnly beauty remains\\n\\nMy orphan heart\\nWas given a name\\n\\nMy mourning grew quiet,\\nMy feet rose to dance\\n\\nWhen death was arrested\\nAnd my life began\",Verse(number:1):\"Alone in my sorrow\\nAnd dead in my sin\\n\\nLost without hope\\nWith no place to begin\\n\\nYour love made a way\\nTo let mercy come in\\n\\nWhen death was arrested\\nAnd my life began\",Chorus(number:1):\"Oh, Your grace so free,\\nWashes over me\\n\\nYou have made me new,\\nNow life begins with You\\n\\nIt\\'s Your endless love,\\nPouring down on us\\n\\nYou have made us new,\\nNow life begins with You\"})".to_string(); let verse_map: Option> = - ron::from_str(&lyrics) - .expect("Error creating lyrics object from string"); + ron::from_str(&lyrics).expect("Error creating lyrics object from string"); Song { id: 7, title: "Death Was Arrested".to_string(), @@ -1604,19 +1484,14 @@ You saved my soul" .collect(); let fontdb = Arc::new(fontdb::Database::new()); songs.into_par_iter().for_each(|song| { - let slides = song - .to_slides() - .expect("Error in making slides from song"); + let slides = song.to_slides().expect("Error in making slides from song"); slides.into_par_iter().for_each(|slide| { - text_svg_generator_with_cache(slide, &fontdb, None) - .map_or_else( - |e| panic!("{e}"), - |slide| { - assert!(slide.text_svg.is_some_and( - |svg| svg.handle.is_some() - )); - }, - ); + text_svg_generator_with_cache(slide, &fontdb, None).map_or_else( + |e| panic!("{e}"), + |slide| { + assert!(slide.text_svg.is_some_and(|svg| svg.handle.is_some())); + }, + ); }); }); } diff --git a/src/core/thumbnail.rs b/src/core/thumbnail.rs index cd87a01..11db871 100644 --- a/src/core/thumbnail.rs +++ b/src/core/thumbnail.rs @@ -6,10 +6,7 @@ use std::process::Command; use std::{fs, str}; use tracing::debug; -pub fn bg_from_video( - video: &Path, - screenshot: &Path, -) -> Result<(), Box> { +pub fn bg_from_video(video: &Path, screenshot: &Path) -> Result<(), Box> { if screenshot.exists() { debug!("Screenshot already exists"); } else { @@ -39,10 +36,8 @@ pub fn bg_from_video( } } let hours: i32 = hours.parse().unwrap_or_default(); - let mut minutes: i32 = - minutes.parse().unwrap_or_default(); - let mut seconds: i32 = - seconds.parse().unwrap_or_default(); + let mut minutes: i32 = minutes.parse().unwrap_or_default(); + let mut seconds: i32 = seconds.parse().unwrap_or_default(); minutes += hours * 60; seconds += minutes * 60; at_second = seconds / 5; @@ -70,18 +65,15 @@ pub fn bg_from_video( pub fn bg_path_from_video(video: &Path) -> PathBuf { let video = PathBuf::from(video); debug!(?video); - let mut data_dir = - dirs::cache_dir().expect("Can't find cache dir"); + let mut data_dir = dirs::cache_dir().expect("Can't find cache dir"); data_dir.push("lumina"); data_dir.push("thumbnails"); let _ = fs::create_dir_all(&data_dir); if !data_dir.exists() { - fs::create_dir(&data_dir) - .expect("Could not create thumbnails dir"); + fs::create_dir(&data_dir).expect("Could not create thumbnails dir"); } let mut screenshot = data_dir.clone(); - screenshot - .push(video.file_name().expect("Should have file name")); + screenshot.push(video.file_name().expect("Should have file name")); screenshot.set_extension("png"); screenshot } @@ -96,10 +88,9 @@ mod test { let screenshot = bg_path_from_video(video); match bg_from_video(video, &screenshot) { Ok(_o) => assert!(screenshot.exists()), - Err(e) => debug_assert!( - false, - "There was an error in the runtime future. {e}", - ), + Err(e) => { + debug_assert!(false, "There was an error in the runtime future. {e}",) + } } } } diff --git a/src/core/videos.rs b/src/core/videos.rs index 97ddb78..a4e4e7e 100644 --- a/src/core/videos.rs +++ b/src/core/videos.rs @@ -15,9 +15,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use tracing::error; -#[derive( - Clone, Debug, Default, PartialEq, Serialize, Deserialize, -)] +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct Video { pub id: i32, pub title: String, @@ -95,30 +93,21 @@ impl From<&Value> for Video { Value::List(list) => { let path = list .iter() - .position(|v| { - v == &Value::Keyword(Keyword::from("source")) - }) + .position(|v| v == &Value::Keyword(Keyword::from("source"))) .and_then(|path_pos| { let pos = path_pos + 1; - list.get(pos) - .map(|p| PathBuf::from(String::from(p))) + list.get(pos).map(|p| PathBuf::from(String::from(p))) }); let title = path.clone().map(|p| { - let path = - p.to_str().unwrap_or_default().to_string(); - let title = - path.rsplit_once('/').unwrap_or_default().1; + let path = p.to_str().unwrap_or_default().to_string(); + let title = path.rsplit_once('/').unwrap_or_default().1; title.to_string() }); let start_time = list .iter() - .position(|v| { - v == &Value::Keyword(Keyword::from( - "start-time", - )) - }) + .position(|v| v == &Value::Keyword(Keyword::from("start-time"))) .and_then(|start_pos| { let pos = start_pos + 1; list.get(pos).map(|p| i32::from(p) as f32) @@ -126,11 +115,7 @@ impl From<&Value> for Video { let end_time = list .iter() - .position(|v| { - v == &Value::Keyword(Keyword::from( - "end-time", - )) - }) + .position(|v| v == &Value::Keyword(Keyword::from("end-time"))) .and_then(|end_pos| { let pos = end_pos + 1; list.get(pos).map(|p| i32::from(p) as f32) @@ -138,14 +123,10 @@ impl From<&Value> for Video { let looping = list .iter() - .position(|v| { - v == &Value::Keyword(Keyword::from("loop")) - }) + .position(|v| v == &Value::Keyword(Keyword::from("loop"))) .is_some_and(|loop_pos| { let pos = loop_pos + 1; - list.get(pos).is_some_and(|l| { - String::from(l) == *"true" - }) + list.get(pos).is_some_and(|l| String::from(l) == *"true") }); Self { @@ -173,10 +154,7 @@ impl ServiceTrait for Video { fn to_slides(&self) -> Result> { let slide = SlideBuilder::new() - .background( - Background::try_from(self.path.clone()) - .into_diagnostic()?, - ) + .background(Background::try_from(self.path.clone()).into_diagnostic()?) .text("") .audio("") .font("") @@ -214,9 +192,7 @@ impl Model