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