avoid rebuilding unchanged image files

This commit is contained in:
2019-01-26 19:13:30 +01:00
parent 7d1d36ac8d
commit 7cb1bb11b2
5 changed files with 182 additions and 10 deletions
+64
View File
@@ -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
View File
@@ -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();