diff --git a/src/build.rs b/src/build.rs index 9a13529..daf78c2 100644 --- a/src/build.rs +++ b/src/build.rs @@ -29,16 +29,11 @@ pub(crate) fn build_content( pending: &[&Output], hole: &[&Output], hash: Option>, -) -> HashMap { +) { let now = std::time::Instant::now(); - let hashes = render_all(ctx, pending, hole, hash); + render_all(ctx, pending, hole, hash); println!("Elapsed: {:.2?}", now.elapsed()); copy_recursively(Path::new(".hash"), Path::new("dist/hash")).unwrap(); - let mut lmao = HashMap::::new(); - for hash in hashes { - lmao.insert(hash.file, hash.hash); - } - lmao } pub(crate) fn build_static() { @@ -89,10 +84,10 @@ fn render_all( pending: &[&Output], hole: &[&Output], hash: Option>, -) -> Vec { +) { pending .iter() - .filter_map(|item| { + .map(|item| { let file = match &item.kind { OutputKind::Asset(a) => Some(&a.meta.path), OutputKind::Virtual(_) => None, @@ -112,17 +107,20 @@ fn render_all( .collect() } -fn store_hash_png(data: &[u8]) -> Utf8PathBuf { +fn store_hash(buffer: &[u8]) -> Utf8PathBuf { let store = Utf8Path::new(".hash"); - let ident = sha256::digest(data); - let store_hash = store.join(&ident).with_extension("webp"); + let hash = sha256::digest(buffer); + let img = image::load_from_memory(buffer).expect("Couldn't load image"); + let store_hash = store.join(&hash).with_extension("webp"); if !store_hash.exists() { - let img = image::load_from_memory(data).expect("Couldn't load image"); let dim = (img.width(), img.height()); let mut out = Vec::new(); let encoder = image::codecs::webp::WebPEncoder::new_lossless(&mut out); - encoder.encode(&img.to_rgba8(), dim.0, dim.1, image::ColorType::Rgba8).expect("Encoding error"); + + encoder + .encode(&img.to_rgba8(), dim.0, dim.1, image::ColorType::Rgba8) + .expect("Encoding error"); fs::create_dir_all(store).unwrap(); fs::write(store_hash, out).expect("Couldn't output optimized image"); @@ -130,17 +128,45 @@ fn store_hash_png(data: &[u8]) -> Utf8PathBuf { Utf8Path::new("/") .join("hash") - .join(ident) + .join(hash) .with_extension("webp") } +pub(crate) fn store_hash_all(items: &[&Output]) -> Vec { + items + .iter() + .filter_map(|item| match item.kind { + OutputKind::Asset(ref asset) => match asset.kind { + AssetKind::Image => { + let buffer = std::fs::read(&asset.meta.path).expect("Couldn't read file"); + let format = image::guess_format(&buffer).expect("Couldn't read format"); + + if matches!(format, image::ImageFormat::Gif) { + return None; + } + + let hash = store_hash(&buffer); + println!("Hashing image {} as {}", asset.meta.path, hash); + + Some(Hashed { + file: item.path.to_owned(), + hash, + }) + } + _ => None, + }, + _ => None, + }) + .collect() +} + #[derive(Debug)] pub(crate) struct Hashed { pub file: Utf8PathBuf, pub hash: Utf8PathBuf, } -fn render(item: &Output, sack: Sack) -> Option { +fn render(item: &Output, sack: Sack) { let dist = Utf8Path::new("dist"); let o = dist.join(&item.path); fs::create_dir_all(o.parent().unwrap()).unwrap(); @@ -154,24 +180,12 @@ fn render(item: &Output, sack: Sack) -> Option { let mut file = File::create(&o).unwrap(); file.write_all(closure(&sack).as_bytes()).unwrap(); println!("HTML: {} -> {}", i, o); - None } - AssetKind::Bibtex(_) => None, + AssetKind::Bibtex(_) => (), AssetKind::Image => { - let hash = match item.path.extension() { - Some("png") => Some(store_hash_png(&std::fs::read(i).unwrap())), - Some("") => None, - _ => None, - }; - fs::create_dir_all(o.parent().unwrap()).unwrap(); fs::copy(i, &o).unwrap(); println!("Image: {} -> {}", i, o); - - hash.map(|hash| Hashed { - file: item.path.to_owned(), - hash, - }) } } } @@ -179,7 +193,6 @@ fn render(item: &Output, sack: Sack) -> Option { let mut file = File::create(&o).unwrap(); file.write_all(closure(&sack).as_bytes()).unwrap(); println!("Virtual: -> {}", o); - None } } } diff --git a/src/main.rs b/src/main.rs index 6243c14..ae187f5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,13 +10,14 @@ use std::collections::{HashMap, HashSet}; use std::fs; use std::process::Command; +use build::Hashed; use camino::{Utf8Path, Utf8PathBuf}; use chrono::{DateTime, Datelike, Utc}; use clap::{Parser, ValueEnum}; use gray_matter::engine::YAML; use gray_matter::Matter; use hypertext::{Raw, Renderable}; -use pipeline::{Asset, AssetKind, Content, FileItemKind, Output, PipelineItem}; +use pipeline::{Asset, AssetKind, Content, FileItemKind, Output, OutputKind, PipelineItem}; use serde::Deserialize; use crate::pipeline::Virtual; @@ -201,23 +202,33 @@ impl Source { fn build(ctx: &BuildContext, sources: &[Source], special: Vec) -> Vec { crate::build::clean_dist(); - let sources: Vec<_> = sources + let content: Vec = sources .iter() .flat_map(Source::get) .map(to_bundle) .filter_map(Option::from) .collect(); - let assets: Vec<_> = sources.iter().chain(special.iter()).collect(); + let images: Vec<&Output> = content + .iter() + .filter(|&e| match e.kind { + OutputKind::Asset(ref a) => matches!(a.kind, AssetKind::Image), + _ => false, + }) + .collect(); - let lmao = crate::build::build_content(ctx, &assets, &assets, None); - crate::build::build_content(ctx, &assets, &assets, Some(lmao)); + let hashes = crate::build::store_hash_all(&images); + let hashes = HashMap::from_iter(hashes.into_iter().map(|Hashed { file, hash } | (file, hash))); + + let assets: Vec<_> = content.iter().chain(special.iter()).collect(); + + crate::build::build_content(ctx, &assets, &assets, Some(hashes)); crate::build::build_static(); crate::build::build_styles(); crate::build::build_pagefind(); crate::build::build_js(); - sources.into_iter().chain(special).collect() + content.into_iter().chain(special).collect() } pub fn parse_frontmatter(raw: &str) -> (D, String) @@ -265,7 +276,10 @@ where parsed.clone(), lib, dir.clone(), - sack.hash.as_ref().map(ToOwned::to_owned).unwrap_or_default(), + sack.hash + .as_ref() + .map(ToOwned::to_owned) + .unwrap_or_default(), ); T::render(matter.clone(), sack, Raw(parsed), outline, bib) .render() diff --git a/src/text/md.rs b/src/text/md.rs index 6d1b8bc..68d1594 100644 --- a/src/text/md.rs +++ b/src/text/md.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use camino::{Utf8Path, Utf8PathBuf}; +use camino::Utf8PathBuf; use hayagriva::{ archive::ArchivedStyle, citationberg::{IndependentStyle, Locale, Style}, diff --git a/src/watch.rs b/src/watch.rs index a356141..775f52d 100644 --- a/src/watch.rs +++ b/src/watch.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::env; use std::io::Result; use std::net::{TcpListener, TcpStream}; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::rc::Rc; use std::sync::mpsc::Sender; use std::sync::{Arc, Mutex};