1
Fork 0
bauke-xyz/source/video/mod.rs

139 lines
3.3 KiB
Rust

//! Templates, data structures and logic for the video pages.
use std::{fs, path::Path};
use {
askama::Template,
color_eyre::{eyre::eyre, Result},
serde::Deserialize,
};
mod filters;
/// The template for videos.
#[derive(Debug, Template)]
#[template(path = "video.html")]
pub struct VideoTemplate {
/// Deep Rock Galactic data.
pub drg: Option<DeepRockGalacticData>,
/// The title of the page.
pub page_title: String,
/// Markdown rendered by [`comrak`].
pub rendered_markdown: String,
/// Data for a speedrun video.
pub speedrun: Option<SpeedrunData>,
/// The YouTube video ID.
pub video_id: String,
}
/// The frontmatter data for a video.
#[derive(Debug, Deserialize)]
pub struct VideoData {
/// Deep Rock Galactic data.
pub drg: Option<DeepRockGalacticData>,
/// The YouTube video ID.
pub id: String,
/// The title of the page.
pub page_title: String,
/// Data for a speedrun video.
pub speedrun: Option<SpeedrunData>,
/// Tags for the video.
#[serde(default)]
pub tags: Vec<String>,
}
/// Data for speedrun videos.
#[derive(Debug, Deserialize)]
pub struct SpeedrunData {
/// Video chapters as with timestamps and chapter titles.
pub chapters: Option<Vec<(String, String)>>,
/// A link to the entry for this specific speedrun.
pub entry: String,
/// A link to the leaderboard for this speedrun's category.
pub leaderboard: String,
/// Deep Rock Galactic mods used in the run.
pub mods: Option<Vec<String>>,
}
/// Additional data for Deep Rock Galactic videos.
#[derive(Debug, Deserialize)]
pub struct DeepRockGalacticData {
/// Deep Rock Galactic mods used in the run.
pub mods: Option<Vec<String>>,
}
/// Compile and write all the found videos to their respective locations.
pub fn write_all(public_dir: &Path) -> Result<()> {
let video_datas = {
let mut data = vec![];
for dir in ["2022", "2023"] {
for file in fs::read_dir(format!("source/video/{dir}"))? {
let file_path = file?.path();
if file_path.extension().unwrap() != "md" {
continue;
}
let file_contents = fs::read_to_string(&file_path)?;
let (video_data, markdown) =
match toml_frontmatter::parse::<VideoData>(&file_contents) {
Ok(parsed) => parsed,
Err(error) => {
println!("{:?} {}", file_path.file_name().unwrap(), error);
continue;
}
};
data.push((video_data, markdown.to_string()));
}
}
data
};
let video_dir = public_dir.join("v");
let expected_video_count = video_datas.len();
for (video_data, markdown) in video_datas {
let video_dir = video_dir.join(&video_data.id.to_lowercase());
fs::create_dir_all(&video_dir)?;
let template = VideoTemplate {
drg: video_data.drg,
page_title: video_data.page_title,
rendered_markdown: comrak::markdown_to_html(
&markdown,
&Default::default(),
),
speedrun: video_data.speedrun,
video_id: video_data.id,
};
fs::write(
video_dir.join("index.html"),
crate::minify::html(template.render()?)?,
)?;
}
let actual_video_count = fs::read_dir(video_dir)?.count();
if expected_video_count != actual_video_count {
return Err(eyre!(
"Expected {} videos, found {}",
expected_video_count,
actual_video_count
));
}
Ok(())
}