mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-31 05:28:25 -06:00
LRC-LIB-KEYWORDS: keywords from files keep their hierarchy
Exports now write names to `dc:subject` and paths to `lr:hierarchicalSubject`, as Lightroom Classic does, but import and sidecars read only `dc:subject`: an exported `travel|Italy|Rome` came back as three keywords, Rome, Italy and travel. They now take the paths of `lr:hierarchicalSubject` and the names of `dc:subject` that aren't levels of those paths (`keywords::from_file`); without paths, the names as they are, so LightCraft's own sidecars read as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
d62a5637d8
commit
3a145eef4e
@@ -37,7 +37,8 @@ fn meta_of(m: &lightcraft_meta::Metadata) -> (Meta, Option<String>) {
|
||||
usage_terms: m.usage_terms.clone().unwrap_or_default(),
|
||||
copyright_url: m.copyright_url.clone().unwrap_or_default(),
|
||||
creator: m.artist.clone().unwrap_or_default(),
|
||||
keywords: m.keywords.clone(),
|
||||
// paths from `lr:hierarchicalSubject`, names from `dc:subject` that aren't their levels
|
||||
keywords: lightcraft_catalog::keywords::from_file(&m.keywords, &m.hierarchical_keywords),
|
||||
regions: m.regions.clone(),
|
||||
};
|
||||
(meta, m.capture_time.as_ref().map(|d| d.to_iso()))
|
||||
@@ -587,6 +588,19 @@ impl crate::Session {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
/// Keywords from a file keep their hierarchy: the paths of `lr:hierarchicalSubject`, not the
|
||||
/// flat names of `dc:subject` that LightCraft's exports (and Lightroom Classic) write besides
|
||||
/// them; an exported `travel|Italy|Rome` comes back as itself.
|
||||
#[test]
|
||||
fn imported_keywords_keep_their_hierarchy() {
|
||||
let m = lightcraft_meta::Metadata {
|
||||
keywords: vec!["Rome".into(), "Italy".into(), "travel".into(), "beach".into()],
|
||||
hierarchical_keywords: vec!["travel|Italy|Rome".into()],
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(super::meta_of(&m).0.keywords, ["travel|Italy|Rome", "beach"]);
|
||||
}
|
||||
|
||||
use super::*;
|
||||
use lightcraft_codecs::{ChromaSubsampling, EncodeImage, EncodeMeta, Samples, encode_jpeg};
|
||||
|
||||
|
||||
@@ -133,7 +133,8 @@ pub fn parse_sidecar(xmp: &str, raw: bool) -> std::result::Result<SidecarData, S
|
||||
country: m.country.clone(),
|
||||
alt_text: m.alt_text.clone(),
|
||||
extended_description: m.extended_description.clone(),
|
||||
keywords: (!m.keywords.is_empty()).then(|| m.keywords.clone()),
|
||||
keywords: (!m.keywords.is_empty() || !m.hierarchical_keywords.is_empty())
|
||||
.then(|| lightcraft_catalog::keywords::from_file(&m.keywords, &m.hierarchical_keywords)),
|
||||
// A sidecar that has `mwg-rs:Regions` at all (even an empty list) was written by an app that
|
||||
// knows about regions, so it's authoritative: its list, empty or not, replaces the catalog's.
|
||||
// One without it (most writers, LightCraft's own included, which keeps another app's
|
||||
@@ -515,6 +516,19 @@ impl Session {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
/// A sidecar written by Lightroom Classic (names flat, paths in `lr:hierarchicalSubject`)
|
||||
/// gives the photo its keywords as paths.
|
||||
#[test]
|
||||
fn sidecar_keywords_keep_their_hierarchy() {
|
||||
let m = lightcraft_meta::Metadata {
|
||||
keywords: vec!["Lisbon".into(), "Places".into()],
|
||||
hierarchical_keywords: vec!["Places|Lisbon".into()],
|
||||
..Default::default()
|
||||
};
|
||||
let sc = super::parse_sidecar(&lightcraft_meta::write_xmp(&m, None), false).unwrap();
|
||||
assert_eq!(sc.keywords, Some(vec!["Places|Lisbon".to_string()]));
|
||||
}
|
||||
|
||||
use super::*;
|
||||
use lightcraft_catalog::Meta;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user