Add generation for video pages.
This commit is contained in:
parent
235064a0ae
commit
eb21f1b777
|
@ -8,6 +8,7 @@ use color_eyre::{install, Result};
|
|||
mod copy;
|
||||
mod scss;
|
||||
mod templates;
|
||||
mod video;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
install()?;
|
||||
|
@ -20,6 +21,7 @@ fn main() -> Result<()> {
|
|||
templates::Index::write(&public_dir)?;
|
||||
scss::Scss::write(&public_dir, &source_dir)?;
|
||||
copy::Copy::write(&build_dir, &public_dir, &source_dir)?;
|
||||
video::write_all(&public_dir)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ impl Scss {
|
|||
create_dir_all(&css_dir)?;
|
||||
|
||||
let scss_dir = source_dir.join("scss");
|
||||
let scss_filenames = vec!["index", "modern-normalize"];
|
||||
let scss_filenames = vec!["index", "modern-normalize", "video"];
|
||||
|
||||
let format = Format {
|
||||
precision: 5,
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
@use "mixins";
|
||||
@use "reset";
|
||||
|
||||
body {
|
||||
// Colors.
|
||||
--foreground: #f1ebff;
|
||||
--background: #1f003e;
|
||||
--anchor: #89c3ff;
|
||||
|
||||
// Spacing constants.
|
||||
--spacing-small: 4px;
|
||||
--spacing-medium: 8px;
|
||||
--spacing-large: 16px;
|
||||
|
||||
background-color: var(--background);
|
||||
color: var(--foreground);
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--anchor);
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
iframe,
|
||||
h2 {
|
||||
margin-top: var(--spacing-large);
|
||||
}
|
||||
|
||||
iframe {
|
||||
aspect-ratio: 16 / 9;
|
||||
border: 2px dashed;
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin-bottom: var(--spacing-large);
|
||||
max-width: 1280px;
|
||||
padding: var(--spacing-medium);
|
||||
}
|
||||
|
||||
.page-header {
|
||||
border-bottom: 2px dashed;
|
||||
padding: var(--spacing-large);
|
||||
|
||||
h1 {
|
||||
@include mixins.responsive-container;
|
||||
}
|
||||
}
|
||||
|
||||
.page-main {
|
||||
@include mixins.responsive-container;
|
||||
}
|
||||
|
||||
.timestamp-link {
|
||||
font-family: monospace;
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block head %}
|
||||
<link rel="stylesheet" href="/css/video.css">
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<header class="page-header">
|
||||
<h1>{{ page_title }}</h1>
|
||||
</header>
|
||||
|
||||
<main class="page-main">
|
||||
{{ rendered_markdown|safe }}
|
||||
|
||||
{% if let Some(speedrun) = speedrun %}
|
||||
<h2>Speedrun</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="{{ speedrun.entry }}" target="_blank">Entry</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ speedrun.leaderboard }}" target="_blank">Leaderboard</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{% if let Some(mods) = speedrun.mods %}
|
||||
<h2>Mods</h2>
|
||||
<ul>
|
||||
{% for (name, id) in mods %}
|
||||
<li>
|
||||
<a href="https://drg.mod.io/{{ id }}" target="_blank">{{ name }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{% if let Some(chapters) = speedrun.chapters %}
|
||||
<h2>Chapters</h2>
|
||||
<ul>
|
||||
{% for (timestamp, text) in chapters %}
|
||||
<li>
|
||||
<p>
|
||||
<a
|
||||
class="timestamp-link"
|
||||
href="https://youtu.be/{{ video_id }}?t={{ timestamp|timestamp_to_seconds }}"
|
||||
target="_blank"
|
||||
>{{ timestamp }}</a>
|
||||
{{ text }}
|
||||
</p>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/{{ video_id }}"
|
||||
title="Embedded YouTube video player"
|
||||
frameborder="0"
|
||||
allowfullscreen>
|
||||
</iframe>
|
||||
{% endif %}
|
||||
|
||||
</main>
|
||||
{% endblock %}
|
|
@ -0,0 +1,19 @@
|
|||
/*!
|
||||
Filters for Askama templates.
|
||||
*/
|
||||
|
||||
/**
|
||||
Turn a timestamp with format `mm:ss` into its total seconds.
|
||||
|
||||
## Examples
|
||||
|
||||
- `00:30` -> 30 seconds
|
||||
- `01:00` -> 60 seconds
|
||||
- `01:30` -> 90 seconds
|
||||
*/
|
||||
pub fn timestamp_to_seconds(timestamp: &str) -> askama::Result<i32> {
|
||||
let mut split = timestamp.split(":");
|
||||
let minutes = split.next().map(str::parse::<i32>).unwrap().unwrap();
|
||||
let seconds = split.next().map(str::parse::<i32>).unwrap().unwrap();
|
||||
Ok(minutes * 60 + seconds)
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
use std::{fs, path::Path};
|
||||
|
||||
use {askama::Template, color_eyre::Result, serde::Deserialize};
|
||||
|
||||
mod filters;
|
||||
|
||||
#[derive(Debug, Template)]
|
||||
#[template(path = "video.html")]
|
||||
pub struct VideoTemplate {
|
||||
pub page_title: String,
|
||||
pub rendered_markdown: String,
|
||||
pub speedrun: Option<SpeedrunData>,
|
||||
pub video_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct VideoData {
|
||||
pub id: String,
|
||||
pub page_title: String,
|
||||
pub speedrun: Option<SpeedrunData>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct SpeedrunData {
|
||||
pub chapters: Option<Vec<(String, String)>>,
|
||||
pub entry: String,
|
||||
pub leaderboard: String,
|
||||
pub mods: Option<Vec<(String, String)>>,
|
||||
}
|
||||
|
||||
pub fn write_all(public_dir: &Path) -> Result<()> {
|
||||
let video_datas = {
|
||||
let mut data = vec![];
|
||||
|
||||
for dir in ["2022"] {
|
||||
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) =
|
||||
toml_frontmatter::parse::<VideoData>(&file_contents).unwrap();
|
||||
data.push((video_data, markdown.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
data
|
||||
};
|
||||
|
||||
for (video_data, markdown) in video_datas {
|
||||
let video_dir = public_dir.join("v").join(&video_data.id);
|
||||
fs::create_dir_all(&video_dir)?;
|
||||
|
||||
let template = VideoTemplate {
|
||||
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"), template.render()?)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue