mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-22 18:22:26 +00:00
commit
6eb04f9a1c
3 files changed
+29
-11
No files matched your search
+25
-10
@@ -10,13 +10,6 @@ use serde_json::{Value, json};
|
||||
|
||||
use crate::backend::{Backend, ProgressHook};
|
||||
|
||||
/// File extensions recognised as photos when expanding folders.
|
||||
pub const PHOTO_EXTENSIONS: &[&str] = &[
|
||||
"jpg", "jpeg", "png", "tif", "tiff", "webp", "dng", "cr2", "cr3", "nef", "arw", "raf", "orf", "rw2", "rwl", "raw", "pef", "srw", "psd", "jxl",
|
||||
"gif", "bmp", "avif", // containers LightCraft cannot decode but imports as preview only (their embedded JPEG)
|
||||
"iiq", "crw", "mrw", "x3f", "kdc", "mos", "erf", "3fr", "fff",
|
||||
];
|
||||
|
||||
/// Headless backend: a [`Session`] with filesystem hooks.
|
||||
pub struct Headless {
|
||||
pub session: Session,
|
||||
@@ -175,15 +168,16 @@ impl Backend for Headless {
|
||||
}
|
||||
|
||||
/// Expand folders (recursively, sorted; bounded, see `lightcraft_engine::walk`) into photo files
|
||||
/// and make paths absolute.
|
||||
/// and make paths absolute. Folders take the extensions `library.import` takes
|
||||
/// (`lightcraft_engine::import::EXTENSIONS`), so the two can't drift apart (issue #1080).
|
||||
pub fn expand_paths(paths: &[String]) -> Vec<String> {
|
||||
let absolute = |p: &Path| std::path::absolute(p).unwrap_or_else(|_| p.to_path_buf()).to_string_lossy().to_string();
|
||||
let photo = |p: &Path| p.extension().is_some_and(|e| PHOTO_EXTENSIONS.contains(&e.to_string_lossy().to_lowercase().as_str()));
|
||||
let mut out = Vec::new();
|
||||
for p in paths {
|
||||
let path = Path::new(p);
|
||||
if path.is_dir() {
|
||||
let w = lightcraft_engine::walk::files_in(path, None, lightcraft_engine::walk::Limits::default(), photo);
|
||||
let w =
|
||||
lightcraft_engine::walk::files_in(path, None, lightcraft_engine::walk::Limits::default(), lightcraft_engine::import::is_supported);
|
||||
out.extend(w.files.iter().map(|f| absolute(f)));
|
||||
} else {
|
||||
// Explicit files are kept even with unknown extensions (the probe decides).
|
||||
@@ -226,6 +220,27 @@ mod tests {
|
||||
assert_eq!(r["dir"], json!(dir.display().to_string()), "{r}");
|
||||
}
|
||||
|
||||
/// `--import <folder>` picks up every extension `library.import` takes, HEIC included (issue #1080).
|
||||
#[test]
|
||||
fn expand_paths_takes_the_engine_extensions() {
|
||||
let dir = std::env::temp_dir().join(format!("lc-mcp-expand-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
for e in lightcraft_engine::import::EXTENSIONS {
|
||||
std::fs::write(dir.join(format!("a.{e}")), b"x").unwrap();
|
||||
}
|
||||
std::fs::write(dir.join("B.HEIC"), b"x").unwrap();
|
||||
std::fs::write(dir.join("notes.txt"), b"x").unwrap();
|
||||
let found = expand_paths(&[dir.to_string_lossy().to_string()]);
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
let ext = |f: &String| Path::new(f).extension().map(|e| e.to_string_lossy().to_string()).unwrap_or_default();
|
||||
let mut got: Vec<String> = found.iter().map(ext).collect();
|
||||
got.sort();
|
||||
let mut want: Vec<String> = lightcraft_engine::import::EXTENSIONS.iter().map(|e| e.to_string()).chain(["HEIC".to_string()]).collect();
|
||||
want.sort();
|
||||
assert_eq!(got, want);
|
||||
}
|
||||
|
||||
/// A headless session stamps imports and edits with the system clock, not the engine's fixed test clock.
|
||||
#[test]
|
||||
fn headless_uses_the_system_clock() {
|
||||
|
||||
@@ -23,7 +23,7 @@ mod tools;
|
||||
|
||||
pub use backend::{Backend, ProgressHook, Remote};
|
||||
pub use base64::{base64_decode, base64_encode};
|
||||
pub use headless::{Headless, PHOTO_EXTENSIONS, encode_image, expand_paths, write_image};
|
||||
pub use headless::{Headless, encode_image, expand_paths, write_image};
|
||||
pub use server::{PROTOCOL_VERSION, Server};
|
||||
pub use tools::{COMMAND_TOOL_PREFIX, ToolResult, call_tool, command_tool_name, helper_tools, tool_definitions};
|
||||
|
||||
|
||||
@@ -69,6 +69,9 @@
|
||||
its embedded JPEG or a thumbnail to show, the loupe now says so at the bottom of the photo ("Original offline · no
|
||||
smart preview" or "This photo can't be opened", the reason on hover) instead of showing that preview as if it were
|
||||
the photo.
|
||||
### `--import <folder>` takes HEIC
|
||||
- `lightcraft-cli run --import <folder>` (and the MCP tools that take folders) now picks up HEIC, HEIF and Nikon NRW
|
||||
files, the same files as `library.import` (issue #1080). They used to be skipped without a word.
|
||||
|
||||
### JPEG XL export
|
||||
- Export as JPEG XL (issue #247): Format ▸ JPEG XL in the Export dialog, `format: "jxl"` for agents and the CLI
|
||||
|
||||
Reference in new issue
Block a user