adding pdf rendering
Some checks are pending
/ test (push) Waiting to run

This commit is contained in:
Chris Cochrun 2025-09-15 09:29:27 -05:00
parent 6532666c56
commit ad14135ddf
6 changed files with 177 additions and 78 deletions

View file

@ -1,12 +1,13 @@
use crisp::types::{Keyword, Symbol, Value};
use miette::{IntoDiagnostic, Result};
use mupdf::{Document, Page};
use serde::{Deserialize, Serialize};
use sqlx::{
pool::PoolConnection, prelude::FromRow, query, sqlite::SqliteRow,
Row, Sqlite, SqliteConnection, SqlitePool,
};
use std::path::PathBuf;
use tracing::error;
use std::{path::PathBuf, sync::Arc};
use tracing::{debug, error};
use crate::{Background, Slide, SlideBuilder, TextAlignment};
@ -27,9 +28,7 @@ pub enum PresKind {
Generic,
}
#[derive(
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize,
)]
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Presentation {
pub id: i32,
pub title: String,
@ -37,6 +36,17 @@ pub struct Presentation {
pub kind: PresKind,
}
impl Eq for Presentation {}
impl PartialEq for Presentation {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
&& self.title == other.title
&& self.path == other.path
&& self.kind == other.kind
}
}
impl From<&Presentation> for Value {
fn from(value: &Presentation) -> Self {
Self::List(vec![Self::Symbol(Symbol("presentation".into()))])
@ -117,22 +127,36 @@ impl ServiceTrait for Presentation {
}
fn to_slides(&self) -> Result<Vec<Slide>> {
let slide = SlideBuilder::new()
.background(
Background::try_from(self.path.clone())
.into_diagnostic()?,
)
.text("")
.audio("")
.font("")
.font_size(50)
.text_alignment(TextAlignment::MiddleCenter)
.video_loop(false)
.video_start_time(0.0)
.video_end_time(0.0)
.build()?;
Ok(vec![slide])
debug!(?self);
let background = Background::try_from(self.path.clone())
.into_diagnostic()?;
debug!(?background);
let doc = Document::open(background.path.as_path())
.into_diagnostic()?;
debug!(?doc);
let pages = doc.page_count().into_diagnostic()?;
debug!(?pages);
let mut slides: Vec<Slide> = vec![];
for page in 0..pages {
let slide = SlideBuilder::new()
.background(
Background::try_from(self.path.clone())
.into_diagnostic()?,
)
.text("")
.audio("")
.font("")
.font_size(50)
.text_alignment(TextAlignment::MiddleCenter)
.video_loop(false)
.video_start_time(0.0)
.video_end_time(0.0)
.pdf_index(page as u32)
.build()?;
slides.push(slide);
}
debug!(?slides);
Ok(slides)
}
fn box_clone(&self) -> Box<dyn ServiceTrait> {

View file

@ -318,8 +318,8 @@ impl From<&Image> for ServiceItem {
impl From<&Presentation> for ServiceItem {
fn from(presentation: &Presentation) -> Self {
if let Ok(slides) = presentation.to_slides() {
Self {
match presentation.to_slides() {
Ok(slides) => Self {
kind: ServiceItemKind::Presentation(
presentation.clone(),
),
@ -327,15 +327,17 @@ impl From<&Presentation> for ServiceItem {
title: presentation.title.clone(),
slides: slides.into(),
..Default::default()
}
} else {
Self {
kind: ServiceItemKind::Presentation(
presentation.clone(),
),
database_id: presentation.id,
title: presentation.title.clone(),
..Default::default()
},
Err(e) => {
error!(?e);
Self {
kind: ServiceItemKind::Presentation(
presentation.clone(),
),
database_id: presentation.id,
title: presentation.title.clone(),
..Default::default()
}
}
}
}

View file

@ -11,7 +11,10 @@ use std::{
};
use tracing::error;
use crate::ui::text_svg::{self, TextSvg};
use crate::ui::{
pdf::PdfViewer,
text_svg::{self, TextSvg},
};
use super::songs::Song;
@ -29,6 +32,7 @@ pub struct Slide {
video_loop: bool,
video_start_time: f32,
video_end_time: f32,
pdf_index: u32,
#[serde(skip)]
pub text_svg: Option<TextSvg>,
}
@ -40,6 +44,8 @@ pub enum BackgroundKind {
#[default]
Image,
Video,
Pdf,
Html,
}
#[derive(Debug, Clone, Default)]
@ -157,16 +163,22 @@ impl TryFrom<PathBuf> for Background {
.to_str()
.unwrap_or_default();
match extension {
"jpeg" | "jpg" | "png" | "webp" | "html" => {
Ok(Self {
path: value,
kind: BackgroundKind::Image,
})
}
"jpeg" | "jpg" | "png" | "webp" => Ok(Self {
path: value,
kind: BackgroundKind::Image,
}),
"mp4" | "mkv" | "webm" => Ok(Self {
path: value,
kind: BackgroundKind::Video,
}),
"pdf" => Ok(Self {
path: value,
kind: BackgroundKind::Pdf,
}),
"html" => Ok(Self {
path: value,
kind: BackgroundKind::Html,
}),
_ => Err(ParseError::NonBackgroundFile),
}
}
@ -281,6 +293,11 @@ impl Slide {
self
}
pub fn set_pdf_index(mut self, pdf_index: u32) -> Self {
self.pdf_index = pdf_index;
self
}
pub fn background(&self) -> &Background {
&self.background
}
@ -309,6 +326,10 @@ impl Slide {
self.audio.clone()
}
pub fn pdf_index(&self) -> u32 {
self.pdf_index
}
pub fn song_slides(song: &Song) -> Result<Vec<Self>> {
let lyrics = song.get_lyrics()?;
let slides: Vec<Slide> = lyrics
@ -524,6 +545,7 @@ pub struct SlideBuilder {
video_loop: Option<bool>,
video_start_time: Option<f32>,
video_end_time: Option<f32>,
pdf_index: Option<u32>,
#[serde(skip)]
text_svg: Option<TextSvg>,
}
@ -607,6 +629,14 @@ impl SlideBuilder {
self
}
pub(crate) fn pdf_index(
mut self,
pdf_index: impl Into<u32>,
) -> Self {
let _ = self.pdf_index.insert(pdf_index.into());
self
}
pub(crate) fn build(self) -> Result<Slide> {
let Some(background) = self.background else {
return Err(miette!("No background"));
@ -643,6 +673,7 @@ impl SlideBuilder {
video_start_time,
video_end_time,
text_svg: self.text_svg,
pdf_index: self.pdf_index.unwrap_or_default(),
..Default::default()
})
}