fixing lots of bugs

This commit is contained in:
Chris Cochrun 2025-03-10 23:18:30 -05:00
parent da735aa00b
commit 0ba3e7588b
24 changed files with 781 additions and 486 deletions

4
Cargo.lock generated
View file

@ -1464,7 +1464,7 @@ dependencies = [
"cxx-qt-lib", "cxx-qt-lib",
"dirs", "dirs",
"fastrand 2.1.1", "fastrand 2.1.1",
"lumina-core", "lumina_core",
"obws", "obws",
"qt-build-utils", "qt-build-utils",
"quote", "quote",
@ -1549,7 +1549,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]] [[package]]
name = "lumina-core" name = "lumina_core"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"color-eyre", "color-eyre",

View file

@ -21,7 +21,7 @@ path = "src/rust/lib.rs"
# path = "src/rust/main.rs" # path = "src/rust/main.rs"
[dependencies] [dependencies]
lumina-core = { path = "src/rust/core" } lumina_core = { path = "src/rust/core" }
configparser = "3.0.2" configparser = "3.0.2"
serde = "1.0.152" serde = "1.0.152"
serde_derive = "1.0.152" serde_derive = "1.0.152"

View file

@ -15,7 +15,7 @@ test:
RUST_LOG=debug cargo test --benches --tests --all-features -- --nocapture RUST_LOG=debug cargo test --benches --tests --all-features -- --nocapture
testcore: testcore:
RUST_LOG=debug cargo test -p core --benches --tests --all-features -- --nocapture RUST_LOG=debug cargo test -p lumina_core --benches --tests --all-features -- --nocapture
alias b := build alias b := build
alias r := run alias r := run

View file

@ -1,5 +1,5 @@
[package] [package]
name = "lumina-core" name = "lumina_core"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
authors = [ authors = [

View file

@ -1,86 +1,131 @@
use tar::{Archive, Builder}; use crate::{
use tracing::error; images::{get_image_from_db, Image},
use zstd::Encoder; kinds::ServiceItemKind,
use std::{fs::{self, File}, iter, path::{Path, PathBuf}}; model::get_db,
presentations::{
get_presentation_from_db, PresKind, Presentation,
},
service_items::ServiceItem,
slides::Background,
songs::{get_song_from_db, Song},
videos::{get_video_from_db, Video},
};
use color_eyre::eyre::{eyre, Context, Result}; use color_eyre::eyre::{eyre, Context, Result};
use serde_json::Value; use serde_json::Value;
use sqlx::{query, query_as, FromRow, SqliteConnection}; use sqlx::{query, query_as, FromRow, SqliteConnection};
use crate::{images::{get_image_from_db, Image}, kinds::ServiceItemKind, model::get_db, presentations::{get_presentation_from_db, PresKind, Presentation}, service_items::ServiceItem, slides::Background, songs::{get_song_from_db, Song}, videos::{get_video_from_db, Video}}; use std::{
fs::{self, File},
iter,
path::{Path, PathBuf},
};
use tar::{Archive, Builder};
use tracing::error;
use zstd::Encoder;
pub async fn save(list: Vec<ServiceItem>, path: impl AsRef<Path>) -> Result<()> { pub async fn save(
list: Vec<ServiceItem>,
path: impl AsRef<Path>,
) -> Result<()> {
let path = path.as_ref(); let path = path.as_ref();
let save_file = File::create(path)?; let save_file = File::create(path)?;
let mut db = get_db().await; let mut db = get_db().await;
let json = process_service_items(&list, &mut db).await?; let json = process_service_items(&list, &mut db).await?;
let archive = store_service_items(&list, &mut db, &save_file, &json).await?; let archive =
store_service_items(&list, &mut db, &save_file, &json)
.await?;
Ok(()) Ok(())
} }
async fn store_service_items(items: &Vec<ServiceItem>, db: &mut SqliteConnection, save_file: &File, json: &Value) -> Result<()> { async fn store_service_items(
items: &Vec<ServiceItem>,
db: &mut SqliteConnection,
save_file: &File,
json: &Value,
) -> Result<()> {
let encoder = Encoder::new(save_file, 3).unwrap(); let encoder = Encoder::new(save_file, 3).unwrap();
let mut tar = Builder::new(encoder); let mut tar = Builder::new(encoder);
let mut temp_dir = dirs::data_dir().unwrap(); let mut temp_dir = dirs::data_dir().unwrap();
temp_dir.push("lumina"); temp_dir.push("lumina");
let mut s: String = let mut s: String =
iter::repeat_with(fastrand::alphanumeric) iter::repeat_with(fastrand::alphanumeric).take(5).collect();
.take(5)
.collect();
s.insert_str(0, "temp_"); s.insert_str(0, "temp_");
temp_dir.push(s); temp_dir.push(s);
fs::create_dir_all(&temp_dir)?; fs::create_dir_all(&temp_dir)?;
let service_file = temp_dir.join("serviceitems.json"); let service_file = temp_dir.join("serviceitems.json");
fs::File::create(&service_file)?; fs::File::create(&service_file)?;
match fs::File::options().read(true).write(true).open(service_file) { match fs::File::options()
.read(true)
.write(true)
.open(service_file)
{
Ok(f) => { Ok(f) => {
serde_json::to_writer_pretty(f, json)?; serde_json::to_writer_pretty(f, json)?;
}, }
Err(e) => error!("There were problems making a file i guess: {e}"), Err(e) => {
error!("There were problems making a file i guess: {e}")
}
}; };
for item in items { for item in items {
let background; let background;
let audio: Option<PathBuf>; let audio: Option<PathBuf>;
match item.kind { match item.kind {
ServiceItemKind::Song => { ServiceItemKind::Song => {
let song = get_song_from_db(item.database_id, db).await?; let song =
get_song_from_db(item.database_id, db).await?;
background = song.background; background = song.background;
audio = song.audio; audio = song.audio;
}, }
ServiceItemKind::Image => { ServiceItemKind::Image => {
let image = get_image_from_db(item.database_id, db).await?; let image =
get_image_from_db(item.database_id, db).await?;
background = Some(Background::try_from(image.path)?); background = Some(Background::try_from(image.path)?);
audio = None; audio = None;
}, }
ServiceItemKind::Video => { ServiceItemKind::Video => {
let video = get_video_from_db(item.database_id, db).await?; let video =
get_video_from_db(item.database_id, db).await?;
background = Some(Background::try_from(video.path)?); background = Some(Background::try_from(video.path)?);
audio = None; audio = None;
}, }
ServiceItemKind::Presentation(_) => { ServiceItemKind::Presentation(_) => {
let presentation = get_presentation_from_db(item.database_id, db).await?; let presentation =
background = Some(Background::try_from(presentation.path)?); get_presentation_from_db(item.database_id, db)
.await?;
background =
Some(Background::try_from(presentation.path)?);
audio = None; audio = None;
}, }
ServiceItemKind::Content => { ServiceItemKind::Content => {
todo!() todo!()
}, }
}; };
if let Some(file) = audio { if let Some(file) = audio {
let audio_file = temp_dir.join(file.file_name().expect("Audio file couldn't be added to temp_dir")); let audio_file =
temp_dir.join(file.file_name().expect(
"Audio file couldn't be added to temp_dir",
));
if let Ok(file) = file.strip_prefix("file://") { if let Ok(file) = file.strip_prefix("file://") {
fs::File::create(&audio_file).wrap_err("Couldn't create audio file")?; fs::File::create(&audio_file)
.wrap_err("Couldn't create audio file")?;
fs::copy(file, audio_file).wrap_err("Audio file could not be copied, the source file doesn't exist not be found"); fs::copy(file, audio_file).wrap_err("Audio file could not be copied, the source file doesn't exist not be found");
} else { } else {
fs::File::create(&audio_file).wrap_err("Couldn't create audio file")?; fs::File::create(&audio_file)
.wrap_err("Couldn't create audio file")?;
fs::copy(file, audio_file).wrap_err("Audio file could not be copied, the source file doesn't exist not be found"); fs::copy(file, audio_file).wrap_err("Audio file could not be copied, the source file doesn't exist not be found");
} }
}; };
if let Some(file) = background { if let Some(file) = background {
let background_file = temp_dir.join(file.path.file_name().expect("Background file couldn't be added to temp_dir")); let background_file =
temp_dir.join(file.path.file_name().expect(
"Background file couldn't be added to temp_dir",
));
if let Ok(file) = file.path.strip_prefix("file://") { if let Ok(file) = file.path.strip_prefix("file://") {
fs::File::create(&background_file).wrap_err("Couldn't create background file")?; fs::File::create(&background_file)
.wrap_err("Couldn't create background file")?;
fs::copy(file, background_file).wrap_err("Background file could not be copied, the source file doesn't exist not be found"); fs::copy(file, background_file).wrap_err("Background file could not be copied, the source file doesn't exist not be found");
} else { } else {
fs::File::create(&background_file).wrap_err("Couldn't create background file")?; fs::File::create(&background_file)
.wrap_err("Couldn't create background file")?;
fs::copy(file.path, background_file).wrap_err("Background file could not be copied, the source file doesn't exist not be found"); fs::copy(file.path, background_file).wrap_err("Background file could not be copied, the source file doesn't exist not be found");
} }
} }
@ -92,66 +137,96 @@ async fn clear_temp_dir(temp_dir: &Path) -> Result<()> {
todo!() todo!()
} }
async fn process_service_items(items: &Vec<ServiceItem>, db: &mut SqliteConnection) -> Result<Value> { async fn process_service_items(
items: &Vec<ServiceItem>,
db: &mut SqliteConnection,
) -> Result<Value> {
let mut values: Vec<Value> = vec![]; let mut values: Vec<Value> = vec![];
for item in items { for item in items {
match item.kind { match item.kind {
ServiceItemKind::Song => { ServiceItemKind::Song => {
let value = process_song(item.database_id, db).await?; let value =
process_song(item.database_id, db).await?;
values.push(value); values.push(value);
}, }
ServiceItemKind::Image => { ServiceItemKind::Image => {
let value = process_image(item.database_id, db).await?; let value =
process_image(item.database_id, db).await?;
values.push(value); values.push(value);
}, }
ServiceItemKind::Video => { ServiceItemKind::Video => {
let value = process_video(item.database_id, db).await?; let value =
process_video(item.database_id, db).await?;
values.push(value); values.push(value);
}, }
ServiceItemKind::Presentation(_) => { ServiceItemKind::Presentation(_) => {
let value = process_presentation(item.database_id, db).await?; let value =
process_presentation(item.database_id, db)
.await?;
values.push(value); values.push(value);
}, }
ServiceItemKind::Content => { ServiceItemKind::Content => {
todo!() todo!()
}, }
} }
} }
let json = Value::from(values); let json = Value::from(values);
Ok(json) Ok(json)
} }
async fn process_song(database_id: i32, db: &mut SqliteConnection) -> Result<Value> { async fn process_song(
database_id: i32,
db: &mut SqliteConnection,
) -> Result<Value> {
let song = get_song_from_db(database_id, db).await?; let song = get_song_from_db(database_id, db).await?;
let song_json = serde_json::to_value(&song)?; let song_json = serde_json::to_value(&song)?;
let kind_json = serde_json::to_value(ServiceItemKind::Song)?; let kind_json = serde_json::to_value(ServiceItemKind::Song)?;
let json = serde_json::json!({"item": song_json, "kind": kind_json}); let json =
serde_json::json!({"item": song_json, "kind": kind_json});
Ok(json) Ok(json)
} }
async fn process_image(database_id: i32, db: &mut SqliteConnection) -> Result<Value> { async fn process_image(
database_id: i32,
db: &mut SqliteConnection,
) -> Result<Value> {
let image = get_image_from_db(database_id, db).await?; let image = get_image_from_db(database_id, db).await?;
let image_json = serde_json::to_value(&image)?; let image_json = serde_json::to_value(&image)?;
let kind_json = serde_json::to_value(ServiceItemKind::Image)?; let kind_json = serde_json::to_value(ServiceItemKind::Image)?;
let json = serde_json::json!({"item": image_json, "kind": kind_json}); let json =
serde_json::json!({"item": image_json, "kind": kind_json});
Ok(json) Ok(json)
} }
async fn process_video(database_id: i32, db: &mut SqliteConnection) -> Result<Value> { async fn process_video(
database_id: i32,
db: &mut SqliteConnection,
) -> Result<Value> {
let video = get_video_from_db(database_id, db).await?; let video = get_video_from_db(database_id, db).await?;
let video_json = serde_json::to_value(&video)?; let video_json = serde_json::to_value(&video)?;
let kind_json = serde_json::to_value(ServiceItemKind::Video)?; let kind_json = serde_json::to_value(ServiceItemKind::Video)?;
let json = serde_json::json!({"item": video_json, "kind": kind_json}); let json =
serde_json::json!({"item": video_json, "kind": kind_json});
Ok(json) Ok(json)
} }
async fn process_presentation(database_id: i32, db: &mut SqliteConnection) -> Result<Value> { async fn process_presentation(
let presentation = get_presentation_from_db(database_id, db).await?; database_id: i32,
db: &mut SqliteConnection,
) -> Result<Value> {
let presentation =
get_presentation_from_db(database_id, db).await?;
let presentation_json = serde_json::to_value(&presentation)?; let presentation_json = serde_json::to_value(&presentation)?;
let kind_json = match presentation.kind { let kind_json = match presentation.kind {
PresKind::Html => serde_json::to_value(ServiceItemKind::Presentation(PresKind::Html))?, PresKind::Html => serde_json::to_value(
PresKind::Pdf => serde_json::to_value(ServiceItemKind::Presentation(PresKind::Pdf))?, ServiceItemKind::Presentation(PresKind::Html),
PresKind::Generic => serde_json::to_value(ServiceItemKind::Presentation(PresKind::Generic))?, )?,
PresKind::Pdf => serde_json::to_value(
ServiceItemKind::Presentation(PresKind::Pdf),
)?,
PresKind::Generic => serde_json::to_value(
ServiceItemKind::Presentation(PresKind::Generic),
)?,
}; };
let json = serde_json::json!({"item": presentation_json, "kind": kind_json}); let json = serde_json::json!({"item": presentation_json, "kind": kind_json});
Ok(json) Ok(json)
@ -161,11 +236,11 @@ async fn process_presentation(database_id: i32, db: &mut SqliteConnection) -> Re
mod test { mod test {
use std::path::PathBuf; use std::path::PathBuf;
use fs::canonicalize;
use sqlx::Connection;
use pretty_assertions::assert_eq;
use tracing::debug;
use super::*; use super::*;
use fs::canonicalize;
use pretty_assertions::assert_eq;
use sqlx::Connection;
use tracing::debug;
async fn get_db() -> SqliteConnection { async fn get_db() -> SqliteConnection {
let mut data = dirs::data_local_dir().unwrap(); let mut data = dirs::data_local_dir().unwrap();
@ -173,9 +248,7 @@ mod test {
data.push("library-db.sqlite3"); data.push("library-db.sqlite3");
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
SqliteConnection::connect(&db_url) SqliteConnection::connect(&db_url).await.expect("problems")
.await
.expect("problems")
} }
#[tokio::test(flavor = "current_thread")] #[tokio::test(flavor = "current_thread")]
@ -245,7 +318,8 @@ mod test {
async fn test_process_presentation() { async fn test_process_presentation() {
let mut db = get_db().await; let mut db = get_db().await;
let result = process_presentation(54, &mut db).await; let result = process_presentation(54, &mut db).await;
let json_presentation_file = PathBuf::from("./test/test_presentation.json"); let json_presentation_file =
PathBuf::from("./test/test_presentation.json");
if let Ok(path) = canonicalize(json_presentation_file) { if let Ok(path) = canonicalize(json_presentation_file) {
debug!(file = ?&path); debug!(file = ?&path);
if let Ok(s) = fs::read_to_string(path) { if let Ok(s) = fs::read_to_string(path) {
@ -258,7 +332,9 @@ mod test {
panic!("String wasn't read from file"); panic!("String wasn't read from file");
} }
} else { } else {
panic!("Cannot find absolute path to test_presentation.json"); panic!(
"Cannot find absolute path to test_presentation.json"
);
} }
} }
@ -287,7 +363,8 @@ mod test {
async fn test_service_items() { async fn test_service_items() {
let mut db = get_db().await; let mut db = get_db().await;
let items = get_items(); let items = get_items();
let json_item_file = PathBuf::from("./test/test_service_items.json"); let json_item_file =
PathBuf::from("./test/test_service_items.json");
let result = process_service_items(&items, &mut db).await; let result = process_service_items(&items, &mut db).await;
if let Ok(path) = canonicalize(json_item_file) { if let Ok(path) = canonicalize(json_item_file) {
if let Ok(s) = fs::read_to_string(path) { if let Ok(s) = fs::read_to_string(path) {
@ -311,16 +388,23 @@ mod test {
#[tokio::test] #[tokio::test]
async fn test_store() { async fn test_store() {
let path = PathBuf::from("/home/chris/dev/lumina/src/rust/core/test.pres"); let path = PathBuf::from(
let save_file = match File::create(path) { "/home/chris/dev/lumina/src/rust/core/test.pres",
);
let save_file = match File::create(path) {
Ok(f) => f, Ok(f) => f,
Err(e) => panic!("Couldn't create save_file: {e}"), Err(e) => panic!("Couldn't create save_file: {e}"),
}; };
let mut db = get_db().await; let mut db = get_db().await;
let list = get_items(); let list = get_items();
if let Ok(json) = process_service_items(&list, &mut db).await { if let Ok(json) = process_service_items(&list, &mut db).await
{
println!("{:?}", json); println!("{:?}", json);
match store_service_items(&list, &mut db, &save_file, &json).await { match store_service_items(
&list, &mut db, &save_file, &json,
)
.await
{
Ok(_) => assert!(true), Ok(_) => assert!(true),
Err(e) => panic!("There was an error: {e}"), Err(e) => panic!("There was an error: {e}"),
} }

View file

@ -5,7 +5,9 @@ use sqlx::{query_as, SqliteConnection};
use std::path::PathBuf; use std::path::PathBuf;
use tracing::error; use tracing::error;
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] #[derive(
Clone, Debug, Default, PartialEq, Serialize, Deserialize,
)]
pub struct Image { pub struct Image {
pub id: i32, pub id: i32,
pub title: String, pub title: String,
@ -16,7 +18,7 @@ impl Model<Image> {
pub fn load_from_db(&mut self) { pub fn load_from_db(&mut self) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query_as!(Image, r#"SELECT title as "title!", filePath as "path!", id as "id: i32" from images"#).fetch_all(&mut self.db).await; let result = query_as!(Image, r#"SELECT title as "title!", file_path as "path!", id as "id: i32" from images"#).fetch_all(&mut self.db).await;
match result { match result {
Ok(v) => { Ok(v) => {
for image in v.into_iter() { for image in v.into_iter() {
@ -29,9 +31,11 @@ impl Model<Image> {
} }
} }
pub async fn get_image_from_db(
pub async fn get_image_from_db(database_id: i32, db: &mut SqliteConnection) -> Result<Image> { database_id: i32,
Ok(query_as!(Image, r#"SELECT title as "title!", filePath as "path!", id as "id: i32" from images where id = ?"#, database_id).fetch_one(db).await?) db: &mut SqliteConnection,
) -> Result<Image> {
Ok(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?)
} }
#[cfg(test)] #[cfg(test)]
@ -67,7 +71,10 @@ mod test {
let new_image = test_image("A newer image".into()); let new_image = test_image("A newer image".into());
match result { match result {
Ok(_) => { Ok(_) => {
assert_eq!(&image, image_model.find(|i| i.id == 0).unwrap()); assert_eq!(
&image,
image_model.find(|i| i.id == 0).unwrap()
);
assert_ne!( assert_ne!(
&new_image, &new_image,
image_model.find(|i| i.id == 0).unwrap() image_model.find(|i| i.id == 0).unwrap()

View file

@ -4,7 +4,9 @@ use serde::{Deserialize, Serialize};
use crate::presentations::PresKind; use crate::presentations::PresKind;
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub enum ServiceItemKind { pub enum ServiceItemKind {
#[default] #[default]
Song, Song,

View file

@ -1,3 +1,4 @@
pub mod file;
pub mod images; pub mod images;
pub mod kinds; pub mod kinds;
pub mod model; pub mod model;
@ -6,4 +7,3 @@ pub mod service_items;
pub mod slides; pub mod slides;
pub mod songs; pub mod songs;
pub mod videos; pub mod videos;
pub mod file;

View file

@ -36,8 +36,7 @@ impl<T> Model<T> {
Ok(()) Ok(())
} }
pub fn get_item(&self, index: i32) -> Option<&T> pub fn get_item(&self, index: i32) -> Option<&T> {
{
self.items.get(index as usize) self.items.get(index as usize)
} }
@ -60,10 +59,8 @@ impl<T> Default for Model<T> {
items: vec![], items: vec![],
db: { db: {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async { get_db().await })
get_db().await },
})
}
} }
} }
} }
@ -74,9 +71,7 @@ pub async fn get_db() -> SqliteConnection {
data.push("library-db.sqlite3"); data.push("library-db.sqlite3");
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
SqliteConnection::connect(&db_url) SqliteConnection::connect(&db_url).await.expect("problems")
.await
.expect("problems")
} }
pub trait Modeling { pub trait Modeling {

View file

@ -1,12 +1,16 @@
use std::path::PathBuf;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{prelude::FromRow, query, sqlite::SqliteRow, Row, SqliteConnection}; use sqlx::{
prelude::FromRow, query, sqlite::SqliteRow, Row, SqliteConnection,
};
use std::path::PathBuf;
use tracing::error; use tracing::error;
use crate::model::Model; use crate::model::Model;
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub enum PresKind { pub enum PresKind {
Html, Html,
#[default] #[default]
@ -14,7 +18,9 @@ pub enum PresKind {
Generic, Generic,
} }
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub struct Presentation { pub struct Presentation {
pub id: i32, pub id: i32,
pub title: String, pub title: String,
@ -57,7 +63,7 @@ impl Model<Presentation> {
pub fn load_from_db(&mut self) { pub fn load_from_db(&mut self) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!(r#"SELECT id as "id: i32", title, filePath as "path", html from presentations"#).fetch_all(&mut self.db).await; let result = query!(r#"SELECT id as "id: i32", title, file_path as "path", html from presentations"#).fetch_all(&mut self.db).await;
match result { match result {
Ok(v) => { Ok(v) => {
for presentation in v.into_iter() { for presentation in v.into_iter() {
@ -79,8 +85,11 @@ impl Model<Presentation> {
} }
} }
pub async fn get_presentation_from_db(database_id: i32, db: &mut SqliteConnection) -> Result<Presentation> { pub async fn get_presentation_from_db(
let row = query(r#"SELECT id as "id: i32", title, filePath as "path", html from presentations where id = $1"#).bind(database_id).fetch_one(db).await?; database_id: i32,
db: &mut SqliteConnection,
) -> Result<Presentation> {
let row = query(r#"SELECT id as "id: i32", title, file_path as "path", html from presentations where id = $1"#).bind(database_id).fetch_one(db).await?;
Ok(Presentation::from_row(&row)?) Ok(Presentation::from_row(&row)?)
} }
@ -111,7 +120,9 @@ mod test {
let mut presentation_model: Model<Presentation> = let mut presentation_model: Model<Presentation> =
Model::default(); Model::default();
presentation_model.load_from_db(); presentation_model.load_from_db();
if let Some(presentation) = presentation_model.find(|p| p.id == 54) { if let Some(presentation) =
presentation_model.find(|p| p.id == 54)
{
let test_presentation = test_presentation(); let test_presentation = test_presentation();
assert_eq!(&test_presentation, presentation); assert_eq!(&test_presentation, presentation);
} else { } else {

View file

@ -52,7 +52,9 @@ impl From<&Image> for ServiceItem {
impl From<&Presentation> for ServiceItem { impl From<&Presentation> for ServiceItem {
fn from(presentation: &Presentation) -> Self { fn from(presentation: &Presentation) -> Self {
Self { Self {
kind: ServiceItemKind::Presentation(presentation.kind.clone()), kind: ServiceItemKind::Presentation(
presentation.kind.clone(),
),
database_id: presentation.id, database_id: presentation.id,
..Default::default() ..Default::default()
} }
@ -60,7 +62,10 @@ impl From<&Presentation> for ServiceItem {
} }
impl ServiceItemModel { impl ServiceItemModel {
fn add_item(&mut self, item: impl Into<ServiceItem>) -> Result<()> { fn add_item(
&mut self,
item: impl Into<ServiceItem>,
) -> Result<()> {
let service_item: ServiceItem = item.into(); let service_item: ServiceItem = item.into();
self.items.push(service_item); self.items.push(service_item);
Ok(()) Ok(())
@ -94,7 +99,6 @@ mod test {
} }
} }
#[test] #[test]
pub fn test_service_item() { pub fn test_service_item() {
let song = test_song(); let song = test_song();
@ -104,10 +108,16 @@ mod test {
let mut service_model = ServiceItemModel::default(); let mut service_model = ServiceItemModel::default();
match service_model.add_item(&song) { match service_model.add_item(&song) {
Ok(_) => { Ok(_) => {
assert_eq!(ServiceItemKind::Song, service_model.items[0].kind); assert_eq!(
assert_eq!(ServiceItemKind::Presentation(PresKind::Html), pres_item.kind); ServiceItemKind::Song,
service_model.items[0].kind
);
assert_eq!(
ServiceItemKind::Presentation(PresKind::Html),
pres_item.kind
);
assert_eq!(service_item, service_model.items[0]); assert_eq!(service_item, service_model.items[0]);
}, }
Err(e) => panic!("Problem adding item: {:?}", e), Err(e) => panic!("Problem adding item: {:?}", e),
} }
} }

View file

@ -1,4 +1,8 @@
use std::{error::Error, fmt::Display, path::{Path, PathBuf}}; use std::{
error::Error,
fmt::Display,
path::{Path, PathBuf},
};
use color_eyre::eyre::{eyre, Result}; use color_eyre::eyre::{eyre, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -10,7 +14,9 @@ use crate::{
presentations::Presentation, songs::Song, videos::Video, presentations::Presentation, songs::Song, videos::Video,
}; };
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(
Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub enum TextAlignment { pub enum TextAlignment {
TopLeft, TopLeft,
TopCenter, TopCenter,
@ -24,7 +30,9 @@ pub enum TextAlignment {
BottomRight, BottomRight,
} }
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(
Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub struct Background { pub struct Background {
pub path: PathBuf, pub path: PathBuf,
pub kind: BackgroundKind, pub kind: BackgroundKind,
@ -36,7 +44,7 @@ impl TryFrom<String> for Background {
let value = value.trim_start_matches("file://"); let value = value.trim_start_matches("file://");
let path = PathBuf::from(value); let path = PathBuf::from(value);
if !path.exists() { if !path.exists() {
return Err(ParseError::DoesNotExist) return Err(ParseError::DoesNotExist);
} }
let extension = value.rsplit_once('.').unwrap_or_default(); let extension = value.rsplit_once('.').unwrap_or_default();
match extension.1 { match extension.1 {
@ -106,11 +114,15 @@ impl DatabaseError for ParseError {
todo!() todo!()
} }
fn as_error_mut(&mut self) -> &mut (dyn Error + Send + Sync + 'static) { fn as_error_mut(
&mut self,
) -> &mut (dyn Error + Send + Sync + 'static) {
todo!() todo!()
} }
fn into_error(self: Box<Self>) -> Box<dyn Error + Send + Sync + 'static> { fn into_error(
self: Box<Self>,
) -> Box<dyn Error + Send + Sync + 'static> {
todo!() todo!()
} }
@ -128,15 +140,15 @@ impl Display for ParseError {
Self::NonBackgroundFile => { Self::NonBackgroundFile => {
"The file is not a recognized image or video type" "The file is not a recognized image or video type"
} }
Self::DoesNotExist => { Self::DoesNotExist => "This file doesn't exist",
"This file doesn't exist"
}
}; };
write!(f, "Error: {message}") write!(f, "Error: {message}")
} }
} }
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(
Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub enum BackgroundKind { pub enum BackgroundKind {
#[default] #[default]
Image, Image,

View file

@ -2,7 +2,10 @@ use std::{collections::HashMap, path::PathBuf};
use color_eyre::eyre::{eyre, Context, Result}; use color_eyre::eyre::{eyre, Context, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{query, query_as, sqlite::SqliteRow, FromRow, Row, SqliteConnection}; use sqlx::{
query, query_as, sqlite::SqliteRow, FromRow, Row,
SqliteConnection,
};
use tracing::{debug, error}; use tracing::{debug, error};
use crate::{ use crate::{
@ -10,7 +13,9 @@ use crate::{
slides::{Background, TextAlignment}, slides::{Background, TextAlignment},
}; };
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(
Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub struct Song { pub struct Song {
pub id: i32, pub id: i32,
pub title: String, pub title: String,
@ -56,17 +61,24 @@ impl FromRow<'_, SqliteRow> for Song {
text_alignment: Some({ text_alignment: Some({
let horizontal_alignment: String = row.try_get(3)?; let horizontal_alignment: String = row.try_get(3)?;
let vertical_alignment: String = row.try_get(4)?; let vertical_alignment: String = row.try_get(4)?;
match (horizontal_alignment.to_lowercase().as_str(), vertical_alignment.to_lowercase().as_str()) { match (
horizontal_alignment.to_lowercase().as_str(),
vertical_alignment.to_lowercase().as_str(),
) {
("left", "top") => TextAlignment::TopLeft, ("left", "top") => TextAlignment::TopLeft,
("left", "center") => TextAlignment::MiddleLeft, ("left", "center") => TextAlignment::MiddleLeft,
("left", "bottom") => TextAlignment::BottomLeft, ("left", "bottom") => TextAlignment::BottomLeft,
("center", "top") => TextAlignment::TopCenter, ("center", "top") => TextAlignment::TopCenter,
("center", "center") => TextAlignment::MiddleCenter, ("center", "center") => {
("center", "bottom") => TextAlignment::BottomCenter, TextAlignment::MiddleCenter
}
("center", "bottom") => {
TextAlignment::BottomCenter
}
("right", "top") => TextAlignment::TopRight, ("right", "top") => TextAlignment::TopRight,
("right", "center") => TextAlignment::MiddleRight, ("right", "center") => TextAlignment::MiddleRight,
("right", "bottom") => TextAlignment::BottomRight, ("right", "bottom") => TextAlignment::BottomRight,
_ => TextAlignment::MiddleCenter _ => TextAlignment::MiddleCenter,
} }
}), }),
font: row.try_get(6)?, font: row.try_get(6)?,
@ -75,19 +87,20 @@ impl FromRow<'_, SqliteRow> for Song {
} }
} }
pub async fn get_song_from_db(
pub async fn get_song_from_db(index: i32, db: &mut SqliteConnection) -> Result<Song> { index: i32,
let row = query(r#"SELECT vorder as "verse_order!", fontSize as "font_size!: i32", backgroundType as "background_type!", horizontalTextAlignment as "horizontal_text_alignment!", verticalTextAlignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs where id = $1"#).bind(index).fetch_one(db).await?; db: &mut SqliteConnection,
) -> Result<Song> {
let row = query(r#"SELECT verse_order as "verse_order!", font_size as "font_size!: i32", background_type as "background_type!", horizontal_text_alignment as "horizontal_text_alignment!", vertical_text_alignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs where id = $1"#).bind(index).fetch_one(db).await?;
Ok(Song::from_row(&row)?) Ok(Song::from_row(&row)?)
} }
impl Model<Song> { impl Model<Song> {
pub fn load_from_db(&mut self) { pub fn load_from_db(&mut self) {
// static DATABASE_URL: &str = "sqlite:///home/chris/.local/share/lumina/library-db.sqlite3"; // static DATABASE_URL: &str = "sqlite:///home/chris/.local/share/lumina/library-db.sqlite3";
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query(r#"SELECT vorder as "verse_order!", fontSize as "font_size!: i32", backgroundType as "background_type!", horizontalTextAlignment as "horizontal_text_alignment!", verticalTextAlignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs"#).fetch_all(&mut self.db).await; let result = query(r#"SELECT verse_order as "verse_order!", font_size as "font_size!: i32", background_type as "background_type!", horizontal_text_alignment as "horizontal_text_alignment!", vertical_text_alignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs"#).fetch_all(&mut self.db).await;
match result { match result {
Ok(s) => { Ok(s) => {
for song in s.into_iter() { for song in s.into_iter() {

View file

@ -5,7 +5,9 @@ use sqlx::{query_as, SqliteConnection};
use std::path::PathBuf; use std::path::PathBuf;
use tracing::error; use tracing::error;
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] #[derive(
Clone, Debug, Default, PartialEq, Serialize, Deserialize,
)]
pub struct Video { pub struct Video {
pub id: i32, pub id: i32,
pub title: String, pub title: String,
@ -19,7 +21,7 @@ impl Model<Video> {
pub fn load_from_db(&mut self) { pub fn load_from_db(&mut self) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query_as!(Video, r#"SELECT title as "title!", filePath as "path!", startTime as "start_time!: f32", endTime as "end_time!: f32", loop as "looping!", id as "id: i32" from videos"#).fetch_all(&mut self.db).await; let result = query_as!(Video, r#"SELECT title as "title!", file_path as "path!", start_time as "start_time!: f32", end_time as "end_time!: f32", loop as "looping!", id as "id: i32" from videos"#).fetch_all(&mut self.db).await;
match result { match result {
Ok(v) => { Ok(v) => {
for video in v.into_iter() { for video in v.into_iter() {
@ -32,12 +34,13 @@ impl Model<Video> {
} }
} }
pub async fn get_video_from_db(
pub async fn get_video_from_db(database_id: i32, db: &mut SqliteConnection) -> Result<Video> { database_id: i32,
Ok(query_as!(Video, r#"SELECT title as "title!", filePath as "path!", startTime as "start_time!: f32", endTime as "end_time!: f32", loop as "looping!", id as "id: i32" from videos where id = ?"#, database_id).fetch_one(db).await?) db: &mut SqliteConnection,
) -> Result<Video> {
Ok(query_as!(Video, r#"SELECT title as "title!", file_path as "path!", start_time as "start_time!: f32", end_time as "end_time!: f32", loop as "looping!", id as "id: i32" from videos where id = ?"#, database_id).fetch_one(db).await?)
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
@ -71,7 +74,10 @@ mod test {
let new_video = test_video("A newer video".into()); let new_video = test_video("A newer video".into());
match result { match result {
Ok(_) => { Ok(_) => {
assert_eq!(&video, video_model.find(|v| v.id == 0).unwrap()); assert_eq!(
&video,
video_model.find(|v| v.id == 0).unwrap()
);
assert_ne!( assert_ne!(
&new_video, &new_video,
video_model.find(|v| v.id == 0).unwrap() video_model.find(|v| v.id == 0).unwrap()

View file

@ -181,7 +181,7 @@ pub struct ImageModelRust {
highest_id: i32, highest_id: i32,
images: Vec<Image>, images: Vec<Image>,
inner_images: Vec<Image>, inner_images: Vec<Image>,
db: SqliteConnection db: SqliteConnection,
} }
impl Default for ImageModelRust { impl Default for ImageModelRust {
@ -199,9 +199,11 @@ impl Default for ImageModelRust {
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
rt.block_on(async { rt.block_on(async {
SqliteConnection::connect(&db_url).await.expect("problems") SqliteConnection::connect(&db_url)
.await
.expect("problems")
}) })
} },
} }
} }
} }
@ -215,11 +217,13 @@ pub fn get_image(index: i32) -> color_eyre::Result<Image> {
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
rt.block_on(async { rt.block_on(async {
SqliteConnection::connect(&db_url).await.expect("problems") SqliteConnection::connect(&db_url)
.await
.expect("problems")
}) })
}; };
rt.block_on(async { rt.block_on(async {
let result = query_as!(Image, r#"SELECT id as "id: i32", title as "title!", filePath as "path!" from images where id = ?"#, index).fetch_one(&mut db).await?; let result = query_as!(Image, r#"SELECT id as "id: i32", title as "title!", file_path as "path!" from images where id = ?"#, index).fetch_one(&mut db).await?;
Ok(result) Ok(result)
}) })
} }
@ -236,7 +240,7 @@ impl image_model::ImageModel {
pub fn setup(mut self: Pin<&mut Self>) { pub fn setup(mut self: Pin<&mut Self>) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query_as!(Image, r#"SELECT id as "id: i32", title as "title!", filePath as "path!" from images"#).fetch_all(&mut self.as_mut().rust_mut().db).await; let result = query_as!(Image, r#"SELECT id as "id: i32", title as "title!", file_path as "path!" from images"#).fetch_all(&mut self.as_mut().rust_mut().db).await;
match result { match result {
Ok(i) => i.into_iter().for_each(|i| self.as_mut().add_image(i)), Ok(i) => i.into_iter().for_each(|i| self.as_mut().add_image(i)),
Err(e) => error!("There was an error in converting songs: {e}"), Err(e) => error!("There was an error in converting songs: {e}"),
@ -251,7 +255,10 @@ impl image_model::ImageModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("delete from images where id = ?", index).execute(&mut self.as_mut().rust_mut().db).await; let result =
query!("delete from images where id = ?", index)
.execute(&mut self.as_mut().rust_mut().db)
.await;
match result { match result {
Ok(_i) => { Ok(_i) => {
unsafe { unsafe {
@ -308,7 +315,7 @@ impl image_model::ImageModel {
rt.block_on(async { rt.block_on(async {
let image_title = image_title.to_string(); let image_title = image_title.to_string();
let image_path = image_path.to_string(); let image_path = image_path.to_string();
let result = query!(r#"INSERT into images (id, title, filePath) VALUES (?, ?, ?)"#, let result = query!(r#"INSERT into images (id, title, file_path) VALUES (?, ?, ?)"#,
image_id, image_id,
image_title, image_title,
image_path) image_path)
@ -367,9 +374,13 @@ impl image_model::ImageModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let title = updated_title.to_string(); let title = updated_title.to_string();
let result = query!("UPDATE images SET title = ? where id = ?", title, index) let result = query!(
.execute(&mut self.as_mut().rust_mut().db) "UPDATE images SET title = ? where id = ?",
.await; title,
index
)
.execute(&mut self.as_mut().rust_mut().db)
.await;
match result { match result {
Ok(_i) => { Ok(_i) => {
for image in self for image in self
@ -380,9 +391,11 @@ impl image_model::ImageModel {
.filter(|x| x.id == index) .filter(|x| x.id == index)
{ {
image.title = title.clone(); image.title = title.clone();
debug!(title = image.title, debug!(
title = title, title = image.title,
"updated image title"); title = title,
"updated image title"
);
} }
self.as_mut().data_changed( self.as_mut().data_changed(
model_index, model_index,
@ -394,7 +407,7 @@ impl image_model::ImageModel {
Err(e) => { Err(e) => {
error!("Error connecting to db: {e}"); error!("Error connecting to db: {e}");
false false
}, }
} }
}); });
true true
@ -414,9 +427,13 @@ impl image_model::ImageModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let updated_path = updated_path.to_string(); let updated_path = updated_path.to_string();
let result = query!("UPDATE images SET filePath = ? where id = ?", updated_path, index) let result = query!(
.execute(&mut self.as_mut().rust_mut().db) "UPDATE images SET file_path = ? where id = ?",
.await; updated_path,
index
)
.execute(&mut self.as_mut().rust_mut().db)
.await;
match result { match result {
Ok(_i) => { Ok(_i) => {
for image in self for image in self
@ -427,9 +444,11 @@ impl image_model::ImageModel {
.filter(|x| x.id == index) .filter(|x| x.id == index)
{ {
image.path = updated_path.clone(); image.path = updated_path.clone();
debug!(title = image.title, debug!(
path = updated_path, title = image.title,
"updated image path"); path = updated_path,
"updated image path"
);
} }
self.as_mut().data_changed( self.as_mut().data_changed(
model_index, model_index,
@ -441,7 +460,7 @@ impl image_model::ImageModel {
Err(e) => { Err(e) => {
error!("Error connecting to db: {e}"); error!("Error connecting to db: {e}");
false false
}, }
} }
}); });
true true

View file

@ -8,10 +8,9 @@ pub mod service_item_model;
pub mod settings; pub mod settings;
pub mod slide_model; pub mod slide_model;
pub mod slide_object; pub mod slide_object;
pub mod slide_types;
pub mod songs; pub mod songs;
pub mod utils; pub mod utils;
pub mod video_model; pub mod video_model;
pub mod ytdl; pub mod ytdl;
pub mod slide_types;
// pub mod core;
// mod video_thumbnail; // mod video_thumbnail;

View file

@ -4,7 +4,6 @@ use cxx_qt_lib::{QString, QStringList};
use obws::responses::scenes::{CurrentProgramScene, Scenes}; use obws::responses::scenes::{CurrentProgramScene, Scenes};
use obws::Client; use obws::Client;
use std::{error::Error, pin::Pin}; use std::{error::Error, pin::Pin};
use tracing::{debug, error}; use tracing::{debug, error};
@ -22,7 +21,10 @@ impl fmt::Debug for Obs {
f.debug_struct("Client") f.debug_struct("Client")
.field("scenes", &self.scenes) .field("scenes", &self.scenes)
.field("client", &self.client.is_some()) .field("client", &self.client.is_some())
.field("current_program_scene", &self.current_program_scene) .field(
"current_program_scene",
&self.current_program_scene,
)
.finish() .finish()
} }
} }
@ -37,8 +39,6 @@ impl Clone for Obs {
} }
} }
impl Obs { impl Obs {
pub async fn new() -> Result<Self, Box<dyn Error>> { pub async fn new() -> Result<Self, Box<dyn Error>> {
let client = let client =

View file

@ -208,7 +208,7 @@ pub struct PresentationModelRust {
highest_id: i32, highest_id: i32,
presentations: Vec<Presentation>, presentations: Vec<Presentation>,
inner_presentations: Vec<Presentation>, inner_presentations: Vec<Presentation>,
db: SqliteConnection db: SqliteConnection,
} }
impl Default for PresentationModelRust { impl Default for PresentationModelRust {
@ -226,14 +226,18 @@ impl Default for PresentationModelRust {
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
rt.block_on(async { rt.block_on(async {
SqliteConnection::connect(&db_url).await.expect("problems") SqliteConnection::connect(&db_url)
.await
.expect("problems")
}) })
} },
} }
} }
} }
pub fn get_presentation(index: i32) -> color_eyre::Result<Presentation> { pub fn get_presentation(
index: i32,
) -> color_eyre::Result<Presentation> {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
let mut db = { let mut db = {
let mut data = dirs::data_local_dir().unwrap(); let mut data = dirs::data_local_dir().unwrap();
@ -242,11 +246,13 @@ pub fn get_presentation(index: i32) -> color_eyre::Result<Presentation> {
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
rt.block_on(async { rt.block_on(async {
SqliteConnection::connect(&db_url).await.expect("problems") SqliteConnection::connect(&db_url)
.await
.expect("problems")
}) })
}; };
rt.block_on(async { rt.block_on(async {
let result = query_as!(Presentation, r#"SELECT id as "id: i32", title as "title!", filePath as "path!", html as "html!", pageCount as "page_count!: i32" from presentations where id = ?"#, index).fetch_one(&mut db).await?; let result = query_as!(Presentation, r#"SELECT id as "id: i32", title as "title!", file_path as "path!", html as "html!", pageCount as "page_count!: i32" from presentations where id = ?"#, index).fetch_one(&mut db).await?;
Ok(result) Ok(result)
}) })
} }
@ -263,7 +269,7 @@ impl presentation_model::PresentationModel {
pub fn setup(mut self: Pin<&mut Self>) { pub fn setup(mut self: Pin<&mut Self>) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query_as!(Presentation, r#"SELECT id as "id: i32", title as "title!", filePath as "path!", html as "html!", pageCount as "page_count!: i32" from presentations"#).fetch_all(&mut self.as_mut().rust_mut().db).await; let result = query_as!(Presentation, r#"SELECT id as "id: i32", title as "title!", file_path as "path!", html as "html!", pageCount as "page_count!: i32" from presentations"#).fetch_all(&mut self.as_mut().rust_mut().db).await;
match result { match result {
Ok(p) => p.into_iter().for_each(|p| self.as_mut().add_presentation(p)), Ok(p) => p.into_iter().for_each(|p| self.as_mut().add_presentation(p)),
Err(e) => error!("There was an error in converting songs: {e}"), Err(e) => error!("There was an error in converting songs: {e}"),
@ -278,7 +284,12 @@ impl presentation_model::PresentationModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("delete from presentations where id = ?", index).execute(&mut self.as_mut().rust_mut().db).await; let result = query!(
"delete from presentations where id = ?",
index
)
.execute(&mut self.as_mut().rust_mut().db)
.await;
match result { match result {
Ok(_i) => { Ok(_i) => {
unsafe { unsafe {
@ -365,7 +376,7 @@ impl presentation_model::PresentationModel {
rt.block_on(async { rt.block_on(async {
let presentation_title = presentation_title.to_string(); let presentation_title = presentation_title.to_string();
let presentation_path = presentation_path.to_string(); let presentation_path = presentation_path.to_string();
let result = query!(r#"INSERT into presentations (id, title, filePath, html, pageCount) VALUES (?, ?, ?, ?, ?)"#, let result = query!(r#"INSERT into presentations (id, title, file_path, html, pageCount) VALUES (?, ?, ?, ?, ?)"#,
presentation_id, presentation_id,
presentation_title, presentation_title,
presentation_path, presentation_path,
@ -503,9 +514,13 @@ impl presentation_model::PresentationModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let title = updated_title.to_string(); let title = updated_title.to_string();
let result = query!("UPDATE presentations SET title = ? where id = ?", title, index) let result = query!(
.execute(&mut self.as_mut().rust_mut().db) "UPDATE presentations SET title = ? where id = ?",
.await; title,
index
)
.execute(&mut self.as_mut().rust_mut().db)
.await;
match result { match result {
Ok(_i) => { Ok(_i) => {
for presentation in self for presentation in self
@ -516,9 +531,11 @@ impl presentation_model::PresentationModel {
.filter(|x| x.id == index) .filter(|x| x.id == index)
{ {
presentation.title = title.clone(); presentation.title = title.clone();
debug!(title = presentation.title, debug!(
title = title, title = presentation.title,
"updated presentation title"); title = title,
"updated presentation title"
);
} }
self.as_mut().data_changed( self.as_mut().data_changed(
model_index, model_index,
@ -530,7 +547,7 @@ impl presentation_model::PresentationModel {
Err(e) => { Err(e) => {
error!("Error connecting to db: {e}"); error!("Error connecting to db: {e}");
false false
}, }
} }
}); });
true true
@ -549,9 +566,13 @@ impl presentation_model::PresentationModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("UPDATE presentations SET pageCount = ? where id = ?", updated_page_count, index) let result = query!(
.execute(&mut self.as_mut().rust_mut().db) "UPDATE presentations SET pageCount = ? where id = ?",
.await; updated_page_count,
index
)
.execute(&mut self.as_mut().rust_mut().db)
.await;
match result { match result {
Ok(_i) => { Ok(_i) => {
for presentation in self for presentation in self
@ -561,10 +582,13 @@ impl presentation_model::PresentationModel {
.iter_mut() .iter_mut()
.filter(|x| x.id == index) .filter(|x| x.id == index)
{ {
presentation.page_count = updated_page_count.clone(); presentation.page_count =
debug!(title = presentation.title, updated_page_count.clone();
page_count = updated_page_count, debug!(
"updated presentation page_count"); title = presentation.title,
page_count = updated_page_count,
"updated presentation page_count"
);
} }
self.as_mut().data_changed( self.as_mut().data_changed(
model_index, model_index,
@ -576,7 +600,7 @@ impl presentation_model::PresentationModel {
Err(e) => { Err(e) => {
error!("Error connecting to db: {e}"); error!("Error connecting to db: {e}");
false false
}, }
} }
}); });
true true

View file

@ -271,7 +271,12 @@ mod service_item_model {
} }
} }
use self::service_item_model::{
QHash_i32_QByteArray, QMap_QString_QVariant, QVector_i32,
ServiceRoles,
};
use crate::service_item_model::service_item_model::QList_QString; use crate::service_item_model::service_item_model::QList_QString;
use crate::slide_types::SlideType;
use crate::songs::song_model::{get_song, Song}; use crate::songs::song_model::{get_song, Song};
use crate::{image_model, presentation_model, video_model}; use crate::{image_model, presentation_model, video_model};
use cxx_qt::{CxxQtType, Threading}; use cxx_qt::{CxxQtType, Threading};
@ -279,6 +284,7 @@ use cxx_qt_lib::{
QByteArray, QModelIndex, QString, QStringList, QUrl, QVariant, QByteArray, QModelIndex, QString, QStringList, QUrl, QVariant,
}; };
use dirs; use dirs;
// use lumina_core::service_items::ServiceItem as SI;
use serde_json::{json, Value}; use serde_json::{json, Value};
use std::iter; use std::iter;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -288,12 +294,6 @@ use std::{fs, println};
use tar::{Archive, Builder}; use tar::{Archive, Builder};
use tracing::{debug, error}; use tracing::{debug, error};
use zstd::{Decoder, Encoder}; use zstd::{Decoder, Encoder};
use self::service_item_model::{
QHash_i32_QByteArray, QMap_QString_QVariant, QVector_i32,
ServiceRoles,
};
use crate::slide_types::SlideType;
use lumina_core::service_items::ServiceItem as SI;
use super::service_item_model::service_item_model::ServiceItemModel; use super::service_item_model::service_item_model::ServiceItemModel;
@ -377,7 +377,9 @@ impl service_item_model::ServiceItemModel {
pub fn remove_items(mut self: Pin<&mut Self>) { pub fn remove_items(mut self: Pin<&mut Self>) {
let mut indices = vec![]; let mut indices = vec![];
let mut items = self.service_items.clone(); let mut items = self.service_items.clone();
for (index, _item) in items.iter_mut().enumerate().filter(|(_y, x)| x.selected) { for (index, _item) in
items.iter_mut().enumerate().filter(|(_y, x)| x.selected)
{
let index = index as i32; let index = index as i32;
indices.push(index); indices.push(index);
} }
@ -436,7 +438,10 @@ impl service_item_model::ServiceItemModel {
self.as_mut().end_insert_rows(); self.as_mut().end_insert_rows();
} }
debug!("ADDING: {:?}", &service_item); debug!("ADDING: {:?}", &service_item);
self.as_mut().item_added(&service_item.database_id.unwrap_or_default(), &QString::from(&service_item.ty.to_string())); self.as_mut().item_added(
&service_item.database_id.unwrap_or_default(),
&QString::from(&service_item.ty.to_string()),
);
} }
pub fn insert_item( pub fn insert_item(
@ -475,7 +480,11 @@ impl service_item_model::ServiceItemModel {
self.as_mut().end_insert_rows(); self.as_mut().end_insert_rows();
} }
debug!("ADDING: {:?}", &service_item); debug!("ADDING: {:?}", &service_item);
self.as_mut().item_inserted(&index, &service_item.database_id.unwrap_or_default(), &QString::from(&service_item.ty.to_string())); self.as_mut().item_inserted(
&index,
&service_item.database_id.unwrap_or_default(),
&QString::from(&service_item.ty.to_string()),
);
} }
pub fn get_item( pub fn get_item(
@ -876,8 +885,7 @@ impl service_item_model::ServiceItemModel {
Some(name) => { Some(name) => {
println!("audio: {:?}", &name); println!("audio: {:?}", &name);
if name.to_str().unwrap() != "temp" { if name.to_str().unwrap() != "temp" {
flat_audio = flat_audio = name.to_str().unwrap()
name.to_str().unwrap()
} else { } else {
flat_audio = ""; flat_audio = "";
} }
@ -961,12 +969,18 @@ impl service_item_model::ServiceItemModel {
debug!(time = ?now.elapsed(), "file written"); debug!(time = ?now.elapsed(), "file written");
std::thread::spawn(move || { std::thread::spawn(move || {
debug!(time = ?now.elapsed(), "idk"); debug!(time = ?now.elapsed(), "idk");
let dir = fs::read_dir(&temp_dir).expect("idk"); let dir = fs::read_dir(&temp_dir)
.expect("idk");
for (index, file) in dir.enumerate() { for (index, file) in dir.enumerate() {
if let Ok(file) = file { if let Ok(file) = file {
let file_name = file.file_name(); let file_name =
file.file_name();
debug!(?file, ?file_name); debug!(?file, ?file_name);
let mut file = std::fs::File::open(file.path()).expect("missing file"); let mut file =
std::fs::File::open(
file.path(),
)
.expect("missing file");
tar.append_file(file_name, &mut file).expect("Error in moving file to tar"); tar.append_file(file_name, &mut file).expect("Error in moving file to tar");
thread.queue(move |mut service| { thread.queue(move |mut service| {
service service
@ -977,10 +991,11 @@ impl service_item_model::ServiceItemModel {
) )
}).expect("Problem queuing on cxx thread"); }).expect("Problem queuing on cxx thread");
} }
} }
if let Ok(encoder) = tar.into_inner() { if let Ok(encoder) = tar.into_inner()
if let Ok(done) = encoder.finish() { {
if let Ok(done) = encoder.finish()
{
debug!(time = ?now.elapsed(), ?done, "tar finished"); debug!(time = ?now.elapsed(), ?done, "tar finished");
thread.queue(move |mut service| { thread.queue(move |mut service| {
service.as_mut().set_save_progress(100.0); service.as_mut().set_save_progress(100.0);
@ -1000,9 +1015,7 @@ impl service_item_model::ServiceItemModel {
} }
} else { } else {
fs::remove_dir_all(&temp_dir) fs::remove_dir_all(&temp_dir)
.expect( .expect("error in removal");
"error in removal",
);
false false
} }
}); });
@ -1058,7 +1071,9 @@ impl service_item_model::ServiceItemModel {
if !file_path.exists() { if !file_path.exists() {
match file.unpack_in(&datadir) { match file.unpack_in(&datadir) {
Ok(_t) => (), Ok(_t) => (),
Err(e) => error!("Error unpacking archive: {}", e), Err(e) => {
error!("Error unpacking archive: {}", e)
}
} }
} }
} }
@ -1341,7 +1356,9 @@ impl service_item_model::ServiceItemModel {
let mut vector_roles = QVector_i32::default(); let mut vector_roles = QVector_i32::default();
vector_roles.append(self.as_ref().get_role(role)); vector_roles.append(self.as_ref().get_role(role));
if let Some(index) = if let Some(index) =
self.as_ref().service_items.iter().position(|x| x.database_id.unwrap_or_default() == item_id) self.as_ref().service_items.iter().position(|x| {
x.database_id.unwrap_or_default() == item_id
})
{ {
let model_index = self.as_ref().index( let model_index = self.as_ref().index(
index as i32, index as i32,
@ -1355,7 +1372,6 @@ impl service_item_model::ServiceItemModel {
} }
} }
pub fn load_last_saved(self: Pin<&mut Self>) -> bool { pub fn load_last_saved(self: Pin<&mut Self>) -> bool {
todo!(); todo!();
// Don't actually need // Don't actually need
@ -1394,9 +1410,9 @@ impl service_item_model::ServiceItemModel {
ServiceRoles::Name => { ServiceRoles::Name => {
QVariant::from(&service_item.name) QVariant::from(&service_item.name)
} }
ServiceRoles::Type => { ServiceRoles::Type => QVariant::from(&QString::from(
QVariant::from(&QString::from(&service_item.ty.clone().to_string())) &service_item.ty.clone().to_string(),
} )),
ServiceRoles::Audio => { ServiceRoles::Audio => {
QVariant::from(&service_item.audio) QVariant::from(&service_item.audio)
} }
@ -1433,9 +1449,9 @@ impl service_item_model::ServiceItemModel {
ServiceRoles::VideoEndTime => { ServiceRoles::VideoEndTime => {
QVariant::from(&service_item.video_end_time) QVariant::from(&service_item.video_end_time)
} }
ServiceRoles::Id => { ServiceRoles::Id => QVariant::from(
QVariant::from(&service_item.database_id.unwrap_or_default()) &service_item.database_id.unwrap_or_default(),
} ),
_ => QVariant::default(), _ => QVariant::default(),
}; };
} }
@ -1503,22 +1519,21 @@ impl service_item_model::ServiceItemModel {
ServiceRoles::VideoEndTime.repr, ServiceRoles::VideoEndTime.repr,
QByteArray::from("videoEndTime"), QByteArray::from("videoEndTime"),
); );
roles.insert( roles.insert(ServiceRoles::Id.repr, QByteArray::from("id"));
ServiceRoles::Id.repr,
QByteArray::from("id"),
);
roles roles
} }
pub fn row_count(&self, _parent: &QModelIndex) -> i32 { pub fn row_count(&self, _parent: &QModelIndex) -> i32 {
// println!("row count is {cnt}"); // println!("row count is {cnt}");
self.service_items.len() as i32 self.service_items.len() as i32
} }
} }
impl ServiceItemModelRust { impl ServiceItemModelRust {
pub fn save(_model: Pin<&mut ServiceItemModel>, _file: QUrl) -> bool { pub fn save(
_model: Pin<&mut ServiceItemModel>,
_file: QUrl,
) -> bool {
todo!() todo!()
} }
} }

View file

@ -19,9 +19,11 @@ pub mod slide_model {
include!("cxx-qt-lib/qlist.h"); include!("cxx-qt-lib/qlist.h");
type QList_QString = cxx_qt_lib::QList<QString>; type QList_QString = cxx_qt_lib::QList<QString>;
include!("cxx-qt-gen/slide_object.cxxqt.h"); include!("cxx-qt-gen/slide_object.cxxqt.h");
type SlideObject = crate::slide_object::slide_object::SlideObject; type SlideObject =
crate::slide_object::slide_object::SlideObject;
include!("cxx-qt-gen/song_model.cxxqt.h"); include!("cxx-qt-gen/song_model.cxxqt.h");
type SongModel = crate::songs::song_model::song_model::SongModel; type SongModel =
crate::songs::song_model::song_model::SongModel;
include!("cxx-qt-gen/video_model.cxxqt.h"); include!("cxx-qt-gen/video_model.cxxqt.h");
type VideoModel = crate::video_model::video_model::VideoModel; type VideoModel = crate::video_model::video_model::VideoModel;
include!("cxx-qt-gen/image_model.cxxqt.h"); include!("cxx-qt-gen/image_model.cxxqt.h");
@ -229,26 +231,29 @@ pub mod slide_model {
use crate::image_model::image_model::ImageModel; use crate::image_model::image_model::ImageModel;
use crate::image_model::{self, Image, ImageModelRust}; use crate::image_model::{self, Image, ImageModelRust};
use crate::obs::Obs;
use crate::presentation_model::presentation_model::PresentationModel; use crate::presentation_model::presentation_model::PresentationModel;
use crate::presentation_model::{self, Presentation, PresentationModelRust}; use crate::presentation_model::{
self, Presentation, PresentationModelRust,
};
use crate::slide_model::slide_model::QList_QString;
use crate::songs::song_model::song_model::{self, SongModel}; use crate::songs::song_model::song_model::{self, SongModel};
use crate::songs::song_model::{get_song, Song, SongModelRust}; use crate::songs::song_model::{get_song, Song, SongModelRust};
use crate::video_model::video_model::VideoModel; use crate::video_model::video_model::VideoModel;
use crate::video_model::{self, Video, VideoModelRust}; use crate::video_model::{self, Video, VideoModelRust};
use crate::{ffmpeg, slide_types::SlideType}; use crate::{ffmpeg, slide_types::SlideType};
use crate::obs::Obs;
use crate::slide_model::slide_model::QList_QString;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use color_eyre::Section; use color_eyre::Section;
use cxx_qt::{CxxQtType, Threading}; use cxx_qt::{CxxQtType, Threading};
use cxx_qt_lib::{ use cxx_qt_lib::{
CaseSensitivity, QByteArray, QList, QModelIndex, QString, QStringList, QVariant CaseSensitivity, QByteArray, QList, QModelIndex, QString,
QStringList, QVariant,
}; };
use slide_model::SlideObject; use slide_model::SlideObject;
use std::error::Error; use std::error::Error;
use std::fmt::{Display}; use std::fmt::Display;
use std::{path::PathBuf, pin::Pin}; use std::{path::PathBuf, pin::Pin};
use tracing::{debug, error}; use tracing::{debug, error, warn};
use self::slide_model::{ use self::slide_model::{
QHash_i32_QByteArray, QMap_QString_QVariant, QVector_i32, QHash_i32_QByteArray, QMap_QString_QVariant, QVector_i32,
@ -336,45 +341,40 @@ impl Slide {
fn slides_from_song(song: Song) -> Result<Vec<Self>> { fn slides_from_song(song: Song) -> Result<Vec<Self>> {
let list = song.get_lyric_list(); let list = song.get_lyric_list();
let total = list.len(); let total = list.len();
let mut vector: Vec<Slide> = vec![]; let vector = list
list.iter().map(|t| t.to_string()).enumerate() .iter()
.for_each(|(i, s)| { .map(|t| {
if song.background_type == "image" { let s = t.to_string();
vector.push( warn!(s);
Self { s
text: s, })
ty: SlideType::Song, .enumerate()
audio: song.audio.clone(), .map(|(i, s)| Self {
image_background: song.background.clone(), text: s,
video_background: "".to_owned(), ty: SlideType::Song,
htext_alignment: song.horizontal_text_alignment.clone(), audio: song.audio.clone(),
vtext_alignment: song.vertical_text_alignment.clone(), image_background: if song.background_type == "image" {
font: song.font.clone(), song.background.clone()
font_size: song.font_size, } else {
slide_count: total as i32, "".into()
slide_index: i as i32, },
..Default::default() video_background: if song.background_type == "video" {
} song.background.clone()
); } else {
} else { "".to_owned()
vector.push( },
Self { htext_alignment: song
text: s, .horizontal_text_alignment
ty: SlideType::Song, .clone(),
audio: song.audio.clone(), vtext_alignment: song.vertical_text_alignment.clone(),
image_background: "".to_owned(), font: song.font.clone(),
video_background: song.background.clone(), font_size: song.font_size,
htext_alignment: song.horizontal_text_alignment.clone(), slide_count: total as i32,
vtext_alignment: song.vertical_text_alignment.clone(), slide_index: i as i32,
font: song.font.clone(), ..Default::default()
font_size: song.font_size, })
slide_count: total as i32, .collect();
slide_index: i as i32, warn!(?vector);
..Default::default()
}
)
}
});
Ok(vector) Ok(vector)
} }
@ -395,7 +395,9 @@ impl Slide {
}) })
} }
fn slides_from_presentation(presentation: Presentation) -> Result<Vec<Self>> { fn slides_from_presentation(
presentation: Presentation,
) -> Result<Vec<Self>> {
let total = presentation.page_count; let total = presentation.page_count;
let mut slides: Vec<Slide> = vec![]; let mut slides: Vec<Slide> = vec![];
for i in 0..total { for i in 0..total {
@ -406,7 +408,7 @@ impl Slide {
image_background: presentation.path.clone(), image_background: presentation.path.clone(),
..Default::default() ..Default::default()
}) })
}; }
Ok(slides) Ok(slides)
} }
} }
@ -456,9 +458,12 @@ impl slide_model::SlideModel {
index: i32, index: i32,
) -> bool { ) -> bool {
let mut vector_roles = QVector_i32::default(); let mut vector_roles = QVector_i32::default();
vector_roles.append(self.get_role(SlideRoles::VideoThumbnail)); vector_roles
vector_roles.append(self.get_role(SlideRoles::VideoBackground)); .append(self.get_role(SlideRoles::VideoThumbnail));
vector_roles.append(self.get_role(SlideRoles::ImageBackground)); vector_roles
.append(self.get_role(SlideRoles::VideoBackground));
vector_roles
.append(self.get_role(SlideRoles::ImageBackground));
let rc = self.as_ref().count() - 1; let rc = self.as_ref().count() - 1;
let tl = self.as_ref().index(0, 0, &QModelIndex::default()); let tl = self.as_ref().index(0, 0, &QModelIndex::default());
let br = self.as_ref().index(rc, 0, &QModelIndex::default()); let br = self.as_ref().index(rc, 0, &QModelIndex::default());
@ -470,7 +475,11 @@ impl slide_model::SlideModel {
let path = let path =
PathBuf::from(slide.video_background.to_string()); PathBuf::from(slide.video_background.to_string());
let screenshot = ffmpeg::bg_path_from_video(&path); let screenshot = ffmpeg::bg_path_from_video(&path);
let mut screenshot_string = screenshot.clone().into_os_string().into_string().unwrap_or_default(); let mut screenshot_string = screenshot
.clone()
.into_os_string()
.into_string()
.unwrap_or_default();
screenshot_string.insert_str(0, "file://"); screenshot_string.insert_str(0, "file://");
slide.video_thumbnail = screenshot_string; slide.video_thumbnail = screenshot_string;
std::thread::spawn(move || { std::thread::spawn(move || {
@ -616,37 +625,56 @@ impl slide_model::SlideModel {
SlideType::Song => { SlideType::Song => {
let song = get_song(item_model_id)?; let song = get_song(item_model_id)?;
let slides = Slide::slides_from_song(song)?; let slides = Slide::slides_from_song(song)?;
slides.iter().for_each(|slide| self.as_mut().insert_slide(slide, index)); slides.iter().enumerate().for_each(|(i, slide)| {
self.as_mut()
.insert_slide(slide, index + i as i32)
});
Ok(()) Ok(())
}, }
SlideType::Video => { SlideType::Video => {
let video = video_model::get_video(item_model_id)?; let video = video_model::get_video(item_model_id)?;
self.insert_slide(&Slide::slide_from_video(video)?, index); self.insert_slide(
&Slide::slide_from_video(video)?,
index,
);
Ok(()) Ok(())
}, }
SlideType::Image => { SlideType::Image => {
let result = image_model::get_image(item_model_id); let result = image_model::get_image(item_model_id);
match result { match result {
Ok(image) => self.insert_slide(&Slide::slide_from_image(image)?, index), Ok(image) => self.insert_slide(
&Slide::slide_from_image(image)?,
index,
),
Err(e) => { Err(e) => {
e.with_note(|| { e.with_note(|| {
format!("This might fail if we are loading the items from a file") format!("This might fail if we are loading the items from a file")
}); });
let mut slide = Slide::default(); let mut slide = Slide::default();
slide.image_background = "qrc:/assets/black.jpg".to_owned(); slide.image_background =
"qrc:/assets/black.jpg".to_owned();
self.insert_slide(&slide, index); self.insert_slide(&slide, index);
}, }
} }
Ok(()) Ok(())
}, }
SlideType::Content => { SlideType::Content => {
todo!(); todo!();
Ok(()) Ok(())
}, }
SlideType::Presentation(_) => { SlideType::Presentation(_) => {
let presentation = presentation_model::get_presentation(item_model_id)?; let presentation =
let slides = Slide::slides_from_presentation(presentation)?; presentation_model::get_presentation(
slides.iter().for_each(|slide| self.as_mut().insert_slide(slide, slide.slide_index + index)); item_model_id,
)?;
let slides =
Slide::slides_from_presentation(presentation)?;
slides.iter().for_each(|slide| {
self.as_mut().insert_slide(
slide,
slide.slide_index + index,
)
});
Ok(()) Ok(())
} }
} }
@ -656,7 +684,7 @@ impl slide_model::SlideModel {
self: Pin<&mut Self>, self: Pin<&mut Self>,
item_model_id: i32, item_model_id: i32,
kind: &QString, kind: &QString,
) -> Result<()>{ ) -> Result<()> {
let index = self.count; let index = self.count;
self.insert_item_from_service(index, item_model_id, kind) self.insert_item_from_service(index, item_model_id, kind)
} }
@ -692,7 +720,8 @@ impl slide_model::SlideModel {
if let Some((i, slide)) = slides_iter if let Some((i, slide)) = slides_iter
.clone() .clone()
.enumerate().find(|slide| slide.1.service_item_id == source_index) .enumerate()
.find(|slide| slide.1.service_item_id == source_index)
{ {
debug!(index = i, ?slide); debug!(index = i, ?slide);
first_slide = i as i32; first_slide = i as i32;
@ -705,11 +734,8 @@ impl slide_model::SlideModel {
// lets get the dest_slide and count // lets get the dest_slide and count
if move_down { if move_down {
if let Some((i, slide)) = slides_iter if let Some((i, slide)) =
.clone() slides_iter.clone().enumerate().rev().find(|slide| {
.enumerate()
.rev()
.find(|slide| {
slide.1.service_item_id == destination_index slide.1.service_item_id == destination_index
}) })
{ {
@ -724,9 +750,8 @@ impl slide_model::SlideModel {
dest_slide, dest_count dest_slide, dest_count
); );
} }
} else if let Some((i, slide)) = slides_iter } else if let Some((i, slide)) =
.enumerate() slides_iter.enumerate().find(|slide| {
.find(|slide| {
slide.1.service_item_id == destination_index slide.1.service_item_id == destination_index
}) })
{ {
@ -1001,7 +1026,8 @@ impl slide_model::SlideModel {
debug!(service_item = index, "Getting slide from this item"); debug!(service_item = index, "Getting slide from this item");
let mut id = 0; let mut id = 0;
if let Some((i, slide)) = slides_iter if let Some((i, slide)) = slides_iter
.enumerate().find(|(_i, slide)| slide.service_item_id == index) .enumerate()
.find(|(_i, slide)| slide.service_item_id == index)
{ {
debug!(slide_id = i, ?slide); debug!(slide_id = i, ?slide);
id = i as i32; id = i as i32;
@ -1105,7 +1131,6 @@ impl slide_model::SlideModel {
(0, QModelIndex::default(), vector_roles) (0, QModelIndex::default(), vector_roles)
} }
} }
} }
// QAbstractListModel implementation // QAbstractListModel implementation
@ -1114,22 +1139,30 @@ impl slide_model::SlideModel {
let role = SlideRoles { repr: role }; let role = SlideRoles { repr: role };
if let Some(slide) = self.slides.get(index.row() as usize) { if let Some(slide) = self.slides.get(index.row() as usize) {
return match role { return match role {
SlideRoles::Ty => QVariant::from(&QString::from(&slide.ty.to_string())), SlideRoles::Ty => QVariant::from(&QString::from(
SlideRoles::Text => QVariant::from(&QString::from(&slide.text)), &slide.ty.to_string(),
SlideRoles::Audio => QVariant::from(&QString::from(&slide.audio)), )),
SlideRoles::ImageBackground => { SlideRoles::Text => {
QVariant::from(&QString::from(&slide.image_background)) QVariant::from(&QString::from(&slide.text))
} }
SlideRoles::VideoBackground => { SlideRoles::Audio => {
QVariant::from(&QString::from(&slide.video_background)) QVariant::from(&QString::from(&slide.audio))
} }
SlideRoles::HTextAlignment => { SlideRoles::ImageBackground => QVariant::from(
QVariant::from(&QString::from(&slide.htext_alignment)) &QString::from(&slide.image_background),
),
SlideRoles::VideoBackground => QVariant::from(
&QString::from(&slide.video_background),
),
SlideRoles::HTextAlignment => QVariant::from(
&QString::from(&slide.htext_alignment),
),
SlideRoles::VTextAlignment => QVariant::from(
&QString::from(&slide.vtext_alignment),
),
SlideRoles::Font => {
QVariant::from(&QString::from(&slide.font))
} }
SlideRoles::VTextAlignment => {
QVariant::from(&QString::from(&slide.vtext_alignment))
}
SlideRoles::Font => QVariant::from(&QString::from(&slide.font)),
SlideRoles::FontSize => { SlideRoles::FontSize => {
QVariant::from(&slide.font_size) QVariant::from(&slide.font_size)
} }
@ -1147,9 +1180,9 @@ impl slide_model::SlideModel {
QVariant::from(&slide.selected) QVariant::from(&slide.selected)
} }
SlideRoles::Looping => QVariant::from(&slide.looping), SlideRoles::Looping => QVariant::from(&slide.looping),
SlideRoles::VideoThumbnail => { SlideRoles::VideoThumbnail => QVariant::from(
QVariant::from(&QString::from(&slide.video_thumbnail)) &QString::from(&slide.video_thumbnail),
} ),
SlideRoles::VideoStartTime => { SlideRoles::VideoStartTime => {
QVariant::from(&slide.video_start_time) QVariant::from(&slide.video_start_time)
} }
@ -1256,7 +1289,8 @@ impl slide_model::SlideModel {
fn extract_string(item: &QMap_QString_QVariant, key: &str) -> String { fn extract_string(item: &QMap_QString_QVariant, key: &str) -> String {
item.get(&QString::from(key)) item.get(&QString::from(key))
.unwrap_or(QVariant::from(&QString::default())) .unwrap_or(QVariant::from(&QString::default()))
.value_or_default::<QString>().to_string() .value_or_default::<QString>()
.to_string()
} }
fn extract_value(item: &QMap_QString_QVariant, key: &str) -> i32 { fn extract_value(item: &QMap_QString_QVariant, key: &str) -> i32 {
@ -1277,12 +1311,11 @@ fn extract_bool(item: &QMap_QString_QVariant, key: &str) -> bool {
.value_or_default::<bool>() .value_or_default::<bool>()
} }
#[cfg(test)] // #[cfg(test)]
mod test { // mod test {
// #[test]
#[test] // pub fn test_obs_setting_scene() {
pub fn test_obs_setting_scene() { // assert_eq!(true, true)
assert_eq!(true, true) // }
} // }
}

View file

@ -89,7 +89,8 @@ use cxx_qt_lib::{CaseSensitivity, QString, QVariant};
use tracing::{debug, error}; use tracing::{debug, error};
use crate::{ use crate::{
slide_model::{slide_model, Slide}, slide_types::SlideType slide_model::{slide_model, Slide},
slide_types::SlideType,
}; };
use self::slide_object::QMap_QString_QVariant; use self::slide_object::QMap_QString_QVariant;
@ -484,10 +485,18 @@ impl slide_object::SlideObject {
self.as_mut().set_text(QString::from(&slide.text)); self.as_mut().set_text(QString::from(&slide.text));
self.as_mut().set_ty(QString::from(&slide.ty.to_string())); self.as_mut().set_ty(QString::from(&slide.ty.to_string()));
self.as_mut().set_audio(QString::from(&slide.audio)); self.as_mut().set_audio(QString::from(&slide.audio));
self.as_mut().set_image_background(QString::from(&slide.image_background)); self.as_mut().set_image_background(QString::from(
self.as_mut().set_video_background(QString::from(&slide.video_background)); &slide.image_background,
self.as_mut().set_vtext_alignment(QString::from(&slide.vtext_alignment)); ));
self.as_mut().set_htext_alignment(QString::from(&slide.htext_alignment)); self.as_mut().set_video_background(QString::from(
&slide.video_background,
));
self.as_mut().set_vtext_alignment(QString::from(
&slide.vtext_alignment,
));
self.as_mut().set_htext_alignment(QString::from(
&slide.htext_alignment,
));
self.as_mut().set_font(QString::from(&slide.font)); self.as_mut().set_font(QString::from(&slide.font));
self.as_mut().set_font_size(slide.font_size); self.as_mut().set_font_size(slide.font_size);
self.as_mut().set_video_start_time(slide.video_start_time); self.as_mut().set_video_start_time(slide.video_start_time);

View file

@ -241,6 +241,7 @@ pub mod song_model {
} }
use crate::songs::song_editor::song_editor::QList_QString; use crate::songs::song_editor::song_editor::QList_QString;
use color_eyre::Result;
use cxx_qt::{CxxQtType, Threading}; use cxx_qt::{CxxQtType, Threading};
use cxx_qt_lib::{ use cxx_qt_lib::{
QByteArray, QModelIndex, QString, QStringList, QVariant, QByteArray, QModelIndex, QString, QStringList, QVariant,
@ -249,7 +250,6 @@ use sqlx::{query, query_as, Connection, SqliteConnection};
use std::collections::HashMap; use std::collections::HashMap;
use std::pin::Pin; use std::pin::Pin;
use tracing::{debug, error}; use tracing::{debug, error};
use color_eyre::Result;
use self::song_model::{ use self::song_model::{
QHash_i32_QByteArray, QMap_QString_QVariant, QVector_i32, QHash_i32_QByteArray, QMap_QString_QVariant, QVector_i32,
@ -288,90 +288,86 @@ impl Default for Song {
impl Song { impl Song {
pub fn get_lyric_list(&self) -> QList_QString { pub fn get_lyric_list(&self) -> QList_QString {
let mut lyric_list = QList_QString::default(); let mut lyric_list = QList_QString::default();
if self.lyrics.is_empty() { if self.lyrics.is_empty() {
return QList_QString::default(); return QList_QString::default();
} }
let raw_lyrics = self.lyrics.clone(); let raw_lyrics = self.lyrics.clone();
println!("raw-lyrics: {:?}", raw_lyrics); println!("raw-lyrics: {:?}", raw_lyrics);
let vorder: Vec<&str> = let vorder: Vec<&str> = self.verse_order.split(' ').collect();
self.verse_order.split(' ').collect(); let keywords = vec![
let keywords = vec![ "Verse 1", "Verse 2", "Verse 3", "Verse 4", "Verse 5",
"Verse 1", "Verse 2", "Verse 3", "Verse 4", "Verse 6", "Verse 7", "Verse 8", "Chorus 1", "Chorus 2",
"Verse 5", "Verse 6", "Verse 7", "Verse 8", "Chorus 3", "Chorus 4", "Bridge 1", "Bridge 2",
"Chorus 1", "Chorus 2", "Chorus 3", "Chorus 4", "Bridge 3", "Bridge 4", "Intro 1", "Intro 2", "Ending 1",
"Bridge 1", "Bridge 2", "Bridge 3", "Bridge 4", "Ending 2", "Other 1", "Other 2", "Other 3", "Other 4",
"Intro 1", "Intro 2", "Ending 1", "Ending 2", ];
"Other 1", "Other 2", "Other 3", "Other 4", let _first_item = true;
];
let _first_item = true;
let mut lyric_map = HashMap::new(); let mut lyric_map = HashMap::new();
let mut verse_title = String::from(""); let mut verse_title = String::from("");
let mut lyric = String::from(""); let mut lyric = String::from("");
for (i, line) in raw_lyrics.split('\n').enumerate() { for (i, line) in raw_lyrics.split('\n').enumerate() {
if keywords.contains(&line) { if keywords.contains(&line) {
if i != 0 { if i != 0 {
// println!("{verse_title}"); // println!("{verse_title}");
// println!("{lyric}"); // println!("{lyric}");
lyric_map.insert(verse_title, lyric); lyric_map.insert(verse_title, lyric);
lyric = String::from(""); lyric = String::from("");
verse_title = line.to_string(); verse_title = line.to_string();
// println!("{line}"); // println!("{line}");
// println!("\n"); // println!("\n");
} else {
verse_title = line.to_string();
// println!("{line}");
// println!("\n");
}
} else { } else {
lyric.push_str(line); verse_title = line.to_string();
lyric.push('\n'); // println!("{line}");
// println!("\n");
}
} else {
lyric.push_str(line);
lyric.push('\n');
}
}
lyric_map.insert(verse_title, lyric);
// println!("da-map: {:?}", lyric_map);
for verse in vorder {
let mut verse_name = "";
// debug!(verse = verse);
for word in keywords.clone() {
let end_verse = verse.get(1..2).unwrap_or_default();
let beg_verse = verse.get(0..1).unwrap_or_default();
// println!(
// "verse: {:?}, beginning: {:?}, end: {:?}, word: {:?}",
// verse, beg_verse, end_verse, word
// );
if word.starts_with(beg_verse)
&& word.ends_with(end_verse)
{
verse_name = word;
// println!("TITLE: {verse_name}");
continue;
} }
} }
lyric_map.insert(verse_title, lyric); if let Some(lyric) = lyric_map.get(verse_name) {
// println!("da-map: {:?}", lyric_map); if lyric.contains("\n\n") {
let split_lyrics: Vec<&str> =
for verse in vorder { lyric.split("\n\n").collect();
let mut verse_name = ""; for lyric in split_lyrics {
// debug!(verse = verse); if lyric.is_empty() {
for word in keywords.clone() { continue;
let end_verse =
verse.get(1..2).unwrap_or_default();
let beg_verse =
verse.get(0..1).unwrap_or_default();
// println!(
// "verse: {:?}, beginning: {:?}, end: {:?}, word: {:?}",
// verse, beg_verse, end_verse, word
// );
if word.starts_with(beg_verse)
&& word.ends_with(end_verse)
{
verse_name = word;
// println!("TITLE: {verse_name}");
continue;
}
}
if let Some(lyric) = lyric_map.get(verse_name) {
if lyric.contains("\n\n") {
let split_lyrics: Vec<&str> =
lyric.split("\n\n").collect();
for lyric in split_lyrics {
if lyric.is_empty() {
continue;
}
lyric_list.append(QString::from(lyric));
} }
continue; lyric_list.append(QString::from(lyric));
} }
lyric_list.append(QString::from(lyric)); continue;
} else { }
println!("NOT WORKING!"); lyric_list.append(QString::from(lyric));
}; } else {
} println!("NOT WORKING!");
for lyric in lyric_list.iter() { };
// println!("da-list: {:?}", lyric); }
debug!(lyric = ?lyric) for lyric in lyric_list.iter() {
} // println!("da-list: {:?}", lyric);
debug!(lyric = ?lyric)
}
lyric_list lyric_list
} }
} }
@ -400,9 +396,11 @@ impl Default for SongModelRust {
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
rt.block_on(async { rt.block_on(async {
SqliteConnection::connect(&db_url).await.expect("problems") SqliteConnection::connect(&db_url)
.await
.expect("problems")
}) })
} },
} }
} }
} }
@ -416,12 +414,14 @@ pub fn get_song(id: i32) -> Result<Song> {
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
rt.block_on(async { rt.block_on(async {
SqliteConnection::connect(&db_url).await.expect("problems") SqliteConnection::connect(&db_url)
.await
.expect("problems")
}) })
}; };
debug!("getting song with id: {id}"); debug!("getting song with id: {id}");
rt.block_on(async { rt.block_on(async {
let result = query_as!(Song, r#"SELECT vorder as "verse_order!", fontSize as "font_size!: i32", backgroundType as "background_type!", horizontalTextAlignment as "horizontal_text_alignment!", verticalTextAlignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs where id = ?"#, id).fetch_one(&mut db).await?; let result = query_as!(Song, r#"SELECT verse_order as "verse_order!", font_size as "font_size!: i32", background_type as "background_type!", horizontal_text_alignment as "horizontal_text_alignment!", vertical_text_alignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs where id = $1"#, id).fetch_one(&mut db).await?;
debug!(?result); debug!(?result);
Ok(result) Ok(result)
}) })
@ -440,7 +440,7 @@ impl song_model::SongModel {
static DATABASE_URL: &str = "sqlite:///home/chris/.local/share/lumina/library-db.sqlite3"; static DATABASE_URL: &str = "sqlite:///home/chris/.local/share/lumina/library-db.sqlite3";
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query_as!(Song, r#"SELECT vorder as "verse_order!", fontSize as "font_size!: i32", backgroundType as "background_type!", horizontalTextAlignment as "horizontal_text_alignment!", verticalTextAlignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs"#).fetch_all(&mut self.as_mut().rust_mut().db).await; let result = query_as!(Song, r#"SELECT verse_order as "verse_order!", font_size as "font_size!: i32", background_type as "background_type!", horizontal_text_alignment as "horizontal_text_alignment!", vertical_text_alignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs"#).fetch_all(&mut self.as_mut().rust_mut().db).await;
match result { match result {
Ok(s) => s.into_iter().for_each(|s| self.as_mut().add_song(s)), Ok(s) => s.into_iter().for_each(|s| self.as_mut().add_song(s)),
Err(e) => error!("There was an error in converting songs: {e}"), Err(e) => error!("There was an error in converting songs: {e}"),
@ -453,7 +453,13 @@ impl song_model::SongModel {
return false; return false;
} }
let song_id = self.as_mut().rust_mut().songs.get(index as usize).unwrap().id; let song_id = self
.as_mut()
.rust_mut()
.songs
.get(index as usize)
.unwrap()
.id;
let thread = self.qt_thread(); let thread = self.qt_thread();
let db = &mut self.as_mut().rust_mut().db; let db = &mut self.as_mut().rust_mut().db;
@ -504,7 +510,7 @@ impl song_model::SongModel {
}; };
rt.block_on(async { rt.block_on(async {
let result = query!(r#"INSERT into songs (vorder, fontSize, backgroundType, horizontalTextAlignment, verticalTextAlignment, title, font, background, lyrics, ccli, author, audio, id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"#, let result = query!(r#"INSERT into songs (verse_order, font_size, background_type, horizontal_text_alignment, vertical_text_alignment, title, font, background, lyrics, ccli, author, audio, id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"#,
song.verse_order, song.verse_order,
song.font_size, song.font_size,
song.background_type, song.background_type,
@ -758,9 +764,13 @@ impl song_model::SongModel {
let db_string = updated_ccli.clone().to_string(); let db_string = updated_ccli.clone().to_string();
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("UPDATE songs SET ccli = ? where id = ?", db_string, song_id) let result = query!(
.execute(&mut self.as_mut().rust_mut().db) "UPDATE songs SET ccli = ? where id = ?",
.await; db_string,
song_id
)
.execute(&mut self.as_mut().rust_mut().db)
.await;
match result { match result {
Ok(_i) => { Ok(_i) => {
@ -783,9 +793,11 @@ impl song_model::SongModel {
} }
} }
Err(e) => { Err(e) => {
error!("There was an error updating ccli in db: {e}"); error!(
"There was an error updating ccli in db: {e}"
);
false false
}, }
} }
}); });
true true
@ -802,7 +814,7 @@ impl song_model::SongModel {
let db_string = updated_verse_order.clone().to_string(); let db_string = updated_verse_order.clone().to_string();
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("UPDATE songs SET vorder = ? where id = ?", db_string, song_id) let result = query!("UPDATE songs SET verse_order = ? where id = ?", db_string, song_id)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
@ -891,7 +903,7 @@ impl song_model::SongModel {
let db_string = updated_background_type.clone().to_string(); let db_string = updated_background_type.clone().to_string();
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("UPDATE songs SET backgroundType = ? where id = ?", db_string, song_id) let result = query!("UPDATE songs SET background_type = ? where id = ?", db_string, song_id)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
@ -933,10 +945,11 @@ impl song_model::SongModel {
.as_mut() .as_mut()
.get_indices(song_id, SongRoles::HorizontalTextAlignment); .get_indices(song_id, SongRoles::HorizontalTextAlignment);
let db_string = updated_horizontal_text_alignment.clone().to_string(); let db_string =
updated_horizontal_text_alignment.clone().to_string();
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("UPDATE songs SET horizontalTextAlignment = ? where id = ?", db_string, song_id) let result = query!("UPDATE songs SET horizontal_text_alignment = ? where id = ?", db_string, song_id)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
@ -978,10 +991,11 @@ impl song_model::SongModel {
.as_mut() .as_mut()
.get_indices(song_id, SongRoles::VerticalTextAlignment); .get_indices(song_id, SongRoles::VerticalTextAlignment);
let db_string = updated_vertical_text_alignment.clone().to_string(); let db_string =
updated_vertical_text_alignment.clone().to_string();
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("UPDATE songs SET verticalTextAlignment = ? where id = ?", db_string, song_id) let result = query!("UPDATE songs SET vertical_text_alignment = ? where id = ?", db_string, song_id)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;
@ -1025,9 +1039,13 @@ impl song_model::SongModel {
let db_string = updated_font.clone().to_string(); let db_string = updated_font.clone().to_string();
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("UPDATE songs SET font = ? where id = ?", db_string, song_id) let result = query!(
.execute(&mut self.as_mut().rust_mut().db) "UPDATE songs SET font = ? where id = ?",
.await; db_string,
song_id
)
.execute(&mut self.as_mut().rust_mut().db)
.await;
match result { match result {
Ok(_i) => { Ok(_i) => {
@ -1050,9 +1068,11 @@ impl song_model::SongModel {
} }
} }
Err(e) => { Err(e) => {
error!("There was an error updating font in db: {e}"); error!(
"There was an error updating font in db: {e}"
);
false false
}, }
} }
}); });
true true
@ -1069,7 +1089,7 @@ impl song_model::SongModel {
let db_string = updated_font_size.clone().to_string(); let db_string = updated_font_size.clone().to_string();
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("UPDATE songs SET fontSize = ? where id = ?", db_string, song_id) let result = query!("UPDATE songs SET font_size = ? where id = ?", db_string, song_id)
.execute(&mut self.as_mut().rust_mut().db) .execute(&mut self.as_mut().rust_mut().db)
.await; .await;

View file

@ -178,6 +178,7 @@ pub mod video_model {
} }
} }
use color_eyre::eyre::Error;
use cxx_qt::{CxxQtType, Threading}; use cxx_qt::{CxxQtType, Threading};
use cxx_qt_lib::{QByteArray, QModelIndex, QString, QUrl, QVariant}; use cxx_qt_lib::{QByteArray, QModelIndex, QString, QUrl, QVariant};
use sqlx::{query, query_as, Connection, SqliteConnection}; use sqlx::{query, query_as, Connection, SqliteConnection};
@ -224,9 +225,11 @@ impl Default for VideoModelRust {
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
rt.block_on(async { rt.block_on(async {
SqliteConnection::connect(&db_url).await.expect("problems") SqliteConnection::connect(&db_url)
.await
.expect("problems")
}) })
} },
} }
} }
} }
@ -240,12 +243,20 @@ pub fn get_video(index: i32) -> color_eyre::Result<Video> {
let mut db_url = String::from("sqlite://"); let mut db_url = String::from("sqlite://");
db_url.push_str(data.to_str().unwrap()); db_url.push_str(data.to_str().unwrap());
rt.block_on(async { rt.block_on(async {
SqliteConnection::connect(&db_url).await.expect("problems") SqliteConnection::connect(&db_url)
.await
.expect("problems")
}) })
}; };
rt.block_on(async { rt.block_on(async {
let result = query_as!(Video, r#"SELECT id as "id: i32", title as "title!", filePath as "path!", startTime as "start_time!: f32", endTime as "end_time!: f32", loop as "looping!" from videos where id = ?"#, index).fetch_one(&mut db).await?; let result = query_as!(Video, r#"SELECT id as "id: i32", title as "title!", file_path as "path!", start_time as "start_time!: f32", end_time as "end_time!: f32", loop as "looping!" from videos where id = ?"#, index).fetch_one(&mut db).await;
Ok(result) match result {
Ok(v) => Ok(v),
Err(e) => {
error!(?e);
Err(color_eyre::Report::from(e))
},
}
}) })
} }
@ -261,7 +272,7 @@ impl video_model::VideoModel {
pub fn setup(mut self: Pin<&mut Self>) { pub fn setup(mut self: Pin<&mut Self>) {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query_as!(Video, r#"SELECT id as "id: i32", title as "title!", filePath as "path!", startTime as "start_time!: f32", endTime as "end_time!: f32", loop as "looping!" from videos"#).fetch_all(&mut self.as_mut().rust_mut().db).await; let result = query_as!(Video, r#"SELECT id as "id: i32", title as "title!", file_path as "path!", start_time as "start_time!: f32", end_time as "end_time!: f32", loop as "looping!" from videos"#).fetch_all(&mut self.as_mut().rust_mut().db).await;
match result { match result {
Ok(v) => v.into_iter().for_each(|v| self.as_mut().add_video(v)), Ok(v) => v.into_iter().for_each(|v| self.as_mut().add_video(v)),
Err(e) => error!("There was an error in converting songs: {e}"), Err(e) => error!("There was an error in converting songs: {e}"),
@ -277,7 +288,10 @@ impl video_model::VideoModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("delete from videos where id = ?", video_id).execute(&mut self.as_mut().rust_mut().db).await; let result =
query!("delete from videos where id = ?", video_id)
.execute(&mut self.as_mut().rust_mut().db)
.await;
match result { match result {
Ok(_i) => { Ok(_i) => {
unsafe { unsafe {
@ -334,7 +348,7 @@ impl video_model::VideoModel {
rt.block_on(async { rt.block_on(async {
let video_title = video_title.to_string(); let video_title = video_title.to_string();
let video_path = video_path.to_string(); let video_path = video_path.to_string();
let result = query!(r#"INSERT into videos (id, title, filePath, startTime, endTime, loop) VALUES (?, ?, ?, ?, ?, ?)"#, let result = query!(r#"INSERT into videos (id, title, file_path, start_time, end_time, loop) VALUES (?, ?, ?, ?, ?, ?)"#,
video_id, video_id,
video_title, video_title,
video_path, video_path,
@ -435,9 +449,13 @@ impl video_model::VideoModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("UPDATE videos SET loop = ? where id = ?", loop_value, index) let result = query!(
.execute(&mut self.as_mut().rust_mut().db) "UPDATE videos SET loop = ? where id = ?",
.await; loop_value,
index
)
.execute(&mut self.as_mut().rust_mut().db)
.await;
match result { match result {
Ok(_i) => { Ok(_i) => {
for video in self for video in self
@ -448,9 +466,11 @@ impl video_model::VideoModel {
.filter(|x| x.id == index) .filter(|x| x.id == index)
{ {
video.looping = loop_value; video.looping = loop_value;
debug!(title = video.title, debug!(
looping = loop_value, title = video.title,
"updated video loop"); looping = loop_value,
"updated video loop"
);
} }
self.as_mut().data_changed( self.as_mut().data_changed(
model_index, model_index,
@ -462,7 +482,7 @@ impl video_model::VideoModel {
Err(e) => { Err(e) => {
error!("Error connecting to db: {e}"); error!("Error connecting to db: {e}");
false false
}, }
} }
}); });
true true
@ -481,9 +501,13 @@ impl video_model::VideoModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("UPDATE videos SET endTime = ? where id = ?", updated_end_time, index) let result = query!(
.execute(&mut self.as_mut().rust_mut().db) "UPDATE videos SET end_time = ? where id = ?",
.await; updated_end_time,
index
)
.execute(&mut self.as_mut().rust_mut().db)
.await;
match result { match result {
Ok(_i) => { Ok(_i) => {
for video in self for video in self
@ -494,9 +518,11 @@ impl video_model::VideoModel {
.filter(|x| x.id == index) .filter(|x| x.id == index)
{ {
video.end_time = updated_end_time; video.end_time = updated_end_time;
debug!(title = video.title, debug!(
end_time = updated_end_time, title = video.title,
"updated video end_time"); end_time = updated_end_time,
"updated video end_time"
);
} }
self.as_mut().data_changed( self.as_mut().data_changed(
model_index, model_index,
@ -508,7 +534,7 @@ impl video_model::VideoModel {
Err(e) => { Err(e) => {
error!("Error connecting to db: {e}"); error!("Error connecting to db: {e}");
false false
}, }
} }
}); });
true true
@ -527,9 +553,13 @@ impl video_model::VideoModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let result = query!("UPDATE videos SET startTime = ? where id = ?", updated_start_time, index) let result = query!(
.execute(&mut self.as_mut().rust_mut().db) "UPDATE videos SET start_time = ? where id = ?",
.await; updated_start_time,
index
)
.execute(&mut self.as_mut().rust_mut().db)
.await;
match result { match result {
Ok(_i) => { Ok(_i) => {
for video in self for video in self
@ -540,9 +570,11 @@ impl video_model::VideoModel {
.filter(|x| x.id == index) .filter(|x| x.id == index)
{ {
video.start_time = updated_start_time; video.start_time = updated_start_time;
debug!(title = video.title, debug!(
start_time = updated_start_time, title = video.title,
"updated video start_time"); start_time = updated_start_time,
"updated video start_time"
);
} }
self.as_mut().data_changed( self.as_mut().data_changed(
model_index, model_index,
@ -554,7 +586,7 @@ impl video_model::VideoModel {
Err(e) => { Err(e) => {
error!("Error connecting to db: {e}"); error!("Error connecting to db: {e}");
false false
}, }
} }
}); });
true true
@ -574,9 +606,13 @@ impl video_model::VideoModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let title = updated_title.to_string(); let title = updated_title.to_string();
let result = query!("UPDATE videos SET title = ? where id = ?", title, index) let result = query!(
.execute(&mut self.as_mut().rust_mut().db) "UPDATE videos SET title = ? where id = ?",
.await; title,
index
)
.execute(&mut self.as_mut().rust_mut().db)
.await;
match result { match result {
Ok(_i) => { Ok(_i) => {
for video in self for video in self
@ -587,9 +623,11 @@ impl video_model::VideoModel {
.filter(|x| x.id == index) .filter(|x| x.id == index)
{ {
video.title = title.clone(); video.title = title.clone();
debug!(title = video.title, debug!(
title = title, title = video.title,
"updated video title"); title = title,
"updated video title"
);
} }
self.as_mut().data_changed( self.as_mut().data_changed(
model_index, model_index,
@ -601,7 +639,7 @@ impl video_model::VideoModel {
Err(e) => { Err(e) => {
error!("Error connecting to db: {e}"); error!("Error connecting to db: {e}");
false false
}, }
} }
}); });
true true
@ -620,9 +658,13 @@ impl video_model::VideoModel {
let rt = tokio::runtime::Runtime::new().unwrap(); let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async { rt.block_on(async {
let updated_path = updated_path.to_string(); let updated_path = updated_path.to_string();
let result = query!("UPDATE videos SET filePath = ? where id = ?", updated_path, index) let result = query!(
.execute(&mut self.as_mut().rust_mut().db) "UPDATE videos SET file_path = ? where id = ?",
.await; updated_path,
index
)
.execute(&mut self.as_mut().rust_mut().db)
.await;
match result { match result {
Ok(_i) => { Ok(_i) => {
for video in self for video in self
@ -633,9 +675,11 @@ impl video_model::VideoModel {
.filter(|x| x.id == index) .filter(|x| x.id == index)
{ {
video.path = updated_path.clone(); video.path = updated_path.clone();
debug!(title = video.title, debug!(
path = updated_path, title = video.title,
"updated video path"); path = updated_path,
"updated video path"
);
} }
self.as_mut().data_changed( self.as_mut().data_changed(
model_index, model_index,
@ -647,7 +691,7 @@ impl video_model::VideoModel {
Err(e) => { Err(e) => {
error!("Error connecting to db: {e}"); error!("Error connecting to db: {e}");
false false
}, }
} }
}); });
true true

View file

@ -67,14 +67,10 @@ impl ytdl::Ytdl {
.run() .run()
.unwrap(); .unwrap();
let output = ytdl.into_single_video().unwrap(); let output = ytdl.into_single_video().unwrap();
debug!( debug!(output.title, output.thumbnail, output.url);
output.title,
output.thumbnail, output.url
);
let title = QString::from(&output.title); let title = QString::from(&output.title);
let thumbnail = QUrl::from( let thumbnail =
&output.thumbnail.unwrap_or_default(), QUrl::from(&output.thumbnail.unwrap_or_default());
);
let mut file = String::from(output_dirs); let mut file = String::from(output_dirs);
file.push('/'); file.push('/');
file.push_str(&output.title); file.push_str(&output.title);
@ -86,12 +82,8 @@ impl ytdl::Ytdl {
qobject_ytdl.as_mut().set_loaded(true); qobject_ytdl.as_mut().set_loaded(true);
qobject_ytdl.as_mut().set_loading(false); qobject_ytdl.as_mut().set_loading(false);
qobject_ytdl.as_mut().set_title(title); qobject_ytdl.as_mut().set_title(title);
qobject_ytdl qobject_ytdl.as_mut().set_thumbnail(thumbnail);
.as_mut() qobject_ytdl.as_mut().set_file(QUrl::from(&file));
.set_thumbnail(thumbnail);
qobject_ytdl
.as_mut()
.set_file(QUrl::from(&file));
}) })
}); });
true true