avoid rebuilding unchanged image files
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::io::Write;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
|
||||
// file-stored hash map used to prevent needless image regenerating
|
||||
#[derive(Debug)]
|
||||
pub struct HashDict {
|
||||
hashes: HashMap<String, String>,
|
||||
path: PathBuf,
|
||||
any_change: bool,
|
||||
}
|
||||
|
||||
impl HashDict {
|
||||
pub fn load(path: PathBuf) -> Result<HashDict, io::Error> {
|
||||
let mut hd = HashDict {
|
||||
hashes: HashMap::new(),
|
||||
path,
|
||||
any_change: false,
|
||||
};
|
||||
|
||||
if !hd.path.exists() {
|
||||
return Ok(hd);
|
||||
}
|
||||
|
||||
let mut f = File::open(&hd.path)?;
|
||||
let mut s = String::new();
|
||||
f.read_to_string(&mut s)?;
|
||||
|
||||
let lines: Vec<&str> = s.split("\n").collect();
|
||||
for l in lines {
|
||||
let halves: Vec<&str> = l.split("\t").collect();
|
||||
if halves.len() == 2 {
|
||||
hd.hashes.insert(halves[0].to_string(), halves[1].to_string());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(hd)
|
||||
}
|
||||
|
||||
pub fn get(&self, key : &str) -> Option<&String> {
|
||||
self.hashes.get(key)
|
||||
}
|
||||
|
||||
pub fn put(&mut self, key : String, value: String) {
|
||||
self.hashes.insert(key, value);
|
||||
self.any_change = true;
|
||||
}
|
||||
|
||||
pub fn save(&mut self) {
|
||||
if self.any_change || !self.path.exists() {
|
||||
let mut f = File::create(&self.path).unwrap();
|
||||
let mut buf = String::new();
|
||||
for (k, v) in &self.hashes {
|
||||
buf.push_str(&format!("{}\t{}\n", k, v));
|
||||
}
|
||||
f.write(buf.as_ref()).unwrap();
|
||||
|
||||
self.any_change = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+40
-10
@@ -1,4 +1,5 @@
|
||||
use std::env;
|
||||
use std::io;
|
||||
use std::fs;
|
||||
use std::fs::DirEntry;
|
||||
use std::fs::File;
|
||||
@@ -14,6 +15,11 @@ use image_utils;
|
||||
use chrono::offset::TimeZone;
|
||||
use chrono::Date;
|
||||
use chrono::Utc;
|
||||
use blake2::{Digest,Blake2b};
|
||||
|
||||
use base64;
|
||||
|
||||
mod hash_dict;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Bread {
|
||||
@@ -119,11 +125,15 @@ fn main() {
|
||||
|
||||
let mut channel_items = Vec::<Item>::new();
|
||||
|
||||
let mut hashes = hash_dict::HashDict::load(cwd.join(".hashes.txt")).unwrap();
|
||||
|
||||
for bread in &breads {
|
||||
let date = bread.date.format("%Y/%m/%d").to_string();
|
||||
let date_slug = bread.date.format("%Y-%m-%d").to_string();
|
||||
let detail_file = date_slug.clone() + ".html";
|
||||
|
||||
println!("+ {}", date_slug);
|
||||
|
||||
let (img_path, img_alt) = bread.thumb_photo();
|
||||
let note = if bread.note.is_empty() { "<i>There's no note about this bread.</i>" } else { &bread.note };
|
||||
|
||||
@@ -133,14 +143,30 @@ fn main() {
|
||||
|
||||
let image_path_encoded = utf8_percent_encode(thumb_relpath.to_str().unwrap(), DEFAULT_ENCODE_SET).to_string();
|
||||
|
||||
let im = image::open(&web_path.join(img_path)).unwrap();
|
||||
let im = im.thumbnail(500, 500);
|
||||
//let mut output = File::create(&thumb_path);
|
||||
im.save(&thumb_path).unwrap();
|
||||
// TODO keep the original path in bread so we dont have to reconstruct it here
|
||||
let image_real_path = web_path.join(img_path);
|
||||
|
||||
//image_utils::resize(&web_path.join(img_path), 500, 500, &thumb_path).unwrap();
|
||||
// Create the thumb
|
||||
{
|
||||
let mut img_file = fs::File::open(&image_real_path).unwrap();
|
||||
let mut hasher = Blake2b::new();
|
||||
io::copy(&mut img_file, &mut hasher).unwrap();
|
||||
let hash = base64::encode(&hasher.result());
|
||||
|
||||
// bread pic for the thumbnails page
|
||||
let hash_key = thumb_path.to_str().unwrap();
|
||||
let old_hash = hashes.get(hash_key);
|
||||
if old_hash.is_none() || !old_hash.unwrap().eq(&hash) {
|
||||
println!("building thumb...");
|
||||
|
||||
let im = image::open(&image_real_path).unwrap();
|
||||
let im = im.thumbnail(500, 500);
|
||||
im.save(&thumb_path).unwrap();
|
||||
|
||||
hashes.put(hash_key.to_string(), hash);
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare the thumb card for the gallery page
|
||||
{
|
||||
let thumb = thumb_tpl
|
||||
.replace("{detail_url}", &detail_file)
|
||||
@@ -151,7 +177,7 @@ fn main() {
|
||||
thumbs.push_str(&thumb);
|
||||
}
|
||||
|
||||
// add to rss
|
||||
// Add to RSS
|
||||
{
|
||||
let image_url : String = channel.link().to_string() + "/" + &image_path_encoded;
|
||||
|
||||
@@ -172,7 +198,7 @@ fn main() {
|
||||
.build().unwrap());
|
||||
}
|
||||
|
||||
// generate the detail page
|
||||
// Generate the detail page
|
||||
{
|
||||
let detail = detail_tpl
|
||||
.replace("{head}", &head_tpl.replace("{title}", &format!("Bread from {}", date)).trim())
|
||||
@@ -191,15 +217,19 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let main = main_tpl.replace("{breads}", &thumbs.trim())
|
||||
.replace("{head}", &head_tpl.replace("{title}", "Piggo's breads").trim());
|
||||
hashes.save();
|
||||
|
||||
{
|
||||
println!("Building the gallery page");
|
||||
let main = main_tpl.replace("{breads}", &thumbs.trim())
|
||||
.replace("{head}", &head_tpl.replace("{title}", "Piggo's breads").trim());
|
||||
|
||||
let mut f = OpenOptions::new().write(true).truncate(true).create(true).open(web_path.join("index.html")).unwrap();
|
||||
f.write(main.as_bytes()).unwrap();
|
||||
}
|
||||
|
||||
{
|
||||
println!("Generating feed...");
|
||||
let f = OpenOptions::new().write(true).truncate(true).create(true).open(web_path.join("feed.xml")).unwrap();
|
||||
channel.set_items(channel_items);
|
||||
channel.pretty_write_to(f, b' ', 2).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user