Compare commits
5 commits
main
...
feature/re
| Author | SHA1 | Date | |
|---|---|---|---|
| c151ac409b | |||
| ace35c7c86 | |||
| 04932b2c77 | |||
| 89f6ea5335 | |||
| 16699d86a8 |
7 changed files with 92 additions and 103 deletions
74
Cargo.lock
generated
74
Cargo.lock
generated
|
|
@ -145,9 +145,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.1"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||
|
||||
[[package]]
|
||||
name = "bitstream-io"
|
||||
|
|
@ -200,9 +200,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.23"
|
||||
version = "1.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766"
|
||||
checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
|
|
@ -227,9 +227,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.38"
|
||||
version = "4.5.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
|
||||
checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
|
@ -237,9 +237,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.38"
|
||||
version = "4.5.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
|
||||
checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
|
@ -481,9 +481,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.3"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||
checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
|
|
@ -520,7 +520,7 @@ version = "0.9.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"bitflags 2.9.0",
|
||||
"ignore",
|
||||
"walkdir",
|
||||
]
|
||||
|
|
@ -537,9 +537,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.3"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
|
|
@ -659,9 +659,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
|||
|
||||
[[package]]
|
||||
name = "jiff"
|
||||
version = "0.2.13"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806"
|
||||
checksum = "d07d8d955d798e7a4d6f9c58cd1f1916e790b42b092758a9ef6e16fef9f1b3fd"
|
||||
dependencies = [
|
||||
"jiff-static",
|
||||
"log",
|
||||
|
|
@ -672,9 +672,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "jiff-static"
|
||||
version = "0.2.13"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48"
|
||||
checksum = "f244cfe006d98d26f859c7abd1318d85327e1882dc9cef80f62daeeb0adcf300"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -687,7 +687,7 @@ version = "0.1.33"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
|
||||
dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
"getrandom 0.3.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
|
|
@ -744,6 +744,16 @@ dependencies = [
|
|||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libyml"
|
||||
version = "0.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3302702afa434ffa30847a83305f0a69d6abd74293b6554c18ec85c7ef30c980"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.27"
|
||||
|
|
@ -949,7 +959,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "photojawn"
|
||||
version = "0.2.0"
|
||||
version = "0.2.0-pre.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
|
|
@ -963,7 +973,7 @@ dependencies = [
|
|||
"pulldown-cmark",
|
||||
"rayon",
|
||||
"serde",
|
||||
"serde_yaml_ng",
|
||||
"serde_yml",
|
||||
"tera",
|
||||
"thiserror 2.0.12",
|
||||
"time",
|
||||
|
|
@ -1052,7 +1062,7 @@ version = "0.13.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"bitflags 2.9.0",
|
||||
"getopts",
|
||||
"memchr",
|
||||
"pulldown-cmark-escape",
|
||||
|
|
@ -1293,16 +1303,18 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml_ng"
|
||||
version = "0.10.0"
|
||||
name = "serde_yml"
|
||||
version = "0.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b4db627b98b36d4203a7b458cf3573730f2bb591b28871d916dfa9efabfd41f"
|
||||
checksum = "59e2dd588bf1597a252c3b920e0143eb99b0f76e4e082f4c92ce34fbc9e71ddd"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"libyml",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
"unsafe-libyaml",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1597,12 +1609,6 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
|
|
@ -1824,9 +1830,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
|||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.10"
|
||||
version = "0.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
|
||||
checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
|
@ -1837,7 +1843,7 @@ version = "0.39.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"bitflags 2.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
34
Cargo.toml
34
Cargo.toml
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "photojawn"
|
||||
version = "0.2.0"
|
||||
version = "0.2.0-pre.1"
|
||||
description = "A static site generator for photo albums"
|
||||
authors = ["Nick Pegg <nick@nickpegg.com>"]
|
||||
license = "MIT"
|
||||
|
|
@ -8,21 +8,21 @@ repository = "https://github.com/nickpegg/photojawn"
|
|||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
clap = { version = "4.5", features = ["derive"] }
|
||||
env_logger = "0.11.8"
|
||||
fs_extra = "1.3"
|
||||
image = "0.25.6"
|
||||
indicatif = "0.17.11"
|
||||
kamadak-exif = "0.6.1"
|
||||
log = "0.4.27"
|
||||
pulldown-cmark = "0.13.0"
|
||||
rayon = "1.10"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_yaml_ng = "0.10.0"
|
||||
tera = { version = "1.20", default-features = false }
|
||||
thiserror = "2.0"
|
||||
time = { version = "0.3.41", features = ["formatting", "macros", "parsing"] }
|
||||
anyhow = "^1.0"
|
||||
clap = { version = "^4.5", features = ["derive"] }
|
||||
env_logger = "^0.11.8"
|
||||
fs_extra = "^1.3.0"
|
||||
image = "^0.25.6"
|
||||
indicatif = "^0.17.11"
|
||||
kamadak-exif = "^0.6.1"
|
||||
log = "^0.4.27"
|
||||
pulldown-cmark = "^0.13.0"
|
||||
rayon = "^1.10.0"
|
||||
serde = { version = "^1.0", features = ["derive"] }
|
||||
serde_yml = "^0.0.12"
|
||||
tera = { version = "^1.20", default-features = false }
|
||||
thiserror = "^2.0"
|
||||
time = { version = "^0.3.41", features = ["formatting", "macros", "parsing"] }
|
||||
|
||||
[dev-dependencies]
|
||||
mktemp = "0.5.1"
|
||||
mktemp = "^0.5.1"
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 50 KiB |
|
|
@ -23,7 +23,7 @@ impl Config {
|
|||
config_path.display(),
|
||||
)
|
||||
})?;
|
||||
let cfg = serde_yaml_ng::from_slice(&content)
|
||||
let cfg = serde_yml::from_slice(&content)
|
||||
.with_context(|| format!("Failed to parse config from {}", config_path.display()))?;
|
||||
Ok(cfg)
|
||||
}
|
||||
|
|
@ -56,11 +56,11 @@ mod test {
|
|||
fn from_yaml() {
|
||||
// Empty YAML gives full default values
|
||||
let default_cfg = Config::default();
|
||||
let cfg: Config = serde_yaml_ng::from_str("").unwrap();
|
||||
let cfg: Config = serde_yml::from_str("").unwrap();
|
||||
assert_eq!(cfg, default_cfg);
|
||||
|
||||
// Default values for any unspecified fields
|
||||
let cfg: Config = serde_yaml_ng::from_str("thumbnail_size: [1, 1]").unwrap();
|
||||
let cfg: Config = serde_yml::from_str("thumbnail_size: [1, 1]").unwrap();
|
||||
assert_ne!(cfg, default_cfg);
|
||||
assert_eq!(cfg.thumbnail_size, (1, 1));
|
||||
assert_eq!(cfg.view_size, default_cfg.view_size);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ pub struct AlbumDir {
|
|||
|
||||
impl AlbumDir {
|
||||
/// Returns an iterator over all images in the album and subalbums
|
||||
pub fn iter_all_images(&self) -> AlbumImageIter<'_> {
|
||||
pub fn iter_all_images(&self) -> AlbumImageIter {
|
||||
AlbumImageIter::new(self)
|
||||
}
|
||||
|
||||
|
|
@ -79,9 +79,8 @@ impl AlbumDir {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if entry_path.is_dir()
|
||||
&& let Some(dirname) = entry_path.file_name().and_then(|n| n.to_str())
|
||||
{
|
||||
} else if entry_path.is_dir() {
|
||||
if let Some(dirname) = entry_path.file_name().and_then(|n| n.to_str()) {
|
||||
if dirname.starts_with("_") {
|
||||
// Likely a templates or static dir
|
||||
continue;
|
||||
|
|
@ -95,6 +94,7 @@ impl AlbumDir {
|
|||
children.push(AlbumDir::from_path(&entry_path, root)?);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
children.sort_by_key(|c| c.path.clone());
|
||||
images.sort_by_key(|i| i.path.clone());
|
||||
|
|
|
|||
|
|
@ -55,7 +55,8 @@ impl Image {
|
|||
/// return "blah.thumb"
|
||||
fn slide_filename(path: &Path, ext: &str, keep_ext: bool) -> anyhow::Result<String> {
|
||||
let mut new_ext: OsString = ext.into();
|
||||
if keep_ext && let Some(e) = path.extension() {
|
||||
if keep_ext {
|
||||
if let Some(e) = path.extension() {
|
||||
new_ext = OsString::from(
|
||||
ext.to_string()
|
||||
+ "."
|
||||
|
|
@ -65,6 +66,7 @@ impl Image {
|
|||
))?,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let new_path = path.with_extension(new_ext);
|
||||
let new_name = new_path
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use anyhow::{Context, anyhow};
|
||||
use anyhow::{anyhow, Context};
|
||||
use image::ImageReader;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::{File, rename};
|
||||
use std::fs::{rename, File};
|
||||
use std::io::BufReader;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::from_utf8;
|
||||
|
|
@ -51,10 +51,6 @@ fn get_renames(dir: &Path) -> anyhow::Result<Vec<(PathBuf, PathBuf)>> {
|
|||
for entry in dir.read_dir()? {
|
||||
let entry = entry?;
|
||||
|
||||
if !entry.path().is_file() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only bother with image files, because those are the only hope for EXIF
|
||||
let is_image: bool = ImageReader::open(entry.path())?
|
||||
.with_guessed_format()?
|
||||
|
|
@ -138,6 +134,7 @@ fn get_exif_datetime(path: PathBuf) -> anyhow::Result<UtcDateTime> {
|
|||
|
||||
let file = File::open(&path).with_context(|| format!("Couldn't open {}", path.display()))?;
|
||||
let mut bufreader = BufReader::new(file);
|
||||
// TODO: Return a better error if EXIF is not supported
|
||||
let exif = exif::Reader::new()
|
||||
.read_from_container(&mut bufreader)
|
||||
.with_context(|| format!("Couldn't read EXIF data from {}", path.display()))?;
|
||||
|
|
@ -155,7 +152,8 @@ fn get_exif_datetime(path: PathBuf) -> anyhow::Result<UtcDateTime> {
|
|||
Err(_) => PrimitiveDateTime::parse(s, format_without_offset)?.as_utc(),
|
||||
}
|
||||
}
|
||||
_ => return Err(OrganizeError::ExifNoDateTime(path).into()),
|
||||
// TODO: return some error
|
||||
_ => todo!(),
|
||||
};
|
||||
|
||||
Ok(dt)
|
||||
|
|
@ -191,7 +189,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic_renames() {
|
||||
fn basic_renames() {
|
||||
init();
|
||||
let tmp_album_dir = make_test_album();
|
||||
let dir = tmp_album_dir.join("with_description");
|
||||
|
|
@ -212,27 +210,10 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// get_renames() should ignore other stuff in the directory
|
||||
fn test_other_junk() {
|
||||
init();
|
||||
let tmp_album_dir = make_test_album();
|
||||
|
||||
let renames = get_renames(&tmp_album_dir).unwrap();
|
||||
// No mountain.jpg since it doesn't have EXIF data
|
||||
assert_eq!(
|
||||
renames,
|
||||
vec![(
|
||||
tmp_album_dir.join("moon.jpg"),
|
||||
tmp_album_dir.join("19700101_133700_moon.jpg")
|
||||
)]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// The rename function will prepend date and time to the original filenames. If we do it a
|
||||
/// second time, it should be a no-op instead of continuing to prepend date and time.
|
||||
fn test_rerename() {
|
||||
fn rerename() {
|
||||
let tmp_album_dir = make_test_album();
|
||||
let dir = tmp_album_dir.join("with_description");
|
||||
reorganize(&dir, false).unwrap();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue